@livekit/agents 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/voice/agent_activity.cjs +7 -0
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +7 -0
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/speech_handle.cjs +1 -0
- package/dist/voice/speech_handle.cjs.map +1 -1
- package/dist/voice/speech_handle.d.ts.map +1 -1
- package/dist/voice/speech_handle.js +1 -0
- package/dist/voice/speech_handle.js.map +1 -1
- package/package.json +1 -1
- package/src/voice/agent_activity.ts +14 -0
- package/src/voice/speech_handle.ts +1 -0
|
@@ -1337,6 +1337,13 @@ ${instructions}` : instructions,
|
|
|
1337
1337
|
draining = true;
|
|
1338
1338
|
}
|
|
1339
1339
|
if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {
|
|
1340
|
+
while (this.currentSpeech || this.speechQueue.size() > 0) {
|
|
1341
|
+
if (this.currentSpeech && !this.currentSpeech.done() && this.currentSpeech !== speechHandle) {
|
|
1342
|
+
await this.currentSpeech.waitForPlayout();
|
|
1343
|
+
} else {
|
|
1344
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1340
1347
|
const chatCtx = this.realtimeSession.chatCtx.copy();
|
|
1341
1348
|
chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);
|
|
1342
1349
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/agent_activity.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Mutex } from '@livekit/mutex';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { Heap } from 'heap-js';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { ReadableStream } from 'node:stream/web';\nimport { type ChatContext, ChatMessage } from '../llm/chat_context.js';\nimport {\n type ChatItem,\n type FunctionCall,\n type GenerationCreatedEvent,\n type InputSpeechStartedEvent,\n type InputSpeechStoppedEvent,\n type InputTranscriptionCompleted,\n LLM,\n RealtimeModel,\n type RealtimeModelError,\n type RealtimeSession,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.js';\nimport type { LLMError } from '../llm/llm.js';\nimport { log } from '../log.js';\nimport type {\n EOUMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from '../metrics/base.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { STT, type STTError, type SpeechEvent } from '../stt/stt.js';\nimport { splitWords } from '../tokenize/basic/word.js';\nimport { TTS, type TTSError } from '../tts/tts.js';\nimport { Future, Task, cancelAndWait, waitFor } from '../utils.js';\nimport { VAD, type VADEvent } from '../vad.js';\nimport type { Agent, ModelSettings } from './agent.js';\nimport { StopResponse, asyncLocalStorage } from './agent.js';\nimport { type AgentSession, type TurnDetectionMode } from './agent_session.js';\nimport {\n AudioRecognition,\n type EndOfTurnInfo,\n type RecognitionHooks,\n type _TurnDetector,\n} from './audio_recognition.js';\nimport {\n AgentSessionEventTypes,\n createErrorEvent,\n createFunctionToolsExecutedEvent,\n createMetricsCollectedEvent,\n createSpeechCreatedEvent,\n createUserInputTranscribedEvent,\n} from './events.js';\nimport type { ToolExecutionOutput } from './generation.js';\nimport {\n type _AudioOut,\n type _TextOut,\n performAudioForwarding,\n performLLMInference,\n performTTSInference,\n performTextForwarding,\n performToolExecutions,\n removeInstructions,\n updateInstructions,\n} from './generation.js';\nimport { SpeechHandle } from './speech_handle.js';\n\n// equivalent to Python's contextvars\nconst speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();\n\nexport class AgentActivity implements RecognitionHooks {\n private static readonly REPLY_TASK_CANCEL_TIMEOUT = 5000;\n private started = false;\n private audioRecognition?: AudioRecognition;\n private realtimeSession?: RealtimeSession;\n private turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n private logger = log();\n private _draining = false;\n private _currentSpeech?: SpeechHandle;\n private speechQueue: Heap<[number, number, SpeechHandle]>; // [priority, timestamp, speechHandle]\n private q_updated: Future;\n private speechTasks: Set<Task<void>> = new Set();\n private lock = new Mutex();\n private audioStream = new DeferredReadableStream<AudioFrame>();\n // default to null as None, which maps to the default provider tool choice value\n private toolChoice: ToolChoice | null = null;\n\n agent: Agent;\n agentSession: AgentSession;\n\n /** @internal */\n _mainTask?: Task<void>;\n _userTurnCompletedTask?: Promise<void>;\n\n constructor(agent: Agent, agentSession: AgentSession) {\n this.agent = agent;\n this.agentSession = agentSession;\n\n /**\n * Custom comparator to prioritize speech handles with higher priority\n * - Prefer higher priority\n * - Prefer earlier timestamp (so calling a sequence of generateReply() will execute in FIFO order)\n */\n this.speechQueue = new Heap<[number, number, SpeechHandle]>(([p1, t1, _], [p2, t2, __]) => {\n return p1 === p2 ? t1 - t2 : p2 - p1;\n });\n this.q_updated = new Future();\n\n this.turnDetectionMode =\n typeof this.turnDetection === 'string' ? this.turnDetection : undefined;\n\n if (this.turnDetectionMode === 'vad' && this.vad === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"vad\", but no VAD model is provided, ignoring the turnDdetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt' && this.stt === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but no STT model is provided, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection && !this.allowInterruptions) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false, ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentSession instead',\n );\n }\n\n if (this.turnDetectionMode === 'realtime_llm' && !this.llm.capabilities.turnDetection) {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel or the server-side turn detection is not supported/enabled, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt') {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but the LLM is a RealtimeModel, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n this.turnDetectionMode &&\n this.turnDetectionMode !== 'realtime_llm' &&\n this.llm.capabilities.turnDetection\n ) {\n this.logger.warn(\n `turnDetection is set to \"${this.turnDetectionMode}\", but the LLM is a RealtimeModel and server-side turn detection enabled, ignoring the turnDetection setting`,\n );\n this.turnDetectionMode = undefined;\n }\n\n // fallback to VAD if server side turn detection is disabled and VAD is available\n if (\n !this.llm.capabilities.turnDetection &&\n this.vad &&\n this.turnDetectionMode === undefined\n ) {\n this.turnDetectionMode = 'vad';\n }\n } else if (this.turnDetectionMode === 'realtime_llm') {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n !this.vad &&\n this.stt &&\n this.llm instanceof LLM &&\n this.allowInterruptions &&\n this.turnDetectionMode === undefined\n ) {\n this.logger.warn(\n 'VAD is not set. Enabling VAD is recommended when using LLM and STT ' +\n 'for more responsive interruption handling.',\n );\n }\n }\n\n async start(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n this.agent._agentActivity = this;\n\n if (this.llm instanceof RealtimeModel) {\n this.realtimeSession = this.llm.session();\n this.realtimeSession.on('generation_created', (ev) => this.onGenerationCreated(ev));\n this.realtimeSession.on('input_speech_started', (ev) => this.onInputSpeechStarted(ev));\n this.realtimeSession.on('input_speech_stopped', (ev) => this.onInputSpeechStopped(ev));\n this.realtimeSession.on('input_audio_transcription_completed', (ev) =>\n this.onInputAudioTranscriptionCompleted(ev),\n );\n this.realtimeSession.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.realtimeSession.on('error', (ev) => this.onError(ev));\n\n removeInstructions(this.agent._chatCtx);\n try {\n await this.realtimeSession.updateInstructions(this.agent.instructions);\n } catch (error) {\n this.logger.error(error, 'failed to update the instructions');\n }\n\n try {\n await this.realtimeSession.updateChatCtx(this.agent.chatCtx);\n } catch (error) {\n this.logger.error(error, 'failed to update the chat context');\n }\n\n try {\n await this.realtimeSession.updateTools(this.tools);\n } catch (error) {\n this.logger.error(error, 'failed to update the tools');\n }\n } else if (this.llm instanceof LLM) {\n try {\n updateInstructions({\n chatCtx: this.agent._chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n } catch (error) {\n this.logger.error('failed to update the instructions', error);\n }\n }\n\n // metrics and error handling\n if (this.llm instanceof LLM) {\n this.llm.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.llm.on('error', (ev) => this.onError(ev));\n }\n\n if (this.stt instanceof STT) {\n this.stt.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.stt.on('error', (ev) => this.onError(ev));\n }\n\n if (this.tts instanceof TTS) {\n this.tts.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.tts.on('error', (ev) => this.onError(ev));\n }\n\n if (this.vad instanceof VAD) {\n this.vad.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n }\n\n this.audioRecognition = new AudioRecognition({\n recognitionHooks: this,\n // Disable stt node if stt is not provided\n stt: this.stt ? (...args) => this.agent.sttNode(...args) : undefined,\n vad: this.vad,\n turnDetector: typeof this.turnDetection === 'string' ? undefined : this.turnDetection,\n turnDetectionMode: this.turnDetectionMode,\n minEndpointingDelay: this.agentSession.options.minEndpointingDelay,\n maxEndpointingDelay: this.agentSession.options.maxEndpointingDelay,\n });\n this.audioRecognition.start();\n this.started = true;\n\n this._mainTask = Task.from(({ signal }) => this.mainTask(signal));\n this.createSpeechTask({\n task: Task.from(() => this.agent.onEnter()),\n name: 'AgentActivity_onEnter',\n });\n } finally {\n unlock();\n }\n }\n\n get currentSpeech(): SpeechHandle | undefined {\n return this._currentSpeech;\n }\n\n get vad(): VAD | undefined {\n return this.agent.vad || this.agentSession.vad;\n }\n\n get stt(): STT | undefined {\n return this.agent.stt || this.agentSession.stt;\n }\n\n get llm(): LLM | RealtimeModel | undefined {\n return this.agent.llm || this.agentSession.llm;\n }\n\n get tts(): TTS | undefined {\n return this.agent.tts || this.agentSession.tts;\n }\n\n get tools(): ToolContext {\n return this.agent.toolCtx;\n }\n\n get draining(): boolean {\n return this._draining;\n }\n\n get realtimeLLMSession(): RealtimeSession | undefined {\n return this.realtimeSession;\n }\n\n get allowInterruptions(): boolean {\n // TODO(AJS-51): Allow options to be defined in Agent class\n return this.agentSession.options.allowInterruptions;\n }\n\n get turnDetection(): TurnDetectionMode | undefined {\n // TODO(brian): prioritize using agent.turn_detection\n return this.agentSession.turnDetection;\n }\n\n get toolCtx(): ToolContext {\n return this.agent.toolCtx;\n }\n\n async updateChatCtx(chatCtx: ChatContext): Promise<void> {\n chatCtx = chatCtx.copy({ toolCtx: this.toolCtx });\n\n this.agent._chatCtx = chatCtx;\n\n if (this.realtimeSession) {\n removeInstructions(chatCtx);\n this.realtimeSession.updateChatCtx(chatCtx);\n } else {\n updateInstructions({\n chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n }\n }\n\n updateOptions({ toolChoice }: { toolChoice?: ToolChoice | null }): void {\n if (toolChoice !== undefined) {\n this.toolChoice = toolChoice;\n }\n\n if (this.realtimeSession) {\n this.realtimeSession.updateOptions({ toolChoice: this.toolChoice });\n }\n }\n\n attachAudioInput(audioStream: ReadableStream<AudioFrame>): void {\n if (this.audioStream.isSourceSet) {\n this.logger.debug('detaching existing audio input in agent activity');\n this.audioStream.detachSource();\n }\n\n /**\n * We need to add a deferred ReadableStream layer on top of the audioStream from the agent session.\n * The tee() operation should be applied to the deferred stream, not the original audioStream.\n * This is important because teeing the original stream directly makes it very difficult—if not\n * impossible—to implement stream unlock logic cleanly.\n */\n this.audioStream.setSource(audioStream);\n const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.tee();\n\n if (this.realtimeSession) {\n this.realtimeSession.setInputAudioStream(realtimeAudioStream);\n }\n\n if (this.audioRecognition) {\n this.audioRecognition.setInputAudioStream(recognitionAudioStream);\n }\n }\n\n detachAudioInput(): void {\n this.audioStream.detachSource();\n }\n\n commitUserTurn() {\n if (!this.audioRecognition) {\n throw new Error('AudioRecognition is not initialized');\n }\n\n // TODO(brian): add audio_detached flag\n const audioDetached = false;\n this.audioRecognition.commitUserTurn(audioDetached);\n }\n\n clearUserTurn() {\n this.audioRecognition?.clearUserTurn();\n this.realtimeSession?.clearAudio();\n }\n\n say(\n text: string | ReadableStream<string>,\n options?: {\n audio?: ReadableStream<AudioFrame>;\n allowInterruptions?: boolean;\n addToChatCtx?: boolean;\n },\n ): SpeechHandle {\n const {\n audio,\n allowInterruptions: defaultAllowInterruptions,\n addToChatCtx = true,\n } = options ?? {};\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n !audio &&\n !this.tts &&\n this.agentSession.output.audio &&\n this.agentSession.output.audioEnabled\n ) {\n throw new Error('trying to generate speech from text without a TTS model');\n }\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.say(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'say',\n speechHandle: handle,\n }),\n );\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.ttsTask(handle, text, addToChatCtx, {}, abortController, audio),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.say_tts',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n // -- Metrics and errors --\n\n private onMetricsCollected = (\n ev: STTMetrics | TTSMetrics | VADMetrics | LLMMetrics | RealtimeModelMetrics,\n ) => {\n const speechHandle = speechHandleStorage.getStore();\n if (speechHandle && (ev.type === 'llm_metrics' || ev.type === 'tts_metrics')) {\n ev.speechId = speechHandle.id;\n }\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: ev }),\n );\n };\n\n private onError(ev: RealtimeModelError | STTError | TTSError | LLMError): void {\n if (ev.type === 'realtime_model_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'stt_error') {\n const errorEvent = createErrorEvent(ev.error, this.stt);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'tts_error') {\n const errorEvent = createErrorEvent(ev.error, this.tts);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'llm_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n }\n\n this.agentSession._onError(ev);\n }\n\n // -- Realtime Session events --\n\n onInputSpeechStarted(_ev: InputSpeechStartedEvent): void {\n this.logger.info('onInputSpeechStarted');\n\n if (!this.vad) {\n this.agentSession._updateUserState('speaking');\n }\n\n // this.interrupt() is going to raise when allow_interruptions is False,\n // llm.InputSpeechStartedEvent is only fired by the server when the turn_detection is enabled.\n try {\n this.interrupt();\n } catch (error) {\n this.logger.error(\n 'RealtimeAPI input_speech_started, but current speech is not interruptable, this should never happen!',\n error,\n );\n }\n }\n\n onInputSpeechStopped(ev: InputSpeechStoppedEvent): void {\n this.logger.info(ev, 'onInputSpeechStopped');\n\n if (!this.vad) {\n this.agentSession._updateUserState('listening');\n }\n\n if (ev.userTranscriptionEnabled) {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n isFinal: false,\n transcript: '',\n }),\n );\n }\n }\n\n onInputAudioTranscriptionCompleted(ev: InputTranscriptionCompleted): void {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.transcript,\n isFinal: ev.isFinal,\n }),\n );\n\n if (ev.isFinal) {\n const message = ChatMessage.create({\n role: 'user',\n content: ev.transcript,\n id: ev.itemId,\n });\n this.agent._chatCtx.items.push(message);\n this.agentSession._conversationItemAdded(message);\n }\n }\n\n onGenerationCreated(ev: GenerationCreatedEvent): void {\n if (ev.userInitiated) {\n // user initiated generations are directly handled inside _realtime_reply_task\n return;\n }\n\n if (this.draining) {\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent?\n this.logger.warn('skipping new realtime generation, the agent is draining');\n return;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: this.allowInterruptions,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeGenerationTask(handle, ev, {}, abortController),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeGeneration',\n });\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n }\n\n // recognition hooks\n\n onStartOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('speaking');\n }\n\n onEndOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('listening');\n }\n\n onVADInferenceDone(ev: VADEvent): void {\n if (this.turnDetection === 'manual' || this.turnDetection === 'realtime_llm') {\n // skip speech handle interruption for manual and realtime model\n return;\n }\n\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.turnDetection) {\n // skip speech handle interruption if server side turn detection is enabled\n return;\n }\n\n if (ev.speechDuration < this.agentSession.options.minInterruptionDuration) {\n return;\n }\n\n if (this.stt && this.agentSession.options.minInterruptionWords > 0 && this.audioRecognition) {\n const text = this.audioRecognition.currentTranscript;\n\n // TODO(shubhra): better word splitting for multi-language\n if (text && splitWords(text, true).length < this.agentSession.options.minInterruptionWords) {\n return;\n }\n }\n\n this.realtimeSession?.startUserActivity();\n\n if (\n this._currentSpeech &&\n !this._currentSpeech.interrupted &&\n this._currentSpeech.allowInterruptions\n ) {\n this.logger.info({ 'speech id': this._currentSpeech.id }, 'speech interrupted by VAD');\n this.realtimeSession?.interrupt();\n this._currentSpeech.interrupt();\n }\n }\n\n onInterimTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: false,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n onFinalTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: true,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n private createSpeechTask(options: {\n task: Task<void>;\n ownedSpeechHandle?: SpeechHandle;\n name?: string;\n }): Promise<void> {\n const { task, ownedSpeechHandle } = options;\n\n this.speechTasks.add(task);\n task.addDoneCallback(() => {\n this.speechTasks.delete(task);\n });\n\n if (ownedSpeechHandle) {\n ownedSpeechHandle._tasks.push(task);\n task.addDoneCallback(() => {\n if (ownedSpeechHandle._tasks.every((t) => t.done)) {\n ownedSpeechHandle._markDone();\n }\n });\n }\n\n task.addDoneCallback(() => {\n this.wakeupMainTask();\n });\n\n return task.result;\n }\n\n async onEndOfTurn(info: EndOfTurnInfo): Promise<boolean> {\n if (this.draining) {\n this.logger.warn({ user_input: info.newTranscript }, 'skipping user input, task is draining');\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent/activity?\n return true;\n }\n\n if (\n this.stt &&\n this.turnDetection !== 'manual' &&\n this._currentSpeech &&\n this._currentSpeech.allowInterruptions &&\n !this._currentSpeech.interrupted &&\n this.agentSession.options.minInterruptionWords > 0 &&\n info.newTranscript.split(' ').length < this.agentSession.options.minInterruptionWords\n ) {\n // avoid interruption if the new_transcript is too short\n this.logger.info('skipping user input, new_transcript is too short');\n return false;\n }\n\n const oldTask = this._userTurnCompletedTask;\n this._userTurnCompletedTask = this.createSpeechTask({\n task: Task.from(() => this.userTurnCompleted(info, oldTask)),\n name: 'AgentActivity.userTurnCompleted',\n });\n return true;\n }\n\n retrieveChatCtx(): ChatContext {\n return this.agentSession.chatCtx;\n }\n\n private async mainTask(signal: AbortSignal): Promise<void> {\n const abortFuture = new Future();\n const abortHandler = () => {\n abortFuture.resolve();\n signal.removeEventListener('abort', abortHandler);\n };\n signal.addEventListener('abort', abortHandler);\n\n while (true) {\n await Promise.race([this.q_updated.await, abortFuture.await]);\n if (signal.aborted) break;\n\n while (this.speechQueue.size() > 0) {\n if (signal.aborted) break;\n\n const heapItem = this.speechQueue.pop();\n if (!heapItem) {\n throw new Error('Speech queue is empty');\n }\n const speechHandle = heapItem[2];\n this._currentSpeech = speechHandle;\n speechHandle._authorizeGeneration();\n await speechHandle._waitForGeneration();\n this._currentSpeech = undefined;\n }\n\n // If we're draining and there are no more speech tasks, we can exit.\n // Only speech tasks can bypass draining to create a tool response\n if (this.draining && this.speechTasks.size === 0) {\n this.logger.info('mainTask: draining and no more speech tasks');\n break;\n }\n\n this.q_updated = new Future();\n }\n\n this.logger.info('AgentActivity mainTask: exiting');\n }\n\n private wakeupMainTask(): void {\n this.q_updated.resolve();\n }\n\n generateReply(options: {\n userMessage?: ChatMessage;\n chatCtx?: ChatContext;\n instructions?: string;\n toolChoice?: ToolChoice | null;\n allowInterruptions?: boolean;\n }): SpeechHandle {\n const {\n userMessage,\n chatCtx,\n instructions: defaultInstructions,\n toolChoice: defaultToolChoice,\n allowInterruptions: defaultAllowInterruptions,\n } = options;\n\n let instructions = defaultInstructions;\n let toolChoice = defaultToolChoice;\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.generateReply(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n if (this.llm === undefined) {\n throw new Error('trying to generate reply without an LLM model');\n }\n\n const functionCall = asyncLocalStorage.getStore()?.functionCall;\n if (toolChoice === undefined && functionCall !== undefined) {\n // when generateReply is called inside a tool, set toolChoice to 'none' by default\n toolChoice = 'none';\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n if (this.llm instanceof RealtimeModel) {\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: handle,\n // TODO(brian): support llm.ChatMessage for the realtime model\n userInput: userMessage?.textContent,\n instructions,\n modelSettings: {\n // isGiven(toolChoice) = toolChoice !== undefined\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n }),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeReply',\n });\n } else if (this.llm instanceof LLM) {\n // instructions used inside generateReply are \"extra\" instructions.\n // this matches the behavior of the Realtime API:\n // https://platform.openai.com/docs/api-reference/realtime-client-events/response/create\n if (instructions) {\n instructions = `${this.agent.instructions}\\n${instructions}`;\n }\n\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.pipelineReplyTask(\n handle,\n chatCtx ?? this.agent.chatCtx,\n this.agent.toolCtx,\n {\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n instructions ? `${this.agent.instructions}\\n${instructions}` : instructions,\n userMessage,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n }\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n interrupt(): Future<void> {\n const future = new Future<void>();\n const currentSpeech = this._currentSpeech;\n\n //TODO(AJS-273): add interrupt for background speeches\n\n currentSpeech?.interrupt();\n\n for (const [_, __, speech] of this.speechQueue) {\n speech.interrupt();\n }\n\n this.realtimeSession?.interrupt();\n\n if (currentSpeech === undefined) {\n future.resolve();\n } else {\n currentSpeech.addDoneCallback(() => {\n if (future.done) return;\n future.resolve();\n });\n }\n\n return future;\n }\n\n private onPipelineReplyDone(): void {\n if (!this.speechQueue.peek() && (!this._currentSpeech || this._currentSpeech.done())) {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async userTurnCompleted(info: EndOfTurnInfo, oldTask?: Promise<void>): Promise<void> {\n if (oldTask) {\n // We never cancel user code as this is very confusing.\n // So we wait for the old execution of onUserTurnCompleted to finish.\n // In practice this is OK because most speeches will be interrupted if a new turn\n // is detected. So the previous execution should complete quickly.\n await oldTask;\n }\n\n // When the audio recognition detects the end of a user turn:\n // - check if realtime model server-side turn detection is enabled\n // - check if there is no current generation happening\n // - cancel the current generation if it allows interruptions (otherwise skip this current\n // turn)\n // - generate a reply to the user input\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection) {\n return;\n }\n this.realtimeSession?.commitAudio();\n }\n\n if (this._currentSpeech) {\n if (!this._currentSpeech.allowInterruptions) {\n this.logger.warn(\n { user_input: info.newTranscript },\n 'skipping user input, current speech generation cannot be interrupted',\n );\n return;\n }\n\n this.logger.info(\n { 'speech id': this._currentSpeech.id },\n 'speech interrupted, new user turn detected',\n );\n\n this._currentSpeech.interrupt();\n this.realtimeSession?.interrupt();\n }\n\n let userMessage: ChatMessage | undefined = ChatMessage.create({\n role: 'user',\n content: info.newTranscript,\n });\n\n // create a temporary mutable chat context to pass to onUserTurnCompleted\n // the user can edit it for the current generation, but changes will not be kept inside the\n // Agent.chatCtx\n const chatCtx = this.agent.chatCtx.copy();\n const startTime = Date.now();\n\n try {\n await this.agent.onUserTurnCompleted(chatCtx, userMessage);\n } catch (e) {\n if (e instanceof StopResponse) {\n return;\n }\n this.logger.error({ error: e }, 'error occurred during onUserTurnCompleted');\n }\n\n const callbackDuration = Date.now() - startTime;\n\n if (this.llm instanceof RealtimeModel) {\n // ignore stt transcription for realtime model\n userMessage = undefined;\n } else if (this.llm === undefined) {\n return;\n }\n\n // Ensure the new message is passed to generateReply\n // This preserves the original message id, making it easier for users to track responses\n const speechHandle = this.generateReply({ userMessage, chatCtx });\n\n const eouMetrics: EOUMetrics = {\n type: 'eou_metrics',\n timestamp: Date.now(),\n endOfUtteranceDelay: info.endOfUtteranceDelay,\n transcriptionDelay: info.transcriptionDelay,\n onUserTurnCompletedDelay: callbackDuration,\n speechId: speechHandle.id,\n };\n\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: eouMetrics }),\n );\n }\n\n private async ttsTask(\n speechHandle: SpeechHandle,\n text: string | ReadableStream<string>,\n addToChatCtx: boolean,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n audio?: ReadableStream<AudioFrame> | null,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (speechHandle.interrupted) {\n return;\n }\n\n let baseStream: ReadableStream<string>;\n if (text instanceof ReadableStream) {\n baseStream = text;\n } else {\n baseStream = new ReadableStream({\n start(controller) {\n controller.enqueue(text);\n controller.close();\n },\n });\n }\n\n const [textSource, audioSource] = baseStream.tee();\n\n const tasks: Array<Task<void>> = [];\n\n const trNode = await this.agent.transcriptionNode(textSource, {});\n let textOut: _TextOut | null = null;\n if (trNode) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNode,\n replyAbortController,\n transcriptionOutput,\n );\n textOut = _textOut;\n tasks.push(textForwardTask);\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n if (!audioOutput) {\n if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n } else {\n let audioOut: _AudioOut | null = null;\n if (!audio) {\n // generate audio using TTS\n const [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n audioSource,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n } else {\n // use the provided audio\n const [forwardTask, _audioOut] = performAudioForwarding(\n audio,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n }\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n }\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n if (audioOutput) {\n audioOutput.clearBuffer();\n await audioOutput.waitForPlayout();\n }\n }\n\n if (addToChatCtx) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n interrupted: speechHandle.interrupted,\n });\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async pipelineReplyTask(\n speechHandle: SpeechHandle,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n instructions?: string,\n newMessage?: ChatMessage,\n toolsMessages?: ChatItem[],\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n chatCtx = chatCtx.copy();\n\n if (newMessage) {\n chatCtx.insert(newMessage);\n this.agent._chatCtx.insert(newMessage);\n this.agentSession._conversationItemAdded(newMessage);\n }\n\n if (instructions) {\n try {\n updateInstructions({\n chatCtx,\n instructions,\n addIfMissing: true,\n });\n } catch (e) {\n this.logger.error({ error: e }, 'error occurred during updateInstructions');\n }\n }\n\n this.agentSession._updateAgentState('thinking');\n const tasks: Array<Task<void>> = [];\n const [llmTask, llmGenData] = performLLMInference(\n // preserve `this` context in llmNode\n (...args) => this.agent.llmNode(...args),\n chatCtx,\n toolCtx,\n modelSettings,\n replyAbortController,\n );\n tasks.push(llmTask);\n\n const [ttsTextInput, llmOutput] = llmGenData.textStream.tee();\n\n let ttsTask: Task<void> | null = null;\n let ttsStream: ReadableStream<AudioFrame> | null = null;\n if (audioOutput) {\n [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n ttsTextInput,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForScheduled()]);\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n this.agentSession._updateAgentState('thinking');\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n const replyStartedAt = Date.now();\n const trNodeResult = await this.agent.transcriptionNode(llmOutput, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n replyAbortController,\n transcriptionOutput,\n );\n tasks.push(textForwardTask);\n textOut = _textOut;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n if (ttsStream) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n audioOut = _audioOut;\n tasks.push(forwardTask);\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n throw Error('ttsStream is null when audioOutput is enabled');\n }\n } else {\n textOut?.firstTextFut.await.finally(onFirstFrame);\n }\n\n //TODO(AJS-272): before executing tools, make sure we generated all the text\n // (this ensure everything is kept ordered)\n\n const onToolExecutionStarted = (_: FunctionCall) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const onToolExecutionCompleted = (_: ToolExecutionOutput) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolChoice: modelSettings.toolChoice,\n toolCallStream: llmGenData.toolCallStream,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n // add the tools messages that triggers this reply to the chat context\n if (toolsMessages) {\n for (const msg of toolsMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolsMessages);\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all pipeline reply tasks due to interruption',\n );\n replyAbortController.abort();\n await Promise.allSettled(\n tasks.map((task) => task.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT)),\n );\n\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n }\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: llmGenData.id,\n interrupted: true,\n createdAt: replyStartedAt,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n // TODO(shubhra) add chat message to speech handle\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n if (textOut && textOut.text) {\n const message = ChatMessage.create({\n role: 'assistant',\n id: llmGenData.id,\n interrupted: false,\n createdAt: replyStartedAt,\n content: textOut.text,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n this.logger.info(\n { speech_id: speechHandle.id, message: textOut.text },\n 'playout completed without interruption',\n );\n }\n\n if (toolOutput.output.length > 0) {\n this.agentSession._updateAgentState('thinking');\n } else if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent output should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCalls.push(sanitizedOut.toolCall);\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n // TODO(brian): should we mark the function call as failed to notify the LLM?\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n const toolMessages = [\n ...functionToolsExecutedEvent.functionCalls,\n ...functionToolsExecutedEvent.functionCallOutputs,\n ] as ChatItem[];\n if (shouldGenerateToolReply) {\n chatCtx.insert(toolMessages);\n\n const handle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle._stepIndex + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: handle,\n }),\n );\n\n // Avoid setting tool_choice to \"required\" or a specific function when\n // passing tool response back to the LLM\n const respondToolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n\n const toolResponseTask = this.createSpeechTask({\n task: Task.from(() =>\n this.pipelineReplyTask(\n handle,\n chatCtx,\n toolCtx,\n { toolChoice: respondToolChoice },\n replyAbortController,\n instructions,\n undefined,\n toolMessages,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n toolResponseTask.finally(() => this.onPipelineReplyDone());\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n } else if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n for (const msg of toolMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolMessages);\n }\n }\n\n private async realtimeGenerationTask(\n speechHandle: SpeechHandle,\n ev: GenerationCreatedEvent,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not initialized');\n }\n if (!(this.llm instanceof RealtimeModel)) {\n throw new Error('llm is not a realtime model');\n }\n\n this.logger.debug(\n { speech_id: speechHandle.id, stepIndex: speechHandle.numSteps },\n 'realtime generation started',\n );\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const textOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n const toolCtx = this.realtimeSession.tools;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n if (speechHandle.interrupted) {\n return;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n const readMessages = async (\n abortController: AbortController,\n outputs: Array<[string, _TextOut | null, _AudioOut | null]>,\n ) => {\n const forwardTasks: Array<Task<void>> = [];\n try {\n for await (const msg of ev.messageStream) {\n if (forwardTasks.length > 0) {\n this.logger.warn(\n 'expected to receive only one message generation from the realtime API',\n );\n break;\n }\n const trNodeResult = await this.agent.transcriptionNode(msg.textStream, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n abortController,\n textOutput,\n );\n forwardTasks.push(textForwardTask);\n textOut = _textOut;\n }\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n const realtimeAudio = await this.agent.realtimeAudioOutputNode(\n msg.audioStream,\n modelSettings,\n );\n if (realtimeAudio) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n realtimeAudio,\n audioOutput,\n abortController,\n );\n forwardTasks.push(forwardTask);\n audioOut = _audioOut;\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n this.logger.warn(\n 'audio output is enabled but neither tts nor realtime audio is available',\n );\n }\n } else if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n outputs.push([msg.messageId, textOut, audioOut]);\n }\n await waitFor(forwardTasks);\n } catch (error) {\n this.logger.error(error, 'error reading messages from the realtime API');\n } finally {\n await cancelAndWait(forwardTasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n }\n };\n\n const messageOutputs: Array<[string, _TextOut | null, _AudioOut | null]> = [];\n const tasks = [\n Task.from(\n (controller) => readMessages(controller, messageOutputs),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_messages',\n ),\n ];\n\n const [toolCallStream, toolCallStreamForTracing] = ev.functionStream.tee();\n // TODO(brian): append to tracing tees\n const toolCalls: FunctionCall[] = [];\n\n const readToolStreamTask = async (\n controller: AbortController,\n stream: ReadableStream<FunctionCall>,\n ) => {\n const reader = stream.getReader();\n try {\n while (!controller.signal.aborted) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.logger.debug({ tool_call: value }, 'received tool call from the realtime API');\n toolCalls.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n };\n\n tasks.push(\n Task.from(\n (controller) => readToolStreamTask(controller, toolCallStreamForTracing),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_tool_stream',\n ),\n );\n\n const onToolExecutionStarted = (f: FunctionCall) => {\n speechHandle._itemAdded([f]);\n };\n\n const onToolExecutionCompleted = (out: ToolExecutionOutput) => {\n if (out.toolCallOutput) {\n speechHandle._itemAdded([out.toolCallOutput]);\n }\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolCallStream,\n toolChoice: modelSettings.toolChoice,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n // TODO(brian): add tracing span\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n this.agentSession._updateAgentState('listening');\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all realtime generation tasks due to interruption',\n );\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, audioOut] = messageOutputs[0]!;\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n let playbackPosition = playbackEv.playbackPosition;\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n playbackPosition = 0;\n }\n\n // truncate server-side message\n this.realtimeSession.truncate({\n messageId: msgId,\n audioEndMs: Math.floor(playbackPosition),\n });\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: msgId,\n interrupted: true,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message);\n\n // TODO(brian): add tracing span\n }\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n }\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n // TODO(brian): close tees\n return;\n }\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, _] = messageOutputs[0]!;\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n id: msgId,\n interrupted: false,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message); // mark the playout done before waiting for the tool execution\\\n // TODO(brian): add tracing span\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n // TODO(brian): close tees\n\n toolOutput.firstToolStartedFuture.await.finally(() => {\n this.agentSession._updateAgentState('thinking');\n });\n\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent ouput should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n const chatCtx = this.realtimeSession.chatCtx.copy();\n chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);\n try {\n await this.realtimeSession.updateChatCtx(chatCtx);\n } catch (error) {\n this.logger.warn(\n { error },\n 'failed to update chat context before generating the function calls results',\n );\n }\n }\n\n // skip realtime reply if not required or auto-generated\n if (!shouldGenerateToolReply || this.llm.capabilities.autoToolReplyGeneration) {\n return;\n }\n\n this.realtimeSession.interrupt();\n\n const replySpeechHandle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle.numSteps + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: replySpeechHandle,\n }),\n );\n\n const toolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: replySpeechHandle,\n modelSettings: { toolChoice },\n abortController,\n }),\n ),\n ownedSpeechHandle: replySpeechHandle,\n name: 'AgentActivity.realtime_reply',\n });\n\n this.scheduleSpeech(replySpeechHandle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n }\n\n private async realtimeReplyTask({\n speechHandle,\n modelSettings: { toolChoice },\n userInput,\n instructions,\n abortController,\n }: {\n speechHandle: SpeechHandle;\n modelSettings: ModelSettings;\n abortController: AbortController;\n userInput?: string;\n instructions?: string;\n }): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not available');\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (userInput) {\n const chatCtx = this.realtimeSession.chatCtx.copy();\n const message = chatCtx.addMessage({\n role: 'user',\n content: userInput,\n });\n await this.realtimeSession.updateChatCtx(chatCtx);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n const originalToolChoice = this.toolChoice;\n if (toolChoice !== undefined) {\n this.realtimeSession.updateOptions({ toolChoice });\n }\n\n try {\n const generationEvent = await this.realtimeSession.generateReply(instructions);\n await this.realtimeGenerationTask(\n speechHandle,\n generationEvent,\n { toolChoice },\n abortController,\n );\n } finally {\n // reset toolChoice value\n if (toolChoice !== undefined && toolChoice !== originalToolChoice) {\n this.realtimeSession.updateOptions({ toolChoice: originalToolChoice });\n }\n }\n }\n\n private scheduleSpeech(\n speechHandle: SpeechHandle,\n priority: number,\n force: boolean = false,\n ): void {\n // when force=true, we allow tool responses to bypass draining\n // This allows for tool responses to be generated before the AgentActivity is finalized\n if (this.draining && !force) {\n throw new Error('cannot schedule new speech, the agent is draining');\n }\n\n // Monotonic time to avoid near 0 collisions\n this.speechQueue.push([priority, Number(process.hrtime.bigint()), speechHandle]);\n speechHandle._markScheduled();\n this.wakeupMainTask();\n }\n\n async drain(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (this._draining) return;\n\n this.createSpeechTask({\n task: Task.from(() => this.agent.onExit()),\n name: 'AgentActivity_onExit',\n });\n\n this.wakeupMainTask();\n this._draining = true;\n await this._mainTask?.result;\n } finally {\n unlock();\n }\n }\n\n async close(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (!this._draining) {\n this.logger.warn('task closing without draining');\n }\n\n // Unregister event handlers to prevent duplicate metrics\n if (this.llm instanceof LLM) {\n this.llm.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.realtimeSession) {\n this.realtimeSession.off('generation_created', this.onGenerationCreated);\n this.realtimeSession.off('input_speech_started', this.onInputSpeechStarted);\n this.realtimeSession.off('input_speech_stopped', this.onInputSpeechStopped);\n this.realtimeSession.off(\n 'input_audio_transcription_completed',\n this.onInputAudioTranscriptionCompleted,\n );\n this.realtimeSession.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.stt instanceof STT) {\n this.stt.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.tts instanceof TTS) {\n this.tts.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.vad instanceof VAD) {\n this.vad.off('metrics_collected', this.onMetricsCollected);\n }\n\n this.detachAudioInput();\n await this.realtimeSession?.close();\n await this.audioRecognition?.close();\n await this._mainTask?.cancelAndWait();\n } finally {\n unlock();\n }\n }\n}\n\nfunction toOaiToolChoice(toolChoice: ToolChoice | null): ToolChoice | undefined {\n // we convert null to undefined, which maps to the default provider tool choice value\n return toolChoice !== null ? toolChoice : undefined;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/agent_activity.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Mutex } from '@livekit/mutex';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { Heap } from 'heap-js';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { ReadableStream } from 'node:stream/web';\nimport { type ChatContext, ChatMessage } from '../llm/chat_context.js';\nimport {\n type ChatItem,\n type FunctionCall,\n type GenerationCreatedEvent,\n type InputSpeechStartedEvent,\n type InputSpeechStoppedEvent,\n type InputTranscriptionCompleted,\n LLM,\n RealtimeModel,\n type RealtimeModelError,\n type RealtimeSession,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.js';\nimport type { LLMError } from '../llm/llm.js';\nimport { log } from '../log.js';\nimport type {\n EOUMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from '../metrics/base.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { STT, type STTError, type SpeechEvent } from '../stt/stt.js';\nimport { splitWords } from '../tokenize/basic/word.js';\nimport { TTS, type TTSError } from '../tts/tts.js';\nimport { Future, Task, cancelAndWait, waitFor } from '../utils.js';\nimport { VAD, type VADEvent } from '../vad.js';\nimport type { Agent, ModelSettings } from './agent.js';\nimport { StopResponse, asyncLocalStorage } from './agent.js';\nimport { type AgentSession, type TurnDetectionMode } from './agent_session.js';\nimport {\n AudioRecognition,\n type EndOfTurnInfo,\n type RecognitionHooks,\n type _TurnDetector,\n} from './audio_recognition.js';\nimport {\n AgentSessionEventTypes,\n createErrorEvent,\n createFunctionToolsExecutedEvent,\n createMetricsCollectedEvent,\n createSpeechCreatedEvent,\n createUserInputTranscribedEvent,\n} from './events.js';\nimport type { ToolExecutionOutput } from './generation.js';\nimport {\n type _AudioOut,\n type _TextOut,\n performAudioForwarding,\n performLLMInference,\n performTTSInference,\n performTextForwarding,\n performToolExecutions,\n removeInstructions,\n updateInstructions,\n} from './generation.js';\nimport { SpeechHandle } from './speech_handle.js';\n\n// equivalent to Python's contextvars\nconst speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();\n\nexport class AgentActivity implements RecognitionHooks {\n private static readonly REPLY_TASK_CANCEL_TIMEOUT = 5000;\n private started = false;\n private audioRecognition?: AudioRecognition;\n private realtimeSession?: RealtimeSession;\n private turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n private logger = log();\n private _draining = false;\n private _currentSpeech?: SpeechHandle;\n private speechQueue: Heap<[number, number, SpeechHandle]>; // [priority, timestamp, speechHandle]\n private q_updated: Future;\n private speechTasks: Set<Task<void>> = new Set();\n private lock = new Mutex();\n private audioStream = new DeferredReadableStream<AudioFrame>();\n // default to null as None, which maps to the default provider tool choice value\n private toolChoice: ToolChoice | null = null;\n\n agent: Agent;\n agentSession: AgentSession;\n\n /** @internal */\n _mainTask?: Task<void>;\n _userTurnCompletedTask?: Promise<void>;\n\n constructor(agent: Agent, agentSession: AgentSession) {\n this.agent = agent;\n this.agentSession = agentSession;\n\n /**\n * Custom comparator to prioritize speech handles with higher priority\n * - Prefer higher priority\n * - Prefer earlier timestamp (so calling a sequence of generateReply() will execute in FIFO order)\n */\n this.speechQueue = new Heap<[number, number, SpeechHandle]>(([p1, t1, _], [p2, t2, __]) => {\n return p1 === p2 ? t1 - t2 : p2 - p1;\n });\n this.q_updated = new Future();\n\n this.turnDetectionMode =\n typeof this.turnDetection === 'string' ? this.turnDetection : undefined;\n\n if (this.turnDetectionMode === 'vad' && this.vad === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"vad\", but no VAD model is provided, ignoring the turnDdetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt' && this.stt === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but no STT model is provided, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection && !this.allowInterruptions) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false, ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentSession instead',\n );\n }\n\n if (this.turnDetectionMode === 'realtime_llm' && !this.llm.capabilities.turnDetection) {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel or the server-side turn detection is not supported/enabled, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt') {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but the LLM is a RealtimeModel, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n this.turnDetectionMode &&\n this.turnDetectionMode !== 'realtime_llm' &&\n this.llm.capabilities.turnDetection\n ) {\n this.logger.warn(\n `turnDetection is set to \"${this.turnDetectionMode}\", but the LLM is a RealtimeModel and server-side turn detection enabled, ignoring the turnDetection setting`,\n );\n this.turnDetectionMode = undefined;\n }\n\n // fallback to VAD if server side turn detection is disabled and VAD is available\n if (\n !this.llm.capabilities.turnDetection &&\n this.vad &&\n this.turnDetectionMode === undefined\n ) {\n this.turnDetectionMode = 'vad';\n }\n } else if (this.turnDetectionMode === 'realtime_llm') {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n !this.vad &&\n this.stt &&\n this.llm instanceof LLM &&\n this.allowInterruptions &&\n this.turnDetectionMode === undefined\n ) {\n this.logger.warn(\n 'VAD is not set. Enabling VAD is recommended when using LLM and STT ' +\n 'for more responsive interruption handling.',\n );\n }\n }\n\n async start(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n this.agent._agentActivity = this;\n\n if (this.llm instanceof RealtimeModel) {\n this.realtimeSession = this.llm.session();\n this.realtimeSession.on('generation_created', (ev) => this.onGenerationCreated(ev));\n this.realtimeSession.on('input_speech_started', (ev) => this.onInputSpeechStarted(ev));\n this.realtimeSession.on('input_speech_stopped', (ev) => this.onInputSpeechStopped(ev));\n this.realtimeSession.on('input_audio_transcription_completed', (ev) =>\n this.onInputAudioTranscriptionCompleted(ev),\n );\n this.realtimeSession.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.realtimeSession.on('error', (ev) => this.onError(ev));\n\n removeInstructions(this.agent._chatCtx);\n try {\n await this.realtimeSession.updateInstructions(this.agent.instructions);\n } catch (error) {\n this.logger.error(error, 'failed to update the instructions');\n }\n\n try {\n await this.realtimeSession.updateChatCtx(this.agent.chatCtx);\n } catch (error) {\n this.logger.error(error, 'failed to update the chat context');\n }\n\n try {\n await this.realtimeSession.updateTools(this.tools);\n } catch (error) {\n this.logger.error(error, 'failed to update the tools');\n }\n } else if (this.llm instanceof LLM) {\n try {\n updateInstructions({\n chatCtx: this.agent._chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n } catch (error) {\n this.logger.error('failed to update the instructions', error);\n }\n }\n\n // metrics and error handling\n if (this.llm instanceof LLM) {\n this.llm.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.llm.on('error', (ev) => this.onError(ev));\n }\n\n if (this.stt instanceof STT) {\n this.stt.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.stt.on('error', (ev) => this.onError(ev));\n }\n\n if (this.tts instanceof TTS) {\n this.tts.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.tts.on('error', (ev) => this.onError(ev));\n }\n\n if (this.vad instanceof VAD) {\n this.vad.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n }\n\n this.audioRecognition = new AudioRecognition({\n recognitionHooks: this,\n // Disable stt node if stt is not provided\n stt: this.stt ? (...args) => this.agent.sttNode(...args) : undefined,\n vad: this.vad,\n turnDetector: typeof this.turnDetection === 'string' ? undefined : this.turnDetection,\n turnDetectionMode: this.turnDetectionMode,\n minEndpointingDelay: this.agentSession.options.minEndpointingDelay,\n maxEndpointingDelay: this.agentSession.options.maxEndpointingDelay,\n });\n this.audioRecognition.start();\n this.started = true;\n\n this._mainTask = Task.from(({ signal }) => this.mainTask(signal));\n this.createSpeechTask({\n task: Task.from(() => this.agent.onEnter()),\n name: 'AgentActivity_onEnter',\n });\n } finally {\n unlock();\n }\n }\n\n get currentSpeech(): SpeechHandle | undefined {\n return this._currentSpeech;\n }\n\n get vad(): VAD | undefined {\n return this.agent.vad || this.agentSession.vad;\n }\n\n get stt(): STT | undefined {\n return this.agent.stt || this.agentSession.stt;\n }\n\n get llm(): LLM | RealtimeModel | undefined {\n return this.agent.llm || this.agentSession.llm;\n }\n\n get tts(): TTS | undefined {\n return this.agent.tts || this.agentSession.tts;\n }\n\n get tools(): ToolContext {\n return this.agent.toolCtx;\n }\n\n get draining(): boolean {\n return this._draining;\n }\n\n get realtimeLLMSession(): RealtimeSession | undefined {\n return this.realtimeSession;\n }\n\n get allowInterruptions(): boolean {\n // TODO(AJS-51): Allow options to be defined in Agent class\n return this.agentSession.options.allowInterruptions;\n }\n\n get turnDetection(): TurnDetectionMode | undefined {\n // TODO(brian): prioritize using agent.turn_detection\n return this.agentSession.turnDetection;\n }\n\n get toolCtx(): ToolContext {\n return this.agent.toolCtx;\n }\n\n async updateChatCtx(chatCtx: ChatContext): Promise<void> {\n chatCtx = chatCtx.copy({ toolCtx: this.toolCtx });\n\n this.agent._chatCtx = chatCtx;\n\n if (this.realtimeSession) {\n removeInstructions(chatCtx);\n this.realtimeSession.updateChatCtx(chatCtx);\n } else {\n updateInstructions({\n chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n }\n }\n\n updateOptions({ toolChoice }: { toolChoice?: ToolChoice | null }): void {\n if (toolChoice !== undefined) {\n this.toolChoice = toolChoice;\n }\n\n if (this.realtimeSession) {\n this.realtimeSession.updateOptions({ toolChoice: this.toolChoice });\n }\n }\n\n attachAudioInput(audioStream: ReadableStream<AudioFrame>): void {\n if (this.audioStream.isSourceSet) {\n this.logger.debug('detaching existing audio input in agent activity');\n this.audioStream.detachSource();\n }\n\n /**\n * We need to add a deferred ReadableStream layer on top of the audioStream from the agent session.\n * The tee() operation should be applied to the deferred stream, not the original audioStream.\n * This is important because teeing the original stream directly makes it very difficult—if not\n * impossible—to implement stream unlock logic cleanly.\n */\n this.audioStream.setSource(audioStream);\n const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.tee();\n\n if (this.realtimeSession) {\n this.realtimeSession.setInputAudioStream(realtimeAudioStream);\n }\n\n if (this.audioRecognition) {\n this.audioRecognition.setInputAudioStream(recognitionAudioStream);\n }\n }\n\n detachAudioInput(): void {\n this.audioStream.detachSource();\n }\n\n commitUserTurn() {\n if (!this.audioRecognition) {\n throw new Error('AudioRecognition is not initialized');\n }\n\n // TODO(brian): add audio_detached flag\n const audioDetached = false;\n this.audioRecognition.commitUserTurn(audioDetached);\n }\n\n clearUserTurn() {\n this.audioRecognition?.clearUserTurn();\n this.realtimeSession?.clearAudio();\n }\n\n say(\n text: string | ReadableStream<string>,\n options?: {\n audio?: ReadableStream<AudioFrame>;\n allowInterruptions?: boolean;\n addToChatCtx?: boolean;\n },\n ): SpeechHandle {\n const {\n audio,\n allowInterruptions: defaultAllowInterruptions,\n addToChatCtx = true,\n } = options ?? {};\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n !audio &&\n !this.tts &&\n this.agentSession.output.audio &&\n this.agentSession.output.audioEnabled\n ) {\n throw new Error('trying to generate speech from text without a TTS model');\n }\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.say(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'say',\n speechHandle: handle,\n }),\n );\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.ttsTask(handle, text, addToChatCtx, {}, abortController, audio),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.say_tts',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n // -- Metrics and errors --\n\n private onMetricsCollected = (\n ev: STTMetrics | TTSMetrics | VADMetrics | LLMMetrics | RealtimeModelMetrics,\n ) => {\n const speechHandle = speechHandleStorage.getStore();\n if (speechHandle && (ev.type === 'llm_metrics' || ev.type === 'tts_metrics')) {\n ev.speechId = speechHandle.id;\n }\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: ev }),\n );\n };\n\n private onError(ev: RealtimeModelError | STTError | TTSError | LLMError): void {\n if (ev.type === 'realtime_model_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'stt_error') {\n const errorEvent = createErrorEvent(ev.error, this.stt);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'tts_error') {\n const errorEvent = createErrorEvent(ev.error, this.tts);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'llm_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n }\n\n this.agentSession._onError(ev);\n }\n\n // -- Realtime Session events --\n\n onInputSpeechStarted(_ev: InputSpeechStartedEvent): void {\n this.logger.info('onInputSpeechStarted');\n\n if (!this.vad) {\n this.agentSession._updateUserState('speaking');\n }\n\n // this.interrupt() is going to raise when allow_interruptions is False,\n // llm.InputSpeechStartedEvent is only fired by the server when the turn_detection is enabled.\n try {\n this.interrupt();\n } catch (error) {\n this.logger.error(\n 'RealtimeAPI input_speech_started, but current speech is not interruptable, this should never happen!',\n error,\n );\n }\n }\n\n onInputSpeechStopped(ev: InputSpeechStoppedEvent): void {\n this.logger.info(ev, 'onInputSpeechStopped');\n\n if (!this.vad) {\n this.agentSession._updateUserState('listening');\n }\n\n if (ev.userTranscriptionEnabled) {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n isFinal: false,\n transcript: '',\n }),\n );\n }\n }\n\n onInputAudioTranscriptionCompleted(ev: InputTranscriptionCompleted): void {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.transcript,\n isFinal: ev.isFinal,\n }),\n );\n\n if (ev.isFinal) {\n const message = ChatMessage.create({\n role: 'user',\n content: ev.transcript,\n id: ev.itemId,\n });\n this.agent._chatCtx.items.push(message);\n this.agentSession._conversationItemAdded(message);\n }\n }\n\n onGenerationCreated(ev: GenerationCreatedEvent): void {\n if (ev.userInitiated) {\n // user initiated generations are directly handled inside _realtime_reply_task\n return;\n }\n\n if (this.draining) {\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent?\n this.logger.warn('skipping new realtime generation, the agent is draining');\n return;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: this.allowInterruptions,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeGenerationTask(handle, ev, {}, abortController),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeGeneration',\n });\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n }\n\n // recognition hooks\n\n onStartOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('speaking');\n }\n\n onEndOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('listening');\n }\n\n onVADInferenceDone(ev: VADEvent): void {\n if (this.turnDetection === 'manual' || this.turnDetection === 'realtime_llm') {\n // skip speech handle interruption for manual and realtime model\n return;\n }\n\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.turnDetection) {\n // skip speech handle interruption if server side turn detection is enabled\n return;\n }\n\n if (ev.speechDuration < this.agentSession.options.minInterruptionDuration) {\n return;\n }\n\n if (this.stt && this.agentSession.options.minInterruptionWords > 0 && this.audioRecognition) {\n const text = this.audioRecognition.currentTranscript;\n\n // TODO(shubhra): better word splitting for multi-language\n if (text && splitWords(text, true).length < this.agentSession.options.minInterruptionWords) {\n return;\n }\n }\n\n this.realtimeSession?.startUserActivity();\n\n if (\n this._currentSpeech &&\n !this._currentSpeech.interrupted &&\n this._currentSpeech.allowInterruptions\n ) {\n this.logger.info({ 'speech id': this._currentSpeech.id }, 'speech interrupted by VAD');\n this.realtimeSession?.interrupt();\n this._currentSpeech.interrupt();\n }\n }\n\n onInterimTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: false,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n onFinalTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: true,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n private createSpeechTask(options: {\n task: Task<void>;\n ownedSpeechHandle?: SpeechHandle;\n name?: string;\n }): Promise<void> {\n const { task, ownedSpeechHandle } = options;\n\n this.speechTasks.add(task);\n task.addDoneCallback(() => {\n this.speechTasks.delete(task);\n });\n\n if (ownedSpeechHandle) {\n ownedSpeechHandle._tasks.push(task);\n task.addDoneCallback(() => {\n if (ownedSpeechHandle._tasks.every((t) => t.done)) {\n ownedSpeechHandle._markDone();\n }\n });\n }\n\n task.addDoneCallback(() => {\n this.wakeupMainTask();\n });\n\n return task.result;\n }\n\n async onEndOfTurn(info: EndOfTurnInfo): Promise<boolean> {\n if (this.draining) {\n this.logger.warn({ user_input: info.newTranscript }, 'skipping user input, task is draining');\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent/activity?\n return true;\n }\n\n if (\n this.stt &&\n this.turnDetection !== 'manual' &&\n this._currentSpeech &&\n this._currentSpeech.allowInterruptions &&\n !this._currentSpeech.interrupted &&\n this.agentSession.options.minInterruptionWords > 0 &&\n info.newTranscript.split(' ').length < this.agentSession.options.minInterruptionWords\n ) {\n // avoid interruption if the new_transcript is too short\n this.logger.info('skipping user input, new_transcript is too short');\n return false;\n }\n\n const oldTask = this._userTurnCompletedTask;\n this._userTurnCompletedTask = this.createSpeechTask({\n task: Task.from(() => this.userTurnCompleted(info, oldTask)),\n name: 'AgentActivity.userTurnCompleted',\n });\n return true;\n }\n\n retrieveChatCtx(): ChatContext {\n return this.agentSession.chatCtx;\n }\n\n private async mainTask(signal: AbortSignal): Promise<void> {\n const abortFuture = new Future();\n const abortHandler = () => {\n abortFuture.resolve();\n signal.removeEventListener('abort', abortHandler);\n };\n signal.addEventListener('abort', abortHandler);\n\n while (true) {\n await Promise.race([this.q_updated.await, abortFuture.await]);\n if (signal.aborted) break;\n\n while (this.speechQueue.size() > 0) {\n if (signal.aborted) break;\n\n const heapItem = this.speechQueue.pop();\n if (!heapItem) {\n throw new Error('Speech queue is empty');\n }\n const speechHandle = heapItem[2];\n this._currentSpeech = speechHandle;\n speechHandle._authorizeGeneration();\n await speechHandle._waitForGeneration();\n this._currentSpeech = undefined;\n }\n\n // If we're draining and there are no more speech tasks, we can exit.\n // Only speech tasks can bypass draining to create a tool response\n if (this.draining && this.speechTasks.size === 0) {\n this.logger.info('mainTask: draining and no more speech tasks');\n break;\n }\n\n this.q_updated = new Future();\n }\n\n this.logger.info('AgentActivity mainTask: exiting');\n }\n\n private wakeupMainTask(): void {\n this.q_updated.resolve();\n }\n\n generateReply(options: {\n userMessage?: ChatMessage;\n chatCtx?: ChatContext;\n instructions?: string;\n toolChoice?: ToolChoice | null;\n allowInterruptions?: boolean;\n }): SpeechHandle {\n const {\n userMessage,\n chatCtx,\n instructions: defaultInstructions,\n toolChoice: defaultToolChoice,\n allowInterruptions: defaultAllowInterruptions,\n } = options;\n\n let instructions = defaultInstructions;\n let toolChoice = defaultToolChoice;\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.generateReply(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n if (this.llm === undefined) {\n throw new Error('trying to generate reply without an LLM model');\n }\n\n const functionCall = asyncLocalStorage.getStore()?.functionCall;\n if (toolChoice === undefined && functionCall !== undefined) {\n // when generateReply is called inside a tool, set toolChoice to 'none' by default\n toolChoice = 'none';\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n if (this.llm instanceof RealtimeModel) {\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: handle,\n // TODO(brian): support llm.ChatMessage for the realtime model\n userInput: userMessage?.textContent,\n instructions,\n modelSettings: {\n // isGiven(toolChoice) = toolChoice !== undefined\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n }),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeReply',\n });\n } else if (this.llm instanceof LLM) {\n // instructions used inside generateReply are \"extra\" instructions.\n // this matches the behavior of the Realtime API:\n // https://platform.openai.com/docs/api-reference/realtime-client-events/response/create\n if (instructions) {\n instructions = `${this.agent.instructions}\\n${instructions}`;\n }\n\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.pipelineReplyTask(\n handle,\n chatCtx ?? this.agent.chatCtx,\n this.agent.toolCtx,\n {\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n instructions ? `${this.agent.instructions}\\n${instructions}` : instructions,\n userMessage,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n }\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n interrupt(): Future<void> {\n const future = new Future<void>();\n const currentSpeech = this._currentSpeech;\n\n //TODO(AJS-273): add interrupt for background speeches\n\n currentSpeech?.interrupt();\n\n for (const [_, __, speech] of this.speechQueue) {\n speech.interrupt();\n }\n\n this.realtimeSession?.interrupt();\n\n if (currentSpeech === undefined) {\n future.resolve();\n } else {\n currentSpeech.addDoneCallback(() => {\n if (future.done) return;\n future.resolve();\n });\n }\n\n return future;\n }\n\n private onPipelineReplyDone(): void {\n if (!this.speechQueue.peek() && (!this._currentSpeech || this._currentSpeech.done())) {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async userTurnCompleted(info: EndOfTurnInfo, oldTask?: Promise<void>): Promise<void> {\n if (oldTask) {\n // We never cancel user code as this is very confusing.\n // So we wait for the old execution of onUserTurnCompleted to finish.\n // In practice this is OK because most speeches will be interrupted if a new turn\n // is detected. So the previous execution should complete quickly.\n await oldTask;\n }\n\n // When the audio recognition detects the end of a user turn:\n // - check if realtime model server-side turn detection is enabled\n // - check if there is no current generation happening\n // - cancel the current generation if it allows interruptions (otherwise skip this current\n // turn)\n // - generate a reply to the user input\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection) {\n return;\n }\n this.realtimeSession?.commitAudio();\n }\n\n if (this._currentSpeech) {\n if (!this._currentSpeech.allowInterruptions) {\n this.logger.warn(\n { user_input: info.newTranscript },\n 'skipping user input, current speech generation cannot be interrupted',\n );\n return;\n }\n\n this.logger.info(\n { 'speech id': this._currentSpeech.id },\n 'speech interrupted, new user turn detected',\n );\n\n this._currentSpeech.interrupt();\n this.realtimeSession?.interrupt();\n }\n\n let userMessage: ChatMessage | undefined = ChatMessage.create({\n role: 'user',\n content: info.newTranscript,\n });\n\n // create a temporary mutable chat context to pass to onUserTurnCompleted\n // the user can edit it for the current generation, but changes will not be kept inside the\n // Agent.chatCtx\n const chatCtx = this.agent.chatCtx.copy();\n const startTime = Date.now();\n\n try {\n await this.agent.onUserTurnCompleted(chatCtx, userMessage);\n } catch (e) {\n if (e instanceof StopResponse) {\n return;\n }\n this.logger.error({ error: e }, 'error occurred during onUserTurnCompleted');\n }\n\n const callbackDuration = Date.now() - startTime;\n\n if (this.llm instanceof RealtimeModel) {\n // ignore stt transcription for realtime model\n userMessage = undefined;\n } else if (this.llm === undefined) {\n return;\n }\n\n // Ensure the new message is passed to generateReply\n // This preserves the original message id, making it easier for users to track responses\n const speechHandle = this.generateReply({ userMessage, chatCtx });\n\n const eouMetrics: EOUMetrics = {\n type: 'eou_metrics',\n timestamp: Date.now(),\n endOfUtteranceDelay: info.endOfUtteranceDelay,\n transcriptionDelay: info.transcriptionDelay,\n onUserTurnCompletedDelay: callbackDuration,\n speechId: speechHandle.id,\n };\n\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: eouMetrics }),\n );\n }\n\n private async ttsTask(\n speechHandle: SpeechHandle,\n text: string | ReadableStream<string>,\n addToChatCtx: boolean,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n audio?: ReadableStream<AudioFrame> | null,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (speechHandle.interrupted) {\n return;\n }\n\n let baseStream: ReadableStream<string>;\n if (text instanceof ReadableStream) {\n baseStream = text;\n } else {\n baseStream = new ReadableStream({\n start(controller) {\n controller.enqueue(text);\n controller.close();\n },\n });\n }\n\n const [textSource, audioSource] = baseStream.tee();\n\n const tasks: Array<Task<void>> = [];\n\n const trNode = await this.agent.transcriptionNode(textSource, {});\n let textOut: _TextOut | null = null;\n if (trNode) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNode,\n replyAbortController,\n transcriptionOutput,\n );\n textOut = _textOut;\n tasks.push(textForwardTask);\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n if (!audioOutput) {\n if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n } else {\n let audioOut: _AudioOut | null = null;\n if (!audio) {\n // generate audio using TTS\n const [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n audioSource,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n } else {\n // use the provided audio\n const [forwardTask, _audioOut] = performAudioForwarding(\n audio,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n }\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n }\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n if (audioOutput) {\n audioOutput.clearBuffer();\n await audioOutput.waitForPlayout();\n }\n }\n\n if (addToChatCtx) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n interrupted: speechHandle.interrupted,\n });\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async pipelineReplyTask(\n speechHandle: SpeechHandle,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n instructions?: string,\n newMessage?: ChatMessage,\n toolsMessages?: ChatItem[],\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n chatCtx = chatCtx.copy();\n\n if (newMessage) {\n chatCtx.insert(newMessage);\n this.agent._chatCtx.insert(newMessage);\n this.agentSession._conversationItemAdded(newMessage);\n }\n\n if (instructions) {\n try {\n updateInstructions({\n chatCtx,\n instructions,\n addIfMissing: true,\n });\n } catch (e) {\n this.logger.error({ error: e }, 'error occurred during updateInstructions');\n }\n }\n\n this.agentSession._updateAgentState('thinking');\n const tasks: Array<Task<void>> = [];\n const [llmTask, llmGenData] = performLLMInference(\n // preserve `this` context in llmNode\n (...args) => this.agent.llmNode(...args),\n chatCtx,\n toolCtx,\n modelSettings,\n replyAbortController,\n );\n tasks.push(llmTask);\n\n const [ttsTextInput, llmOutput] = llmGenData.textStream.tee();\n\n let ttsTask: Task<void> | null = null;\n let ttsStream: ReadableStream<AudioFrame> | null = null;\n if (audioOutput) {\n [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n ttsTextInput,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForScheduled()]);\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n this.agentSession._updateAgentState('thinking');\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n const replyStartedAt = Date.now();\n const trNodeResult = await this.agent.transcriptionNode(llmOutput, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n replyAbortController,\n transcriptionOutput,\n );\n tasks.push(textForwardTask);\n textOut = _textOut;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n if (ttsStream) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n audioOut = _audioOut;\n tasks.push(forwardTask);\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n throw Error('ttsStream is null when audioOutput is enabled');\n }\n } else {\n textOut?.firstTextFut.await.finally(onFirstFrame);\n }\n\n //TODO(AJS-272): before executing tools, make sure we generated all the text\n // (this ensure everything is kept ordered)\n\n const onToolExecutionStarted = (_: FunctionCall) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const onToolExecutionCompleted = (_: ToolExecutionOutput) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolChoice: modelSettings.toolChoice,\n toolCallStream: llmGenData.toolCallStream,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n // add the tools messages that triggers this reply to the chat context\n if (toolsMessages) {\n for (const msg of toolsMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolsMessages);\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all pipeline reply tasks due to interruption',\n );\n replyAbortController.abort();\n await Promise.allSettled(\n tasks.map((task) => task.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT)),\n );\n\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n }\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: llmGenData.id,\n interrupted: true,\n createdAt: replyStartedAt,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n // TODO(shubhra) add chat message to speech handle\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n if (textOut && textOut.text) {\n const message = ChatMessage.create({\n role: 'assistant',\n id: llmGenData.id,\n interrupted: false,\n createdAt: replyStartedAt,\n content: textOut.text,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n this.logger.info(\n { speech_id: speechHandle.id, message: textOut.text },\n 'playout completed without interruption',\n );\n }\n\n if (toolOutput.output.length > 0) {\n this.agentSession._updateAgentState('thinking');\n } else if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent output should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCalls.push(sanitizedOut.toolCall);\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n // TODO(brian): should we mark the function call as failed to notify the LLM?\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n const toolMessages = [\n ...functionToolsExecutedEvent.functionCalls,\n ...functionToolsExecutedEvent.functionCallOutputs,\n ] as ChatItem[];\n if (shouldGenerateToolReply) {\n chatCtx.insert(toolMessages);\n\n const handle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle._stepIndex + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: handle,\n }),\n );\n\n // Avoid setting tool_choice to \"required\" or a specific function when\n // passing tool response back to the LLM\n const respondToolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n\n const toolResponseTask = this.createSpeechTask({\n task: Task.from(() =>\n this.pipelineReplyTask(\n handle,\n chatCtx,\n toolCtx,\n { toolChoice: respondToolChoice },\n replyAbortController,\n instructions,\n undefined,\n toolMessages,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n toolResponseTask.finally(() => this.onPipelineReplyDone());\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n } else if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n for (const msg of toolMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolMessages);\n }\n }\n\n private async realtimeGenerationTask(\n speechHandle: SpeechHandle,\n ev: GenerationCreatedEvent,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not initialized');\n }\n if (!(this.llm instanceof RealtimeModel)) {\n throw new Error('llm is not a realtime model');\n }\n\n this.logger.debug(\n { speech_id: speechHandle.id, stepIndex: speechHandle.numSteps },\n 'realtime generation started',\n );\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const textOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n const toolCtx = this.realtimeSession.tools;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n if (speechHandle.interrupted) {\n return;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n const readMessages = async (\n abortController: AbortController,\n outputs: Array<[string, _TextOut | null, _AudioOut | null]>,\n ) => {\n const forwardTasks: Array<Task<void>> = [];\n try {\n for await (const msg of ev.messageStream) {\n if (forwardTasks.length > 0) {\n this.logger.warn(\n 'expected to receive only one message generation from the realtime API',\n );\n break;\n }\n const trNodeResult = await this.agent.transcriptionNode(msg.textStream, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n abortController,\n textOutput,\n );\n forwardTasks.push(textForwardTask);\n textOut = _textOut;\n }\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n const realtimeAudio = await this.agent.realtimeAudioOutputNode(\n msg.audioStream,\n modelSettings,\n );\n if (realtimeAudio) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n realtimeAudio,\n audioOutput,\n abortController,\n );\n forwardTasks.push(forwardTask);\n audioOut = _audioOut;\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n this.logger.warn(\n 'audio output is enabled but neither tts nor realtime audio is available',\n );\n }\n } else if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n outputs.push([msg.messageId, textOut, audioOut]);\n }\n await waitFor(forwardTasks);\n } catch (error) {\n this.logger.error(error, 'error reading messages from the realtime API');\n } finally {\n await cancelAndWait(forwardTasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n }\n };\n\n const messageOutputs: Array<[string, _TextOut | null, _AudioOut | null]> = [];\n const tasks = [\n Task.from(\n (controller) => readMessages(controller, messageOutputs),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_messages',\n ),\n ];\n\n const [toolCallStream, toolCallStreamForTracing] = ev.functionStream.tee();\n // TODO(brian): append to tracing tees\n const toolCalls: FunctionCall[] = [];\n\n const readToolStreamTask = async (\n controller: AbortController,\n stream: ReadableStream<FunctionCall>,\n ) => {\n const reader = stream.getReader();\n try {\n while (!controller.signal.aborted) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.logger.debug({ tool_call: value }, 'received tool call from the realtime API');\n toolCalls.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n };\n\n tasks.push(\n Task.from(\n (controller) => readToolStreamTask(controller, toolCallStreamForTracing),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_tool_stream',\n ),\n );\n\n const onToolExecutionStarted = (f: FunctionCall) => {\n speechHandle._itemAdded([f]);\n };\n\n const onToolExecutionCompleted = (out: ToolExecutionOutput) => {\n if (out.toolCallOutput) {\n speechHandle._itemAdded([out.toolCallOutput]);\n }\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolCallStream,\n toolChoice: modelSettings.toolChoice,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n // TODO(brian): add tracing span\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n this.agentSession._updateAgentState('listening');\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all realtime generation tasks due to interruption',\n );\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, audioOut] = messageOutputs[0]!;\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n let playbackPosition = playbackEv.playbackPosition;\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n playbackPosition = 0;\n }\n\n // truncate server-side message\n this.realtimeSession.truncate({\n messageId: msgId,\n audioEndMs: Math.floor(playbackPosition),\n });\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: msgId,\n interrupted: true,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message);\n\n // TODO(brian): add tracing span\n }\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n }\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n // TODO(brian): close tees\n return;\n }\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, _] = messageOutputs[0]!;\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n id: msgId,\n interrupted: false,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message); // mark the playout done before waiting for the tool execution\\\n // TODO(brian): add tracing span\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n // TODO(brian): close tees\n\n toolOutput.firstToolStartedFuture.await.finally(() => {\n this.agentSession._updateAgentState('thinking');\n });\n\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent ouput should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n // wait all speeches played before updating the tool output and generating the response\n // most realtime models dont support generating multiple responses at the same time\n while (this.currentSpeech || this.speechQueue.size() > 0) {\n if (\n this.currentSpeech &&\n !this.currentSpeech.done() &&\n this.currentSpeech !== speechHandle\n ) {\n await this.currentSpeech.waitForPlayout();\n } else {\n // Don't block the event loop\n await new Promise((resolve) => setImmediate(resolve));\n }\n }\n const chatCtx = this.realtimeSession.chatCtx.copy();\n chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);\n try {\n await this.realtimeSession.updateChatCtx(chatCtx);\n } catch (error) {\n this.logger.warn(\n { error },\n 'failed to update chat context before generating the function calls results',\n );\n }\n }\n\n // skip realtime reply if not required or auto-generated\n if (!shouldGenerateToolReply || this.llm.capabilities.autoToolReplyGeneration) {\n return;\n }\n\n this.realtimeSession.interrupt();\n\n const replySpeechHandle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle.numSteps + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: replySpeechHandle,\n }),\n );\n\n const toolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: replySpeechHandle,\n modelSettings: { toolChoice },\n abortController,\n }),\n ),\n ownedSpeechHandle: replySpeechHandle,\n name: 'AgentActivity.realtime_reply',\n });\n\n this.scheduleSpeech(replySpeechHandle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n }\n\n private async realtimeReplyTask({\n speechHandle,\n modelSettings: { toolChoice },\n userInput,\n instructions,\n abortController,\n }: {\n speechHandle: SpeechHandle;\n modelSettings: ModelSettings;\n abortController: AbortController;\n userInput?: string;\n instructions?: string;\n }): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not available');\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (userInput) {\n const chatCtx = this.realtimeSession.chatCtx.copy();\n const message = chatCtx.addMessage({\n role: 'user',\n content: userInput,\n });\n await this.realtimeSession.updateChatCtx(chatCtx);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n const originalToolChoice = this.toolChoice;\n if (toolChoice !== undefined) {\n this.realtimeSession.updateOptions({ toolChoice });\n }\n\n try {\n const generationEvent = await this.realtimeSession.generateReply(instructions);\n await this.realtimeGenerationTask(\n speechHandle,\n generationEvent,\n { toolChoice },\n abortController,\n );\n } finally {\n // reset toolChoice value\n if (toolChoice !== undefined && toolChoice !== originalToolChoice) {\n this.realtimeSession.updateOptions({ toolChoice: originalToolChoice });\n }\n }\n }\n\n private scheduleSpeech(\n speechHandle: SpeechHandle,\n priority: number,\n force: boolean = false,\n ): void {\n // when force=true, we allow tool responses to bypass draining\n // This allows for tool responses to be generated before the AgentActivity is finalized\n if (this.draining && !force) {\n throw new Error('cannot schedule new speech, the agent is draining');\n }\n\n // Monotonic time to avoid near 0 collisions\n this.speechQueue.push([priority, Number(process.hrtime.bigint()), speechHandle]);\n speechHandle._markScheduled();\n this.wakeupMainTask();\n }\n\n async drain(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (this._draining) return;\n\n this.createSpeechTask({\n task: Task.from(() => this.agent.onExit()),\n name: 'AgentActivity_onExit',\n });\n\n this.wakeupMainTask();\n this._draining = true;\n await this._mainTask?.result;\n } finally {\n unlock();\n }\n }\n\n async close(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (!this._draining) {\n this.logger.warn('task closing without draining');\n }\n\n // Unregister event handlers to prevent duplicate metrics\n if (this.llm instanceof LLM) {\n this.llm.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.realtimeSession) {\n this.realtimeSession.off('generation_created', this.onGenerationCreated);\n this.realtimeSession.off('input_speech_started', this.onInputSpeechStarted);\n this.realtimeSession.off('input_speech_stopped', this.onInputSpeechStopped);\n this.realtimeSession.off(\n 'input_audio_transcription_completed',\n this.onInputAudioTranscriptionCompleted,\n );\n this.realtimeSession.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.stt instanceof STT) {\n this.stt.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.tts instanceof TTS) {\n this.tts.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.vad instanceof VAD) {\n this.vad.off('metrics_collected', this.onMetricsCollected);\n }\n\n this.detachAudioInput();\n await this.realtimeSession?.close();\n await this.audioRecognition?.close();\n await this._mainTask?.cancelAndWait();\n } finally {\n unlock();\n }\n }\n}\n\nfunction toOaiToolChoice(toolChoice: ToolChoice | null): ToolChoice | undefined {\n // we convert null to undefined, which maps to the default provider tool choice value\n return toolChoice !== null ? toolChoice : undefined;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent_activity.d.ts","sourceRoot":"","sources":["../../src/voice/agent_activity.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"agent_activity.d.ts","sourceRoot":"","sources":["../../src/voice/agent_activity.ts"],"names":[],"mappings":"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"}
|
|
@@ -1334,6 +1334,13 @@ ${instructions}` : instructions,
|
|
|
1334
1334
|
draining = true;
|
|
1335
1335
|
}
|
|
1336
1336
|
if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {
|
|
1337
|
+
while (this.currentSpeech || this.speechQueue.size() > 0) {
|
|
1338
|
+
if (this.currentSpeech && !this.currentSpeech.done() && this.currentSpeech !== speechHandle) {
|
|
1339
|
+
await this.currentSpeech.waitForPlayout();
|
|
1340
|
+
} else {
|
|
1341
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1337
1344
|
const chatCtx = this.realtimeSession.chatCtx.copy();
|
|
1338
1345
|
chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);
|
|
1339
1346
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/agent_activity.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Mutex } from '@livekit/mutex';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { Heap } from 'heap-js';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { ReadableStream } from 'node:stream/web';\nimport { type ChatContext, ChatMessage } from '../llm/chat_context.js';\nimport {\n type ChatItem,\n type FunctionCall,\n type GenerationCreatedEvent,\n type InputSpeechStartedEvent,\n type InputSpeechStoppedEvent,\n type InputTranscriptionCompleted,\n LLM,\n RealtimeModel,\n type RealtimeModelError,\n type RealtimeSession,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.js';\nimport type { LLMError } from '../llm/llm.js';\nimport { log } from '../log.js';\nimport type {\n EOUMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from '../metrics/base.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { STT, type STTError, type SpeechEvent } from '../stt/stt.js';\nimport { splitWords } from '../tokenize/basic/word.js';\nimport { TTS, type TTSError } from '../tts/tts.js';\nimport { Future, Task, cancelAndWait, waitFor } from '../utils.js';\nimport { VAD, type VADEvent } from '../vad.js';\nimport type { Agent, ModelSettings } from './agent.js';\nimport { StopResponse, asyncLocalStorage } from './agent.js';\nimport { type AgentSession, type TurnDetectionMode } from './agent_session.js';\nimport {\n AudioRecognition,\n type EndOfTurnInfo,\n type RecognitionHooks,\n type _TurnDetector,\n} from './audio_recognition.js';\nimport {\n AgentSessionEventTypes,\n createErrorEvent,\n createFunctionToolsExecutedEvent,\n createMetricsCollectedEvent,\n createSpeechCreatedEvent,\n createUserInputTranscribedEvent,\n} from './events.js';\nimport type { ToolExecutionOutput } from './generation.js';\nimport {\n type _AudioOut,\n type _TextOut,\n performAudioForwarding,\n performLLMInference,\n performTTSInference,\n performTextForwarding,\n performToolExecutions,\n removeInstructions,\n updateInstructions,\n} from './generation.js';\nimport { SpeechHandle } from './speech_handle.js';\n\n// equivalent to Python's contextvars\nconst speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();\n\nexport class AgentActivity implements RecognitionHooks {\n private static readonly REPLY_TASK_CANCEL_TIMEOUT = 5000;\n private started = false;\n private audioRecognition?: AudioRecognition;\n private realtimeSession?: RealtimeSession;\n private turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n private logger = log();\n private _draining = false;\n private _currentSpeech?: SpeechHandle;\n private speechQueue: Heap<[number, number, SpeechHandle]>; // [priority, timestamp, speechHandle]\n private q_updated: Future;\n private speechTasks: Set<Task<void>> = new Set();\n private lock = new Mutex();\n private audioStream = new DeferredReadableStream<AudioFrame>();\n // default to null as None, which maps to the default provider tool choice value\n private toolChoice: ToolChoice | null = null;\n\n agent: Agent;\n agentSession: AgentSession;\n\n /** @internal */\n _mainTask?: Task<void>;\n _userTurnCompletedTask?: Promise<void>;\n\n constructor(agent: Agent, agentSession: AgentSession) {\n this.agent = agent;\n this.agentSession = agentSession;\n\n /**\n * Custom comparator to prioritize speech handles with higher priority\n * - Prefer higher priority\n * - Prefer earlier timestamp (so calling a sequence of generateReply() will execute in FIFO order)\n */\n this.speechQueue = new Heap<[number, number, SpeechHandle]>(([p1, t1, _], [p2, t2, __]) => {\n return p1 === p2 ? t1 - t2 : p2 - p1;\n });\n this.q_updated = new Future();\n\n this.turnDetectionMode =\n typeof this.turnDetection === 'string' ? this.turnDetection : undefined;\n\n if (this.turnDetectionMode === 'vad' && this.vad === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"vad\", but no VAD model is provided, ignoring the turnDdetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt' && this.stt === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but no STT model is provided, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection && !this.allowInterruptions) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false, ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentSession instead',\n );\n }\n\n if (this.turnDetectionMode === 'realtime_llm' && !this.llm.capabilities.turnDetection) {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel or the server-side turn detection is not supported/enabled, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt') {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but the LLM is a RealtimeModel, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n this.turnDetectionMode &&\n this.turnDetectionMode !== 'realtime_llm' &&\n this.llm.capabilities.turnDetection\n ) {\n this.logger.warn(\n `turnDetection is set to \"${this.turnDetectionMode}\", but the LLM is a RealtimeModel and server-side turn detection enabled, ignoring the turnDetection setting`,\n );\n this.turnDetectionMode = undefined;\n }\n\n // fallback to VAD if server side turn detection is disabled and VAD is available\n if (\n !this.llm.capabilities.turnDetection &&\n this.vad &&\n this.turnDetectionMode === undefined\n ) {\n this.turnDetectionMode = 'vad';\n }\n } else if (this.turnDetectionMode === 'realtime_llm') {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n !this.vad &&\n this.stt &&\n this.llm instanceof LLM &&\n this.allowInterruptions &&\n this.turnDetectionMode === undefined\n ) {\n this.logger.warn(\n 'VAD is not set. Enabling VAD is recommended when using LLM and STT ' +\n 'for more responsive interruption handling.',\n );\n }\n }\n\n async start(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n this.agent._agentActivity = this;\n\n if (this.llm instanceof RealtimeModel) {\n this.realtimeSession = this.llm.session();\n this.realtimeSession.on('generation_created', (ev) => this.onGenerationCreated(ev));\n this.realtimeSession.on('input_speech_started', (ev) => this.onInputSpeechStarted(ev));\n this.realtimeSession.on('input_speech_stopped', (ev) => this.onInputSpeechStopped(ev));\n this.realtimeSession.on('input_audio_transcription_completed', (ev) =>\n this.onInputAudioTranscriptionCompleted(ev),\n );\n this.realtimeSession.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.realtimeSession.on('error', (ev) => this.onError(ev));\n\n removeInstructions(this.agent._chatCtx);\n try {\n await this.realtimeSession.updateInstructions(this.agent.instructions);\n } catch (error) {\n this.logger.error(error, 'failed to update the instructions');\n }\n\n try {\n await this.realtimeSession.updateChatCtx(this.agent.chatCtx);\n } catch (error) {\n this.logger.error(error, 'failed to update the chat context');\n }\n\n try {\n await this.realtimeSession.updateTools(this.tools);\n } catch (error) {\n this.logger.error(error, 'failed to update the tools');\n }\n } else if (this.llm instanceof LLM) {\n try {\n updateInstructions({\n chatCtx: this.agent._chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n } catch (error) {\n this.logger.error('failed to update the instructions', error);\n }\n }\n\n // metrics and error handling\n if (this.llm instanceof LLM) {\n this.llm.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.llm.on('error', (ev) => this.onError(ev));\n }\n\n if (this.stt instanceof STT) {\n this.stt.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.stt.on('error', (ev) => this.onError(ev));\n }\n\n if (this.tts instanceof TTS) {\n this.tts.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.tts.on('error', (ev) => this.onError(ev));\n }\n\n if (this.vad instanceof VAD) {\n this.vad.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n }\n\n this.audioRecognition = new AudioRecognition({\n recognitionHooks: this,\n // Disable stt node if stt is not provided\n stt: this.stt ? (...args) => this.agent.sttNode(...args) : undefined,\n vad: this.vad,\n turnDetector: typeof this.turnDetection === 'string' ? undefined : this.turnDetection,\n turnDetectionMode: this.turnDetectionMode,\n minEndpointingDelay: this.agentSession.options.minEndpointingDelay,\n maxEndpointingDelay: this.agentSession.options.maxEndpointingDelay,\n });\n this.audioRecognition.start();\n this.started = true;\n\n this._mainTask = Task.from(({ signal }) => this.mainTask(signal));\n this.createSpeechTask({\n task: Task.from(() => this.agent.onEnter()),\n name: 'AgentActivity_onEnter',\n });\n } finally {\n unlock();\n }\n }\n\n get currentSpeech(): SpeechHandle | undefined {\n return this._currentSpeech;\n }\n\n get vad(): VAD | undefined {\n return this.agent.vad || this.agentSession.vad;\n }\n\n get stt(): STT | undefined {\n return this.agent.stt || this.agentSession.stt;\n }\n\n get llm(): LLM | RealtimeModel | undefined {\n return this.agent.llm || this.agentSession.llm;\n }\n\n get tts(): TTS | undefined {\n return this.agent.tts || this.agentSession.tts;\n }\n\n get tools(): ToolContext {\n return this.agent.toolCtx;\n }\n\n get draining(): boolean {\n return this._draining;\n }\n\n get realtimeLLMSession(): RealtimeSession | undefined {\n return this.realtimeSession;\n }\n\n get allowInterruptions(): boolean {\n // TODO(AJS-51): Allow options to be defined in Agent class\n return this.agentSession.options.allowInterruptions;\n }\n\n get turnDetection(): TurnDetectionMode | undefined {\n // TODO(brian): prioritize using agent.turn_detection\n return this.agentSession.turnDetection;\n }\n\n get toolCtx(): ToolContext {\n return this.agent.toolCtx;\n }\n\n async updateChatCtx(chatCtx: ChatContext): Promise<void> {\n chatCtx = chatCtx.copy({ toolCtx: this.toolCtx });\n\n this.agent._chatCtx = chatCtx;\n\n if (this.realtimeSession) {\n removeInstructions(chatCtx);\n this.realtimeSession.updateChatCtx(chatCtx);\n } else {\n updateInstructions({\n chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n }\n }\n\n updateOptions({ toolChoice }: { toolChoice?: ToolChoice | null }): void {\n if (toolChoice !== undefined) {\n this.toolChoice = toolChoice;\n }\n\n if (this.realtimeSession) {\n this.realtimeSession.updateOptions({ toolChoice: this.toolChoice });\n }\n }\n\n attachAudioInput(audioStream: ReadableStream<AudioFrame>): void {\n if (this.audioStream.isSourceSet) {\n this.logger.debug('detaching existing audio input in agent activity');\n this.audioStream.detachSource();\n }\n\n /**\n * We need to add a deferred ReadableStream layer on top of the audioStream from the agent session.\n * The tee() operation should be applied to the deferred stream, not the original audioStream.\n * This is important because teeing the original stream directly makes it very difficult—if not\n * impossible—to implement stream unlock logic cleanly.\n */\n this.audioStream.setSource(audioStream);\n const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.tee();\n\n if (this.realtimeSession) {\n this.realtimeSession.setInputAudioStream(realtimeAudioStream);\n }\n\n if (this.audioRecognition) {\n this.audioRecognition.setInputAudioStream(recognitionAudioStream);\n }\n }\n\n detachAudioInput(): void {\n this.audioStream.detachSource();\n }\n\n commitUserTurn() {\n if (!this.audioRecognition) {\n throw new Error('AudioRecognition is not initialized');\n }\n\n // TODO(brian): add audio_detached flag\n const audioDetached = false;\n this.audioRecognition.commitUserTurn(audioDetached);\n }\n\n clearUserTurn() {\n this.audioRecognition?.clearUserTurn();\n this.realtimeSession?.clearAudio();\n }\n\n say(\n text: string | ReadableStream<string>,\n options?: {\n audio?: ReadableStream<AudioFrame>;\n allowInterruptions?: boolean;\n addToChatCtx?: boolean;\n },\n ): SpeechHandle {\n const {\n audio,\n allowInterruptions: defaultAllowInterruptions,\n addToChatCtx = true,\n } = options ?? {};\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n !audio &&\n !this.tts &&\n this.agentSession.output.audio &&\n this.agentSession.output.audioEnabled\n ) {\n throw new Error('trying to generate speech from text without a TTS model');\n }\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.say(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'say',\n speechHandle: handle,\n }),\n );\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.ttsTask(handle, text, addToChatCtx, {}, abortController, audio),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.say_tts',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n // -- Metrics and errors --\n\n private onMetricsCollected = (\n ev: STTMetrics | TTSMetrics | VADMetrics | LLMMetrics | RealtimeModelMetrics,\n ) => {\n const speechHandle = speechHandleStorage.getStore();\n if (speechHandle && (ev.type === 'llm_metrics' || ev.type === 'tts_metrics')) {\n ev.speechId = speechHandle.id;\n }\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: ev }),\n );\n };\n\n private onError(ev: RealtimeModelError | STTError | TTSError | LLMError): void {\n if (ev.type === 'realtime_model_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'stt_error') {\n const errorEvent = createErrorEvent(ev.error, this.stt);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'tts_error') {\n const errorEvent = createErrorEvent(ev.error, this.tts);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'llm_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n }\n\n this.agentSession._onError(ev);\n }\n\n // -- Realtime Session events --\n\n onInputSpeechStarted(_ev: InputSpeechStartedEvent): void {\n this.logger.info('onInputSpeechStarted');\n\n if (!this.vad) {\n this.agentSession._updateUserState('speaking');\n }\n\n // this.interrupt() is going to raise when allow_interruptions is False,\n // llm.InputSpeechStartedEvent is only fired by the server when the turn_detection is enabled.\n try {\n this.interrupt();\n } catch (error) {\n this.logger.error(\n 'RealtimeAPI input_speech_started, but current speech is not interruptable, this should never happen!',\n error,\n );\n }\n }\n\n onInputSpeechStopped(ev: InputSpeechStoppedEvent): void {\n this.logger.info(ev, 'onInputSpeechStopped');\n\n if (!this.vad) {\n this.agentSession._updateUserState('listening');\n }\n\n if (ev.userTranscriptionEnabled) {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n isFinal: false,\n transcript: '',\n }),\n );\n }\n }\n\n onInputAudioTranscriptionCompleted(ev: InputTranscriptionCompleted): void {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.transcript,\n isFinal: ev.isFinal,\n }),\n );\n\n if (ev.isFinal) {\n const message = ChatMessage.create({\n role: 'user',\n content: ev.transcript,\n id: ev.itemId,\n });\n this.agent._chatCtx.items.push(message);\n this.agentSession._conversationItemAdded(message);\n }\n }\n\n onGenerationCreated(ev: GenerationCreatedEvent): void {\n if (ev.userInitiated) {\n // user initiated generations are directly handled inside _realtime_reply_task\n return;\n }\n\n if (this.draining) {\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent?\n this.logger.warn('skipping new realtime generation, the agent is draining');\n return;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: this.allowInterruptions,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeGenerationTask(handle, ev, {}, abortController),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeGeneration',\n });\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n }\n\n // recognition hooks\n\n onStartOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('speaking');\n }\n\n onEndOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('listening');\n }\n\n onVADInferenceDone(ev: VADEvent): void {\n if (this.turnDetection === 'manual' || this.turnDetection === 'realtime_llm') {\n // skip speech handle interruption for manual and realtime model\n return;\n }\n\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.turnDetection) {\n // skip speech handle interruption if server side turn detection is enabled\n return;\n }\n\n if (ev.speechDuration < this.agentSession.options.minInterruptionDuration) {\n return;\n }\n\n if (this.stt && this.agentSession.options.minInterruptionWords > 0 && this.audioRecognition) {\n const text = this.audioRecognition.currentTranscript;\n\n // TODO(shubhra): better word splitting for multi-language\n if (text && splitWords(text, true).length < this.agentSession.options.minInterruptionWords) {\n return;\n }\n }\n\n this.realtimeSession?.startUserActivity();\n\n if (\n this._currentSpeech &&\n !this._currentSpeech.interrupted &&\n this._currentSpeech.allowInterruptions\n ) {\n this.logger.info({ 'speech id': this._currentSpeech.id }, 'speech interrupted by VAD');\n this.realtimeSession?.interrupt();\n this._currentSpeech.interrupt();\n }\n }\n\n onInterimTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: false,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n onFinalTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: true,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n private createSpeechTask(options: {\n task: Task<void>;\n ownedSpeechHandle?: SpeechHandle;\n name?: string;\n }): Promise<void> {\n const { task, ownedSpeechHandle } = options;\n\n this.speechTasks.add(task);\n task.addDoneCallback(() => {\n this.speechTasks.delete(task);\n });\n\n if (ownedSpeechHandle) {\n ownedSpeechHandle._tasks.push(task);\n task.addDoneCallback(() => {\n if (ownedSpeechHandle._tasks.every((t) => t.done)) {\n ownedSpeechHandle._markDone();\n }\n });\n }\n\n task.addDoneCallback(() => {\n this.wakeupMainTask();\n });\n\n return task.result;\n }\n\n async onEndOfTurn(info: EndOfTurnInfo): Promise<boolean> {\n if (this.draining) {\n this.logger.warn({ user_input: info.newTranscript }, 'skipping user input, task is draining');\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent/activity?\n return true;\n }\n\n if (\n this.stt &&\n this.turnDetection !== 'manual' &&\n this._currentSpeech &&\n this._currentSpeech.allowInterruptions &&\n !this._currentSpeech.interrupted &&\n this.agentSession.options.minInterruptionWords > 0 &&\n info.newTranscript.split(' ').length < this.agentSession.options.minInterruptionWords\n ) {\n // avoid interruption if the new_transcript is too short\n this.logger.info('skipping user input, new_transcript is too short');\n return false;\n }\n\n const oldTask = this._userTurnCompletedTask;\n this._userTurnCompletedTask = this.createSpeechTask({\n task: Task.from(() => this.userTurnCompleted(info, oldTask)),\n name: 'AgentActivity.userTurnCompleted',\n });\n return true;\n }\n\n retrieveChatCtx(): ChatContext {\n return this.agentSession.chatCtx;\n }\n\n private async mainTask(signal: AbortSignal): Promise<void> {\n const abortFuture = new Future();\n const abortHandler = () => {\n abortFuture.resolve();\n signal.removeEventListener('abort', abortHandler);\n };\n signal.addEventListener('abort', abortHandler);\n\n while (true) {\n await Promise.race([this.q_updated.await, abortFuture.await]);\n if (signal.aborted) break;\n\n while (this.speechQueue.size() > 0) {\n if (signal.aborted) break;\n\n const heapItem = this.speechQueue.pop();\n if (!heapItem) {\n throw new Error('Speech queue is empty');\n }\n const speechHandle = heapItem[2];\n this._currentSpeech = speechHandle;\n speechHandle._authorizeGeneration();\n await speechHandle._waitForGeneration();\n this._currentSpeech = undefined;\n }\n\n // If we're draining and there are no more speech tasks, we can exit.\n // Only speech tasks can bypass draining to create a tool response\n if (this.draining && this.speechTasks.size === 0) {\n this.logger.info('mainTask: draining and no more speech tasks');\n break;\n }\n\n this.q_updated = new Future();\n }\n\n this.logger.info('AgentActivity mainTask: exiting');\n }\n\n private wakeupMainTask(): void {\n this.q_updated.resolve();\n }\n\n generateReply(options: {\n userMessage?: ChatMessage;\n chatCtx?: ChatContext;\n instructions?: string;\n toolChoice?: ToolChoice | null;\n allowInterruptions?: boolean;\n }): SpeechHandle {\n const {\n userMessage,\n chatCtx,\n instructions: defaultInstructions,\n toolChoice: defaultToolChoice,\n allowInterruptions: defaultAllowInterruptions,\n } = options;\n\n let instructions = defaultInstructions;\n let toolChoice = defaultToolChoice;\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.generateReply(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n if (this.llm === undefined) {\n throw new Error('trying to generate reply without an LLM model');\n }\n\n const functionCall = asyncLocalStorage.getStore()?.functionCall;\n if (toolChoice === undefined && functionCall !== undefined) {\n // when generateReply is called inside a tool, set toolChoice to 'none' by default\n toolChoice = 'none';\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n if (this.llm instanceof RealtimeModel) {\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: handle,\n // TODO(brian): support llm.ChatMessage for the realtime model\n userInput: userMessage?.textContent,\n instructions,\n modelSettings: {\n // isGiven(toolChoice) = toolChoice !== undefined\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n }),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeReply',\n });\n } else if (this.llm instanceof LLM) {\n // instructions used inside generateReply are \"extra\" instructions.\n // this matches the behavior of the Realtime API:\n // https://platform.openai.com/docs/api-reference/realtime-client-events/response/create\n if (instructions) {\n instructions = `${this.agent.instructions}\\n${instructions}`;\n }\n\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.pipelineReplyTask(\n handle,\n chatCtx ?? this.agent.chatCtx,\n this.agent.toolCtx,\n {\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n instructions ? `${this.agent.instructions}\\n${instructions}` : instructions,\n userMessage,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n }\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n interrupt(): Future<void> {\n const future = new Future<void>();\n const currentSpeech = this._currentSpeech;\n\n //TODO(AJS-273): add interrupt for background speeches\n\n currentSpeech?.interrupt();\n\n for (const [_, __, speech] of this.speechQueue) {\n speech.interrupt();\n }\n\n this.realtimeSession?.interrupt();\n\n if (currentSpeech === undefined) {\n future.resolve();\n } else {\n currentSpeech.addDoneCallback(() => {\n if (future.done) return;\n future.resolve();\n });\n }\n\n return future;\n }\n\n private onPipelineReplyDone(): void {\n if (!this.speechQueue.peek() && (!this._currentSpeech || this._currentSpeech.done())) {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async userTurnCompleted(info: EndOfTurnInfo, oldTask?: Promise<void>): Promise<void> {\n if (oldTask) {\n // We never cancel user code as this is very confusing.\n // So we wait for the old execution of onUserTurnCompleted to finish.\n // In practice this is OK because most speeches will be interrupted if a new turn\n // is detected. So the previous execution should complete quickly.\n await oldTask;\n }\n\n // When the audio recognition detects the end of a user turn:\n // - check if realtime model server-side turn detection is enabled\n // - check if there is no current generation happening\n // - cancel the current generation if it allows interruptions (otherwise skip this current\n // turn)\n // - generate a reply to the user input\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection) {\n return;\n }\n this.realtimeSession?.commitAudio();\n }\n\n if (this._currentSpeech) {\n if (!this._currentSpeech.allowInterruptions) {\n this.logger.warn(\n { user_input: info.newTranscript },\n 'skipping user input, current speech generation cannot be interrupted',\n );\n return;\n }\n\n this.logger.info(\n { 'speech id': this._currentSpeech.id },\n 'speech interrupted, new user turn detected',\n );\n\n this._currentSpeech.interrupt();\n this.realtimeSession?.interrupt();\n }\n\n let userMessage: ChatMessage | undefined = ChatMessage.create({\n role: 'user',\n content: info.newTranscript,\n });\n\n // create a temporary mutable chat context to pass to onUserTurnCompleted\n // the user can edit it for the current generation, but changes will not be kept inside the\n // Agent.chatCtx\n const chatCtx = this.agent.chatCtx.copy();\n const startTime = Date.now();\n\n try {\n await this.agent.onUserTurnCompleted(chatCtx, userMessage);\n } catch (e) {\n if (e instanceof StopResponse) {\n return;\n }\n this.logger.error({ error: e }, 'error occurred during onUserTurnCompleted');\n }\n\n const callbackDuration = Date.now() - startTime;\n\n if (this.llm instanceof RealtimeModel) {\n // ignore stt transcription for realtime model\n userMessage = undefined;\n } else if (this.llm === undefined) {\n return;\n }\n\n // Ensure the new message is passed to generateReply\n // This preserves the original message id, making it easier for users to track responses\n const speechHandle = this.generateReply({ userMessage, chatCtx });\n\n const eouMetrics: EOUMetrics = {\n type: 'eou_metrics',\n timestamp: Date.now(),\n endOfUtteranceDelay: info.endOfUtteranceDelay,\n transcriptionDelay: info.transcriptionDelay,\n onUserTurnCompletedDelay: callbackDuration,\n speechId: speechHandle.id,\n };\n\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: eouMetrics }),\n );\n }\n\n private async ttsTask(\n speechHandle: SpeechHandle,\n text: string | ReadableStream<string>,\n addToChatCtx: boolean,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n audio?: ReadableStream<AudioFrame> | null,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (speechHandle.interrupted) {\n return;\n }\n\n let baseStream: ReadableStream<string>;\n if (text instanceof ReadableStream) {\n baseStream = text;\n } else {\n baseStream = new ReadableStream({\n start(controller) {\n controller.enqueue(text);\n controller.close();\n },\n });\n }\n\n const [textSource, audioSource] = baseStream.tee();\n\n const tasks: Array<Task<void>> = [];\n\n const trNode = await this.agent.transcriptionNode(textSource, {});\n let textOut: _TextOut | null = null;\n if (trNode) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNode,\n replyAbortController,\n transcriptionOutput,\n );\n textOut = _textOut;\n tasks.push(textForwardTask);\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n if (!audioOutput) {\n if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n } else {\n let audioOut: _AudioOut | null = null;\n if (!audio) {\n // generate audio using TTS\n const [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n audioSource,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n } else {\n // use the provided audio\n const [forwardTask, _audioOut] = performAudioForwarding(\n audio,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n }\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n }\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n if (audioOutput) {\n audioOutput.clearBuffer();\n await audioOutput.waitForPlayout();\n }\n }\n\n if (addToChatCtx) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n interrupted: speechHandle.interrupted,\n });\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async pipelineReplyTask(\n speechHandle: SpeechHandle,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n instructions?: string,\n newMessage?: ChatMessage,\n toolsMessages?: ChatItem[],\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n chatCtx = chatCtx.copy();\n\n if (newMessage) {\n chatCtx.insert(newMessage);\n this.agent._chatCtx.insert(newMessage);\n this.agentSession._conversationItemAdded(newMessage);\n }\n\n if (instructions) {\n try {\n updateInstructions({\n chatCtx,\n instructions,\n addIfMissing: true,\n });\n } catch (e) {\n this.logger.error({ error: e }, 'error occurred during updateInstructions');\n }\n }\n\n this.agentSession._updateAgentState('thinking');\n const tasks: Array<Task<void>> = [];\n const [llmTask, llmGenData] = performLLMInference(\n // preserve `this` context in llmNode\n (...args) => this.agent.llmNode(...args),\n chatCtx,\n toolCtx,\n modelSettings,\n replyAbortController,\n );\n tasks.push(llmTask);\n\n const [ttsTextInput, llmOutput] = llmGenData.textStream.tee();\n\n let ttsTask: Task<void> | null = null;\n let ttsStream: ReadableStream<AudioFrame> | null = null;\n if (audioOutput) {\n [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n ttsTextInput,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForScheduled()]);\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n this.agentSession._updateAgentState('thinking');\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n const replyStartedAt = Date.now();\n const trNodeResult = await this.agent.transcriptionNode(llmOutput, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n replyAbortController,\n transcriptionOutput,\n );\n tasks.push(textForwardTask);\n textOut = _textOut;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n if (ttsStream) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n audioOut = _audioOut;\n tasks.push(forwardTask);\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n throw Error('ttsStream is null when audioOutput is enabled');\n }\n } else {\n textOut?.firstTextFut.await.finally(onFirstFrame);\n }\n\n //TODO(AJS-272): before executing tools, make sure we generated all the text\n // (this ensure everything is kept ordered)\n\n const onToolExecutionStarted = (_: FunctionCall) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const onToolExecutionCompleted = (_: ToolExecutionOutput) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolChoice: modelSettings.toolChoice,\n toolCallStream: llmGenData.toolCallStream,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n // add the tools messages that triggers this reply to the chat context\n if (toolsMessages) {\n for (const msg of toolsMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolsMessages);\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all pipeline reply tasks due to interruption',\n );\n replyAbortController.abort();\n await Promise.allSettled(\n tasks.map((task) => task.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT)),\n );\n\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n }\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: llmGenData.id,\n interrupted: true,\n createdAt: replyStartedAt,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n // TODO(shubhra) add chat message to speech handle\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n if (textOut && textOut.text) {\n const message = ChatMessage.create({\n role: 'assistant',\n id: llmGenData.id,\n interrupted: false,\n createdAt: replyStartedAt,\n content: textOut.text,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n this.logger.info(\n { speech_id: speechHandle.id, message: textOut.text },\n 'playout completed without interruption',\n );\n }\n\n if (toolOutput.output.length > 0) {\n this.agentSession._updateAgentState('thinking');\n } else if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent output should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCalls.push(sanitizedOut.toolCall);\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n // TODO(brian): should we mark the function call as failed to notify the LLM?\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n const toolMessages = [\n ...functionToolsExecutedEvent.functionCalls,\n ...functionToolsExecutedEvent.functionCallOutputs,\n ] as ChatItem[];\n if (shouldGenerateToolReply) {\n chatCtx.insert(toolMessages);\n\n const handle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle._stepIndex + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: handle,\n }),\n );\n\n // Avoid setting tool_choice to \"required\" or a specific function when\n // passing tool response back to the LLM\n const respondToolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n\n const toolResponseTask = this.createSpeechTask({\n task: Task.from(() =>\n this.pipelineReplyTask(\n handle,\n chatCtx,\n toolCtx,\n { toolChoice: respondToolChoice },\n replyAbortController,\n instructions,\n undefined,\n toolMessages,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n toolResponseTask.finally(() => this.onPipelineReplyDone());\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n } else if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n for (const msg of toolMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolMessages);\n }\n }\n\n private async realtimeGenerationTask(\n speechHandle: SpeechHandle,\n ev: GenerationCreatedEvent,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not initialized');\n }\n if (!(this.llm instanceof RealtimeModel)) {\n throw new Error('llm is not a realtime model');\n }\n\n this.logger.debug(\n { speech_id: speechHandle.id, stepIndex: speechHandle.numSteps },\n 'realtime generation started',\n );\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const textOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n const toolCtx = this.realtimeSession.tools;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n if (speechHandle.interrupted) {\n return;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n const readMessages = async (\n abortController: AbortController,\n outputs: Array<[string, _TextOut | null, _AudioOut | null]>,\n ) => {\n const forwardTasks: Array<Task<void>> = [];\n try {\n for await (const msg of ev.messageStream) {\n if (forwardTasks.length > 0) {\n this.logger.warn(\n 'expected to receive only one message generation from the realtime API',\n );\n break;\n }\n const trNodeResult = await this.agent.transcriptionNode(msg.textStream, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n abortController,\n textOutput,\n );\n forwardTasks.push(textForwardTask);\n textOut = _textOut;\n }\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n const realtimeAudio = await this.agent.realtimeAudioOutputNode(\n msg.audioStream,\n modelSettings,\n );\n if (realtimeAudio) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n realtimeAudio,\n audioOutput,\n abortController,\n );\n forwardTasks.push(forwardTask);\n audioOut = _audioOut;\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n this.logger.warn(\n 'audio output is enabled but neither tts nor realtime audio is available',\n );\n }\n } else if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n outputs.push([msg.messageId, textOut, audioOut]);\n }\n await waitFor(forwardTasks);\n } catch (error) {\n this.logger.error(error, 'error reading messages from the realtime API');\n } finally {\n await cancelAndWait(forwardTasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n }\n };\n\n const messageOutputs: Array<[string, _TextOut | null, _AudioOut | null]> = [];\n const tasks = [\n Task.from(\n (controller) => readMessages(controller, messageOutputs),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_messages',\n ),\n ];\n\n const [toolCallStream, toolCallStreamForTracing] = ev.functionStream.tee();\n // TODO(brian): append to tracing tees\n const toolCalls: FunctionCall[] = [];\n\n const readToolStreamTask = async (\n controller: AbortController,\n stream: ReadableStream<FunctionCall>,\n ) => {\n const reader = stream.getReader();\n try {\n while (!controller.signal.aborted) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.logger.debug({ tool_call: value }, 'received tool call from the realtime API');\n toolCalls.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n };\n\n tasks.push(\n Task.from(\n (controller) => readToolStreamTask(controller, toolCallStreamForTracing),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_tool_stream',\n ),\n );\n\n const onToolExecutionStarted = (f: FunctionCall) => {\n speechHandle._itemAdded([f]);\n };\n\n const onToolExecutionCompleted = (out: ToolExecutionOutput) => {\n if (out.toolCallOutput) {\n speechHandle._itemAdded([out.toolCallOutput]);\n }\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolCallStream,\n toolChoice: modelSettings.toolChoice,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n // TODO(brian): add tracing span\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n this.agentSession._updateAgentState('listening');\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all realtime generation tasks due to interruption',\n );\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, audioOut] = messageOutputs[0]!;\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n let playbackPosition = playbackEv.playbackPosition;\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n playbackPosition = 0;\n }\n\n // truncate server-side message\n this.realtimeSession.truncate({\n messageId: msgId,\n audioEndMs: Math.floor(playbackPosition),\n });\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: msgId,\n interrupted: true,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message);\n\n // TODO(brian): add tracing span\n }\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n }\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n // TODO(brian): close tees\n return;\n }\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, _] = messageOutputs[0]!;\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n id: msgId,\n interrupted: false,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message); // mark the playout done before waiting for the tool execution\\\n // TODO(brian): add tracing span\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n // TODO(brian): close tees\n\n toolOutput.firstToolStartedFuture.await.finally(() => {\n this.agentSession._updateAgentState('thinking');\n });\n\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent ouput should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n const chatCtx = this.realtimeSession.chatCtx.copy();\n chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);\n try {\n await this.realtimeSession.updateChatCtx(chatCtx);\n } catch (error) {\n this.logger.warn(\n { error },\n 'failed to update chat context before generating the function calls results',\n );\n }\n }\n\n // skip realtime reply if not required or auto-generated\n if (!shouldGenerateToolReply || this.llm.capabilities.autoToolReplyGeneration) {\n return;\n }\n\n this.realtimeSession.interrupt();\n\n const replySpeechHandle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle.numSteps + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: replySpeechHandle,\n }),\n );\n\n const toolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: replySpeechHandle,\n modelSettings: { toolChoice },\n abortController,\n }),\n ),\n ownedSpeechHandle: replySpeechHandle,\n name: 'AgentActivity.realtime_reply',\n });\n\n this.scheduleSpeech(replySpeechHandle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n }\n\n private async realtimeReplyTask({\n speechHandle,\n modelSettings: { toolChoice },\n userInput,\n instructions,\n abortController,\n }: {\n speechHandle: SpeechHandle;\n modelSettings: ModelSettings;\n abortController: AbortController;\n userInput?: string;\n instructions?: string;\n }): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not available');\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (userInput) {\n const chatCtx = this.realtimeSession.chatCtx.copy();\n const message = chatCtx.addMessage({\n role: 'user',\n content: userInput,\n });\n await this.realtimeSession.updateChatCtx(chatCtx);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n const originalToolChoice = this.toolChoice;\n if (toolChoice !== undefined) {\n this.realtimeSession.updateOptions({ toolChoice });\n }\n\n try {\n const generationEvent = await this.realtimeSession.generateReply(instructions);\n await this.realtimeGenerationTask(\n speechHandle,\n generationEvent,\n { toolChoice },\n abortController,\n );\n } finally {\n // reset toolChoice value\n if (toolChoice !== undefined && toolChoice !== originalToolChoice) {\n this.realtimeSession.updateOptions({ toolChoice: originalToolChoice });\n }\n }\n }\n\n private scheduleSpeech(\n speechHandle: SpeechHandle,\n priority: number,\n force: boolean = false,\n ): void {\n // when force=true, we allow tool responses to bypass draining\n // This allows for tool responses to be generated before the AgentActivity is finalized\n if (this.draining && !force) {\n throw new Error('cannot schedule new speech, the agent is draining');\n }\n\n // Monotonic time to avoid near 0 collisions\n this.speechQueue.push([priority, Number(process.hrtime.bigint()), speechHandle]);\n speechHandle._markScheduled();\n this.wakeupMainTask();\n }\n\n async drain(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (this._draining) return;\n\n this.createSpeechTask({\n task: Task.from(() => this.agent.onExit()),\n name: 'AgentActivity_onExit',\n });\n\n this.wakeupMainTask();\n this._draining = true;\n await this._mainTask?.result;\n } finally {\n unlock();\n }\n }\n\n async close(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (!this._draining) {\n this.logger.warn('task closing without draining');\n }\n\n // Unregister event handlers to prevent duplicate metrics\n if (this.llm instanceof LLM) {\n this.llm.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.realtimeSession) {\n this.realtimeSession.off('generation_created', this.onGenerationCreated);\n this.realtimeSession.off('input_speech_started', this.onInputSpeechStarted);\n this.realtimeSession.off('input_speech_stopped', this.onInputSpeechStopped);\n this.realtimeSession.off(\n 'input_audio_transcription_completed',\n this.onInputAudioTranscriptionCompleted,\n );\n this.realtimeSession.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.stt instanceof STT) {\n this.stt.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.tts instanceof TTS) {\n this.tts.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.vad instanceof VAD) {\n this.vad.off('metrics_collected', this.onMetricsCollected);\n }\n\n this.detachAudioInput();\n await this.realtimeSession?.close();\n await this.audioRecognition?.close();\n await this._mainTask?.cancelAndWait();\n } finally {\n unlock();\n }\n }\n}\n\nfunction toOaiToolChoice(toolChoice: ToolChoice | null): ToolChoice | undefined {\n // we convert null to undefined, which maps to the default provider tool choice value\n return toolChoice !== null ? toolChoice : undefined;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/agent_activity.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Mutex } from '@livekit/mutex';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { Heap } from 'heap-js';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { ReadableStream } from 'node:stream/web';\nimport { type ChatContext, ChatMessage } from '../llm/chat_context.js';\nimport {\n type ChatItem,\n type FunctionCall,\n type GenerationCreatedEvent,\n type InputSpeechStartedEvent,\n type InputSpeechStoppedEvent,\n type InputTranscriptionCompleted,\n LLM,\n RealtimeModel,\n type RealtimeModelError,\n type RealtimeSession,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.js';\nimport type { LLMError } from '../llm/llm.js';\nimport { log } from '../log.js';\nimport type {\n EOUMetrics,\n LLMMetrics,\n RealtimeModelMetrics,\n STTMetrics,\n TTSMetrics,\n VADMetrics,\n} from '../metrics/base.js';\nimport { DeferredReadableStream } from '../stream/deferred_stream.js';\nimport { STT, type STTError, type SpeechEvent } from '../stt/stt.js';\nimport { splitWords } from '../tokenize/basic/word.js';\nimport { TTS, type TTSError } from '../tts/tts.js';\nimport { Future, Task, cancelAndWait, waitFor } from '../utils.js';\nimport { VAD, type VADEvent } from '../vad.js';\nimport type { Agent, ModelSettings } from './agent.js';\nimport { StopResponse, asyncLocalStorage } from './agent.js';\nimport { type AgentSession, type TurnDetectionMode } from './agent_session.js';\nimport {\n AudioRecognition,\n type EndOfTurnInfo,\n type RecognitionHooks,\n type _TurnDetector,\n} from './audio_recognition.js';\nimport {\n AgentSessionEventTypes,\n createErrorEvent,\n createFunctionToolsExecutedEvent,\n createMetricsCollectedEvent,\n createSpeechCreatedEvent,\n createUserInputTranscribedEvent,\n} from './events.js';\nimport type { ToolExecutionOutput } from './generation.js';\nimport {\n type _AudioOut,\n type _TextOut,\n performAudioForwarding,\n performLLMInference,\n performTTSInference,\n performTextForwarding,\n performToolExecutions,\n removeInstructions,\n updateInstructions,\n} from './generation.js';\nimport { SpeechHandle } from './speech_handle.js';\n\n// equivalent to Python's contextvars\nconst speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();\n\nexport class AgentActivity implements RecognitionHooks {\n private static readonly REPLY_TASK_CANCEL_TIMEOUT = 5000;\n private started = false;\n private audioRecognition?: AudioRecognition;\n private realtimeSession?: RealtimeSession;\n private turnDetectionMode?: Exclude<TurnDetectionMode, _TurnDetector>;\n private logger = log();\n private _draining = false;\n private _currentSpeech?: SpeechHandle;\n private speechQueue: Heap<[number, number, SpeechHandle]>; // [priority, timestamp, speechHandle]\n private q_updated: Future;\n private speechTasks: Set<Task<void>> = new Set();\n private lock = new Mutex();\n private audioStream = new DeferredReadableStream<AudioFrame>();\n // default to null as None, which maps to the default provider tool choice value\n private toolChoice: ToolChoice | null = null;\n\n agent: Agent;\n agentSession: AgentSession;\n\n /** @internal */\n _mainTask?: Task<void>;\n _userTurnCompletedTask?: Promise<void>;\n\n constructor(agent: Agent, agentSession: AgentSession) {\n this.agent = agent;\n this.agentSession = agentSession;\n\n /**\n * Custom comparator to prioritize speech handles with higher priority\n * - Prefer higher priority\n * - Prefer earlier timestamp (so calling a sequence of generateReply() will execute in FIFO order)\n */\n this.speechQueue = new Heap<[number, number, SpeechHandle]>(([p1, t1, _], [p2, t2, __]) => {\n return p1 === p2 ? t1 - t2 : p2 - p1;\n });\n this.q_updated = new Future();\n\n this.turnDetectionMode =\n typeof this.turnDetection === 'string' ? this.turnDetection : undefined;\n\n if (this.turnDetectionMode === 'vad' && this.vad === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"vad\", but no VAD model is provided, ignoring the turnDdetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt' && this.stt === undefined) {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but no STT model is provided, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection && !this.allowInterruptions) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false, ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentSession instead',\n );\n }\n\n if (this.turnDetectionMode === 'realtime_llm' && !this.llm.capabilities.turnDetection) {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel or the server-side turn detection is not supported/enabled, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (this.turnDetectionMode === 'stt') {\n this.logger.warn(\n 'turnDetection is set to \"stt\", but the LLM is a RealtimeModel, ignoring the turnDetection setting',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n this.turnDetectionMode &&\n this.turnDetectionMode !== 'realtime_llm' &&\n this.llm.capabilities.turnDetection\n ) {\n this.logger.warn(\n `turnDetection is set to \"${this.turnDetectionMode}\", but the LLM is a RealtimeModel and server-side turn detection enabled, ignoring the turnDetection setting`,\n );\n this.turnDetectionMode = undefined;\n }\n\n // fallback to VAD if server side turn detection is disabled and VAD is available\n if (\n !this.llm.capabilities.turnDetection &&\n this.vad &&\n this.turnDetectionMode === undefined\n ) {\n this.turnDetectionMode = 'vad';\n }\n } else if (this.turnDetectionMode === 'realtime_llm') {\n this.logger.warn(\n 'turnDetection is set to \"realtime_llm\", but the LLM is not a RealtimeModel',\n );\n this.turnDetectionMode = undefined;\n }\n\n if (\n !this.vad &&\n this.stt &&\n this.llm instanceof LLM &&\n this.allowInterruptions &&\n this.turnDetectionMode === undefined\n ) {\n this.logger.warn(\n 'VAD is not set. Enabling VAD is recommended when using LLM and STT ' +\n 'for more responsive interruption handling.',\n );\n }\n }\n\n async start(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n this.agent._agentActivity = this;\n\n if (this.llm instanceof RealtimeModel) {\n this.realtimeSession = this.llm.session();\n this.realtimeSession.on('generation_created', (ev) => this.onGenerationCreated(ev));\n this.realtimeSession.on('input_speech_started', (ev) => this.onInputSpeechStarted(ev));\n this.realtimeSession.on('input_speech_stopped', (ev) => this.onInputSpeechStopped(ev));\n this.realtimeSession.on('input_audio_transcription_completed', (ev) =>\n this.onInputAudioTranscriptionCompleted(ev),\n );\n this.realtimeSession.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.realtimeSession.on('error', (ev) => this.onError(ev));\n\n removeInstructions(this.agent._chatCtx);\n try {\n await this.realtimeSession.updateInstructions(this.agent.instructions);\n } catch (error) {\n this.logger.error(error, 'failed to update the instructions');\n }\n\n try {\n await this.realtimeSession.updateChatCtx(this.agent.chatCtx);\n } catch (error) {\n this.logger.error(error, 'failed to update the chat context');\n }\n\n try {\n await this.realtimeSession.updateTools(this.tools);\n } catch (error) {\n this.logger.error(error, 'failed to update the tools');\n }\n } else if (this.llm instanceof LLM) {\n try {\n updateInstructions({\n chatCtx: this.agent._chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n } catch (error) {\n this.logger.error('failed to update the instructions', error);\n }\n }\n\n // metrics and error handling\n if (this.llm instanceof LLM) {\n this.llm.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.llm.on('error', (ev) => this.onError(ev));\n }\n\n if (this.stt instanceof STT) {\n this.stt.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.stt.on('error', (ev) => this.onError(ev));\n }\n\n if (this.tts instanceof TTS) {\n this.tts.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n this.tts.on('error', (ev) => this.onError(ev));\n }\n\n if (this.vad instanceof VAD) {\n this.vad.on('metrics_collected', (ev) => this.onMetricsCollected(ev));\n }\n\n this.audioRecognition = new AudioRecognition({\n recognitionHooks: this,\n // Disable stt node if stt is not provided\n stt: this.stt ? (...args) => this.agent.sttNode(...args) : undefined,\n vad: this.vad,\n turnDetector: typeof this.turnDetection === 'string' ? undefined : this.turnDetection,\n turnDetectionMode: this.turnDetectionMode,\n minEndpointingDelay: this.agentSession.options.minEndpointingDelay,\n maxEndpointingDelay: this.agentSession.options.maxEndpointingDelay,\n });\n this.audioRecognition.start();\n this.started = true;\n\n this._mainTask = Task.from(({ signal }) => this.mainTask(signal));\n this.createSpeechTask({\n task: Task.from(() => this.agent.onEnter()),\n name: 'AgentActivity_onEnter',\n });\n } finally {\n unlock();\n }\n }\n\n get currentSpeech(): SpeechHandle | undefined {\n return this._currentSpeech;\n }\n\n get vad(): VAD | undefined {\n return this.agent.vad || this.agentSession.vad;\n }\n\n get stt(): STT | undefined {\n return this.agent.stt || this.agentSession.stt;\n }\n\n get llm(): LLM | RealtimeModel | undefined {\n return this.agent.llm || this.agentSession.llm;\n }\n\n get tts(): TTS | undefined {\n return this.agent.tts || this.agentSession.tts;\n }\n\n get tools(): ToolContext {\n return this.agent.toolCtx;\n }\n\n get draining(): boolean {\n return this._draining;\n }\n\n get realtimeLLMSession(): RealtimeSession | undefined {\n return this.realtimeSession;\n }\n\n get allowInterruptions(): boolean {\n // TODO(AJS-51): Allow options to be defined in Agent class\n return this.agentSession.options.allowInterruptions;\n }\n\n get turnDetection(): TurnDetectionMode | undefined {\n // TODO(brian): prioritize using agent.turn_detection\n return this.agentSession.turnDetection;\n }\n\n get toolCtx(): ToolContext {\n return this.agent.toolCtx;\n }\n\n async updateChatCtx(chatCtx: ChatContext): Promise<void> {\n chatCtx = chatCtx.copy({ toolCtx: this.toolCtx });\n\n this.agent._chatCtx = chatCtx;\n\n if (this.realtimeSession) {\n removeInstructions(chatCtx);\n this.realtimeSession.updateChatCtx(chatCtx);\n } else {\n updateInstructions({\n chatCtx,\n instructions: this.agent.instructions,\n addIfMissing: true,\n });\n }\n }\n\n updateOptions({ toolChoice }: { toolChoice?: ToolChoice | null }): void {\n if (toolChoice !== undefined) {\n this.toolChoice = toolChoice;\n }\n\n if (this.realtimeSession) {\n this.realtimeSession.updateOptions({ toolChoice: this.toolChoice });\n }\n }\n\n attachAudioInput(audioStream: ReadableStream<AudioFrame>): void {\n if (this.audioStream.isSourceSet) {\n this.logger.debug('detaching existing audio input in agent activity');\n this.audioStream.detachSource();\n }\n\n /**\n * We need to add a deferred ReadableStream layer on top of the audioStream from the agent session.\n * The tee() operation should be applied to the deferred stream, not the original audioStream.\n * This is important because teeing the original stream directly makes it very difficult—if not\n * impossible—to implement stream unlock logic cleanly.\n */\n this.audioStream.setSource(audioStream);\n const [realtimeAudioStream, recognitionAudioStream] = this.audioStream.stream.tee();\n\n if (this.realtimeSession) {\n this.realtimeSession.setInputAudioStream(realtimeAudioStream);\n }\n\n if (this.audioRecognition) {\n this.audioRecognition.setInputAudioStream(recognitionAudioStream);\n }\n }\n\n detachAudioInput(): void {\n this.audioStream.detachSource();\n }\n\n commitUserTurn() {\n if (!this.audioRecognition) {\n throw new Error('AudioRecognition is not initialized');\n }\n\n // TODO(brian): add audio_detached flag\n const audioDetached = false;\n this.audioRecognition.commitUserTurn(audioDetached);\n }\n\n clearUserTurn() {\n this.audioRecognition?.clearUserTurn();\n this.realtimeSession?.clearAudio();\n }\n\n say(\n text: string | ReadableStream<string>,\n options?: {\n audio?: ReadableStream<AudioFrame>;\n allowInterruptions?: boolean;\n addToChatCtx?: boolean;\n },\n ): SpeechHandle {\n const {\n audio,\n allowInterruptions: defaultAllowInterruptions,\n addToChatCtx = true,\n } = options ?? {};\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n !audio &&\n !this.tts &&\n this.agentSession.output.audio &&\n this.agentSession.output.audioEnabled\n ) {\n throw new Error('trying to generate speech from text without a TTS model');\n }\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.say(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'say',\n speechHandle: handle,\n }),\n );\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.ttsTask(handle, text, addToChatCtx, {}, abortController, audio),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.say_tts',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n // -- Metrics and errors --\n\n private onMetricsCollected = (\n ev: STTMetrics | TTSMetrics | VADMetrics | LLMMetrics | RealtimeModelMetrics,\n ) => {\n const speechHandle = speechHandleStorage.getStore();\n if (speechHandle && (ev.type === 'llm_metrics' || ev.type === 'tts_metrics')) {\n ev.speechId = speechHandle.id;\n }\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: ev }),\n );\n };\n\n private onError(ev: RealtimeModelError | STTError | TTSError | LLMError): void {\n if (ev.type === 'realtime_model_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'stt_error') {\n const errorEvent = createErrorEvent(ev.error, this.stt);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'tts_error') {\n const errorEvent = createErrorEvent(ev.error, this.tts);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n } else if (ev.type === 'llm_error') {\n const errorEvent = createErrorEvent(ev.error, this.llm);\n this.agentSession.emit(AgentSessionEventTypes.Error, errorEvent);\n }\n\n this.agentSession._onError(ev);\n }\n\n // -- Realtime Session events --\n\n onInputSpeechStarted(_ev: InputSpeechStartedEvent): void {\n this.logger.info('onInputSpeechStarted');\n\n if (!this.vad) {\n this.agentSession._updateUserState('speaking');\n }\n\n // this.interrupt() is going to raise when allow_interruptions is False,\n // llm.InputSpeechStartedEvent is only fired by the server when the turn_detection is enabled.\n try {\n this.interrupt();\n } catch (error) {\n this.logger.error(\n 'RealtimeAPI input_speech_started, but current speech is not interruptable, this should never happen!',\n error,\n );\n }\n }\n\n onInputSpeechStopped(ev: InputSpeechStoppedEvent): void {\n this.logger.info(ev, 'onInputSpeechStopped');\n\n if (!this.vad) {\n this.agentSession._updateUserState('listening');\n }\n\n if (ev.userTranscriptionEnabled) {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n isFinal: false,\n transcript: '',\n }),\n );\n }\n }\n\n onInputAudioTranscriptionCompleted(ev: InputTranscriptionCompleted): void {\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.transcript,\n isFinal: ev.isFinal,\n }),\n );\n\n if (ev.isFinal) {\n const message = ChatMessage.create({\n role: 'user',\n content: ev.transcript,\n id: ev.itemId,\n });\n this.agent._chatCtx.items.push(message);\n this.agentSession._conversationItemAdded(message);\n }\n }\n\n onGenerationCreated(ev: GenerationCreatedEvent): void {\n if (ev.userInitiated) {\n // user initiated generations are directly handled inside _realtime_reply_task\n return;\n }\n\n if (this.draining) {\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent?\n this.logger.warn('skipping new realtime generation, the agent is draining');\n return;\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: this.allowInterruptions,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeGenerationTask(handle, ev, {}, abortController),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeGeneration',\n });\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n }\n\n // recognition hooks\n\n onStartOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('speaking');\n }\n\n onEndOfSpeech(_ev: VADEvent): void {\n this.agentSession._updateUserState('listening');\n }\n\n onVADInferenceDone(ev: VADEvent): void {\n if (this.turnDetection === 'manual' || this.turnDetection === 'realtime_llm') {\n // skip speech handle interruption for manual and realtime model\n return;\n }\n\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.turnDetection) {\n // skip speech handle interruption if server side turn detection is enabled\n return;\n }\n\n if (ev.speechDuration < this.agentSession.options.minInterruptionDuration) {\n return;\n }\n\n if (this.stt && this.agentSession.options.minInterruptionWords > 0 && this.audioRecognition) {\n const text = this.audioRecognition.currentTranscript;\n\n // TODO(shubhra): better word splitting for multi-language\n if (text && splitWords(text, true).length < this.agentSession.options.minInterruptionWords) {\n return;\n }\n }\n\n this.realtimeSession?.startUserActivity();\n\n if (\n this._currentSpeech &&\n !this._currentSpeech.interrupted &&\n this._currentSpeech.allowInterruptions\n ) {\n this.logger.info({ 'speech id': this._currentSpeech.id }, 'speech interrupted by VAD');\n this.realtimeSession?.interrupt();\n this._currentSpeech.interrupt();\n }\n }\n\n onInterimTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: false,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n onFinalTranscript(ev: SpeechEvent): void {\n if (this.llm instanceof RealtimeModel && this.llm.capabilities.userTranscription) {\n // skip stt transcription if userTranscription is enabled on the realtime model\n return;\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.UserInputTranscribed,\n createUserInputTranscribedEvent({\n transcript: ev.alternatives![0].text,\n isFinal: true,\n language: ev.alternatives![0].language,\n // TODO(AJS-106): add multi participant support\n }),\n );\n }\n\n private createSpeechTask(options: {\n task: Task<void>;\n ownedSpeechHandle?: SpeechHandle;\n name?: string;\n }): Promise<void> {\n const { task, ownedSpeechHandle } = options;\n\n this.speechTasks.add(task);\n task.addDoneCallback(() => {\n this.speechTasks.delete(task);\n });\n\n if (ownedSpeechHandle) {\n ownedSpeechHandle._tasks.push(task);\n task.addDoneCallback(() => {\n if (ownedSpeechHandle._tasks.every((t) => t.done)) {\n ownedSpeechHandle._markDone();\n }\n });\n }\n\n task.addDoneCallback(() => {\n this.wakeupMainTask();\n });\n\n return task.result;\n }\n\n async onEndOfTurn(info: EndOfTurnInfo): Promise<boolean> {\n if (this.draining) {\n this.logger.warn({ user_input: info.newTranscript }, 'skipping user input, task is draining');\n // copied from python:\n // TODO(shubhra): should we \"forward\" this new turn to the next agent/activity?\n return true;\n }\n\n if (\n this.stt &&\n this.turnDetection !== 'manual' &&\n this._currentSpeech &&\n this._currentSpeech.allowInterruptions &&\n !this._currentSpeech.interrupted &&\n this.agentSession.options.minInterruptionWords > 0 &&\n info.newTranscript.split(' ').length < this.agentSession.options.minInterruptionWords\n ) {\n // avoid interruption if the new_transcript is too short\n this.logger.info('skipping user input, new_transcript is too short');\n return false;\n }\n\n const oldTask = this._userTurnCompletedTask;\n this._userTurnCompletedTask = this.createSpeechTask({\n task: Task.from(() => this.userTurnCompleted(info, oldTask)),\n name: 'AgentActivity.userTurnCompleted',\n });\n return true;\n }\n\n retrieveChatCtx(): ChatContext {\n return this.agentSession.chatCtx;\n }\n\n private async mainTask(signal: AbortSignal): Promise<void> {\n const abortFuture = new Future();\n const abortHandler = () => {\n abortFuture.resolve();\n signal.removeEventListener('abort', abortHandler);\n };\n signal.addEventListener('abort', abortHandler);\n\n while (true) {\n await Promise.race([this.q_updated.await, abortFuture.await]);\n if (signal.aborted) break;\n\n while (this.speechQueue.size() > 0) {\n if (signal.aborted) break;\n\n const heapItem = this.speechQueue.pop();\n if (!heapItem) {\n throw new Error('Speech queue is empty');\n }\n const speechHandle = heapItem[2];\n this._currentSpeech = speechHandle;\n speechHandle._authorizeGeneration();\n await speechHandle._waitForGeneration();\n this._currentSpeech = undefined;\n }\n\n // If we're draining and there are no more speech tasks, we can exit.\n // Only speech tasks can bypass draining to create a tool response\n if (this.draining && this.speechTasks.size === 0) {\n this.logger.info('mainTask: draining and no more speech tasks');\n break;\n }\n\n this.q_updated = new Future();\n }\n\n this.logger.info('AgentActivity mainTask: exiting');\n }\n\n private wakeupMainTask(): void {\n this.q_updated.resolve();\n }\n\n generateReply(options: {\n userMessage?: ChatMessage;\n chatCtx?: ChatContext;\n instructions?: string;\n toolChoice?: ToolChoice | null;\n allowInterruptions?: boolean;\n }): SpeechHandle {\n const {\n userMessage,\n chatCtx,\n instructions: defaultInstructions,\n toolChoice: defaultToolChoice,\n allowInterruptions: defaultAllowInterruptions,\n } = options;\n\n let instructions = defaultInstructions;\n let toolChoice = defaultToolChoice;\n let allowInterruptions = defaultAllowInterruptions;\n\n if (\n this.llm instanceof RealtimeModel &&\n this.llm.capabilities.turnDetection &&\n allowInterruptions === false\n ) {\n this.logger.warn(\n 'the RealtimeModel uses a server-side turn detection, allowInterruptions cannot be false when using VoiceAgent.generateReply(), ' +\n 'disable turnDetection in the RealtimeModel and use VAD on the AgentTask/VoiceAgent instead',\n );\n allowInterruptions = true;\n }\n\n if (this.llm === undefined) {\n throw new Error('trying to generate reply without an LLM model');\n }\n\n const functionCall = asyncLocalStorage.getStore()?.functionCall;\n if (toolChoice === undefined && functionCall !== undefined) {\n // when generateReply is called inside a tool, set toolChoice to 'none' by default\n toolChoice = 'none';\n }\n\n const handle = SpeechHandle.create({\n allowInterruptions: allowInterruptions ?? this.allowInterruptions,\n });\n\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: true,\n source: 'generate_reply',\n speechHandle: handle,\n }),\n );\n this.logger.info({ speech_id: handle.id }, 'Creating speech handle');\n\n if (this.llm instanceof RealtimeModel) {\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: handle,\n // TODO(brian): support llm.ChatMessage for the realtime model\n userInput: userMessage?.textContent,\n instructions,\n modelSettings: {\n // isGiven(toolChoice) = toolChoice !== undefined\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n }),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.realtimeReply',\n });\n } else if (this.llm instanceof LLM) {\n // instructions used inside generateReply are \"extra\" instructions.\n // this matches the behavior of the Realtime API:\n // https://platform.openai.com/docs/api-reference/realtime-client-events/response/create\n if (instructions) {\n instructions = `${this.agent.instructions}\\n${instructions}`;\n }\n\n const task = this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.pipelineReplyTask(\n handle,\n chatCtx ?? this.agent.chatCtx,\n this.agent.toolCtx,\n {\n toolChoice: toOaiToolChoice(toolChoice !== undefined ? toolChoice : this.toolChoice),\n },\n abortController,\n instructions ? `${this.agent.instructions}\\n${instructions}` : instructions,\n userMessage,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n task.finally(() => this.onPipelineReplyDone());\n }\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL);\n return handle;\n }\n\n interrupt(): Future<void> {\n const future = new Future<void>();\n const currentSpeech = this._currentSpeech;\n\n //TODO(AJS-273): add interrupt for background speeches\n\n currentSpeech?.interrupt();\n\n for (const [_, __, speech] of this.speechQueue) {\n speech.interrupt();\n }\n\n this.realtimeSession?.interrupt();\n\n if (currentSpeech === undefined) {\n future.resolve();\n } else {\n currentSpeech.addDoneCallback(() => {\n if (future.done) return;\n future.resolve();\n });\n }\n\n return future;\n }\n\n private onPipelineReplyDone(): void {\n if (!this.speechQueue.peek() && (!this._currentSpeech || this._currentSpeech.done())) {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async userTurnCompleted(info: EndOfTurnInfo, oldTask?: Promise<void>): Promise<void> {\n if (oldTask) {\n // We never cancel user code as this is very confusing.\n // So we wait for the old execution of onUserTurnCompleted to finish.\n // In practice this is OK because most speeches will be interrupted if a new turn\n // is detected. So the previous execution should complete quickly.\n await oldTask;\n }\n\n // When the audio recognition detects the end of a user turn:\n // - check if realtime model server-side turn detection is enabled\n // - check if there is no current generation happening\n // - cancel the current generation if it allows interruptions (otherwise skip this current\n // turn)\n // - generate a reply to the user input\n\n if (this.llm instanceof RealtimeModel) {\n if (this.llm.capabilities.turnDetection) {\n return;\n }\n this.realtimeSession?.commitAudio();\n }\n\n if (this._currentSpeech) {\n if (!this._currentSpeech.allowInterruptions) {\n this.logger.warn(\n { user_input: info.newTranscript },\n 'skipping user input, current speech generation cannot be interrupted',\n );\n return;\n }\n\n this.logger.info(\n { 'speech id': this._currentSpeech.id },\n 'speech interrupted, new user turn detected',\n );\n\n this._currentSpeech.interrupt();\n this.realtimeSession?.interrupt();\n }\n\n let userMessage: ChatMessage | undefined = ChatMessage.create({\n role: 'user',\n content: info.newTranscript,\n });\n\n // create a temporary mutable chat context to pass to onUserTurnCompleted\n // the user can edit it for the current generation, but changes will not be kept inside the\n // Agent.chatCtx\n const chatCtx = this.agent.chatCtx.copy();\n const startTime = Date.now();\n\n try {\n await this.agent.onUserTurnCompleted(chatCtx, userMessage);\n } catch (e) {\n if (e instanceof StopResponse) {\n return;\n }\n this.logger.error({ error: e }, 'error occurred during onUserTurnCompleted');\n }\n\n const callbackDuration = Date.now() - startTime;\n\n if (this.llm instanceof RealtimeModel) {\n // ignore stt transcription for realtime model\n userMessage = undefined;\n } else if (this.llm === undefined) {\n return;\n }\n\n // Ensure the new message is passed to generateReply\n // This preserves the original message id, making it easier for users to track responses\n const speechHandle = this.generateReply({ userMessage, chatCtx });\n\n const eouMetrics: EOUMetrics = {\n type: 'eou_metrics',\n timestamp: Date.now(),\n endOfUtteranceDelay: info.endOfUtteranceDelay,\n transcriptionDelay: info.transcriptionDelay,\n onUserTurnCompletedDelay: callbackDuration,\n speechId: speechHandle.id,\n };\n\n this.agentSession.emit(\n AgentSessionEventTypes.MetricsCollected,\n createMetricsCollectedEvent({ metrics: eouMetrics }),\n );\n }\n\n private async ttsTask(\n speechHandle: SpeechHandle,\n text: string | ReadableStream<string>,\n addToChatCtx: boolean,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n audio?: ReadableStream<AudioFrame> | null,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (speechHandle.interrupted) {\n return;\n }\n\n let baseStream: ReadableStream<string>;\n if (text instanceof ReadableStream) {\n baseStream = text;\n } else {\n baseStream = new ReadableStream({\n start(controller) {\n controller.enqueue(text);\n controller.close();\n },\n });\n }\n\n const [textSource, audioSource] = baseStream.tee();\n\n const tasks: Array<Task<void>> = [];\n\n const trNode = await this.agent.transcriptionNode(textSource, {});\n let textOut: _TextOut | null = null;\n if (trNode) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNode,\n replyAbortController,\n transcriptionOutput,\n );\n textOut = _textOut;\n tasks.push(textForwardTask);\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n if (!audioOutput) {\n if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n } else {\n let audioOut: _AudioOut | null = null;\n if (!audio) {\n // generate audio using TTS\n const [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n audioSource,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n } else {\n // use the provided audio\n const [forwardTask, _audioOut] = performAudioForwarding(\n audio,\n audioOutput,\n replyAbortController,\n );\n tasks.push(forwardTask);\n audioOut = _audioOut;\n }\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n }\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n if (audioOutput) {\n audioOutput.clearBuffer();\n await audioOutput.waitForPlayout();\n }\n }\n\n if (addToChatCtx) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n interrupted: speechHandle.interrupted,\n });\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n }\n\n private async pipelineReplyTask(\n speechHandle: SpeechHandle,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n instructions?: string,\n newMessage?: ChatMessage,\n toolsMessages?: ChatItem[],\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const transcriptionOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n\n chatCtx = chatCtx.copy();\n\n if (newMessage) {\n chatCtx.insert(newMessage);\n this.agent._chatCtx.insert(newMessage);\n this.agentSession._conversationItemAdded(newMessage);\n }\n\n if (instructions) {\n try {\n updateInstructions({\n chatCtx,\n instructions,\n addIfMissing: true,\n });\n } catch (e) {\n this.logger.error({ error: e }, 'error occurred during updateInstructions');\n }\n }\n\n this.agentSession._updateAgentState('thinking');\n const tasks: Array<Task<void>> = [];\n const [llmTask, llmGenData] = performLLMInference(\n // preserve `this` context in llmNode\n (...args) => this.agent.llmNode(...args),\n chatCtx,\n toolCtx,\n modelSettings,\n replyAbortController,\n );\n tasks.push(llmTask);\n\n const [ttsTextInput, llmOutput] = llmGenData.textStream.tee();\n\n let ttsTask: Task<void> | null = null;\n let ttsStream: ReadableStream<AudioFrame> | null = null;\n if (audioOutput) {\n [ttsTask, ttsStream] = performTTSInference(\n (...args) => this.agent.ttsNode(...args),\n ttsTextInput,\n modelSettings,\n replyAbortController,\n );\n tasks.push(ttsTask);\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForScheduled()]);\n\n if (speechHandle.interrupted) {\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n this.agentSession._updateAgentState('thinking');\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n const replyStartedAt = Date.now();\n const trNodeResult = await this.agent.transcriptionNode(llmOutput, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n replyAbortController,\n transcriptionOutput,\n );\n tasks.push(textForwardTask);\n textOut = _textOut;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n if (ttsStream) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n ttsStream,\n audioOutput,\n replyAbortController,\n );\n audioOut = _audioOut;\n tasks.push(forwardTask);\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n throw Error('ttsStream is null when audioOutput is enabled');\n }\n } else {\n textOut?.firstTextFut.await.finally(onFirstFrame);\n }\n\n //TODO(AJS-272): before executing tools, make sure we generated all the text\n // (this ensure everything is kept ordered)\n\n const onToolExecutionStarted = (_: FunctionCall) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const onToolExecutionCompleted = (_: ToolExecutionOutput) => {\n // TODO(brian): handle speech_handle item_added\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolChoice: modelSettings.toolChoice,\n toolCallStream: llmGenData.toolCallStream,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n }\n\n // add the tools messages that triggers this reply to the chat context\n if (toolsMessages) {\n for (const msg of toolsMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolsMessages);\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all pipeline reply tasks due to interruption',\n );\n replyAbortController.abort();\n await Promise.allSettled(\n tasks.map((task) => task.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT)),\n );\n\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n }\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: llmGenData.id,\n interrupted: true,\n createdAt: replyStartedAt,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n // TODO(shubhra) add chat message to speech handle\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n return;\n }\n\n if (textOut && textOut.text) {\n const message = ChatMessage.create({\n role: 'assistant',\n id: llmGenData.id,\n interrupted: false,\n createdAt: replyStartedAt,\n content: textOut.text,\n });\n chatCtx.insert(message);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n this.logger.info(\n { speech_id: speechHandle.id, message: textOut.text },\n 'playout completed without interruption',\n );\n }\n\n if (toolOutput.output.length > 0) {\n this.agentSession._updateAgentState('thinking');\n } else if (this.agentSession.agentState === 'speaking') {\n this.agentSession._updateAgentState('listening');\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent output should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCalls.push(sanitizedOut.toolCall);\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n // TODO(brian): should we mark the function call as failed to notify the LLM?\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n const toolMessages = [\n ...functionToolsExecutedEvent.functionCalls,\n ...functionToolsExecutedEvent.functionCallOutputs,\n ] as ChatItem[];\n if (shouldGenerateToolReply) {\n chatCtx.insert(toolMessages);\n\n const handle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle._stepIndex + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: handle,\n }),\n );\n\n // Avoid setting tool_choice to \"required\" or a specific function when\n // passing tool response back to the LLM\n const respondToolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n\n const toolResponseTask = this.createSpeechTask({\n task: Task.from(() =>\n this.pipelineReplyTask(\n handle,\n chatCtx,\n toolCtx,\n { toolChoice: respondToolChoice },\n replyAbortController,\n instructions,\n undefined,\n toolMessages,\n ),\n ),\n ownedSpeechHandle: handle,\n name: 'AgentActivity.pipelineReply',\n });\n\n toolResponseTask.finally(() => this.onPipelineReplyDone());\n\n this.scheduleSpeech(handle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n } else if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n for (const msg of toolMessages) {\n msg.createdAt = replyStartedAt;\n }\n this.agent._chatCtx.insert(toolMessages);\n }\n }\n\n private async realtimeGenerationTask(\n speechHandle: SpeechHandle,\n ev: GenerationCreatedEvent,\n modelSettings: ModelSettings,\n replyAbortController: AbortController,\n ): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not initialized');\n }\n if (!(this.llm instanceof RealtimeModel)) {\n throw new Error('llm is not a realtime model');\n }\n\n this.logger.debug(\n { speech_id: speechHandle.id, stepIndex: speechHandle.numSteps },\n 'realtime generation started',\n );\n\n const audioOutput = this.agentSession.output.audioEnabled\n ? this.agentSession.output.audio\n : null;\n const textOutput = this.agentSession.output.transcriptionEnabled\n ? this.agentSession.output.transcription\n : null;\n const toolCtx = this.realtimeSession.tools;\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n speechHandle._clearAuthorization();\n\n if (speechHandle.interrupted) {\n return;\n }\n\n const onFirstFrame = () => {\n this.agentSession._updateAgentState('speaking');\n };\n\n const readMessages = async (\n abortController: AbortController,\n outputs: Array<[string, _TextOut | null, _AudioOut | null]>,\n ) => {\n const forwardTasks: Array<Task<void>> = [];\n try {\n for await (const msg of ev.messageStream) {\n if (forwardTasks.length > 0) {\n this.logger.warn(\n 'expected to receive only one message generation from the realtime API',\n );\n break;\n }\n const trNodeResult = await this.agent.transcriptionNode(msg.textStream, modelSettings);\n let textOut: _TextOut | null = null;\n if (trNodeResult) {\n const [textForwardTask, _textOut] = performTextForwarding(\n trNodeResult,\n abortController,\n textOutput,\n );\n forwardTasks.push(textForwardTask);\n textOut = _textOut;\n }\n let audioOut: _AudioOut | null = null;\n if (audioOutput) {\n const realtimeAudio = await this.agent.realtimeAudioOutputNode(\n msg.audioStream,\n modelSettings,\n );\n if (realtimeAudio) {\n const [forwardTask, _audioOut] = performAudioForwarding(\n realtimeAudio,\n audioOutput,\n abortController,\n );\n forwardTasks.push(forwardTask);\n audioOut = _audioOut;\n audioOut.firstFrameFut.await.finally(onFirstFrame);\n } else {\n this.logger.warn(\n 'audio output is enabled but neither tts nor realtime audio is available',\n );\n }\n } else if (textOut) {\n textOut.firstTextFut.await.finally(onFirstFrame);\n }\n outputs.push([msg.messageId, textOut, audioOut]);\n }\n await waitFor(forwardTasks);\n } catch (error) {\n this.logger.error(error, 'error reading messages from the realtime API');\n } finally {\n await cancelAndWait(forwardTasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n }\n };\n\n const messageOutputs: Array<[string, _TextOut | null, _AudioOut | null]> = [];\n const tasks = [\n Task.from(\n (controller) => readMessages(controller, messageOutputs),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_messages',\n ),\n ];\n\n const [toolCallStream, toolCallStreamForTracing] = ev.functionStream.tee();\n // TODO(brian): append to tracing tees\n const toolCalls: FunctionCall[] = [];\n\n const readToolStreamTask = async (\n controller: AbortController,\n stream: ReadableStream<FunctionCall>,\n ) => {\n const reader = stream.getReader();\n try {\n while (!controller.signal.aborted) {\n const { done, value } = await reader.read();\n if (done) break;\n\n this.logger.debug({ tool_call: value }, 'received tool call from the realtime API');\n toolCalls.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n };\n\n tasks.push(\n Task.from(\n (controller) => readToolStreamTask(controller, toolCallStreamForTracing),\n replyAbortController,\n 'AgentActivity.realtime_generation.read_tool_stream',\n ),\n );\n\n const onToolExecutionStarted = (f: FunctionCall) => {\n speechHandle._itemAdded([f]);\n };\n\n const onToolExecutionCompleted = (out: ToolExecutionOutput) => {\n if (out.toolCallOutput) {\n speechHandle._itemAdded([out.toolCallOutput]);\n }\n };\n\n const [executeToolsTask, toolOutput] = performToolExecutions({\n session: this.agentSession,\n speechHandle,\n toolCtx,\n toolCallStream,\n toolChoice: modelSettings.toolChoice,\n controller: replyAbortController,\n onToolExecutionStarted,\n onToolExecutionCompleted,\n });\n\n await speechHandle.waitIfNotInterrupted(tasks.map((task) => task.result));\n\n // TODO(brian): add tracing span\n\n if (audioOutput) {\n await speechHandle.waitIfNotInterrupted([audioOutput.waitForPlayout()]);\n this.agentSession._updateAgentState('listening');\n }\n\n if (speechHandle.interrupted) {\n this.logger.debug(\n { speech_id: speechHandle.id },\n 'Aborting all realtime generation tasks due to interruption',\n );\n replyAbortController.abort();\n await cancelAndWait(tasks, AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, audioOut] = messageOutputs[0]!;\n let forwardedText = textOut?.text || '';\n\n if (audioOutput) {\n audioOutput.clearBuffer();\n const playbackEv = await audioOutput.waitForPlayout();\n let playbackPosition = playbackEv.playbackPosition;\n if (audioOut?.firstFrameFut.done) {\n // playback EV is valid only if the first frame was already played\n this.logger.info(\n { speech_id: speechHandle.id, playbackPosition: playbackEv.playbackPosition },\n 'playout interrupted',\n );\n if (playbackEv.synchronizedTranscript) {\n forwardedText = playbackEv.synchronizedTranscript;\n }\n } else {\n forwardedText = '';\n playbackPosition = 0;\n }\n\n // truncate server-side message\n this.realtimeSession.truncate({\n messageId: msgId,\n audioEndMs: Math.floor(playbackPosition),\n });\n }\n\n if (forwardedText) {\n const message = ChatMessage.create({\n role: 'assistant',\n content: forwardedText,\n id: msgId,\n interrupted: true,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message);\n\n // TODO(brian): add tracing span\n }\n this.logger.info(\n { speech_id: speechHandle.id, message: forwardedText },\n 'playout completed with interrupt',\n );\n }\n speechHandle._markGenerationDone();\n await executeToolsTask.cancelAndWait(AgentActivity.REPLY_TASK_CANCEL_TIMEOUT);\n\n // TODO(brian): close tees\n return;\n }\n\n if (messageOutputs.length > 0) {\n // there should be only one message\n const [msgId, textOut, _] = messageOutputs[0]!;\n const message = ChatMessage.create({\n role: 'assistant',\n content: textOut?.text || '',\n id: msgId,\n interrupted: false,\n });\n this.agent._chatCtx.insert(message);\n speechHandle._itemAdded([message]);\n this.agentSession._conversationItemAdded(message); // mark the playout done before waiting for the tool execution\\\n // TODO(brian): add tracing span\n }\n\n // mark the playout done before waiting for the tool execution\n speechHandle._markGenerationDone();\n // TODO(brian): close tees\n\n toolOutput.firstToolStartedFuture.await.finally(() => {\n this.agentSession._updateAgentState('thinking');\n });\n\n await executeToolsTask.result;\n\n if (toolOutput.output.length === 0) return;\n\n // important: no agent ouput should be used after this point\n const { maxToolSteps } = this.agentSession.options;\n if (speechHandle.numSteps >= maxToolSteps) {\n this.logger.warn(\n { speech_id: speechHandle.id, max_tool_steps: maxToolSteps },\n 'maximum number of function calls steps reached',\n );\n return;\n }\n\n const functionToolsExecutedEvent = createFunctionToolsExecutedEvent({\n functionCalls: [],\n functionCallOutputs: [],\n });\n let shouldGenerateToolReply: boolean = false;\n let newAgentTask: Agent | null = null;\n let ignoreTaskSwitch: boolean = false;\n\n for (const sanitizedOut of toolOutput.output) {\n if (sanitizedOut.toolCallOutput !== undefined) {\n functionToolsExecutedEvent.functionCallOutputs.push(sanitizedOut.toolCallOutput);\n if (sanitizedOut.replyRequired) {\n shouldGenerateToolReply = true;\n }\n }\n\n if (newAgentTask !== null && sanitizedOut.agentTask !== undefined) {\n this.logger.error('expected to receive only one agent task from the tool executions');\n ignoreTaskSwitch = true;\n }\n\n newAgentTask = sanitizedOut.agentTask ?? null;\n\n this.logger.debug(\n {\n speechId: speechHandle.id,\n name: sanitizedOut.toolCall?.name,\n args: sanitizedOut.toolCall.args,\n output: sanitizedOut.toolCallOutput?.output,\n isError: sanitizedOut.toolCallOutput?.isError,\n },\n 'Tool call execution finished',\n );\n }\n\n this.agentSession.emit(\n AgentSessionEventTypes.FunctionToolsExecuted,\n functionToolsExecutedEvent,\n );\n\n let draining = this.draining;\n if (!ignoreTaskSwitch && newAgentTask !== null) {\n this.agentSession.updateAgent(newAgentTask);\n draining = true;\n }\n\n if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {\n // wait all speeches played before updating the tool output and generating the response\n // most realtime models dont support generating multiple responses at the same time\n while (this.currentSpeech || this.speechQueue.size() > 0) {\n if (\n this.currentSpeech &&\n !this.currentSpeech.done() &&\n this.currentSpeech !== speechHandle\n ) {\n await this.currentSpeech.waitForPlayout();\n } else {\n // Don't block the event loop\n await new Promise((resolve) => setImmediate(resolve));\n }\n }\n const chatCtx = this.realtimeSession.chatCtx.copy();\n chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);\n try {\n await this.realtimeSession.updateChatCtx(chatCtx);\n } catch (error) {\n this.logger.warn(\n { error },\n 'failed to update chat context before generating the function calls results',\n );\n }\n }\n\n // skip realtime reply if not required or auto-generated\n if (!shouldGenerateToolReply || this.llm.capabilities.autoToolReplyGeneration) {\n return;\n }\n\n this.realtimeSession.interrupt();\n\n const replySpeechHandle = SpeechHandle.create({\n allowInterruptions: speechHandle.allowInterruptions,\n stepIndex: speechHandle.numSteps + 1,\n parent: speechHandle,\n });\n this.agentSession.emit(\n AgentSessionEventTypes.SpeechCreated,\n createSpeechCreatedEvent({\n userInitiated: false,\n source: 'tool_response',\n speechHandle: replySpeechHandle,\n }),\n );\n\n const toolChoice = draining || modelSettings.toolChoice === 'none' ? 'none' : 'auto';\n this.createSpeechTask({\n task: Task.from((abortController: AbortController) =>\n this.realtimeReplyTask({\n speechHandle: replySpeechHandle,\n modelSettings: { toolChoice },\n abortController,\n }),\n ),\n ownedSpeechHandle: replySpeechHandle,\n name: 'AgentActivity.realtime_reply',\n });\n\n this.scheduleSpeech(replySpeechHandle, SpeechHandle.SPEECH_PRIORITY_NORMAL, true);\n }\n\n private async realtimeReplyTask({\n speechHandle,\n modelSettings: { toolChoice },\n userInput,\n instructions,\n abortController,\n }: {\n speechHandle: SpeechHandle;\n modelSettings: ModelSettings;\n abortController: AbortController;\n userInput?: string;\n instructions?: string;\n }): Promise<void> {\n speechHandleStorage.enterWith(speechHandle);\n\n if (!this.realtimeSession) {\n throw new Error('realtime session is not available');\n }\n\n await speechHandle.waitIfNotInterrupted([speechHandle._waitForAuthorization()]);\n\n if (userInput) {\n const chatCtx = this.realtimeSession.chatCtx.copy();\n const message = chatCtx.addMessage({\n role: 'user',\n content: userInput,\n });\n await this.realtimeSession.updateChatCtx(chatCtx);\n this.agent._chatCtx.insert(message);\n this.agentSession._conversationItemAdded(message);\n }\n\n const originalToolChoice = this.toolChoice;\n if (toolChoice !== undefined) {\n this.realtimeSession.updateOptions({ toolChoice });\n }\n\n try {\n const generationEvent = await this.realtimeSession.generateReply(instructions);\n await this.realtimeGenerationTask(\n speechHandle,\n generationEvent,\n { toolChoice },\n abortController,\n );\n } finally {\n // reset toolChoice value\n if (toolChoice !== undefined && toolChoice !== originalToolChoice) {\n this.realtimeSession.updateOptions({ toolChoice: originalToolChoice });\n }\n }\n }\n\n private scheduleSpeech(\n speechHandle: SpeechHandle,\n priority: number,\n force: boolean = false,\n ): void {\n // when force=true, we allow tool responses to bypass draining\n // This allows for tool responses to be generated before the AgentActivity is finalized\n if (this.draining && !force) {\n throw new Error('cannot schedule new speech, the agent is draining');\n }\n\n // Monotonic time to avoid near 0 collisions\n this.speechQueue.push([priority, Number(process.hrtime.bigint()), speechHandle]);\n speechHandle._markScheduled();\n this.wakeupMainTask();\n }\n\n async drain(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (this._draining) return;\n\n this.createSpeechTask({\n task: Task.from(() => this.agent.onExit()),\n name: 'AgentActivity_onExit',\n });\n\n this.wakeupMainTask();\n this._draining = true;\n await this._mainTask?.result;\n } finally {\n unlock();\n }\n }\n\n async close(): Promise<void> {\n const unlock = await this.lock.lock();\n try {\n if (!this._draining) {\n this.logger.warn('task closing without draining');\n }\n\n // Unregister event handlers to prevent duplicate metrics\n if (this.llm instanceof LLM) {\n this.llm.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.realtimeSession) {\n this.realtimeSession.off('generation_created', this.onGenerationCreated);\n this.realtimeSession.off('input_speech_started', this.onInputSpeechStarted);\n this.realtimeSession.off('input_speech_stopped', this.onInputSpeechStopped);\n this.realtimeSession.off(\n 'input_audio_transcription_completed',\n this.onInputAudioTranscriptionCompleted,\n );\n this.realtimeSession.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.stt instanceof STT) {\n this.stt.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.tts instanceof TTS) {\n this.tts.off('metrics_collected', this.onMetricsCollected);\n }\n if (this.vad instanceof VAD) {\n this.vad.off('metrics_collected', this.onMetricsCollected);\n }\n\n this.detachAudioInput();\n await this.realtimeSession?.close();\n await this.audioRecognition?.close();\n await this._mainTask?.cancelAndWait();\n } finally {\n unlock();\n }\n }\n}\n\nfunction toOaiToolChoice(toolChoice: ToolChoice | null): ToolChoice | undefined {\n // we convert null to undefined, which maps to the default provider tool choice value\n return toolChoice !== null ? toolChoice : undefined;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -125,6 +125,7 @@ class SpeechHandle {
|
|
|
125
125
|
To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.`
|
|
126
126
|
);
|
|
127
127
|
}
|
|
128
|
+
await this.doneFut.await;
|
|
128
129
|
}
|
|
129
130
|
async waitIfNotInterrupted(aw) {
|
|
130
131
|
const allTasksPromise = Promise.all(aw);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/speech_handle.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { ChatItem } from '../llm/index.js';\nimport { Event, Future, shortuuid } from '../utils.js';\nimport type { Task } from '../utils.js';\nimport { asyncLocalStorage } from './agent.js';\n\nexport class SpeechHandle {\n /** Priority for messages that should be played after all other messages in the queue */\n static SPEECH_PRIORITY_LOW = 0;\n /** Every speech generates by the VoiceAgent defaults to this priority. */\n static SPEECH_PRIORITY_NORMAL = 5;\n /** Priority for important messages that should be played before others. */\n static SPEECH_PRIORITY_HIGH = 10;\n\n private interruptFut = new Future<void>();\n private authorizedEvent = new Event();\n private scheduledFut = new Future<void>();\n private doneFut = new Future<void>();\n\n private generations: Future<void>[] = [];\n /** @internal */\n _tasks: Task<void>[] = [];\n private _chatItems: ChatItem[] = [];\n private _numSteps = 1;\n\n private itemAddedCallbacks: Set<(item: ChatItem) => void> = new Set();\n private doneCallbacks: Set<(sh: SpeechHandle) => void> = new Set();\n\n constructor(\n private _id: string,\n private _allowInterruptions: boolean,\n /** @internal */\n public _stepIndex: number,\n readonly parent?: SpeechHandle,\n ) {\n this.doneFut.await.finally(() => {\n for (const callback of this.doneCallbacks) {\n callback(this);\n }\n });\n }\n\n static create(options?: {\n allowInterruptions?: boolean;\n stepIndex?: number;\n parent?: SpeechHandle;\n }) {\n const { allowInterruptions = true, stepIndex = 0, parent } = options ?? {};\n\n return new SpeechHandle(shortuuid('speech_'), allowInterruptions, stepIndex, parent);\n }\n\n get interrupted(): boolean {\n return this.interruptFut.done;\n }\n\n get numSteps(): number {\n return this._numSteps;\n }\n\n get id(): string {\n return this._id;\n }\n\n get scheduled(): boolean {\n return this.scheduledFut.done;\n }\n\n get allowInterruptions(): boolean {\n return this._allowInterruptions;\n }\n\n /**\n * Allow or disallow interruptions on this SpeechHandle.\n *\n * When set to false, the SpeechHandle will no longer accept any incoming\n * interruption requests until re-enabled. If the handle is already\n * interrupted, clearing interruptions is not allowed.\n *\n * @param value - true to allow interruptions, false to disallow\n * @throws Error If attempting to disable interruptions when already interrupted\n */\n set allowInterruptions(value: boolean) {\n if (this.interrupted && !value) {\n throw new Error(\n 'Cannot set allow_interruptions to False, the SpeechHandle is already interrupted',\n );\n }\n this._allowInterruptions = value;\n }\n\n done(): boolean {\n return this.doneFut.done;\n }\n\n get chatItems(): ChatItem[] {\n return this._chatItems;\n }\n\n /**\n * Interrupt the current speech generation.\n *\n * @throws Error If this speech handle does not allow interruptions.\n *\n * @returns The same speech handle that was interrupted.\n */\n interrupt(force: boolean = false): SpeechHandle {\n if (!force && !this.allowInterruptions) {\n throw new Error('This generation handle does not allow interruptions');\n }\n\n this._cancel();\n return this;\n }\n\n /**\n * Waits for the entire assistant turn to complete playback.\n *\n * This method waits until the assistant has fully finished speaking,\n * including any finalization steps beyond initial response generation.\n * This is appropriate to call when you want to ensure the speech output\n * has entirely played out, including any tool calls and response follow-ups.\n */\n async waitForPlayout(): Promise<void> {\n const store = asyncLocalStorage.getStore();\n if (store && store?.functionCall) {\n throw new Error(\n `Cannot call 'SpeechHandle.waitForPlayout()' from inside the function tool '${store.functionCall.name}'. ` +\n 'This creates a circular wait: the speech handle is waiting for the function tool to complete, ' +\n 'while the function tool is simultaneously waiting for the speech handle.\\n' +\n \"To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.\",\n );\n }\n }\n\n async waitIfNotInterrupted(aw: Promise<unknown>[]): Promise<void> {\n const allTasksPromise = Promise.all(aw);\n const fs: Promise<unknown>[] = [allTasksPromise, this.interruptFut.await];\n await Promise.race(fs);\n }\n\n addDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.add(callback);\n }\n\n removeDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.delete(callback);\n }\n\n /** @internal */\n _cancel(): SpeechHandle {\n if (this.done()) {\n return this;\n }\n\n if (!this.interruptFut.done) {\n this.interruptFut.resolve();\n }\n\n return this;\n }\n\n /** @internal */\n _authorizeGeneration(): void {\n const fut = new Future<void>();\n this.generations.push(fut);\n this.authorizedEvent.set();\n }\n\n /** @internal */\n _clearAuthorization(): void {\n this.authorizedEvent.clear();\n }\n\n /** @internal */\n async _waitForAuthorization(): Promise<void> {\n await this.authorizedEvent.wait();\n }\n\n /** @internal */\n async _waitForGeneration(stepIdx: number = -1): Promise<void> {\n if (this.generations.length === 0) {\n throw new Error('cannot use wait_for_generation: no active generation is running.');\n }\n\n const index = stepIdx === -1 ? this.generations.length - 1 : stepIdx;\n const generation = this.generations[index];\n if (!generation) {\n throw new Error(`Generation at index ${index} not found.`);\n }\n return generation.await;\n }\n\n /** @internal */\n async _waitForScheduled(): Promise<void> {\n return this.scheduledFut.await;\n }\n\n /** @internal */\n _markGenerationDone(): void {\n if (this.generations.length === 0) {\n throw new Error('cannot use mark_generation_done: no active generation is running.');\n }\n\n const lastGeneration = this.generations[this.generations.length - 1];\n if (lastGeneration && !lastGeneration.done) {\n lastGeneration.resolve();\n }\n }\n\n /** @internal */\n _markDone(): void {\n if (!this.doneFut.done) {\n this.doneFut.resolve();\n if (this.generations.length > 0) {\n this._markGenerationDone(); // preemptive generation could be cancelled before being scheduled\n }\n }\n }\n\n /** @internal */\n _markScheduled(): void {\n if (!this.scheduledFut.done) {\n this.scheduledFut.resolve();\n }\n }\n\n /** @internal */\n _addItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.add(callback);\n }\n\n /** @internal */\n _removeItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.delete(callback);\n }\n\n /** @internal */\n _itemAdded(items: ChatItem[]): void {\n for (const item of items) {\n for (const cb of this.itemAddedCallbacks) {\n cb(item);\n }\n this._chatItems.push(item);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/speech_handle.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { ChatItem } from '../llm/index.js';\nimport { Event, Future, shortuuid } from '../utils.js';\nimport type { Task } from '../utils.js';\nimport { asyncLocalStorage } from './agent.js';\n\nexport class SpeechHandle {\n /** Priority for messages that should be played after all other messages in the queue */\n static SPEECH_PRIORITY_LOW = 0;\n /** Every speech generates by the VoiceAgent defaults to this priority. */\n static SPEECH_PRIORITY_NORMAL = 5;\n /** Priority for important messages that should be played before others. */\n static SPEECH_PRIORITY_HIGH = 10;\n\n private interruptFut = new Future<void>();\n private authorizedEvent = new Event();\n private scheduledFut = new Future<void>();\n private doneFut = new Future<void>();\n\n private generations: Future<void>[] = [];\n /** @internal */\n _tasks: Task<void>[] = [];\n private _chatItems: ChatItem[] = [];\n private _numSteps = 1;\n\n private itemAddedCallbacks: Set<(item: ChatItem) => void> = new Set();\n private doneCallbacks: Set<(sh: SpeechHandle) => void> = new Set();\n\n constructor(\n private _id: string,\n private _allowInterruptions: boolean,\n /** @internal */\n public _stepIndex: number,\n readonly parent?: SpeechHandle,\n ) {\n this.doneFut.await.finally(() => {\n for (const callback of this.doneCallbacks) {\n callback(this);\n }\n });\n }\n\n static create(options?: {\n allowInterruptions?: boolean;\n stepIndex?: number;\n parent?: SpeechHandle;\n }) {\n const { allowInterruptions = true, stepIndex = 0, parent } = options ?? {};\n\n return new SpeechHandle(shortuuid('speech_'), allowInterruptions, stepIndex, parent);\n }\n\n get interrupted(): boolean {\n return this.interruptFut.done;\n }\n\n get numSteps(): number {\n return this._numSteps;\n }\n\n get id(): string {\n return this._id;\n }\n\n get scheduled(): boolean {\n return this.scheduledFut.done;\n }\n\n get allowInterruptions(): boolean {\n return this._allowInterruptions;\n }\n\n /**\n * Allow or disallow interruptions on this SpeechHandle.\n *\n * When set to false, the SpeechHandle will no longer accept any incoming\n * interruption requests until re-enabled. If the handle is already\n * interrupted, clearing interruptions is not allowed.\n *\n * @param value - true to allow interruptions, false to disallow\n * @throws Error If attempting to disable interruptions when already interrupted\n */\n set allowInterruptions(value: boolean) {\n if (this.interrupted && !value) {\n throw new Error(\n 'Cannot set allow_interruptions to False, the SpeechHandle is already interrupted',\n );\n }\n this._allowInterruptions = value;\n }\n\n done(): boolean {\n return this.doneFut.done;\n }\n\n get chatItems(): ChatItem[] {\n return this._chatItems;\n }\n\n /**\n * Interrupt the current speech generation.\n *\n * @throws Error If this speech handle does not allow interruptions.\n *\n * @returns The same speech handle that was interrupted.\n */\n interrupt(force: boolean = false): SpeechHandle {\n if (!force && !this.allowInterruptions) {\n throw new Error('This generation handle does not allow interruptions');\n }\n\n this._cancel();\n return this;\n }\n\n /**\n * Waits for the entire assistant turn to complete playback.\n *\n * This method waits until the assistant has fully finished speaking,\n * including any finalization steps beyond initial response generation.\n * This is appropriate to call when you want to ensure the speech output\n * has entirely played out, including any tool calls and response follow-ups.\n */\n async waitForPlayout(): Promise<void> {\n const store = asyncLocalStorage.getStore();\n if (store && store?.functionCall) {\n throw new Error(\n `Cannot call 'SpeechHandle.waitForPlayout()' from inside the function tool '${store.functionCall.name}'. ` +\n 'This creates a circular wait: the speech handle is waiting for the function tool to complete, ' +\n 'while the function tool is simultaneously waiting for the speech handle.\\n' +\n \"To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.\",\n );\n }\n await this.doneFut.await;\n }\n\n async waitIfNotInterrupted(aw: Promise<unknown>[]): Promise<void> {\n const allTasksPromise = Promise.all(aw);\n const fs: Promise<unknown>[] = [allTasksPromise, this.interruptFut.await];\n await Promise.race(fs);\n }\n\n addDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.add(callback);\n }\n\n removeDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.delete(callback);\n }\n\n /** @internal */\n _cancel(): SpeechHandle {\n if (this.done()) {\n return this;\n }\n\n if (!this.interruptFut.done) {\n this.interruptFut.resolve();\n }\n\n return this;\n }\n\n /** @internal */\n _authorizeGeneration(): void {\n const fut = new Future<void>();\n this.generations.push(fut);\n this.authorizedEvent.set();\n }\n\n /** @internal */\n _clearAuthorization(): void {\n this.authorizedEvent.clear();\n }\n\n /** @internal */\n async _waitForAuthorization(): Promise<void> {\n await this.authorizedEvent.wait();\n }\n\n /** @internal */\n async _waitForGeneration(stepIdx: number = -1): Promise<void> {\n if (this.generations.length === 0) {\n throw new Error('cannot use wait_for_generation: no active generation is running.');\n }\n\n const index = stepIdx === -1 ? this.generations.length - 1 : stepIdx;\n const generation = this.generations[index];\n if (!generation) {\n throw new Error(`Generation at index ${index} not found.`);\n }\n return generation.await;\n }\n\n /** @internal */\n async _waitForScheduled(): Promise<void> {\n return this.scheduledFut.await;\n }\n\n /** @internal */\n _markGenerationDone(): void {\n if (this.generations.length === 0) {\n throw new Error('cannot use mark_generation_done: no active generation is running.');\n }\n\n const lastGeneration = this.generations[this.generations.length - 1];\n if (lastGeneration && !lastGeneration.done) {\n lastGeneration.resolve();\n }\n }\n\n /** @internal */\n _markDone(): void {\n if (!this.doneFut.done) {\n this.doneFut.resolve();\n if (this.generations.length > 0) {\n this._markGenerationDone(); // preemptive generation could be cancelled before being scheduled\n }\n }\n }\n\n /** @internal */\n _markScheduled(): void {\n if (!this.scheduledFut.done) {\n this.scheduledFut.resolve();\n }\n }\n\n /** @internal */\n _addItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.add(callback);\n }\n\n /** @internal */\n _removeItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.delete(callback);\n }\n\n /** @internal */\n _itemAdded(items: ChatItem[]): void {\n for (const item of items) {\n for (const cb of this.itemAddedCallbacks) {\n cb(item);\n }\n this._chatItems.push(item);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speech_handle.d.ts","sourceRoot":"","sources":["../../src/voice/speech_handle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,qBAAa,YAAY;IAuBrB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,mBAAmB;IAC3B,gBAAgB;IACT,UAAU,EAAE,MAAM;IACzB,QAAQ,CAAC,MAAM,CAAC;IA1BlB,wFAAwF;IACxF,MAAM,CAAC,mBAAmB,SAAK;IAC/B,0EAA0E;IAC1E,MAAM,CAAC,sBAAsB,SAAK;IAClC,2EAA2E;IAC3E,MAAM,CAAC,oBAAoB,SAAM;IAEjC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,eAAe,CAAe;IACtC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,OAAO,CAAsB;IAErC,OAAO,CAAC,WAAW,CAAsB;IACzC,gBAAgB;IAChB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAM;IAC1B,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,SAAS,CAAK;IAEtB,OAAO,CAAC,kBAAkB,CAA4C;IACtE,OAAO,CAAC,aAAa,CAA8C;gBAGzD,GAAG,EAAE,MAAM,EACX,mBAAmB,EAAE,OAAO;IACpC,gBAAgB;IACT,UAAU,EAAE,MAAM,EAChB,MAAM,CAAC,0BAAc;IAShC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;QACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,YAAY,CAAC;KACvB;IAMD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,kBAAkB,IAAI,OAAO,CAEhC;IAED;;;;;;;;;OASG;IACH,IAAI,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAOpC;IAED,IAAI,IAAI,OAAO;IAIf,IAAI,SAAS,IAAI,QAAQ,EAAE,CAE1B;IAED;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,GAAE,OAAe,GAAG,YAAY;IAS/C;;;;;;;OAOG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"speech_handle.d.ts","sourceRoot":"","sources":["../../src/voice/speech_handle.ts"],"names":[],"mappings":"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"}
|
|
@@ -102,6 +102,7 @@ class SpeechHandle {
|
|
|
102
102
|
To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.`
|
|
103
103
|
);
|
|
104
104
|
}
|
|
105
|
+
await this.doneFut.await;
|
|
105
106
|
}
|
|
106
107
|
async waitIfNotInterrupted(aw) {
|
|
107
108
|
const allTasksPromise = Promise.all(aw);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/speech_handle.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { ChatItem } from '../llm/index.js';\nimport { Event, Future, shortuuid } from '../utils.js';\nimport type { Task } from '../utils.js';\nimport { asyncLocalStorage } from './agent.js';\n\nexport class SpeechHandle {\n /** Priority for messages that should be played after all other messages in the queue */\n static SPEECH_PRIORITY_LOW = 0;\n /** Every speech generates by the VoiceAgent defaults to this priority. */\n static SPEECH_PRIORITY_NORMAL = 5;\n /** Priority for important messages that should be played before others. */\n static SPEECH_PRIORITY_HIGH = 10;\n\n private interruptFut = new Future<void>();\n private authorizedEvent = new Event();\n private scheduledFut = new Future<void>();\n private doneFut = new Future<void>();\n\n private generations: Future<void>[] = [];\n /** @internal */\n _tasks: Task<void>[] = [];\n private _chatItems: ChatItem[] = [];\n private _numSteps = 1;\n\n private itemAddedCallbacks: Set<(item: ChatItem) => void> = new Set();\n private doneCallbacks: Set<(sh: SpeechHandle) => void> = new Set();\n\n constructor(\n private _id: string,\n private _allowInterruptions: boolean,\n /** @internal */\n public _stepIndex: number,\n readonly parent?: SpeechHandle,\n ) {\n this.doneFut.await.finally(() => {\n for (const callback of this.doneCallbacks) {\n callback(this);\n }\n });\n }\n\n static create(options?: {\n allowInterruptions?: boolean;\n stepIndex?: number;\n parent?: SpeechHandle;\n }) {\n const { allowInterruptions = true, stepIndex = 0, parent } = options ?? {};\n\n return new SpeechHandle(shortuuid('speech_'), allowInterruptions, stepIndex, parent);\n }\n\n get interrupted(): boolean {\n return this.interruptFut.done;\n }\n\n get numSteps(): number {\n return this._numSteps;\n }\n\n get id(): string {\n return this._id;\n }\n\n get scheduled(): boolean {\n return this.scheduledFut.done;\n }\n\n get allowInterruptions(): boolean {\n return this._allowInterruptions;\n }\n\n /**\n * Allow or disallow interruptions on this SpeechHandle.\n *\n * When set to false, the SpeechHandle will no longer accept any incoming\n * interruption requests until re-enabled. If the handle is already\n * interrupted, clearing interruptions is not allowed.\n *\n * @param value - true to allow interruptions, false to disallow\n * @throws Error If attempting to disable interruptions when already interrupted\n */\n set allowInterruptions(value: boolean) {\n if (this.interrupted && !value) {\n throw new Error(\n 'Cannot set allow_interruptions to False, the SpeechHandle is already interrupted',\n );\n }\n this._allowInterruptions = value;\n }\n\n done(): boolean {\n return this.doneFut.done;\n }\n\n get chatItems(): ChatItem[] {\n return this._chatItems;\n }\n\n /**\n * Interrupt the current speech generation.\n *\n * @throws Error If this speech handle does not allow interruptions.\n *\n * @returns The same speech handle that was interrupted.\n */\n interrupt(force: boolean = false): SpeechHandle {\n if (!force && !this.allowInterruptions) {\n throw new Error('This generation handle does not allow interruptions');\n }\n\n this._cancel();\n return this;\n }\n\n /**\n * Waits for the entire assistant turn to complete playback.\n *\n * This method waits until the assistant has fully finished speaking,\n * including any finalization steps beyond initial response generation.\n * This is appropriate to call when you want to ensure the speech output\n * has entirely played out, including any tool calls and response follow-ups.\n */\n async waitForPlayout(): Promise<void> {\n const store = asyncLocalStorage.getStore();\n if (store && store?.functionCall) {\n throw new Error(\n `Cannot call 'SpeechHandle.waitForPlayout()' from inside the function tool '${store.functionCall.name}'. ` +\n 'This creates a circular wait: the speech handle is waiting for the function tool to complete, ' +\n 'while the function tool is simultaneously waiting for the speech handle.\\n' +\n \"To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.\",\n );\n }\n }\n\n async waitIfNotInterrupted(aw: Promise<unknown>[]): Promise<void> {\n const allTasksPromise = Promise.all(aw);\n const fs: Promise<unknown>[] = [allTasksPromise, this.interruptFut.await];\n await Promise.race(fs);\n }\n\n addDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.add(callback);\n }\n\n removeDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.delete(callback);\n }\n\n /** @internal */\n _cancel(): SpeechHandle {\n if (this.done()) {\n return this;\n }\n\n if (!this.interruptFut.done) {\n this.interruptFut.resolve();\n }\n\n return this;\n }\n\n /** @internal */\n _authorizeGeneration(): void {\n const fut = new Future<void>();\n this.generations.push(fut);\n this.authorizedEvent.set();\n }\n\n /** @internal */\n _clearAuthorization(): void {\n this.authorizedEvent.clear();\n }\n\n /** @internal */\n async _waitForAuthorization(): Promise<void> {\n await this.authorizedEvent.wait();\n }\n\n /** @internal */\n async _waitForGeneration(stepIdx: number = -1): Promise<void> {\n if (this.generations.length === 0) {\n throw new Error('cannot use wait_for_generation: no active generation is running.');\n }\n\n const index = stepIdx === -1 ? this.generations.length - 1 : stepIdx;\n const generation = this.generations[index];\n if (!generation) {\n throw new Error(`Generation at index ${index} not found.`);\n }\n return generation.await;\n }\n\n /** @internal */\n async _waitForScheduled(): Promise<void> {\n return this.scheduledFut.await;\n }\n\n /** @internal */\n _markGenerationDone(): void {\n if (this.generations.length === 0) {\n throw new Error('cannot use mark_generation_done: no active generation is running.');\n }\n\n const lastGeneration = this.generations[this.generations.length - 1];\n if (lastGeneration && !lastGeneration.done) {\n lastGeneration.resolve();\n }\n }\n\n /** @internal */\n _markDone(): void {\n if (!this.doneFut.done) {\n this.doneFut.resolve();\n if (this.generations.length > 0) {\n this._markGenerationDone(); // preemptive generation could be cancelled before being scheduled\n }\n }\n }\n\n /** @internal */\n _markScheduled(): void {\n if (!this.scheduledFut.done) {\n this.scheduledFut.resolve();\n }\n }\n\n /** @internal */\n _addItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.add(callback);\n }\n\n /** @internal */\n _removeItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.delete(callback);\n }\n\n /** @internal */\n _itemAdded(items: ChatItem[]): void {\n for (const item of items) {\n for (const cb of this.itemAddedCallbacks) {\n cb(item);\n }\n this._chatItems.push(item);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/speech_handle.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { ChatItem } from '../llm/index.js';\nimport { Event, Future, shortuuid } from '../utils.js';\nimport type { Task } from '../utils.js';\nimport { asyncLocalStorage } from './agent.js';\n\nexport class SpeechHandle {\n /** Priority for messages that should be played after all other messages in the queue */\n static SPEECH_PRIORITY_LOW = 0;\n /** Every speech generates by the VoiceAgent defaults to this priority. */\n static SPEECH_PRIORITY_NORMAL = 5;\n /** Priority for important messages that should be played before others. */\n static SPEECH_PRIORITY_HIGH = 10;\n\n private interruptFut = new Future<void>();\n private authorizedEvent = new Event();\n private scheduledFut = new Future<void>();\n private doneFut = new Future<void>();\n\n private generations: Future<void>[] = [];\n /** @internal */\n _tasks: Task<void>[] = [];\n private _chatItems: ChatItem[] = [];\n private _numSteps = 1;\n\n private itemAddedCallbacks: Set<(item: ChatItem) => void> = new Set();\n private doneCallbacks: Set<(sh: SpeechHandle) => void> = new Set();\n\n constructor(\n private _id: string,\n private _allowInterruptions: boolean,\n /** @internal */\n public _stepIndex: number,\n readonly parent?: SpeechHandle,\n ) {\n this.doneFut.await.finally(() => {\n for (const callback of this.doneCallbacks) {\n callback(this);\n }\n });\n }\n\n static create(options?: {\n allowInterruptions?: boolean;\n stepIndex?: number;\n parent?: SpeechHandle;\n }) {\n const { allowInterruptions = true, stepIndex = 0, parent } = options ?? {};\n\n return new SpeechHandle(shortuuid('speech_'), allowInterruptions, stepIndex, parent);\n }\n\n get interrupted(): boolean {\n return this.interruptFut.done;\n }\n\n get numSteps(): number {\n return this._numSteps;\n }\n\n get id(): string {\n return this._id;\n }\n\n get scheduled(): boolean {\n return this.scheduledFut.done;\n }\n\n get allowInterruptions(): boolean {\n return this._allowInterruptions;\n }\n\n /**\n * Allow or disallow interruptions on this SpeechHandle.\n *\n * When set to false, the SpeechHandle will no longer accept any incoming\n * interruption requests until re-enabled. If the handle is already\n * interrupted, clearing interruptions is not allowed.\n *\n * @param value - true to allow interruptions, false to disallow\n * @throws Error If attempting to disable interruptions when already interrupted\n */\n set allowInterruptions(value: boolean) {\n if (this.interrupted && !value) {\n throw new Error(\n 'Cannot set allow_interruptions to False, the SpeechHandle is already interrupted',\n );\n }\n this._allowInterruptions = value;\n }\n\n done(): boolean {\n return this.doneFut.done;\n }\n\n get chatItems(): ChatItem[] {\n return this._chatItems;\n }\n\n /**\n * Interrupt the current speech generation.\n *\n * @throws Error If this speech handle does not allow interruptions.\n *\n * @returns The same speech handle that was interrupted.\n */\n interrupt(force: boolean = false): SpeechHandle {\n if (!force && !this.allowInterruptions) {\n throw new Error('This generation handle does not allow interruptions');\n }\n\n this._cancel();\n return this;\n }\n\n /**\n * Waits for the entire assistant turn to complete playback.\n *\n * This method waits until the assistant has fully finished speaking,\n * including any finalization steps beyond initial response generation.\n * This is appropriate to call when you want to ensure the speech output\n * has entirely played out, including any tool calls and response follow-ups.\n */\n async waitForPlayout(): Promise<void> {\n const store = asyncLocalStorage.getStore();\n if (store && store?.functionCall) {\n throw new Error(\n `Cannot call 'SpeechHandle.waitForPlayout()' from inside the function tool '${store.functionCall.name}'. ` +\n 'This creates a circular wait: the speech handle is waiting for the function tool to complete, ' +\n 'while the function tool is simultaneously waiting for the speech handle.\\n' +\n \"To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.\",\n );\n }\n await this.doneFut.await;\n }\n\n async waitIfNotInterrupted(aw: Promise<unknown>[]): Promise<void> {\n const allTasksPromise = Promise.all(aw);\n const fs: Promise<unknown>[] = [allTasksPromise, this.interruptFut.await];\n await Promise.race(fs);\n }\n\n addDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.add(callback);\n }\n\n removeDoneCallback(callback: (sh: SpeechHandle) => void) {\n this.doneCallbacks.delete(callback);\n }\n\n /** @internal */\n _cancel(): SpeechHandle {\n if (this.done()) {\n return this;\n }\n\n if (!this.interruptFut.done) {\n this.interruptFut.resolve();\n }\n\n return this;\n }\n\n /** @internal */\n _authorizeGeneration(): void {\n const fut = new Future<void>();\n this.generations.push(fut);\n this.authorizedEvent.set();\n }\n\n /** @internal */\n _clearAuthorization(): void {\n this.authorizedEvent.clear();\n }\n\n /** @internal */\n async _waitForAuthorization(): Promise<void> {\n await this.authorizedEvent.wait();\n }\n\n /** @internal */\n async _waitForGeneration(stepIdx: number = -1): Promise<void> {\n if (this.generations.length === 0) {\n throw new Error('cannot use wait_for_generation: no active generation is running.');\n }\n\n const index = stepIdx === -1 ? this.generations.length - 1 : stepIdx;\n const generation = this.generations[index];\n if (!generation) {\n throw new Error(`Generation at index ${index} not found.`);\n }\n return generation.await;\n }\n\n /** @internal */\n async _waitForScheduled(): Promise<void> {\n return this.scheduledFut.await;\n }\n\n /** @internal */\n _markGenerationDone(): void {\n if (this.generations.length === 0) {\n throw new Error('cannot use mark_generation_done: no active generation is running.');\n }\n\n const lastGeneration = this.generations[this.generations.length - 1];\n if (lastGeneration && !lastGeneration.done) {\n lastGeneration.resolve();\n }\n }\n\n /** @internal */\n _markDone(): void {\n if (!this.doneFut.done) {\n this.doneFut.resolve();\n if (this.generations.length > 0) {\n this._markGenerationDone(); // preemptive generation could be cancelled before being scheduled\n }\n }\n }\n\n /** @internal */\n _markScheduled(): void {\n if (!this.scheduledFut.done) {\n this.scheduledFut.resolve();\n }\n }\n\n /** @internal */\n _addItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.add(callback);\n }\n\n /** @internal */\n _removeItemAddedCallback(callback: (item: ChatItem) => void): void {\n this.itemAddedCallbacks.delete(callback);\n }\n\n /** @internal */\n _itemAdded(items: ChatItem[]): void {\n for (const item of items) {\n for (const cb of this.itemAddedCallbacks) {\n cb(item);\n }\n this._chatItems.push(item);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1775,6 +1775,20 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1775
1775
|
}
|
|
1776
1776
|
|
|
1777
1777
|
if (functionToolsExecutedEvent.functionCallOutputs.length > 0) {
|
|
1778
|
+
// wait all speeches played before updating the tool output and generating the response
|
|
1779
|
+
// most realtime models dont support generating multiple responses at the same time
|
|
1780
|
+
while (this.currentSpeech || this.speechQueue.size() > 0) {
|
|
1781
|
+
if (
|
|
1782
|
+
this.currentSpeech &&
|
|
1783
|
+
!this.currentSpeech.done() &&
|
|
1784
|
+
this.currentSpeech !== speechHandle
|
|
1785
|
+
) {
|
|
1786
|
+
await this.currentSpeech.waitForPlayout();
|
|
1787
|
+
} else {
|
|
1788
|
+
// Don't block the event loop
|
|
1789
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1778
1792
|
const chatCtx = this.realtimeSession.chatCtx.copy();
|
|
1779
1793
|
chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);
|
|
1780
1794
|
try {
|
|
@@ -133,6 +133,7 @@ export class SpeechHandle {
|
|
|
133
133
|
"To wait for the assistant's spoken response prior to running this tool, use RunContext.wait_for_playout() instead.",
|
|
134
134
|
);
|
|
135
135
|
}
|
|
136
|
+
await this.doneFut.await;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
async waitIfNotInterrupted(aw: Promise<unknown>[]): Promise<void> {
|