(t *testing.T)
| 166 | } |
| 167 | |
| 168 | func TestSplitIndexForKeep(t *testing.T) { |
| 169 | t.Parallel() |
| 170 | |
| 171 | msg := func(role chat.MessageRole, content string) chat.Message { |
| 172 | return chat.Message{Role: role, Content: content} |
| 173 | } |
| 174 | |
| 175 | tests := []struct { |
| 176 | name string |
| 177 | messages []chat.Message |
| 178 | maxTokens int64 |
| 179 | wantSplit int // expected split index |
| 180 | }{ |
| 181 | { |
| 182 | name: "empty messages", |
| 183 | messages: nil, |
| 184 | maxTokens: 1000, |
| 185 | wantSplit: 0, |
| 186 | }, |
| 187 | { |
| 188 | name: "all messages fit in keep budget - returned len(messages) signals 'compact everything, keep nothing' (the manual /compact contract)", |
| 189 | messages: []chat.Message{ |
| 190 | msg(chat.MessageRoleUser, "short"), |
| 191 | msg(chat.MessageRoleAssistant, "short"), |
| 192 | }, |
| 193 | maxTokens: 100_000, |
| 194 | wantSplit: 2, // all fit → messages[:2] is everything to compact, messages[2:] is empty (nothing kept) |
| 195 | }, |
| 196 | { |
| 197 | name: "recent messages kept, older ones compacted", |
| 198 | messages: []chat.Message{ |
| 199 | msg(chat.MessageRoleUser, strings.Repeat("a", 40000)), // ~10005 tokens |
| 200 | msg(chat.MessageRoleAssistant, strings.Repeat("b", 40000)), // ~10005 tokens |
| 201 | msg(chat.MessageRoleUser, strings.Repeat("c", 40000)), // ~10005 tokens |
| 202 | msg(chat.MessageRoleAssistant, strings.Repeat("d", 40000)), // ~10005 tokens |
| 203 | msg(chat.MessageRoleUser, strings.Repeat("e", 40000)), // ~10005 tokens |
| 204 | msg(chat.MessageRoleAssistant, strings.Repeat("f", 40000)), // ~10005 tokens |
| 205 | }, |
| 206 | maxTokens: 20_100, // enough for exactly 2 messages |
| 207 | wantSplit: 4, // last 2 messages are kept |
| 208 | }, |
| 209 | { |
| 210 | name: "snap to assistant boundary even when a tool result fits", |
| 211 | messages: []chat.Message{ |
| 212 | msg(chat.MessageRoleUser, "u1"), |
| 213 | msg(chat.MessageRoleAssistant, "a1"), |
| 214 | msg(chat.MessageRoleTool, "t1"), |
| 215 | }, |
| 216 | maxTokens: 100_000, // everything fits |
| 217 | wantSplit: 3, // all fit → compact everything (returned len) |
| 218 | }, |
| 219 | } |
| 220 | |
| 221 | for _, tt := range tests { |
| 222 | t.Run(tt.name, func(t *testing.T) { |
| 223 | t.Parallel() |
| 224 | got := SplitIndexForKeep(tt.messages, tt.maxTokens) |
| 225 | assert.Equal(t, tt.wantSplit, got) |
nothing calls this directly
no test coverage detected