keepLastMessages function
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)]);
};
}