* Aggregate provider metadata across all steps. * * CRITICAL: For multi-step tool calls, cache creation tokens are reported per-step. * streamResult.providerMetadata only contains the LAST step's metadata, missing * cache creation tokens from earlier steps. We must sum across all steps.
(
streamInfo: WorkspaceStreamInfo,
timeoutMs = 1000
)
| 1048 | * cache creation tokens from earlier steps. We must sum across all steps. |
| 1049 | */ |
| 1050 | private async getAggregatedProviderMetadata( |
| 1051 | streamInfo: WorkspaceStreamInfo, |
| 1052 | timeoutMs = 1000 |
| 1053 | ): Promise<Record<string, unknown> | undefined> { |
| 1054 | try { |
| 1055 | const steps = await Promise.race([ |
| 1056 | streamInfo.streamResult.steps, |
| 1057 | new Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), timeoutMs)), |
| 1058 | ]); |
| 1059 | |
| 1060 | if (!steps || steps.length === 0) { |
| 1061 | // Fall back to last step's provider metadata |
| 1062 | return await streamInfo.streamResult.providerMetadata; |
| 1063 | } |
| 1064 | |
| 1065 | // If only one step, no aggregation needed |
| 1066 | if (steps.length === 1) { |
| 1067 | return steps[0].providerMetadata; |
| 1068 | } |
| 1069 | |
| 1070 | // Aggregate cache creation tokens across all steps |
| 1071 | let totalCacheCreationTokens = 0; |
| 1072 | let lastStepMetadata: Record<string, unknown> | undefined; |
| 1073 | |
| 1074 | for (const step of steps) { |
| 1075 | lastStepMetadata = step.providerMetadata; |
| 1076 | const anthropicMeta = step.providerMetadata?.anthropic as |
| 1077 | | { cacheCreationInputTokens?: number } |
| 1078 | | undefined; |
| 1079 | if (anthropicMeta?.cacheCreationInputTokens) { |
| 1080 | totalCacheCreationTokens += anthropicMeta.cacheCreationInputTokens; |
| 1081 | } |
| 1082 | } |
| 1083 | |
| 1084 | // If no cache creation tokens found, just return last step's metadata |
| 1085 | if (totalCacheCreationTokens === 0) { |
| 1086 | return lastStepMetadata; |
| 1087 | } |
| 1088 | |
| 1089 | // Merge aggregated cache creation tokens into the last step's metadata |
| 1090 | return { |
| 1091 | ...lastStepMetadata, |
| 1092 | anthropic: { |
| 1093 | ...(lastStepMetadata?.anthropic as Record<string, unknown> | undefined), |
| 1094 | cacheCreationInputTokens: totalCacheCreationTokens, |
| 1095 | }, |
| 1096 | }; |
| 1097 | } catch (error) { |
| 1098 | log.debug("Could not aggregate provider metadata:", error); |
| 1099 | return undefined; |
| 1100 | } |
| 1101 | } |
| 1102 | |
| 1103 | /** |
| 1104 | * Safely cancels an existing stream with proper cleanup |
no test coverage detected