@livekit/agents 1.0.46 → 1.0.47
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 +14 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -20
- package/dist/cli.js.map +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs +14 -5
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +14 -5
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/llm/chat_context.cjs +19 -0
- package/dist/llm/chat_context.cjs.map +1 -1
- package/dist/llm/chat_context.d.cts +4 -0
- package/dist/llm/chat_context.d.ts +4 -0
- package/dist/llm/chat_context.d.ts.map +1 -1
- package/dist/llm/chat_context.js +19 -0
- package/dist/llm/chat_context.js.map +1 -1
- package/dist/llm/provider_format/index.cjs +2 -0
- package/dist/llm/provider_format/index.cjs.map +1 -1
- package/dist/llm/provider_format/index.d.cts +1 -1
- package/dist/llm/provider_format/index.d.ts +1 -1
- package/dist/llm/provider_format/index.d.ts.map +1 -1
- package/dist/llm/provider_format/index.js +6 -1
- package/dist/llm/provider_format/index.js.map +1 -1
- package/dist/llm/provider_format/openai.cjs +82 -2
- package/dist/llm/provider_format/openai.cjs.map +1 -1
- package/dist/llm/provider_format/openai.d.cts +1 -0
- package/dist/llm/provider_format/openai.d.ts +1 -0
- package/dist/llm/provider_format/openai.d.ts.map +1 -1
- package/dist/llm/provider_format/openai.js +80 -1
- package/dist/llm/provider_format/openai.js.map +1 -1
- package/dist/llm/provider_format/openai.test.cjs +326 -0
- package/dist/llm/provider_format/openai.test.cjs.map +1 -1
- package/dist/llm/provider_format/openai.test.js +327 -1
- package/dist/llm/provider_format/openai.test.js.map +1 -1
- package/dist/llm/provider_format/utils.cjs +4 -3
- package/dist/llm/provider_format/utils.cjs.map +1 -1
- package/dist/llm/provider_format/utils.d.ts.map +1 -1
- package/dist/llm/provider_format/utils.js +4 -3
- package/dist/llm/provider_format/utils.js.map +1 -1
- package/dist/llm/realtime.cjs.map +1 -1
- package/dist/llm/realtime.d.cts +1 -0
- package/dist/llm/realtime.d.ts +1 -0
- package/dist/llm/realtime.d.ts.map +1 -1
- package/dist/llm/realtime.js.map +1 -1
- package/dist/log.cjs +5 -2
- package/dist/log.cjs.map +1 -1
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +5 -2
- package/dist/log.js.map +1 -1
- package/dist/stream/deferred_stream.cjs +15 -6
- 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 +15 -6
- package/dist/stream/deferred_stream.js.map +1 -1
- package/dist/utils.cjs +31 -2
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +7 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +31 -2
- package/dist/utils.js.map +1 -1
- package/dist/utils.test.cjs +71 -0
- package/dist/utils.test.cjs.map +1 -1
- package/dist/utils.test.js +71 -0
- package/dist/utils.test.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/voice/agent.cjs +144 -12
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +29 -4
- package/dist/voice/agent.d.ts +29 -4
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +140 -11
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent.test.cjs +120 -0
- package/dist/voice/agent.test.cjs.map +1 -1
- package/dist/voice/agent.test.js +122 -2
- package/dist/voice/agent.test.js.map +1 -1
- package/dist/voice/agent_activity.cjs +383 -298
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +34 -7
- package/dist/voice/agent_activity.d.ts +34 -7
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +383 -293
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +140 -40
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +19 -7
- package/dist/voice/agent_session.d.ts +19 -7
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +137 -37
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +4 -0
- package/dist/voice/audio_recognition.cjs.map +1 -1
- package/dist/voice/audio_recognition.d.ts.map +1 -1
- package/dist/voice/audio_recognition.js +4 -0
- package/dist/voice/audio_recognition.js.map +1 -1
- package/dist/voice/generation.cjs +39 -19
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.ts.map +1 -1
- package/dist/voice/generation.js +44 -20
- package/dist/voice/generation.js.map +1 -1
- package/dist/voice/index.cjs +2 -0
- 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 +2 -1
- package/dist/voice/index.js.map +1 -1
- package/dist/voice/speech_handle.cjs +7 -1
- package/dist/voice/speech_handle.cjs.map +1 -1
- package/dist/voice/speech_handle.d.cts +2 -0
- package/dist/voice/speech_handle.d.ts +2 -0
- package/dist/voice/speech_handle.d.ts.map +1 -1
- package/dist/voice/speech_handle.js +8 -2
- package/dist/voice/speech_handle.js.map +1 -1
- package/dist/voice/testing/run_result.cjs +66 -15
- package/dist/voice/testing/run_result.cjs.map +1 -1
- package/dist/voice/testing/run_result.d.cts +14 -3
- package/dist/voice/testing/run_result.d.ts +14 -3
- package/dist/voice/testing/run_result.d.ts.map +1 -1
- package/dist/voice/testing/run_result.js +66 -15
- package/dist/voice/testing/run_result.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +20 -33
- package/src/ipc/job_proc_lazy_main.ts +16 -5
- package/src/llm/chat_context.ts +35 -0
- package/src/llm/provider_format/index.ts +7 -2
- package/src/llm/provider_format/openai.test.ts +385 -1
- package/src/llm/provider_format/openai.ts +103 -0
- package/src/llm/provider_format/utils.ts +6 -4
- package/src/llm/realtime.ts +1 -0
- package/src/log.ts +5 -2
- package/src/stream/deferred_stream.ts +17 -6
- package/src/utils.test.ts +87 -0
- package/src/utils.ts +36 -2
- package/src/version.ts +1 -1
- package/src/voice/agent.test.ts +140 -2
- package/src/voice/agent.ts +189 -10
- package/src/voice/agent_activity.ts +427 -289
- package/src/voice/agent_session.ts +178 -40
- package/src/voice/audio_recognition.ts +4 -0
- package/src/voice/generation.ts +52 -23
- package/src/voice/index.ts +1 -1
- package/src/voice/speech_handle.ts +9 -2
- package/src/voice/testing/run_result.ts +81 -23
package/dist/voice/agent.d.ts
CHANGED
|
@@ -5,17 +5,33 @@ import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
5
5
|
import { ReadableStream } from 'node:stream/web';
|
|
6
6
|
import { type LLMModels, type STTModelString, type TTSModelString } from '../inference/index.js';
|
|
7
7
|
import { ReadonlyChatContext } from '../llm/chat_context.js';
|
|
8
|
-
import type { ChatMessage, FunctionCall
|
|
9
|
-
import { type ChatChunk, ChatContext, LLM, type ToolChoice, type ToolContext } from '../llm/index.js';
|
|
8
|
+
import type { ChatMessage, FunctionCall } from '../llm/index.js';
|
|
9
|
+
import { type ChatChunk, ChatContext, LLM, RealtimeModel, type ToolChoice, type ToolContext } from '../llm/index.js';
|
|
10
10
|
import type { STT, SpeechEvent } from '../stt/index.js';
|
|
11
11
|
import type { TTS } from '../tts/index.js';
|
|
12
|
+
import { Task } from '../utils.js';
|
|
12
13
|
import type { VAD } from '../vad.js';
|
|
13
|
-
import type
|
|
14
|
+
import { type AgentActivity } from './agent_activity.js';
|
|
14
15
|
import type { AgentSession, TurnDetectionMode } from './agent_session.js';
|
|
15
16
|
import type { TimedString } from './io.js';
|
|
16
|
-
|
|
17
|
+
import type { SpeechHandle } from './speech_handle.js';
|
|
18
|
+
export declare const functionCallStorage: AsyncLocalStorage<{
|
|
17
19
|
functionCall?: FunctionCall | undefined;
|
|
18
20
|
}>;
|
|
21
|
+
export declare const speechHandleStorage: AsyncLocalStorage<SpeechHandle>;
|
|
22
|
+
type _ActivityTaskInfo = {
|
|
23
|
+
functionCall: FunctionCall | null;
|
|
24
|
+
speechHandle: SpeechHandle | null;
|
|
25
|
+
inlineTask: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** @internal */
|
|
28
|
+
export declare function _setActivityTaskInfo<T>(task: Task<T>, options: {
|
|
29
|
+
functionCall?: FunctionCall | null;
|
|
30
|
+
speechHandle?: SpeechHandle | null;
|
|
31
|
+
inlineTask?: boolean;
|
|
32
|
+
}): void;
|
|
33
|
+
/** @internal */
|
|
34
|
+
export declare function _getActivityTaskInfo<T>(task: Task<T>): _ActivityTaskInfo | undefined;
|
|
19
35
|
export declare const STOP_RESPONSE_SYMBOL: unique symbol;
|
|
20
36
|
export declare class StopResponse extends Error {
|
|
21
37
|
constructor();
|
|
@@ -84,4 +100,13 @@ export declare class Agent<UserData = any> {
|
|
|
84
100
|
realtimeAudioOutputNode(_agent: Agent, audio: ReadableStream<AudioFrame>, _modelSettings: ModelSettings): Promise<ReadableStream<AudioFrame> | null>;
|
|
85
101
|
};
|
|
86
102
|
}
|
|
103
|
+
export declare class AgentTask<ResultT = unknown, UserData = any> extends Agent<UserData> {
|
|
104
|
+
#private;
|
|
105
|
+
private started;
|
|
106
|
+
private future;
|
|
107
|
+
get done(): boolean;
|
|
108
|
+
complete(result: ResultT | Error): void;
|
|
109
|
+
run(): Promise<ResultT>;
|
|
110
|
+
}
|
|
111
|
+
export {};
|
|
87
112
|
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/voice/agent.ts"],"names":[],"mappings":";;AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/voice/agent.ts"],"names":[],"mappings":";;AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EACL,KAAK,SAAS,EACd,WAAW,EACX,GAAG,EACH,aAAa,EACb,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,EAAU,IAAI,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,eAAO,MAAM,mBAAmB;;EAA2D,CAAC;AAC5F,eAAO,MAAM,mBAAmB,iCAAwC,CAAC;AAGzE,KAAK,iBAAiB,GAAG;IACvB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,gBAAgB;AAChB,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACb,OAAO,EAAE;IACP,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACA,IAAI,CAkBN;AAED,gBAAgB;AAChB,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,iBAAiB,GAAG,SAAS,CAEpF;AACD,eAAO,MAAM,oBAAoB,eAAyB,CAAC;AAE3D,qBAAa,YAAa,SAAQ,KAAK;;CAStC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAOpE;AAED,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,YAAY,CAAC,QAAQ;IACpC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,GAAG,CAAC,EAAE,GAAG,GAAG,cAAc,CAAC;IAC3B,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,GAAG,CAAC,EAAE,GAAG,GAAG,aAAa,GAAG,SAAS,CAAC;IACtC,GAAG,CAAC,EAAE,GAAG,GAAG,cAAc,CAAC;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,qBAAa,KAAK,CAAC,QAAQ,GAAG,GAAG;IAC/B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAM;IACnB,OAAO,CAAC,IAAI,CAAC,CAAM;IACnB,OAAO,CAAC,IAAI,CAAC,CAAsB;IACnC,OAAO,CAAC,IAAI,CAAC,CAAM;IACnB,OAAO,CAAC,wBAAwB,CAAC,CAAU;IAE3C,gBAAgB;IAChB,cAAc,CAAC,EAAE,aAAa,CAAC;IAE/B,gBAAgB;IAChB,QAAQ,EAAE,WAAW,CAAC;IAEtB,gBAAgB;IAChB,aAAa,EAAE,MAAM,CAAC;IAEtB,gBAAgB;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAEnB,EACV,EAAE,EACF,YAAY,EACZ,OAAO,EACP,KAAK,EACL,aAAa,EACb,GAAG,EACH,GAAG,EACH,GAAG,EACH,GAAG,EACH,uBAAuB,GACxB,EAAE,YAAY,CAAC,QAAQ,CAAC;IAkDzB,IAAI,GAAG,IAAI,GAAG,GAAG,SAAS,CAEzB;IAED,IAAI,GAAG,IAAI,GAAG,GAAG,SAAS,CAEzB;IAED,IAAI,GAAG,IAAI,GAAG,GAAG,aAAa,GAAG,SAAS,CAEzC;IAED,IAAI,GAAG,IAAI,GAAG,GAAG,SAAS,CAEzB;IAED,IAAI,uBAAuB,IAAI,OAAO,GAAG,SAAS,CAEjD;IAED,IAAI,OAAO,IAAI,mBAAmB,CAEjC;IAED,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,OAAO,IAAI,WAAW,CAAC,QAAQ,CAAC,CAEnC;IAED,IAAI,OAAO,IAAI,YAAY,CAAC,QAAQ,CAAC,CAEpC;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAExB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAEvB,iBAAiB,CACrB,IAAI,EAAE,cAAc,CAAC,MAAM,GAAG,WAAW,CAAC,EAC1C,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC;IAIjD,mBAAmB,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAEnF,OAAO,CACX,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,EACjC,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,cAAc,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAIjD,OAAO,CACX,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,EACpB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,cAAc,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAI/C,OAAO,CACX,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAC5B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAIvC,uBAAuB,CAC3B,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,EACjC,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAM7C,kBAAkB,IAAI,aAAa;IAO7B,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IASxD,MAAM,CAAC,OAAO;uBAEH,KAAK,SACL,eAAe,UAAU,CAAC,kBACjB,aAAa,GAC5B,QAAQ,eAAe,WAAW,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;uBA0D9C,KAAK,WACH,WAAW,WACX,WAAW,iBACL,aAAa,GAC3B,QAAQ,eAAe,SAAS,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;uBAiD5C,KAAK,QACN,eAAe,MAAM,CAAC,kBACZ,aAAa,GAC5B,QAAQ,eAAe,UAAU,CAAC,GAAG,IAAI,CAAC;iCAgDpC,KAAK,QACN,eAAe,MAAM,GAAG,WAAW,CAAC,kBAC1B,aAAa,GAC5B,QAAQ,eAAe,MAAM,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC;wCAK7C,KAAK,SACN,eAAe,UAAU,CAAC,kBACjB,aAAa,GAC5B,QAAQ,eAAe,UAAU,CAAC,GAAG,IAAI,CAAC;MAG7C;CACH;AAED,qBAAa,SAAS,CAAC,OAAO,GAAG,OAAO,EAAE,QAAQ,GAAG,GAAG,CAAE,SAAQ,KAAK,CAAC,QAAQ,CAAC;;IAC/E,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAyB;IAIvC,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI;IAiBjC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;CAyG9B"}
|
package/dist/voice/agent.js
CHANGED
|
@@ -8,13 +8,39 @@ import {
|
|
|
8
8
|
import { ReadonlyChatContext } from "../llm/chat_context.js";
|
|
9
9
|
import {
|
|
10
10
|
ChatContext,
|
|
11
|
-
LLM
|
|
11
|
+
LLM,
|
|
12
|
+
RealtimeModel
|
|
12
13
|
} from "../llm/index.js";
|
|
14
|
+
import { log } from "../log.js";
|
|
13
15
|
import { StreamAdapter as STTStreamAdapter } from "../stt/index.js";
|
|
14
16
|
import { SentenceTokenizer as BasicSentenceTokenizer } from "../tokenize/basic/index.js";
|
|
15
17
|
import { SynthesizeStream, StreamAdapter as TTSStreamAdapter } from "../tts/index.js";
|
|
16
18
|
import { USERDATA_TIMED_TRANSCRIPT } from "../types.js";
|
|
17
|
-
|
|
19
|
+
import { Future, Task } from "../utils.js";
|
|
20
|
+
import { agentActivityStorage } from "./agent_activity.js";
|
|
21
|
+
const functionCallStorage = new AsyncLocalStorage();
|
|
22
|
+
const speechHandleStorage = new AsyncLocalStorage();
|
|
23
|
+
const activityTaskInfoStorage = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
function _setActivityTaskInfo(task, options) {
|
|
25
|
+
const info = activityTaskInfoStorage.get(task) ?? {
|
|
26
|
+
functionCall: null,
|
|
27
|
+
speechHandle: null,
|
|
28
|
+
inlineTask: false
|
|
29
|
+
};
|
|
30
|
+
if (Object.hasOwn(options, "functionCall")) {
|
|
31
|
+
info.functionCall = options.functionCall ?? null;
|
|
32
|
+
}
|
|
33
|
+
if (Object.hasOwn(options, "speechHandle")) {
|
|
34
|
+
info.speechHandle = options.speechHandle ?? null;
|
|
35
|
+
}
|
|
36
|
+
if (Object.hasOwn(options, "inlineTask")) {
|
|
37
|
+
info.inlineTask = options.inlineTask ?? false;
|
|
38
|
+
}
|
|
39
|
+
activityTaskInfoStorage.set(task, info);
|
|
40
|
+
}
|
|
41
|
+
function _getActivityTaskInfo(task) {
|
|
42
|
+
return activityTaskInfoStorage.get(task);
|
|
43
|
+
}
|
|
18
44
|
const STOP_RESPONSE_SYMBOL = Symbol("StopResponse");
|
|
19
45
|
class StopResponse extends Error {
|
|
20
46
|
constructor() {
|
|
@@ -163,18 +189,18 @@ class Agent {
|
|
|
163
189
|
if (!activity.stt) {
|
|
164
190
|
throw new Error("sttNode called but no STT node is available");
|
|
165
191
|
}
|
|
166
|
-
let
|
|
167
|
-
if (!
|
|
192
|
+
let wrappedStt = activity.stt;
|
|
193
|
+
if (!wrappedStt.capabilities.streaming) {
|
|
168
194
|
const vad = agent.vad || activity.vad;
|
|
169
195
|
if (!vad) {
|
|
170
196
|
throw new Error(
|
|
171
197
|
"STT does not support streaming, add a VAD to the AgentTask/VoiceAgent to enable streaming"
|
|
172
198
|
);
|
|
173
199
|
}
|
|
174
|
-
|
|
200
|
+
wrappedStt = new STTStreamAdapter(wrappedStt, vad);
|
|
175
201
|
}
|
|
176
202
|
const connOptions = activity.agentSession.connOptions.sttConnOptions;
|
|
177
|
-
const stream =
|
|
203
|
+
const stream = wrappedStt.stream({ connOptions });
|
|
178
204
|
const audioInputStartedAt = ((_a = activity.agentSession._recorderIO) == null ? void 0 : _a.recordingStartedAt) ?? // Use recording start time if available
|
|
179
205
|
activity.agentSession._startedAt ?? // Fallback to session start time
|
|
180
206
|
Date.now();
|
|
@@ -248,12 +274,12 @@ class Agent {
|
|
|
248
274
|
if (!activity.tts) {
|
|
249
275
|
throw new Error("ttsNode called but no TTS node is available");
|
|
250
276
|
}
|
|
251
|
-
let
|
|
277
|
+
let wrappedTts = activity.tts;
|
|
252
278
|
if (!activity.tts.capabilities.streaming) {
|
|
253
|
-
|
|
279
|
+
wrappedTts = new TTSStreamAdapter(wrappedTts, new BasicSentenceTokenizer());
|
|
254
280
|
}
|
|
255
281
|
const connOptions = activity.agentSession.connOptions.ttsConnOptions;
|
|
256
|
-
const stream =
|
|
282
|
+
const stream = wrappedTts.stream({ connOptions });
|
|
257
283
|
stream.updateInputStream(text);
|
|
258
284
|
let cleaned = false;
|
|
259
285
|
const cleanup = () => {
|
|
@@ -291,11 +317,114 @@ class Agent {
|
|
|
291
317
|
}
|
|
292
318
|
};
|
|
293
319
|
}
|
|
320
|
+
class AgentTask extends Agent {
|
|
321
|
+
started = false;
|
|
322
|
+
future = new Future();
|
|
323
|
+
#logger = log();
|
|
324
|
+
get done() {
|
|
325
|
+
return this.future.done;
|
|
326
|
+
}
|
|
327
|
+
complete(result) {
|
|
328
|
+
if (this.future.done) {
|
|
329
|
+
throw new Error(`${this.constructor.name} is already done`);
|
|
330
|
+
}
|
|
331
|
+
if (result instanceof Error) {
|
|
332
|
+
this.future.reject(result);
|
|
333
|
+
} else {
|
|
334
|
+
this.future.resolve(result);
|
|
335
|
+
}
|
|
336
|
+
const speechHandle = speechHandleStorage.getStore();
|
|
337
|
+
if (speechHandle) {
|
|
338
|
+
speechHandle._maybeRunFinalOutput = result;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
async run() {
|
|
342
|
+
if (this.started) {
|
|
343
|
+
throw new Error(
|
|
344
|
+
`Task ${this.constructor.name} has already started and cannot be awaited multiple times`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
this.started = true;
|
|
348
|
+
const currentTask = Task.current();
|
|
349
|
+
if (!currentTask) {
|
|
350
|
+
throw new Error(`${this.constructor.name} must be executed inside a Task context`);
|
|
351
|
+
}
|
|
352
|
+
const taskInfo = _getActivityTaskInfo(currentTask);
|
|
353
|
+
if (!taskInfo || !taskInfo.inlineTask) {
|
|
354
|
+
throw new Error(
|
|
355
|
+
`${this.constructor.name} should only be awaited inside function tools or the onEnter/onExit methods of an Agent`
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
const speechHandle = speechHandleStorage.getStore();
|
|
359
|
+
const oldActivity = agentActivityStorage.getStore();
|
|
360
|
+
if (!oldActivity) {
|
|
361
|
+
throw new Error(`${this.constructor.name} must be executed inside an AgentActivity context`);
|
|
362
|
+
}
|
|
363
|
+
currentTask.addDoneCallback(() => {
|
|
364
|
+
if (this.future.done) return;
|
|
365
|
+
this.#logger.error(`The Task finished before ${this.constructor.name} was completed.`);
|
|
366
|
+
this.complete(new Error(`The Task finished before ${this.constructor.name} was completed.`));
|
|
367
|
+
});
|
|
368
|
+
const oldAgent = oldActivity.agent;
|
|
369
|
+
const session = oldActivity.agentSession;
|
|
370
|
+
const blockedTasks = [currentTask];
|
|
371
|
+
const onEnterTask = oldActivity._onEnterTask;
|
|
372
|
+
if (onEnterTask && !onEnterTask.done && onEnterTask !== currentTask) {
|
|
373
|
+
blockedTasks.push(onEnterTask);
|
|
374
|
+
}
|
|
375
|
+
if (taskInfo.functionCall && oldActivity.llm instanceof RealtimeModel && !oldActivity.llm.capabilities.manualFunctionCalls) {
|
|
376
|
+
this.#logger.error(
|
|
377
|
+
`Realtime model does not support resuming function calls from chat context, using AgentTask inside a function tool may have unexpected behavior.`
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
await session._updateActivity(this, {
|
|
381
|
+
previousActivity: "pause",
|
|
382
|
+
newActivity: "start",
|
|
383
|
+
blockedTasks
|
|
384
|
+
});
|
|
385
|
+
let runState = session._globalRunState;
|
|
386
|
+
if (speechHandle && runState && !runState.done()) {
|
|
387
|
+
if (runState._watchedHandleCount() > 1) {
|
|
388
|
+
runState._unwatchHandle(speechHandle);
|
|
389
|
+
}
|
|
390
|
+
runState._markDoneIfNeeded();
|
|
391
|
+
}
|
|
392
|
+
try {
|
|
393
|
+
return await this.future.await;
|
|
394
|
+
} finally {
|
|
395
|
+
runState = session._globalRunState;
|
|
396
|
+
if (session.currentAgent !== this) {
|
|
397
|
+
this.#logger.warn(
|
|
398
|
+
`${this.constructor.name} completed, but the agent has changed in the meantime. Ignoring handoff to the previous agent, likely due to AgentSession.updateAgent being invoked.`
|
|
399
|
+
);
|
|
400
|
+
await oldActivity.close();
|
|
401
|
+
} else {
|
|
402
|
+
if (speechHandle && runState && !runState.done()) {
|
|
403
|
+
runState._watchHandle(speechHandle);
|
|
404
|
+
}
|
|
405
|
+
const mergedChatCtx = oldAgent._chatCtx.merge(this._chatCtx, {
|
|
406
|
+
excludeFunctionCall: true,
|
|
407
|
+
excludeInstructions: true
|
|
408
|
+
});
|
|
409
|
+
oldAgent._chatCtx.items = mergedChatCtx.items;
|
|
410
|
+
await session._updateActivity(oldAgent, {
|
|
411
|
+
previousActivity: "close",
|
|
412
|
+
newActivity: "resume",
|
|
413
|
+
waitOnEnter: false
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
294
419
|
export {
|
|
295
420
|
Agent,
|
|
421
|
+
AgentTask,
|
|
296
422
|
STOP_RESPONSE_SYMBOL,
|
|
297
423
|
StopResponse,
|
|
298
|
-
|
|
299
|
-
|
|
424
|
+
_getActivityTaskInfo,
|
|
425
|
+
_setActivityTaskInfo,
|
|
426
|
+
functionCallStorage,
|
|
427
|
+
isStopResponse,
|
|
428
|
+
speechHandleStorage
|
|
300
429
|
};
|
|
301
430
|
//# sourceMappingURL=agent.js.map
|
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, RealtimeModel } from '../llm/index.js';\nimport {\n type ChatChunk,\n ChatContext,\n LLM,\n type ToolChoice,\n type ToolContext,\n} from '../llm/index.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 type { VAD } from '../vad.js';\nimport type { AgentActivity } from './agent_activity.js';\nimport type { AgentSession, TurnDetectionMode } from './agent_session.js';\nimport type { TimedString } from './io.js';\n\nexport const asyncLocalStorage = new AsyncLocalStorage<{ functionCall?: FunctionCall }>();\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 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 useTtsAlignedTranscript?: boolean;\n}\n\nexport class Agent<UserData = any> {\n private _id: string;\n private turnDetection?: TurnDetectionMode;\n private _stt?: STT;\n private _vad?: VAD;\n private _llm?: LLM | RealtimeModel;\n private _tts?: TTS;\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 useTtsAlignedTranscript,\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 this.turnDetection = turnDetection;\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._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 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 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 wrapped_stt = activity.stt;\n\n if (!wrapped_stt.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 wrapped_stt = new STTStreamAdapter(wrapped_stt, vad);\n }\n\n const connOptions = activity.agentSession.connOptions.sttConnOptions;\n const stream = wrapped_stt.stream({ connOptions });\n\n // Set startTimeOffset to provide linear timestamps across reconnections\n const audioInputStartedAt =\n activity.agentSession._recorderIO?.recordingStartedAt ?? // Use 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 wrapped_tts = activity.tts;\n\n if (!activity.tts.capabilities.streaming) {\n wrapped_tts = new TTSStreamAdapter(wrapped_tts, new BasicSentenceTokenizer());\n }\n\n const connOptions = activity.agentSession.connOptions.ttsConnOptions;\n const stream = wrapped_tts.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"],"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';\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 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 useTtsAlignedTranscript?: boolean;\n}\n\nexport class Agent<UserData = any> {\n private _id: string;\n private turnDetection?: TurnDetectionMode;\n private _stt?: STT;\n private _vad?: VAD;\n private _llm?: LLM | RealtimeModel;\n private _tts?: TTS;\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 useTtsAlignedTranscript,\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 this.turnDetection = turnDetection;\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._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 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 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.agentSession._recorderIO?.recordingStartedAt ?? // Use 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":[]}
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
var import_vitest = require("vitest");
|
|
3
3
|
var import_zod = require("zod");
|
|
4
4
|
var import_llm = require("../llm/index.cjs");
|
|
5
|
+
var import_log = require("../log.cjs");
|
|
6
|
+
var import_utils = require("../utils.cjs");
|
|
5
7
|
var import_agent = require("./agent.cjs");
|
|
8
|
+
var import_agent_activity = require("./agent_activity.cjs");
|
|
9
|
+
(0, import_log.initializeLogger)({ pretty: false, level: "error" });
|
|
6
10
|
(0, import_vitest.describe)("Agent", () => {
|
|
7
11
|
(0, import_vitest.it)("should create agent with basic instructions", () => {
|
|
8
12
|
const instructions = "You are a helpful assistant";
|
|
@@ -57,5 +61,121 @@ var import_agent = require("./agent.cjs");
|
|
|
57
61
|
(0, import_vitest.expect)(tools1).toEqual(tools2);
|
|
58
62
|
(0, import_vitest.expect)(tools1).toEqual(tools);
|
|
59
63
|
});
|
|
64
|
+
(0, import_vitest.it)("should require AgentTask to run inside task context", async () => {
|
|
65
|
+
class TestTask extends import_agent.AgentTask {
|
|
66
|
+
constructor() {
|
|
67
|
+
super({ instructions: "test task" });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const task = new TestTask();
|
|
71
|
+
await (0, import_vitest.expect)(task.run()).rejects.toThrow("must be executed inside a Task context");
|
|
72
|
+
});
|
|
73
|
+
(0, import_vitest.it)("should require AgentTask to run inside inline task context", async () => {
|
|
74
|
+
class TestTask extends import_agent.AgentTask {
|
|
75
|
+
constructor() {
|
|
76
|
+
super({ instructions: "test task" });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const task = new TestTask();
|
|
80
|
+
const wrapper = import_utils.Task.from(async () => {
|
|
81
|
+
return await task.run();
|
|
82
|
+
});
|
|
83
|
+
await (0, import_vitest.expect)(wrapper.result).rejects.toThrow(
|
|
84
|
+
"should only be awaited inside function tools or the onEnter/onExit methods of an Agent"
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
(0, import_vitest.it)("should allow AgentTask run from inline task context", async () => {
|
|
88
|
+
class TestTask extends import_agent.AgentTask {
|
|
89
|
+
constructor() {
|
|
90
|
+
super({ instructions: "test task" });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const task = new TestTask();
|
|
94
|
+
const oldAgent = new import_agent.Agent({ instructions: "old agent" });
|
|
95
|
+
const mockSession = {
|
|
96
|
+
currentAgent: oldAgent,
|
|
97
|
+
_globalRunState: void 0,
|
|
98
|
+
_updateActivity: async (agent) => {
|
|
99
|
+
if (agent === task) {
|
|
100
|
+
task.complete("ok");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const mockActivity = {
|
|
105
|
+
agent: oldAgent,
|
|
106
|
+
agentSession: mockSession,
|
|
107
|
+
_onEnterTask: void 0,
|
|
108
|
+
llm: void 0,
|
|
109
|
+
close: async () => {
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const wrapper = import_utils.Task.from(async () => {
|
|
113
|
+
const currentTask = import_utils.Task.current();
|
|
114
|
+
if (!currentTask) {
|
|
115
|
+
throw new Error("expected task context");
|
|
116
|
+
}
|
|
117
|
+
(0, import_agent._setActivityTaskInfo)(currentTask, { inlineTask: true });
|
|
118
|
+
return await import_agent_activity.agentActivityStorage.run(mockActivity, () => task.run());
|
|
119
|
+
});
|
|
120
|
+
await (0, import_vitest.expect)(wrapper.result).resolves.toBe("ok");
|
|
121
|
+
});
|
|
122
|
+
(0, import_vitest.it)("should require AgentTask to run inside AgentActivity context", async () => {
|
|
123
|
+
class TestTask extends import_agent.AgentTask {
|
|
124
|
+
constructor() {
|
|
125
|
+
super({ instructions: "test task" });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const task = new TestTask();
|
|
129
|
+
const wrapper = import_utils.Task.from(async () => {
|
|
130
|
+
const currentTask = import_utils.Task.current();
|
|
131
|
+
if (!currentTask) {
|
|
132
|
+
throw new Error("expected task context");
|
|
133
|
+
}
|
|
134
|
+
(0, import_agent._setActivityTaskInfo)(currentTask, { inlineTask: true });
|
|
135
|
+
return await task.run();
|
|
136
|
+
});
|
|
137
|
+
await (0, import_vitest.expect)(wrapper.result).rejects.toThrow(
|
|
138
|
+
"must be executed inside an AgentActivity context"
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
(0, import_vitest.it)("should close old activity when current agent changes while AgentTask is pending", async () => {
|
|
142
|
+
class TestTask extends import_agent.AgentTask {
|
|
143
|
+
constructor() {
|
|
144
|
+
super({ instructions: "test task" });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const task = new TestTask();
|
|
148
|
+
const oldAgent = new import_agent.Agent({ instructions: "old agent" });
|
|
149
|
+
const switchedAgent = new import_agent.Agent({ instructions: "switched agent" });
|
|
150
|
+
const closeOldActivity = import_vitest.vi.fn(async () => {
|
|
151
|
+
});
|
|
152
|
+
const mockSession = {
|
|
153
|
+
currentAgent: oldAgent,
|
|
154
|
+
_globalRunState: void 0,
|
|
155
|
+
_updateActivity: async (agent) => {
|
|
156
|
+
if (agent === task) {
|
|
157
|
+
mockSession.currentAgent = switchedAgent;
|
|
158
|
+
task.complete("ok");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const mockActivity = {
|
|
163
|
+
agent: oldAgent,
|
|
164
|
+
agentSession: mockSession,
|
|
165
|
+
_onEnterTask: void 0,
|
|
166
|
+
llm: void 0,
|
|
167
|
+
close: closeOldActivity
|
|
168
|
+
};
|
|
169
|
+
const wrapper = import_utils.Task.from(async () => {
|
|
170
|
+
const currentTask = import_utils.Task.current();
|
|
171
|
+
if (!currentTask) {
|
|
172
|
+
throw new Error("expected task context");
|
|
173
|
+
}
|
|
174
|
+
(0, import_agent._setActivityTaskInfo)(currentTask, { inlineTask: true });
|
|
175
|
+
return await import_agent_activity.agentActivityStorage.run(mockActivity, () => task.run());
|
|
176
|
+
});
|
|
177
|
+
await (0, import_vitest.expect)(wrapper.result).resolves.toBe("ok");
|
|
178
|
+
(0, import_vitest.expect)(closeOldActivity).toHaveBeenCalledTimes(1);
|
|
179
|
+
});
|
|
60
180
|
});
|
|
61
181
|
//# 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 } from 'vitest';\nimport { z } from 'zod';\nimport { tool } from '../llm/index.js';\nimport { Agent } from './agent.js';\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"],"mappings":";AAGA,oBAAqC;AACrC,iBAAkB;AAClB,iBAAqB;AACrB,mBAAsB;AAAA,IAEtB,wBAAS,SAAS,MAAM;AACtB,wBAAG,+CAA+C,MAAM;AACtD,UAAM,eAAe;AACrB,UAAM,QAAQ,IAAI,mBAAM,EAAE,aAAa,CAAC;AAExC,8BAAO,KAAK,EAAE,YAAY;AAC1B,8BAAO,MAAM,YAAY,EAAE,KAAK,YAAY;AAAA,EAC9C,CAAC;AAED,wBAAG,mDAAmD,MAAM;AAjB9D;AAkBI,UAAM,eAAe;AAGrB,UAAM,gBAAY,iBAAK;AAAA,MACrB,aAAa;AAAA,MACb,YAAY,aAAE,OAAO,CAAC,CAAC;AAAA,MACvB,SAAS,YAAY;AAAA,IACvB,CAAC;AAED,UAAM,gBAAY,iBAAK;AAAA,MACrB,aAAa;AAAA,MACb,YAAY,aAAE,OAAO;AAAA,QACnB,OAAO,aAAE,OAAO,EAAE,SAAS,iBAAiB;AAAA,MAC9C,CAAC;AAAA,MACD,SAAS,OAAO,EAAE,MAAM,MAAM,UAAU,KAAK;AAAA,IAC/C,CAAC;AAED,UAAM,QAAQ,IAAI,mBAAM;AAAA,MACtB;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAED,8BAAO,KAAK,EAAE,YAAY;AAC1B,8BAAO,MAAM,YAAY,EAAE,KAAK,YAAY;AAG5C,UAAM,aAAa,MAAM;AACzB,8BAAO,OAAO,KAAK,UAAU,CAAC,EAAE,aAAa,CAAC;AAC9C,8BAAO,UAAU,EAAE,eAAe,UAAU;AAC5C,8BAAO,UAAU,EAAE,eAAe,UAAU;AAG5C,+BAAO,gBAAW,aAAX,mBAAqB,WAAW,EAAE,KAAK,iBAAiB;AAC/D,+BAAO,gBAAW,aAAX,mBAAqB,WAAW,EAAE,KAAK,kBAAkB;AAAA,EAClE,CAAC;AAED,wBAAG,6DAA6D,MAAM;AACpE,UAAM,eAAe;AACrB,UAAM,eAAW,iBAAK;AAAA,MACpB,aAAa;AAAA,MACb,YAAY,aAAE,OAAO,CAAC,CAAC;AAAA,MACvB,SAAS,YAAY;AAAA,IACvB,CAAC;AAED,UAAM,QAAQ,EAAE,UAAU,SAAS;AACnC,UAAM,QAAQ,IAAI,mBAAM,EAAE,cAAc,MAAM,CAAC;AAE/C,UAAM,SAAS,MAAM;AACrB,UAAM,SAAS,MAAM;AAGrB,8BAAO,MAAM,EAAE,IAAI,KAAK,MAAM;AAC9B,8BAAO,MAAM,EAAE,IAAI,KAAK,KAAK;AAG7B,8BAAO,MAAM,EAAE,QAAQ,MAAM;AAC7B,8BAAO,MAAM,EAAE,QAAQ,KAAK;AAAA,EAC9B,CAAC;AACH,CAAC;","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 { 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":[]}
|