@livekit/agents 1.0.17 → 1.0.19
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/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/inference/api_protos.d.cts +12 -12
- package/dist/inference/api_protos.d.ts +12 -12
- package/dist/inference/llm.cjs +35 -13
- package/dist/inference/llm.cjs.map +1 -1
- package/dist/inference/llm.d.cts +10 -5
- package/dist/inference/llm.d.ts +10 -5
- package/dist/inference/llm.d.ts.map +1 -1
- package/dist/inference/llm.js +35 -13
- package/dist/inference/llm.js.map +1 -1
- package/dist/inference/tts.cjs +1 -1
- package/dist/inference/tts.cjs.map +1 -1
- package/dist/inference/tts.js +1 -1
- package/dist/inference/tts.js.map +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs +6 -2
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +6 -2
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/job.cjs +31 -0
- package/dist/job.cjs.map +1 -1
- package/dist/job.d.cts +6 -0
- package/dist/job.d.ts +6 -0
- package/dist/job.d.ts.map +1 -1
- package/dist/job.js +31 -0
- package/dist/job.js.map +1 -1
- package/dist/llm/chat_context.cjs +33 -0
- package/dist/llm/chat_context.cjs.map +1 -1
- package/dist/llm/chat_context.d.cts +22 -2
- package/dist/llm/chat_context.d.ts +22 -2
- package/dist/llm/chat_context.d.ts.map +1 -1
- package/dist/llm/chat_context.js +32 -0
- package/dist/llm/chat_context.js.map +1 -1
- 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/llm/llm.cjs.map +1 -1
- package/dist/llm/llm.d.cts +1 -1
- package/dist/llm/llm.d.ts +1 -1
- package/dist/llm/llm.d.ts.map +1 -1
- package/dist/llm/llm.js.map +1 -1
- package/dist/llm/provider_format/google.cjs.map +1 -1
- package/dist/llm/provider_format/google.d.cts +1 -1
- package/dist/llm/provider_format/google.d.ts +1 -1
- package/dist/llm/provider_format/google.d.ts.map +1 -1
- package/dist/llm/provider_format/google.js.map +1 -1
- package/dist/llm/provider_format/google.test.cjs +48 -0
- package/dist/llm/provider_format/google.test.cjs.map +1 -1
- package/dist/llm/provider_format/google.test.js +54 -1
- package/dist/llm/provider_format/google.test.js.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/openai.cjs +1 -2
- package/dist/llm/provider_format/openai.cjs.map +1 -1
- package/dist/llm/provider_format/openai.js +1 -2
- package/dist/llm/provider_format/openai.js.map +1 -1
- package/dist/llm/provider_format/openai.test.cjs +32 -0
- package/dist/llm/provider_format/openai.test.cjs.map +1 -1
- package/dist/llm/provider_format/openai.test.js +38 -1
- package/dist/llm/provider_format/openai.test.js.map +1 -1
- package/dist/llm/realtime.cjs.map +1 -1
- package/dist/llm/realtime.d.cts +4 -0
- package/dist/llm/realtime.d.ts +4 -0
- package/dist/llm/realtime.d.ts.map +1 -1
- package/dist/llm/realtime.js.map +1 -1
- package/dist/llm/utils.cjs +2 -2
- package/dist/llm/utils.cjs.map +1 -1
- package/dist/llm/utils.d.cts +1 -1
- package/dist/llm/utils.d.ts +1 -1
- package/dist/llm/utils.d.ts.map +1 -1
- package/dist/llm/utils.js +2 -2
- package/dist/llm/utils.js.map +1 -1
- package/dist/llm/zod-utils.cjs +6 -3
- package/dist/llm/zod-utils.cjs.map +1 -1
- package/dist/llm/zod-utils.d.cts +1 -1
- package/dist/llm/zod-utils.d.ts +1 -1
- package/dist/llm/zod-utils.d.ts.map +1 -1
- package/dist/llm/zod-utils.js +6 -3
- package/dist/llm/zod-utils.js.map +1 -1
- package/dist/llm/zod-utils.test.cjs +83 -0
- package/dist/llm/zod-utils.test.cjs.map +1 -1
- package/dist/llm/zod-utils.test.js +83 -0
- package/dist/llm/zod-utils.test.js.map +1 -1
- package/dist/log.cjs.map +1 -1
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js.map +1 -1
- package/dist/telemetry/index.cjs +51 -0
- package/dist/telemetry/index.cjs.map +1 -0
- package/dist/telemetry/index.d.cts +4 -0
- package/dist/telemetry/index.d.ts +4 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +12 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/trace_types.cjs +191 -0
- package/dist/telemetry/trace_types.cjs.map +1 -0
- package/dist/telemetry/trace_types.d.cts +56 -0
- package/dist/telemetry/trace_types.d.ts +56 -0
- package/dist/telemetry/trace_types.d.ts.map +1 -0
- package/dist/telemetry/trace_types.js +113 -0
- package/dist/telemetry/trace_types.js.map +1 -0
- package/dist/telemetry/traces.cjs +196 -0
- package/dist/telemetry/traces.cjs.map +1 -0
- package/dist/telemetry/traces.d.cts +97 -0
- package/dist/telemetry/traces.d.ts +97 -0
- package/dist/telemetry/traces.d.ts.map +1 -0
- package/dist/telemetry/traces.js +173 -0
- package/dist/telemetry/traces.js.map +1 -0
- package/dist/telemetry/utils.cjs +86 -0
- package/dist/telemetry/utils.cjs.map +1 -0
- package/dist/telemetry/utils.d.cts +5 -0
- package/dist/telemetry/utils.d.ts +5 -0
- package/dist/telemetry/utils.d.ts.map +1 -0
- package/dist/telemetry/utils.js +51 -0
- package/dist/telemetry/utils.js.map +1 -0
- package/dist/tts/tts.cjs.map +1 -1
- package/dist/tts/tts.d.ts.map +1 -1
- package/dist/tts/tts.js.map +1 -1
- 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.map +1 -1
- package/dist/voice/agent.cjs +15 -0
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +4 -1
- package/dist/voice/agent.d.ts +4 -1
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +15 -0
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent_activity.cjs +71 -20
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +71 -20
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +69 -2
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +11 -2
- package/dist/voice/agent_session.d.ts +11 -2
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +70 -3
- package/dist/voice/agent_session.js.map +1 -1
- 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.map +1 -1
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.ts.map +1 -1
- 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 -0
- package/dist/voice/index.d.ts +1 -0
- package/dist/voice/index.d.ts.map +1 -1
- package/dist/voice/index.js +1 -0
- package/dist/voice/index.js.map +1 -1
- package/dist/voice/interruption_detection.test.cjs +114 -0
- package/dist/voice/interruption_detection.test.cjs.map +1 -0
- package/dist/voice/interruption_detection.test.js +113 -0
- package/dist/voice/interruption_detection.test.js.map +1 -0
- package/dist/voice/report.cjs +69 -0
- package/dist/voice/report.cjs.map +1 -0
- package/dist/voice/report.d.cts +26 -0
- package/dist/voice/report.d.ts +26 -0
- package/dist/voice/report.d.ts.map +1 -0
- package/dist/voice/report.js +44 -0
- package/dist/voice/report.js.map +1 -0
- package/dist/voice/room_io/room_io.cjs +3 -0
- package/dist/voice/room_io/room_io.cjs.map +1 -1
- package/dist/voice/room_io/room_io.d.cts +1 -0
- package/dist/voice/room_io/room_io.d.ts +1 -0
- package/dist/voice/room_io/room_io.d.ts.map +1 -1
- package/dist/voice/room_io/room_io.js +3 -0
- package/dist/voice/room_io/room_io.js.map +1 -1
- package/package.json +12 -5
- package/src/index.ts +2 -1
- package/src/inference/llm.ts +53 -21
- package/src/inference/tts.ts +1 -1
- package/src/ipc/job_proc_lazy_main.ts +10 -2
- package/src/job.ts +48 -0
- package/src/llm/__snapshots__/zod-utils.test.ts.snap +218 -0
- package/src/llm/chat_context.ts +53 -1
- package/src/llm/index.ts +1 -0
- package/src/llm/llm.ts +3 -1
- package/src/llm/provider_format/google.test.ts +72 -1
- package/src/llm/provider_format/google.ts +4 -4
- package/src/llm/provider_format/openai.test.ts +55 -1
- package/src/llm/provider_format/openai.ts +3 -2
- package/src/llm/realtime.ts +8 -1
- package/src/llm/utils.ts +7 -2
- package/src/llm/zod-utils.test.ts +101 -0
- package/src/llm/zod-utils.ts +12 -3
- package/src/log.ts +1 -0
- package/src/telemetry/index.ts +10 -0
- package/src/telemetry/trace_types.ts +88 -0
- package/src/telemetry/traces.ts +266 -0
- package/src/telemetry/utils.ts +61 -0
- package/src/tts/tts.ts +4 -0
- package/src/utils.ts +17 -0
- package/src/voice/agent.ts +22 -0
- package/src/voice/agent_activity.ts +102 -24
- package/src/voice/agent_session.ts +98 -1
- package/src/voice/audio_recognition.ts +2 -0
- package/src/voice/generation.ts +3 -0
- package/src/voice/index.ts +1 -0
- package/src/voice/interruption_detection.test.ts +151 -0
- package/src/voice/report.ts +77 -0
- package/src/voice/room_io/room_io.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/agents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "LiveKit Agents - Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"require": "dist/index.cjs",
|
|
@@ -39,21 +39,28 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
41
41
|
"@livekit/mutex": "^1.1.1",
|
|
42
|
-
"@livekit/protocol": "^1.
|
|
42
|
+
"@livekit/protocol": "^1.43.0",
|
|
43
43
|
"@livekit/typed-emitter": "^3.0.0",
|
|
44
|
+
"@opentelemetry/api": "^1.9.0",
|
|
45
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.54.0",
|
|
46
|
+
"@opentelemetry/otlp-exporter-base": "^0.208.0",
|
|
47
|
+
"@opentelemetry/resources": "^1.28.0",
|
|
48
|
+
"@opentelemetry/sdk-trace-base": "^1.28.0",
|
|
49
|
+
"@opentelemetry/sdk-trace-node": "^1.28.0",
|
|
50
|
+
"@opentelemetry/semantic-conventions": "^1.28.0",
|
|
44
51
|
"@types/pidusage": "^2.0.5",
|
|
45
52
|
"commander": "^12.0.0",
|
|
46
53
|
"fluent-ffmpeg": "^2.1.3",
|
|
47
54
|
"heap-js": "^2.6.0",
|
|
48
55
|
"json-schema": "^0.4.0",
|
|
49
|
-
"livekit-server-sdk": "^2.
|
|
50
|
-
"openai": "^
|
|
56
|
+
"livekit-server-sdk": "^2.14.1",
|
|
57
|
+
"openai": "^6.8.1",
|
|
51
58
|
"pidusage": "^4.0.1",
|
|
52
59
|
"pino": "^8.19.0",
|
|
53
60
|
"pino-pretty": "^11.0.0",
|
|
54
61
|
"sharp": "0.34.3",
|
|
55
62
|
"uuid": "^11.1.0",
|
|
56
|
-
"ws": "^8.
|
|
63
|
+
"ws": "^8.18.0",
|
|
57
64
|
"zod-to-json-schema": "^3.24.6"
|
|
58
65
|
},
|
|
59
66
|
"peerDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import * as llm from './llm/index.js';
|
|
|
16
16
|
import * as metrics from './metrics/index.js';
|
|
17
17
|
import * as stream from './stream/index.js';
|
|
18
18
|
import * as stt from './stt/index.js';
|
|
19
|
+
import * as telemetry from './telemetry/index.js';
|
|
19
20
|
import * as tokenize from './tokenize/index.js';
|
|
20
21
|
import * as tts from './tts/index.js';
|
|
21
22
|
import * as voice from './voice/index.js';
|
|
@@ -34,4 +35,4 @@ export * from './vad.js';
|
|
|
34
35
|
export * from './version.js';
|
|
35
36
|
export * from './worker.js';
|
|
36
37
|
|
|
37
|
-
export { cli, inference, ipc, llm, metrics, stream, stt, tokenize, tts, voice };
|
|
38
|
+
export { cli, inference, ipc, llm, metrics, stream, stt, telemetry, tokenize, tts, voice };
|
package/src/inference/llm.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
APIStatusError,
|
|
8
8
|
APITimeoutError,
|
|
9
9
|
DEFAULT_API_CONNECT_OPTIONS,
|
|
10
|
+
type Expand,
|
|
10
11
|
toError,
|
|
11
12
|
} from '../index.js';
|
|
12
13
|
import * as llm from '../llm/index.js';
|
|
@@ -34,9 +35,10 @@ export type KimiModels = 'moonshotai/kimi-k2-instruct';
|
|
|
34
35
|
|
|
35
36
|
export type DeepSeekModels = 'deepseek-ai/deepseek-v3';
|
|
36
37
|
|
|
37
|
-
type ChatCompletionPredictionContentParam =
|
|
38
|
-
|
|
39
|
-
type
|
|
38
|
+
type ChatCompletionPredictionContentParam =
|
|
39
|
+
Expand<OpenAI.Chat.Completions.ChatCompletionPredictionContent>;
|
|
40
|
+
type WebSearchOptions = Expand<OpenAI.Chat.Completions.ChatCompletionCreateParams.WebSearchOptions>;
|
|
41
|
+
type ToolChoice = Expand<OpenAI.Chat.Completions.ChatCompletionCreateParams['tool_choice']>;
|
|
40
42
|
type Verbosity = 'low' | 'medium' | 'high';
|
|
41
43
|
|
|
42
44
|
export interface ChatCompletionOptions extends Record<string, unknown> {
|
|
@@ -86,6 +88,7 @@ export interface InferenceLLMOptions {
|
|
|
86
88
|
apiKey: string;
|
|
87
89
|
apiSecret: string;
|
|
88
90
|
modelOptions: ChatCompletionOptions;
|
|
91
|
+
strictToolSchema?: boolean;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
export interface GatewayOptions {
|
|
@@ -107,10 +110,19 @@ export class LLM extends llm.LLM {
|
|
|
107
110
|
apiKey?: string;
|
|
108
111
|
apiSecret?: string;
|
|
109
112
|
modelOptions?: InferenceLLMOptions['modelOptions'];
|
|
113
|
+
strictToolSchema?: boolean;
|
|
110
114
|
}) {
|
|
111
115
|
super();
|
|
112
116
|
|
|
113
|
-
const {
|
|
117
|
+
const {
|
|
118
|
+
model,
|
|
119
|
+
provider,
|
|
120
|
+
baseURL,
|
|
121
|
+
apiKey,
|
|
122
|
+
apiSecret,
|
|
123
|
+
modelOptions,
|
|
124
|
+
strictToolSchema = false,
|
|
125
|
+
} = opts;
|
|
114
126
|
|
|
115
127
|
const lkBaseURL = baseURL || process.env.LIVEKIT_INFERENCE_URL || DEFAULT_BASE_URL;
|
|
116
128
|
const lkApiKey = apiKey || process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY;
|
|
@@ -131,6 +143,7 @@ export class LLM extends llm.LLM {
|
|
|
131
143
|
apiKey: lkApiKey,
|
|
132
144
|
apiSecret: lkApiSecret,
|
|
133
145
|
modelOptions: modelOptions || {},
|
|
146
|
+
strictToolSchema,
|
|
134
147
|
};
|
|
135
148
|
|
|
136
149
|
this.client = new OpenAI({
|
|
@@ -180,9 +193,13 @@ export class LLM extends llm.LLM {
|
|
|
180
193
|
modelOptions.parallel_tool_calls = parallelToolCalls;
|
|
181
194
|
}
|
|
182
195
|
|
|
183
|
-
toolChoice =
|
|
196
|
+
toolChoice =
|
|
197
|
+
toolChoice !== undefined
|
|
198
|
+
? toolChoice
|
|
199
|
+
: (this.opts.modelOptions.tool_choice as llm.ToolChoice | undefined);
|
|
200
|
+
|
|
184
201
|
if (toolChoice) {
|
|
185
|
-
modelOptions.tool_choice = toolChoice;
|
|
202
|
+
modelOptions.tool_choice = toolChoice as ToolChoice;
|
|
186
203
|
}
|
|
187
204
|
|
|
188
205
|
// TODO(AJS-270): Add response_format support here
|
|
@@ -197,6 +214,7 @@ export class LLM extends llm.LLM {
|
|
|
197
214
|
toolCtx,
|
|
198
215
|
connOptions,
|
|
199
216
|
modelOptions,
|
|
217
|
+
strictToolSchema: this.opts.strictToolSchema ?? false, // default to false if not set
|
|
200
218
|
gatewayOptions: {
|
|
201
219
|
apiKey: this.opts.apiKey,
|
|
202
220
|
apiSecret: this.opts.apiSecret,
|
|
@@ -211,6 +229,7 @@ export class LLMStream extends llm.LLMStream {
|
|
|
211
229
|
private providerFmt: llm.ProviderFormat;
|
|
212
230
|
private client: OpenAI;
|
|
213
231
|
private modelOptions: Record<string, unknown>;
|
|
232
|
+
private strictToolSchema: boolean;
|
|
214
233
|
|
|
215
234
|
private gatewayOptions?: GatewayOptions;
|
|
216
235
|
private toolCallId?: string;
|
|
@@ -230,6 +249,7 @@ export class LLMStream extends llm.LLMStream {
|
|
|
230
249
|
connOptions,
|
|
231
250
|
modelOptions,
|
|
232
251
|
providerFmt,
|
|
252
|
+
strictToolSchema,
|
|
233
253
|
}: {
|
|
234
254
|
model: LLMModels;
|
|
235
255
|
provider?: string;
|
|
@@ -238,8 +258,9 @@ export class LLMStream extends llm.LLMStream {
|
|
|
238
258
|
toolCtx?: llm.ToolContext;
|
|
239
259
|
gatewayOptions?: GatewayOptions;
|
|
240
260
|
connOptions: APIConnectOptions;
|
|
241
|
-
modelOptions: Record<string,
|
|
261
|
+
modelOptions: Record<string, unknown>;
|
|
242
262
|
providerFmt?: llm.ProviderFormat;
|
|
263
|
+
strictToolSchema: boolean;
|
|
243
264
|
},
|
|
244
265
|
) {
|
|
245
266
|
super(llm, { chatCtx, toolCtx, connOptions });
|
|
@@ -249,6 +270,7 @@ export class LLMStream extends llm.LLMStream {
|
|
|
249
270
|
this.providerFmt = providerFmt || 'openai';
|
|
250
271
|
this.modelOptions = modelOptions;
|
|
251
272
|
this.model = model;
|
|
273
|
+
this.strictToolSchema = strictToolSchema;
|
|
252
274
|
}
|
|
253
275
|
|
|
254
276
|
protected async run(): Promise<void> {
|
|
@@ -263,16 +285,26 @@ export class LLMStream extends llm.LLMStream {
|
|
|
263
285
|
)) as OpenAI.ChatCompletionMessageParam[];
|
|
264
286
|
|
|
265
287
|
const tools = this.toolCtx
|
|
266
|
-
? Object.entries(this.toolCtx).map(([name, func]) =>
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
288
|
+
? Object.entries(this.toolCtx).map(([name, func]) => {
|
|
289
|
+
const oaiParams = {
|
|
290
|
+
type: 'function' as const,
|
|
291
|
+
function: {
|
|
292
|
+
name,
|
|
293
|
+
description: func.description,
|
|
294
|
+
parameters: llm.toJsonSchema(
|
|
295
|
+
func.parameters,
|
|
296
|
+
true,
|
|
297
|
+
this.strictToolSchema,
|
|
298
|
+
) as unknown as OpenAI.Chat.Completions.ChatCompletionFunctionTool['function']['parameters'],
|
|
299
|
+
} as OpenAI.Chat.Completions.ChatCompletionFunctionTool['function'],
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
if (this.strictToolSchema) {
|
|
303
|
+
oaiParams.function.strict = true;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return oaiParams;
|
|
307
|
+
})
|
|
276
308
|
: undefined;
|
|
277
309
|
|
|
278
310
|
const requestOptions: Record<string, unknown> = { ...this.modelOptions };
|
|
@@ -345,7 +377,7 @@ export class LLMStream extends llm.LLMStream {
|
|
|
345
377
|
options: {
|
|
346
378
|
statusCode: error.status,
|
|
347
379
|
body: error.error,
|
|
348
|
-
requestId: error.
|
|
380
|
+
requestId: error.requestID,
|
|
349
381
|
retryable,
|
|
350
382
|
},
|
|
351
383
|
});
|
|
@@ -387,10 +419,10 @@ export class LLMStream extends llm.LLMStream {
|
|
|
387
419
|
*
|
|
388
420
|
* Choice(delta=ChoiceDelta(content=None, function_call=None, refusal=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)
|
|
389
421
|
* [ChoiceDeltaToolCall(index=0, id='call_LaVeHWUHpef9K1sd5UO8TtLg', function=ChoiceDeltaToolCallFunction(arguments='', name='get_weather'), type='function')]
|
|
390
|
-
* [ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='{"location": "P', name=None), type=None)]
|
|
391
|
-
* [ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='aris}', name=None), type=None)]
|
|
422
|
+
* [ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='\{"location": "P', name=None), type=None)]
|
|
423
|
+
* [ChoiceDeltaToolCall(index=0, id=None, function=ChoiceDeltaToolCallFunction(arguments='aris\}', name=None), type=None)]
|
|
392
424
|
* [ChoiceDeltaToolCall(index=1, id='call_ThU4OmMdQXnnVmpXGOCknXIB', function=ChoiceDeltaToolCallFunction(arguments='', name='get_weather'), type='function')]
|
|
393
|
-
* [ChoiceDeltaToolCall(index=1, id=None, function=ChoiceDeltaToolCallFunction(arguments='{"location": "T', name=None), type=None)]
|
|
425
|
+
* [ChoiceDeltaToolCall(index=1, id=None, function=ChoiceDeltaToolCallFunction(arguments='\{"location": "T', name=None), type=None)]
|
|
394
426
|
* [ChoiceDeltaToolCall(index=1, id=None, function=ChoiceDeltaToolCallFunction(arguments='okyo', name=None), type=None)]
|
|
395
427
|
* Choice(delta=ChoiceDelta(content=None, function_call=None, refusal=None, role=None, tool_calls=None), finish_reason='tool_calls', index=0, logprobs=None)
|
|
396
428
|
*/
|
package/src/inference/tts.ts
CHANGED
|
@@ -421,7 +421,7 @@ export class SynthesizeStream<TModel extends TTSModels> extends BaseSynthesizeSt
|
|
|
421
421
|
createRecvTask(),
|
|
422
422
|
]);
|
|
423
423
|
} catch (e) {
|
|
424
|
-
this.#logger.error(
|
|
424
|
+
this.#logger.error({ error: e }, 'Error in SynthesizeStream');
|
|
425
425
|
} finally {
|
|
426
426
|
resourceCleanup();
|
|
427
427
|
}
|
|
@@ -88,7 +88,7 @@ const startJob = (
|
|
|
88
88
|
|
|
89
89
|
const ctx = new JobContext(proc, info, room, onConnect, onShutdown, new InfClient());
|
|
90
90
|
|
|
91
|
-
const task =
|
|
91
|
+
const task = (async () => {
|
|
92
92
|
const unconnectedTimeout = setTimeout(() => {
|
|
93
93
|
if (!(connect || shutdown)) {
|
|
94
94
|
logger.warn(
|
|
@@ -109,6 +109,14 @@ const startJob = (
|
|
|
109
109
|
process.send!({ case: 'exiting', value: { reason: close[1] } });
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
+
// Close the primary agent session if it exists
|
|
113
|
+
if (ctx._primaryAgentSession) {
|
|
114
|
+
await ctx._primaryAgentSession.close();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Generate and save/upload session report
|
|
118
|
+
await ctx._onSessionEnd();
|
|
119
|
+
|
|
112
120
|
await room.disconnect();
|
|
113
121
|
logger.debug('disconnected from room');
|
|
114
122
|
|
|
@@ -122,7 +130,7 @@ const startJob = (
|
|
|
122
130
|
|
|
123
131
|
process.send!({ case: 'done' });
|
|
124
132
|
joinFuture.resolve();
|
|
125
|
-
});
|
|
133
|
+
})();
|
|
126
134
|
|
|
127
135
|
return { ctx, task };
|
|
128
136
|
};
|
package/src/job.ts
CHANGED
|
@@ -14,6 +14,8 @@ import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
14
14
|
import type { Logger } from 'pino';
|
|
15
15
|
import type { InferenceExecutor } from './ipc/inference_executor.js';
|
|
16
16
|
import { log } from './log.js';
|
|
17
|
+
import type { AgentSession } from './voice/agent_session.js';
|
|
18
|
+
import { type SessionReport, createSessionReport } from './voice/report.js';
|
|
17
19
|
|
|
18
20
|
// AsyncLocalStorage for job context, similar to Python's contextvars
|
|
19
21
|
const jobContextStorage = new AsyncLocalStorage<JobContext>();
|
|
@@ -79,6 +81,8 @@ export class FunctionExistsError extends Error {
|
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
/** The job and environment context as seen by the agent, accessible by the entrypoint function. */
|
|
84
|
+
// TODO(brian): PR3 - Add @tracer.startActiveSpan('job_entrypoint') wrapper in entrypoint
|
|
85
|
+
// TODO(brian): PR5 - Add uploadSessionReport() call in cleanup/session end
|
|
82
86
|
export class JobContext {
|
|
83
87
|
#proc: JobProcess;
|
|
84
88
|
#info: RunningJobInfo;
|
|
@@ -97,6 +101,9 @@ export class JobContext {
|
|
|
97
101
|
#logger: Logger;
|
|
98
102
|
#inferenceExecutor: InferenceExecutor;
|
|
99
103
|
|
|
104
|
+
/** @internal */
|
|
105
|
+
_primaryAgentSession?: AgentSession;
|
|
106
|
+
|
|
100
107
|
private connected: boolean = false;
|
|
101
108
|
|
|
102
109
|
constructor(
|
|
@@ -232,6 +239,47 @@ export class JobContext {
|
|
|
232
239
|
this.connected = true;
|
|
233
240
|
}
|
|
234
241
|
|
|
242
|
+
makeSessionReport(session?: AgentSession): SessionReport {
|
|
243
|
+
const targetSession = session || this._primaryAgentSession;
|
|
244
|
+
|
|
245
|
+
if (!targetSession) {
|
|
246
|
+
throw new Error('Cannot prepare report, no AgentSession was found');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// TODO(brian): implement and check recorder io
|
|
250
|
+
// TODO(brian): PR5 - Ensure chat history serialization includes all required fields (use sessionReportToJSON helper)
|
|
251
|
+
|
|
252
|
+
return createSessionReport({
|
|
253
|
+
jobId: this.job.id,
|
|
254
|
+
roomId: this.job.room?.sid || '',
|
|
255
|
+
room: this.job.room?.name || '',
|
|
256
|
+
options: targetSession.options,
|
|
257
|
+
events: targetSession._recordedEvents,
|
|
258
|
+
enableUserDataTraining: true,
|
|
259
|
+
chatHistory: targetSession.history.copy(),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async _onSessionEnd(): Promise<void> {
|
|
264
|
+
const session = this._primaryAgentSession;
|
|
265
|
+
if (!session) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const report = this.makeSessionReport(session);
|
|
270
|
+
|
|
271
|
+
// TODO(brian): Implement CLI/console
|
|
272
|
+
|
|
273
|
+
// TODO(brian): PR5 - Call uploadSessionReport() if report.enableUserDataTraining is true
|
|
274
|
+
// TODO(brian): PR5 - Upload includes: multipart form with header (protobuf), chat_history (JSON), and audio recording (if available)
|
|
275
|
+
|
|
276
|
+
this.#logger.debug('Session ended, report generated', {
|
|
277
|
+
jobId: report.jobId,
|
|
278
|
+
roomId: report.roomId,
|
|
279
|
+
eventsCount: report.events.length,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
235
283
|
/**
|
|
236
284
|
* Gracefully shuts down the job, and runs all shutdown promises.
|
|
237
285
|
*
|
|
@@ -339,3 +339,221 @@ exports[`Zod Utils > zodSchemaToJsonSchema > Zod v4 schemas > should handle v4 s
|
|
|
339
339
|
"type": "object",
|
|
340
340
|
}
|
|
341
341
|
`;
|
|
342
|
+
|
|
343
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should handle arrays in strict mode 1`] = `
|
|
344
|
+
{
|
|
345
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
346
|
+
"additionalProperties": false,
|
|
347
|
+
"properties": {
|
|
348
|
+
"numbers": {
|
|
349
|
+
"items": {
|
|
350
|
+
"type": "number",
|
|
351
|
+
},
|
|
352
|
+
"type": "array",
|
|
353
|
+
},
|
|
354
|
+
"tags": {
|
|
355
|
+
"items": {
|
|
356
|
+
"type": "string",
|
|
357
|
+
},
|
|
358
|
+
"type": "array",
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
"required": [
|
|
362
|
+
"tags",
|
|
363
|
+
"numbers",
|
|
364
|
+
],
|
|
365
|
+
"type": "object",
|
|
366
|
+
}
|
|
367
|
+
`;
|
|
368
|
+
|
|
369
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should handle default values in strict mode 1`] = `
|
|
370
|
+
{
|
|
371
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
372
|
+
"additionalProperties": false,
|
|
373
|
+
"properties": {
|
|
374
|
+
"active": {
|
|
375
|
+
"default": true,
|
|
376
|
+
"type": "boolean",
|
|
377
|
+
},
|
|
378
|
+
"name": {
|
|
379
|
+
"type": "string",
|
|
380
|
+
},
|
|
381
|
+
"role": {
|
|
382
|
+
"default": "user",
|
|
383
|
+
"type": "string",
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
"required": [
|
|
387
|
+
"name",
|
|
388
|
+
"role",
|
|
389
|
+
"active",
|
|
390
|
+
],
|
|
391
|
+
"type": "object",
|
|
392
|
+
}
|
|
393
|
+
`;
|
|
394
|
+
|
|
395
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should handle nested objects in strict mode 1`] = `
|
|
396
|
+
{
|
|
397
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
398
|
+
"additionalProperties": false,
|
|
399
|
+
"properties": {
|
|
400
|
+
"metadata": {
|
|
401
|
+
"additionalProperties": false,
|
|
402
|
+
"properties": {
|
|
403
|
+
"created": {
|
|
404
|
+
"type": "string",
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
"required": [
|
|
408
|
+
"created",
|
|
409
|
+
],
|
|
410
|
+
"type": "object",
|
|
411
|
+
},
|
|
412
|
+
"user": {
|
|
413
|
+
"additionalProperties": false,
|
|
414
|
+
"properties": {
|
|
415
|
+
"email": {
|
|
416
|
+
"anyOf": [
|
|
417
|
+
{
|
|
418
|
+
"type": "string",
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
"type": "null",
|
|
422
|
+
},
|
|
423
|
+
],
|
|
424
|
+
},
|
|
425
|
+
"name": {
|
|
426
|
+
"type": "string",
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
"required": [
|
|
430
|
+
"name",
|
|
431
|
+
"email",
|
|
432
|
+
],
|
|
433
|
+
"type": "object",
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
"required": [
|
|
437
|
+
"user",
|
|
438
|
+
"metadata",
|
|
439
|
+
],
|
|
440
|
+
"type": "object",
|
|
441
|
+
}
|
|
442
|
+
`;
|
|
443
|
+
|
|
444
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should handle nullable fields in strict mode 1`] = `
|
|
445
|
+
{
|
|
446
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
447
|
+
"additionalProperties": false,
|
|
448
|
+
"properties": {
|
|
449
|
+
"optional": {
|
|
450
|
+
"anyOf": [
|
|
451
|
+
{
|
|
452
|
+
"type": "string",
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"type": "null",
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
},
|
|
459
|
+
"required": {
|
|
460
|
+
"type": "string",
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
"required": [
|
|
464
|
+
"required",
|
|
465
|
+
"optional",
|
|
466
|
+
],
|
|
467
|
+
"type": "object",
|
|
468
|
+
}
|
|
469
|
+
`;
|
|
470
|
+
|
|
471
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should handle optional fields in strict mode 1`] = `
|
|
472
|
+
{
|
|
473
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
474
|
+
"additionalProperties": false,
|
|
475
|
+
"properties": {
|
|
476
|
+
"optional": {
|
|
477
|
+
"anyOf": [
|
|
478
|
+
{
|
|
479
|
+
"type": "string",
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"type": "null",
|
|
483
|
+
},
|
|
484
|
+
],
|
|
485
|
+
},
|
|
486
|
+
"required": {
|
|
487
|
+
"type": "string",
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
"required": [
|
|
491
|
+
"required",
|
|
492
|
+
"optional",
|
|
493
|
+
],
|
|
494
|
+
"type": "object",
|
|
495
|
+
}
|
|
496
|
+
`;
|
|
497
|
+
|
|
498
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should handle v3 schemas in strict mode 1`] = `
|
|
499
|
+
{
|
|
500
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema#",
|
|
501
|
+
"additionalProperties": false,
|
|
502
|
+
"properties": {
|
|
503
|
+
"age": {
|
|
504
|
+
"type": [
|
|
505
|
+
"number",
|
|
506
|
+
"null",
|
|
507
|
+
],
|
|
508
|
+
},
|
|
509
|
+
"name": {
|
|
510
|
+
"type": "string",
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
"required": [
|
|
514
|
+
"name",
|
|
515
|
+
"age",
|
|
516
|
+
],
|
|
517
|
+
"type": "object",
|
|
518
|
+
}
|
|
519
|
+
`;
|
|
520
|
+
|
|
521
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should produce standard JSON schema with strict: false 1`] = `
|
|
522
|
+
{
|
|
523
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
524
|
+
"additionalProperties": false,
|
|
525
|
+
"properties": {
|
|
526
|
+
"age": {
|
|
527
|
+
"type": "number",
|
|
528
|
+
},
|
|
529
|
+
"name": {
|
|
530
|
+
"type": "string",
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
"required": [
|
|
534
|
+
"name",
|
|
535
|
+
"age",
|
|
536
|
+
],
|
|
537
|
+
"type": "object",
|
|
538
|
+
}
|
|
539
|
+
`;
|
|
540
|
+
|
|
541
|
+
exports[`Zod Utils > zodSchemaToJsonSchema > strict parameter > should produce strict JSON schema with strict: true 1`] = `
|
|
542
|
+
{
|
|
543
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
544
|
+
"additionalProperties": false,
|
|
545
|
+
"properties": {
|
|
546
|
+
"age": {
|
|
547
|
+
"type": "number",
|
|
548
|
+
},
|
|
549
|
+
"name": {
|
|
550
|
+
"type": "string",
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
"required": [
|
|
554
|
+
"name",
|
|
555
|
+
"age",
|
|
556
|
+
],
|
|
557
|
+
"type": "object",
|
|
558
|
+
}
|
|
559
|
+
`;
|
package/src/llm/chat_context.ts
CHANGED
|
@@ -300,7 +300,59 @@ export class FunctionCallOutput {
|
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
|
|
303
|
-
export
|
|
303
|
+
export class AgentHandoffItem {
|
|
304
|
+
readonly id: string;
|
|
305
|
+
|
|
306
|
+
readonly type = 'agent_handoff' as const;
|
|
307
|
+
|
|
308
|
+
oldAgentId: string | undefined;
|
|
309
|
+
|
|
310
|
+
newAgentId: string;
|
|
311
|
+
|
|
312
|
+
createdAt: number;
|
|
313
|
+
|
|
314
|
+
constructor(params: {
|
|
315
|
+
oldAgentId?: string;
|
|
316
|
+
newAgentId: string;
|
|
317
|
+
id?: string;
|
|
318
|
+
createdAt?: number;
|
|
319
|
+
}) {
|
|
320
|
+
const { oldAgentId, newAgentId, id = shortuuid('item_'), createdAt = Date.now() } = params;
|
|
321
|
+
this.id = id;
|
|
322
|
+
this.oldAgentId = oldAgentId;
|
|
323
|
+
this.newAgentId = newAgentId;
|
|
324
|
+
this.createdAt = createdAt;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
static create(params: {
|
|
328
|
+
oldAgentId?: string;
|
|
329
|
+
newAgentId: string;
|
|
330
|
+
id?: string;
|
|
331
|
+
createdAt?: number;
|
|
332
|
+
}) {
|
|
333
|
+
return new AgentHandoffItem(params);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
toJSON(excludeTimestamp: boolean = false): JSONValue {
|
|
337
|
+
const result: JSONValue = {
|
|
338
|
+
id: this.id,
|
|
339
|
+
type: this.type,
|
|
340
|
+
newAgentId: this.newAgentId,
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
if (this.oldAgentId !== undefined) {
|
|
344
|
+
result.oldAgentId = this.oldAgentId;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (!excludeTimestamp) {
|
|
348
|
+
result.createdAt = this.createdAt;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return result;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export type ChatItem = ChatMessage | FunctionCall | FunctionCallOutput | AgentHandoffItem;
|
|
304
356
|
|
|
305
357
|
export class ChatContext {
|
|
306
358
|
protected _items: ChatItem[];
|
package/src/llm/index.ts
CHANGED
package/src/llm/llm.ts
CHANGED
|
@@ -78,7 +78,7 @@ export abstract class LLM extends (EventEmitter as new () => TypedEmitter<LLMCal
|
|
|
78
78
|
connOptions?: APIConnectOptions;
|
|
79
79
|
parallelToolCalls?: boolean;
|
|
80
80
|
toolChoice?: ToolChoice;
|
|
81
|
-
extraKwargs?: Record<string,
|
|
81
|
+
extraKwargs?: Record<string, unknown>;
|
|
82
82
|
}): LLMStream;
|
|
83
83
|
|
|
84
84
|
/**
|
|
@@ -136,8 +136,10 @@ export abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
private async mainTask() {
|
|
139
|
+
// TODO(brian): PR3 - Add span wrapping: tracer.startActiveSpan('llm_request', ..., { endOnExit: false })
|
|
139
140
|
for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {
|
|
140
141
|
try {
|
|
142
|
+
// TODO(brian): PR3 - Add span for retry attempts: tracer.startActiveSpan('llm_request_run', ...)
|
|
141
143
|
return await this.run();
|
|
142
144
|
} catch (error) {
|
|
143
145
|
if (error instanceof APIError) {
|