{"version":3,"sources":["../../src/realtime/gpt_live_model.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n  type APIConnectOptions,\n  APIConnectionError,\n  APIError,\n  APITimeoutError,\n  AudioByteStream,\n  DEFAULT_API_CONNECT_OPTIONS,\n  Future,\n  intervalForRetry,\n  llm,\n  log,\n  type metrics,\n  shortuuid,\n} from '@livekit/agents';\nimport { AudioFrame, AudioResampler } from '@livekit/rtc-node';\nimport { ReadableStream, type ReadableStreamDefaultController } from 'node:stream/web';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport WebSocket from 'ws';\nimport { toResponsesTool } from '../tool_utils.js';\nimport type {\n  ClientEvent,\n  Delegation,\n  DelegationTarget,\n  InputItem,\n  InputRole,\n  ResponsesConfig,\n  ResponsesEvent,\n  ServerEvent,\n} from './gpt_live_types.js';\n\nconst SAMPLE_RATE = 24000;\nconst MIN_SILENCE_DURATION = 800;\nconst DEFAULT_MODEL = 'gpt-live-1';\nconst DEFAULT_BACKEND_MODEL = 'gpt-5.6-luna';\nconst SPEAK_NOW = 'Do not wait for the caller to speak first. After that, pause and listen.';\nconst ASK_INSTRUCTED = `Immediately follow the instruction below. ${SPEAK_NOW}`;\nconst ASK_TYPED = `Reply to the caller now, don't repeat what they said. ${SPEAK_NOW}`;\nconst ASK_BARE = `Reply to the caller now. ${SPEAK_NOW}`;\nconst SESSION_CLOSE_TIMEOUT = 5000;\nconst FATAL_ERROR_CODES = new Set([\n  'insufficient_quota',\n  'invalid_api_key',\n  'account_deactivated',\n  'billing_hard_limit_reached',\n]);\n\n/** Settings for the backend Responses model. Unset fields use the service defaults.\n * @public\n */\nexport interface ResponsesDelegationOptions {\n  /** Defaults to gpt-5.6-luna. */\n  model?: string;\n  /** Backend instructions, separate from the voice persona. */\n  instructions?: string;\n  /** Restrict backend tool selection. Null restores automatic selection. */\n  toolChoice?: llm.ToolChoice | null;\n  /** Allow the backend to request multiple tools in one response. */\n  parallelToolCalls?: boolean;\n  /** Reasoning effort for the backend model. */\n  reasoning?: ResponsesConfig['reasoning'];\n  /** Text format and verbosity for backend responses. */\n  text?: ResponsesConfig['text'];\n  /** Processing tier for backend responses. */\n  serviceTier?: ResponsesConfig['service_tier'];\n  /** Maximum tokens per backend response; the service requires at least 16. */\n  maxOutputTokens?: number;\n}\n\n/** Work handed to the application under client delegation.\n * @public\n */\nexport interface GPTLiveDelegation {\n  /** Answer with GPTLiveSession.appendCommentary. Valid only on the connection that created it. */\n  id: string;\n  /** The caller's current turn, which may not yet be in the agent's chat context. */\n  pendingTranscript: string;\n}\n\n/** Suggested GPT-Live voice names. Other supported names also pass through to the API. @public */\nexport type GPTLiveVoices = 'aster' | 'beacon' | 'cinder' | 'marin' | 'stone' | 'vesper';\n\n/** Options for the OpenAI GPT-Live full-duplex voice model.\n * @public\n */\nexport interface GPTLiveModelOptions {\n  /** Voice model identifier. Defaults to gpt-live-1. */\n  model?: string;\n  /**\n   * A named voice (marin by default), or an authorized custom voice object. Fixed at startup.\n   * Names pass through unchanged.\n   */\n  voice?: GPTLiveVoices | (string & NonNullable<unknown>) | Record<string, unknown>;\n  /** Fixed at startup. Client delegation requires an agent with no tools. */\n  delegation?: DelegationTarget;\n  /** Backend configuration when delegation is responses (the default). */\n  responsesOptions?: ResponsesDelegationOptions;\n  /** Falls back to OPENAI_API_KEY. */\n  apiKey?: string;\n  /** Falls back to OPENAI_BASE_URL, then https://api.openai.com/v1. */\n  baseURL?: string;\n  /** Recycle the connection after this many milliseconds. Null (the default) disables the timer. */\n  maxSessionDuration?: number | null;\n  /** Connection/startup timeout and retry limits. Defaults to DEFAULT_API_CONNECT_OPTIONS. */\n  connOptions?: APIConnectOptions;\n}\n\ntype LiveOptions = Required<GPTLiveModelOptions>;\n\n/** OpenAI GPT-Live full-duplex voice model, ready to pass to AgentSession.\n * @public\n */\nexport class GPTLiveModel extends llm.DuplexModel {\n  /** @internal */\n  readonly _opts: Required<GPTLiveModelOptions>;\n\n  /** Configure a voice model. Throws when no OpenAI API key is available. */\n  constructor(options: GPTLiveModelOptions = {}) {\n    super({\n      userTranscription: true,\n      autoToolReplyGeneration: true,\n      midSessionChatCtxUpdate: false,\n      midSessionInstructionsUpdate: false,\n      midSessionToolsUpdate: (options.delegation ?? 'responses') === 'responses',\n    });\n    const apiKey = options.apiKey ?? process.env.OPENAI_API_KEY;\n    if (!apiKey) {\n      throw new Error('OpenAI API key is required: pass apiKey or set OPENAI_API_KEY');\n    }\n    this._opts = {\n      model: options.model ?? DEFAULT_MODEL,\n      voice: options.voice ?? 'marin',\n      delegation: options.delegation ?? 'responses',\n      responsesOptions: { ...options.responsesOptions },\n      apiKey,\n      baseURL: options.baseURL ?? process.env.OPENAI_BASE_URL ?? 'https://api.openai.com/v1',\n      maxSessionDuration: options.maxSessionDuration ?? null,\n      connOptions: { ...(options.connOptions ?? DEFAULT_API_CONNECT_OPTIONS) },\n    };\n  }\n\n  /** Voice model identifier used for sessions and metrics. */\n  get model(): string {\n    return this._opts.model;\n  }\n  /** Host of the configured API endpoint. */\n  get provider(): string {\n    return new URL(this._opts.baseURL).host;\n  }\n\n  /** Keep output active through short pauses in speech. */\n  audioGate(): llm.AudioGate {\n    return new llm.FixedGate(0.0006, { minSilenceDuration: MIN_SILENCE_DURATION });\n  }\n\n  /** Create a connection that starts after the framework configures the session. */\n  session(): GPTLiveSession {\n    return new GPTLiveSession(this);\n  }\n  /** The model owns no shared resources. Close each session to release its connection. */\n  async close(): Promise<void> {}\n}\n\ntype Role = 'user' | 'assistant';\ninterface Speech {\n  messageId: string;\n  text: string;\n  endMs?: number;\n  startedAt: number;\n  quietMs: number;\n}\n\n/**\n * GPT-Live WebSocket session, accessible through Agent.duplexSession.\n * Also emits openai_server_event_received, openai_client_event_queued and delegation_created.\n * Append methods queue context without waiting for acknowledgment. The appended events arrive\n * at the estimated context-injection end and do not indicate speech completion.\n * @public\n */\nexport class GPTLiveSession extends llm.DuplexSession<{\n  openai_server_event_received: (event: ServerEvent) => void;\n  openai_client_event_queued: (event: ClientEvent | Record<string, unknown>) => void;\n  delegation_created: (event: GPTLiveDelegation) => void;\n}> {\n  private readonly opts: LiveOptions;\n  private readonly logger = log();\n  private readonly debug = Number(process.env.LK_OPENAI_DEBUG ?? 0) !== 0;\n  private readonly history = llm.ChatContext.empty();\n  private readonly speech = new Map<Role, Speech>();\n  // delegation id -> call ids of its response that has not completed yet; on completion the\n  // call ids move to the open set, and stay there until each output is sent to the backend.\n  // backendResponsePending is set once an output is sent and cleared by the response.create\n  private readonly backendRunningResponses = new Map<string | null, Set<string>>();\n  private readonly backendOpenCalls = new Set<string>();\n  private backendResponsePending = false;\n  private readonly delegationIds = new Set<string>();\n  private readonly bstream = new AudioByteStream(SAMPLE_RATE, 1, SAMPLE_RATE / 10);\n  private inputResampler?: AudioResampler;\n  private inputRate?: number;\n  private _tools = llm.ToolContext.empty();\n  private instructions?: string;\n  private askedItemId?: string;\n  private _sessionId?: string;\n  private usageSeconds = 0;\n  private sessionStartSent = false;\n  private sessionStarted = false;\n  private closing = false;\n  private audioClosed = false;\n  private queued: {\n    event: ClientEvent | Record<string, unknown>;\n    replayOnReconnect: boolean;\n    context?: string;\n  }[] = [];\n  private ws?: WebSocket;\n  private connectionDone?: Future<Error | undefined>;\n  private connectionDraining = false;\n  private requestConnectionClose?: () => void;\n  private readonly shutdown = new AbortController();\n  private readonly mainTask: Promise<void>;\n  private audioController!: ReadableStreamDefaultController<llm.DuplexAudioFrame>;\n  private readonly output = new ReadableStream<llm.DuplexAudioFrame>({\n    start: (controller) => {\n      this.audioController = controller;\n    },\n    cancel: () => {\n      this.audioClosed = true;\n    },\n  });\n\n  /** Create a session using a copy of the model configuration. */\n  constructor(model: GPTLiveModel) {\n    super(model);\n    this.opts = { ...model._opts, responsesOptions: { ...model._opts.responsesOptions } };\n    // Let the adapter attach error/metrics listeners before starting the connection.\n    this.mainTask = Promise.resolve()\n      .then(() => this.main())\n      .catch((error) => {\n        this.logger.error({ 'lk.pii.error': error }, 'GPT-Live session failed');\n      });\n  }\n\n  /** Provider session identifier. Changes when a replacement connection starts. */\n  get sessionId(): string | undefined {\n    return this._sessionId;\n  }\n  /** Mono 24 kHz PCM output, retained across reconnects and closed on shutdown. */\n  get audioStream(): ReadableStream<llm.DuplexAudioFrame> {\n    return this.output;\n  }\n  /** Copy of the tools available to the backend Responses model. */\n  get tools(): llm.ToolContext {\n    return this._tools.copy();\n  }\n\n  /** Queue a wire event. Commands wait for session.started before being sent. */\n  sendEvent(event: ClientEvent | Record<string, unknown>): void {\n    this.queueEvent(event, true);\n  }\n\n  private queueEvent(\n    event: ClientEvent | Record<string, unknown>,\n    replayOnReconnect: boolean,\n    context?: string,\n  ): void {\n    if (this.closing) return;\n    this.queued.push({ event, replayOnReconnect, context });\n    this.flushQueued();\n  }\n\n  private flushQueued(): void {\n    if (this.connectionDraining || !this.sessionStarted || this.ws?.readyState !== WebSocket.OPEN)\n      return;\n    while (this.queued.length) {\n      const { event, context } = this.queued.shift()!;\n      if (context !== undefined)\n        this.history.insert(new llm.ChatMessage({ role: 'developer', content: [context] }));\n      this.wsSend(this.ws, event);\n    }\n  }\n\n  private wsSend(ws: WebSocket, event: ClientEvent | Record<string, unknown>): void {\n    this.emit('openai_client_event_queued', event);\n    if (this.debug && event.type !== 'session.input_audio.append')\n      this.logger.debug({ 'lk.pii.event': event }, 'GPT-Live client event');\n    const done = this.connectionDone;\n    try {\n      ws.send(JSON.stringify(event), (error) => {\n        if (error) done?.resolve(new APIConnectionError({ message: 'GPT-Live send failed' }));\n      });\n    } catch {\n      done?.resolve(new APIConnectionError({ message: 'GPT-Live send failed' }));\n    }\n  }\n\n  private buildDelegation(): Delegation {\n    if (this.opts.delegation === 'client') return { type: 'client' };\n    const opts = this.opts.responsesOptions;\n    const tools = this.buildTools();\n    return {\n      type: 'responses',\n      responses: {\n        model: opts.model ?? DEFAULT_BACKEND_MODEL,\n        instructions: opts.instructions,\n        tools: tools.length ? tools : undefined,\n        tool_choice: opts.toolChoice !== undefined ? toToolChoice(opts.toolChoice) : undefined,\n        parallel_tool_calls: opts.parallelToolCalls,\n        reasoning: opts.reasoning,\n        text: opts.text,\n        service_tier: opts.serviceTier,\n        max_output_tokens: opts.maxOutputTokens,\n      },\n    };\n  }\n\n  private buildTools(): NonNullable<ResponsesConfig['tools']> {\n    return this._tools.flatten().flatMap((tool) => {\n      const converted = toResponsesTool(tool, false);\n      if (converted) return [converted];\n      this.logger.debug({ 'lk.pii.tool': tool.id }, 'GPT-Live delegation ignores unsupported tool');\n      return [];\n    });\n  }\n\n  private sessionStartEvent(): ClientEvent {\n    const items = this.history.items.flatMap((item): InputItem[] => {\n      const rendered = renderItem(item);\n      if (!rendered) return [];\n      const [role, text] = rendered;\n      return [\n        {\n          type: 'message',\n          role,\n          content: [{ type: role === 'assistant' ? 'output_text' : 'input_text', text }],\n        },\n      ];\n    });\n    if (items.length > 128) {\n      this.logger.warn(\n        { dropped: items.length - 128, kept: 128 },\n        'GPT-Live startup history exceeds the message limit; dropping the oldest',\n      );\n    }\n    return {\n      type: 'session.start',\n      event_id: shortuuid('session_start_'),\n      session: {\n        model: this.opts.model,\n        instructions: this.instructions,\n        input: items.length ? items.slice(-128) : undefined,\n        audio: {\n          format: { type: 'audio/pcm', rate: SAMPLE_RATE },\n          output: { voice: this.opts.voice },\n        },\n        delegation: this.buildDelegation(),\n      },\n    };\n  }\n\n  private sendDelegationUpdate(responses: ResponsesConfig): void {\n    if (this.opts.delegation !== 'responses' || !this.sessionStartSent) return;\n    this.queueEvent(\n      {\n        type: 'session.update',\n        event_id: shortuuid('delegation_update_'),\n        session: { delegation: { type: 'responses', responses } },\n      } satisfies ClientEvent,\n      false,\n    );\n  }\n\n  private async main(): Promise<void> {\n    let retries = 0;\n    let reconnecting = false;\n    try {\n      while (!this.closing) {\n        try {\n          await this.runConnection(\n            () => {\n              if (reconnecting) {\n                // History and delegation settings are rebuilt in session.start.\n                this.queued = this.queued.filter((command) => command.replayOnReconnect);\n                this.resetInputAudio();\n                this.endSpeech('user');\n                this.speech.clear();\n                this.backendRunningResponses.clear();\n                this.backendOpenCalls.clear();\n                this.backendResponsePending = false;\n                this.delegationIds.clear();\n                this.usageSeconds = 0;\n                this._sessionId = undefined;\n              }\n            },\n            () => {\n              retries = 0;\n              if (reconnecting) this.emit('session_reconnected', {});\n            },\n          );\n        } catch (error) {\n          if (this.closing) break;\n          const err =\n            error instanceof APIError\n              ? error\n              : new APIConnectionError({\n                  message: 'GPT-Live session failed',\n                  options: { retryable: false },\n                });\n          const recoverable = err.retryable && retries < this.opts.connOptions.maxRetry;\n          this.emitError(err, recoverable);\n          if (!recoverable) throw err;\n          await delay(intervalForRetry(this.opts.connOptions, retries++), undefined, {\n            signal: this.shutdown.signal,\n          }).catch((error) => {\n            if (!this.closing) throw error;\n          });\n        } finally {\n          this.sessionStartSent = false;\n          this.sessionStarted = false;\n        }\n        reconnecting = true;\n      }\n    } finally {\n      this.endSpeech('user');\n      this.delegationIds.clear();\n      this.resetInputAudio();\n      if (!this.audioClosed) {\n        this.audioClosed = true;\n        this.audioController.close();\n      }\n    }\n  }\n\n  private async runConnection(onOpen: () => void, onStarted: () => void): Promise<void> {\n    const url = new URL(this.opts.baseURL);\n    url.protocol =\n      url.protocol === 'https:' ? 'wss:' : url.protocol === 'http:' ? 'ws:' : url.protocol;\n    url.pathname = url.pathname.replace(/\\/$/, '');\n    if (!url.pathname.endsWith('/live/sessions')) url.pathname += '/live/sessions';\n    url.search = '';\n    url.hash = '';\n    const done = new Future<Error | undefined>();\n    this.connectionDone = done;\n    const startTime = performance.now();\n    const ws = new WebSocket(url, {\n      headers: {\n        'User-Agent': 'LiveKit Agents',\n        Authorization: `Bearer ${this.opts.apiKey}`,\n      },\n      handshakeTimeout: this.opts.connOptions.timeoutMs,\n    });\n    this.ws = ws;\n    let recycleTimer: ReturnType<typeof setTimeout> | undefined;\n    let startupTimer: ReturnType<typeof setTimeout> | undefined;\n    let closeTimer: ReturnType<typeof setTimeout> | undefined;\n    const requestClose = () => {\n      if (this.connectionDraining || done.done) return;\n      this.connectionDraining = true;\n      if (this.sessionStarted && ws.readyState === WebSocket.OPEN) {\n        closeTimer = setTimeout(() => done.resolve(undefined), SESSION_CLOSE_TIMEOUT);\n        this.wsSend(ws, { type: 'session.close' } satisfies ClientEvent);\n      } else {\n        done.resolve(undefined);\n      }\n    };\n    this.requestConnectionClose = requestClose;\n    const closed = new Future();\n    ws.once('close', () => closed.resolve());\n    ws.on('open', () => {\n      this._reportConnectionAcquired(performance.now() - startTime);\n      onOpen();\n      void Promise.race([this._configured.wait(), done.await])\n        .then(() => {\n          if (this.closing || done.done) return;\n          this.sessionStartSent = true;\n          startupTimer = setTimeout(\n            () =>\n              done.resolve(new APITimeoutError({ message: 'GPT-Live session start timed out' })),\n            this.opts.connOptions.timeoutMs,\n          );\n          this.wsSend(ws, this.sessionStartEvent());\n        })\n        .catch((error: Error) => done.resolve(error));\n    });\n    ws.on('error', () =>\n      done.resolve(new APIConnectionError({ message: 'GPT-Live connection failed' })),\n    );\n    ws.on('close', () =>\n      done.resolve(\n        this.closing || this.connectionDraining\n          ? undefined\n          : new APIConnectionError({ message: 'OpenAI Live API connection closed unexpectedly' }),\n      ),\n    );\n    ws.on('message', (data, isBinary) => {\n      if (isBinary || done.done) return;\n      try {\n        const event = JSON.parse(data.toString()) as ServerEvent;\n        if (event.type === 'session.delegation.created' && event.delegation?.id)\n          this.delegationIds.add(event.delegation.id);\n        this.emit('openai_server_event_received', event);\n        if (this.debug && event.type !== 'session.output_audio.delta')\n          this.logger.debug({ 'lk.pii.event': event }, 'GPT-Live server event');\n        if (\n          this.closing &&\n          event.type !== 'session.usage.updated' &&\n          event.type !== 'session.closed'\n        )\n          return;\n        const started = event.type === 'session.started' && !this.sessionStarted;\n        this.handleEvent(event);\n        if (started) {\n          clearTimeout(startupTimer);\n          onStarted();\n          if (this.opts.maxSessionDuration !== null) {\n            recycleTimer = setTimeout(requestClose, this.opts.maxSessionDuration);\n          }\n        }\n      } catch (error) {\n        if (error instanceof APIError && !error.retryable) done.resolve(error);\n        else this.logger.error({ 'lk.pii.error': error }, 'Failed to handle GPT-Live event');\n      }\n    });\n    try {\n      const error = await done.await;\n      if (error) throw error;\n    } finally {\n      this.sessionStartSent = false;\n      this.sessionStarted = false;\n      clearTimeout(recycleTimer);\n      clearTimeout(startupTimer);\n      clearTimeout(closeTimer);\n      this.connectionDraining = false;\n      this.requestConnectionClose = undefined;\n      this.ws = undefined;\n      this.connectionDone = undefined;\n      ws.terminate();\n      await closed.await;\n    }\n  }\n\n  private handleEvent(event: ServerEvent): void {\n    switch (event.type) {\n      case 'session.started':\n        this._sessionId = event.session?.id ?? this._sessionId;\n        this.sessionStarted = true;\n        this.flushQueued();\n        break;\n      case 'session.output_audio.delta': {\n        const data = Buffer.from(event.delta ?? '', 'base64');\n        if (!data.length || this.audioClosed) break;\n        const samples = new Int16Array(data.length / 2);\n        for (let i = 0; i < samples.length; i++) samples[i] = data.readInt16LE(i * 2);\n        this.audioController.enqueue({\n          frame: new AudioFrame(samples, SAMPLE_RATE, 1, samples.length),\n        });\n        break;\n      }\n      case 'session.input_transcript.delta':\n      case 'session.output_transcript.delta':\n        this.handleTranscript(\n          event.type === 'session.input_transcript.delta' ? 'user' : 'assistant',\n          event,\n        );\n        break;\n      case 'session.delegation.created': {\n        const delegation = event.delegation;\n        if (!delegation?.id)\n          this.logger.warn('GPT-Live delegation has no id; nothing can answer it');\n        else if (delegation.target === 'client')\n          this.emit('delegation_created', {\n            id: delegation.id,\n            pendingTranscript: this.speech.get('user')?.text ?? '',\n          } satisfies GPTLiveDelegation);\n        break;\n      }\n      case 'response.event':\n        this.handleResponseEvent(event.delegation_id ?? null, event.event ?? { type: '' });\n        break;\n      case 'session.usage.updated':\n      case 'session.closed':\n        if (event.type === 'session.closed')\n          this.logger.debug(\n            { reason: event.reason ?? null, sessionId: this._sessionId },\n            'GPT-Live session closed',\n          );\n        if (event.context_window?.usage_ratio != null)\n          this.logger.debug(\n            { usageRatio: event.context_window.usage_ratio },\n            'GPT-Live context window utilization',\n          );\n        this.handleUsage(event.usage?.seconds);\n        if (event.type === 'session.closed') this.connectionDone?.resolve(undefined);\n        break;\n      case 'error': {\n        const error = event.error ?? {};\n        const recoverable = !FATAL_ERROR_CODES.has(error.code || error.type || '');\n        this.logger.error({ 'lk.pii.error': error }, 'GPT-Live returned an error');\n        const apiError = new APIError('GPT-Live returned an error', {\n          retryable: recoverable,\n        });\n        if (!recoverable) throw apiError;\n        this.emitError(apiError, true);\n        break;\n      }\n      default:\n        this.logger.debug({ 'lk.pii.type': event.type }, 'GPT-Live acknowledged a command');\n    }\n  }\n\n  private handleTranscript(\n    role: Role,\n    event: { delta?: string; start_ms?: number | null; end_ms?: number | null },\n  ): void {\n    if (!event.delta) return;\n    let speech = this.speech.get(role);\n    if (\n      speech?.endMs !== undefined &&\n      event.start_ms != null &&\n      event.start_ms - speech.endMs > MIN_SILENCE_DURATION\n    ) {\n      this.endSpeech(role);\n      speech = undefined;\n    }\n    if (!speech) {\n      speech = { messageId: shortuuid('speech_'), text: '', startedAt: Date.now(), quietMs: 0 };\n      this.speech.set(role, speech);\n      this.history.insert(\n        new llm.ChatMessage({\n          id: speech.messageId,\n          role,\n          content: [''],\n          transcriptConfidence: role === 'user' ? 1 : undefined,\n        }),\n      );\n      if (role === 'user') this.emit('input_speech_started', {});\n    }\n    speech.text += event.delta;\n    speech.quietMs = 0;\n    if (event.end_ms != null) speech.endMs = Math.max(speech.endMs ?? 0, event.end_ms);\n    const message = this.history.getById(speech.messageId);\n    if (message?.type === 'message') message.content[0] = speech.text;\n    if (role === 'user') {\n      this.emit('input_audio_transcription_completed', {\n        itemId: speech.messageId,\n        transcript: speech.text,\n        isFinal: false,\n        turnStartedAt: speech.startedAt,\n      } satisfies llm.InputTranscriptionCompleted);\n    } else {\n      this.emit('transcript_delta', {\n        text: event.delta,\n        startMs: event.start_ms ?? undefined,\n        endMs: event.end_ms ?? undefined,\n      } satisfies llm.DuplexOutputTranscriptDelta);\n    }\n  }\n\n  private endSpeech(role: Role): void {\n    const speech = this.speech.get(role);\n    this.speech.delete(role);\n    if (!speech || role !== 'user') return;\n    this.emit('input_audio_transcription_completed', {\n      itemId: speech.messageId,\n      transcript: speech.text,\n      isFinal: true,\n      turnStartedAt: speech.startedAt,\n    } satisfies llm.InputTranscriptionCompleted);\n    this.emit('input_speech_stopped', {\n      userTranscriptionEnabled: false,\n    } satisfies llm.InputSpeechStoppedEvent);\n  }\n\n  private handleResponseEvent(delegationId: string | null, event: ResponsesEvent): void {\n    switch (event.type) {\n      case 'response.created':\n        this.backendRunningResponses.set(delegationId, new Set());\n        break;\n      case 'response.output_item.done': {\n        const item = event.item;\n        if (!item || item.type !== 'function_call') return;\n        if (!item.call_id || !item.name || item.arguments == null) {\n          this.logger.warn(\n            { 'lk.pii.call_id': item.call_id, 'lk.pii.name': item.name },\n            'GPT-Live dropping function call with missing fields',\n          );\n          return;\n        }\n        let calls = this.backendRunningResponses.get(delegationId);\n        if (!calls) {\n          this.logger.warn(\n            { 'lk.pii.call_id': item.call_id, 'lk.pii.delegation_id': delegationId },\n            'GPT-Live function call outside a known response',\n          );\n          calls = this.backendOpenCalls;\n        }\n        calls.add(item.call_id);\n        const call = new llm.FunctionCall({\n          id: item.id ?? shortuuid('fc_'),\n          callId: item.call_id,\n          name: item.name,\n          args: item.arguments,\n        });\n        this.history.insert(call);\n        this.emit('function_call', call);\n        break;\n      }\n      case 'response.completed': {\n        this.handleResponseUsage(event.response);\n        const calls = this.backendRunningResponses.get(delegationId);\n        if (calls) {\n          this.backendRunningResponses.delete(delegationId);\n          for (const callId of calls) this.backendOpenCalls.add(callId);\n        }\n        this.maybeContinueResponse();\n        break;\n      }\n      case 'response.failed':\n      case 'response.incomplete': {\n        this.handleResponseUsage(event.response);\n        this.logger.warn(\n          {\n            type: event.type,\n            'lk.pii.delegation_id': delegationId,\n            'lk.pii.error': event.response?.error,\n            'lk.pii.incomplete_details': event.response?.incomplete_details,\n          },\n          'GPT-Live backend response did not complete',\n        );\n        // the service discards a failed response's calls: an output for one is refused, so it\n        // goes to the voice model as context instead\n        this.backendRunningResponses.delete(delegationId);\n        this.maybeContinueResponse();\n        break;\n      }\n    }\n  }\n\n  private handleResponseUsage(response: ResponsesEvent['response']): void {\n    const usage = response?.usage;\n    if (usage) {\n      const metric: metrics.LLMMetrics & { reasoningTokens: number } = {\n        type: 'llm_metrics',\n        label: this.duplexModel.label(),\n        requestId: response?.id ?? '',\n        timestamp: Date.now(),\n        durationMs: 0,\n        ttftMs: -1,\n        cancelled: false,\n        tokensPerSecond: 0,\n        promptTokens: usage.input_tokens ?? 0,\n        promptCachedTokens: usage.input_tokens_details?.cached_tokens ?? 0,\n        cacheCreationTokens: usage.input_tokens_details?.cache_write_tokens ?? 0,\n        completionTokens: usage.output_tokens ?? 0,\n        reasoningTokens: usage.output_tokens_details?.reasoning_tokens ?? 0,\n        totalTokens: usage.total_tokens ?? 0,\n        metadata: {\n          modelName: response?.model || this.opts.responsesOptions.model || DEFAULT_BACKEND_MODEL,\n          modelProvider: this.duplexModel.provider,\n        },\n      };\n      this.emit('metrics_collected', metric);\n    }\n  }\n\n  private maybeContinueResponse(): void {\n    // one response.create continues the chain, and only once nothing is still asking and every\n    // call in the conversation has its answer: the service refuses a partial batch\n    if (\n      this.backendRunningResponses.size ||\n      this.backendOpenCalls.size ||\n      !this.backendResponsePending\n    )\n      return;\n    this.backendResponsePending = false;\n    this.queueEvent(\n      {\n        type: 'response.create',\n        event_id: shortuuid('response_create_'),\n      } satisfies ClientEvent,\n      false,\n    );\n  }\n\n  private handleUsage(seconds: number | undefined): void {\n    if (seconds === undefined || !Number.isFinite(seconds) || seconds < this.usageSeconds) return;\n    const previous = this.usageSeconds;\n    this.usageSeconds = seconds;\n    this.emit('metrics_collected', {\n      type: 'realtime_model_metrics',\n      label: this.duplexModel.label(),\n      requestId: this._sessionId ?? '',\n      timestamp: Date.now(),\n      durationMs: 0,\n      ttftMs: -1,\n      cancelled: false,\n      sessionDurationMs: Math.max(0, seconds - previous) * 1000,\n      inputTokens: 0,\n      outputTokens: 0,\n      totalTokens: 0,\n      tokensPerSecond: 0,\n      inputTokenDetails: { audioTokens: 0, textTokens: 0, imageTokens: 0, cachedTokens: 0 },\n      outputTokenDetails: { audioTokens: 0, textTokens: 0, imageTokens: 0 },\n      metadata: { modelName: this.duplexModel.model, modelProvider: this.duplexModel.provider },\n    } satisfies metrics.RealtimeModelMetrics);\n  }\n\n  private emitError(error: Error, recoverable: boolean): void {\n    this.emit('error', {\n      type: 'realtime_model_error',\n      timestamp: Date.now(),\n      label: this.duplexModel.label(),\n      error,\n      recoverable,\n    } satisfies llm.RealtimeModelError);\n  }\n\n  /** Buffer microphone audio, mixing to mono and resampling to 24 kHz as needed. */\n  pushAudio(frame: AudioFrame): void {\n    if (this.closing) return;\n    const speech = this.speech.get('user');\n    if (speech) {\n      speech.quietMs += Math.round((frame.samplesPerChannel / frame.sampleRate) * 1000);\n      if (speech.quietMs >= MIN_SILENCE_DURATION) this.endSpeech('user');\n    }\n    if (frame.channels !== 1) {\n      const mono = new Int16Array(frame.samplesPerChannel);\n      for (let i = 0; i < mono.length; i++) {\n        let sum = 0;\n        for (let channel = 0; channel < frame.channels; channel++)\n          sum += frame.data[i * frame.channels + channel]!;\n        mono[i] = Math.round(sum / frame.channels);\n      }\n      frame = new AudioFrame(mono, frame.sampleRate, 1, mono.length);\n    }\n    if (this.inputRate !== frame.sampleRate) {\n      this.inputResampler?.close();\n      this.inputResampler =\n        frame.sampleRate === SAMPLE_RATE\n          ? undefined\n          : new AudioResampler(frame.sampleRate, SAMPLE_RATE, 1);\n      this.inputRate = frame.sampleRate;\n    }\n    for (const resampled of this.inputResampler ? this.inputResampler.push(frame) : [frame]) {\n      for (const chunk of this.bstream.write(resampled.data)) {\n        this.sendEvent({\n          type: 'session.input_audio.append',\n          audio: Buffer.from(\n            chunk.data.buffer,\n            chunk.data.byteOffset,\n            chunk.data.byteLength,\n          ).toString('base64'),\n        } satisfies ClientEvent);\n      }\n    }\n  }\n\n  private resetInputAudio(): void {\n    // Discard partial samples from the old session, including the resampler's filter history.\n    this.bstream.flush();\n    this.inputResampler?.close();\n    this.inputResampler = undefined;\n    this.inputRate = undefined;\n  }\n\n  /** Add a standing rule retained in reconnect history. The service caps each append at 500 tokens. */\n  appendInstructions(text: string, options: { delegationId?: string | null } = {}): void {\n    this.append('session.instructions.append', text, options.delegationId ?? null, {\n      persist: true,\n    });\n  }\n  /** Add silent context retained in reconnect history. The service caps each append at 500 tokens. */\n  appendThinking(text: string, options: { delegationId?: string | null } = {}): void {\n    this.append('session.thinking.append', text, options.delegationId ?? null, { persist: true });\n  }\n  /** Give the model text to paraphrase aloud, or answer a client delegation. Capped at 500 tokens by the service. */\n  appendCommentary(text: string, options: { delegationId?: string | null } = {}): void {\n    this.append('session.commentary.append', text, options.delegationId ?? null);\n  }\n  private append(\n    type: 'session.instructions.append' | 'session.thinking.append' | 'session.commentary.append',\n    content: string,\n    delegationId: string | null,\n    options: { replayOnReconnect?: boolean; persist?: boolean } = {},\n  ): void {\n    if (delegationId !== null && !this.delegationIds.has(delegationId)) {\n      this.logger.debug('GPT-Live ignoring append for an inactive delegation');\n      return;\n    }\n    this.queueEvent(\n      {\n        type,\n        event_id: shortuuid('append_'),\n        delegation_id: delegationId,\n        content,\n      } satisfies ClientEvent,\n      delegationId === null && (options.replayOnReconnect ?? true),\n      options.persist ? content : undefined,\n    );\n  }\n  /** Replace microphone input with silence while the model continues speaking. */\n  muteInput(): void {\n    this.sendEvent({\n      type: 'session.input_audio.mute',\n      event_id: shortuuid('mute_'),\n    } satisfies ClientEvent);\n  }\n  /** Restore microphone input. */\n  unmuteInput(): void {\n    this.sendEvent({\n      type: 'session.input_audio.unmute',\n      event_id: shortuuid('unmute_'),\n    } satisfies ClientEvent);\n  }\n\n  /** Drain final provider usage, then close the transport and output stream. */\n  protected async closeConnection(): Promise<void> {\n    if (!this.closing) {\n      this.closing = true;\n      this.shutdown.abort();\n      this.requestConnectionClose?.();\n    }\n    await this.mainTask;\n  }\n\n  /** Set the initial voice instructions. Changes after session.start are rejected. */\n  async _updateInstructions(instructions: string): Promise<void> {\n    if (this.sessionStartSent && instructions !== this.instructions) {\n      throw new llm.RealtimeError(\n        'gpt-live voice instructions are immutable after session start; use appendInstructions for a standing rule',\n      );\n    }\n    this.instructions = instructions;\n  }\n  /** Update backend tools. Client delegation requires an empty tool context. */\n  async _updateTools(tools: llm.ToolContext): Promise<void> {\n    if (this.opts.delegation === 'client' && tools.flatten().length) {\n      throw new llm.RealtimeError(\n        `gpt-live client delegation has no tool channel, so the model can never call ${tools\n          .flatten()\n          .map((tool) => tool.id)\n          .sort()\n          .join(\n            ', ',\n          )}. Leave the agent's tools empty and answer delegation_created with appendCommentary, or pass delegation=\"responses\" to run tools on the backend model.`,\n      );\n    }\n    this._tools = tools.copy();\n    this.sendDelegationUpdate({ tools: this.buildTools() });\n  }\n  /** Retain framework chat items for reconnects and send their context or tool results. */\n  async _appendItems(items: llm.ChatItem[]): Promise<void> {\n    this.history.insert(items);\n    if (!this.sessionStartSent) return;\n    const outputs: llm.FunctionCallOutput[] = [];\n    const lines: string[] = [];\n    for (const item of items) {\n      if (item.type === 'message' && (item.role === 'system' || item.role === 'developer')) {\n        if (item.textContent)\n          this.append('session.instructions.append', item.textContent, null, {\n            replayOnReconnect: false,\n          });\n      } else if (\n        item.type === 'function_call_output' &&\n        (this.backendOpenCalls.has(item.callId) ||\n          [...this.backendRunningResponses.values()].some((calls) => calls.has(item.callId)))\n      ) {\n        outputs.push(item);\n      } else {\n        const rendered = renderItem(item);\n        if (rendered) lines.push(`${rendered[0]}: ${rendered[1]}`);\n      }\n    }\n    if (lines.length)\n      this.append('session.thinking.append', lines.join('\\n'), null, { replayOnReconnect: false });\n    for (const output of outputs) {\n      this.queueEvent(\n        {\n          type: 'response.item.create',\n          event_id: shortuuid('tool_output_'),\n          item: { type: 'function_call_output', call_id: output.callId, output: output.output },\n        } satisfies ClientEvent,\n        false,\n      );\n      this.backendOpenCalls.delete(output.callId);\n      for (const calls of this.backendRunningResponses.values()) calls.delete(output.callId);\n    }\n    if (outputs.length) {\n      this.backendResponsePending = true;\n      this.maybeContinueResponse();\n    }\n  }\n  /** Prompt an immediate spoken reply to instructions or the newest typed user message. */\n  _generateReply(instructions?: string): void {\n    if (instructions !== undefined) {\n      this.appendCommentary(`${ASK_INSTRUCTED}\\n\\n${instructions}`);\n      return;\n    }\n    const newest = this.history.items.at(-1);\n    const typed =\n      newest?.type === 'message' &&\n      newest.role === 'user' &&\n      newest.transcriptConfidence === undefined &&\n      newest.id !== this.askedItemId\n        ? newest.textContent\n        : undefined;\n    this.askedItemId = newest?.id;\n    this.appendCommentary(typed ? `${ASK_TYPED}\\n\\n${typed}` : ASK_BARE);\n  }\n  /** Update backend tool selection for this session and future reconnects. */\n  _updateOptions(options: { toolChoice?: llm.ToolChoice | null }): void {\n    if (options.toolChoice !== undefined) {\n      this.opts.responsesOptions.toolChoice = options.toolChoice;\n      this.sendDelegationUpdate({ tool_choice: toToolChoice(options.toolChoice) });\n    }\n  }\n}\n\nfunction toToolChoice(choice: llm.ToolChoice | null): NonNullable<ResponsesConfig['tool_choice']> {\n  return typeof choice === 'string'\n    ? choice\n    : choice?.type === 'function'\n      ? { type: 'function', name: choice.function.name }\n      : 'auto';\n}\n\nfunction renderItem(item: llm.ChatItem): [InputRole, string] | undefined {\n  if (item.type === 'message') {\n    if (item.textContent)\n      return [item.role === 'system' ? 'developer' : item.role, item.textContent];\n  } else if (item.type === 'function_call') {\n    return ['developer', `Called tool ${item.name} with ${item.args}`];\n  } else if (item.type === 'function_call_output') {\n    return [\n      'developer',\n      `Tool ${item.name || item.callId} ${item.isError ? 'failed with' : 'returned'} ${item.output}`,\n    ];\n  }\n  return undefined;\n}\n"],"mappings":"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","names":["WebSocket","delay","error"]}