const MIN_DURATION_MS = 100; type AssistantUsage = { output: number; }; type AssistantLikeMessage = { role: "assistant"; timestamp: number; duration?: number; usage: AssistantUsage; }; type MaybeAssistantMessage = { role?: string; timestamp?: number; duration?: number; usage?: { output?: number; }; }; function isAssistantMessage(message: MaybeAssistantMessage | undefined): message is AssistantLikeMessage { return ( message?.role === "assistant" && typeof message.timestamp === "number" && message.usage !== undefined && typeof message.usage.output === "number" ); } function getLastAssistantMessage(messages: ReadonlyArray): AssistantLikeMessage | null { for (let i = messages.length - 1; i >= 0; i--) { const message = messages[i]; if (isAssistantMessage(message)) { return message; } } return null; } export function calculateTokensPerSecond( messages: ReadonlyArray, isStreaming: boolean, nowMs: number = Date.now(), ): number | null { const assistant = getLastAssistantMessage(messages); if (!assistant) return null; const outputTokens = assistant.usage.output; if (!Number.isFinite(outputTokens) || outputTokens <= 0) return null; const resolvedDurationMs = typeof assistant.duration === "number" && Number.isFinite(assistant.duration) && assistant.duration > 0 ? assistant.duration : isStreaming ? nowMs - assistant.timestamp : null; if (resolvedDurationMs === null || resolvedDurationMs < MIN_DURATION_MS) return null; const tokensPerSecond = (outputTokens * 1000) / resolvedDurationMs; if (!Number.isFinite(tokensPerSecond) || tokensPerSecond <= 0) return null; return tokensPerSecond; }