@livekit/agents 1.0.47 → 1.0.49
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/beta/index.cjs +29 -0
- package/dist/beta/index.cjs.map +1 -0
- package/dist/beta/index.d.cts +2 -0
- package/dist/beta/index.d.ts +2 -0
- package/dist/beta/index.d.ts.map +1 -0
- package/dist/beta/index.js +7 -0
- package/dist/beta/index.js.map +1 -0
- package/dist/beta/workflows/index.cjs +29 -0
- package/dist/beta/workflows/index.cjs.map +1 -0
- package/dist/beta/workflows/index.d.cts +2 -0
- package/dist/beta/workflows/index.d.ts +2 -0
- package/dist/beta/workflows/index.d.ts.map +1 -0
- package/dist/beta/workflows/index.js +7 -0
- package/dist/beta/workflows/index.js.map +1 -0
- package/dist/beta/workflows/task_group.cjs +162 -0
- package/dist/beta/workflows/task_group.cjs.map +1 -0
- package/dist/beta/workflows/task_group.d.cts +32 -0
- package/dist/beta/workflows/task_group.d.ts +32 -0
- package/dist/beta/workflows/task_group.d.ts.map +1 -0
- package/dist/beta/workflows/task_group.js +138 -0
- package/dist/beta/workflows/task_group.js.map +1 -0
- package/dist/cpu.cjs +189 -0
- package/dist/cpu.cjs.map +1 -0
- package/dist/cpu.d.cts +24 -0
- package/dist/cpu.d.ts +24 -0
- package/dist/cpu.d.ts.map +1 -0
- package/dist/cpu.js +152 -0
- package/dist/cpu.js.map +1 -0
- package/dist/cpu.test.cjs +227 -0
- package/dist/cpu.test.cjs.map +1 -0
- package/dist/cpu.test.js +204 -0
- package/dist/cpu.test.js.map +1 -0
- package/dist/index.cjs +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 +59 -59
- package/dist/inference/api_protos.d.ts +59 -59
- package/dist/inference/llm.cjs.map +1 -1
- package/dist/inference/llm.d.cts +1 -1
- package/dist/inference/llm.d.ts +1 -1
- package/dist/inference/llm.d.ts.map +1 -1
- package/dist/inference/llm.js.map +1 -1
- package/dist/inference/tts.cjs.map +1 -1
- package/dist/inference/tts.d.cts +6 -0
- package/dist/inference/tts.d.ts +6 -0
- package/dist/inference/tts.d.ts.map +1 -1
- package/dist/inference/tts.js.map +1 -1
- package/dist/llm/chat_context.cjs +89 -1
- package/dist/llm/chat_context.cjs.map +1 -1
- package/dist/llm/chat_context.d.cts +10 -1
- package/dist/llm/chat_context.d.ts +10 -1
- package/dist/llm/chat_context.d.ts.map +1 -1
- package/dist/llm/chat_context.js +89 -1
- package/dist/llm/chat_context.js.map +1 -1
- package/dist/llm/chat_context.test.cjs +43 -0
- package/dist/llm/chat_context.test.cjs.map +1 -1
- package/dist/llm/chat_context.test.js +43 -0
- package/dist/llm/chat_context.test.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 +3 -1
- package/dist/llm/index.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/tool_context.cjs +7 -0
- package/dist/llm/tool_context.cjs.map +1 -1
- package/dist/llm/tool_context.d.cts +10 -2
- package/dist/llm/tool_context.d.ts +10 -2
- package/dist/llm/tool_context.d.ts.map +1 -1
- package/dist/llm/tool_context.js +6 -0
- package/dist/llm/tool_context.js.map +1 -1
- package/dist/utils.cjs +1 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -0
- package/dist/utils.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/dist/voice/agent.cjs +9 -0
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +1 -0
- package/dist/voice/agent.d.ts +1 -0
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +9 -0
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent_activity.cjs +67 -16
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +7 -0
- package/dist/voice/agent_activity.d.ts +7 -0
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +68 -17
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +27 -1
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +6 -0
- package/dist/voice/agent_session.d.ts +6 -0
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +27 -1
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/room_io/room_io.cjs +11 -2
- package/dist/voice/room_io/room_io.cjs.map +1 -1
- package/dist/voice/room_io/room_io.d.ts.map +1 -1
- package/dist/voice/room_io/room_io.js +12 -3
- package/dist/voice/room_io/room_io.js.map +1 -1
- package/dist/voice/testing/fake_llm.cjs +127 -0
- package/dist/voice/testing/fake_llm.cjs.map +1 -0
- package/dist/voice/testing/fake_llm.d.cts +30 -0
- package/dist/voice/testing/fake_llm.d.ts +30 -0
- package/dist/voice/testing/fake_llm.d.ts.map +1 -0
- package/dist/voice/testing/fake_llm.js +103 -0
- package/dist/voice/testing/fake_llm.js.map +1 -0
- package/dist/voice/testing/index.cjs +3 -0
- package/dist/voice/testing/index.cjs.map +1 -1
- package/dist/voice/testing/index.d.cts +1 -0
- package/dist/voice/testing/index.d.ts +1 -0
- package/dist/voice/testing/index.d.ts.map +1 -1
- package/dist/voice/testing/index.js +2 -0
- package/dist/voice/testing/index.js.map +1 -1
- package/dist/worker.cjs +6 -29
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +6 -19
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/src/beta/index.ts +9 -0
- package/src/beta/workflows/index.ts +9 -0
- package/src/beta/workflows/task_group.ts +194 -0
- package/src/cpu.test.ts +239 -0
- package/src/cpu.ts +173 -0
- package/src/index.ts +2 -1
- package/src/inference/llm.ts +2 -0
- package/src/inference/tts.ts +8 -1
- package/src/llm/chat_context.test.ts +48 -0
- package/src/llm/chat_context.ts +123 -0
- package/src/llm/index.ts +1 -0
- package/src/llm/tool_context.ts +14 -0
- package/src/utils.ts +5 -0
- package/src/voice/agent.ts +11 -0
- package/src/voice/agent_activity.ts +102 -16
- package/src/voice/agent_session.ts +33 -2
- package/src/voice/room_io/room_io.ts +14 -3
- package/src/voice/testing/fake_llm.ts +138 -0
- package/src/voice/testing/index.ts +2 -0
- package/src/worker.ts +34 -50
|
@@ -21,7 +21,7 @@ import type { WritableStreamDefaultWriter } from 'node:stream/web';
|
|
|
21
21
|
import { ATTRIBUTE_PUBLISH_ON_BEHALF, TOPIC_CHAT } from '../../constants.js';
|
|
22
22
|
import { log } from '../../log.js';
|
|
23
23
|
import { IdentityTransform } from '../../stream/identity_transform.js';
|
|
24
|
-
import { Future, Task } from '../../utils.js';
|
|
24
|
+
import { Future, Task, waitForAbort } from '../../utils.js';
|
|
25
25
|
import { type AgentSession } from '../agent_session.js';
|
|
26
26
|
import {
|
|
27
27
|
AgentSessionEventTypes,
|
|
@@ -177,7 +177,10 @@ export class RoomIO {
|
|
|
177
177
|
: this.inputOptions.participantIdentity ?? null;
|
|
178
178
|
}
|
|
179
179
|
private async init(signal: AbortSignal): Promise<void> {
|
|
180
|
-
await this.roomConnectedFuture.await;
|
|
180
|
+
await Promise.race([this.roomConnectedFuture.await, waitForAbort(signal)]);
|
|
181
|
+
if (signal.aborted) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
181
184
|
|
|
182
185
|
for (const participant of this.room.remoteParticipants.values()) {
|
|
183
186
|
this.onParticipantConnected(participant);
|
|
@@ -186,7 +189,15 @@ export class RoomIO {
|
|
|
186
189
|
return;
|
|
187
190
|
}
|
|
188
191
|
|
|
189
|
-
const participant = await
|
|
192
|
+
const participant = await Promise.race([
|
|
193
|
+
this.participantAvailableFuture.await,
|
|
194
|
+
waitForAbort(signal),
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
if (!participant) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
190
201
|
this.setParticipant(participant.identity);
|
|
191
202
|
|
|
192
203
|
// init agent outputs
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import type { ChatContext } from '../../llm/chat_context.js';
|
|
5
|
+
import { FunctionCall } from '../../llm/chat_context.js';
|
|
6
|
+
import { LLMStream as BaseLLMStream, LLM, type LLMStream } from '../../llm/llm.js';
|
|
7
|
+
import type { ToolChoice, ToolContext } from '../../llm/tool_context.js';
|
|
8
|
+
import { type APIConnectOptions, DEFAULT_API_CONNECT_OPTIONS } from '../../types.js';
|
|
9
|
+
import { delay } from '../../utils.js';
|
|
10
|
+
|
|
11
|
+
export interface FakeLLMResponse {
|
|
12
|
+
input: string;
|
|
13
|
+
type?: 'llm';
|
|
14
|
+
content?: string;
|
|
15
|
+
ttft?: number;
|
|
16
|
+
duration?: number;
|
|
17
|
+
toolCalls?: Array<{ name: string; args: Record<string, unknown> }>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class FakeLLM extends LLM {
|
|
21
|
+
private readonly responseMap = new Map<string, FakeLLMResponse>();
|
|
22
|
+
|
|
23
|
+
constructor(responses: FakeLLMResponse[] = []) {
|
|
24
|
+
super();
|
|
25
|
+
for (const response of responses) {
|
|
26
|
+
this.responseMap.set(response.input, {
|
|
27
|
+
type: 'llm',
|
|
28
|
+
ttft: 0,
|
|
29
|
+
duration: 0,
|
|
30
|
+
...response,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
label(): string {
|
|
36
|
+
return 'fake-llm';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
chat({
|
|
40
|
+
chatCtx,
|
|
41
|
+
toolCtx,
|
|
42
|
+
connOptions = DEFAULT_API_CONNECT_OPTIONS,
|
|
43
|
+
}: {
|
|
44
|
+
chatCtx: ChatContext;
|
|
45
|
+
toolCtx?: ToolContext;
|
|
46
|
+
connOptions?: APIConnectOptions;
|
|
47
|
+
parallelToolCalls?: boolean;
|
|
48
|
+
toolChoice?: ToolChoice;
|
|
49
|
+
extraKwargs?: Record<string, unknown>;
|
|
50
|
+
}): LLMStream {
|
|
51
|
+
return new FakeLLMStream(this, {
|
|
52
|
+
chatCtx,
|
|
53
|
+
toolCtx,
|
|
54
|
+
connOptions,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
lookup(input: string): FakeLLMResponse | undefined {
|
|
59
|
+
return this.responseMap.get(input);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
class FakeLLMStream extends BaseLLMStream {
|
|
64
|
+
private readonly fake: FakeLLM;
|
|
65
|
+
|
|
66
|
+
constructor(
|
|
67
|
+
fake: FakeLLM,
|
|
68
|
+
params: { chatCtx: ChatContext; toolCtx?: ToolContext; connOptions: APIConnectOptions },
|
|
69
|
+
) {
|
|
70
|
+
super(fake, params);
|
|
71
|
+
this.fake = fake;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected async run(): Promise<void> {
|
|
75
|
+
const input = this.getInputText();
|
|
76
|
+
const decision = this.fake.lookup(input);
|
|
77
|
+
if (!decision) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const startedAt = Date.now();
|
|
82
|
+
if ((decision.ttft ?? 0) > 0) {
|
|
83
|
+
await delay(decision.ttft!);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const content = decision.content ?? '';
|
|
87
|
+
const chunkSize = 3;
|
|
88
|
+
for (let i = 0; i < content.length; i += chunkSize) {
|
|
89
|
+
this.queue.put({
|
|
90
|
+
id: 'fake',
|
|
91
|
+
delta: { role: 'assistant', content: content.slice(i, i + chunkSize) },
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (decision.toolCalls && decision.toolCalls.length > 0) {
|
|
96
|
+
const calls = decision.toolCalls.map((tc, index) =>
|
|
97
|
+
FunctionCall.create({
|
|
98
|
+
callId: `fake_call_${index}`,
|
|
99
|
+
name: tc.name,
|
|
100
|
+
args: JSON.stringify(tc.args),
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
this.queue.put({
|
|
104
|
+
id: 'fake',
|
|
105
|
+
delta: { role: 'assistant', toolCalls: calls },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const elapsed = Date.now() - startedAt;
|
|
110
|
+
const waitMs = Math.max(0, (decision.duration ?? 0) - elapsed);
|
|
111
|
+
if (waitMs > 0) {
|
|
112
|
+
await delay(waitMs);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private getInputText(): string {
|
|
117
|
+
const items = this.chatCtx.items;
|
|
118
|
+
if (items.length === 0) {
|
|
119
|
+
throw new Error('No input text found');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const item of items) {
|
|
123
|
+
if (item.type === 'message' && item.role === 'system') {
|
|
124
|
+
const text = item.textContent ?? '';
|
|
125
|
+
const lines = text.split('\n');
|
|
126
|
+
const tail = lines[lines.length - 1] ?? '';
|
|
127
|
+
if (lines.length > 1 && tail.startsWith('instructions:')) {
|
|
128
|
+
return tail;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const last = items[items.length - 1]!;
|
|
134
|
+
if (last.type === 'message' && last.role === 'user') return last.textContent ?? '';
|
|
135
|
+
if (last.type === 'function_call_output') return last.output;
|
|
136
|
+
throw new Error('No input text found');
|
|
137
|
+
}
|
|
138
|
+
}
|
package/src/worker.ts
CHANGED
|
@@ -13,8 +13,8 @@ import {
|
|
|
13
13
|
import type { ParticipantInfo } from 'livekit-server-sdk';
|
|
14
14
|
import { AccessToken, RoomServiceClient } from 'livekit-server-sdk';
|
|
15
15
|
import { EventEmitter } from 'node:events';
|
|
16
|
-
import os from 'node:os';
|
|
17
16
|
import { WebSocket } from 'ws';
|
|
17
|
+
import { getCpuMonitor } from './cpu.js';
|
|
18
18
|
import { HTTPServer } from './http_server.js';
|
|
19
19
|
import { InferenceRunner } from './inference_runner.js';
|
|
20
20
|
import { InferenceProcExecutor } from './ipc/inference_proc_executor.js';
|
|
@@ -79,32 +79,11 @@ const defaultRequestFunc = async (ctx: JobRequest) => {
|
|
|
79
79
|
await ctx.accept();
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
const defaultCpuLoad = async (worker: AgentServer): Promise<number> => {
|
|
84
|
-
return new Promise((resolve) => {
|
|
85
|
-
const cpus1 = os.cpus();
|
|
86
|
-
|
|
87
|
-
setTimeout(() => {
|
|
88
|
-
const cpus2 = os.cpus();
|
|
89
|
-
|
|
90
|
-
let idle = 0;
|
|
91
|
-
let total = 0;
|
|
92
|
-
|
|
93
|
-
for (let i = 0; i < cpus1.length; i++) {
|
|
94
|
-
const cpu1 = cpus1[i]!.times;
|
|
95
|
-
const cpu2 = cpus2[i]!.times;
|
|
96
|
-
|
|
97
|
-
idle += cpu2.idle - cpu1.idle;
|
|
98
|
-
|
|
99
|
-
const total1 = Object.values(cpu1).reduce((acc, i) => acc + i, 0);
|
|
100
|
-
const total2 = Object.values(cpu2).reduce((acc, i) => acc + i, 0);
|
|
82
|
+
const cpuMonitor = getCpuMonitor();
|
|
101
83
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
resolve(+(1 - idle / total).toFixed(2));
|
|
106
|
-
}, UPDATE_LOAD_INTERVAL);
|
|
107
|
-
});
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
85
|
+
const defaultCpuLoad = async (_worker: AgentServer): Promise<number> => {
|
|
86
|
+
return cpuMonitor.cpuPercent(UPDATE_LOAD_INTERVAL);
|
|
108
87
|
};
|
|
109
88
|
|
|
110
89
|
/** Participant permissions to pass to every agent spun up by this worker. */
|
|
@@ -651,33 +630,38 @@ export class AgentServer {
|
|
|
651
630
|
if (closingWS) clearInterval(loadMonitor);
|
|
652
631
|
|
|
653
632
|
const oldStatus = currentStatus;
|
|
654
|
-
this.#opts
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
if (
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
633
|
+
this.#opts
|
|
634
|
+
.loadFunc(this)
|
|
635
|
+
.then((currentLoad: number) => {
|
|
636
|
+
const isFull = currentLoad >= this.#opts.loadThreshold;
|
|
637
|
+
const currentlyAvailable = !isFull;
|
|
638
|
+
currentStatus = currentlyAvailable ? WorkerStatus.WS_AVAILABLE : WorkerStatus.WS_FULL;
|
|
639
|
+
|
|
640
|
+
if (oldStatus != currentStatus) {
|
|
641
|
+
const extra = { load: currentLoad, loadThreshold: this.#opts.loadThreshold };
|
|
642
|
+
if (isFull) {
|
|
643
|
+
this.#logger.child(extra).info('worker is at full capacity, marking as unavailable');
|
|
644
|
+
} else {
|
|
645
|
+
this.#logger.child(extra).info('worker is below capacity, marking as available');
|
|
646
|
+
}
|
|
665
647
|
}
|
|
666
|
-
}
|
|
667
648
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
649
|
+
this.event.emit(
|
|
650
|
+
'worker_msg',
|
|
651
|
+
new WorkerMessage({
|
|
652
|
+
message: {
|
|
653
|
+
case: 'updateWorker',
|
|
654
|
+
value: {
|
|
655
|
+
load: currentLoad,
|
|
656
|
+
status: currentStatus,
|
|
657
|
+
},
|
|
676
658
|
},
|
|
677
|
-
},
|
|
678
|
-
|
|
679
|
-
)
|
|
680
|
-
|
|
659
|
+
}),
|
|
660
|
+
);
|
|
661
|
+
})
|
|
662
|
+
.catch((e) => {
|
|
663
|
+
this.#logger.warn({ error: e }, 'failed to measure CPU load');
|
|
664
|
+
});
|
|
681
665
|
}, UPDATE_LOAD_INTERVAL);
|
|
682
666
|
|
|
683
667
|
await close;
|