@livekit/agents 1.0.18 → 1.0.20
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/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.ts.map +1 -1
- package/dist/llm/llm.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/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/log.cjs.map +1 -1
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js.map +1 -1
- package/dist/stt/stt.cjs +3 -0
- package/dist/stt/stt.cjs.map +1 -1
- package/dist/stt/stt.d.cts +1 -0
- package/dist/stt/stt.d.ts +1 -0
- package/dist/stt/stt.d.ts.map +1 -1
- package/dist/stt/stt.js +3 -0
- package/dist/stt/stt.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 +3 -0
- package/dist/tts/tts.cjs.map +1 -1
- package/dist/tts/tts.d.cts +1 -0
- package/dist/tts/tts.d.ts +1 -0
- package/dist/tts/tts.d.ts.map +1 -1
- package/dist/tts/tts.js +3 -0
- package/dist/tts/tts.js.map +1 -1
- package/dist/vad.cjs +3 -0
- package/dist/vad.cjs.map +1 -1
- package/dist/vad.d.cts +1 -0
- package/dist/vad.d.ts +1 -0
- package/dist/vad.d.ts.map +1 -1
- package/dist/vad.js +3 -0
- package/dist/vad.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 +5 -0
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +5 -0
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +29 -1
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +6 -2
- package/dist/voice/agent_session.d.ts +6 -2
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +30 -2
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +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 +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/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/package.json +10 -3
- package/src/index.ts +2 -1
- 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/chat_context.ts +53 -1
- package/src/llm/index.ts +1 -0
- package/src/llm/llm.ts +2 -0
- package/src/llm/provider_format/google.test.ts +72 -1
- package/src/llm/provider_format/openai.test.ts +55 -1
- package/src/llm/provider_format/openai.ts +3 -2
- package/src/log.ts +1 -0
- package/src/stt/stt.ts +4 -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 +8 -0
- package/src/vad.ts +4 -0
- package/src/voice/agent.ts +22 -0
- package/src/voice/agent_activity.ts +9 -0
- package/src/voice/agent_session.ts +44 -1
- package/src/voice/audio_recognition.ts +3 -1
- package/src/voice/generation.ts +3 -0
- package/src/voice/index.ts +1 -0
- package/src/voice/report.ts +77 -0
package/dist/voice/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\nexport * from './avatar/index.js';\nexport * from './background_audio.js';\nexport * from './events.js';\nexport * from './room_io/index.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA2E;AAC3E,2BAAuD;AACvD,0BAAc,8BALd;AAMA,0BAAc,kCANd;AAOA,0BAAc,wBAPd;AAQA,0BAAc
|
|
1
|
+
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\nexport * from './avatar/index.js';\nexport * from './background_audio.js';\nexport * from './events.js';\nexport * from './report.js';\nexport * from './room_io/index.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAA2E;AAC3E,2BAAuD;AACvD,0BAAc,8BALd;AAMA,0BAAc,kCANd;AAOA,0BAAc,wBAPd;AAQA,0BAAc,wBARd;AASA,0BAAc,+BATd;AAUA,yBAA2B;","names":[]}
|
package/dist/voice/index.d.cts
CHANGED
|
@@ -3,6 +3,7 @@ export { AgentSession, type AgentSessionOptions } from './agent_session.js';
|
|
|
3
3
|
export * from './avatar/index.js';
|
|
4
4
|
export * from './background_audio.js';
|
|
5
5
|
export * from './events.js';
|
|
6
|
+
export * from './report.js';
|
|
6
7
|
export * from './room_io/index.js';
|
|
7
8
|
export { RunContext } from './run_context.js';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/voice/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { AgentSession, type AgentSessionOptions } from './agent_session.js';
|
|
|
3
3
|
export * from './avatar/index.js';
|
|
4
4
|
export * from './background_audio.js';
|
|
5
5
|
export * from './events.js';
|
|
6
|
+
export * from './report.js';
|
|
6
7
|
export * from './room_io/index.js';
|
|
7
8
|
export { RunContext } from './run_context.js';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voice/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/voice/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/voice/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { AgentSession } from "./agent_session.js";
|
|
|
3
3
|
export * from "./avatar/index.js";
|
|
4
4
|
export * from "./background_audio.js";
|
|
5
5
|
export * from "./events.js";
|
|
6
|
+
export * from "./report.js";
|
|
6
7
|
export * from "./room_io/index.js";
|
|
7
8
|
import { RunContext } from "./run_context.js";
|
|
8
9
|
export {
|
package/dist/voice/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\nexport * from './avatar/index.js';\nexport * from './background_audio.js';\nexport * from './events.js';\nexport * from './room_io/index.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":"AAGA,SAAS,OAAO,oBAA2D;AAC3E,SAAS,oBAA8C;AACvD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,kBAAkB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/voice/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { Agent, StopResponse, type AgentOptions, type ModelSettings } from './agent.js';\nexport { AgentSession, type AgentSessionOptions } from './agent_session.js';\nexport * from './avatar/index.js';\nexport * from './background_audio.js';\nexport * from './events.js';\nexport * from './report.js';\nexport * from './room_io/index.js';\nexport { RunContext } from './run_context.js';\n"],"mappings":"AAGA,SAAS,OAAO,oBAA2D;AAC3E,SAAS,oBAA8C;AACvD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,kBAAkB;","names":[]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var report_exports = {};
|
|
20
|
+
__export(report_exports, {
|
|
21
|
+
createSessionReport: () => createSessionReport,
|
|
22
|
+
sessionReportToJSON: () => sessionReportToJSON
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(report_exports);
|
|
25
|
+
function createSessionReport(opts) {
|
|
26
|
+
return {
|
|
27
|
+
jobId: opts.jobId,
|
|
28
|
+
roomId: opts.roomId,
|
|
29
|
+
room: opts.room,
|
|
30
|
+
options: opts.options,
|
|
31
|
+
events: opts.events,
|
|
32
|
+
chatHistory: opts.chatHistory,
|
|
33
|
+
enableUserDataTraining: opts.enableUserDataTraining ?? false,
|
|
34
|
+
timestamp: opts.timestamp ?? Date.now()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function sessionReportToJSON(report) {
|
|
38
|
+
const events = [];
|
|
39
|
+
for (const event of report.events) {
|
|
40
|
+
if (event.type === "metrics_collected") {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
events.push({ ...event });
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
job_id: report.jobId,
|
|
47
|
+
room_id: report.roomId,
|
|
48
|
+
room: report.room,
|
|
49
|
+
events,
|
|
50
|
+
options: {
|
|
51
|
+
allow_interruptions: report.options.allowInterruptions,
|
|
52
|
+
discard_audio_if_uninterruptible: report.options.discardAudioIfUninterruptible,
|
|
53
|
+
min_interruption_duration: report.options.minInterruptionDuration,
|
|
54
|
+
min_interruption_words: report.options.minInterruptionWords,
|
|
55
|
+
min_endpointing_delay: report.options.minEndpointingDelay,
|
|
56
|
+
max_endpointing_delay: report.options.maxEndpointingDelay,
|
|
57
|
+
max_tool_steps: report.options.maxToolSteps
|
|
58
|
+
},
|
|
59
|
+
chat_history: report.chatHistory.toJSON({ excludeTimestamp: false }),
|
|
60
|
+
enable_user_data_training: report.enableUserDataTraining,
|
|
61
|
+
timestamp: report.timestamp
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
65
|
+
0 && (module.exports = {
|
|
66
|
+
createSessionReport,
|
|
67
|
+
sessionReportToJSON
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=report.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/voice/report.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { ChatContext } from '../llm/chat_context.js';\nimport type { VoiceOptions } from './agent_session.js';\nimport type { AgentEvent } from './events.js';\n\nexport interface SessionReport {\n jobId: string;\n roomId: string;\n room: string;\n options: VoiceOptions;\n events: AgentEvent[];\n chatHistory: ChatContext;\n enableUserDataTraining: boolean;\n timestamp: number;\n}\n\nexport interface SessionReportOptions {\n jobId: string;\n roomId: string;\n room: string;\n options: VoiceOptions;\n events: AgentEvent[];\n chatHistory: ChatContext;\n enableUserDataTraining?: boolean;\n timestamp?: number;\n}\n\nexport function createSessionReport(opts: SessionReportOptions): SessionReport {\n return {\n jobId: opts.jobId,\n roomId: opts.roomId,\n room: opts.room,\n options: opts.options,\n events: opts.events,\n chatHistory: opts.chatHistory,\n enableUserDataTraining: opts.enableUserDataTraining ?? false,\n timestamp: opts.timestamp ?? Date.now(),\n };\n}\n\n// TODO(brian): PR5 - Add uploadSessionReport() function that creates multipart form with:\n// - header: protobuf MetricsRecordingHeader (room_id, duration, start_time)\n// - chat_history: JSON serialized chat history (use sessionReportToJSON)\n// - audio: audio recording file if available (ogg format)\n// - Uploads to LiveKit Cloud observability endpoint with JWT auth\nexport function sessionReportToJSON(report: SessionReport): Record<string, unknown> {\n const events: Record<string, unknown>[] = [];\n\n for (const event of report.events) {\n if (event.type === 'metrics_collected') {\n continue; // metrics are too noisy, Cloud is using the chat_history as the source of truth\n }\n\n events.push({ ...event });\n }\n\n return {\n job_id: report.jobId,\n room_id: report.roomId,\n room: report.room,\n events,\n options: {\n allow_interruptions: report.options.allowInterruptions,\n discard_audio_if_uninterruptible: report.options.discardAudioIfUninterruptible,\n min_interruption_duration: report.options.minInterruptionDuration,\n min_interruption_words: report.options.minInterruptionWords,\n min_endpointing_delay: report.options.minEndpointingDelay,\n max_endpointing_delay: report.options.maxEndpointingDelay,\n max_tool_steps: report.options.maxToolSteps,\n },\n chat_history: report.chatHistory.toJSON({ excludeTimestamp: false }),\n enable_user_data_training: report.enableUserDataTraining,\n timestamp: report.timestamp,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BO,SAAS,oBAAoB,MAA2C;AAC7E,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,QAAQ,KAAK;AAAA,IACb,aAAa,KAAK;AAAA,IAClB,wBAAwB,KAAK,0BAA0B;AAAA,IACvD,WAAW,KAAK,aAAa,KAAK,IAAI;AAAA,EACxC;AACF;AAOO,SAAS,oBAAoB,QAAgD;AAClF,QAAM,SAAoC,CAAC;AAE3C,aAAW,SAAS,OAAO,QAAQ;AACjC,QAAI,MAAM,SAAS,qBAAqB;AACtC;AAAA,IACF;AAEA,WAAO,KAAK,EAAE,GAAG,MAAM,CAAC;AAAA,EAC1B;AAEA,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO;AAAA,IAChB,MAAM,OAAO;AAAA,IACb;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,OAAO,QAAQ;AAAA,MACpC,kCAAkC,OAAO,QAAQ;AAAA,MACjD,2BAA2B,OAAO,QAAQ;AAAA,MAC1C,wBAAwB,OAAO,QAAQ;AAAA,MACvC,uBAAuB,OAAO,QAAQ;AAAA,MACtC,uBAAuB,OAAO,QAAQ;AAAA,MACtC,gBAAgB,OAAO,QAAQ;AAAA,IACjC;AAAA,IACA,cAAc,OAAO,YAAY,OAAO,EAAE,kBAAkB,MAAM,CAAC;AAAA,IACnE,2BAA2B,OAAO;AAAA,IAClC,WAAW,OAAO;AAAA,EACpB;AACF;","names":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChatContext } from '../llm/chat_context.js';
|
|
2
|
+
import type { VoiceOptions } from './agent_session.js';
|
|
3
|
+
import type { AgentEvent } from './events.js';
|
|
4
|
+
export interface SessionReport {
|
|
5
|
+
jobId: string;
|
|
6
|
+
roomId: string;
|
|
7
|
+
room: string;
|
|
8
|
+
options: VoiceOptions;
|
|
9
|
+
events: AgentEvent[];
|
|
10
|
+
chatHistory: ChatContext;
|
|
11
|
+
enableUserDataTraining: boolean;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionReportOptions {
|
|
15
|
+
jobId: string;
|
|
16
|
+
roomId: string;
|
|
17
|
+
room: string;
|
|
18
|
+
options: VoiceOptions;
|
|
19
|
+
events: AgentEvent[];
|
|
20
|
+
chatHistory: ChatContext;
|
|
21
|
+
enableUserDataTraining?: boolean;
|
|
22
|
+
timestamp?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function createSessionReport(opts: SessionReportOptions): SessionReport;
|
|
25
|
+
export declare function sessionReportToJSON(report: SessionReport): Record<string, unknown>;
|
|
26
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ChatContext } from '../llm/chat_context.js';
|
|
2
|
+
import type { VoiceOptions } from './agent_session.js';
|
|
3
|
+
import type { AgentEvent } from './events.js';
|
|
4
|
+
export interface SessionReport {
|
|
5
|
+
jobId: string;
|
|
6
|
+
roomId: string;
|
|
7
|
+
room: string;
|
|
8
|
+
options: VoiceOptions;
|
|
9
|
+
events: AgentEvent[];
|
|
10
|
+
chatHistory: ChatContext;
|
|
11
|
+
enableUserDataTraining: boolean;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SessionReportOptions {
|
|
15
|
+
jobId: string;
|
|
16
|
+
roomId: string;
|
|
17
|
+
room: string;
|
|
18
|
+
options: VoiceOptions;
|
|
19
|
+
events: AgentEvent[];
|
|
20
|
+
chatHistory: ChatContext;
|
|
21
|
+
enableUserDataTraining?: boolean;
|
|
22
|
+
timestamp?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function createSessionReport(opts: SessionReportOptions): SessionReport;
|
|
25
|
+
export declare function sessionReportToJSON(report: SessionReport): Record<string, unknown>;
|
|
26
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/voice/report.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,sBAAsB,EAAE,OAAO,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,aAAa,CAW7E;AAOD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BlF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function createSessionReport(opts) {
|
|
2
|
+
return {
|
|
3
|
+
jobId: opts.jobId,
|
|
4
|
+
roomId: opts.roomId,
|
|
5
|
+
room: opts.room,
|
|
6
|
+
options: opts.options,
|
|
7
|
+
events: opts.events,
|
|
8
|
+
chatHistory: opts.chatHistory,
|
|
9
|
+
enableUserDataTraining: opts.enableUserDataTraining ?? false,
|
|
10
|
+
timestamp: opts.timestamp ?? Date.now()
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function sessionReportToJSON(report) {
|
|
14
|
+
const events = [];
|
|
15
|
+
for (const event of report.events) {
|
|
16
|
+
if (event.type === "metrics_collected") {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
events.push({ ...event });
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
job_id: report.jobId,
|
|
23
|
+
room_id: report.roomId,
|
|
24
|
+
room: report.room,
|
|
25
|
+
events,
|
|
26
|
+
options: {
|
|
27
|
+
allow_interruptions: report.options.allowInterruptions,
|
|
28
|
+
discard_audio_if_uninterruptible: report.options.discardAudioIfUninterruptible,
|
|
29
|
+
min_interruption_duration: report.options.minInterruptionDuration,
|
|
30
|
+
min_interruption_words: report.options.minInterruptionWords,
|
|
31
|
+
min_endpointing_delay: report.options.minEndpointingDelay,
|
|
32
|
+
max_endpointing_delay: report.options.maxEndpointingDelay,
|
|
33
|
+
max_tool_steps: report.options.maxToolSteps
|
|
34
|
+
},
|
|
35
|
+
chat_history: report.chatHistory.toJSON({ excludeTimestamp: false }),
|
|
36
|
+
enable_user_data_training: report.enableUserDataTraining,
|
|
37
|
+
timestamp: report.timestamp
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
createSessionReport,
|
|
42
|
+
sessionReportToJSON
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/voice/report.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { ChatContext } from '../llm/chat_context.js';\nimport type { VoiceOptions } from './agent_session.js';\nimport type { AgentEvent } from './events.js';\n\nexport interface SessionReport {\n jobId: string;\n roomId: string;\n room: string;\n options: VoiceOptions;\n events: AgentEvent[];\n chatHistory: ChatContext;\n enableUserDataTraining: boolean;\n timestamp: number;\n}\n\nexport interface SessionReportOptions {\n jobId: string;\n roomId: string;\n room: string;\n options: VoiceOptions;\n events: AgentEvent[];\n chatHistory: ChatContext;\n enableUserDataTraining?: boolean;\n timestamp?: number;\n}\n\nexport function createSessionReport(opts: SessionReportOptions): SessionReport {\n return {\n jobId: opts.jobId,\n roomId: opts.roomId,\n room: opts.room,\n options: opts.options,\n events: opts.events,\n chatHistory: opts.chatHistory,\n enableUserDataTraining: opts.enableUserDataTraining ?? false,\n timestamp: opts.timestamp ?? Date.now(),\n };\n}\n\n// TODO(brian): PR5 - Add uploadSessionReport() function that creates multipart form with:\n// - header: protobuf MetricsRecordingHeader (room_id, duration, start_time)\n// - chat_history: JSON serialized chat history (use sessionReportToJSON)\n// - audio: audio recording file if available (ogg format)\n// - Uploads to LiveKit Cloud observability endpoint with JWT auth\nexport function sessionReportToJSON(report: SessionReport): Record<string, unknown> {\n const events: Record<string, unknown>[] = [];\n\n for (const event of report.events) {\n if (event.type === 'metrics_collected') {\n continue; // metrics are too noisy, Cloud is using the chat_history as the source of truth\n }\n\n events.push({ ...event });\n }\n\n return {\n job_id: report.jobId,\n room_id: report.roomId,\n room: report.room,\n events,\n options: {\n allow_interruptions: report.options.allowInterruptions,\n discard_audio_if_uninterruptible: report.options.discardAudioIfUninterruptible,\n min_interruption_duration: report.options.minInterruptionDuration,\n min_interruption_words: report.options.minInterruptionWords,\n min_endpointing_delay: report.options.minEndpointingDelay,\n max_endpointing_delay: report.options.maxEndpointingDelay,\n max_tool_steps: report.options.maxToolSteps,\n },\n chat_history: report.chatHistory.toJSON({ excludeTimestamp: false }),\n enable_user_data_training: report.enableUserDataTraining,\n timestamp: report.timestamp,\n };\n}\n"],"mappings":"AA6BO,SAAS,oBAAoB,MAA2C;AAC7E,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,QAAQ,KAAK;AAAA,IACb,aAAa,KAAK;AAAA,IAClB,wBAAwB,KAAK,0BAA0B;AAAA,IACvD,WAAW,KAAK,aAAa,KAAK,IAAI;AAAA,EACxC;AACF;AAOO,SAAS,oBAAoB,QAAgD;AAClF,QAAM,SAAoC,CAAC;AAE3C,aAAW,SAAS,OAAO,QAAQ;AACjC,QAAI,MAAM,SAAS,qBAAqB;AACtC;AAAA,IACF;AAEA,WAAO,KAAK,EAAE,GAAG,MAAM,CAAC;AAAA,EAC1B;AAEA,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO;AAAA,IAChB,MAAM,OAAO;AAAA,IACb;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,OAAO,QAAQ;AAAA,MACpC,kCAAkC,OAAO,QAAQ;AAAA,MACjD,2BAA2B,OAAO,QAAQ;AAAA,MAC1C,wBAAwB,OAAO,QAAQ;AAAA,MACvC,uBAAuB,OAAO,QAAQ;AAAA,MACtC,uBAAuB,OAAO,QAAQ;AAAA,MACtC,gBAAgB,OAAO,QAAQ;AAAA,IACjC;AAAA,IACA,cAAc,OAAO,YAAY,OAAO,EAAE,kBAAkB,MAAM,CAAC;AAAA,IACnE,2BAA2B,OAAO;AAAA,IAClC,WAAW,OAAO;AAAA,EACpB;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/agents",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "LiveKit Agents - Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"require": "dist/index.cjs",
|
|
@@ -39,14 +39,21 @@
|
|
|
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.
|
|
56
|
+
"livekit-server-sdk": "^2.14.1",
|
|
50
57
|
"openai": "^6.8.1",
|
|
51
58
|
"pidusage": "^4.0.1",
|
|
52
59
|
"pino": "^8.19.0",
|
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/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
|
*
|
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
|
@@ -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) {
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
import { VideoBufferType, VideoFrame } from '@livekit/rtc-node';
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
6
|
import { initializeLogger } from '../../log.js';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AgentHandoffItem,
|
|
9
|
+
ChatContext,
|
|
10
|
+
FunctionCall,
|
|
11
|
+
FunctionCallOutput,
|
|
12
|
+
} from '../chat_context.js';
|
|
8
13
|
import { serializeImage } from '../utils.js';
|
|
9
14
|
import { toChatCtx } from './google.js';
|
|
10
15
|
|
|
@@ -769,4 +774,70 @@ describe('Google Provider Format - toChatCtx', () => {
|
|
|
769
774
|
]);
|
|
770
775
|
expect(formatData.systemMessages).toBeNull();
|
|
771
776
|
});
|
|
777
|
+
|
|
778
|
+
it('should filter out agent handoff items', async () => {
|
|
779
|
+
const ctx = ChatContext.empty();
|
|
780
|
+
|
|
781
|
+
ctx.addMessage({ role: 'user', content: 'Hello' });
|
|
782
|
+
|
|
783
|
+
// Insert an agent handoff item
|
|
784
|
+
const handoff = new AgentHandoffItem({
|
|
785
|
+
oldAgentId: 'agent_1',
|
|
786
|
+
newAgentId: 'agent_2',
|
|
787
|
+
});
|
|
788
|
+
ctx.insert(handoff);
|
|
789
|
+
|
|
790
|
+
ctx.addMessage({ role: 'assistant', content: 'Hi there!' });
|
|
791
|
+
|
|
792
|
+
const [result, formatData] = await toChatCtx(ctx, false);
|
|
793
|
+
|
|
794
|
+
// Agent handoff should be filtered out, only messages should remain
|
|
795
|
+
expect(result).toEqual([
|
|
796
|
+
{
|
|
797
|
+
role: 'user',
|
|
798
|
+
parts: [{ text: 'Hello' }],
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
role: 'model',
|
|
802
|
+
parts: [{ text: 'Hi there!' }],
|
|
803
|
+
},
|
|
804
|
+
]);
|
|
805
|
+
expect(formatData.systemMessages).toBeNull();
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
it('should handle multiple agent handoffs without errors', async () => {
|
|
809
|
+
const ctx = ChatContext.empty();
|
|
810
|
+
|
|
811
|
+
ctx.addMessage({ role: 'user', content: 'Start' });
|
|
812
|
+
|
|
813
|
+
// Multiple handoffs
|
|
814
|
+
ctx.insert(new AgentHandoffItem({ oldAgentId: undefined, newAgentId: 'agent_1' }));
|
|
815
|
+
ctx.addMessage({ role: 'assistant', content: 'Response from agent 1' });
|
|
816
|
+
|
|
817
|
+
ctx.insert(new AgentHandoffItem({ oldAgentId: 'agent_1', newAgentId: 'agent_2' }));
|
|
818
|
+
ctx.addMessage({ role: 'assistant', content: 'Response from agent 2' });
|
|
819
|
+
|
|
820
|
+
ctx.insert(new AgentHandoffItem({ oldAgentId: 'agent_2', newAgentId: 'agent_3' }));
|
|
821
|
+
ctx.addMessage({ role: 'assistant', content: 'Response from agent 3' });
|
|
822
|
+
|
|
823
|
+
const [result, formatData] = await toChatCtx(ctx, false);
|
|
824
|
+
|
|
825
|
+
// All handoffs should be filtered out
|
|
826
|
+
// Note: Google provider groups consecutive messages by the same role
|
|
827
|
+
expect(result).toEqual([
|
|
828
|
+
{
|
|
829
|
+
role: 'user',
|
|
830
|
+
parts: [{ text: 'Start' }],
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
role: 'model',
|
|
834
|
+
parts: [
|
|
835
|
+
{ text: 'Response from agent 1' },
|
|
836
|
+
{ text: 'Response from agent 2' },
|
|
837
|
+
{ text: 'Response from agent 3' },
|
|
838
|
+
],
|
|
839
|
+
},
|
|
840
|
+
]);
|
|
841
|
+
expect(formatData.systemMessages).toBeNull();
|
|
842
|
+
});
|
|
772
843
|
});
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
import { VideoBufferType, VideoFrame } from '@livekit/rtc-node';
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
6
|
import { initializeLogger } from '../../log.js';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AgentHandoffItem,
|
|
9
|
+
ChatContext,
|
|
10
|
+
FunctionCall,
|
|
11
|
+
FunctionCallOutput,
|
|
12
|
+
} from '../chat_context.js';
|
|
8
13
|
import { serializeImage } from '../utils.js';
|
|
9
14
|
import { toChatCtx } from './openai.js';
|
|
10
15
|
|
|
@@ -578,4 +583,53 @@ describe('toChatCtx', () => {
|
|
|
578
583
|
},
|
|
579
584
|
]);
|
|
580
585
|
});
|
|
586
|
+
|
|
587
|
+
it('should filter out agent handoff items', async () => {
|
|
588
|
+
const ctx = ChatContext.empty();
|
|
589
|
+
|
|
590
|
+
ctx.addMessage({ role: 'user', content: 'Hello' });
|
|
591
|
+
|
|
592
|
+
// Insert an agent handoff item
|
|
593
|
+
const handoff = new AgentHandoffItem({
|
|
594
|
+
oldAgentId: 'agent_1',
|
|
595
|
+
newAgentId: 'agent_2',
|
|
596
|
+
});
|
|
597
|
+
ctx.insert(handoff);
|
|
598
|
+
|
|
599
|
+
ctx.addMessage({ role: 'assistant', content: 'Hi there!' });
|
|
600
|
+
|
|
601
|
+
const result = await toChatCtx(ctx);
|
|
602
|
+
|
|
603
|
+
// Agent handoff should be filtered out, only messages should remain
|
|
604
|
+
expect(result).toEqual([
|
|
605
|
+
{ role: 'user', content: 'Hello' },
|
|
606
|
+
{ role: 'assistant', content: 'Hi there!' },
|
|
607
|
+
]);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
it('should handle multiple agent handoffs without errors', async () => {
|
|
611
|
+
const ctx = ChatContext.empty();
|
|
612
|
+
|
|
613
|
+
ctx.addMessage({ role: 'user', content: 'Start' });
|
|
614
|
+
|
|
615
|
+
// Multiple handoffs
|
|
616
|
+
ctx.insert(new AgentHandoffItem({ oldAgentId: undefined, newAgentId: 'agent_1' }));
|
|
617
|
+
ctx.addMessage({ role: 'assistant', content: 'Response from agent 1' });
|
|
618
|
+
|
|
619
|
+
ctx.insert(new AgentHandoffItem({ oldAgentId: 'agent_1', newAgentId: 'agent_2' }));
|
|
620
|
+
ctx.addMessage({ role: 'assistant', content: 'Response from agent 2' });
|
|
621
|
+
|
|
622
|
+
ctx.insert(new AgentHandoffItem({ oldAgentId: 'agent_2', newAgentId: 'agent_3' }));
|
|
623
|
+
ctx.addMessage({ role: 'assistant', content: 'Response from agent 3' });
|
|
624
|
+
|
|
625
|
+
const result = await toChatCtx(ctx);
|
|
626
|
+
|
|
627
|
+
// All handoffs should be filtered out
|
|
628
|
+
expect(result).toEqual([
|
|
629
|
+
{ role: 'user', content: 'Start' },
|
|
630
|
+
{ role: 'assistant', content: 'Response from agent 1' },
|
|
631
|
+
{ role: 'assistant', content: 'Response from agent 2' },
|
|
632
|
+
{ role: 'assistant', content: 'Response from agent 3' },
|
|
633
|
+
]);
|
|
634
|
+
});
|
|
581
635
|
});
|
|
@@ -78,9 +78,10 @@ async function toChatItem(item: ChatItem) {
|
|
|
78
78
|
tool_call_id: item.callId,
|
|
79
79
|
content: item.output,
|
|
80
80
|
};
|
|
81
|
-
} else {
|
|
82
|
-
throw new Error(`Unsupported item type: ${item['type']}`);
|
|
83
81
|
}
|
|
82
|
+
// Skip other item types (e.g., agent_handoff)
|
|
83
|
+
// These should be filtered by groupToolCalls, but this is a safety net
|
|
84
|
+
throw new Error(`Unsupported item type: ${item['type']}`);
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
async function toImageContent(content: ImageContent) {
|