fix(agent): include SystemParts in token estimation and add reasoning guards

This commit is contained in:
Badgerbees
2026-03-26 00:31:22 +07:00
parent dd54601f2d
commit 93f391a6bf
2 changed files with 25 additions and 4 deletions
+5 -4
View File
@@ -91,11 +91,12 @@ func findSafeBoundary(history []providers.Message, targetIndex int) int {
// metadata, and Media items. Uses a heuristic of 2.5 characters per token.
func estimateMessageTokens(msg providers.Message) int {
chars := utf8.RuneCountInString(msg.Content)
chars += utf8.RuneCountInString(msg.ReasoningContent)
// ReasoningContent (extended thinking / chain-of-thought) can be
// substantial and is stored in session history via AddFullMessage.
if msg.ReasoningContent != "" {
chars += utf8.RuneCountInString(msg.ReasoningContent)
// SystemParts are structured system blocks that can be substantial
// when using instruction-heavy agents or KV-cache-aware adapters.
for _, part := range msg.SystemParts {
chars += utf8.RuneCountInString(part.Text)
}
for _, tc := range msg.ToolCalls {
+20
View File
@@ -529,6 +529,26 @@ func TestEstimateMessageTokens_MediaItems(t *testing.T) {
}
}
func TestEstimateMessageTokens_SystemParts(t *testing.T) {
plain := providers.Message{Role: "system", Content: "instructions"}
withParts := providers.Message{
Role: "system",
Content: "instructions",
SystemParts: []providers.ContentBlock{
{Type: "text", Text: "some more system context"},
{Type: "text", Text: "even more cached blocks"},
},
}
plainTokens := estimateMessageTokens(plain)
partsTokens := estimateMessageTokens(withParts)
if partsTokens <= plainTokens {
t.Errorf("system message with SystemParts (%d) should exceed plain message (%d)",
partsTokens, plainTokens)
}
}
// --- estimateToolDefsTokens tests ---
func TestEstimateToolDefsTokens(t *testing.T) {