@livekit/agents 1.0.21 → 1.0.23
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/inference/api_protos.cjs +2 -2
- package/dist/inference/api_protos.cjs.map +1 -1
- package/dist/inference/api_protos.d.cts +16 -16
- package/dist/inference/api_protos.d.ts +16 -16
- package/dist/inference/api_protos.js +2 -2
- package/dist/inference/api_protos.js.map +1 -1
- package/dist/inference/stt.cjs +42 -30
- package/dist/inference/stt.cjs.map +1 -1
- package/dist/inference/stt.d.ts.map +1 -1
- package/dist/inference/stt.js +42 -30
- package/dist/inference/stt.js.map +1 -1
- package/dist/inference/tts.cjs +2 -3
- package/dist/inference/tts.cjs.map +1 -1
- package/dist/inference/tts.d.ts.map +1 -1
- package/dist/inference/tts.js +2 -3
- package/dist/inference/tts.js.map +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs +35 -1
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +13 -1
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/job.cjs +52 -6
- package/dist/job.cjs.map +1 -1
- package/dist/job.d.cts +2 -0
- package/dist/job.d.ts +2 -0
- package/dist/job.d.ts.map +1 -1
- package/dist/job.js +52 -6
- package/dist/job.js.map +1 -1
- package/dist/llm/llm.cjs +38 -3
- package/dist/llm/llm.cjs.map +1 -1
- package/dist/llm/llm.d.cts +1 -0
- package/dist/llm/llm.d.ts +1 -0
- package/dist/llm/llm.d.ts.map +1 -1
- package/dist/llm/llm.js +38 -3
- package/dist/llm/llm.js.map +1 -1
- package/dist/log.cjs +34 -10
- package/dist/log.cjs.map +1 -1
- package/dist/log.d.cts +7 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +34 -11
- package/dist/log.js.map +1 -1
- package/dist/stt/stt.cjs +18 -5
- package/dist/stt/stt.cjs.map +1 -1
- package/dist/stt/stt.d.ts.map +1 -1
- package/dist/stt/stt.js +18 -5
- package/dist/stt/stt.js.map +1 -1
- package/dist/telemetry/index.cjs +23 -2
- package/dist/telemetry/index.cjs.map +1 -1
- package/dist/telemetry/index.d.cts +4 -1
- package/dist/telemetry/index.d.ts +4 -1
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/index.js +27 -2
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/logging.cjs +65 -0
- package/dist/telemetry/logging.cjs.map +1 -0
- package/dist/telemetry/logging.d.cts +21 -0
- package/dist/telemetry/logging.d.ts +21 -0
- package/dist/telemetry/logging.d.ts.map +1 -0
- package/dist/telemetry/logging.js +40 -0
- package/dist/telemetry/logging.js.map +1 -0
- package/dist/telemetry/otel_http_exporter.cjs +144 -0
- package/dist/telemetry/otel_http_exporter.cjs.map +1 -0
- package/dist/telemetry/otel_http_exporter.d.cts +62 -0
- package/dist/telemetry/otel_http_exporter.d.ts +62 -0
- package/dist/telemetry/otel_http_exporter.d.ts.map +1 -0
- package/dist/telemetry/otel_http_exporter.js +120 -0
- package/dist/telemetry/otel_http_exporter.js.map +1 -0
- package/dist/telemetry/pino_otel_transport.cjs +217 -0
- package/dist/telemetry/pino_otel_transport.cjs.map +1 -0
- package/dist/telemetry/pino_otel_transport.d.cts +58 -0
- package/dist/telemetry/pino_otel_transport.d.ts +58 -0
- package/dist/telemetry/pino_otel_transport.d.ts.map +1 -0
- package/dist/telemetry/pino_otel_transport.js +189 -0
- package/dist/telemetry/pino_otel_transport.js.map +1 -0
- package/dist/telemetry/traces.cjs +225 -16
- package/dist/telemetry/traces.cjs.map +1 -1
- package/dist/telemetry/traces.d.cts +17 -0
- package/dist/telemetry/traces.d.ts +17 -0
- package/dist/telemetry/traces.d.ts.map +1 -1
- package/dist/telemetry/traces.js +211 -14
- package/dist/telemetry/traces.js.map +1 -1
- package/dist/tts/tts.cjs +68 -20
- package/dist/tts/tts.cjs.map +1 -1
- package/dist/tts/tts.d.cts +2 -0
- package/dist/tts/tts.d.ts +2 -0
- package/dist/tts/tts.d.ts.map +1 -1
- package/dist/tts/tts.js +68 -20
- package/dist/tts/tts.js.map +1 -1
- package/dist/utils.cjs +6 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +5 -0
- package/dist/utils.js.map +1 -1
- package/dist/voice/agent_activity.cjs +93 -7
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +3 -0
- package/dist/voice/agent_activity.d.ts +3 -0
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +93 -7
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +122 -27
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +15 -0
- package/dist/voice/agent_session.d.ts +15 -0
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +122 -27
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +69 -22
- package/dist/voice/audio_recognition.cjs.map +1 -1
- package/dist/voice/audio_recognition.d.cts +5 -0
- package/dist/voice/audio_recognition.d.ts +5 -0
- package/dist/voice/audio_recognition.d.ts.map +1 -1
- package/dist/voice/audio_recognition.js +69 -22
- package/dist/voice/audio_recognition.js.map +1 -1
- package/dist/voice/generation.cjs +43 -3
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.ts.map +1 -1
- package/dist/voice/generation.js +43 -3
- package/dist/voice/generation.js.map +1 -1
- package/dist/voice/report.cjs +3 -2
- package/dist/voice/report.cjs.map +1 -1
- package/dist/voice/report.d.cts +7 -1
- package/dist/voice/report.d.ts +7 -1
- package/dist/voice/report.d.ts.map +1 -1
- package/dist/voice/report.js +3 -2
- package/dist/voice/report.js.map +1 -1
- package/package.json +8 -2
- package/src/inference/api_protos.ts +2 -2
- package/src/inference/stt.ts +48 -33
- package/src/inference/tts.ts +4 -3
- package/src/ipc/job_proc_lazy_main.ts +12 -1
- package/src/job.ts +59 -10
- package/src/llm/llm.ts +48 -5
- package/src/log.ts +52 -15
- package/src/stt/stt.ts +18 -5
- package/src/telemetry/index.ts +22 -4
- package/src/telemetry/logging.ts +55 -0
- package/src/telemetry/otel_http_exporter.ts +191 -0
- package/src/telemetry/pino_otel_transport.ts +265 -0
- package/src/telemetry/traces.ts +320 -20
- package/src/tts/tts.ts +85 -24
- package/src/utils.ts +5 -0
- package/src/voice/agent_activity.ts +140 -22
- package/src/voice/agent_session.ts +174 -34
- package/src/voice/audio_recognition.ts +85 -26
- package/src/voice/generation.ts +59 -7
- package/src/voice/report.ts +10 -4
package/src/tts/tts.ts
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import type { AudioFrame } from '@livekit/rtc-node';
|
|
5
5
|
import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
|
|
6
|
+
import type { Span } from '@opentelemetry/api';
|
|
6
7
|
import { EventEmitter } from 'node:events';
|
|
7
8
|
import type { ReadableStream } from 'node:stream/web';
|
|
8
9
|
import { APIConnectionError, APIError } from '../_exceptions.js';
|
|
9
10
|
import { log } from '../log.js';
|
|
10
11
|
import type { TTSMetrics } from '../metrics/base.js';
|
|
11
12
|
import { DeferredReadableStream } from '../stream/deferred_stream.js';
|
|
13
|
+
import { recordException, traceTypes, tracer } from '../telemetry/index.js';
|
|
12
14
|
import { type APIConnectOptions, DEFAULT_API_CONNECT_OPTIONS } from '../types.js';
|
|
13
15
|
import { AsyncIterableQueue, delay, mergeFrames, startSoon, toError } from '../utils.js';
|
|
14
16
|
|
|
@@ -134,6 +136,7 @@ export abstract class SynthesizeStream
|
|
|
134
136
|
#monitorMetricsTask?: Promise<void>;
|
|
135
137
|
private _connOptions: APIConnectOptions;
|
|
136
138
|
protected abortController = new AbortController();
|
|
139
|
+
#ttsRequestSpan?: Span;
|
|
137
140
|
|
|
138
141
|
private deferredInputStream: DeferredReadableStream<
|
|
139
142
|
string | typeof SynthesizeStream.FLUSH_SENTINEL
|
|
@@ -160,12 +163,27 @@ export abstract class SynthesizeStream
|
|
|
160
163
|
startSoon(() => this.mainTask().then(() => this.queue.close()));
|
|
161
164
|
}
|
|
162
165
|
|
|
163
|
-
private async
|
|
164
|
-
|
|
166
|
+
private _mainTaskImpl = async (span: Span) => {
|
|
167
|
+
this.#ttsRequestSpan = span;
|
|
168
|
+
span.setAttributes({
|
|
169
|
+
[traceTypes.ATTR_TTS_STREAMING]: true,
|
|
170
|
+
[traceTypes.ATTR_TTS_LABEL]: this.#tts.label,
|
|
171
|
+
});
|
|
172
|
+
|
|
165
173
|
for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {
|
|
166
174
|
try {
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
return await tracer.startActiveSpan(
|
|
176
|
+
async (attemptSpan) => {
|
|
177
|
+
attemptSpan.setAttribute(traceTypes.ATTR_RETRY_COUNT, i);
|
|
178
|
+
try {
|
|
179
|
+
return await this.run();
|
|
180
|
+
} catch (error) {
|
|
181
|
+
recordException(attemptSpan, toError(error));
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{ name: 'tts_request_run' },
|
|
186
|
+
);
|
|
169
187
|
} catch (error) {
|
|
170
188
|
if (error instanceof APIError) {
|
|
171
189
|
const retryInterval = this._connOptions._intervalForRetry(i);
|
|
@@ -197,7 +215,13 @@ export abstract class SynthesizeStream
|
|
|
197
215
|
}
|
|
198
216
|
}
|
|
199
217
|
}
|
|
200
|
-
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
private mainTask = async () =>
|
|
221
|
+
tracer.startActiveSpan(async (span) => this._mainTaskImpl(span), {
|
|
222
|
+
name: 'tts_request',
|
|
223
|
+
endOnExit: false,
|
|
224
|
+
});
|
|
201
225
|
|
|
202
226
|
private emitError({ error, recoverable }: { error: Error; recoverable: boolean }) {
|
|
203
227
|
this.#tts.emit('error', {
|
|
@@ -265,6 +289,9 @@ export abstract class SynthesizeStream
|
|
|
265
289
|
label: this.#tts.label,
|
|
266
290
|
streamed: false,
|
|
267
291
|
};
|
|
292
|
+
if (this.#ttsRequestSpan) {
|
|
293
|
+
this.#ttsRequestSpan.setAttribute(traceTypes.ATTR_TTS_METRICS, JSON.stringify(metrics));
|
|
294
|
+
}
|
|
268
295
|
this.#tts.emit('metrics_collected', metrics);
|
|
269
296
|
}
|
|
270
297
|
};
|
|
@@ -289,6 +316,11 @@ export abstract class SynthesizeStream
|
|
|
289
316
|
if (requestId) {
|
|
290
317
|
emit();
|
|
291
318
|
}
|
|
319
|
+
|
|
320
|
+
if (this.#ttsRequestSpan) {
|
|
321
|
+
this.#ttsRequestSpan.end();
|
|
322
|
+
this.#ttsRequestSpan = undefined;
|
|
323
|
+
}
|
|
292
324
|
}
|
|
293
325
|
|
|
294
326
|
protected abstract run(): Promise<void>;
|
|
@@ -307,12 +339,11 @@ export abstract class SynthesizeStream
|
|
|
307
339
|
}
|
|
308
340
|
this.#metricsText += text;
|
|
309
341
|
|
|
310
|
-
if (this.input.closed) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (this.closed) {
|
|
314
|
-
throw new Error('Stream is closed');
|
|
342
|
+
if (this.input.closed || this.closed) {
|
|
343
|
+
// Stream was aborted/closed, silently skip
|
|
344
|
+
return;
|
|
315
345
|
}
|
|
346
|
+
|
|
316
347
|
this.input.put(text);
|
|
317
348
|
}
|
|
318
349
|
|
|
@@ -322,24 +353,24 @@ export abstract class SynthesizeStream
|
|
|
322
353
|
this.#metricsPendingTexts.push(this.#metricsText);
|
|
323
354
|
this.#metricsText = '';
|
|
324
355
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
throw new Error('Stream is closed');
|
|
356
|
+
|
|
357
|
+
if (this.input.closed || this.closed) {
|
|
358
|
+
// Stream was aborted/closed, silently skip
|
|
359
|
+
return;
|
|
330
360
|
}
|
|
361
|
+
|
|
331
362
|
this.input.put(SynthesizeStream.FLUSH_SENTINEL);
|
|
332
363
|
}
|
|
333
364
|
|
|
334
365
|
/** Mark the input as ended and forbid additional pushes */
|
|
335
366
|
endInput() {
|
|
336
367
|
this.flush();
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
throw new Error('Stream is closed');
|
|
368
|
+
|
|
369
|
+
if (this.input.closed || this.closed) {
|
|
370
|
+
// Stream was aborted/closed, silently skip
|
|
371
|
+
return;
|
|
342
372
|
}
|
|
373
|
+
|
|
343
374
|
this.input.close();
|
|
344
375
|
}
|
|
345
376
|
|
|
@@ -378,6 +409,7 @@ export abstract class ChunkedStream implements AsyncIterableIterator<Synthesized
|
|
|
378
409
|
abstract label: string;
|
|
379
410
|
#text: string;
|
|
380
411
|
#tts: TTS;
|
|
412
|
+
#ttsRequestSpan?: Span;
|
|
381
413
|
private _connOptions: APIConnectOptions;
|
|
382
414
|
private logger = log();
|
|
383
415
|
|
|
@@ -399,12 +431,27 @@ export abstract class ChunkedStream implements AsyncIterableIterator<Synthesized
|
|
|
399
431
|
Promise.resolve().then(() => this.mainTask().then(() => this.queue.close()));
|
|
400
432
|
}
|
|
401
433
|
|
|
402
|
-
private async
|
|
403
|
-
|
|
434
|
+
private _mainTaskImpl = async (span: Span) => {
|
|
435
|
+
this.#ttsRequestSpan = span;
|
|
436
|
+
span.setAttributes({
|
|
437
|
+
[traceTypes.ATTR_TTS_STREAMING]: false,
|
|
438
|
+
[traceTypes.ATTR_TTS_LABEL]: this.#tts.label,
|
|
439
|
+
});
|
|
440
|
+
|
|
404
441
|
for (let i = 0; i < this._connOptions.maxRetry + 1; i++) {
|
|
405
442
|
try {
|
|
406
|
-
|
|
407
|
-
|
|
443
|
+
return await tracer.startActiveSpan(
|
|
444
|
+
async (attemptSpan) => {
|
|
445
|
+
attemptSpan.setAttribute(traceTypes.ATTR_RETRY_COUNT, i);
|
|
446
|
+
try {
|
|
447
|
+
return await this.run();
|
|
448
|
+
} catch (error) {
|
|
449
|
+
recordException(attemptSpan, toError(error));
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
{ name: 'tts_request_run' },
|
|
454
|
+
);
|
|
408
455
|
} catch (error) {
|
|
409
456
|
if (error instanceof APIError) {
|
|
410
457
|
const retryInterval = this._connOptions._intervalForRetry(i);
|
|
@@ -436,6 +483,13 @@ export abstract class ChunkedStream implements AsyncIterableIterator<Synthesized
|
|
|
436
483
|
}
|
|
437
484
|
}
|
|
438
485
|
}
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
private async mainTask() {
|
|
489
|
+
return tracer.startActiveSpan(async (span) => this._mainTaskImpl(span), {
|
|
490
|
+
name: 'tts_request',
|
|
491
|
+
endOnExit: false,
|
|
492
|
+
});
|
|
439
493
|
}
|
|
440
494
|
|
|
441
495
|
private emitError({ error, recoverable }: { error: Error; recoverable: boolean }) {
|
|
@@ -483,6 +537,13 @@ export abstract class ChunkedStream implements AsyncIterableIterator<Synthesized
|
|
|
483
537
|
label: this.#tts.label,
|
|
484
538
|
streamed: false,
|
|
485
539
|
};
|
|
540
|
+
|
|
541
|
+
if (this.#ttsRequestSpan) {
|
|
542
|
+
this.#ttsRequestSpan.setAttribute(traceTypes.ATTR_TTS_METRICS, JSON.stringify(metrics));
|
|
543
|
+
this.#ttsRequestSpan.end();
|
|
544
|
+
this.#ttsRequestSpan = undefined;
|
|
545
|
+
}
|
|
546
|
+
|
|
486
547
|
this.#tts.emit('metrics_collected', metrics);
|
|
487
548
|
}
|
|
488
549
|
|
package/src/utils.ts
CHANGED
|
@@ -839,3 +839,8 @@ export async function waitForAbort(signal: AbortSignal) {
|
|
|
839
839
|
signal.addEventListener('abort', handler, { once: true });
|
|
840
840
|
return await abortFuture.await;
|
|
841
841
|
}
|
|
842
|
+
|
|
843
|
+
export const isCloud = (url: URL) => {
|
|
844
|
+
const hostname = url.hostname;
|
|
845
|
+
return hostname.endsWith('.livekit.cloud') || hostname.endsWith('.livekit.run');
|
|
846
|
+
};
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { Mutex } from '@livekit/mutex';
|
|
5
5
|
import type { AudioFrame } from '@livekit/rtc-node';
|
|
6
|
+
import type { Span } from '@opentelemetry/api';
|
|
7
|
+
import { ROOT_CONTEXT, trace } from '@opentelemetry/api';
|
|
6
8
|
import { Heap } from 'heap-js';
|
|
7
9
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
8
10
|
import { ReadableStream } from 'node:stream/web';
|
|
@@ -10,6 +12,7 @@ import { type ChatContext, ChatMessage } from '../llm/chat_context.js';
|
|
|
10
12
|
import {
|
|
11
13
|
type ChatItem,
|
|
12
14
|
type FunctionCall,
|
|
15
|
+
type FunctionCallOutput,
|
|
13
16
|
type GenerationCreatedEvent,
|
|
14
17
|
type InputSpeechStartedEvent,
|
|
15
18
|
type InputSpeechStoppedEvent,
|
|
@@ -34,6 +37,7 @@ import type {
|
|
|
34
37
|
} from '../metrics/base.js';
|
|
35
38
|
import { DeferredReadableStream } from '../stream/deferred_stream.js';
|
|
36
39
|
import { STT, type STTError, type SpeechEvent } from '../stt/stt.js';
|
|
40
|
+
import { traceTypes, tracer } from '../telemetry/index.js';
|
|
37
41
|
import { splitWords } from '../tokenize/basic/word.js';
|
|
38
42
|
import { TTS, type TTSError } from '../tts/tts.js';
|
|
39
43
|
import { Future, Task, cancelAndWait, waitFor } from '../utils.js';
|
|
@@ -70,7 +74,6 @@ import {
|
|
|
70
74
|
} from './generation.js';
|
|
71
75
|
import { SpeechHandle } from './speech_handle.js';
|
|
72
76
|
|
|
73
|
-
// equivalent to Python's contextvars
|
|
74
77
|
const speechHandleStorage = new AsyncLocalStorage<SpeechHandle>();
|
|
75
78
|
|
|
76
79
|
interface PreemptiveGeneration {
|
|
@@ -202,10 +205,15 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
async start(): Promise<void> {
|
|
205
|
-
// TODO(brian): PR3 - Add span: startSpan = tracer.startSpan('start_agent_activity', { attributes: { 'lk.agent_label': this.agent.label } })
|
|
206
|
-
// TODO(brian): PR3 - Wrap prewarm calls with trace.useSpan(startSpan, endOnExit: false)
|
|
207
208
|
const unlock = await this.lock.lock();
|
|
208
209
|
try {
|
|
210
|
+
// Create start_agent_activity as a ROOT span (new trace) to match Python behavior
|
|
211
|
+
const startSpan = tracer.startSpan({
|
|
212
|
+
name: 'start_agent_activity',
|
|
213
|
+
attributes: { [traceTypes.ATTR_AGENT_LABEL]: this.agent.id },
|
|
214
|
+
context: ROOT_CONTEXT,
|
|
215
|
+
});
|
|
216
|
+
|
|
209
217
|
this.agent._agentActivity = this;
|
|
210
218
|
|
|
211
219
|
if (this.llm instanceof RealtimeModel) {
|
|
@@ -286,16 +294,26 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
286
294
|
turnDetectionMode: this.turnDetectionMode,
|
|
287
295
|
minEndpointingDelay: this.agentSession.options.minEndpointingDelay,
|
|
288
296
|
maxEndpointingDelay: this.agentSession.options.maxEndpointingDelay,
|
|
297
|
+
rootSpanContext: this.agentSession.rootSpanContext,
|
|
289
298
|
});
|
|
290
299
|
this.audioRecognition.start();
|
|
291
300
|
this.started = true;
|
|
292
301
|
|
|
293
302
|
this._mainTask = Task.from(({ signal }) => this.mainTask(signal));
|
|
294
|
-
|
|
303
|
+
|
|
304
|
+
// Create on_enter as a child of start_agent_activity in the new trace
|
|
305
|
+
const onEnterTask = tracer.startActiveSpan(async () => this.agent.onEnter(), {
|
|
306
|
+
name: 'on_enter',
|
|
307
|
+
context: trace.setSpan(ROOT_CONTEXT, startSpan),
|
|
308
|
+
attributes: { [traceTypes.ATTR_AGENT_LABEL]: this.agent.id },
|
|
309
|
+
});
|
|
310
|
+
|
|
295
311
|
this.createSpeechTask({
|
|
296
|
-
task: Task.from(() =>
|
|
312
|
+
task: Task.from(() => onEnterTask),
|
|
297
313
|
name: 'AgentActivity_onEnter',
|
|
298
314
|
});
|
|
315
|
+
|
|
316
|
+
startSpan.end();
|
|
299
317
|
} finally {
|
|
300
318
|
unlock();
|
|
301
319
|
}
|
|
@@ -577,7 +595,6 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
577
595
|
}
|
|
578
596
|
|
|
579
597
|
if (this.draining) {
|
|
580
|
-
// copied from python:
|
|
581
598
|
// TODO(shubhra): should we "forward" this new turn to the next agent?
|
|
582
599
|
this.logger.warn('skipping new realtime generation, the agent is draining');
|
|
583
600
|
return;
|
|
@@ -783,7 +800,6 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
783
800
|
if (this.draining) {
|
|
784
801
|
this.cancelPreemptiveGeneration();
|
|
785
802
|
this.logger.warn({ user_input: info.newTranscript }, 'skipping user input, task is draining');
|
|
786
|
-
// copied from python:
|
|
787
803
|
// TODO(shubhra): should we "forward" this new turn to the next agent/activity?
|
|
788
804
|
return true;
|
|
789
805
|
}
|
|
@@ -1254,17 +1270,35 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1254
1270
|
}
|
|
1255
1271
|
}
|
|
1256
1272
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1273
|
+
private _pipelineReplyTaskImpl = async ({
|
|
1274
|
+
speechHandle,
|
|
1275
|
+
chatCtx,
|
|
1276
|
+
toolCtx,
|
|
1277
|
+
modelSettings,
|
|
1278
|
+
replyAbortController,
|
|
1279
|
+
instructions,
|
|
1280
|
+
newMessage,
|
|
1281
|
+
toolsMessages,
|
|
1282
|
+
span,
|
|
1283
|
+
}: {
|
|
1284
|
+
speechHandle: SpeechHandle;
|
|
1285
|
+
chatCtx: ChatContext;
|
|
1286
|
+
toolCtx: ToolContext;
|
|
1287
|
+
modelSettings: ModelSettings;
|
|
1288
|
+
replyAbortController: AbortController;
|
|
1289
|
+
instructions?: string;
|
|
1290
|
+
newMessage?: ChatMessage;
|
|
1291
|
+
toolsMessages?: ChatItem[];
|
|
1292
|
+
span: Span;
|
|
1293
|
+
}): Promise<void> => {
|
|
1294
|
+
span.setAttribute(traceTypes.ATTR_SPEECH_ID, speechHandle.id);
|
|
1295
|
+
if (instructions) {
|
|
1296
|
+
span.setAttribute(traceTypes.ATTR_INSTRUCTIONS, instructions);
|
|
1297
|
+
}
|
|
1298
|
+
if (newMessage) {
|
|
1299
|
+
span.setAttribute(traceTypes.ATTR_USER_INPUT, newMessage.textContent || '');
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1268
1302
|
speechHandleStorage.enterWith(speechHandle);
|
|
1269
1303
|
|
|
1270
1304
|
const audioOutput = this.agentSession.output.audioEnabled
|
|
@@ -1406,6 +1440,8 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1406
1440
|
msg.createdAt = replyStartedAt;
|
|
1407
1441
|
}
|
|
1408
1442
|
this.agent._chatCtx.insert(toolsMessages);
|
|
1443
|
+
// Also add to session history (matches Python agent_session.py _tool_items_added)
|
|
1444
|
+
this.agentSession._toolItemsAdded(toolsMessages as (FunctionCall | FunctionCallOutput)[]);
|
|
1409
1445
|
}
|
|
1410
1446
|
|
|
1411
1447
|
if (speechHandle.interrupted) {
|
|
@@ -1601,8 +1637,38 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1601
1637
|
msg.createdAt = replyStartedAt;
|
|
1602
1638
|
}
|
|
1603
1639
|
this.agent._chatCtx.insert(toolMessages);
|
|
1640
|
+
this.agentSession._toolItemsAdded(toolMessages as (FunctionCall | FunctionCallOutput)[]);
|
|
1604
1641
|
}
|
|
1605
|
-
}
|
|
1642
|
+
};
|
|
1643
|
+
|
|
1644
|
+
private pipelineReplyTask = async (
|
|
1645
|
+
speechHandle: SpeechHandle,
|
|
1646
|
+
chatCtx: ChatContext,
|
|
1647
|
+
toolCtx: ToolContext,
|
|
1648
|
+
modelSettings: ModelSettings,
|
|
1649
|
+
replyAbortController: AbortController,
|
|
1650
|
+
instructions?: string,
|
|
1651
|
+
newMessage?: ChatMessage,
|
|
1652
|
+
toolsMessages?: ChatItem[],
|
|
1653
|
+
): Promise<void> =>
|
|
1654
|
+
tracer.startActiveSpan(
|
|
1655
|
+
async (span) =>
|
|
1656
|
+
this._pipelineReplyTaskImpl({
|
|
1657
|
+
speechHandle,
|
|
1658
|
+
chatCtx,
|
|
1659
|
+
toolCtx,
|
|
1660
|
+
modelSettings,
|
|
1661
|
+
replyAbortController,
|
|
1662
|
+
instructions,
|
|
1663
|
+
newMessage,
|
|
1664
|
+
toolsMessages,
|
|
1665
|
+
span,
|
|
1666
|
+
}),
|
|
1667
|
+
{
|
|
1668
|
+
name: 'agent_turn',
|
|
1669
|
+
context: this.agentSession.rootSpanContext,
|
|
1670
|
+
},
|
|
1671
|
+
);
|
|
1606
1672
|
|
|
1607
1673
|
private async realtimeGenerationTask(
|
|
1608
1674
|
speechHandle: SpeechHandle,
|
|
@@ -1610,6 +1676,37 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1610
1676
|
modelSettings: ModelSettings,
|
|
1611
1677
|
replyAbortController: AbortController,
|
|
1612
1678
|
): Promise<void> {
|
|
1679
|
+
return tracer.startActiveSpan(
|
|
1680
|
+
async (span) =>
|
|
1681
|
+
this._realtimeGenerationTaskImpl({
|
|
1682
|
+
speechHandle,
|
|
1683
|
+
ev,
|
|
1684
|
+
modelSettings,
|
|
1685
|
+
replyAbortController,
|
|
1686
|
+
span,
|
|
1687
|
+
}),
|
|
1688
|
+
{
|
|
1689
|
+
name: 'agent_turn',
|
|
1690
|
+
context: this.agentSession.rootSpanContext,
|
|
1691
|
+
},
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
private async _realtimeGenerationTaskImpl({
|
|
1696
|
+
speechHandle,
|
|
1697
|
+
ev,
|
|
1698
|
+
modelSettings,
|
|
1699
|
+
replyAbortController,
|
|
1700
|
+
span,
|
|
1701
|
+
}: {
|
|
1702
|
+
speechHandle: SpeechHandle;
|
|
1703
|
+
ev: GenerationCreatedEvent;
|
|
1704
|
+
modelSettings: ModelSettings;
|
|
1705
|
+
replyAbortController: AbortController;
|
|
1706
|
+
span: Span;
|
|
1707
|
+
}): Promise<void> {
|
|
1708
|
+
span.setAttribute(traceTypes.ATTR_SPEECH_ID, speechHandle.id);
|
|
1709
|
+
|
|
1613
1710
|
speechHandleStorage.enterWith(speechHandle);
|
|
1614
1711
|
|
|
1615
1712
|
if (!this.realtimeSession) {
|
|
@@ -1786,6 +1883,8 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1786
1883
|
|
|
1787
1884
|
const onToolExecutionStarted = (f: FunctionCall) => {
|
|
1788
1885
|
speechHandle._itemAdded([f]);
|
|
1886
|
+
this.agent._chatCtx.items.push(f);
|
|
1887
|
+
this.agentSession._toolItemsAdded([f]);
|
|
1789
1888
|
};
|
|
1790
1889
|
|
|
1791
1890
|
const onToolExecutionCompleted = (out: ToolExecutionOutput) => {
|
|
@@ -1979,6 +2078,11 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
1979
2078
|
}
|
|
1980
2079
|
const chatCtx = this.realtimeSession.chatCtx.copy();
|
|
1981
2080
|
chatCtx.items.push(...functionToolsExecutedEvent.functionCallOutputs);
|
|
2081
|
+
|
|
2082
|
+
this.agentSession._toolItemsAdded(
|
|
2083
|
+
functionToolsExecutedEvent.functionCallOutputs as FunctionCallOutput[],
|
|
2084
|
+
);
|
|
2085
|
+
|
|
1982
2086
|
try {
|
|
1983
2087
|
await this.realtimeSession.updateChatCtx(chatCtx);
|
|
1984
2088
|
} catch (error) {
|
|
@@ -2096,16 +2200,30 @@ export class AgentActivity implements RecognitionHooks {
|
|
|
2096
2200
|
this.wakeupMainTask();
|
|
2097
2201
|
}
|
|
2098
2202
|
|
|
2099
|
-
// TODO(brian): PR3 - Wrap entire drain() method with tracer.startActiveSpan('drain_agent_activity', { attributes: { 'lk.agent_label': this.agent.label } })
|
|
2100
2203
|
async drain(): Promise<void> {
|
|
2204
|
+
// Create drain_agent_activity as a ROOT span (new trace) to match Python behavior
|
|
2205
|
+
return tracer.startActiveSpan(async (span) => this._drainImpl(span), {
|
|
2206
|
+
name: 'drain_agent_activity',
|
|
2207
|
+
context: ROOT_CONTEXT,
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
private async _drainImpl(span: Span): Promise<void> {
|
|
2212
|
+
span.setAttribute(traceTypes.ATTR_AGENT_LABEL, this.agent.id);
|
|
2213
|
+
|
|
2101
2214
|
const unlock = await this.lock.lock();
|
|
2102
2215
|
try {
|
|
2103
2216
|
if (this._draining) return;
|
|
2104
2217
|
|
|
2105
2218
|
this.cancelPreemptiveGeneration();
|
|
2106
|
-
|
|
2219
|
+
|
|
2220
|
+
const onExitTask = tracer.startActiveSpan(async () => this.agent.onExit(), {
|
|
2221
|
+
name: 'on_exit',
|
|
2222
|
+
attributes: { [traceTypes.ATTR_AGENT_LABEL]: this.agent.id },
|
|
2223
|
+
});
|
|
2224
|
+
|
|
2107
2225
|
this.createSpeechTask({
|
|
2108
|
-
task: Task.from(() =>
|
|
2226
|
+
task: Task.from(() => onExitTask),
|
|
2109
2227
|
name: 'AgentActivity_onExit',
|
|
2110
2228
|
});
|
|
2111
2229
|
|