SplitIndexForKeep walks messages from the end and returns the earliest index whose suffix fits in maxTokens, snapping to user/assistant boundaries. All messages from the returned index onward are intended to be preserved verbatim across a compaction; messages before it are the candidates to summariz
(messages []chat.Message, maxTokens int64)
| 75 | // the kept window on a user/assistant turn, we guarantee the kept |
| 76 | // suffix begins on a clean conversational turn. |
| 77 | func SplitIndexForKeep(messages []chat.Message, maxTokens int64) int { |
| 78 | if len(messages) == 0 { |
| 79 | return 0 |
| 80 | } |
| 81 | |
| 82 | var tokens int64 |
| 83 | lastValidBoundary := len(messages) |
| 84 | for i := range slices.Backward(messages) { |
| 85 | tokens += EstimateMessageTokens(&messages[i]) |
| 86 | if tokens > maxTokens { |
| 87 | return lastValidBoundary |
| 88 | } |
| 89 | role := messages[i].Role |
| 90 | if role == chat.MessageRoleUser || role == chat.MessageRoleAssistant { |
| 91 | lastValidBoundary = i |
| 92 | } |
| 93 | } |
| 94 | return len(messages) |
| 95 | } |
| 96 | |
| 97 | // FirstIndexInBudget returns the smallest index N such that |
| 98 | // messages[N:] fits within contextLimit, snapping to a user/assistant |