@livekit/agents 1.1.0-dev.0 → 1.2.0
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/cli.cjs +2 -0
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/constants.cjs +3 -0
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -1
- package/dist/cpu.cjs +189 -0
- package/dist/cpu.cjs.map +1 -0
- package/dist/cpu.d.cts +24 -0
- package/dist/cpu.d.ts +24 -0
- package/dist/cpu.d.ts.map +1 -0
- package/dist/cpu.js +152 -0
- package/dist/cpu.js.map +1 -0
- package/dist/cpu.test.cjs +227 -0
- package/dist/cpu.test.cjs.map +1 -0
- package/dist/cpu.test.js +204 -0
- package/dist/cpu.test.js.map +1 -0
- package/dist/index.cjs +12 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -13
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -1
- package/dist/inference/interruption/defaults.cjs +1 -1
- package/dist/inference/interruption/defaults.cjs.map +1 -1
- package/dist/inference/interruption/defaults.d.cts +1 -1
- package/dist/inference/interruption/defaults.d.ts +1 -1
- package/dist/inference/interruption/defaults.d.ts.map +1 -1
- package/dist/inference/interruption/defaults.js +1 -1
- package/dist/inference/interruption/defaults.js.map +1 -1
- package/dist/inference/interruption/http_transport.cjs +44 -28
- package/dist/inference/interruption/http_transport.cjs.map +1 -1
- package/dist/inference/interruption/http_transport.d.ts.map +1 -1
- package/dist/inference/interruption/http_transport.js +45 -29
- package/dist/inference/interruption/http_transport.js.map +1 -1
- package/dist/inference/interruption/interruption_detector.cjs +22 -5
- package/dist/inference/interruption/interruption_detector.cjs.map +1 -1
- package/dist/inference/interruption/interruption_detector.d.cts +2 -2
- package/dist/inference/interruption/interruption_detector.d.ts +2 -2
- package/dist/inference/interruption/interruption_detector.d.ts.map +1 -1
- package/dist/inference/interruption/interruption_detector.js +22 -5
- package/dist/inference/interruption/interruption_detector.js.map +1 -1
- package/dist/inference/interruption/interruption_stream.cjs +4 -4
- package/dist/inference/interruption/interruption_stream.cjs.map +1 -1
- package/dist/inference/interruption/interruption_stream.js +4 -4
- package/dist/inference/interruption/interruption_stream.js.map +1 -1
- package/dist/inference/interruption/types.cjs.map +1 -1
- package/dist/inference/interruption/types.d.cts +2 -2
- package/dist/inference/interruption/types.d.ts +2 -2
- package/dist/inference/interruption/types.d.ts.map +1 -1
- package/dist/inference/interruption/ws_transport.cjs +60 -47
- package/dist/inference/interruption/ws_transport.cjs.map +1 -1
- package/dist/inference/interruption/ws_transport.d.ts.map +1 -1
- package/dist/inference/interruption/ws_transport.js +60 -47
- package/dist/inference/interruption/ws_transport.js.map +1 -1
- package/dist/inference/llm.cjs.map +1 -1
- package/dist/inference/llm.d.cts +1 -1
- package/dist/inference/llm.d.ts +1 -1
- package/dist/inference/llm.d.ts.map +1 -1
- package/dist/inference/llm.js.map +1 -1
- package/dist/inference/stt.cjs +20 -12
- package/dist/inference/stt.cjs.map +1 -1
- package/dist/inference/stt.d.cts +3 -2
- package/dist/inference/stt.d.ts +3 -2
- package/dist/inference/stt.d.ts.map +1 -1
- package/dist/inference/stt.js +20 -12
- package/dist/inference/stt.js.map +1 -1
- package/dist/inference/stt.test.cjs +14 -0
- package/dist/inference/stt.test.cjs.map +1 -1
- package/dist/inference/stt.test.js +14 -0
- package/dist/inference/stt.test.js.map +1 -1
- package/dist/inference/tts.cjs +13 -4
- package/dist/inference/tts.cjs.map +1 -1
- package/dist/inference/tts.d.cts +8 -1
- package/dist/inference/tts.d.ts +8 -1
- package/dist/inference/tts.d.ts.map +1 -1
- package/dist/inference/tts.js +13 -4
- package/dist/inference/tts.js.map +1 -1
- package/dist/inference/tts.test.cjs +10 -0
- package/dist/inference/tts.test.cjs.map +1 -1
- package/dist/inference/tts.test.js +10 -0
- package/dist/inference/tts.test.js.map +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs +41 -23
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +41 -23
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/job.cjs +1 -1
- package/dist/job.cjs.map +1 -1
- package/dist/job.js +1 -1
- package/dist/job.js.map +1 -1
- package/dist/language.cjs +394 -0
- package/dist/language.cjs.map +1 -0
- package/dist/language.d.cts +15 -0
- package/dist/language.d.ts +15 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +363 -0
- package/dist/language.js.map +1 -0
- package/dist/language.test.cjs +43 -0
- package/dist/language.test.cjs.map +1 -0
- package/dist/language.test.js +49 -0
- package/dist/language.test.js.map +1 -0
- package/dist/llm/index.cjs +2 -0
- package/dist/llm/index.cjs.map +1 -1
- package/dist/llm/index.d.cts +1 -1
- package/dist/llm/index.d.ts +1 -1
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/llm/index.js +2 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/stream/deferred_stream.cjs +6 -2
- package/dist/stream/deferred_stream.cjs.map +1 -1
- package/dist/stream/deferred_stream.d.ts.map +1 -1
- package/dist/stream/deferred_stream.js +6 -2
- package/dist/stream/deferred_stream.js.map +1 -1
- package/dist/stt/stt.cjs.map +1 -1
- package/dist/stt/stt.d.cts +2 -1
- package/dist/stt/stt.d.ts +2 -1
- package/dist/stt/stt.d.ts.map +1 -1
- package/dist/stt/stt.js.map +1 -1
- package/dist/utils.cjs +15 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +8 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +13 -0
- package/dist/utils.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist/voice/agent.cjs +14 -17
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +10 -11
- package/dist/voice/agent.d.ts +10 -11
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +15 -18
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent.test.cjs +194 -0
- package/dist/voice/agent.test.cjs.map +1 -1
- package/dist/voice/agent.test.js +195 -1
- package/dist/voice/agent.test.js.map +1 -1
- package/dist/voice/agent_activity.cjs +116 -39
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +2 -0
- package/dist/voice/agent_activity.d.ts +2 -0
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +117 -40
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_activity.test.cjs +135 -0
- package/dist/voice/agent_activity.test.cjs.map +1 -0
- package/dist/voice/agent_activity.test.js +134 -0
- package/dist/voice/agent_activity.test.js.map +1 -0
- package/dist/voice/agent_session.cjs +38 -38
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +65 -56
- package/dist/voice/agent_session.d.ts +65 -56
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +37 -37
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +106 -52
- package/dist/voice/audio_recognition.cjs.map +1 -1
- package/dist/voice/audio_recognition.d.cts +4 -2
- package/dist/voice/audio_recognition.d.ts +4 -2
- package/dist/voice/audio_recognition.d.ts.map +1 -1
- package/dist/voice/audio_recognition.js +106 -52
- package/dist/voice/audio_recognition.js.map +1 -1
- package/dist/voice/audio_recognition_span.test.cjs +84 -22
- package/dist/voice/audio_recognition_span.test.cjs.map +1 -1
- package/dist/voice/audio_recognition_span.test.js +90 -23
- package/dist/voice/audio_recognition_span.test.js.map +1 -1
- package/dist/voice/events.cjs +1 -1
- package/dist/voice/events.cjs.map +1 -1
- package/dist/voice/events.d.cts +4 -3
- package/dist/voice/events.d.ts +4 -3
- package/dist/voice/events.d.ts.map +1 -1
- package/dist/voice/events.js +1 -1
- package/dist/voice/events.js.map +1 -1
- package/dist/voice/index.cjs +9 -1
- package/dist/voice/index.cjs.map +1 -1
- package/dist/voice/index.d.cts +1 -1
- package/dist/voice/index.d.ts +1 -1
- package/dist/voice/index.d.ts.map +1 -1
- package/dist/voice/index.js +10 -1
- package/dist/voice/index.js.map +1 -1
- package/dist/voice/remote_session.cjs +922 -0
- package/dist/voice/remote_session.cjs.map +1 -0
- package/dist/voice/remote_session.d.cts +108 -0
- package/dist/voice/remote_session.d.ts +108 -0
- package/dist/voice/remote_session.d.ts.map +1 -0
- package/dist/voice/remote_session.js +887 -0
- package/dist/voice/remote_session.js.map +1 -0
- package/dist/voice/report.cjs +11 -10
- package/dist/voice/report.cjs.map +1 -1
- package/dist/voice/report.d.cts +5 -3
- package/dist/voice/report.d.ts +5 -3
- package/dist/voice/report.d.ts.map +1 -1
- package/dist/voice/report.js +11 -10
- package/dist/voice/report.js.map +1 -1
- package/dist/voice/report.test.cjs +15 -0
- package/dist/voice/report.test.cjs.map +1 -1
- package/dist/voice/report.test.js +15 -0
- package/dist/voice/report.test.js.map +1 -1
- package/dist/voice/room_io/room_io.cjs +39 -0
- package/dist/voice/room_io/room_io.cjs.map +1 -1
- package/dist/voice/room_io/room_io.d.cts +3 -1
- package/dist/voice/room_io/room_io.d.ts +3 -1
- package/dist/voice/room_io/room_io.d.ts.map +1 -1
- package/dist/voice/room_io/room_io.js +40 -1
- package/dist/voice/room_io/room_io.js.map +1 -1
- package/dist/voice/turn_config/interruption.cjs.map +1 -1
- package/dist/voice/turn_config/interruption.d.cts +1 -1
- package/dist/voice/turn_config/interruption.d.ts +1 -1
- package/dist/voice/turn_config/interruption.d.ts.map +1 -1
- package/dist/voice/turn_config/interruption.js.map +1 -1
- package/dist/voice/turn_config/utils.cjs +95 -35
- package/dist/voice/turn_config/utils.cjs.map +1 -1
- package/dist/voice/turn_config/utils.d.cts +17 -5
- package/dist/voice/turn_config/utils.d.ts +17 -5
- package/dist/voice/turn_config/utils.d.ts.map +1 -1
- package/dist/voice/turn_config/utils.js +93 -35
- package/dist/voice/turn_config/utils.js.map +1 -1
- package/dist/voice/turn_config/utils.test.cjs +83 -41
- package/dist/voice/turn_config/utils.test.cjs.map +1 -1
- package/dist/voice/turn_config/utils.test.js +84 -42
- package/dist/voice/turn_config/utils.test.js.map +1 -1
- package/dist/worker.cjs +6 -29
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +6 -19
- package/dist/worker.js.map +1 -1
- package/package.json +3 -2
- package/src/cli.ts +2 -0
- package/src/constants.ts +1 -0
- package/src/cpu.test.ts +239 -0
- package/src/cpu.ts +173 -0
- package/src/index.ts +13 -15
- package/src/inference/interruption/defaults.ts +1 -1
- package/src/inference/interruption/http_transport.ts +49 -30
- package/src/inference/interruption/interruption_detector.ts +22 -6
- package/src/inference/interruption/interruption_stream.ts +4 -4
- package/src/inference/interruption/types.ts +2 -2
- package/src/inference/interruption/ws_transport.ts +63 -59
- package/src/inference/llm.ts +3 -1
- package/src/inference/stt.test.ts +17 -0
- package/src/inference/stt.ts +22 -14
- package/src/inference/tts.test.ts +12 -0
- package/src/inference/tts.ts +22 -6
- package/src/ipc/job_proc_lazy_main.ts +44 -24
- package/src/job.ts +1 -1
- package/src/language.test.ts +62 -0
- package/src/language.ts +380 -0
- package/src/llm/index.ts +2 -0
- package/src/stream/deferred_stream.ts +5 -1
- package/src/stt/stt.ts +2 -1
- package/src/utils.ts +20 -0
- package/src/voice/agent.test.ts +208 -1
- package/src/voice/agent.ts +21 -22
- package/src/voice/agent_activity.test.ts +194 -0
- package/src/voice/agent_activity.ts +161 -43
- package/src/voice/agent_session.ts +103 -92
- package/src/voice/audio_recognition.ts +124 -61
- package/src/voice/audio_recognition_span.test.ts +115 -35
- package/src/voice/events.ts +4 -3
- package/src/voice/index.ts +10 -1
- package/src/voice/remote_session.ts +1083 -0
- package/src/voice/report.test.ts +22 -3
- package/src/voice/report.ts +31 -14
- package/src/voice/room_io/room_io.ts +52 -2
- package/src/voice/turn_config/interruption.ts +1 -1
- package/src/voice/turn_config/utils.test.ts +91 -43
- package/src/voice/turn_config/utils.ts +120 -56
- package/src/worker.ts +34 -50
- package/dist/voice/client_events.cjs +0 -554
- package/dist/voice/client_events.cjs.map +0 -1
- package/dist/voice/client_events.d.cts +0 -195
- package/dist/voice/client_events.d.ts +0 -195
- package/dist/voice/client_events.d.ts.map +0 -1
- package/dist/voice/client_events.js +0 -548
- package/dist/voice/client_events.js.map +0 -1
- package/dist/voice/wire_format.cjs +0 -798
- package/dist/voice/wire_format.cjs.map +0 -1
- package/dist/voice/wire_format.d.cts +0 -5503
- package/dist/voice/wire_format.d.ts +0 -5503
- package/dist/voice/wire_format.d.ts.map +0 -1
- package/dist/voice/wire_format.js +0 -728
- package/dist/voice/wire_format.js.map +0 -1
- package/src/voice/client_events.ts +0 -838
- package/src/voice/wire_format.ts +0 -827
package/dist/voice/agent.js
CHANGED
|
@@ -18,7 +18,7 @@ import { SynthesizeStream, StreamAdapter as TTSStreamAdapter } from "../tts/inde
|
|
|
18
18
|
import { USERDATA_TIMED_TRANSCRIPT } from "../types.js";
|
|
19
19
|
import { Future, Task } from "../utils.js";
|
|
20
20
|
import { agentActivityStorage } from "./agent_activity.js";
|
|
21
|
-
import {
|
|
21
|
+
import { migrateTurnHandling } from "./turn_config/utils.js";
|
|
22
22
|
const functionCallStorage = new AsyncLocalStorage();
|
|
23
23
|
const speechHandleStorage = new AsyncLocalStorage();
|
|
24
24
|
const activityTaskInfoStorage = /* @__PURE__ */ new WeakMap();
|
|
@@ -61,9 +61,8 @@ class Agent {
|
|
|
61
61
|
_vad;
|
|
62
62
|
_llm;
|
|
63
63
|
_tts;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
_allowInterruptions;
|
|
64
|
+
_turnHandling;
|
|
65
|
+
_minConsecutiveSpeechDelay;
|
|
67
66
|
_useTtsAlignedTranscript;
|
|
68
67
|
/** @internal */
|
|
69
68
|
_agentActivity;
|
|
@@ -83,11 +82,11 @@ class Agent {
|
|
|
83
82
|
vad,
|
|
84
83
|
llm,
|
|
85
84
|
tts,
|
|
85
|
+
allowInterruptions,
|
|
86
86
|
turnHandling,
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
minConsecutiveSpeechDelay,
|
|
88
|
+
useTtsAlignedTranscript
|
|
89
89
|
}) {
|
|
90
|
-
var _a, _b;
|
|
91
90
|
if (id) {
|
|
92
91
|
this._id = id;
|
|
93
92
|
} else {
|
|
@@ -103,11 +102,12 @@ class Agent {
|
|
|
103
102
|
this._chatCtx = chatCtx ? chatCtx.copy({
|
|
104
103
|
toolCtx: this._tools
|
|
105
104
|
}) : ChatContext.empty();
|
|
106
|
-
const
|
|
105
|
+
const resolvedTurnHandling = migrateTurnHandling({
|
|
107
106
|
turnDetection,
|
|
108
|
-
|
|
107
|
+
allowInterruptions,
|
|
108
|
+
turnHandling
|
|
109
109
|
});
|
|
110
|
-
this.
|
|
110
|
+
this._turnHandling = Object.keys(resolvedTurnHandling).length > 0 ? resolvedTurnHandling : void 0;
|
|
111
111
|
this._vad = vad;
|
|
112
112
|
if (typeof stt === "string") {
|
|
113
113
|
this._stt = InferenceSTT.fromModelString(stt);
|
|
@@ -124,10 +124,7 @@ class Agent {
|
|
|
124
124
|
} else {
|
|
125
125
|
this._tts = tts;
|
|
126
126
|
}
|
|
127
|
-
this.
|
|
128
|
-
if (((_b = this.turnHandling) == null ? void 0 : _b.interruption.mode) !== void 0) {
|
|
129
|
-
this._allowInterruptions = !!this.turnHandling.interruption.mode;
|
|
130
|
-
}
|
|
127
|
+
this._minConsecutiveSpeechDelay = minConsecutiveSpeechDelay;
|
|
131
128
|
this._useTtsAlignedTranscript = useTtsAlignedTranscript;
|
|
132
129
|
this._agentActivity = void 0;
|
|
133
130
|
}
|
|
@@ -161,11 +158,11 @@ class Agent {
|
|
|
161
158
|
get session() {
|
|
162
159
|
return this.getActivityOrThrow().agentSession;
|
|
163
160
|
}
|
|
164
|
-
get
|
|
165
|
-
return this.
|
|
161
|
+
get turnHandling() {
|
|
162
|
+
return this._turnHandling;
|
|
166
163
|
}
|
|
167
|
-
get
|
|
168
|
-
return this.
|
|
164
|
+
get minConsecutiveSpeechDelay() {
|
|
165
|
+
return this._minConsecutiveSpeechDelay;
|
|
169
166
|
}
|
|
170
167
|
async onEnter() {
|
|
171
168
|
}
|
package/dist/voice/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/agent.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { ReadableStream } from 'node:stream/web';\nimport {\n LLM as InferenceLLM,\n STT as InferenceSTT,\n TTS as InferenceTTS,\n type LLMModels,\n type STTModelString,\n type TTSModelString,\n} from '../inference/index.js';\nimport { ReadonlyChatContext } from '../llm/chat_context.js';\nimport type { ChatMessage, FunctionCall } from '../llm/index.js';\nimport {\n type ChatChunk,\n ChatContext,\n LLM,\n RealtimeModel,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.js';\nimport { log } from '../log.js';\nimport type { STT, SpeechEvent } from '../stt/index.js';\nimport { StreamAdapter as STTStreamAdapter } from '../stt/index.js';\nimport { SentenceTokenizer as BasicSentenceTokenizer } from '../tokenize/basic/index.js';\nimport type { TTS } from '../tts/index.js';\nimport { SynthesizeStream, StreamAdapter as TTSStreamAdapter } from '../tts/index.js';\nimport { USERDATA_TIMED_TRANSCRIPT } from '../types.js';\nimport { Future, Task } from '../utils.js';\nimport type { VAD } from '../vad.js';\nimport { type AgentActivity, agentActivityStorage } from './agent_activity.js';\nimport type { AgentSession, TurnDetectionMode } from './agent_session.js';\nimport type { TimedString } from './io.js';\nimport type { SpeechHandle } from './speech_handle.js';\nimport type { InterruptionOptions } from './turn_config/interruption.js';\nimport type { TurnHandlingOptions } from './turn_config/turn_handling.js';\nimport { migrateLegacyOptions } from './turn_config/utils.js';\n\nexport const functionCallStorage = new AsyncLocalStorage<{ functionCall?: FunctionCall }>();\nexport const speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();\nconst activityTaskInfoStorage = new WeakMap<Task<any>, _ActivityTaskInfo>();\n\ntype _ActivityTaskInfo = {\n functionCall: FunctionCall | null;\n speechHandle: SpeechHandle | null;\n inlineTask: boolean;\n};\n\n/** @internal */\nexport function _setActivityTaskInfo<T>(\n task: Task<T>,\n options: {\n functionCall?: FunctionCall | null;\n speechHandle?: SpeechHandle | null;\n inlineTask?: boolean;\n },\n): void {\n const info = activityTaskInfoStorage.get(task) ?? {\n functionCall: null,\n speechHandle: null,\n inlineTask: false,\n };\n\n if (Object.hasOwn(options, 'functionCall')) {\n info.functionCall = options.functionCall ?? null;\n }\n if (Object.hasOwn(options, 'speechHandle')) {\n info.speechHandle = options.speechHandle ?? null;\n }\n if (Object.hasOwn(options, 'inlineTask')) {\n info.inlineTask = options.inlineTask ?? false;\n }\n\n activityTaskInfoStorage.set(task, info);\n}\n\n/** @internal */\nexport function _getActivityTaskInfo<T>(task: Task<T>): _ActivityTaskInfo | undefined {\n return activityTaskInfoStorage.get(task);\n}\nexport const STOP_RESPONSE_SYMBOL = Symbol('StopResponse');\n\nexport class StopResponse extends Error {\n constructor() {\n super();\n this.name = 'StopResponse';\n\n Object.defineProperty(this, STOP_RESPONSE_SYMBOL, {\n value: true,\n });\n }\n}\n\nexport function isStopResponse(value: unknown): value is StopResponse {\n return (\n value !== undefined &&\n value !== null &&\n typeof value === 'object' &&\n STOP_RESPONSE_SYMBOL in value\n );\n}\n\nexport interface ModelSettings {\n /** The tool choice to use when calling the LLM. */\n toolChoice?: ToolChoice;\n}\n\nexport interface AgentOptions<UserData> {\n id?: string;\n instructions: string;\n chatCtx?: ChatContext;\n tools?: ToolContext<UserData>;\n /** @deprecated use turnHandling instead */\n turnDetection?: TurnDetectionMode;\n stt?: STT | STTModelString;\n vad?: VAD;\n llm?: LLM | RealtimeModel | LLMModels;\n tts?: TTS | TTSModelString;\n allowInterruptions?: boolean;\n minConsecutiveSpeechDelay?: number;\n turnHandling?: TurnHandlingOptions;\n useTtsAlignedTranscript?: boolean;\n}\n\nexport class Agent<UserData = any> {\n private _id: string;\n private _stt?: STT;\n private _vad?: VAD;\n private _llm?: LLM | RealtimeModel;\n private _tts?: TTS;\n private turnHandling?: TurnHandlingOptions;\n private _interruptionDetection: InterruptionOptions['mode'];\n private _allowInterruptions?: boolean;\n private _useTtsAlignedTranscript?: boolean;\n\n /** @internal */\n _agentActivity?: AgentActivity;\n\n /** @internal */\n _chatCtx: ChatContext;\n\n /** @internal */\n _instructions: string;\n\n /** @internal */\n _tools?: ToolContext<UserData>;\n\n constructor({\n id,\n instructions,\n chatCtx,\n tools,\n turnDetection,\n stt,\n vad,\n llm,\n tts,\n turnHandling,\n useTtsAlignedTranscript,\n allowInterruptions,\n }: AgentOptions<UserData>) {\n if (id) {\n this._id = id;\n } else {\n // Convert class name to snake_case\n const className = this.constructor.name;\n if (className === 'Agent') {\n this._id = 'default_agent';\n } else {\n this._id = className\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '');\n }\n }\n\n this._instructions = instructions;\n this._tools = { ...tools };\n this._chatCtx = chatCtx\n ? chatCtx.copy({\n toolCtx: this._tools,\n })\n : ChatContext.empty();\n\n const migratedOptions = migrateLegacyOptions({\n turnDetection,\n options: { turnHandling, allowInterruptions },\n });\n this.turnHandling = migratedOptions.options.turnHandling;\n\n this._vad = vad;\n\n if (typeof stt === 'string') {\n this._stt = InferenceSTT.fromModelString(stt);\n } else {\n this._stt = stt;\n }\n\n if (typeof llm === 'string') {\n this._llm = InferenceLLM.fromModelString(llm);\n } else {\n this._llm = llm;\n }\n\n if (typeof tts === 'string') {\n this._tts = InferenceTTS.fromModelString(tts);\n } else {\n this._tts = tts;\n }\n\n this._interruptionDetection = this.turnHandling?.interruption.mode;\n if (this.turnHandling?.interruption.mode !== undefined) {\n this._allowInterruptions = !!this.turnHandling.interruption.mode;\n }\n this._useTtsAlignedTranscript = useTtsAlignedTranscript;\n\n this._agentActivity = undefined;\n }\n\n get vad(): VAD | undefined {\n return this._vad;\n }\n\n get stt(): STT | undefined {\n return this._stt;\n }\n\n get llm(): LLM | RealtimeModel | undefined {\n return this._llm;\n }\n\n get tts(): TTS | undefined {\n return this._tts;\n }\n\n get useTtsAlignedTranscript(): boolean | undefined {\n return this._useTtsAlignedTranscript;\n }\n\n get chatCtx(): ReadonlyChatContext {\n return new ReadonlyChatContext(this._chatCtx.items);\n }\n\n get id(): string {\n return this._id;\n }\n\n get instructions(): string {\n return this._instructions;\n }\n\n get toolCtx(): ToolContext<UserData> {\n return { ...this._tools };\n }\n\n get session(): AgentSession<UserData> {\n return this.getActivityOrThrow().agentSession as AgentSession<UserData>;\n }\n\n get interruptionDetection(): InterruptionOptions['mode'] {\n return this._interruptionDetection;\n }\n\n get allowInterruptions(): boolean | undefined {\n return this._allowInterruptions;\n }\n\n async onEnter(): Promise<void> {}\n\n async onExit(): Promise<void> {}\n\n async transcriptionNode(\n text: ReadableStream<string | TimedString>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<string | TimedString> | null> {\n return Agent.default.transcriptionNode(this, text, modelSettings);\n }\n\n async onUserTurnCompleted(_chatCtx: ChatContext, _newMessage: ChatMessage): Promise<void> {}\n\n async sttNode(\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<SpeechEvent | string> | null> {\n return Agent.default.sttNode(this, audio, modelSettings);\n }\n\n async llmNode(\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<ChatChunk | string> | null> {\n return Agent.default.llmNode(this, chatCtx, toolCtx, modelSettings);\n }\n\n async ttsNode(\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n return Agent.default.ttsNode(this, text, modelSettings);\n }\n\n async realtimeAudioOutputNode(\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n return Agent.default.realtimeAudioOutputNode(this, audio, modelSettings);\n }\n\n // realtime_audio_output_node\n\n getActivityOrThrow(): AgentActivity {\n if (!this._agentActivity) {\n throw new Error('Agent activity not found');\n }\n return this._agentActivity;\n }\n\n async updateChatCtx(chatCtx: ChatContext): Promise<void> {\n if (!this._agentActivity) {\n this._chatCtx = chatCtx.copy({ toolCtx: this.toolCtx });\n return;\n }\n\n this._agentActivity.updateChatCtx(chatCtx);\n }\n\n // TODO(parity): Add when AgentConfigUpdate is ported to ChatContext.\n async updateTools(tools: ToolContext): Promise<void> {\n if (!this._agentActivity) {\n this._tools = { ...tools };\n this._chatCtx = this._chatCtx.copy({ toolCtx: this._tools });\n return;\n }\n\n await this._agentActivity.updateTools(tools);\n }\n\n static default = {\n async sttNode(\n agent: Agent,\n audio: ReadableStream<AudioFrame>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<SpeechEvent | string> | null> {\n const activity = agent.getActivityOrThrow();\n if (!activity.stt) {\n throw new Error('sttNode called but no STT node is available');\n }\n\n let wrappedStt = activity.stt;\n\n if (!wrappedStt.capabilities.streaming) {\n const vad = agent.vad || activity.vad;\n if (!vad) {\n throw new Error(\n 'STT does not support streaming, add a VAD to the AgentTask/VoiceAgent to enable streaming',\n );\n }\n wrappedStt = new STTStreamAdapter(wrappedStt, vad);\n }\n\n const connOptions = activity.agentSession.connOptions.sttConnOptions;\n const stream = wrappedStt.stream({ connOptions });\n\n // Set startTimeOffset to provide linear timestamps across reconnections\n const audioInputStartedAt =\n activity.inputStartedAt ?? // Use input started at proxied from AudioRecognition if available\n activity.agentSession._recorderIO?.recordingStartedAt ?? // Fallback to recording start time if available\n activity.agentSession._startedAt ?? // Fallback to session start time\n Date.now(); // Fallback to current time\n\n stream.startTimeOffset = (Date.now() - audioInputStartedAt) / 1000;\n\n stream.updateInputStream(audio);\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n stream.detachInputStream();\n stream.close();\n };\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const event of stream) {\n controller.enqueue(event);\n }\n controller.close();\n } finally {\n // Always clean up the STT stream, whether it ends naturally or is cancelled\n cleanup();\n }\n },\n cancel() {\n cleanup();\n },\n });\n },\n\n async llmNode(\n agent: Agent,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<ChatChunk | string> | null> {\n const activity = agent.getActivityOrThrow();\n if (!activity.llm) {\n throw new Error('llmNode called but no LLM node is available');\n }\n\n if (!(activity.llm instanceof LLM)) {\n throw new Error(\n 'llmNode should only be used with LLM (non-multimodal/realtime APIs) nodes',\n );\n }\n\n const { toolChoice } = modelSettings;\n const connOptions = activity.agentSession.connOptions.llmConnOptions;\n\n // parallelToolCalls is not passed here - it will use the value from LLM's modelOptions\n // This allows users to configure it via: new inference.LLM({ modelOptions: { parallel_tool_calls: false } })\n const stream = activity.llm.chat({\n chatCtx,\n toolCtx,\n toolChoice,\n connOptions,\n });\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n stream.close();\n };\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n controller.enqueue(chunk);\n }\n controller.close();\n } finally {\n cleanup();\n }\n },\n cancel() {\n cleanup();\n },\n });\n },\n\n async ttsNode(\n agent: Agent,\n text: ReadableStream<string>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n const activity = agent.getActivityOrThrow();\n if (!activity.tts) {\n throw new Error('ttsNode called but no TTS node is available');\n }\n\n let wrappedTts = activity.tts;\n\n if (!activity.tts.capabilities.streaming) {\n wrappedTts = new TTSStreamAdapter(wrappedTts, new BasicSentenceTokenizer());\n }\n\n const connOptions = activity.agentSession.connOptions.ttsConnOptions;\n const stream = wrappedTts.stream({ connOptions });\n stream.updateInputStream(text);\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n stream.close();\n };\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n if (chunk === SynthesizeStream.END_OF_STREAM) {\n break;\n }\n // Attach timed transcripts to frame.userdata\n if (chunk.timedTranscripts && chunk.timedTranscripts.length > 0) {\n chunk.frame.userdata[USERDATA_TIMED_TRANSCRIPT] = chunk.timedTranscripts;\n }\n controller.enqueue(chunk.frame);\n }\n controller.close();\n } finally {\n cleanup();\n }\n },\n cancel() {\n cleanup();\n },\n });\n },\n\n async transcriptionNode(\n agent: Agent,\n text: ReadableStream<string | TimedString>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<string | TimedString> | null> {\n return text;\n },\n\n async realtimeAudioOutputNode(\n _agent: Agent,\n audio: ReadableStream<AudioFrame>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n return audio;\n },\n };\n}\n\nexport class AgentTask<ResultT = unknown, UserData = any> extends Agent<UserData> {\n private started = false;\n private future = new Future<ResultT>();\n\n #logger = log();\n\n get done(): boolean {\n return this.future.done;\n }\n\n complete(result: ResultT | Error): void {\n if (this.future.done) {\n throw new Error(`${this.constructor.name} is already done`);\n }\n\n if (result instanceof Error) {\n this.future.reject(result);\n } else {\n this.future.resolve(result);\n }\n\n const speechHandle = speechHandleStorage.getStore();\n if (speechHandle) {\n speechHandle._maybeRunFinalOutput = result;\n }\n }\n\n async run(): Promise<ResultT> {\n if (this.started) {\n throw new Error(\n `Task ${this.constructor.name} has already started and cannot be awaited multiple times`,\n );\n }\n this.started = true;\n\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error(`${this.constructor.name} must be executed inside a Task context`);\n }\n\n const taskInfo = _getActivityTaskInfo(currentTask);\n if (!taskInfo || !taskInfo.inlineTask) {\n throw new Error(\n `${this.constructor.name} should only be awaited inside function tools or the onEnter/onExit methods of an Agent`,\n );\n }\n\n const speechHandle = speechHandleStorage.getStore();\n const oldActivity = agentActivityStorage.getStore();\n if (!oldActivity) {\n throw new Error(`${this.constructor.name} must be executed inside an AgentActivity context`);\n }\n\n currentTask.addDoneCallback(() => {\n if (this.future.done) return;\n\n // If the Task finished before the AgentTask was completed, complete the AgentTask with an error.\n this.#logger.error(`The Task finished before ${this.constructor.name} was completed.`);\n this.complete(new Error(`The Task finished before ${this.constructor.name} was completed.`));\n });\n\n const oldAgent = oldActivity.agent;\n const session = oldActivity.agentSession;\n\n const blockedTasks: Task<any>[] = [currentTask];\n const onEnterTask = oldActivity._onEnterTask;\n\n if (onEnterTask && !onEnterTask.done && onEnterTask !== currentTask) {\n blockedTasks.push(onEnterTask);\n }\n\n if (\n taskInfo.functionCall &&\n oldActivity.llm instanceof RealtimeModel &&\n !oldActivity.llm.capabilities.manualFunctionCalls\n ) {\n this.#logger.error(\n `Realtime model does not support resuming function calls from chat context, ` +\n `using AgentTask inside a function tool may have unexpected behavior.`,\n );\n }\n\n await session._updateActivity(this, {\n previousActivity: 'pause',\n newActivity: 'start',\n blockedTasks,\n });\n\n let runState = session._globalRunState;\n if (speechHandle && runState && !runState.done()) {\n // Only unwatch the parent speech handle if there are other handles keeping the run alive.\n // When watchedHandleCount is 1 (only the parent), unwatching would drop it to 0 and\n // mark the run done prematurely — before function_call_output and assistant message arrive.\n if (runState._watchedHandleCount() > 1) {\n runState._unwatchHandle(speechHandle);\n }\n // it is OK to call _markDoneIfNeeded here, the above _updateActivity will call onEnter\n // and newly added handles keep the run alive.\n runState._markDoneIfNeeded();\n }\n\n try {\n return await this.future.await;\n } finally {\n // runState could have changed after future resolved\n runState = session._globalRunState;\n\n if (session.currentAgent !== this) {\n this.#logger.warn(\n `${this.constructor.name} completed, but the agent has changed in the meantime. ` +\n `Ignoring handoff to the previous agent, likely due to AgentSession.updateAgent being invoked.`,\n );\n await oldActivity.close();\n } else {\n if (speechHandle && runState && !runState.done()) {\n runState._watchHandle(speechHandle);\n }\n\n const mergedChatCtx = oldAgent._chatCtx.merge(this._chatCtx, {\n excludeFunctionCall: true,\n excludeInstructions: true,\n });\n oldAgent._chatCtx.items = mergedChatCtx.items;\n\n await session._updateActivity(oldAgent, {\n previousActivity: 'close',\n newActivity: 'resume',\n waitOnEnter: false,\n });\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/agent.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { ReadableStream } from 'node:stream/web';\nimport {\n LLM as InferenceLLM,\n STT as InferenceSTT,\n TTS as InferenceTTS,\n type LLMModels,\n type STTModelString,\n type TTSModelString,\n} from '../inference/index.js';\nimport { ReadonlyChatContext } from '../llm/chat_context.js';\nimport type { ChatMessage, FunctionCall } from '../llm/index.js';\nimport {\n type ChatChunk,\n ChatContext,\n LLM,\n RealtimeModel,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.js';\nimport { log } from '../log.js';\nimport type { STT, SpeechEvent } from '../stt/index.js';\nimport { StreamAdapter as STTStreamAdapter } from '../stt/index.js';\nimport { SentenceTokenizer as BasicSentenceTokenizer } from '../tokenize/basic/index.js';\nimport type { TTS } from '../tts/index.js';\nimport { SynthesizeStream, StreamAdapter as TTSStreamAdapter } from '../tts/index.js';\nimport { USERDATA_TIMED_TRANSCRIPT } from '../types.js';\nimport { Future, Task } from '../utils.js';\nimport type { VAD } from '../vad.js';\nimport { type AgentActivity, agentActivityStorage } from './agent_activity.js';\nimport type { AgentSession, TurnDetectionMode } from './agent_session.js';\nimport type { TimedString } from './io.js';\nimport type { SpeechHandle } from './speech_handle.js';\nimport type { TurnHandlingOptions } from './turn_config/turn_handling.js';\nimport { migrateTurnHandling } from './turn_config/utils.js';\n\nexport const functionCallStorage = new AsyncLocalStorage<{ functionCall?: FunctionCall }>();\nexport const speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();\nconst activityTaskInfoStorage = new WeakMap<Task<any>, _ActivityTaskInfo>();\n\ntype _ActivityTaskInfo = {\n functionCall: FunctionCall | null;\n speechHandle: SpeechHandle | null;\n inlineTask: boolean;\n};\n\n/** @internal */\nexport function _setActivityTaskInfo<T>(\n task: Task<T>,\n options: {\n functionCall?: FunctionCall | null;\n speechHandle?: SpeechHandle | null;\n inlineTask?: boolean;\n },\n): void {\n const info = activityTaskInfoStorage.get(task) ?? {\n functionCall: null,\n speechHandle: null,\n inlineTask: false,\n };\n\n if (Object.hasOwn(options, 'functionCall')) {\n info.functionCall = options.functionCall ?? null;\n }\n if (Object.hasOwn(options, 'speechHandle')) {\n info.speechHandle = options.speechHandle ?? null;\n }\n if (Object.hasOwn(options, 'inlineTask')) {\n info.inlineTask = options.inlineTask ?? false;\n }\n\n activityTaskInfoStorage.set(task, info);\n}\n\n/** @internal */\nexport function _getActivityTaskInfo<T>(task: Task<T>): _ActivityTaskInfo | undefined {\n return activityTaskInfoStorage.get(task);\n}\nexport const STOP_RESPONSE_SYMBOL = Symbol('StopResponse');\n\nexport class StopResponse extends Error {\n constructor() {\n super();\n this.name = 'StopResponse';\n\n Object.defineProperty(this, STOP_RESPONSE_SYMBOL, {\n value: true,\n });\n }\n}\n\nexport function isStopResponse(value: unknown): value is StopResponse {\n return (\n value !== undefined &&\n value !== null &&\n typeof value === 'object' &&\n STOP_RESPONSE_SYMBOL in value\n );\n}\n\nexport interface ModelSettings {\n /** The tool choice to use when calling the LLM. */\n toolChoice?: ToolChoice;\n}\n\nexport interface AgentOptions<UserData> {\n id?: string;\n instructions: string;\n chatCtx?: ChatContext;\n tools?: ToolContext<UserData>;\n stt?: STT | STTModelString;\n vad?: VAD;\n llm?: LLM | RealtimeModel | LLMModels;\n tts?: TTS | TTSModelString;\n turnHandling?: TurnHandlingOptions;\n minConsecutiveSpeechDelay?: number;\n useTtsAlignedTranscript?: boolean;\n /** @deprecated use turnHandling.turnDetection instead */\n turnDetection?: TurnDetectionMode;\n /** @deprecated use turnHandling.interruption.enabled instead */\n allowInterruptions?: boolean;\n}\n\nexport class Agent<UserData = any> {\n private _id: string;\n private _stt?: STT;\n private _vad?: VAD;\n private _llm?: LLM | RealtimeModel;\n private _tts?: TTS;\n private _turnHandling?: Partial<TurnHandlingOptions>;\n\n private _minConsecutiveSpeechDelay?: number;\n private _useTtsAlignedTranscript?: boolean;\n\n /** @internal */\n _agentActivity?: AgentActivity;\n\n /** @internal */\n _chatCtx: ChatContext;\n\n /** @internal */\n _instructions: string;\n\n /** @internal */\n _tools?: ToolContext<UserData>;\n\n constructor({\n id,\n instructions,\n chatCtx,\n tools,\n turnDetection,\n stt,\n vad,\n llm,\n tts,\n allowInterruptions,\n turnHandling,\n minConsecutiveSpeechDelay,\n useTtsAlignedTranscript,\n }: AgentOptions<UserData>) {\n if (id) {\n this._id = id;\n } else {\n const className = this.constructor.name;\n if (className === 'Agent') {\n this._id = 'default_agent';\n } else {\n this._id = className\n .replace(/([A-Z])/g, '_$1')\n .toLowerCase()\n .replace(/^_/, '');\n }\n }\n\n this._instructions = instructions;\n this._tools = { ...tools };\n this._chatCtx = chatCtx\n ? chatCtx.copy({\n toolCtx: this._tools,\n })\n : ChatContext.empty();\n\n const resolvedTurnHandling = migrateTurnHandling({\n turnDetection,\n allowInterruptions,\n turnHandling,\n });\n this._turnHandling =\n Object.keys(resolvedTurnHandling).length > 0 ? resolvedTurnHandling : undefined;\n\n this._vad = vad;\n\n if (typeof stt === 'string') {\n this._stt = InferenceSTT.fromModelString(stt);\n } else {\n this._stt = stt;\n }\n\n if (typeof llm === 'string') {\n this._llm = InferenceLLM.fromModelString(llm);\n } else {\n this._llm = llm;\n }\n\n if (typeof tts === 'string') {\n this._tts = InferenceTTS.fromModelString(tts);\n } else {\n this._tts = tts;\n }\n\n this._minConsecutiveSpeechDelay = minConsecutiveSpeechDelay;\n this._useTtsAlignedTranscript = useTtsAlignedTranscript;\n\n this._agentActivity = undefined;\n }\n\n get vad(): VAD | undefined {\n return this._vad;\n }\n\n get stt(): STT | undefined {\n return this._stt;\n }\n\n get llm(): LLM | RealtimeModel | undefined {\n return this._llm;\n }\n\n get tts(): TTS | undefined {\n return this._tts;\n }\n\n get useTtsAlignedTranscript(): boolean | undefined {\n return this._useTtsAlignedTranscript;\n }\n\n get chatCtx(): ReadonlyChatContext {\n return new ReadonlyChatContext(this._chatCtx.items);\n }\n\n get id(): string {\n return this._id;\n }\n\n get instructions(): string {\n return this._instructions;\n }\n\n get toolCtx(): ToolContext<UserData> {\n return { ...this._tools };\n }\n\n get session(): AgentSession<UserData> {\n return this.getActivityOrThrow().agentSession as AgentSession<UserData>;\n }\n\n get turnHandling(): Partial<TurnHandlingOptions> | undefined {\n return this._turnHandling;\n }\n\n get minConsecutiveSpeechDelay(): number | undefined {\n return this._minConsecutiveSpeechDelay;\n }\n\n async onEnter(): Promise<void> {}\n\n async onExit(): Promise<void> {}\n\n async transcriptionNode(\n text: ReadableStream<string | TimedString>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<string | TimedString> | null> {\n return Agent.default.transcriptionNode(this, text, modelSettings);\n }\n\n async onUserTurnCompleted(_chatCtx: ChatContext, _newMessage: ChatMessage): Promise<void> {}\n\n async sttNode(\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<SpeechEvent | string> | null> {\n return Agent.default.sttNode(this, audio, modelSettings);\n }\n\n async llmNode(\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<ChatChunk | string> | null> {\n return Agent.default.llmNode(this, chatCtx, toolCtx, modelSettings);\n }\n\n async ttsNode(\n text: ReadableStream<string>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n return Agent.default.ttsNode(this, text, modelSettings);\n }\n\n async realtimeAudioOutputNode(\n audio: ReadableStream<AudioFrame>,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n return Agent.default.realtimeAudioOutputNode(this, audio, modelSettings);\n }\n\n // realtime_audio_output_node\n\n getActivityOrThrow(): AgentActivity {\n if (!this._agentActivity) {\n throw new Error('Agent activity not found');\n }\n return this._agentActivity;\n }\n\n async updateChatCtx(chatCtx: ChatContext): Promise<void> {\n if (!this._agentActivity) {\n this._chatCtx = chatCtx.copy({ toolCtx: this.toolCtx });\n return;\n }\n\n this._agentActivity.updateChatCtx(chatCtx);\n }\n\n // TODO(parity): Add when AgentConfigUpdate is ported to ChatContext.\n async updateTools(tools: ToolContext): Promise<void> {\n if (!this._agentActivity) {\n this._tools = { ...tools };\n this._chatCtx = this._chatCtx.copy({ toolCtx: this._tools });\n return;\n }\n\n await this._agentActivity.updateTools(tools);\n }\n\n static default = {\n async sttNode(\n agent: Agent,\n audio: ReadableStream<AudioFrame>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<SpeechEvent | string> | null> {\n const activity = agent.getActivityOrThrow();\n if (!activity.stt) {\n throw new Error('sttNode called but no STT node is available');\n }\n\n let wrappedStt = activity.stt;\n\n if (!wrappedStt.capabilities.streaming) {\n const vad = agent.vad || activity.vad;\n if (!vad) {\n throw new Error(\n 'STT does not support streaming, add a VAD to the AgentTask/VoiceAgent to enable streaming',\n );\n }\n wrappedStt = new STTStreamAdapter(wrappedStt, vad);\n }\n\n const connOptions = activity.agentSession.connOptions.sttConnOptions;\n const stream = wrappedStt.stream({ connOptions });\n\n // Set startTimeOffset to provide linear timestamps across reconnections\n const audioInputStartedAt =\n activity.inputStartedAt ?? // Use input started at proxied from AudioRecognition if available\n activity.agentSession._recorderIO?.recordingStartedAt ?? // Fallback to recording start time if available\n activity.agentSession._startedAt ?? // Fallback to session start time\n Date.now(); // Fallback to current time\n\n stream.startTimeOffset = (Date.now() - audioInputStartedAt) / 1000;\n\n stream.updateInputStream(audio);\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n stream.detachInputStream();\n stream.close();\n };\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const event of stream) {\n controller.enqueue(event);\n }\n controller.close();\n } finally {\n // Always clean up the STT stream, whether it ends naturally or is cancelled\n cleanup();\n }\n },\n cancel() {\n cleanup();\n },\n });\n },\n\n async llmNode(\n agent: Agent,\n chatCtx: ChatContext,\n toolCtx: ToolContext,\n modelSettings: ModelSettings,\n ): Promise<ReadableStream<ChatChunk | string> | null> {\n const activity = agent.getActivityOrThrow();\n if (!activity.llm) {\n throw new Error('llmNode called but no LLM node is available');\n }\n\n if (!(activity.llm instanceof LLM)) {\n throw new Error(\n 'llmNode should only be used with LLM (non-multimodal/realtime APIs) nodes',\n );\n }\n\n const { toolChoice } = modelSettings;\n const connOptions = activity.agentSession.connOptions.llmConnOptions;\n\n // parallelToolCalls is not passed here - it will use the value from LLM's modelOptions\n // This allows users to configure it via: new inference.LLM({ modelOptions: { parallel_tool_calls: false } })\n const stream = activity.llm.chat({\n chatCtx,\n toolCtx,\n toolChoice,\n connOptions,\n });\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n stream.close();\n };\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n controller.enqueue(chunk);\n }\n controller.close();\n } finally {\n cleanup();\n }\n },\n cancel() {\n cleanup();\n },\n });\n },\n\n async ttsNode(\n agent: Agent,\n text: ReadableStream<string>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n const activity = agent.getActivityOrThrow();\n if (!activity.tts) {\n throw new Error('ttsNode called but no TTS node is available');\n }\n\n let wrappedTts = activity.tts;\n\n if (!activity.tts.capabilities.streaming) {\n wrappedTts = new TTSStreamAdapter(wrappedTts, new BasicSentenceTokenizer());\n }\n\n const connOptions = activity.agentSession.connOptions.ttsConnOptions;\n const stream = wrappedTts.stream({ connOptions });\n stream.updateInputStream(text);\n\n let cleaned = false;\n const cleanup = () => {\n if (cleaned) return;\n cleaned = true;\n stream.close();\n };\n\n return new ReadableStream({\n async start(controller) {\n try {\n for await (const chunk of stream) {\n if (chunk === SynthesizeStream.END_OF_STREAM) {\n break;\n }\n // Attach timed transcripts to frame.userdata\n if (chunk.timedTranscripts && chunk.timedTranscripts.length > 0) {\n chunk.frame.userdata[USERDATA_TIMED_TRANSCRIPT] = chunk.timedTranscripts;\n }\n controller.enqueue(chunk.frame);\n }\n controller.close();\n } finally {\n cleanup();\n }\n },\n cancel() {\n cleanup();\n },\n });\n },\n\n async transcriptionNode(\n agent: Agent,\n text: ReadableStream<string | TimedString>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<string | TimedString> | null> {\n return text;\n },\n\n async realtimeAudioOutputNode(\n _agent: Agent,\n audio: ReadableStream<AudioFrame>,\n _modelSettings: ModelSettings,\n ): Promise<ReadableStream<AudioFrame> | null> {\n return audio;\n },\n };\n}\n\nexport class AgentTask<ResultT = unknown, UserData = any> extends Agent<UserData> {\n private started = false;\n private future = new Future<ResultT>();\n\n #logger = log();\n\n get done(): boolean {\n return this.future.done;\n }\n\n complete(result: ResultT | Error): void {\n if (this.future.done) {\n throw new Error(`${this.constructor.name} is already done`);\n }\n\n if (result instanceof Error) {\n this.future.reject(result);\n } else {\n this.future.resolve(result);\n }\n\n const speechHandle = speechHandleStorage.getStore();\n if (speechHandle) {\n speechHandle._maybeRunFinalOutput = result;\n }\n }\n\n async run(): Promise<ResultT> {\n if (this.started) {\n throw new Error(\n `Task ${this.constructor.name} has already started and cannot be awaited multiple times`,\n );\n }\n this.started = true;\n\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error(`${this.constructor.name} must be executed inside a Task context`);\n }\n\n const taskInfo = _getActivityTaskInfo(currentTask);\n if (!taskInfo || !taskInfo.inlineTask) {\n throw new Error(\n `${this.constructor.name} should only be awaited inside function tools or the onEnter/onExit methods of an Agent`,\n );\n }\n\n const speechHandle = speechHandleStorage.getStore();\n const oldActivity = agentActivityStorage.getStore();\n if (!oldActivity) {\n throw new Error(`${this.constructor.name} must be executed inside an AgentActivity context`);\n }\n\n currentTask.addDoneCallback(() => {\n if (this.future.done) return;\n\n // If the Task finished before the AgentTask was completed, complete the AgentTask with an error.\n this.#logger.error(`The Task finished before ${this.constructor.name} was completed.`);\n this.complete(new Error(`The Task finished before ${this.constructor.name} was completed.`));\n });\n\n const oldAgent = oldActivity.agent;\n const session = oldActivity.agentSession;\n\n const blockedTasks: Task<any>[] = [currentTask];\n const onEnterTask = oldActivity._onEnterTask;\n\n if (onEnterTask && !onEnterTask.done && onEnterTask !== currentTask) {\n blockedTasks.push(onEnterTask);\n }\n\n if (\n taskInfo.functionCall &&\n oldActivity.llm instanceof RealtimeModel &&\n !oldActivity.llm.capabilities.manualFunctionCalls\n ) {\n this.#logger.error(\n `Realtime model does not support resuming function calls from chat context, ` +\n `using AgentTask inside a function tool may have unexpected behavior.`,\n );\n }\n\n await session._updateActivity(this, {\n previousActivity: 'pause',\n newActivity: 'start',\n blockedTasks,\n });\n\n let runState = session._globalRunState;\n if (speechHandle && runState && !runState.done()) {\n // Only unwatch the parent speech handle if there are other handles keeping the run alive.\n // When watchedHandleCount is 1 (only the parent), unwatching would drop it to 0 and\n // mark the run done prematurely — before function_call_output and assistant message arrive.\n if (runState._watchedHandleCount() > 1) {\n runState._unwatchHandle(speechHandle);\n }\n // it is OK to call _markDoneIfNeeded here, the above _updateActivity will call onEnter\n // and newly added handles keep the run alive.\n runState._markDoneIfNeeded();\n }\n\n try {\n return await this.future.await;\n } finally {\n // runState could have changed after future resolved\n runState = session._globalRunState;\n\n if (session.currentAgent !== this) {\n this.#logger.warn(\n `${this.constructor.name} completed, but the agent has changed in the meantime. ` +\n `Ignoring handoff to the previous agent, likely due to AgentSession.updateAgent being invoked.`,\n );\n await oldActivity.close();\n } else {\n if (speechHandle && runState && !runState.done()) {\n runState._watchHandle(speechHandle);\n }\n\n const mergedChatCtx = oldAgent._chatCtx.merge(this._chatCtx, {\n excludeFunctionCall: true,\n excludeInstructions: true,\n });\n oldAgent._chatCtx.items = mergedChatCtx.items;\n\n await session._updateActivity(oldAgent, {\n previousActivity: 'close',\n newActivity: 'resume',\n waitOnEnter: false,\n });\n }\n }\n }\n}\n"],"mappings":"AAIA,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B;AAAA,EACE,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,OAIF;AACP,SAAS,2BAA2B;AAEpC;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,WAAW;AAEpB,SAAS,iBAAiB,wBAAwB;AAClD,SAAS,qBAAqB,8BAA8B;AAE5D,SAAS,kBAAkB,iBAAiB,wBAAwB;AACpE,SAAS,iCAAiC;AAC1C,SAAS,QAAQ,YAAY;AAE7B,SAA6B,4BAA4B;AAKzD,SAAS,2BAA2B;AAE7B,MAAM,sBAAsB,IAAI,kBAAmD;AACnF,MAAM,sBAAsB,IAAI,kBAAgC;AACvE,MAAM,0BAA0B,oBAAI,QAAsC;AASnE,SAAS,qBACd,MACA,SAKM;AACN,QAAM,OAAO,wBAAwB,IAAI,IAAI,KAAK;AAAA,IAChD,cAAc;AAAA,IACd,cAAc;AAAA,IACd,YAAY;AAAA,EACd;AAEA,MAAI,OAAO,OAAO,SAAS,cAAc,GAAG;AAC1C,SAAK,eAAe,QAAQ,gBAAgB;AAAA,EAC9C;AACA,MAAI,OAAO,OAAO,SAAS,cAAc,GAAG;AAC1C,SAAK,eAAe,QAAQ,gBAAgB;AAAA,EAC9C;AACA,MAAI,OAAO,OAAO,SAAS,YAAY,GAAG;AACxC,SAAK,aAAa,QAAQ,cAAc;AAAA,EAC1C;AAEA,0BAAwB,IAAI,MAAM,IAAI;AACxC;AAGO,SAAS,qBAAwB,MAA8C;AACpF,SAAO,wBAAwB,IAAI,IAAI;AACzC;AACO,MAAM,uBAAuB,OAAO,cAAc;AAElD,MAAM,qBAAqB,MAAM;AAAA,EACtC,cAAc;AACZ,UAAM;AACN,SAAK,OAAO;AAEZ,WAAO,eAAe,MAAM,sBAAsB;AAAA,MAChD,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAEO,SAAS,eAAe,OAAuC;AACpE,SACE,UAAU,UACV,UAAU,QACV,OAAO,UAAU,YACjB,wBAAwB;AAE5B;AAyBO,MAAM,MAAsB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAGR;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EAEA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAA2B;AACzB,QAAI,IAAI;AACN,WAAK,MAAM;AAAA,IACb,OAAO;AACL,YAAM,YAAY,KAAK,YAAY;AACnC,UAAI,cAAc,SAAS;AACzB,aAAK,MAAM;AAAA,MACb,OAAO;AACL,aAAK,MAAM,UACR,QAAQ,YAAY,KAAK,EACzB,YAAY,EACZ,QAAQ,MAAM,EAAE;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,gBAAgB;AACrB,SAAK,SAAS,EAAE,GAAG,MAAM;AACzB,SAAK,WAAW,UACZ,QAAQ,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,IAChB,CAAC,IACD,YAAY,MAAM;AAEtB,UAAM,uBAAuB,oBAAoB;AAAA,MAC/C;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,SAAK,gBACH,OAAO,KAAK,oBAAoB,EAAE,SAAS,IAAI,uBAAuB;AAExE,SAAK,OAAO;AAEZ,QAAI,OAAO,QAAQ,UAAU;AAC3B,WAAK,OAAO,aAAa,gBAAgB,GAAG;AAAA,IAC9C,OAAO;AACL,WAAK,OAAO;AAAA,IACd;AAEA,QAAI,OAAO,QAAQ,UAAU;AAC3B,WAAK,OAAO,aAAa,gBAAgB,GAAG;AAAA,IAC9C,OAAO;AACL,WAAK,OAAO;AAAA,IACd;AAEA,QAAI,OAAO,QAAQ,UAAU;AAC3B,WAAK,OAAO,aAAa,gBAAgB,GAAG;AAAA,IAC9C,OAAO;AACL,WAAK,OAAO;AAAA,IACd;AAEA,SAAK,6BAA6B;AAClC,SAAK,2BAA2B;AAEhC,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,IAAI,MAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,MAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,MAAuC;AACzC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,MAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,0BAA+C;AACjD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,UAA+B;AACjC,WAAO,IAAI,oBAAoB,KAAK,SAAS,KAAK;AAAA,EACpD;AAAA,EAEA,IAAI,KAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,eAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,UAAiC;AACnC,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA,EAEA,IAAI,UAAkC;AACpC,WAAO,KAAK,mBAAmB,EAAE;AAAA,EACnC;AAAA,EAEA,IAAI,eAAyD;AAC3D,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,4BAAgD;AAClD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,UAAyB;AAAA,EAAC;AAAA,EAEhC,MAAM,SAAwB;AAAA,EAAC;AAAA,EAE/B,MAAM,kBACJ,MACA,eACsD;AACtD,WAAO,MAAM,QAAQ,kBAAkB,MAAM,MAAM,aAAa;AAAA,EAClE;AAAA,EAEA,MAAM,oBAAoB,UAAuB,aAAyC;AAAA,EAAC;AAAA,EAE3F,MAAM,QACJ,OACA,eACsD;AACtD,WAAO,MAAM,QAAQ,QAAQ,MAAM,OAAO,aAAa;AAAA,EACzD;AAAA,EAEA,MAAM,QACJ,SACA,SACA,eACoD;AACpD,WAAO,MAAM,QAAQ,QAAQ,MAAM,SAAS,SAAS,aAAa;AAAA,EACpE;AAAA,EAEA,MAAM,QACJ,MACA,eAC4C;AAC5C,WAAO,MAAM,QAAQ,QAAQ,MAAM,MAAM,aAAa;AAAA,EACxD;AAAA,EAEA,MAAM,wBACJ,OACA,eAC4C;AAC5C,WAAO,MAAM,QAAQ,wBAAwB,MAAM,OAAO,aAAa;AAAA,EACzE;AAAA;AAAA,EAIA,qBAAoC;AAClC,QAAI,CAAC,KAAK,gBAAgB;AACxB,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,cAAc,SAAqC;AACvD,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,WAAW,QAAQ,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC;AACtD;AAAA,IACF;AAEA,SAAK,eAAe,cAAc,OAAO;AAAA,EAC3C;AAAA;AAAA,EAGA,MAAM,YAAY,OAAmC;AACnD,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,SAAS,EAAE,GAAG,MAAM;AACzB,WAAK,WAAW,KAAK,SAAS,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;AAC3D;AAAA,IACF;AAEA,UAAM,KAAK,eAAe,YAAY,KAAK;AAAA,EAC7C;AAAA,EAEA,OAAO,UAAU;AAAA,IACf,MAAM,QACJ,OACA,OACA,gBACsD;AAzV5D;AA0VM,YAAM,WAAW,MAAM,mBAAmB;AAC1C,UAAI,CAAC,SAAS,KAAK;AACjB,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC/D;AAEA,UAAI,aAAa,SAAS;AAE1B,UAAI,CAAC,WAAW,aAAa,WAAW;AACtC,cAAM,MAAM,MAAM,OAAO,SAAS;AAClC,YAAI,CAAC,KAAK;AACR,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AACA,qBAAa,IAAI,iBAAiB,YAAY,GAAG;AAAA,MACnD;AAEA,YAAM,cAAc,SAAS,aAAa,YAAY;AACtD,YAAM,SAAS,WAAW,OAAO,EAAE,YAAY,CAAC;AAGhD,YAAM,sBACJ,SAAS;AAAA,QACT,cAAS,aAAa,gBAAtB,mBAAmC;AAAA,MACnC,SAAS,aAAa;AAAA,MACtB,KAAK,IAAI;AAEX,aAAO,mBAAmB,KAAK,IAAI,IAAI,uBAAuB;AAE9D,aAAO,kBAAkB,KAAK;AAE9B,UAAI,UAAU;AACd,YAAM,UAAU,MAAM;AACpB,YAAI,QAAS;AACb,kBAAU;AACV,eAAO,kBAAkB;AACzB,eAAO,MAAM;AAAA,MACf;AAEA,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM,MAAM,YAAY;AACtB,cAAI;AACF,6BAAiB,SAAS,QAAQ;AAChC,yBAAW,QAAQ,KAAK;AAAA,YAC1B;AACA,uBAAW,MAAM;AAAA,UACnB,UAAE;AAEA,oBAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,SAAS;AACP,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,QACJ,OACA,SACA,SACA,eACoD;AACpD,YAAM,WAAW,MAAM,mBAAmB;AAC1C,UAAI,CAAC,SAAS,KAAK;AACjB,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC/D;AAEA,UAAI,EAAE,SAAS,eAAe,MAAM;AAClC,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,YAAM,EAAE,WAAW,IAAI;AACvB,YAAM,cAAc,SAAS,aAAa,YAAY;AAItD,YAAM,SAAS,SAAS,IAAI,KAAK;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,UAAU;AACd,YAAM,UAAU,MAAM;AACpB,YAAI,QAAS;AACb,kBAAU;AACV,eAAO,MAAM;AAAA,MACf;AAEA,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM,MAAM,YAAY;AACtB,cAAI;AACF,6BAAiB,SAAS,QAAQ;AAChC,yBAAW,QAAQ,KAAK;AAAA,YAC1B;AACA,uBAAW,MAAM;AAAA,UACnB,UAAE;AACA,oBAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,SAAS;AACP,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,QACJ,OACA,MACA,gBAC4C;AAC5C,YAAM,WAAW,MAAM,mBAAmB;AAC1C,UAAI,CAAC,SAAS,KAAK;AACjB,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC/D;AAEA,UAAI,aAAa,SAAS;AAE1B,UAAI,CAAC,SAAS,IAAI,aAAa,WAAW;AACxC,qBAAa,IAAI,iBAAiB,YAAY,IAAI,uBAAuB,CAAC;AAAA,MAC5E;AAEA,YAAM,cAAc,SAAS,aAAa,YAAY;AACtD,YAAM,SAAS,WAAW,OAAO,EAAE,YAAY,CAAC;AAChD,aAAO,kBAAkB,IAAI;AAE7B,UAAI,UAAU;AACd,YAAM,UAAU,MAAM;AACpB,YAAI,QAAS;AACb,kBAAU;AACV,eAAO,MAAM;AAAA,MACf;AAEA,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM,MAAM,YAAY;AACtB,cAAI;AACF,6BAAiB,SAAS,QAAQ;AAChC,kBAAI,UAAU,iBAAiB,eAAe;AAC5C;AAAA,cACF;AAEA,kBAAI,MAAM,oBAAoB,MAAM,iBAAiB,SAAS,GAAG;AAC/D,sBAAM,MAAM,SAAS,yBAAyB,IAAI,MAAM;AAAA,cAC1D;AACA,yBAAW,QAAQ,MAAM,KAAK;AAAA,YAChC;AACA,uBAAW,MAAM;AAAA,UACnB,UAAE;AACA,oBAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,SAAS;AACP,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,kBACJ,OACA,MACA,gBACsD;AACtD,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,wBACJ,QACA,OACA,gBAC4C;AAC5C,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,MAAM,kBAAqD,MAAgB;AAAA,EACxE,UAAU;AAAA,EACV,SAAS,IAAI,OAAgB;AAAA,EAErC,UAAU,IAAI;AAAA,EAEd,IAAI,OAAgB;AAClB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,SAAS,QAA+B;AACtC,QAAI,KAAK,OAAO,MAAM;AACpB,YAAM,IAAI,MAAM,GAAG,KAAK,YAAY,IAAI,kBAAkB;AAAA,IAC5D;AAEA,QAAI,kBAAkB,OAAO;AAC3B,WAAK,OAAO,OAAO,MAAM;AAAA,IAC3B,OAAO;AACL,WAAK,OAAO,QAAQ,MAAM;AAAA,IAC5B;AAEA,UAAM,eAAe,oBAAoB,SAAS;AAClD,QAAI,cAAc;AAChB,mBAAa,uBAAuB;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,MAAwB;AAC5B,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI;AAAA,QACR,QAAQ,KAAK,YAAY,IAAI;AAAA,MAC/B;AAAA,IACF;AACA,SAAK,UAAU;AAEf,UAAM,cAAc,KAAK,QAAQ;AACjC,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,GAAG,KAAK,YAAY,IAAI,yCAAyC;AAAA,IACnF;AAEA,UAAM,WAAW,qBAAqB,WAAW;AACjD,QAAI,CAAC,YAAY,CAAC,SAAS,YAAY;AACrC,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,YAAY,IAAI;AAAA,MAC1B;AAAA,IACF;AAEA,UAAM,eAAe,oBAAoB,SAAS;AAClD,UAAM,cAAc,qBAAqB,SAAS;AAClD,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,GAAG,KAAK,YAAY,IAAI,mDAAmD;AAAA,IAC7F;AAEA,gBAAY,gBAAgB,MAAM;AAChC,UAAI,KAAK,OAAO,KAAM;AAGtB,WAAK,QAAQ,MAAM,4BAA4B,KAAK,YAAY,IAAI,iBAAiB;AACrF,WAAK,SAAS,IAAI,MAAM,4BAA4B,KAAK,YAAY,IAAI,iBAAiB,CAAC;AAAA,IAC7F,CAAC;AAED,UAAM,WAAW,YAAY;AAC7B,UAAM,UAAU,YAAY;AAE5B,UAAM,eAA4B,CAAC,WAAW;AAC9C,UAAM,cAAc,YAAY;AAEhC,QAAI,eAAe,CAAC,YAAY,QAAQ,gBAAgB,aAAa;AACnE,mBAAa,KAAK,WAAW;AAAA,IAC/B;AAEA,QACE,SAAS,gBACT,YAAY,eAAe,iBAC3B,CAAC,YAAY,IAAI,aAAa,qBAC9B;AACA,WAAK,QAAQ;AAAA,QACX;AAAA,MAEF;AAAA,IACF;AAEA,UAAM,QAAQ,gBAAgB,MAAM;AAAA,MAClC,kBAAkB;AAAA,MAClB,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AAED,QAAI,WAAW,QAAQ;AACvB,QAAI,gBAAgB,YAAY,CAAC,SAAS,KAAK,GAAG;AAIhD,UAAI,SAAS,oBAAoB,IAAI,GAAG;AACtC,iBAAS,eAAe,YAAY;AAAA,MACtC;AAGA,eAAS,kBAAkB;AAAA,IAC7B;AAEA,QAAI;AACF,aAAO,MAAM,KAAK,OAAO;AAAA,IAC3B,UAAE;AAEA,iBAAW,QAAQ;AAEnB,UAAI,QAAQ,iBAAiB,MAAM;AACjC,aAAK,QAAQ;AAAA,UACX,GAAG,KAAK,YAAY,IAAI;AAAA,QAE1B;AACA,cAAM,YAAY,MAAM;AAAA,MAC1B,OAAO;AACL,YAAI,gBAAgB,YAAY,CAAC,SAAS,KAAK,GAAG;AAChD,mBAAS,aAAa,YAAY;AAAA,QACpC;AAEA,cAAM,gBAAgB,SAAS,SAAS,MAAM,KAAK,UAAU;AAAA,UAC3D,qBAAqB;AAAA,UACrB,qBAAqB;AAAA,QACvB,CAAC;AACD,iBAAS,SAAS,QAAQ,cAAc;AAExC,cAAM,QAAQ,gBAAgB,UAAU;AAAA,UACtC,kBAAkB;AAAA,UAClB,aAAa;AAAA,UACb,aAAa;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -6,6 +6,9 @@ var import_log = require("../log.cjs");
|
|
|
6
6
|
var import_utils = require("../utils.cjs");
|
|
7
7
|
var import_agent = require("./agent.cjs");
|
|
8
8
|
var import_agent_activity = require("./agent_activity.cjs");
|
|
9
|
+
var import_endpointing = require("./turn_config/endpointing.cjs");
|
|
10
|
+
var import_interruption = require("./turn_config/interruption.cjs");
|
|
11
|
+
import_vitest.vi.mock("ofetch", () => ({ ofetch: import_vitest.vi.fn() }));
|
|
9
12
|
(0, import_log.initializeLogger)({ pretty: false, level: "error" });
|
|
10
13
|
(0, import_vitest.describe)("Agent", () => {
|
|
11
14
|
(0, import_vitest.it)("should create agent with basic instructions", () => {
|
|
@@ -177,5 +180,196 @@ var import_agent_activity = require("./agent_activity.cjs");
|
|
|
177
180
|
await (0, import_vitest.expect)(wrapper.result).resolves.toBe("ok");
|
|
178
181
|
(0, import_vitest.expect)(closeOldActivity).toHaveBeenCalledTimes(1);
|
|
179
182
|
});
|
|
183
|
+
(0, import_vitest.describe)("Agent constructor option migration", () => {
|
|
184
|
+
(0, import_vitest.it)("should set allowInterruptions to false via deprecated constructor field", () => {
|
|
185
|
+
var _a, _b;
|
|
186
|
+
const agent = new import_agent.Agent({ instructions: "test", allowInterruptions: false });
|
|
187
|
+
(0, import_vitest.expect)((_b = (_a = agent.turnHandling) == null ? void 0 : _a.interruption) == null ? void 0 : _b.enabled).toBe(false);
|
|
188
|
+
});
|
|
189
|
+
(0, import_vitest.it)("should not set derived properties when no compatibility fields are provided", () => {
|
|
190
|
+
const agent = new import_agent.Agent({ instructions: "test" });
|
|
191
|
+
(0, import_vitest.expect)(agent.turnHandling).toBeUndefined();
|
|
192
|
+
});
|
|
193
|
+
(0, import_vitest.it)("should expose minConsecutiveSpeechDelay", () => {
|
|
194
|
+
const agent = new import_agent.Agent({ instructions: "test", minConsecutiveSpeechDelay: 1.5 });
|
|
195
|
+
(0, import_vitest.expect)(agent.minConsecutiveSpeechDelay).toBe(1.5);
|
|
196
|
+
});
|
|
197
|
+
(0, import_vitest.it)("should ignore deprecated constructor fields when turnHandling is provided", () => {
|
|
198
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
199
|
+
const agent = new import_agent.Agent({
|
|
200
|
+
instructions: "test",
|
|
201
|
+
turnHandling: {
|
|
202
|
+
endpointing: { minDelay: 999 },
|
|
203
|
+
interruption: {},
|
|
204
|
+
turnDetection: "vad"
|
|
205
|
+
},
|
|
206
|
+
allowInterruptions: false
|
|
207
|
+
});
|
|
208
|
+
(0, import_vitest.expect)((_b = (_a = agent.turnHandling) == null ? void 0 : _a.endpointing) == null ? void 0 : _b.minDelay).toBe(999);
|
|
209
|
+
(0, import_vitest.expect)((_d = (_c = agent.turnHandling) == null ? void 0 : _c.endpointing) == null ? void 0 : _d.maxDelay).toBeUndefined();
|
|
210
|
+
(0, import_vitest.expect)((_f = (_e = agent.turnHandling) == null ? void 0 : _e.interruption) == null ? void 0 : _f.enabled).toBeUndefined();
|
|
211
|
+
(0, import_vitest.expect)((_g = agent.turnHandling) == null ? void 0 : _g.turnDetection).toBe("vad");
|
|
212
|
+
});
|
|
213
|
+
(0, import_vitest.it)("should let turnHandling override deprecated constructor fields on conflicts", () => {
|
|
214
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
215
|
+
const agent = new import_agent.Agent({
|
|
216
|
+
instructions: "test",
|
|
217
|
+
turnHandling: {
|
|
218
|
+
endpointing: { minDelay: 999, maxDelay: 4e3 },
|
|
219
|
+
interruption: { enabled: true },
|
|
220
|
+
turnDetection: "vad"
|
|
221
|
+
},
|
|
222
|
+
allowInterruptions: false,
|
|
223
|
+
turnDetection: "stt"
|
|
224
|
+
});
|
|
225
|
+
(0, import_vitest.expect)((_b = (_a = agent.turnHandling) == null ? void 0 : _a.endpointing) == null ? void 0 : _b.minDelay).toBe(999);
|
|
226
|
+
(0, import_vitest.expect)((_d = (_c = agent.turnHandling) == null ? void 0 : _c.endpointing) == null ? void 0 : _d.maxDelay).toBe(4e3);
|
|
227
|
+
(0, import_vitest.expect)((_f = (_e = agent.turnHandling) == null ? void 0 : _e.interruption) == null ? void 0 : _f.enabled).toBe(true);
|
|
228
|
+
(0, import_vitest.expect)((_g = agent.turnHandling) == null ? void 0 : _g.turnDetection).toBe("vad");
|
|
229
|
+
});
|
|
230
|
+
(0, import_vitest.it)("should set interruptionDetection from turnHandling.interruption.mode", () => {
|
|
231
|
+
var _a, _b;
|
|
232
|
+
const agent = new import_agent.Agent({
|
|
233
|
+
instructions: "test",
|
|
234
|
+
turnHandling: {
|
|
235
|
+
interruption: { mode: "adaptive" },
|
|
236
|
+
endpointing: {},
|
|
237
|
+
turnDetection: void 0
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
(0, import_vitest.expect)((_b = (_a = agent.turnHandling) == null ? void 0 : _a.interruption) == null ? void 0 : _b.mode).toBe("adaptive");
|
|
241
|
+
});
|
|
242
|
+
(0, import_vitest.it)("should let AgentActivity prefer agent-level overrides over session defaults", () => {
|
|
243
|
+
var _a, _b;
|
|
244
|
+
const agent = new import_agent.Agent({
|
|
245
|
+
instructions: "test",
|
|
246
|
+
turnHandling: {
|
|
247
|
+
endpointing: { minDelay: 111, maxDelay: 222 },
|
|
248
|
+
interruption: { enabled: false },
|
|
249
|
+
turnDetection: "manual"
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
const session = {
|
|
253
|
+
options: {
|
|
254
|
+
turnHandling: {
|
|
255
|
+
endpointing: import_endpointing.defaultEndpointingOptions,
|
|
256
|
+
interruption: import_interruption.defaultInterruptionOptions
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
turnDetection: "stt",
|
|
260
|
+
useTtsAlignedTranscript: true,
|
|
261
|
+
vad: void 0,
|
|
262
|
+
stt: void 0,
|
|
263
|
+
llm: void 0,
|
|
264
|
+
tts: void 0,
|
|
265
|
+
interruptionDetection: void 0
|
|
266
|
+
};
|
|
267
|
+
const activity = new import_agent_activity.AgentActivity(agent, session);
|
|
268
|
+
(0, import_vitest.expect)(activity.allowInterruptions).toBe(false);
|
|
269
|
+
(0, import_vitest.expect)(activity.turnDetection).toBe("manual");
|
|
270
|
+
(0, import_vitest.expect)((_a = activity.turnHandling.endpointing) == null ? void 0 : _a.minDelay).toBe(111);
|
|
271
|
+
(0, import_vitest.expect)((_b = activity.turnHandling.endpointing) == null ? void 0 : _b.maxDelay).toBe(222);
|
|
272
|
+
});
|
|
273
|
+
(0, import_vitest.it)("should disable adaptive interruption detection in default mode when prerequisites are missing", () => {
|
|
274
|
+
const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;
|
|
275
|
+
process.env.LIVEKIT_REMOTE_EOT_URL = "http://localhost:9999";
|
|
276
|
+
try {
|
|
277
|
+
const agent = new import_agent.Agent({ instructions: "test" });
|
|
278
|
+
const session = {
|
|
279
|
+
options: {
|
|
280
|
+
turnHandling: {
|
|
281
|
+
endpointing: import_endpointing.defaultEndpointingOptions,
|
|
282
|
+
interruption: import_interruption.defaultInterruptionOptions
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
sessionOptions: {
|
|
286
|
+
turnHandling: {
|
|
287
|
+
endpointing: import_endpointing.defaultEndpointingOptions,
|
|
288
|
+
interruption: import_interruption.defaultInterruptionOptions
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
turnDetection: "manual",
|
|
292
|
+
useTtsAlignedTranscript: true,
|
|
293
|
+
vad: {},
|
|
294
|
+
stt: {
|
|
295
|
+
capabilities: {
|
|
296
|
+
alignedTranscript: true,
|
|
297
|
+
streaming: true
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
llm: void 0,
|
|
301
|
+
tts: void 0,
|
|
302
|
+
interruptionDetection: void 0
|
|
303
|
+
};
|
|
304
|
+
const activity = new import_agent_activity.AgentActivity(agent, session);
|
|
305
|
+
(0, import_vitest.expect)(activity.interruptionDetector).toBeUndefined();
|
|
306
|
+
} finally {
|
|
307
|
+
if (previousRemoteEotUrl === void 0) {
|
|
308
|
+
delete process.env.LIVEKIT_REMOTE_EOT_URL;
|
|
309
|
+
} else {
|
|
310
|
+
process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
(0, import_vitest.it)("should warn when session explicitly requests adaptive detection even if agent overrides it", () => {
|
|
315
|
+
const activity = Object.create(import_agent_activity.AgentActivity.prototype);
|
|
316
|
+
activity.agent = {
|
|
317
|
+
turnHandling: { interruption: { mode: "vad" } },
|
|
318
|
+
turnDetection: void 0
|
|
319
|
+
};
|
|
320
|
+
activity.agentSession = {
|
|
321
|
+
interruptionDetection: "adaptive",
|
|
322
|
+
turnDetection: "manual"
|
|
323
|
+
};
|
|
324
|
+
activity.logger = { warn: import_vitest.vi.fn() };
|
|
325
|
+
(0, import_vitest.expect)(activity.resolveInterruptionDetector()).toBeUndefined();
|
|
326
|
+
(0, import_vitest.expect)(activity.logger.warn).toHaveBeenCalledWith(
|
|
327
|
+
"interruptionDetection is provided, but it's not compatible with the current configuration and will be disabled"
|
|
328
|
+
);
|
|
329
|
+
});
|
|
330
|
+
(0, import_vitest.it)("should disable adaptive interruption detection when interruptions are disabled", () => {
|
|
331
|
+
const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;
|
|
332
|
+
process.env.LIVEKIT_REMOTE_EOT_URL = "http://localhost:9999";
|
|
333
|
+
try {
|
|
334
|
+
const activity = Object.create(import_agent_activity.AgentActivity.prototype);
|
|
335
|
+
activity.agent = {
|
|
336
|
+
turnHandling: {
|
|
337
|
+
interruption: { enabled: false }
|
|
338
|
+
},
|
|
339
|
+
turnDetection: void 0,
|
|
340
|
+
stt: void 0,
|
|
341
|
+
vad: void 0,
|
|
342
|
+
llm: void 0
|
|
343
|
+
};
|
|
344
|
+
activity.agentSession = {
|
|
345
|
+
interruptionDetection: void 0,
|
|
346
|
+
turnDetection: "stt",
|
|
347
|
+
sessionOptions: {
|
|
348
|
+
turnHandling: {
|
|
349
|
+
interruption: import_interruption.defaultInterruptionOptions,
|
|
350
|
+
endpointing: import_endpointing.defaultEndpointingOptions
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
stt: {
|
|
354
|
+
capabilities: {
|
|
355
|
+
alignedTranscript: true,
|
|
356
|
+
streaming: true
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
vad: {},
|
|
360
|
+
llm: void 0
|
|
361
|
+
};
|
|
362
|
+
activity.logger = { warn: import_vitest.vi.fn() };
|
|
363
|
+
(0, import_vitest.expect)(activity.resolveInterruptionDetector()).toBeUndefined();
|
|
364
|
+
(0, import_vitest.expect)(activity.logger.warn).not.toHaveBeenCalled();
|
|
365
|
+
} finally {
|
|
366
|
+
if (previousRemoteEotUrl === void 0) {
|
|
367
|
+
delete process.env.LIVEKIT_REMOTE_EOT_URL;
|
|
368
|
+
} else {
|
|
369
|
+
process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
});
|
|
180
374
|
});
|
|
181
375
|
//# sourceMappingURL=agent.test.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/agent.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { describe, expect, it, vi } from 'vitest';\nimport { z } from 'zod';\nimport { tool } from '../llm/index.js';\nimport { initializeLogger } from '../log.js';\nimport { Task } from '../utils.js';\nimport { Agent, AgentTask, _setActivityTaskInfo } from './agent.js';\nimport { agentActivityStorage } from './agent_activity.js';\n\ninitializeLogger({ pretty: false, level: 'error' });\n\ndescribe('Agent', () => {\n it('should create agent with basic instructions', () => {\n const instructions = 'You are a helpful assistant';\n const agent = new Agent({ instructions });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n });\n\n it('should create agent with instructions and tools', () => {\n const instructions = 'You are a helpful assistant with tools';\n\n // Create mock tools using the tool function\n const mockTool1 = tool({\n description: 'First test tool',\n parameters: z.object({}),\n execute: async () => 'tool1 result',\n });\n\n const mockTool2 = tool({\n description: 'Second test tool',\n parameters: z.object({\n input: z.string().describe('Input parameter'),\n }),\n execute: async ({ input }) => `tool2: ${input}`,\n });\n\n const agent = new Agent({\n instructions,\n tools: {\n getTool1: mockTool1,\n getTool2: mockTool2,\n },\n });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n\n // Assert tools are set correctly\n const agentTools = agent.toolCtx;\n expect(Object.keys(agentTools)).toHaveLength(2);\n expect(agentTools).toHaveProperty('getTool1');\n expect(agentTools).toHaveProperty('getTool2');\n\n // Verify tool properties with proper checks\n expect(agentTools.getTool1?.description).toBe('First test tool');\n expect(agentTools.getTool2?.description).toBe('Second test tool');\n });\n\n it('should return a copy of tools, not the original reference', () => {\n const instructions = 'You are a helpful assistant';\n const mockTool = tool({\n description: 'Test tool',\n parameters: z.object({}),\n execute: async () => 'result',\n });\n\n const tools = { testTool: mockTool };\n const agent = new Agent({ instructions, tools });\n\n const tools1 = agent.toolCtx;\n const tools2 = agent.toolCtx;\n\n // Should return different object references\n expect(tools1).not.toBe(tools2);\n expect(tools1).not.toBe(tools);\n\n // Should contain the same set of tools\n expect(tools1).toEqual(tools2);\n expect(tools1).toEqual(tools);\n });\n\n it('should require AgentTask to run inside task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n await expect(task.run()).rejects.toThrow('must be executed inside a Task context');\n });\n\n it('should require AgentTask to run inside inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'should only be awaited inside function tools or the onEnter/onExit methods of an Agent',\n );\n });\n\n it('should allow AgentTask run from inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const mockSession = {\n currentAgent: oldAgent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: async () => {},\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n });\n\n it('should require AgentTask to run inside AgentActivity context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'must be executed inside an AgentActivity context',\n );\n });\n\n it('should close old activity when current agent changes while AgentTask is pending', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const switchedAgent = new Agent({ instructions: 'switched agent' });\n const closeOldActivity = vi.fn(async () => {});\n\n const mockSession = {\n currentAgent: oldAgent as Agent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n mockSession.currentAgent = switchedAgent;\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: closeOldActivity,\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n expect(closeOldActivity).toHaveBeenCalledTimes(1);\n });\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/agent.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { describe, expect, it, vi } from 'vitest';\nimport { z } from 'zod';\nimport { tool } from '../llm/index.js';\nimport { initializeLogger } from '../log.js';\nimport { Task } from '../utils.js';\nimport { Agent, AgentTask, _setActivityTaskInfo } from './agent.js';\nimport { AgentActivity, agentActivityStorage } from './agent_activity.js';\nimport { defaultEndpointingOptions } from './turn_config/endpointing.js';\nimport { defaultInterruptionOptions } from './turn_config/interruption.js';\n\nvi.mock('ofetch', () => ({ ofetch: vi.fn() }));\n\ninitializeLogger({ pretty: false, level: 'error' });\n\ndescribe('Agent', () => {\n it('should create agent with basic instructions', () => {\n const instructions = 'You are a helpful assistant';\n const agent = new Agent({ instructions });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n });\n\n it('should create agent with instructions and tools', () => {\n const instructions = 'You are a helpful assistant with tools';\n\n // Create mock tools using the tool function\n const mockTool1 = tool({\n description: 'First test tool',\n parameters: z.object({}),\n execute: async () => 'tool1 result',\n });\n\n const mockTool2 = tool({\n description: 'Second test tool',\n parameters: z.object({\n input: z.string().describe('Input parameter'),\n }),\n execute: async ({ input }) => `tool2: ${input}`,\n });\n\n const agent = new Agent({\n instructions,\n tools: {\n getTool1: mockTool1,\n getTool2: mockTool2,\n },\n });\n\n expect(agent).toBeDefined();\n expect(agent.instructions).toBe(instructions);\n\n // Assert tools are set correctly\n const agentTools = agent.toolCtx;\n expect(Object.keys(agentTools)).toHaveLength(2);\n expect(agentTools).toHaveProperty('getTool1');\n expect(agentTools).toHaveProperty('getTool2');\n\n // Verify tool properties with proper checks\n expect(agentTools.getTool1?.description).toBe('First test tool');\n expect(agentTools.getTool2?.description).toBe('Second test tool');\n });\n\n it('should return a copy of tools, not the original reference', () => {\n const instructions = 'You are a helpful assistant';\n const mockTool = tool({\n description: 'Test tool',\n parameters: z.object({}),\n execute: async () => 'result',\n });\n\n const tools = { testTool: mockTool };\n const agent = new Agent({ instructions, tools });\n\n const tools1 = agent.toolCtx;\n const tools2 = agent.toolCtx;\n\n // Should return different object references\n expect(tools1).not.toBe(tools2);\n expect(tools1).not.toBe(tools);\n\n // Should contain the same set of tools\n expect(tools1).toEqual(tools2);\n expect(tools1).toEqual(tools);\n });\n\n it('should require AgentTask to run inside task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n await expect(task.run()).rejects.toThrow('must be executed inside a Task context');\n });\n\n it('should require AgentTask to run inside inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'should only be awaited inside function tools or the onEnter/onExit methods of an Agent',\n );\n });\n\n it('should allow AgentTask run from inline task context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const mockSession = {\n currentAgent: oldAgent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: async () => {},\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n });\n\n it('should require AgentTask to run inside AgentActivity context', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await task.run();\n });\n\n await expect(wrapper.result).rejects.toThrow(\n 'must be executed inside an AgentActivity context',\n );\n });\n\n it('should close old activity when current agent changes while AgentTask is pending', async () => {\n class TestTask extends AgentTask<string> {\n constructor() {\n super({ instructions: 'test task' });\n }\n }\n\n const task = new TestTask();\n const oldAgent = new Agent({ instructions: 'old agent' });\n const switchedAgent = new Agent({ instructions: 'switched agent' });\n const closeOldActivity = vi.fn(async () => {});\n\n const mockSession = {\n currentAgent: oldAgent as Agent,\n _globalRunState: undefined,\n _updateActivity: async (agent: Agent) => {\n if (agent === task) {\n mockSession.currentAgent = switchedAgent;\n task.complete('ok');\n }\n },\n };\n\n const mockActivity = {\n agent: oldAgent,\n agentSession: mockSession,\n _onEnterTask: undefined,\n llm: undefined,\n close: closeOldActivity,\n };\n\n const wrapper = Task.from(async () => {\n const currentTask = Task.current();\n if (!currentTask) {\n throw new Error('expected task context');\n }\n _setActivityTaskInfo(currentTask, { inlineTask: true });\n return await agentActivityStorage.run(mockActivity as any, () => task.run());\n });\n\n await expect(wrapper.result).resolves.toBe('ok');\n expect(closeOldActivity).toHaveBeenCalledTimes(1);\n });\n\n describe('Agent constructor option migration', () => {\n it('should set allowInterruptions to false via deprecated constructor field', () => {\n const agent = new Agent({ instructions: 'test', allowInterruptions: false });\n expect(agent.turnHandling?.interruption?.enabled).toBe(false);\n });\n\n it('should not set derived properties when no compatibility fields are provided', () => {\n const agent = new Agent({ instructions: 'test' });\n expect(agent.turnHandling).toBeUndefined();\n });\n\n it('should expose minConsecutiveSpeechDelay', () => {\n const agent = new Agent({ instructions: 'test', minConsecutiveSpeechDelay: 1.5 });\n expect(agent.minConsecutiveSpeechDelay).toBe(1.5);\n });\n\n it('should ignore deprecated constructor fields when turnHandling is provided', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n endpointing: { minDelay: 999 },\n interruption: {},\n turnDetection: 'vad',\n },\n allowInterruptions: false,\n });\n expect(agent.turnHandling?.endpointing?.minDelay).toBe(999);\n expect(agent.turnHandling?.endpointing?.maxDelay).toBeUndefined();\n expect(agent.turnHandling?.interruption?.enabled).toBeUndefined();\n expect(agent.turnHandling?.turnDetection).toBe('vad');\n });\n\n it('should let turnHandling override deprecated constructor fields on conflicts', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n endpointing: { minDelay: 999, maxDelay: 4000 },\n interruption: { enabled: true },\n turnDetection: 'vad',\n },\n allowInterruptions: false,\n turnDetection: 'stt',\n });\n expect(agent.turnHandling?.endpointing?.minDelay).toBe(999);\n expect(agent.turnHandling?.endpointing?.maxDelay).toBe(4000);\n expect(agent.turnHandling?.interruption?.enabled).toBe(true);\n expect(agent.turnHandling?.turnDetection).toBe('vad');\n });\n\n it('should set interruptionDetection from turnHandling.interruption.mode', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n interruption: { mode: 'adaptive' },\n endpointing: {},\n turnDetection: undefined,\n },\n });\n expect(agent.turnHandling?.interruption?.mode).toBe('adaptive');\n });\n\n it('should let AgentActivity prefer agent-level overrides over session defaults', () => {\n const agent = new Agent({\n instructions: 'test',\n turnHandling: {\n endpointing: { minDelay: 111, maxDelay: 222 },\n interruption: { enabled: false },\n turnDetection: 'manual',\n },\n });\n const session = {\n options: {\n turnHandling: {\n endpointing: defaultEndpointingOptions,\n interruption: defaultInterruptionOptions,\n },\n },\n turnDetection: 'stt',\n useTtsAlignedTranscript: true,\n vad: undefined,\n stt: undefined,\n llm: undefined,\n tts: undefined,\n interruptionDetection: undefined,\n } as any;\n\n const activity = new AgentActivity(agent as any, session);\n\n expect(activity.allowInterruptions).toBe(false);\n expect(activity.turnDetection).toBe('manual');\n expect(activity.turnHandling.endpointing?.minDelay).toBe(111);\n expect(activity.turnHandling.endpointing?.maxDelay).toBe(222);\n });\n\n it('should disable adaptive interruption detection in default mode when prerequisites are missing', () => {\n const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;\n process.env.LIVEKIT_REMOTE_EOT_URL = 'http://localhost:9999';\n\n try {\n const agent = new Agent({ instructions: 'test' });\n const session = {\n options: {\n turnHandling: {\n endpointing: defaultEndpointingOptions,\n interruption: defaultInterruptionOptions,\n },\n },\n sessionOptions: {\n turnHandling: {\n endpointing: defaultEndpointingOptions,\n interruption: defaultInterruptionOptions,\n },\n },\n turnDetection: 'manual',\n useTtsAlignedTranscript: true,\n vad: {},\n stt: {\n capabilities: {\n alignedTranscript: true,\n streaming: true,\n },\n },\n llm: undefined,\n tts: undefined,\n interruptionDetection: undefined,\n } as any;\n\n const activity = new AgentActivity(agent as any, session);\n expect((activity as any).interruptionDetector).toBeUndefined();\n } finally {\n if (previousRemoteEotUrl === undefined) {\n delete process.env.LIVEKIT_REMOTE_EOT_URL;\n } else {\n process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;\n }\n }\n });\n\n it('should warn when session explicitly requests adaptive detection even if agent overrides it', () => {\n const activity = Object.create(AgentActivity.prototype) as any;\n activity.agent = {\n turnHandling: { interruption: { mode: 'vad' } },\n turnDetection: undefined,\n };\n activity.agentSession = {\n interruptionDetection: 'adaptive',\n turnDetection: 'manual',\n };\n activity.logger = { warn: vi.fn() };\n\n expect(activity.resolveInterruptionDetector()).toBeUndefined();\n expect(activity.logger.warn).toHaveBeenCalledWith(\n \"interruptionDetection is provided, but it's not compatible with the current configuration and will be disabled\",\n );\n });\n\n it('should disable adaptive interruption detection when interruptions are disabled', () => {\n const previousRemoteEotUrl = process.env.LIVEKIT_REMOTE_EOT_URL;\n process.env.LIVEKIT_REMOTE_EOT_URL = 'http://localhost:9999';\n\n try {\n const activity = Object.create(AgentActivity.prototype) as any;\n activity.agent = {\n turnHandling: {\n interruption: { enabled: false },\n },\n turnDetection: undefined,\n stt: undefined,\n vad: undefined,\n llm: undefined,\n };\n activity.agentSession = {\n interruptionDetection: undefined,\n turnDetection: 'stt',\n sessionOptions: {\n turnHandling: {\n interruption: defaultInterruptionOptions,\n endpointing: defaultEndpointingOptions,\n },\n },\n stt: {\n capabilities: {\n alignedTranscript: true,\n streaming: true,\n },\n },\n vad: {},\n llm: undefined,\n };\n activity.logger = { warn: vi.fn() };\n\n expect(activity.resolveInterruptionDetector()).toBeUndefined();\n expect(activity.logger.warn).not.toHaveBeenCalled();\n } finally {\n if (previousRemoteEotUrl === undefined) {\n delete process.env.LIVEKIT_REMOTE_EOT_URL;\n } else {\n process.env.LIVEKIT_REMOTE_EOT_URL = previousRemoteEotUrl;\n }\n }\n });\n });\n});\n"],"mappings":"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","names":[]}
|