import type { SDKResultMessage } from "@anthropic-ai/claude-agent-sdk"; import type { ProviderRuntimeTurnStatus, TurnTokenUsage } from "@t3tools/contracts"; function finiteNonNegativeInteger(value: unknown): number | undefined { return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.round(value) : undefined; } export function normalizeClaudeTurnTokenUsage( result: { readonly subtype: SDKResultMessage["subtype"]; readonly usage?: unknown } | undefined, hasSubagents: boolean, terminalStatus: ProviderRuntimeTurnStatus, ): TurnTokenUsage { const usage = result?.usage as Record | undefined; if (!usage) { return { usageStatus: "unavailable", usageScope: "main_agent", hasSubagents, }; } const uncachedInputTokens = finiteNonNegativeInteger(usage.input_tokens); const cachedInputTokens = finiteNonNegativeInteger(usage.cache_read_input_tokens); const cacheCreationTokens = finiteNonNegativeInteger(usage.cache_creation_input_tokens); const rawOutputTokens = finiteNonNegativeInteger(usage.output_tokens); const outputDetails = usage.output_tokens_details as Record | undefined; const thinkingTokens = finiteNonNegativeInteger(outputDetails?.thinking_tokens); const cachedInputContribution = usage.cache_read_input_tokens == null ? 0 : cachedInputTokens; const cacheCreationContribution = usage.cache_creation_input_tokens == null ? 0 : cacheCreationTokens; const inputTokens = uncachedInputTokens !== undefined && cachedInputContribution !== undefined && cacheCreationContribution !== undefined ? uncachedInputTokens + cachedInputContribution + cacheCreationContribution : undefined; const hasKnownUsage = uncachedInputTokens !== undefined || cachedInputTokens !== undefined || cacheCreationTokens !== undefined || rawOutputTokens !== undefined; const hasPositiveUsage = (uncachedInputTokens ?? 0) + (cachedInputTokens ?? 0) + (cacheCreationTokens ?? 0) + (rawOutputTokens ?? 0) > 0; if (!hasKnownUsage || (result?.subtype !== "success" && !hasPositiveUsage)) { return { usageStatus: "unavailable", usageScope: "main_agent", hasSubagents, }; } const commonUsage = { usageScope: "main_agent", ...(cachedInputTokens !== undefined ? { cachedInputTokens } : {}), ...(cacheCreationTokens !== undefined ? { cacheCreationTokens } : {}), ...(thinkingTokens !== undefined && rawOutputTokens !== undefined ? { reasoningTokens: Math.min(rawOutputTokens, thinkingTokens) } : {}), hasSubagents, } as const; if ( terminalStatus === "completed" && result?.subtype === "success" && inputTokens !== undefined && rawOutputTokens !== undefined ) { return { ...commonUsage, usageStatus: "complete", inputTokens, outputTokens: rawOutputTokens, }; } return { ...commonUsage, usageStatus: "partial", ...(inputTokens !== undefined ? { inputTokens } : {}), ...(rawOutputTokens !== undefined ? { outputTokens: rawOutputTokens } : {}), }; }