mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-17 23:51:08 +00:00
refactor: normalize cache usage parsing across ai-sdk providers
This commit is contained in:
parent
61fc45c06c
commit
94232eb644
6 changed files with 361 additions and 34 deletions
|
|
@ -414,6 +414,88 @@ describe("OpenRouterHandler", () => {
|
|||
})
|
||||
})
|
||||
|
||||
it("includes cache metrics from usage.raw.prompt_tokens_details when metadata is absent", async () => {
|
||||
const handler = new OpenRouterHandler(mockOptions)
|
||||
|
||||
const mockFullStream = (async function* () {
|
||||
yield { type: "text-delta", text: "test", id: "1" }
|
||||
})()
|
||||
|
||||
mockStreamText.mockReturnValue({
|
||||
fullStream: mockFullStream,
|
||||
usage: Promise.resolve({
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
totalTokens: 13_173,
|
||||
raw: {
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 12_547,
|
||||
cache_write_tokens: 470,
|
||||
},
|
||||
},
|
||||
}),
|
||||
totalUsage: Promise.resolve({ inputTokens: 13_026, outputTokens: 147, totalTokens: 13_173 }),
|
||||
providerMetadata: Promise.resolve(undefined),
|
||||
})
|
||||
|
||||
const generator = handler.createMessage("test", [{ role: "user", content: "test" }])
|
||||
const chunks = []
|
||||
|
||||
for await (const chunk of generator) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
const usageChunk = chunks.find((c) => c.type === "usage")
|
||||
expect(usageChunk).toMatchObject({
|
||||
type: "usage",
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
cacheReadTokens: 12_547,
|
||||
cacheWriteTokens: 470,
|
||||
})
|
||||
})
|
||||
|
||||
it("derives input/output totals from raw prompt/completion tokens when top-level usage totals are missing", async () => {
|
||||
const handler = new OpenRouterHandler(mockOptions)
|
||||
|
||||
const mockFullStream = (async function* () {
|
||||
yield { type: "text-delta", text: "test", id: "1" }
|
||||
})()
|
||||
|
||||
mockStreamText.mockReturnValue({
|
||||
fullStream: mockFullStream,
|
||||
usage: Promise.resolve({
|
||||
raw: {
|
||||
prompt_tokens: 13_026,
|
||||
completion_tokens: 147,
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 12_547,
|
||||
cache_write_tokens: 470,
|
||||
},
|
||||
},
|
||||
}),
|
||||
totalUsage: Promise.resolve({}),
|
||||
providerMetadata: Promise.resolve(undefined),
|
||||
})
|
||||
|
||||
const generator = handler.createMessage("test", [{ role: "user", content: "test" }])
|
||||
const chunks = []
|
||||
|
||||
for await (const chunk of generator) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
const usageChunk = chunks.find((c) => c.type === "usage")
|
||||
expect(usageChunk).toMatchObject({
|
||||
type: "usage",
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
cacheReadTokens: 12_547,
|
||||
cacheWriteTokens: 470,
|
||||
nonCachedInputTokens: 9,
|
||||
})
|
||||
})
|
||||
|
||||
it("handles experimental_providerMetadata fallback", async () => {
|
||||
const handler = new OpenRouterHandler(mockOptions)
|
||||
|
||||
|
|
|
|||
|
|
@ -930,6 +930,47 @@ describe("RooHandler", () => {
|
|||
expect(usageChunk.cacheWriteTokens).toBe(489)
|
||||
expect(usageChunk.cacheReadTokens).toBe(12_572)
|
||||
})
|
||||
|
||||
it("parses anthropic cache metrics from usage.raw.prompt_tokens_details when metadata cache fields are absent", async () => {
|
||||
const anthropicHandler = new RooHandler({
|
||||
apiModelId: "anthropic/claude-haiku-4.5",
|
||||
})
|
||||
|
||||
mockStreamText.mockReturnValue(
|
||||
createMockStreamResult({
|
||||
usage: {
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
raw: {
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 12_547,
|
||||
cache_write_tokens: 470,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
providerMetadata: {
|
||||
gateway: {
|
||||
cost: "0.01157975",
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const stream = anthropicHandler.createMessage(systemPrompt, messages)
|
||||
const chunks: any[] = []
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
const usageChunk = chunks.find((c) => c.type === "usage")
|
||||
expect(usageChunk).toBeDefined()
|
||||
expect(usageChunk.inputTokens).toBe(13_026)
|
||||
expect(usageChunk.outputTokens).toBe(147)
|
||||
expect(usageChunk.nonCachedInputTokens).toBe(9)
|
||||
expect(usageChunk.cacheWriteTokens).toBe(470)
|
||||
expect(usageChunk.cacheReadTokens).toBe(12_547)
|
||||
expect(usageChunk.totalCost).toBe(0.01157975)
|
||||
})
|
||||
})
|
||||
|
||||
describe("isAiSdkProvider", () => {
|
||||
|
|
|
|||
|
|
@ -153,4 +153,110 @@ describe("normalizeProviderUsage", () => {
|
|||
expect(normalized.chunk.cacheReadTokens).toBeUndefined()
|
||||
expect(normalized.chunk.cacheWriteTokens).toBeUndefined()
|
||||
})
|
||||
|
||||
it("parses OpenRouter-style prompt_tokens_details from raw usage", () => {
|
||||
const normalized = normalizeProviderUsage({
|
||||
provider: "openrouter",
|
||||
apiProtocol: "openai",
|
||||
usage: {
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
raw: {
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 12_547,
|
||||
cache_write_tokens: 470,
|
||||
},
|
||||
},
|
||||
},
|
||||
modelInfo: baseModelInfo,
|
||||
})
|
||||
|
||||
expect(normalized.chunk.inputTokens).toBe(13_026)
|
||||
expect(normalized.chunk.cacheReadTokens).toBe(12_547)
|
||||
expect(normalized.chunk.cacheWriteTokens).toBe(470)
|
||||
expect(normalized.chunk.nonCachedInputTokens).toBe(9)
|
||||
})
|
||||
|
||||
it("parses cache write/read tokens from prompt_tokens_details for anthropic protocol", () => {
|
||||
const normalized = normalizeProviderUsage({
|
||||
provider: "anthropic",
|
||||
apiProtocol: "anthropic",
|
||||
usage: {
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
raw: {
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 12_547,
|
||||
cache_write_tokens: 470,
|
||||
},
|
||||
},
|
||||
},
|
||||
modelInfo: baseModelInfo,
|
||||
})
|
||||
|
||||
expect(normalized.chunk.cacheReadTokens).toBe(12_547)
|
||||
expect(normalized.chunk.cacheWriteTokens).toBe(470)
|
||||
expect(normalized.chunk.nonCachedInputTokens).toBe(9)
|
||||
})
|
||||
|
||||
it("parses reasoning tokens from completion_tokens_details", () => {
|
||||
const normalized = normalizeProviderUsage({
|
||||
provider: "openrouter",
|
||||
apiProtocol: "openai",
|
||||
usage: {
|
||||
inputTokens: 100,
|
||||
outputTokens: 30,
|
||||
raw: {
|
||||
completion_tokens_details: {
|
||||
reasoning_tokens: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
modelInfo: baseModelInfo,
|
||||
})
|
||||
|
||||
expect(normalized.chunk.reasoningTokens).toBe(7)
|
||||
})
|
||||
|
||||
it("uses usage/raw cost candidates when provider metadata cost is absent", () => {
|
||||
const normalized = normalizeProviderUsage({
|
||||
provider: "openrouter",
|
||||
apiProtocol: "openai",
|
||||
usage: {
|
||||
inputTokens: 100,
|
||||
outputTokens: 20,
|
||||
cost: 0.12345 as any,
|
||||
raw: {
|
||||
cost: 0.98765,
|
||||
},
|
||||
} as any,
|
||||
modelInfo: baseModelInfo,
|
||||
})
|
||||
|
||||
expect(normalized.chunk.totalCost).toBe(0.12345)
|
||||
})
|
||||
|
||||
it("falls back to prompt/completion token totals from raw usage", () => {
|
||||
const normalized = normalizeProviderUsage({
|
||||
provider: "openrouter",
|
||||
apiProtocol: "openai",
|
||||
usage: {
|
||||
raw: {
|
||||
prompt_tokens: 200,
|
||||
completion_tokens: 30,
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 100,
|
||||
cache_write_tokens: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
modelInfo: baseModelInfo,
|
||||
})
|
||||
|
||||
expect(normalized.chunk.inputTokens).toBe(200)
|
||||
expect(normalized.chunk.outputTokens).toBe(30)
|
||||
expect(normalized.chunk.cacheReadTokens).toBe(100)
|
||||
expect(normalized.chunk.cacheWriteTokens).toBe(50)
|
||||
expect(normalized.chunk.nonCachedInputTokens).toBe(50)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -340,6 +340,46 @@ describe("VercelAiGatewayHandler", () => {
|
|||
})
|
||||
})
|
||||
|
||||
it("parses anthropic cache metrics from usage.raw.prompt_tokens_details when metadata cache fields are absent", async () => {
|
||||
mockStreamText.mockReturnValue(
|
||||
createMockStreamResult({
|
||||
usage: {
|
||||
inputTokens: 13_026,
|
||||
outputTokens: 147,
|
||||
raw: {
|
||||
prompt_tokens_details: {
|
||||
cached_tokens: 12_547,
|
||||
cache_write_tokens: 470,
|
||||
},
|
||||
},
|
||||
} as any,
|
||||
providerMetadata: {},
|
||||
}),
|
||||
)
|
||||
|
||||
const handler = new VercelAiGatewayHandler(mockOptions)
|
||||
const systemPrompt = "You are a helpful assistant."
|
||||
const messages: RooMessage[] = [{ role: "user", content: "Hello" }]
|
||||
|
||||
const stream = handler.createMessage(systemPrompt, messages)
|
||||
const chunks = []
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
const usageChunk = chunks.find((chunk) => chunk.type === "usage")
|
||||
expect(usageChunk).toEqual({
|
||||
type: "usage",
|
||||
inputTokens: 13_026,
|
||||
nonCachedInputTokens: 9,
|
||||
outputTokens: 147,
|
||||
cacheWriteTokens: 470,
|
||||
cacheReadTokens: 12_547,
|
||||
totalCost: undefined,
|
||||
reasoningTokens: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
describe("native tool calling", () => {
|
||||
const testTools = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -179,10 +179,45 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
|
|||
|
||||
const usage = await result.usage
|
||||
const totalUsage = await result.totalUsage
|
||||
const rawUsage = (usage as any)?.raw as Record<string, unknown> | undefined
|
||||
const toFiniteNumber = (value: unknown): number | undefined => {
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
const parsed = Number(value)
|
||||
return Number.isFinite(parsed) ? parsed : undefined
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
const firstFiniteNumber = (...values: unknown[]): number | undefined => {
|
||||
for (const value of values) {
|
||||
const parsed = toFiniteNumber(value)
|
||||
if (parsed !== undefined) {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
const usageRecord = {
|
||||
...(usage as any),
|
||||
inputTokens: totalUsage.inputTokens ?? usage.inputTokens ?? 0,
|
||||
outputTokens: totalUsage.outputTokens ?? usage.outputTokens ?? 0,
|
||||
inputTokens: firstFiniteNumber(
|
||||
totalUsage.inputTokens,
|
||||
(usage as any).inputTokens,
|
||||
(usage as any).promptTokens,
|
||||
(usage as any).prompt_tokens,
|
||||
rawUsage?.prompt_tokens,
|
||||
rawUsage?.input_tokens,
|
||||
),
|
||||
outputTokens: firstFiniteNumber(
|
||||
totalUsage.outputTokens,
|
||||
(usage as any).outputTokens,
|
||||
(usage as any).completionTokens,
|
||||
(usage as any).completion_tokens,
|
||||
rawUsage?.completion_tokens,
|
||||
rawUsage?.output_tokens,
|
||||
),
|
||||
}
|
||||
const { chunk } = normalizeProviderUsage({
|
||||
provider: "openrouter",
|
||||
|
|
|
|||
|
|
@ -29,14 +29,20 @@ const OPENAI_BASE_PROFILE: UsageProfile = {
|
|||
deriveNonCachedInputFromTotalMinusCache: true,
|
||||
metrics: {
|
||||
inputTokensTotal: {
|
||||
usage: ["inputTokens"],
|
||||
usage: ["inputTokens", "promptTokens", "prompt_tokens"],
|
||||
raw: ["input_tokens", "prompt_tokens"],
|
||||
},
|
||||
outputTokens: {
|
||||
usage: ["outputTokens"],
|
||||
usage: ["outputTokens", "completionTokens", "completion_tokens"],
|
||||
raw: ["output_tokens", "completion_tokens"],
|
||||
},
|
||||
cacheWriteTokens: {
|
||||
usage: ["inputTokenDetails.cacheWriteTokens", "cacheCreationInputTokens", "cache_creation_input_tokens"],
|
||||
raw: ["cache_creation_input_tokens", "cacheCreationInputTokens"],
|
||||
raw: [
|
||||
"cache_creation_input_tokens",
|
||||
"cacheCreationInputTokens",
|
||||
"prompt_tokens_details.cache_write_tokens",
|
||||
],
|
||||
},
|
||||
cacheReadTokens: {
|
||||
usage: [
|
||||
|
|
@ -47,6 +53,7 @@ const OPENAI_BASE_PROFILE: UsageProfile = {
|
|||
],
|
||||
raw: [
|
||||
"input_tokens_details.cached_tokens",
|
||||
"prompt_tokens_details.cached_tokens",
|
||||
"cache_read_input_tokens",
|
||||
"cacheReadInputTokens",
|
||||
"cached_tokens",
|
||||
|
|
@ -54,10 +61,12 @@ const OPENAI_BASE_PROFILE: UsageProfile = {
|
|||
},
|
||||
reasoningTokens: {
|
||||
usage: ["outputTokenDetails.reasoningTokens", "reasoningTokens", "details.reasoningTokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens", "completion_tokens_details.reasoning_tokens"],
|
||||
},
|
||||
totalCostCandidate: {
|
||||
providerMetadata: ["gateway.cost"],
|
||||
usage: ["cost"],
|
||||
raw: ["cost"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -69,7 +78,8 @@ const ANTHROPIC_BASE_PROFILE: UsageProfile = {
|
|||
deriveNonCachedInputFromTotalMinusCache: true,
|
||||
metrics: {
|
||||
inputTokensTotal: {
|
||||
usage: ["inputTokens"],
|
||||
usage: ["inputTokens", "promptTokens", "prompt_tokens"],
|
||||
raw: ["input_tokens", "prompt_tokens"],
|
||||
},
|
||||
inputTokensNonCached: {
|
||||
usage: ["inputTokenDetails.noCacheTokens"],
|
||||
|
|
@ -77,14 +87,14 @@ const ANTHROPIC_BASE_PROFILE: UsageProfile = {
|
|||
raw: ["input_tokens"],
|
||||
},
|
||||
outputTokens: {
|
||||
usage: ["outputTokens"],
|
||||
usage: ["outputTokens", "completionTokens", "completion_tokens"],
|
||||
providerMetadata: ["anthropic.usage.output_tokens"],
|
||||
raw: ["output_tokens"],
|
||||
raw: ["output_tokens", "completion_tokens"],
|
||||
},
|
||||
cacheWriteTokens: {
|
||||
providerMetadata: ["anthropic.usage.cache_creation_input_tokens", "anthropic.cacheCreationInputTokens"],
|
||||
usage: ["inputTokenDetails.cacheWriteTokens", "cacheCreationInputTokens", "cache_creation_input_tokens"],
|
||||
raw: ["cache_creation_input_tokens", "cacheCreationInputTokens"],
|
||||
raw: ["cache_creation_input_tokens", "cacheCreationInputTokens", "prompt_tokens_details.cache_write_tokens"],
|
||||
},
|
||||
cacheReadTokens: {
|
||||
providerMetadata: [
|
||||
|
|
@ -98,19 +108,22 @@ const ANTHROPIC_BASE_PROFILE: UsageProfile = {
|
|||
"details.cachedInputTokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: [
|
||||
"cache_read_input_tokens",
|
||||
"cacheReadInputTokens",
|
||||
"input_tokens_details.cached_tokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: [
|
||||
"cache_read_input_tokens",
|
||||
"cacheReadInputTokens",
|
||||
"input_tokens_details.cached_tokens",
|
||||
"prompt_tokens_details.cached_tokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
},
|
||||
reasoningTokens: {
|
||||
usage: ["outputTokenDetails.reasoningTokens", "reasoningTokens", "details.reasoningTokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens", "completion_tokens_details.reasoning_tokens"],
|
||||
},
|
||||
totalCostCandidate: {
|
||||
providerMetadata: ["gateway.cost"],
|
||||
usage: ["cost"],
|
||||
raw: ["cost"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -144,7 +157,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
"details.cachedInputTokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: ["input_tokens_details.cached_tokens", "cache_read_input_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cache_read_input_tokens", "cached_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -200,12 +213,12 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
"details.cachedInputTokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
reasoningTokens: {
|
||||
providerMetadata: ["openai.reasoningTokens"],
|
||||
usage: ["outputTokenDetails.reasoningTokens", "reasoningTokens", "details.reasoningTokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens", "completion_tokens_details.reasoning_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -216,12 +229,12 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["openai.cachedPromptTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
reasoningTokens: {
|
||||
providerMetadata: ["openai.reasoningTokens"],
|
||||
usage: ["outputTokenDetails.reasoningTokens", "reasoningTokens", "details.reasoningTokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens", "completion_tokens_details.reasoning_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -232,12 +245,12 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["openai.cachedPromptTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
reasoningTokens: {
|
||||
providerMetadata: ["openai.reasoningTokens"],
|
||||
usage: ["outputTokenDetails.reasoningTokens", "reasoningTokens", "details.reasoningTokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens", "completion_tokens_details.reasoning_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -270,7 +283,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
"details.cachedInputTokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
reasoningTokens: {
|
||||
providerMetadata: [
|
||||
|
|
@ -279,7 +292,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
"openrouter.output_tokens_details.reasoning_tokens",
|
||||
],
|
||||
usage: ["outputTokenDetails.reasoningTokens", "reasoningTokens", "details.reasoningTokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens"],
|
||||
raw: ["output_tokens_details.reasoning_tokens", "completion_tokens_details.reasoning_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -298,7 +311,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["requesty.usage.cachedTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -317,7 +330,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["fireworks.promptCacheHitTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -336,7 +349,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["deepseek.promptCacheHitTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -347,7 +360,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["xai.cachedPromptTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -358,7 +371,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["azure.promptCacheHitTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
cacheWriteTokens: {
|
||||
usage: ["inputTokenDetails.cacheWriteTokens"],
|
||||
|
|
@ -380,7 +393,7 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
cacheReadTokens: {
|
||||
providerMetadata: ["sambanova.promptCacheHitTokens"],
|
||||
usage: ["inputTokenDetails.cacheReadTokens", "cachedInputTokens", "details.cachedInputTokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "cached_tokens"],
|
||||
raw: ["input_tokens_details.cached_tokens", "prompt_tokens_details.cached_tokens", "cached_tokens"],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -451,7 +464,12 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
"details.cachedInputTokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: ["input_tokens_details.cached_tokens", "cache_read_input_tokens", "cached_tokens"],
|
||||
raw: [
|
||||
"input_tokens_details.cached_tokens",
|
||||
"prompt_tokens_details.cached_tokens",
|
||||
"cache_read_input_tokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
},
|
||||
totalCostCandidate: {
|
||||
providerMetadata: ["roo.cost", "gateway.cost"],
|
||||
|
|
@ -490,7 +508,12 @@ const PROFILES: Record<string, Partial<UsageProfile>> = {
|
|||
"details.cachedInputTokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
raw: ["input_tokens_details.cached_tokens", "cache_read_input_tokens", "cached_tokens"],
|
||||
raw: [
|
||||
"input_tokens_details.cached_tokens",
|
||||
"prompt_tokens_details.cached_tokens",
|
||||
"cache_read_input_tokens",
|
||||
"cached_tokens",
|
||||
],
|
||||
},
|
||||
totalCostCandidate: {
|
||||
providerMetadata: ["gateway.cost"],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue