refactor(llm): rename Usage.native to providerMetadata

Aligns the escape-hatch field name with `LLMEvent.providerMetadata` used
elsewhere in this package (and with AI SDK / pydantic-ai / LangChain
conventions for the same idea). Two parallel escape hatches having
different names was a wart.

The raw payload is now wrapped under the provider key — `{ openai: ... }`,
`{ anthropic: ... }`, `{ google: ... }`, `{ bedrock: ... }` — using the
existing `ProviderMetadata = Record<string, Record<string, unknown>>`
schema rather than a flat record. Same shape as
`LLMEvent.providerMetadata`, so consumers downstream can read both with
the same code.

Anthropic's `mergeUsage` merges the per-provider sub-record across
`message_start` and `message_delta` instead of spreading at the top level.
This commit is contained in:
Kit Langton 2026-05-10 21:42:09 -04:00
commit ab9b79ef88
10 changed files with 43 additions and 29 deletions

View file

@ -158,7 +158,7 @@ describe("Anthropic Messages route", () => {
outputTokens: 1,
nonCachedInputTokens: 5,
totalTokens: 6,
native: { input_tokens: 5, output_tokens: 1 },
providerMetadata: { anthropic: { input_tokens: 5, output_tokens: 1 } },
}),
},
])

View file

@ -218,12 +218,14 @@ describe("Gemini route", () => {
cacheReadInputTokens: 1,
reasoningTokens: 1,
totalTokens: 7,
native: {
promptTokenCount: 5,
candidatesTokenCount: 2,
totalTokenCount: 7,
thoughtsTokenCount: 1,
cachedContentTokenCount: 1,
providerMetadata: {
google: {
promptTokenCount: 5,
candidatesTokenCount: 2,
totalTokenCount: 7,
thoughtsTokenCount: 1,
cachedContentTokenCount: 1,
},
},
}),
},
@ -264,7 +266,7 @@ describe("Gemini route", () => {
outputTokens: 1,
nonCachedInputTokens: 5,
totalTokens: 6,
native: { promptTokenCount: 5, candidatesTokenCount: 1 },
providerMetadata: { google: { promptTokenCount: 5, candidatesTokenCount: 1 } },
}),
},
])

View file

@ -237,12 +237,14 @@ describe("OpenAI Chat route", () => {
cacheReadInputTokens: 1,
reasoningTokens: 0,
totalTokens: 7,
native: {
prompt_tokens: 5,
completion_tokens: 2,
total_tokens: 7,
prompt_tokens_details: { cached_tokens: 1 },
completion_tokens_details: { reasoning_tokens: 0 },
providerMetadata: {
openai: {
prompt_tokens: 5,
completion_tokens: 2,
total_tokens: 7,
prompt_tokens_details: { cached_tokens: 1 },
completion_tokens_details: { reasoning_tokens: 0 },
},
},
}),
},

View file

@ -349,12 +349,14 @@ describe("OpenAI Responses route", () => {
cacheReadInputTokens: 1,
reasoningTokens: 0,
totalTokens: 7,
native: {
input_tokens: 5,
output_tokens: 2,
total_tokens: 7,
input_tokens_details: { cached_tokens: 1 },
output_tokens_details: { reasoning_tokens: 0 },
providerMetadata: {
openai: {
input_tokens: 5,
output_tokens: 2,
total_tokens: 7,
input_tokens_details: { cached_tokens: 1 },
output_tokens_details: { reasoning_tokens: 0 },
},
},
}),
},
@ -417,7 +419,7 @@ describe("OpenAI Responses route", () => {
outputTokens: 1,
nonCachedInputTokens: 5,
totalTokens: 6,
native: { input_tokens: 5, output_tokens: 1 },
providerMetadata: { openai: { input_tokens: 5, output_tokens: 1 } },
}),
},
])