{"version":3,"sources":["../../src/voice/generation.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { AudioResampler } from '@livekit/rtc-node';\nimport { ThrowsPromise } from '@livekit/throws-transformer/throws';\nimport type { Span } from '@opentelemetry/api';\nimport { context as otelContext } from '@opentelemetry/api';\nimport type { ReadableStream, ReadableStreamDefaultReader } from 'stream/web';\nimport type { Instructions } from '../llm/chat_context.js';\nimport {\n  type ChatContext,\n  ChatMessage,\n  FunctionCall,\n  FunctionCallOutput,\n  isInstructions,\n} from '../llm/chat_context.js';\nimport type { ChatChunk } from '../llm/llm.js';\nimport { hasResponse } from '../llm/llm.js';\nimport {\n  type JSONObject,\n  type ToolChoice,\n  type ToolContext,\n  ToolError,\n  isAgentHandoff,\n  isFunctionTool,\n  isToolError,\n  sortedToolNames,\n} from '../llm/tool_context.js';\nimport { parseFunctionArguments } from '../llm/utils.js';\nimport { isZodSchema, parseZodSchema } from '../llm/zod-utils.js';\nimport { log } from '../log.js';\nimport { IdentityTransform } from '../stream/identity_transform.js';\nimport { genAI, traceTypes, tracer } from '../telemetry/index.js';\nimport { stripAllMarkup } from '../tts/provider_format.js';\nimport {\n  type FlushSentinel,\n  USERDATA_TIMED_TRANSCRIPT,\n  USERDATA_TTS_STARTED_TIME,\n  isFlushSentinel,\n} from '../types.js';\nimport {\n  type Aborted,\n  Future,\n  IdleTimeoutError,\n  Task,\n  shortuuid,\n  toError,\n  waitForAbort,\n  waitUntilTimeout,\n} from '../utils.js';\nimport {\n  type Agent,\n  type ModelSettings,\n  _setActivityTaskInfo,\n  functionCallStorage,\n  isStopResponse,\n} from './agent.js';\nimport type { ForwardOutput } from './agent_activity.ts';\nimport type { AgentSession } from './agent_session.js';\nimport {\n  AudioOutput,\n  type LLMNode,\n  type TTSNode,\n  type TextOutput,\n  type TimedString,\n  isTimedString,\n} from './io.js';\nimport { toSnakeCaseDeep } from './report.js';\nimport { RunContext } from './run_context.js';\nimport type { SpeechHandle } from './speech_handle.js';\nimport { getMockTool } from './testing/run_result.js';\nimport { ToolExecutor, buildExecutorMap } from './tool_executor.js';\nimport { type TextTransform, applyTextTransforms } from './transcription/text_transforms.js';\n\nexport const DEFAULT_TTS_READ_IDLE_TIMEOUT_MS = 10_000;\nexport const DEFAULT_FORWARD_AUDIO_IDLE_TIMEOUT_MS = 10_000;\nexport const RUNNING_TOOL_PLACEHOLDER = 'The tool call is still in progress.';\nexport const RUNNING_TOOL_PLACEHOLDER_KEY = '__lk_running_placeholder__';\nconst RUNNING_TOOL_PLACEHOLDER_OUTPUT_ID_PREFIX = 'lk_running_placeholder/';\n\nexport function _injectRunningToolCalls(\n  chatCtx: ChatContext,\n  runningCalls: Iterable<FunctionCall>,\n): void {\n  const existingCallIds = new Set(\n    chatCtx.items\n      .filter((item): item is FunctionCall => item.type === 'function_call')\n      .map((item) => item.callId),\n  );\n  const existingOutputIds = new Set(\n    chatCtx.items\n      .filter((item): item is FunctionCallOutput => item.type === 'function_call_output')\n      .map((item) => item.callId),\n  );\n\n  for (const runningCall of runningCalls) {\n    if (existingOutputIds.has(runningCall.callId)) continue;\n    if (!existingCallIds.has(runningCall.callId)) {\n      existingCallIds.add(runningCall.callId);\n      chatCtx.insert(\n        FunctionCall.create({\n          ...runningCall,\n          extra: { ...runningCall.extra, [RUNNING_TOOL_PLACEHOLDER_KEY]: true },\n        }),\n      );\n    }\n    existingOutputIds.add(runningCall.callId);\n    chatCtx.insert(\n      FunctionCallOutput.create({\n        id: `${RUNNING_TOOL_PLACEHOLDER_OUTPUT_ID_PREFIX}${runningCall.callId}`,\n        callId: runningCall.callId,\n        name: runningCall.name,\n        output: RUNNING_TOOL_PLACEHOLDER,\n        isError: false,\n        createdAt: runningCall.createdAt,\n      }),\n    );\n  }\n}\n\nexport function _stripRunningToolCalls(chatCtx: ChatContext): void {\n  const injectedCallIds = new Set(\n    chatCtx.items\n      .filter(\n        (item): item is FunctionCall =>\n          item.type === 'function_call' && item.extra[RUNNING_TOOL_PLACEHOLDER_KEY] === true,\n      )\n      .map((item) => item.callId),\n  );\n  chatCtx.items = chatCtx.items.filter(\n    (item) =>\n      !(\n        (item.type === 'function_call' && injectedCallIds.has(item.callId)) ||\n        (item.type === 'function_call_output' &&\n          item.id.startsWith(RUNNING_TOOL_PLACEHOLDER_OUTPUT_ID_PREFIX))\n      ),\n  );\n}\n\n/** @internal */\nexport class _LLMGenerationData {\n  generatedText: string = '';\n  generatedToolCalls: FunctionCall[];\n  generatedExtra: Record<string, unknown> = {};\n  id: string;\n  ttft?: number;\n\n  constructor(\n    public readonly textStream: ReadableStream<string | FlushSentinel>,\n    public readonly toolCallStream: ReadableStream<FunctionCall>,\n  ) {\n    this.id = shortuuid('item_');\n    this.generatedToolCalls = [];\n  }\n}\n\n/**\n * TTS generation data containing audio stream and optional timed transcripts.\n * @internal\n */\nexport interface _TTSGenerationData {\n  /** Audio frame stream from TTS */\n  audioStream: ReadableStream<AudioFrame>;\n  /**\n   * Future that resolves to a stream of timed transcripts, or null if TTS doesn't support it.\n   */\n  timedTextsFut: Future<ReadableStream<TimedString> | null, never>;\n  /** Time to first byte (set when first audio frame is received) */\n  ttfb?: number;\n}\n\n// TODO(brian): remove this class in favor of ToolOutput\nexport class _ToolOutput {\n  output: _JsOutput[];\n  firstToolFut: Future;\n\n  constructor() {\n    this.output = [];\n    this.firstToolFut = new Future();\n  }\n}\n\n// TODO(brian): remove this class in favor of ToolExecutionOutput\nexport class _SanitizedOutput {\n  toolCall: FunctionCall;\n  toolCallOutput?: FunctionCallOutput;\n  replyRequired: boolean;\n  agentTask?: Agent;\n\n  constructor(\n    toolCall: FunctionCall,\n    toolCallOutput: FunctionCallOutput | undefined,\n    replyRequired: boolean,\n    agentTask: Agent | undefined,\n  ) {\n    this.toolCall = toolCall;\n    this.toolCallOutput = toolCallOutput;\n    this.replyRequired = replyRequired;\n    this.agentTask = agentTask;\n  }\n\n  static create(params: {\n    toolCall: FunctionCall;\n    toolCallOutput?: FunctionCallOutput;\n    replyRequired?: boolean;\n    agentTask?: Agent;\n  }) {\n    const { toolCall, toolCallOutput, replyRequired = true, agentTask } = params;\n    return new _SanitizedOutput(toolCall, toolCallOutput, replyRequired, agentTask);\n  }\n}\n\nfunction isValidToolOutput(toolOutput: unknown): boolean {\n  const validTypes = ['string', 'number', 'boolean'];\n\n  if (validTypes.includes(typeof toolOutput)) {\n    return true;\n  }\n\n  if (toolOutput === undefined || toolOutput === null) {\n    return true;\n  }\n\n  if (Array.isArray(toolOutput)) {\n    return toolOutput.every(isValidToolOutput);\n  }\n\n  if (toolOutput instanceof Set) {\n    return Array.from(toolOutput).every(isValidToolOutput);\n  }\n\n  if (toolOutput instanceof Map) {\n    return Array.from(toolOutput.values()).every(isValidToolOutput);\n  }\n\n  if (toolOutput instanceof Object) {\n    return Object.entries(toolOutput).every(\n      ([key, value]) => validTypes.includes(typeof key) && isValidToolOutput(value),\n    );\n  }\n\n  return false;\n}\n\nexport class ToolExecutionOutput {\n  constructor(\n    public readonly toolCall: FunctionCall,\n    public readonly toolCallOutput: FunctionCallOutput | undefined,\n    public readonly agentTask: Agent | undefined,\n    public readonly rawOutput: unknown,\n    public readonly rawException: Error | undefined,\n    public readonly replyRequired: boolean,\n  ) {}\n\n  static create(params: {\n    toolCall: FunctionCall;\n    toolCallOutput?: FunctionCallOutput;\n    agentTask?: Agent;\n    rawOutput: unknown;\n    rawException?: Error;\n    replyRequired?: boolean;\n  }) {\n    const {\n      toolCall,\n      toolCallOutput,\n      agentTask,\n      rawOutput,\n      rawException,\n      replyRequired = true,\n    } = params;\n    return new ToolExecutionOutput(\n      toolCall,\n      toolCallOutput,\n      agentTask,\n      rawOutput,\n      rawException,\n      replyRequired,\n    );\n  }\n}\n\nexport interface ToolOutput {\n  output: ToolExecutionOutput[];\n  firstToolStartedFuture: Future<void>;\n}\n\n// TODO(brian): remove this class in favor of ToolExecutionOutput\nexport class _JsOutput {\n  toolCall: FunctionCall;\n  output: unknown;\n  exception?: Error;\n\n  #logger = log();\n\n  constructor(toolCall: FunctionCall, output: unknown, exception: Error | undefined) {\n    this.toolCall = toolCall;\n    this.output = output;\n    this.exception = exception;\n  }\n\n  static create(params: { toolCall: FunctionCall; output?: unknown; exception?: Error }) {\n    const { toolCall, output = undefined, exception = undefined } = params;\n    return new _JsOutput(toolCall, output, exception);\n  }\n\n  sanitize(): _SanitizedOutput {\n    if (isToolError(this.exception)) {\n      return _SanitizedOutput.create({\n        toolCall: FunctionCall.create({ ...this.toolCall }),\n        toolCallOutput: FunctionCallOutput.create({\n          name: this.toolCall.name,\n          callId: this.toolCall.callId,\n          output: this.exception.message,\n          isError: true,\n        }),\n      });\n    }\n\n    if (isStopResponse(this.exception)) {\n      return _SanitizedOutput.create({\n        toolCall: FunctionCall.create({ ...this.toolCall }),\n      });\n    }\n\n    if (this.exception !== undefined) {\n      return _SanitizedOutput.create({\n        toolCall: FunctionCall.create({ ...this.toolCall }),\n        toolCallOutput: FunctionCallOutput.create({\n          name: this.toolCall.name,\n          callId: this.toolCall.callId,\n          output: 'An internal error occurred while executing the tool.', // Don't send the actual error message, as it may contain sensitive information\n          isError: true,\n        }),\n      });\n    }\n\n    let agentTask: Agent | undefined = undefined;\n    let toolOutput: unknown = this.output;\n    if (isAgentHandoff(this.output)) {\n      agentTask = this.output.agent;\n      toolOutput = this.output.returns;\n    }\n\n    if (!isValidToolOutput(toolOutput)) {\n      this.#logger.error(\n        {\n          callId: this.toolCall.callId,\n          function: this.toolCall.name,\n        },\n        `AI function ${this.toolCall.name} returned an invalid output`,\n      );\n      return _SanitizedOutput.create({\n        toolCall: FunctionCall.create({ ...this.toolCall }),\n        toolCallOutput: undefined,\n      });\n    }\n\n    return _SanitizedOutput.create({\n      toolCall: FunctionCall.create({ ...this.toolCall }),\n      toolCallOutput: FunctionCallOutput.create({\n        name: this.toolCall.name,\n        callId: this.toolCall.callId,\n        output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output\n        isError: false,\n      }),\n      replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output\n      agentTask,\n    });\n  }\n}\n\nexport function createToolOutput(params: {\n  toolCall: FunctionCall;\n  output?: unknown;\n  exception?: Error;\n}): ToolExecutionOutput {\n  const { toolCall, output, exception } = params;\n  const logger = log();\n\n  // support returning Exception instead of raising them (for devex purposes inside evals)\n  let finalOutput = output;\n  let finalException = exception;\n  if (output instanceof Error) {\n    finalException = output;\n    finalOutput = undefined;\n  }\n\n  if (isToolError(finalException)) {\n    return ToolExecutionOutput.create({\n      toolCall: FunctionCall.create({ ...toolCall }),\n      toolCallOutput: FunctionCallOutput.create({\n        name: toolCall.name,\n        callId: toolCall.callId,\n        output: finalException.message,\n        isError: true,\n      }),\n      rawOutput: finalOutput,\n      rawException: finalException,\n    });\n  }\n\n  if (isStopResponse(finalException)) {\n    return ToolExecutionOutput.create({\n      toolCall: FunctionCall.create({ ...toolCall }),\n      rawOutput: finalOutput,\n      rawException: finalException,\n    });\n  }\n\n  if (finalException !== undefined) {\n    return ToolExecutionOutput.create({\n      toolCall: FunctionCall.create({ ...toolCall }),\n      toolCallOutput: FunctionCallOutput.create({\n        name: toolCall.name,\n        callId: toolCall.callId,\n        output: 'An internal error occurred', // Don't send the actual error message, as it may contain sensitive information\n        isError: true,\n      }),\n      rawOutput: finalOutput,\n      rawException: finalException,\n    });\n  }\n\n  let agentTask: Agent | undefined = undefined;\n  let toolOutput: unknown = finalOutput;\n  if (isAgentHandoff(finalOutput)) {\n    agentTask = finalOutput.agent;\n    toolOutput = finalOutput.returns;\n  }\n\n  if (!isValidToolOutput(toolOutput)) {\n    logger.error(\n      {\n        callId: toolCall.callId,\n        'lk.pii.output': finalOutput,\n      },\n      `AI function ${toolCall.name} returned an invalid output`,\n    );\n    return ToolExecutionOutput.create({\n      toolCall: FunctionCall.create({ ...toolCall }),\n      rawOutput: finalOutput,\n      rawException: finalException,\n    });\n  }\n\n  return ToolExecutionOutput.create({\n    toolCall: FunctionCall.create({ ...toolCall }),\n    toolCallOutput: FunctionCallOutput.create({\n      name: toolCall.name,\n      callId: toolCall.callId,\n      output: toolOutput !== undefined ? JSON.stringify(toolOutput) : '', // take the string representation of the output\n      isError: false,\n    }),\n    replyRequired: toolOutput !== undefined, // require a reply if the tool returned an output\n    agentTask,\n    rawOutput: finalOutput,\n    rawException: finalException,\n  });\n}\n\nexport const INSTRUCTIONS_MESSAGE_ID = 'lk.agent_task.instructions';\n\n/**\n * Update the instruction message in the chat context or insert a new one if missing.\n *\n * This function looks for an existing instruction message in the chat context using the identifier\n * 'INSTRUCTIONS_MESSAGE_ID'.\n *\n * @param options - The options for updating the instructions.\n * @param options.chatCtx - The chat context to update.\n * @param options.instructions - The instructions to add.\n * @param options.addIfMissing - Whether to add the instructions if they are missing.\n */\nexport function updateInstructions(options: {\n  chatCtx: ChatContext;\n  instructions: string | Instructions;\n  addIfMissing: boolean;\n}) {\n  const { chatCtx, instructions, addIfMissing } = options;\n\n  const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n  if (idx !== undefined) {\n    if (chatCtx.items[idx]!.type === 'message') {\n      // create a new instance to avoid mutating the original\n      chatCtx.items[idx] = ChatMessage.create({\n        id: INSTRUCTIONS_MESSAGE_ID,\n        role: 'system',\n        content: [instructions],\n        createdAt: chatCtx.items[idx]!.createdAt,\n      });\n    } else {\n      throw new Error('expected the instructions inside the chatCtx to be of type \"message\"');\n    }\n  } else if (addIfMissing) {\n    // insert the instructions at the beginning of the chat context\n    chatCtx.items.unshift(\n      ChatMessage.create({\n        id: INSTRUCTIONS_MESSAGE_ID,\n        role: 'system',\n        content: [instructions],\n      }),\n    );\n  }\n}\n\n/**\n * Apply the correct {@link Instructions} variant for the turn's input modality.\n *\n * Locates the instructions message (by {@link INSTRUCTIONS_MESSAGE_ID}) and,\n * if its content contains any {@link Instructions} entries, rebuilds the\n * message so each Instructions renders as the chosen variant. No-op when no\n * modality-aware instructions are present.\n */\nexport function applyInstructionsModality(\n  chatCtx: ChatContext,\n  options: { modality: 'audio' | 'text' },\n) {\n  const { modality } = options;\n  const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n  if (idx === undefined) return;\n\n  const item = chatCtx.items[idx]!;\n  if (item.type !== 'message') return;\n\n  const hasModalitySpecific = item.content.some((c) => isInstructions(c));\n  if (!hasModalitySpecific) return;\n\n  // ChatContext.copy shadows the original item; create a new instance so the\n  // base context's content isn't mutated when the same Instructions is reused\n  // across turns.\n  chatCtx.items[idx] = ChatMessage.create({\n    id: item.id,\n    role: item.role,\n    content: item.content.map((c) => (isInstructions(c) ? c.asModality(modality) : c)),\n    interrupted: item.interrupted,\n    createdAt: item.createdAt,\n    transcriptConfidence: item.transcriptConfidence,\n    metrics: item.metrics,\n    extra: item.extra,\n  });\n}\n\n/**\n * The ID of the expressive TTS markup-guide message in the chat context.\n *\n * The value must not change: it is what lets re-injection replace the previous guide.\n */\nexport const EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID = 'lk.expressive.instructions';\n\n/**\n * Insert or replace the expressive markup-guide system message.\n *\n * Keyed by {@link EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID} so per-turn re-injection replaces the\n * previous guide instead of accumulating one copy per turn, and a turn that runs with\n * expressive off can remove it again ({@link removeExpressiveInstructions}).\n */\nexport function updateExpressiveInstructions(chatCtx: ChatContext, options: { text: string }) {\n  const idx = chatCtx.indexById(EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID);\n  if (idx !== undefined) {\n    chatCtx.items[idx] = ChatMessage.create({\n      id: EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID,\n      role: 'system',\n      content: [options.text],\n      createdAt: chatCtx.items[idx]!.createdAt,\n    });\n  } else {\n    chatCtx.addMessage({\n      role: 'system',\n      content: options.text,\n      id: EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID,\n    });\n  }\n}\n\n/**\n * Whether `chatCtx` carries the expressive markup-guide message.\n *\n * Cheap enough to call per turn (an id lookup, no content inspection), so it can gate the\n * far more expensive — and destructive — {@link stripAssistantMarkup} scrub.\n */\nexport function hasExpressiveInstructions(chatCtx: ChatContext): boolean {\n  return chatCtx.indexById(EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID) !== undefined;\n}\n\n/**\n * Remove the expressive markup-guide message added by\n * {@link updateExpressiveInstructions}, if present.\n */\nexport function removeExpressiveInstructions(chatCtx: ChatContext) {\n  for (;;) {\n    const idx = chatCtx.indexById(EXPRESSIVE_INSTRUCTIONS_MESSAGE_ID);\n    if (idx === undefined) break;\n    chatCtx.items.splice(idx, 1);\n  }\n}\n\n/**\n * Remove expressive TTS markup from past assistant messages, in place.\n *\n * Called when a turn runs with expressive off (toggled off via an agent-level override, or\n * a handoff to a TTS without a markup dialect): tags left in history would few-shot the\n * LLM into emitting markup that nothing downstream converts or strips, so an unsupported\n * tag would reach the TTS as literal text and be spoken. Mutates the stored history: once\n * a turn runs with expressive off, prior turns' markup is gone even if expressive is\n * re-enabled later (the re-injected instructions carry the style examples instead).\n */\nexport function stripAssistantMarkup(chatCtx: ChatContext) {\n  for (const item of chatCtx.items) {\n    if (item.type !== 'message' || item.role !== 'assistant') continue;\n    // markup is XML-only here: stripAllMarkup leaves square-bracket spans alone\n    if (!item.content.some((c) => typeof c === 'string' && c.includes('<'))) continue;\n    item.content = item.content.map((c) => (typeof c === 'string' ? stripAllMarkup(c) : c));\n  }\n}\n\nexport function performLLMInference(\n  node: LLMNode,\n  chatCtx: ChatContext,\n  toolCtx: ToolContext,\n  modelSettings: ModelSettings,\n  controller: AbortController,\n  model?: string,\n  provider?: string,\n): [Task<void>, _LLMGenerationData] {\n  const logger = log();\n  const textStream = new IdentityTransform<string | FlushSentinel>();\n  const toolCallStream = new IdentityTransform<FunctionCall>();\n\n  const textWriter = textStream.writable.getWriter();\n  const toolCallWriter = toolCallStream.writable.getWriter();\n  const data = new _LLMGenerationData(textStream.readable, toolCallStream.readable);\n\n  const _performLLMInferenceImpl = async (\n    signal: AbortSignal,\n    span: Span,\n    inference: genAI.InferenceMarker,\n  ) => {\n    span.setAttribute(\n      traceTypes.ATTR_CHAT_CTX,\n      // snake_case wire shape, matching Python's `chat_ctx.to_dict()` for this span attribute\n      // (toJSON() emits camelCase). Defaults exclude image/audio/timestamps like the Python side.\n      JSON.stringify(toSnakeCaseDeep(chatCtx.toJSON())),\n    );\n    span.setAttribute(traceTypes.ATTR_FUNCTION_TOOLS, JSON.stringify(sortedToolNames(toolCtx)));\n\n    // the configured model and provider describe the inference only once it is known that\n    // this LLM served it; that is decided below, when the nested span is (or is not) there\n    const recordConfiguredModel = () => {\n      if (model) span.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, model);\n      const normalizedProvider = traceTypes.genAIProviderName(provider);\n      if (normalizedProvider) {\n        span.setAttribute(traceTypes.ATTR_GEN_AI_PROVIDER_NAME, normalizedProvider);\n      }\n    };\n    let nodeError: Error | string | undefined;\n\n    // the GenAI inference attributes belong to the nested `llm_request` span, which is the\n    // provider call the convention describes. Setting them here as well made a backend\n    // summing gen_ai.usage.* over inference spans report twice the calls and tokens, and\n    // serialised the whole chat context onto both spans.\n\n    let llmStreamReader: ReadableStreamDefaultReader<string | ChatChunk | FlushSentinel> | null =\n      null;\n    let llmStream: ReadableStream<string | ChatChunk | FlushSentinel> | null = null;\n    const startTime = performance.now() / 1000; // Convert to seconds\n    let firstTokenReceived = false;\n\n    try {\n      llmStream = await node(chatCtx, toolCtx, modelSettings);\n      if (llmStream === null) {\n        await textWriter.close();\n        return;\n      }\n\n      const abortPromise = waitForAbort(signal);\n\n      // TODO(brian): add support for dynamic tools\n\n      llmStreamReader = llmStream.getReader();\n      while (true) {\n        if (signal.aborted) break;\n\n        const result = await ThrowsPromise.race([llmStreamReader.read(), abortPromise]);\n        if (result === undefined) break;\n\n        const { done, value: chunk } = result;\n        if (done) break;\n\n        let generated = false;\n        if (typeof chunk === 'string') {\n          generated = chunk.length > 0;\n        } else if (!isFlushSentinel(chunk)) {\n          generated = hasResponse(chunk);\n        }\n\n        // measured against generation, not the first chunk: a retry that follows a\n        // contentless chunk would otherwise latch the clock on the failed attempt\n        if (!firstTokenReceived && generated) {\n          firstTokenReceived = true;\n          data.ttft = performance.now() / 1000 - startTime;\n        }\n\n        if (isFlushSentinel(chunk)) {\n          await textWriter.write(chunk);\n        } else if (typeof chunk === 'string') {\n          data.generatedText += chunk;\n          await textWriter.write(chunk);\n          // TODO(shubhra): better way to check??\n        } else {\n          if (chunk.delta === undefined) {\n            continue;\n          }\n\n          if (chunk.delta.toolCalls) {\n            for (const tool of chunk.delta.toolCalls) {\n              if (tool.type !== 'function_call') continue;\n\n              const toolCall = FunctionCall.create({\n                id: `${data.id}/fnc_${data.generatedToolCalls.length}`,\n                callId: tool.callId,\n                name: tool.name,\n                args: tool.args,\n                // Preserve thought signature for Gemini 3+ thinking mode\n                thoughtSignature: tool.thoughtSignature,\n                extra: tool.extra || {},\n              });\n\n              data.generatedToolCalls.push(toolCall);\n              await toolCallWriter.write(toolCall);\n            }\n          }\n\n          if (chunk.delta.extra) {\n            Object.assign(data.generatedExtra, chunk.delta.extra);\n          }\n\n          if (chunk.delta.content) {\n            data.generatedText += chunk.delta.content;\n            await textWriter.write(chunk.delta.content);\n          }\n        }\n\n        // No need to check if chunk is of type other than ChatChunk or string like in\n        // Python since chunk is defined in the type ChatChunk | string in TypeScript\n      }\n    } catch (error) {\n      // an Error is classified by setErrorType; anything else is never used verbatim,\n      // since error.type is low-cardinality and a thrown value can carry content\n      nodeError = error instanceof Error ? error : 'UnknownError';\n      if (error instanceof DOMException && error.name === 'AbortError') {\n        // Abort signal was triggered, handle gracefully\n        return;\n      }\n      // surface inference silent errors even when this task's rejection is never awaited\n      logger.error({ error }, 'error in llm node');\n      throw error;\n    } finally {\n      span.setAttribute(traceTypes.ATTR_RESPONSE_TEXT, data.generatedText);\n      span.setAttribute(\n        traceTypes.ATTR_RESPONSE_FUNCTION_CALLS,\n        JSON.stringify(\n          data.generatedToolCalls.map(({ id, callId, name, args }) => ({\n            id,\n            call_id: callId,\n            name,\n            arguments: args,\n          })),\n        ),\n      );\n      if (data.ttft !== undefined) {\n        span.setAttribute(traceTypes.ATTR_RESPONSE_TTFT, data.ttft);\n      }\n      // a custom node may have generated this itself, with no nested `llm_request` span to\n      // carry the convention's attributes; when there was one, they are already recorded\n      if (inference.recorded) {\n        recordConfiguredModel();\n      } else {\n        // a third-party engine served this, so the configured model and provider are left\n        // off rather than crediting it with a call it never made\n        genAI.setRequestAttributes(span, {\n          operation: traceTypes.GenAIOperationName.CHAT,\n          stream: true,\n          outputType: traceTypes.GenAIOutputType.TEXT,\n        });\n        if (nodeError !== undefined) genAI.setErrorType(span, nodeError);\n        const finishReason = genAI.finishReasonFor({\n          functionCalls: data.generatedToolCalls,\n          interrupted: nodeError !== undefined,\n        });\n        genAI.setResponseAttributes(span, {\n          finishReasons: [finishReason],\n          timeToFirstChunk: data.ttft,\n        });\n        genAI.setContentAttributes(span, {\n          systemInstructions: genAI.toSystemInstructions(chatCtx),\n          inputMessages: genAI.toInputMessages(chatCtx),\n          toolDefinitions: genAI.toToolDefinitions(toolCtx.functionTools),\n          outputMessages: genAI.toOutputMessages({\n            text: data.generatedText,\n            functionCalls: data.generatedToolCalls,\n            finishReason,\n          }),\n        });\n      }\n      llmStreamReader?.releaseLock();\n      await llmStream?.cancel();\n      await textWriter.close();\n      await toolCallWriter.close();\n    }\n  };\n\n  // Capture the current context (agent_turn) to ensure llm_node is properly parented\n  const currentContext = otelContext.active();\n\n  const inferenceTask = async (signal: AbortSignal) =>\n    tracer.startActiveSpan(\n      async (span) =>\n        genAI.withInferenceTracking((marker) => _performLLMInferenceImpl(signal, span, marker)),\n      { name: 'llm_node', context: currentContext },\n    );\n\n  return [\n    Task.from((controller) => inferenceTask(controller.signal), controller, 'performLLMInference'),\n    data,\n  ];\n}\n\nexport function performTTSInference(\n  node: TTSNode,\n  text: ReadableStream<string | TimedString>,\n  modelSettings: ModelSettings,\n  controller: AbortController,\n  model?: string,\n  provider?: string,\n  readIdleTimeout: number = DEFAULT_TTS_READ_IDLE_TIMEOUT_MS,\n  textTransforms?: readonly TextTransform[] | null,\n): [Task<void>, _TTSGenerationData] {\n  const logger = log();\n  const audioStream = new IdentityTransform<AudioFrame>();\n  const outputWriter = audioStream.writable.getWriter();\n  const audioOutputStream = audioStream.readable;\n\n  const timedTextsFut = new Future<ReadableStream<TimedString> | null, never>();\n  const timedTextsStream = new IdentityTransform<TimedString>();\n  const timedTextsWriter = timedTextsStream.writable.getWriter();\n\n  // Transform stream to extract text from TimedString objects\n  const textOnlyStream = new IdentityTransform<string>();\n  const textOnlyWriter = textOnlyStream.writable.getWriter();\n  let startTime: number | undefined;\n  (async () => {\n    const reader = text.getReader();\n    try {\n      while (true) {\n        const { done, value } = await reader.read();\n        if (done) {\n          break;\n        }\n        startTime ??= performance.now() / 1000;\n        const textValue = typeof value === 'string' ? value : value.text;\n        await textOnlyWriter.write(textValue);\n      }\n      await textOnlyWriter.close();\n    } catch (e) {\n      await textOnlyWriter.abort(e as Error);\n    } finally {\n      reader.releaseLock();\n    }\n  })();\n\n  let ttfb: number | undefined;\n\n  const genData: _TTSGenerationData = {\n    audioStream: audioOutputStream,\n    timedTextsFut,\n    ttfb: undefined,\n  };\n\n  const _performTTSInferenceImpl = async (signal: AbortSignal, span: Span) => {\n    if (model) {\n      span.setAttribute(traceTypes.ATTR_GEN_AI_REQUEST_MODEL, model);\n    }\n    if (provider) {\n      span.setAttribute(traceTypes.ATTR_GEN_AI_PROVIDER_NAME, provider);\n    }\n\n    let ttsStreamReader: ReadableStreamDefaultReader<AudioFrame> | null = null;\n    let ttsStream: ReadableStream<AudioFrame> | null = null;\n    let firstByteReceived = false;\n\n    try {\n      const ttsInput = textTransforms\n        ? applyTextTransforms(textOnlyStream.readable, textTransforms)\n        : textOnlyStream.readable;\n      ttsStream = await node(ttsInput, modelSettings);\n      if (ttsStream === null) {\n        timedTextsFut.resolve(null);\n        await outputWriter.close();\n        await timedTextsWriter.close();\n        return;\n      }\n\n      // This is critical: the future must be resolved with the channel/stream before the loop\n      // so that agent_activity can start reading while we write\n      if (!timedTextsFut.done) {\n        timedTextsFut.resolve(timedTextsStream.readable);\n      }\n\n      ttsStreamReader = ttsStream.getReader();\n\n      while (true) {\n        if (signal.aborted) {\n          break;\n        }\n\n        const { done, value: frame } = await waitUntilTimeout(\n          ttsStreamReader.read(),\n          readIdleTimeout,\n        );\n        if (done) {\n          break;\n        }\n\n        if (!firstByteReceived) {\n          firstByteReceived = true;\n          const ttsStartedTime = frame.userdata[USERDATA_TTS_STARTED_TIME];\n          const anchor = typeof ttsStartedTime === 'number' ? ttsStartedTime : startTime;\n          if (anchor !== undefined) {\n            ttfb = performance.now() / 1000 - anchor;\n            genData.ttfb = ttfb;\n            span.setAttribute(traceTypes.ATTR_RESPONSE_TTFB, ttfb);\n          }\n        }\n\n        // Write the audio frame to the output stream\n        await outputWriter.write(frame);\n\n        const timedTranscripts = frame.userdata[USERDATA_TIMED_TRANSCRIPT] as\n          | TimedString[]\n          | undefined;\n        if (timedTranscripts && timedTranscripts.length > 0) {\n          for (const timedText of timedTranscripts) {\n            await timedTextsWriter.write(timedText);\n          }\n        }\n      }\n    } catch (error) {\n      if (error instanceof IdleTimeoutError) {\n        logger.warn('TTS stream stalled after producing audio, forcing close');\n      } else if (error instanceof DOMException && error.name === 'AbortError') {\n        return;\n      } else {\n        throw error;\n      }\n    } finally {\n      if (!timedTextsFut.done) {\n        timedTextsFut.resolve(null);\n      }\n      ttsStreamReader?.releaseLock();\n      await ttsStream?.cancel();\n      await outputWriter.close();\n      await timedTextsWriter.close();\n    }\n  };\n\n  // Capture the current context (agent_turn) to ensure tts_node is properly parented\n  const currentContext = otelContext.active();\n\n  const inferenceTask = async (signal: AbortSignal) =>\n    tracer.startActiveSpan(async (span) => _performTTSInferenceImpl(signal, span), {\n      name: 'tts_node',\n      context: currentContext,\n    });\n\n  return [\n    Task.from((controller) => inferenceTask(controller.signal), controller, 'performTTSInference'),\n    genData,\n  ];\n}\n\nexport interface _TextOut {\n  text: string;\n  firstTextFut: Future;\n}\n\nasync function forwardText(\n  source: ReadableStream<string | TimedString>,\n  out: _TextOut,\n  signal: AbortSignal,\n  textOutput: TextOutput | null,\n): Promise<void> {\n  const reader = source.getReader();\n  try {\n    while (true) {\n      if (signal.aborted) {\n        break;\n      }\n      const { done, value: delta } = await reader.read();\n      if (done) break;\n\n      const deltaIsTimedString = isTimedString(delta);\n      const textDelta = deltaIsTimedString ? delta.text : delta;\n\n      out.text += textDelta;\n      if (textOutput !== null) {\n        // Pass TimedString to textOutput for synchronized transcription\n        await textOutput.captureText(delta);\n      }\n      if (!out.firstTextFut.done) {\n        out.firstTextFut.resolve();\n      }\n    }\n  } finally {\n    if (textOutput !== null) {\n      textOutput.flush();\n    }\n    reader?.releaseLock();\n  }\n}\n\nexport function performTextForwarding(\n  source: ReadableStream<string | TimedString>,\n  controller: AbortController,\n  textOutput: TextOutput | null,\n): [Task<void>, _TextOut] {\n  const out = {\n    text: '',\n    firstTextFut: new Future(),\n  };\n  return [\n    Task.from(\n      (controller) => forwardText(source, out, controller.signal, textOutput),\n      controller,\n      'performTextForwarding',\n    ),\n    out,\n  ];\n}\n\nexport interface _AudioOut {\n  firstFrameFut: Future<number>;\n  /**\n   * Timestamp (ms, `Date.now()`) when the first audio frame was forwarded to the\n   * `AudioOutput`. Set by `forwardAudio` as soon as the first TTS frame is\n   * received; remains `undefined` until then. Used together with the playback-started\n   * timestamp from `firstFrameFut` to derive the assistant's `playbackLatency`\n   * metric.\n   */\n  startedForwardingAt?: number;\n  /**\n   * Whether this segment has captured at least one of its own frames. Read by the\n   * PLAYBACK_STARTED listener registered in `performAudioForwarding` to ignore a\n   * stray event emitted by another overlapping segment before this one has played.\n   * @internal\n   */\n  _hasCapturedOwnFrame: boolean;\n  /**\n   * The output's monotonic segment count (`capturedPlayoutSegments`) when forwarding\n   * was set up. The interrupted-commit gate compares the current count against this\n   * baseline: a bump proves a frame of THIS segment made it through\n   * `AudioOutput.captureFrame` — the same condition under which `waitForPlayout()`\n   * waits for this segment's playback event instead of returning a stale one — so\n   * the reported playback position can be trusted as evidence of partial playback.\n   * (`startedForwardingAt` is set *before* `captureFrame` resolves and is therefore\n   * not usable as capture evidence; a frame can bail at a pause/interrupt gate,\n   * e.g. `ParticipantAudioOutput`, without ever being counted.)\n   */\n  capturedSegmentsBefore: number;\n}\n\n/**\n * The text that actually reached the user, accounting for interruptions.\n *\n * On a mid-playout interruption (`played === 'partial'`) we prefer the\n * playback-aligned `synchronizedTranscript`, but fall back to the full generated\n * text when no synchronized transcript is available (e.g. avatar outputs) so the\n * heard reply is still committed to chat ctx rather than dropped.\n */\nexport function forwardedTextFor(output: ForwardOutput): string {\n  if (output.played === 'skipped') return '';\n  if (output.played === 'partial' && output.synchronizedTranscript !== undefined) {\n    return output.synchronizedTranscript;\n  }\n  return output.textOut?.text ?? '';\n}\n\nasync function forwardAudio(\n  ttsStream: ReadableStream<AudioFrame>,\n  audioOutput: AudioOutput,\n  out: _AudioOut,\n  reconcilePlayoutPause: () => void,\n  idleTimeout: number,\n  signal?: AbortSignal,\n): Promise<void> {\n  const logger = log();\n  const reader = ttsStream.getReader();\n  let resampler: AudioResampler | null = null;\n  const cancelReader = () => {\n    void reader.cancel().catch((error) => {\n      logger.debug({ error }, 'failed to cancel TTS stream reader after abort');\n    });\n  };\n  signal?.addEventListener('abort', cancelReader, { once: true });\n  if (signal?.aborted) {\n    cancelReader();\n  }\n\n  try {\n    // Reconcile any start-of-speech pause before forwarding audio.\n    reconcilePlayoutPause();\n\n    while (true) {\n      if (signal?.aborted) {\n        break;\n      }\n\n      const { done, value: frame } = await waitUntilTimeout(reader.read(), idleTimeout);\n      if (done) break;\n      // Unlike asyncio task cancellation, aborting cannot interrupt reader.read().\n      // Re-check after it resolves so a late frame cannot leak into the shared output.\n      if (signal?.aborted) {\n        break;\n      }\n\n      if (out.startedForwardingAt === undefined) {\n        out.startedForwardingAt = Date.now();\n      }\n\n      if (audioOutput.sampleRate && audioOutput.sampleRate !== frame.sampleRate && !resampler) {\n        resampler = new AudioResampler(frame.sampleRate, audioOutput.sampleRate, frame.channels);\n      }\n\n      // Mark before capturing so the PLAYBACK_STARTED emitted synchronously inside\n      // the first captureFrame is attributed to this segment (see the listener in\n      // `performAudioForwarding`).\n      out._hasCapturedOwnFrame = true;\n\n      if (resampler) {\n        for (const f of resampler.push(frame)) {\n          await audioOutput.captureFrame(f);\n        }\n      } else {\n        await audioOutput.captureFrame(frame);\n      }\n    }\n\n    if (resampler) {\n      for (const f of resampler.flush()) {\n        await audioOutput.captureFrame(f);\n      }\n    }\n  } catch (e) {\n    if (e instanceof IdleTimeoutError) {\n      logger.warn('audio forwarding stalled waiting for TTS frames, forcing close');\n    } else {\n      throw e;\n    }\n  } finally {\n    // NOTE: `firstFrameFut` is intentionally NOT settled here. Forwarding completes\n    // as soon as all TTS frames are *captured*, which can be long before playback\n    // begins:\n    // - DataStream avatar outputs (`waitPlaybackStart: true`, e.g. LemonSlice)\n    //   accept frames faster than real time and only send the\n    //   `lk.playback_started` RPC once the avatar worker actually starts playing,\n    //   typically ~1s after forwarding has finished (#1960).\n    // - A speech paused in the thinking state (`resumeFalseInterruption`) buffers\n    //   its frames; playback starts only once the output resumes, possibly after\n    //   this task has finished (#1909).\n    // Rejecting the future here dropped those late playback-started events on the\n    // floor: the agent never entered the \"speaking\" state and an interrupted reply\n    // was classified \"skipped\" and silently removed from the chat context (phantom\n    // utterance). Mirror the python implementation instead: the PLAYBACK_STARTED\n    // listener registered in `performAudioForwarding` outlives this task and\n    // resolves the future when the late first frame plays; the reply tasks settle\n    // any future still pending once the playout window ends, bounding the\n    // listener's lifetime.\n    signal?.removeEventListener('abort', cancelReader);\n    reader?.releaseLock();\n    audioOutput.flush();\n    if (signal?.aborted) {\n      audioOutput.clearBuffer();\n    }\n    resampler?.close();\n  }\n}\n\nexport function performAudioForwarding(\n  ttsStream: ReadableStream<AudioFrame>,\n  audioOutput: AudioOutput,\n  controller: AbortController,\n  reconcilePlayoutPause: () => void,\n  idleTimeout: number = DEFAULT_FORWARD_AUDIO_IDLE_TIMEOUT_MS,\n): [Task<void>, _AudioOut] {\n  const out: _AudioOut = {\n    firstFrameFut: new Future<number>(),\n    _hasCapturedOwnFrame: false,\n    capturedSegmentsBefore: audioOutput.capturedPlayoutSegments,\n  };\n\n  // Resolve `firstFrameFut` from the output's PLAYBACK_STARTED event. Registered\n  // here (rather than inside `forwardAudio`) so the listener outlives the\n  // forwarding task: frames may be captured into a paused or remote-buffered\n  // output and only start playing after forwarding has finished (#1909, #1960).\n  const onPlaybackStarted = (ev: { createdAt: number }) => {\n    // The audio output is shared across overlapping segments. Only honor the\n    // event once this segment has captured its own first frame, so a stray event\n    // from another segment can't resolve our `firstFrameFut` prematurely. A\n    // premature resolution skips resampler creation (gated on\n    // `!firstFrameFut.done`) and pushes an unresampled frame to the AudioSource,\n    // raising `RtcError: sample_rate and num_channels don't match`.\n    if (out._hasCapturedOwnFrame && !out.firstFrameFut.done) {\n      out.firstFrameFut.resolve(ev.createdAt);\n    }\n  };\n  audioOutput.on(AudioOutput.EVENT_PLAYBACK_STARTED, onPlaybackStarted);\n  // Remove the listener once the future settles — resolved by playback above, or\n  // rejected by the reply task (via `settleFirstFrameFut`) after playout finishes\n  // or is interrupted without a frame ever playing.\n  const removeListener = () =>\n    audioOutput.off(AudioOutput.EVENT_PLAYBACK_STARTED, onPlaybackStarted);\n  out.firstFrameFut.await.then(removeListener).catch(removeListener);\n\n  return [\n    Task.from(\n      (controller) =>\n        forwardAudio(\n          ttsStream,\n          audioOutput,\n          out,\n          reconcilePlayoutPause,\n          idleTimeout,\n          controller.signal,\n        ),\n      controller,\n      'performAudioForwarding',\n    ),\n    out,\n  ];\n}\n\nexport function performToolExecutions({\n  session,\n  speechHandle,\n  toolCtx,\n  toolChoice,\n  toolCallStream,\n  agentName,\n  onToolExecutionStarted = () => {},\n  onToolExecutionCompleted = () => {},\n  controller,\n}: {\n  session: AgentSession;\n  speechHandle: SpeechHandle;\n  toolCtx: ToolContext;\n  toolChoice?: ToolChoice;\n  toolCallStream: ReadableStream<FunctionCall>;\n  /** The agent that invoked these tools — a handoff may already have swapped the session's. */\n  agentName?: string;\n  onToolExecutionStarted?: (toolCall: FunctionCall) => void;\n  onToolExecutionCompleted?: (toolExecutionOutput: ToolExecutionOutput) => void;\n  controller: AbortController;\n}): [Task<void>, ToolOutput] {\n  const logger = log();\n  const toolOutput: ToolOutput = {\n    output: [],\n    firstToolStartedFuture: new Future(),\n  };\n  const toolCompleted = (out: ToolExecutionOutput) => {\n    onToolExecutionCompleted(out);\n    toolOutput.output.push(out);\n  };\n  const toolStarted = (toolCall: FunctionCall) => {\n    if (!toolOutput.firstToolStartedFuture.done) {\n      toolOutput.firstToolStartedFuture.resolve();\n    }\n    onToolExecutionStarted(toolCall);\n  };\n\n  const executeToolsTask = async (controller: AbortController) => {\n    const signal = controller.signal;\n    const reader = toolCallStream.getReader();\n\n    // Production always has an activity (and thus a shared executor). Fall back to a standalone\n    // executor when it's absent (edge cases / unit tests) instead of dropping every tool call,\n    // which would leave callers awaiting `firstToolStartedFuture` hanging forever.\n    const activity = session._activity;\n    const defaultExecutor = activity?._toolExecutor ?? new ToolExecutor({ owningActivity: null });\n\n    // Route AsyncToolset members to their own executor so session-scoped async\n    // tools survive handoff; everything else falls back to the activity executor.\n    const executorByName = buildExecutorMap({\n      toolsets: toolCtx.toolsets,\n      defaultExecutor,\n    });\n\n    const tasks: Task<void>[] = [];\n    while (!signal.aborted) {\n      const { done, value: toolCall } = await reader.read();\n      if (signal.aborted) break;\n      if (done) break;\n\n      if (toolChoice === 'none') {\n        logger.error(\n          {\n            function: toolCall.name,\n            speech_id: speechHandle.id,\n          },\n          \"received a tool call with toolChoice set to 'none', ignoring\",\n        );\n        continue;\n      }\n\n      // TODO(brian): assert other toolChoice values\n\n      const tool = toolCtx.getFunctionTool(toolCall.name);\n      if (!tool) {\n        const availableTools = sortedToolNames(toolCtx).join(', ');\n        const message = `Unknown function: ${toolCall.name} - available tools: ${availableTools}`;\n        logger.warn(\n          {\n            function: toolCall.name,\n            speech_id: speechHandle.id,\n          },\n          `unknown AI function ${toolCall.name}`,\n        );\n        try {\n          toolCall.args = JSON.stringify(parseFunctionArguments(toolCall.args || '{}'));\n        } catch {\n          toolCall.args = '{}';\n        }\n        toolStarted(toolCall);\n        toolCompleted(\n          createToolOutput({\n            toolCall,\n            exception: new ToolError(message),\n          }),\n        );\n        continue;\n      }\n\n      if (!isFunctionTool(tool)) {\n        logger.error(\n          {\n            function: toolCall.name,\n            speech_id: speechHandle.id,\n          },\n          `unknown tool type: ${typeof tool}`,\n        );\n        continue;\n      }\n\n      let parsedArgs: object | undefined;\n      let argumentsParsed = false;\n\n      // Ensure valid arguments\n      try {\n        const rawArgs = toolCall.args || '{}';\n        const jsonArgs = parseFunctionArguments(rawArgs);\n        const canonicalArgs = JSON.stringify(jsonArgs);\n        if (canonicalArgs !== rawArgs) {\n          toolCall.args = canonicalArgs;\n        }\n        argumentsParsed = true;\n\n        if (isZodSchema(tool.parameters)) {\n          const result = await parseZodSchema<object>(tool.parameters, jsonArgs);\n          if (result.success) {\n            parsedArgs = result.data;\n          } else {\n            throw result.error;\n          }\n        } else {\n          parsedArgs = jsonArgs;\n        }\n      } catch (rawError) {\n        const error = toError(rawError);\n        logger.error(\n          {\n            function: toolCall.name,\n            'lk.pii.arguments': toolCall.args,\n            speech_id: speechHandle.id,\n            'lk.pii.error': error.message,\n          },\n          `tried to call AI function ${toolCall.name} with invalid arguments`,\n        );\n        if (!argumentsParsed) {\n          toolCall.args = '{}';\n        }\n        // Surface argument-validation errors to the LLM via ToolError so it can correct\n        // its arguments instead of looping on the same invalid call. The argument schema\n        // and the validator's error message do not contain server-side internals.\n        toolStarted(toolCall);\n        toolCompleted(\n          createToolOutput({\n            toolCall,\n            exception: new ToolError(`Invalid arguments for ${toolCall.name}: ${error.message}`),\n          }),\n        );\n        continue;\n      }\n\n      // Resolve right after argument parsing and before execution (including the\n      // executor's duplicate-check). This ensures a tool that gets duplicate-rejected\n      // by the executor doesn't leave callers awaiting `firstToolStartedFuture` hanging forever.\n      toolStarted(toolCall);\n\n      logger.info(\n        {\n          function: toolCall.name,\n          'lk.pii.arguments': parsedArgs,\n          speech_id: speechHandle.id,\n        },\n        'Executing LLM tool call',\n      );\n\n      const _tracableToolExecutionImpl = async (toolExecTask: Promise<unknown>, span: Span) => {\n        span.setAttribute(traceTypes.ATTR_FUNCTION_TOOL_NAME, toolCall.name);\n        span.setAttribute(traceTypes.ATTR_FUNCTION_TOOL_ARGS, toolCall.args);\n        genAI.setToolAttributes(span, {\n          name: toolCall.name,\n          callId: toolCall.callId,\n          description: isFunctionTool(tool) ? tool.description : undefined,\n          args: toolCall.args,\n          agentName,\n        });\n\n        // Only completed executions produce tool output. An interrupted execution may still\n        // finish in the background and must remain retryable rather than becoming a synthetic\n        // error result in conversation history.\n        let toolOutput: ToolExecutionOutput | undefined;\n        try {\n          const { result, isAborted } = await _waitForToolExecutionResult(toolExecTask, signal);\n          if (isAborted) return;\n          toolOutput = createToolOutput({\n            toolCall,\n            output: result,\n          });\n\n          if (toolOutput.toolCallOutput) {\n            span.setAttribute(\n              traceTypes.ATTR_FUNCTION_TOOL_OUTPUT,\n              toolOutput.toolCallOutput.output,\n            );\n            span.setAttribute(\n              traceTypes.ATTR_FUNCTION_TOOL_IS_ERROR,\n              toolOutput.toolCallOutput.isError,\n            );\n            genAI.setToolResult(span, {\n              result: toolOutput.toolCallOutput.output,\n              isError: toolOutput.toolCallOutput.isError,\n            });\n          }\n        } catch (rawError) {\n          logger.error(\n            {\n              function: toolCall.name,\n              speech_id: speechHandle.id,\n              error: toError(rawError).message,\n            },\n            'exception occurred while executing tool',\n          );\n          toolOutput = createToolOutput({\n            toolCall,\n            exception: toError(rawError),\n          });\n\n          if (toolOutput.toolCallOutput) {\n            span.setAttribute(\n              traceTypes.ATTR_FUNCTION_TOOL_OUTPUT,\n              toolOutput.toolCallOutput.output,\n            );\n            span.setAttribute(traceTypes.ATTR_FUNCTION_TOOL_IS_ERROR, true);\n            genAI.setToolResult(span, { isError: true });\n          }\n        } finally {\n          if (toolOutput) toolCompleted(toolOutput);\n        }\n      };\n\n      const tracableToolExecution = (toolExecTask: Promise<unknown>) =>\n        tracer.startActiveSpan(async (span) => _tracableToolExecutionImpl(toolExecTask, span), {\n          name: 'function_tool',\n        });\n\n      const toolTask = Task.from(\n        async () => {\n          // Ensure this task is marked inline before user tool code executes.\n          const currentTask = Task.current();\n          if (currentTask) {\n            _setActivityTaskInfo(currentTask, {\n              speechHandle,\n              functionCall: toolCall,\n              inlineTask: true,\n            });\n          }\n\n          const toolExecution = functionCallStorage.run(\n            { functionCall: toolCall, speechHandle },\n            async () => {\n              const runCtx = new RunContext(session, speechHandle, toolCall);\n              const mock = getMockTool(session.currentAgent, toolCall.name);\n              const toolToExecute = mock\n                ? {\n                    ...tool,\n                    execute: mock,\n                  }\n                : tool;\n\n              if (mock) {\n                logger.debug(\n                  {\n                    function: toolCall.name,\n                    'lk.pii.arguments': parsedArgs,\n                    speech_id: speechHandle.id,\n                  },\n                  'executing mock tool',\n                );\n              }\n\n              const executor = executorByName.get(toolCall.name) ?? defaultExecutor;\n              return await executor.execute({\n                tool: toolToExecute,\n                runCtx,\n                rawArguments: parsedArgs as JSONObject,\n                abortSignal: signal,\n              });\n            },\n          );\n\n          await tracableToolExecution(toolExecution);\n        },\n        controller,\n        `performToolExecution:${toolCall.name}`,\n      );\n\n      _setActivityTaskInfo(toolTask, {\n        speechHandle,\n        functionCall: toolCall,\n        inlineTask: true,\n      });\n      // wait, not cancelling all tool calling tasks\n      tasks.push(toolTask);\n    }\n\n    await ThrowsPromise.allSettled(tasks.map((task) => task.result));\n    if (toolOutput.output.length > 0) {\n      logger.debug(\n        {\n          speech_id: speechHandle.id,\n        },\n        'tools execution completed',\n      );\n    }\n  };\n\n  return [Task.from(executeToolsTask, controller, 'performToolExecutions'), toolOutput];\n}\n\n/**\n * Race tool completion against interruption while preferring an already-settled result.\n *\n * A plain pre-abort short circuit can discard a result that settled earlier in the same\n * JavaScript turn but whose reaction has not run yet. Passing the original promise first to\n * `Promise.race` preserves the settlement order in that case.\n *\n * @internal\n */\nexport async function _waitForToolExecutionResult<T>(\n  promise: Promise<T>,\n  signal: AbortSignal,\n): Promise<Aborted<T>> {\n  const aborted = Symbol('tool execution aborted');\n  let onAbort: (() => void) | undefined;\n  const abortPromise = new Promise<typeof aborted>((resolve) => {\n    onAbort = () => resolve(aborted);\n    if (signal.aborted) {\n      resolve(aborted);\n    } else {\n      signal.addEventListener('abort', onAbort, { once: true });\n    }\n  });\n\n  try {\n    const result = await Promise.race([promise, abortPromise]);\n    return result === aborted\n      ? { result: undefined, isAborted: true }\n      : { result, isAborted: false };\n  } finally {\n    if (onAbort) signal.removeEventListener('abort', onAbort);\n  }\n}\n\nexport function removeInstructions(chatCtx: ChatContext) {\n  // loop in case there are items with the same id (shouldn't happen!)\n  while (true) {\n    const idx = chatCtx.indexById(INSTRUCTIONS_MESSAGE_ID);\n    if (idx !== undefined) {\n      chatCtx.items.splice(idx, 1);\n    } else {\n      break;\n    }\n  }\n}\n"],"mappings":"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","names":["import_utils","otelContext","controller","toolOutput"]}