Files
goclaw/internal/providers/usage_context_tokens_test.go
thotam 503909d3b6 fix(sessions): store last-call context tokens instead of run-cumulative total
SetLastPromptTokens received TotalUsage.PromptTokens — the sum of prompt
tokens across every think→act→observe iteration of a run — instead of the
final iteration's own usage. A tool-heavy run inflated the stored value by
the iteration count, so the sessions list showed e.g. 901K "context used"
against a 258K window, and maybeSummarize over-triggered compaction once
the inflation exceeded the 40% overhead clamp (observed: 83 compactions
on a 4-message session).

Track the final iteration's usage separately (ThinkState.LastUsage) and
persist its actual context size: prompt tokens + cached segments (Anthropic
reports input_tokens excluding cache read/creation) + output tokens (the
final reply joins history, so it occupies the next request's prompt). The
run-cumulative total still feeds AccumulateTokens for billing.
2026-07-23 10:37:25 +07:00

50 lines
1.3 KiB
Go

package providers
import "testing"
// TestUsage_ContextTokens guards the "current context size" computation used by
// the sessions context-usage display and compaction calibration. Anthropic-style
// accounting reports input_tokens EXCLUDING cached segments, so the real context
// of a call is prompt + cache_read + cache_creation. OpenAI-style accounting
// (PromptTokensIncludeCachedSegments=true) already includes cached tokens.
func TestUsage_ContextTokens(t *testing.T) {
t.Parallel()
tests := []struct {
name string
usage Usage
want int
}{
{
name: "anthropic-style excludes cached segments — add them back",
usage: Usage{
PromptTokens: 1000,
CacheReadTokens: 80000,
CacheCreationTokens: 5000,
},
want: 86000,
},
{
name: "openai-style already includes cached segments",
usage: Usage{
PromptTokens: 86000,
CacheReadTokens: 80000,
PromptTokensIncludeCachedSegments: true,
},
want: 86000,
},
{
name: "zero value",
usage: Usage{},
want: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.usage.ContextTokens(); got != tt.want {
t.Errorf("ContextTokens() = %d, want %d", got, tt.want)
}
})
}
}