@@ -145,6 +145,51 @@ func TestFallbackStepUsageEstimatesToolResults(t *testing.T) {
145 require.Equal(t, usage.InputTokens, usage.TotalTokens)
145 require.Equal(t, usage.InputTokens, usage.TotalTokens)
148+func TestFallbackStepUsageSkipsClientToolResultsAsOutput(t *testing.T) {
151+ step := fantasy.StepResult{
152+ Response: fantasy.Response{
153+ Content: fantasy.ResponseContent{
154+ fantasy.ToolResultContent{
155+ ToolCallID: "tool-call-1",
157+ Result: fantasy.ToolResultOutputContentText{
158+ Text: "large client-executed payload that should not count as model output tokens",
165+ usage, estimated := fallbackStepUsage(nil, step)
166+ require.False(t, estimated)
167+ require.Zero(t, usage.OutputTokens)
170+func TestFallbackStepUsageCountsProviderToolResultsAsOutput(t *testing.T) {
173+ step := fantasy.StepResult{
174+ Response: fantasy.Response{
175+ Content: fantasy.ResponseContent{
176+ fantasy.ToolResultContent{
177+ ToolCallID: "tool-call-1",
178+ ToolName: "web_search",
179+ ProviderExecuted: true,
180+ ClientMetadata: "provider metadata",
181+ Result: fantasy.ToolResultOutputContentText{Text: "provider-executed result"},
187+ usage, estimated := fallbackStepUsage(nil, step)
188+ require.True(t, estimated)
189+ require.Positive(t, usage.OutputTokens)
190+ require.Equal(t, usage.OutputTokens, usage.TotalTokens)
148func TestFallbackStepUsageReturnsZeroWithoutContent(t *testing.T) {
193func TestFallbackStepUsageReturnsZeroWithoutContent(t *testing.T) {
149 t.Parallel()
194 t.Parallel()
@@ -187,6 +232,24 @@ func TestUpdateSessionUsageKeepsCountersForZeroUsage(t *testing.T) {
187 require.Equal(t, int64(456), currentSession.CompletionTokens)
232 require.Equal(t, int64(456), currentSession.CompletionTokens)
235+func TestUpdateSessionUsageReplacesCountersForPartialUsage(t *testing.T) {
238+ agent := &sessionAgent{}
239+ currentSession := &session.Session{
242+ CompletionTokens: 456,
244+ model := Model{CatwalkCfg: catwalk.Model{CostPer1MIn: 10, CostPer1MOut: 20}}
245+ usage := fantasy.Usage{InputTokens: 789}
247+ agent.updateSessionUsage(model, currentSession, usage, nil, false)
249+ require.Equal(t, int64(789), currentSession.PromptTokens)
250+ require.Zero(t, currentSession.CompletionTokens)
190func TestUpdateSessionUsageAddsProviderCost(t *testing.T) {
253func TestUpdateSessionUsageAddsProviderCost(t *testing.T) {
191 t.Parallel()
254 t.Parallel()