Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
24 kB · 788 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789import { feature } from 'bun:bundle'import { APIError } from '@anthropic-ai/sdk'import type { BetaStopReason, BetaUsage as Usage,} from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'import { addToTotalDurationState, consumePostCompaction, getIsNonInteractiveSession, getLastApiCompletionTimestamp, getTeleportedSessionInfo, markFirstTeleportMessageLogged, setLastApiCompletionTimestamp,} from 'src/bootstrap/state.js'import type { QueryChainTracking } from 'src/Tool.js'import { isConnectorTextBlock } from 'src/types/connectorText.js'import type { AssistantMessage } from 'src/types/message.js'import { logForDebugging } from 'src/utils/debug.js'import type { EffortLevel } from 'src/utils/effort.js'import { logError } from 'src/utils/log.js'import { getAPIProviderForStatsig } from 'src/utils/model/providers.js'import type { PermissionMode } from 'src/utils/permissions/PermissionMode.js'import { jsonStringify } from 'src/utils/slowOperations.js'import { logOTelEvent } from 'src/utils/telemetry/events.js'import { endLLMRequestSpan, isBetaTracingEnabled, type Span,} from 'src/utils/telemetry/sessionTracing.js'import type { NonNullableUsage } from '../../entrypoints/sdk/sdkUtilityTypes.js'import { consumeInvokingRequestId } from '../../utils/agentContext.js'import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent,} from '../analytics/index.js'import { sanitizeToolNameForAnalytics } from '../analytics/metadata.js'import { EMPTY_USAGE } from './emptyUsage.js'import { classifyAPIError } from './errors.js'import { extractConnectionErrorDetails } from './errorUtils.js'
export type { NonNullableUsage }export { EMPTY_USAGE }
// Strategy used for global prompt cachingexport type GlobalCacheStrategy = 'tool_based' | 'system_prompt' | 'none'
function getErrorMessage(error: unknown): string { if (error instanceof APIError) { const body = error.error as { error?: { message?: string } } | undefined if (body?.error?.message) return body.error.message } return error instanceof Error ? error.message : String(error)}
type KnownGateway = | 'litellm' | 'helicone' | 'portkey' | 'cloudflare-ai-gateway' | 'kong' | 'braintrust' | 'databricks'
// Gateway fingerprints for detecting AI gateways from response headersconst GATEWAY_FINGERPRINTS: Partial< Record<KnownGateway, { prefixes: string[] }>> = { // https://docs.litellm.ai/docs/proxy/response_headers litellm: { prefixes: ['x-litellm-'], }, // https://docs.helicone.ai/helicone-headers/header-directory helicone: { prefixes: ['helicone-'], }, // https://portkey.ai/docs/api-reference/response-schema portkey: { prefixes: ['x-portkey-'], }, // https://developers.cloudflare.com/ai-gateway/evaluations/add-human-feedback-api/ 'cloudflare-ai-gateway': { prefixes: ['cf-aig-'], }, // https://developer.konghq.com/ai-gateway/ — X-Kong-Upstream-Latency, X-Kong-Proxy-Latency kong: { prefixes: ['x-kong-'], }, // https://www.braintrust.dev/docs/guides/proxy — x-bt-used-endpoint, x-bt-cached braintrust: { prefixes: ['x-bt-'], },}
// Gateways that use provider-owned domains (not self-hosted), so the// ANTHROPIC_BASE_URL hostname is a reliable signal even without a// distinctive response header.const GATEWAY_HOST_SUFFIXES: Partial<Record<KnownGateway, string[]>> = { // https://docs.databricks.com/aws/en/ai-gateway/ databricks: [ '.cloud.databricks.com', '.azuredatabricks.net', '.gcp.databricks.com', ],}
function detectGateway({ headers, baseUrl,}: { headers?: globalThis.Headers baseUrl?: string}): KnownGateway | undefined { if (headers) { // Header names are already lowercase from the Headers API const headerNames: string[] = [] headers.forEach((_, key) => headerNames.push(key)) for (const [gw, { prefixes }] of Object.entries(GATEWAY_FINGERPRINTS)) { if (prefixes.some(p => headerNames.some(h => h.startsWith(p)))) { return gw as KnownGateway } } }
if (baseUrl) { try { const host = new URL(baseUrl).hostname.toLowerCase() for (const [gw, suffixes] of Object.entries(GATEWAY_HOST_SUFFIXES)) { if (suffixes.some(s => host.endsWith(s))) { return gw as KnownGateway } } } catch { // malformed URL — ignore } }
return undefined}
function getAnthropicEnvMetadata() { return { ...(process.env.ANTHROPIC_BASE_URL ? { baseUrl: process.env .ANTHROPIC_BASE_URL as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(process.env.ANTHROPIC_MODEL ? { envModel: process.env .ANTHROPIC_MODEL as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(process.env.ANTHROPIC_SMALL_FAST_MODEL ? { envSmallFastModel: process.env .ANTHROPIC_SMALL_FAST_MODEL as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), }}
function getBuildAgeMinutes(): number | undefined { if (!MACRO.BUILD_TIME) return undefined const buildTime = new Date(MACRO.BUILD_TIME).getTime() if (isNaN(buildTime)) return undefined return Math.floor((Date.now() - buildTime) / 60000)}
export function logAPIQuery({ model, messagesLength, temperature, betas, permissionMode, querySource, queryTracking, thinkingType, effortValue, fastMode, previousRequestId,}: { model: string messagesLength: number temperature: number betas?: string[] permissionMode?: PermissionMode querySource: string queryTracking?: QueryChainTracking thinkingType?: 'adaptive' | 'enabled' | 'disabled' effortValue?: EffortLevel | null fastMode?: boolean previousRequestId?: string | null}): void { logEvent('tengu_api_query', { model: model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, messagesLength, temperature: temperature, provider: getAPIProviderForStatsig(), buildAgeMins: getBuildAgeMinutes(), ...(betas?.length ? { betas: betas.join( ',', ) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), permissionMode: permissionMode as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, querySource: querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, ...(queryTracking ? { queryChainId: queryTracking.chainId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, queryDepth: queryTracking.depth, } : {}), thinkingType: thinkingType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, effortValue: effortValue as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, fastMode, ...(previousRequestId ? { previousRequestId: previousRequestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...getAnthropicEnvMetadata(), })}
export function logAPIError({ error, model, messageCount, messageTokens, durationMs, durationMsIncludingRetries, attempt, requestId, clientRequestId, didFallBackToNonStreaming, promptCategory, headers, queryTracking, querySource, llmSpan, fastMode, previousRequestId,}: { error: unknown model: string messageCount: number messageTokens?: number durationMs: number durationMsIncludingRetries: number attempt: number requestId?: string | null /** Client-generated ID sent as x-client-request-id header (survives timeouts) */ clientRequestId?: string didFallBackToNonStreaming?: boolean promptCategory?: string headers?: globalThis.Headers queryTracking?: QueryChainTracking querySource?: string /** The span from startLLMRequestSpan - pass this to correctly match responses to requests */ llmSpan?: Span fastMode?: boolean previousRequestId?: string | null}): void { const gateway = detectGateway({ headers: error instanceof APIError && error.headers ? error.headers : headers, baseUrl: process.env.ANTHROPIC_BASE_URL, })
const errStr = getErrorMessage(error) const status = error instanceof APIError ? String(error.status) : undefined const errorType = classifyAPIError(error)
// Log detailed connection error info to debug logs (visible via --debug) const connectionDetails = extractConnectionErrorDetails(error) if (connectionDetails) { const sslLabel = connectionDetails.isSSLError ? ' (SSL error)' : '' logForDebugging( `Connection error details: code=${connectionDetails.code}${sslLabel}, message=${connectionDetails.message}`, { level: 'error' }, ) }
const invocation = consumeInvokingRequestId()
if (clientRequestId) { logForDebugging( `API error x-client-request-id=${clientRequestId} (give this to the API team for server-log lookup)`, { level: 'error' }, ) }
logError(error as Error) logEvent('tengu_api_error', { model: model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, error: errStr as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, status: status as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, errorType: errorType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, messageCount, messageTokens, durationMs, durationMsIncludingRetries, attempt, provider: getAPIProviderForStatsig(), requestId: (requestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) || undefined, ...(invocation ? { invokingRequestId: invocation.invokingRequestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, invocationKind: invocation.invocationKind as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), clientRequestId: (clientRequestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) || undefined, didFallBackToNonStreaming, ...(promptCategory ? { promptCategory: promptCategory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(gateway ? { gateway: gateway as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(queryTracking ? { queryChainId: queryTracking.chainId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, queryDepth: queryTracking.depth, } : {}), ...(querySource ? { querySource: querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), fastMode, ...(previousRequestId ? { previousRequestId: previousRequestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...getAnthropicEnvMetadata(), })
// Log API error event for OTLP void logOTelEvent('api_error', { model: model, error: errStr, status_code: String(status), duration_ms: String(durationMs), attempt: String(attempt), speed: fastMode ? 'fast' : 'normal', })
// Pass the span to correctly match responses to requests when beta tracing is enabled endLLMRequestSpan(llmSpan, { success: false, statusCode: status ? parseInt(status) : undefined, error: errStr, attempt, })
// Log first error for teleported sessions (reliability tracking) const teleportInfo = getTeleportedSessionInfo() if (teleportInfo?.isTeleported && !teleportInfo.hasLoggedFirstMessage) { logEvent('tengu_teleport_first_message_error', { session_id: teleportInfo.sessionId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, error_type: errorType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }) markFirstTeleportMessageLogged() }}
function logAPISuccess({ model, preNormalizedModel, messageCount, messageTokens, usage, durationMs, durationMsIncludingRetries, attempt, ttftMs, requestId, stopReason, costUSD, didFallBackToNonStreaming, querySource, gateway, queryTracking, permissionMode, globalCacheStrategy, textContentLength, thinkingContentLength, toolUseContentLengths, connectorTextBlockCount, fastMode, previousRequestId, betas,}: { model: string preNormalizedModel: string messageCount: number messageTokens: number usage: Usage durationMs: number durationMsIncludingRetries: number attempt: number ttftMs: number | null requestId: string | null stopReason: BetaStopReason | null costUSD: number didFallBackToNonStreaming: boolean querySource: string gateway?: KnownGateway queryTracking?: QueryChainTracking permissionMode?: PermissionMode globalCacheStrategy?: GlobalCacheStrategy textContentLength?: number thinkingContentLength?: number toolUseContentLengths?: Record<string, number> connectorTextBlockCount?: number fastMode?: boolean previousRequestId?: string | null betas?: string[]}): void { const isNonInteractiveSession = getIsNonInteractiveSession() const isPostCompaction = consumePostCompaction() const hasPrintFlag = process.argv.includes('-p') || process.argv.includes('--print')
const now = Date.now() const lastCompletion = getLastApiCompletionTimestamp() const timeSinceLastApiCallMs = lastCompletion !== null ? now - lastCompletion : undefined
const invocation = consumeInvokingRequestId()
logEvent('tengu_api_success', { model: model as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, ...(preNormalizedModel !== model ? { preNormalizedModel: preNormalizedModel as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(betas?.length ? { betas: betas.join( ',', ) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), messageCount, messageTokens, inputTokens: usage.input_tokens, outputTokens: usage.output_tokens, cachedInputTokens: usage.cache_read_input_tokens ?? 0, uncachedInputTokens: usage.cache_creation_input_tokens ?? 0, durationMs: durationMs, durationMsIncludingRetries: durationMsIncludingRetries, attempt: attempt, ttftMs: ttftMs ?? undefined, buildAgeMins: getBuildAgeMinutes(), provider: getAPIProviderForStatsig(), requestId: (requestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) ?? undefined, ...(invocation ? { invokingRequestId: invocation.invokingRequestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, invocationKind: invocation.invocationKind as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), stop_reason: (stopReason as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) ?? undefined, costUSD, didFallBackToNonStreaming, isNonInteractiveSession, print: hasPrintFlag, isTTY: process.stdout.isTTY ?? false, querySource: querySource as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, ...(gateway ? { gateway: gateway as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(queryTracking ? { queryChainId: queryTracking.chainId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, queryDepth: queryTracking.depth, } : {}), permissionMode: permissionMode as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, ...(globalCacheStrategy ? { globalCacheStrategy: globalCacheStrategy as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(textContentLength !== undefined ? ({ textContentLength, } as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) : {}), ...(thinkingContentLength !== undefined ? ({ thinkingContentLength, } as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) : {}), ...(toolUseContentLengths !== undefined ? ({ toolUseContentLengths: jsonStringify( toolUseContentLengths, ) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) : {}), ...(connectorTextBlockCount !== undefined ? ({ connectorTextBlockCount, } as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS) : {}), fastMode, // Log cache_deleted_input_tokens for cache editing analysis. Casts needed // because the field is intentionally not on NonNullableUsage (excluded from // external builds). Set by updateUsage() when cache editing is active. ...(feature('CACHED_MICROCOMPACT') && ((usage as unknown as { cache_deleted_input_tokens?: number }) .cache_deleted_input_tokens ?? 0) > 0 ? { cacheDeletedInputTokens: ( usage as unknown as { cache_deleted_input_tokens: number } ).cache_deleted_input_tokens, } : {}), ...(previousRequestId ? { previousRequestId: previousRequestId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, } : {}), ...(isPostCompaction ? { isPostCompaction } : {}), ...getAnthropicEnvMetadata(), timeSinceLastApiCallMs, })
setLastApiCompletionTimestamp(now)}
export function logAPISuccessAndDuration({ model, preNormalizedModel, start, startIncludingRetries, ttftMs, usage, attempt, messageCount, messageTokens, requestId, stopReason, didFallBackToNonStreaming, querySource, headers, costUSD, queryTracking, permissionMode, newMessages, llmSpan, globalCacheStrategy, requestSetupMs, attemptStartTimes, fastMode, previousRequestId, betas,}: { model: string preNormalizedModel: string start: number startIncludingRetries: number ttftMs: number | null usage: NonNullableUsage attempt: number messageCount: number messageTokens: number requestId: string | null stopReason: BetaStopReason | null didFallBackToNonStreaming: boolean querySource: string headers?: globalThis.Headers costUSD: number queryTracking?: QueryChainTracking permissionMode?: PermissionMode /** Assistant messages from the response - used to extract model_output and thinking_output * when beta tracing is enabled */ newMessages?: AssistantMessage[] /** The span from startLLMRequestSpan - pass this to correctly match responses to requests */ llmSpan?: Span /** Strategy used for global prompt caching: 'tool_based', 'system_prompt', or 'none' */ globalCacheStrategy?: GlobalCacheStrategy /** Time spent in pre-request setup before the successful attempt */ requestSetupMs?: number /** Timestamps (Date.now()) of each attempt start — used for retry sub-spans in Perfetto */ attemptStartTimes?: number[] fastMode?: boolean /** Request ID from the previous API call in this session */ previousRequestId?: string | null betas?: string[]}): void { const gateway = detectGateway({ headers, baseUrl: process.env.ANTHROPIC_BASE_URL, })
let textContentLength: number | undefined let thinkingContentLength: number | undefined let toolUseContentLengths: Record<string, number> | undefined let connectorTextBlockCount: number | undefined
if (newMessages) { let textLen = 0 let thinkingLen = 0 let hasToolUse = false const toolLengths: Record<string, number> = {} let connectorCount = 0
for (const msg of newMessages) { for (const block of msg.message.content) { if (block.type === 'text') { textLen += block.text.length } else if (feature('CONNECTOR_TEXT') && isConnectorTextBlock(block)) { connectorCount++ } else if (block.type === 'thinking') { thinkingLen += block.thinking.length } else if ( block.type === 'tool_use' || block.type === 'server_tool_use' || block.type === 'mcp_tool_use' ) { const inputLen = jsonStringify(block.input).length const sanitizedName = sanitizeToolNameForAnalytics(block.name) toolLengths[sanitizedName] = (toolLengths[sanitizedName] ?? 0) + inputLen hasToolUse = true } } }
textContentLength = textLen thinkingContentLength = thinkingLen > 0 ? thinkingLen : undefined toolUseContentLengths = hasToolUse ? toolLengths : undefined connectorTextBlockCount = connectorCount > 0 ? connectorCount : undefined }
const durationMs = Date.now() - start const durationMsIncludingRetries = Date.now() - startIncludingRetries addToTotalDurationState(durationMsIncludingRetries, durationMs)
logAPISuccess({ model, preNormalizedModel, messageCount, messageTokens, usage, durationMs, durationMsIncludingRetries, attempt, ttftMs, requestId, stopReason, costUSD, didFallBackToNonStreaming, querySource, gateway, queryTracking, permissionMode, globalCacheStrategy, textContentLength, thinkingContentLength, toolUseContentLengths, connectorTextBlockCount, fastMode, previousRequestId, betas, }) // Log API request event for OTLP void logOTelEvent('api_request', { model, input_tokens: String(usage.input_tokens), output_tokens: String(usage.output_tokens), cache_read_tokens: String(usage.cache_read_input_tokens), cache_creation_tokens: String(usage.cache_creation_input_tokens), cost_usd: String(costUSD), duration_ms: String(durationMs), speed: fastMode ? 'fast' : 'normal', })
// Extract model output, thinking output, and tool call flag when beta tracing is enabled let modelOutput: string | undefined let thinkingOutput: string | undefined let hasToolCall: boolean | undefined
if (isBetaTracingEnabled() && newMessages) { // Model output - visible to all users modelOutput = newMessages .flatMap(m => m.message.content .filter(c => c.type === 'text') .map(c => (c as { type: 'text'; text: string }).text), ) .join('\n') || undefined
// Thinking output - Ant-only (build-time gated) if (process.env.USER_TYPE === 'ant') { thinkingOutput = newMessages .flatMap(m => m.message.content .filter(c => c.type === 'thinking') .map(c => (c as { type: 'thinking'; thinking: string }).thinking), ) .join('\n') || undefined }
// Check if any tool_use blocks were in the output hasToolCall = newMessages.some(m => m.message.content.some(c => c.type === 'tool_use'), ) }
// Pass the span to correctly match responses to requests when beta tracing is enabled endLLMRequestSpan(llmSpan, { success: true, inputTokens: usage.input_tokens, outputTokens: usage.output_tokens, cacheReadTokens: usage.cache_read_input_tokens, cacheCreationTokens: usage.cache_creation_input_tokens, attempt, modelOutput, thinkingOutput, hasToolCall, ttftMs: ttftMs ?? undefined, requestSetupMs, attemptStartTimes, })
// Log first successful message for teleported sessions (reliability tracking) const teleportInfo = getTeleportedSessionInfo() if (teleportInfo?.isTeleported && !teleportInfo.hasLoggedFirstMessage) { logEvent('tengu_teleport_first_message_success', { session_id: teleportInfo.sessionId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, }) markFirstTeleportMessageLogged() }}