@@ -34,9 +34,12 @@ export function extractAISpanData(
3434 const model = str ( gResponse . model ) ?? str ( gRequest . model ) ?? str ( aiModel . id ) ;
3535 if ( ! model ) return undefined ;
3636
37- // Prefer ai.usage (richer) over gen_ai.usage
38- const inputTokens = num ( aiUsage . inputTokens ) ?? num ( gUsage . input_tokens ) ?? 0 ;
39- const outputTokens = num ( aiUsage . outputTokens ) ?? num ( gUsage . output_tokens ) ?? 0 ;
37+ // Prefer ai.usage (richer) over gen_ai.usage.
38+ // Gateway/some providers emit promptTokens/completionTokens instead of inputTokens/outputTokens.
39+ const inputTokens =
40+ num ( aiUsage . inputTokens ) ?? num ( aiUsage . promptTokens ) ?? num ( gUsage . input_tokens ) ?? 0 ;
41+ const outputTokens =
42+ num ( aiUsage . outputTokens ) ?? num ( aiUsage . completionTokens ) ?? num ( gUsage . output_tokens ) ?? 0 ;
4043 const totalTokens = num ( aiUsage . totalTokens ) ?? inputTokens + outputTokens ;
4144
4245 const tokensPerSecond =
@@ -56,6 +59,7 @@ export function extractAISpanData(
5659 operationName : str ( gOperation . name ) ?? str ( ai . operationId ) ?? "" ,
5760 finishReason : str ( aiResponse . finishReason ) ,
5861 serviceTier : providerMeta ?. serviceTier ,
62+ resolvedProvider : providerMeta ?. resolvedProvider ,
5963 toolChoice : parseToolChoice ( aiPrompt . toolChoice ) ,
6064 toolCount : toolDefs ?. length ,
6165 messageCount : countMessages ( aiPrompt . messages ) ,
@@ -64,14 +68,16 @@ export function extractAISpanData(
6468 outputTokens,
6569 totalTokens,
6670 cachedTokens : num ( aiUsage . cachedInputTokens ) ?? num ( gUsage . cache_read_input_tokens ) ,
71+ cacheCreationTokens :
72+ num ( aiUsage . cacheCreationInputTokens ) ?? num ( gUsage . cache_creation_input_tokens ) ,
6773 reasoningTokens : num ( aiUsage . reasoningTokens ) ?? num ( gUsage . reasoning_tokens ) ,
6874 tokensPerSecond,
6975 msToFirstChunk : num ( aiResponse . msToFirstChunk ) ,
7076 durationMs,
7177 inputCost : num ( triggerLlm . input_cost ) ,
7278 outputCost : num ( triggerLlm . output_cost ) ,
7379 totalCost : num ( triggerLlm . total_cost ) ,
74- responseText : str ( aiResponse . text ) || undefined ,
80+ responseText : str ( aiResponse . text ) || str ( aiResponse . object ) || undefined ,
7581 toolDefinitions : toolDefs ,
7682 items : buildDisplayItems ( aiPrompt . messages , aiResponse . toolCalls , toolDefs ) ,
7783 } ;
@@ -417,18 +423,38 @@ function parseToolDefinitions(raw: unknown): ToolDefinition[] | undefined {
417423
418424function parseProviderMetadata (
419425 raw : unknown
420- ) : { serviceTier ?: string } | undefined {
426+ ) : { serviceTier ?: string ; resolvedProvider ?: string ; gatewayCost ?: string } | undefined {
421427 if ( typeof raw !== "string" ) return undefined ;
422428 try {
423429 const parsed = JSON . parse ( raw ) ;
424430 if ( ! parsed || typeof parsed !== "object" ) return undefined ;
425431
432+ let serviceTier : string | undefined ;
433+ let resolvedProvider : string | undefined ;
434+ let gatewayCost : string | undefined ;
435+
426436 // Anthropic: { anthropic: { usage: { service_tier: "standard" } } }
427- const anthropic = rec ( parsed . anthropic ?? parsed ) ;
428- const usage = rec ( anthropic . usage ) ;
429- const serviceTier = str ( usage . service_tier ) ;
437+ const anthropic = rec ( parsed . anthropic ) ;
438+ serviceTier = str ( rec ( anthropic . usage ) . service_tier ) ;
439+
440+ // Azure/OpenAI: { azure: { serviceTier: "default" } } or { openai: { serviceTier: "..." } }
441+ if ( ! serviceTier ) {
442+ serviceTier = str ( rec ( parsed . azure ) . serviceTier ) ?? str ( rec ( parsed . openai ) . serviceTier ) ;
443+ }
444+
445+ // Gateway: { gateway: { routing: { finalProvider, resolvedProvider }, cost } }
446+ const gateway = rec ( parsed . gateway ) ;
447+ const routing = rec ( gateway . routing ) ;
448+ resolvedProvider = str ( routing . finalProvider ) ?? str ( routing . resolvedProvider ) ;
449+ gatewayCost = str ( gateway . cost ) ;
450+
451+ // OpenRouter: { openrouter: { provider: "xAI" } }
452+ if ( ! resolvedProvider ) {
453+ resolvedProvider = str ( rec ( parsed . openrouter ) . provider ) ;
454+ }
430455
431- return serviceTier ? { serviceTier } : undefined ;
456+ if ( ! serviceTier && ! resolvedProvider && ! gatewayCost ) return undefined ;
457+ return { serviceTier, resolvedProvider, gatewayCost } ;
432458 } catch {
433459 return undefined ;
434460 }
0 commit comments