Skip to content

Commit 775457c

Browse files
authored
Yield the cost in usage data for Anthropic (#4849)
1 parent 48ebb06 commit 775457c

File tree

4 files changed

+54
-20
lines changed

4 files changed

+54
-20
lines changed

src/api/providers/anthropic.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { getModelParams } from "../transform/model-params"
1717

1818
import { BaseProvider } from "./base-provider"
1919
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
20+
import { calculateApiCostAnthropic } from "../../shared/cost"
2021

2122
export class AnthropicHandler extends BaseProvider implements SingleCompletionHandler {
2223
private options: ApiHandlerOptions
@@ -132,20 +133,35 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
132133
}
133134
}
134135

136+
let inputTokens = 0
137+
let outputTokens = 0
138+
let cacheWriteTokens = 0
139+
let cacheReadTokens = 0
140+
135141
for await (const chunk of stream) {
136142
switch (chunk.type) {
137143
case "message_start": {
138144
// Tells us cache reads/writes/input/output.
139-
const usage = chunk.message.usage
145+
const {
146+
input_tokens = 0,
147+
output_tokens = 0,
148+
cache_creation_input_tokens,
149+
cache_read_input_tokens,
150+
} = chunk.message.usage
140151

141152
yield {
142153
type: "usage",
143-
inputTokens: usage.input_tokens || 0,
144-
outputTokens: usage.output_tokens || 0,
145-
cacheWriteTokens: usage.cache_creation_input_tokens || undefined,
146-
cacheReadTokens: usage.cache_read_input_tokens || undefined,
154+
inputTokens: input_tokens,
155+
outputTokens: output_tokens,
156+
cacheWriteTokens: cache_creation_input_tokens || undefined,
157+
cacheReadTokens: cache_read_input_tokens || undefined,
147158
}
148159

160+
inputTokens += input_tokens
161+
outputTokens += output_tokens
162+
cacheWriteTokens += cache_creation_input_tokens || 0
163+
cacheReadTokens += cache_read_input_tokens || 0
164+
149165
break
150166
}
151167
case "message_delta":
@@ -198,6 +214,21 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa
198214
break
199215
}
200216
}
217+
218+
if (inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0) {
219+
yield {
220+
type: "usage",
221+
inputTokens: 0,
222+
outputTokens: 0,
223+
totalCost: calculateApiCostAnthropic(
224+
this.getModel().info,
225+
inputTokens,
226+
outputTokens,
227+
cacheWriteTokens,
228+
cacheReadTokens,
229+
),
230+
}
231+
}
201232
}
202233

203234
getModel() {

src/core/task/Task.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,19 +1439,22 @@ export class Task extends EventEmitter<ClineEvents> {
14391439
} finally {
14401440
this.isStreaming = false
14411441
}
1442-
if (
1443-
inputTokens > 0 ||
1444-
outputTokens > 0 ||
1445-
cacheWriteTokens > 0 ||
1446-
cacheReadTokens > 0 ||
1447-
typeof totalCost !== "undefined"
1448-
) {
1442+
1443+
if (inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0) {
14491444
TelemetryService.instance.captureLlmCompletion(this.taskId, {
14501445
inputTokens,
14511446
outputTokens,
14521447
cacheWriteTokens,
14531448
cacheReadTokens,
1454-
cost: totalCost,
1449+
cost:
1450+
totalCost ??
1451+
calculateApiCostAnthropic(
1452+
this.api.getModel().info,
1453+
inputTokens,
1454+
outputTokens,
1455+
cacheWriteTokens,
1456+
cacheReadTokens,
1457+
),
14551458
})
14561459
}
14571460

src/services/checkpoints/__tests__/ShadowCheckpointService.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as fileSearch from "../../../services/search/file-search"
1212

1313
import { RepoPerTaskCheckpointService } from "../RepoPerTaskCheckpointService"
1414

15-
vitest.setConfig({ testTimeout: 10_000 })
15+
vitest.setConfig({ testTimeout: 20_000 })
1616

1717
const tmpDir = path.join(os.tmpdir(), "CheckpointService")
1818

src/shared/cost.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,25 @@ function calculateApiCostInternal(
1515
return totalCost
1616
}
1717

18-
// For Anthropic compliant usage, the input tokens count does NOT include the cached tokens
18+
// For Anthropic compliant usage, the input tokens count does NOT include the
19+
// cached tokens.
1920
export function calculateApiCostAnthropic(
2021
modelInfo: ModelInfo,
2122
inputTokens: number,
2223
outputTokens: number,
2324
cacheCreationInputTokens?: number,
2425
cacheReadInputTokens?: number,
2526
): number {
26-
const cacheCreationInputTokensNum = cacheCreationInputTokens || 0
27-
const cacheReadInputTokensNum = cacheReadInputTokens || 0
2827
return calculateApiCostInternal(
2928
modelInfo,
3029
inputTokens,
3130
outputTokens,
32-
cacheCreationInputTokensNum,
33-
cacheReadInputTokensNum,
31+
cacheCreationInputTokens || 0,
32+
cacheReadInputTokens || 0,
3433
)
3534
}
3635

37-
// For OpenAI compliant usage, the input tokens count INCLUDES the cached tokens
36+
// For OpenAI compliant usage, the input tokens count INCLUDES the cached tokens.
3837
export function calculateApiCostOpenAI(
3938
modelInfo: ModelInfo,
4039
inputTokens: number,
@@ -45,6 +44,7 @@ export function calculateApiCostOpenAI(
4544
const cacheCreationInputTokensNum = cacheCreationInputTokens || 0
4645
const cacheReadInputTokensNum = cacheReadInputTokens || 0
4746
const nonCachedInputTokens = Math.max(0, inputTokens - cacheCreationInputTokensNum - cacheReadInputTokensNum)
47+
4848
return calculateApiCostInternal(
4949
modelInfo,
5050
nonCachedInputTokens,

0 commit comments

Comments
 (0)