keepLastMessages function

AiConversation Function(AiConversation) keepLastMessages(
  1. int count
)

History-trimming strategies for UseChatController.trimHistory.

A strategy maps the full stored conversation to the (smaller) conversation sent to the provider. The controller never trims its stored transcript, so these only bound what each request costs — the UI keeps the full history.

Both built-ins always preserve leading system messages and avoid starting the kept window on an orphaned tool result (which strict providers reject). Conversations with deeply interleaved tool calls may still need a bespoke strategy — these are pragmatic defaults, not a general solution. Keeps the system prefix plus the most recent count non-system messages.

If the kept window would begin on a tool message (a result whose originating assistant tool-call would be trimmed away), the window is advanced forward past it so no orphaned tool result is sent.

Implementation

/// Keeps the system prefix plus the most recent [count] non-system messages.
///
/// If the kept window would begin on a `tool` message (a result whose
/// originating assistant tool-call would be trimmed away), the window is
/// advanced forward past it so no orphaned tool result is sent.
AiConversation Function(AiConversation) keepLastMessages(int count) {
  assert(count >= 0, 'count must be >= 0');
  return (conversation) {
    final messages = conversation.messages;
    final system = [
      for (final m in messages)
        if (m.role == AiRole.system) m,
    ];
    final rest = [
      for (final m in messages)
        if (m.role != AiRole.system) m,
    ];
    if (rest.length <= count) return conversation;

    var start = rest.length - count;
    while (start < rest.length && rest[start].role == AiRole.tool) {
      start++;
    }
    return conversation.copyWith(messages: [...system, ...rest.sublist(start)]);
  };
}