{"version":3,"sources":["../../src/voice/run_context.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { FunctionCall, FunctionCallOutput } from '../llm/chat_context.js';\nimport type { Future } from '../utils.js';\nimport type { AgentActivity } from './agent_activity.js';\nimport type { AgentSession } from './agent_session.js';\nimport {\n  AgentSessionEventTypes,\n  type AgentStateChangedEvent,\n  type UserStateChangedEvent,\n} from './events.js';\nimport { type SpeechHandle, isSpeechHandle } from './speech_handle.js';\n\nexport type UnknownUserData = unknown;\n\nexport type PromptTemplate<Args> = string | ((args: Args) => string);\n\nexport interface UpdatePromptArgs {\n  functionName: string;\n  callId: string;\n  message: string;\n}\n\nexport interface RunContextUpdateOptions {\n  template?: PromptTemplate<UpdatePromptArgs>;\n}\n\nexport type FillerSource = string | ((step: number) => SpeechHandle | string | null | undefined);\n\nexport interface RunContextFillerOptions {\n  /**\n   * Continuous-idle dwell, in milliseconds, before filler speech fires.\n   * Defaults to 0, which fires as soon as the session is next idle.\n   */\n  delay?: number;\n  /**\n   * Cooldown, in milliseconds, before waiting for another idle dwell.\n   * When omitted, filler speech fires at most once.\n   */\n  interval?: number;\n  /** Maximum number of filler speeches to create. */\n  maxSteps?: number;\n  /** Optional external cancellation signal for the filler scheduler. */\n  signal?: AbortSignal;\n}\n\nexport interface AttachedToolExecutor<UserData = UnknownUserData> {\n  toolOptions: {\n    updateTemplate: PromptTemplate<UpdatePromptArgs>;\n  };\n  enqueueReply(ctx: RunContext<UserData>, items: [FunctionCall, FunctionCallOutput]): Promise<void>;\n  replyTask?: Promise<void>;\n}\n\nexport class RunContext<UserData = UnknownUserData> {\n  private readonly initialStepIdx: number;\n  private _executor?: AttachedToolExecutor<UserData>;\n  private _executorAttachment?: object;\n  private _firstUpdateFuture?: Future<unknown>;\n  private _updates: Array<[FunctionCall, FunctionCallOutput]> = [];\n  private _fillerSchedulers: FillerScheduler<UserData>[] = [];\n  constructor(\n    public readonly session: AgentSession<UserData>,\n    public readonly speechHandle: SpeechHandle,\n    public readonly functionCall: FunctionCall,\n  ) {\n    this.initialStepIdx = speechHandle.numSteps - 1;\n  }\n  get userData(): UserData {\n    return this.session.userData;\n  }\n\n  /**\n   * Waits for the speech playout corresponding to this function call step.\n   *\n   * Unlike {@link SpeechHandle.waitForPlayout}, which waits for the full\n   * assistant turn to complete (including all function tools),\n   * this method only waits for the assistant's spoken response prior to running\n   * this tool to finish playing.\n   */\n  async waitForPlayout() {\n    return this.speechHandle._waitForGeneration(this.initialStepIdx);\n  }\n\n  get updates(): readonly [FunctionCall, FunctionCallOutput][] {\n    return this._updates;\n  }\n\n  disallowInterruptions(): void {\n    this.speechHandle.allowInterruptions = false;\n  }\n\n  /**\n   * Report progress from a long-running tool — and, on the first call, turn the tool\n   * **non-blocking** so the conversation continues while `execute()` keeps running.\n   *\n   * Behavior depends on whether this is the first `update()` for the call:\n   *\n   * - **First call:** resolves the pending tool result with `message` and marks the\n   *   function call non-blocking (`functionCall.extra.__livekit_agents_tool_non_blocking = true`).\n   *   The framework treats `message` as the tool's immediate output to the LLM and returns\n   *   control to the session, so the agent can speak/listen while the tool continues in the\n   *   background. Whatever `execute()` ultimately returns is delivered later as a deferred reply.\n   * - **Subsequent calls:** each `message` is enqueued via the owning executor and delivered as a\n   *   fresh assistant turn, gated on the session being idle (so updates never talk over the user).\n   *   The arrival cadence is therefore conversational, not immediate.\n   *\n   * Message rendering:\n   * - A **string** is rendered through a template — {@link RunContextUpdateOptions.template} if\n   *   provided, otherwise the executor's configured `updateTemplate` — with `{functionName}`,\n   *   `{callId}`, and `{message}` substituted. The default template tells the model the task is\n   *   still running and not to fabricate results.\n   * - A **non-string** value is used as-is (no templating), letting a tool emit structured output.\n   *\n   * Every update is also recorded in {@link RunContext.updates} (with a `_update_N` call-id suffix\n   * for the 2nd and later updates) so the full progress trail is preserved in chat history.\n   *\n   * No-op for delivery when the tool isn't attached to an async-capable executor (e.g. a plain\n   * blocking tool): the update is still recorded but nothing is sent.\n   *\n   * @param message - Progress text (templated) or a structured value (sent verbatim).\n   * @param options - Per-call overrides; see {@link RunContextUpdateOptions}.\n   */\n  async update(message: unknown, options: RunContextUpdateOptions = {}): Promise<void> {\n    for (const scheduler of this._fillerSchedulers) {\n      scheduler.resetDwell();\n    }\n\n    const updateStep = this._updates.length;\n    const renderedMessage =\n      typeof message === 'string'\n        ? renderTemplate(options.template ?? this._executor?.toolOptions.updateTemplate, {\n            functionName: this.functionCall.name,\n            callId: this.functionCall.callId,\n            message,\n          })\n        : message;\n    const pair = this._makeUpdatePair(\n      renderedMessage,\n      updateStep > 0 ? `_update_${updateStep}` : '',\n    );\n    this._updates.push(pair);\n\n    if (!this._executor) {\n      return;\n    }\n\n    if (this._firstUpdateFuture && !this._firstUpdateFuture.done) {\n      this._firstUpdateFuture.resolve(renderedMessage);\n      this.functionCall.extra.__livekit_agents_tool_non_blocking = true;\n      return;\n    }\n\n    await this._executor.enqueueReply(this, pair);\n  }\n\n  async foreground<T>(fn: (activity: AgentActivity) => Promise<T> | T): Promise<T> {\n    await this._drainPendingReply();\n    return this.session.waitForIdleAndHold(fn);\n  }\n\n  /**\n   * Speak filler audio while a long-running tool step is in progress.\n   *\n   * The scheduler waits until the session is continuously idle for\n   * {@link RunContextFillerOptions.delay} milliseconds, then speaks `source`\n   * through {@link AgentSession.say}. When `interval` is set, it waits that\n   * many milliseconds before starting another idle dwell; otherwise it fires at\n   * most once. Agent speech, user speech, and {@link RunContext.update} reset\n   * any pending dwell so filler does not race real conversation turns.\n   *\n   * @example\n   * ```ts\n   * await ctx.filler('Still searching, hang on.', { delay: 5000 }, async () => {\n   *   return await slowLookup();\n   * });\n   * ```\n   */\n  async filler<T>(source: FillerSource, fn: () => Promise<T> | T): Promise<T>;\n  async filler<T>(\n    source: FillerSource,\n    options: RunContextFillerOptions,\n    fn: () => Promise<T> | T,\n  ): Promise<T>;\n  async filler<T>(\n    source: FillerSource,\n    optionsOrFn: RunContextFillerOptions | (() => Promise<T> | T),\n    maybeFn?: () => Promise<T> | T,\n  ): Promise<T> {\n    const options = typeof optionsOrFn === 'function' ? {} : optionsOrFn;\n    const fn = typeof optionsOrFn === 'function' ? optionsOrFn : maybeFn;\n    if (!fn) {\n      throw new Error('RunContext.filler requires a callback scope');\n    }\n\n    const scheduler = new FillerScheduler(this.session, this.speechHandle, source, options);\n    this._fillerSchedulers.push(scheduler);\n    try {\n      return await fn();\n    } finally {\n      await scheduler.close();\n      this._fillerSchedulers = this._fillerSchedulers.filter((s) => s !== scheduler);\n    }\n  }\n\n  _attachExecutor(\n    executor: AttachedToolExecutor<UserData>,\n    firstUpdateFuture: Future<unknown>,\n  ): object {\n    if (this._firstUpdateFuture !== undefined) {\n      throw new Error('Executor already attached');\n    }\n    const attachment = {};\n    this._executor = executor;\n    this._executorAttachment = attachment;\n    this._firstUpdateFuture = firstUpdateFuture;\n    return attachment;\n  }\n\n  _detachExecutor(attachment: object): void {\n    if (this._executorAttachment !== attachment) return;\n    this._executor = undefined;\n    this._executorAttachment = undefined;\n    this._firstUpdateFuture = undefined;\n  }\n\n  async _drainPendingReply(): Promise<void> {\n    if (!this._executor?.replyTask) return;\n    try {\n      await this._executor.replyTask;\n    } catch {\n      // Reply task owns its own logging/errors.\n    }\n  }\n\n  _makeUpdatePair(message: unknown, callIdSuffix: string = ''): [FunctionCall, FunctionCallOutput] {\n    const fncCall = FunctionCall.create({\n      callId: `${this.functionCall.callId}${callIdSuffix}`,\n      name: this.functionCall.name,\n      args: this.functionCall.args,\n      extra: { ...this.functionCall.extra },\n    });\n    return [\n      fncCall,\n      FunctionCallOutput.create({\n        name: fncCall.name,\n        callId: fncCall.callId,\n        output: stringifyToolOutput(message),\n        isError: false,\n      }),\n    ];\n  }\n\n  _recordUpdatePair(pair: [FunctionCall, FunctionCallOutput]): void {\n    this._updates.push(pair);\n  }\n}\n\nfunction renderTemplate(\n  template: PromptTemplate<UpdatePromptArgs> | undefined,\n  args: UpdatePromptArgs,\n): string {\n  if (!template) return args.message;\n  if (typeof template === 'function') return template(args);\n  return template\n    .replaceAll('{functionName}', args.functionName)\n    .replaceAll('{callId}', args.callId)\n    .replaceAll('{message}', args.message);\n}\n\nfunction stringifyToolOutput(value: unknown): string {\n  if (typeof value === 'string') return value;\n  if (value === undefined || value === null) return '';\n  if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n  try {\n    return JSON.stringify(value);\n  } catch {\n    return String(value);\n  }\n}\n\nclass FillerScheduler<UserData = UnknownUserData> {\n  private readonly abortController = new AbortController();\n  private readonly delay: number;\n  private readonly interval?: number;\n  private readonly maxSteps?: number;\n  private readonly task: Promise<void>;\n  private dwellAbortController?: AbortController;\n  private createdSpeeches: SpeechHandle[] = [];\n\n  constructor(\n    private readonly session: AgentSession<UserData>,\n    private readonly speechHandle: SpeechHandle,\n    private readonly source: FillerSource,\n    options: RunContextFillerOptions,\n  ) {\n    const { delay = 0, interval, maxSteps, signal } = options;\n    if (delay < 0) {\n      throw new Error('delay must be non-negative');\n    }\n    if (interval !== undefined && interval < 0) {\n      throw new Error('interval must be non-negative when set');\n    }\n    if (maxSteps !== undefined && maxSteps < 0) {\n      throw new Error('maxSteps must be non-negative when set');\n    }\n\n    this.delay = delay;\n    this.interval = interval;\n    this.maxSteps = maxSteps;\n\n    if (signal?.aborted) {\n      this.abortController.abort();\n    } else {\n      signal?.addEventListener('abort', () => this.abortController.abort(), { once: true });\n    }\n\n    this.task = this.run();\n    void this.task.catch(() => undefined);\n  }\n\n  resetDwell(): void {\n    this.dwellAbortController?.abort();\n  }\n\n  async close(): Promise<void> {\n    this.abortController.abort();\n    await this.task.catch(() => undefined);\n  }\n\n  private async run(): Promise<void> {\n    const onAgentStateChanged = (event: AgentStateChangedEvent): void => {\n      if (event.newState === 'speaking' || event.newState === 'thinking') {\n        this.resetDwell();\n      }\n    };\n    const onUserStateChanged = (event: UserStateChangedEvent): void => {\n      if (event.newState === 'speaking') {\n        this.resetDwell();\n      }\n    };\n\n    this.session.on(AgentSessionEventTypes.AgentStateChanged, onAgentStateChanged);\n    this.session.on(AgentSessionEventTypes.UserStateChanged, onUserStateChanged);\n\n    const loop = this.loop();\n    try {\n      await this.speechHandle.waitIfNotInterrupted([loop]);\n    } finally {\n      this.abortController.abort();\n      this.session.off(AgentSessionEventTypes.AgentStateChanged, onAgentStateChanged);\n      this.session.off(AgentSessionEventTypes.UserStateChanged, onUserStateChanged);\n      await loop.catch(() => undefined);\n    }\n  }\n\n  private async loop(): Promise<void> {\n    while (!this.abortController.signal.aborted) {\n      const idleReached = await waitUnlessAborted(\n        this.session.waitForIdle(),\n        this.abortController.signal,\n      );\n      if (!idleReached) return;\n\n      this.dwellAbortController = new AbortController();\n      const dwellCompleted = await sleepUnlessAborted(this.delay, [\n        this.abortController.signal,\n        this.dwellAbortController.signal,\n      ]);\n      this.dwellAbortController = undefined;\n      if (!dwellCompleted) {\n        continue;\n      }\n\n      if (this.maxSteps !== undefined && this.createdSpeeches.length >= this.maxSteps) {\n        return;\n      }\n\n      const handle = this.createSpeech();\n      if (handle) {\n        this.createdSpeeches.push(handle);\n      }\n\n      if (\n        this.interval === undefined ||\n        (this.maxSteps !== undefined && this.createdSpeeches.length >= this.maxSteps)\n      ) {\n        return;\n      }\n\n      const intervalCompleted = await sleepUnlessAborted(this.interval, [\n        this.abortController.signal,\n      ]);\n      if (!intervalCompleted) return;\n    }\n  }\n\n  private createSpeech(): SpeechHandle | undefined {\n    const value =\n      typeof this.source === 'function' ? this.source(this.createdSpeeches.length) : this.source;\n    if (typeof value === 'string') {\n      return this.session.say(value);\n    }\n    if (isSpeechHandle(value)) {\n      return value;\n    }\n    return undefined;\n  }\n}\n\nasync function waitUnlessAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<boolean> {\n  if (signal.aborted) return false;\n  let onAbort: (() => void) | undefined;\n  const abortPromise = new Promise<false>((resolve) => {\n    onAbort = () => resolve(false);\n    signal.addEventListener('abort', onAbort, { once: true });\n  });\n\n  try {\n    return await Promise.race([promise.then(() => true), abortPromise]);\n  } finally {\n    if (onAbort) {\n      signal.removeEventListener('abort', onAbort);\n    }\n  }\n}\n\nasync function sleepUnlessAborted(ms: number, signals: AbortSignal[]): Promise<boolean> {\n  if (signals.some((signal) => signal.aborted)) return false;\n  return new Promise((resolve) => {\n    const timeout = setTimeout(() => {\n      cleanup();\n      resolve(true);\n    }, ms);\n    const onAbort = () => {\n      clearTimeout(timeout);\n      cleanup();\n      resolve(false);\n    };\n    const cleanup = () => {\n      for (const signal of signals) {\n        signal.removeEventListener('abort', onAbort);\n      }\n    };\n    for (const signal of signals) {\n      signal.addEventListener('abort', onAbort, { once: true });\n    }\n  });\n}\n"],"mappings":"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","names":[]}