@livekit/agents 1.0.34 → 1.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs.map +1 -1
- package/dist/inference/api_protos.d.cts +4 -4
- package/dist/inference/api_protos.d.ts +4 -4
- package/dist/inference/llm.cjs +30 -3
- package/dist/inference/llm.cjs.map +1 -1
- package/dist/inference/llm.d.cts +3 -1
- package/dist/inference/llm.d.ts +3 -1
- package/dist/inference/llm.d.ts.map +1 -1
- package/dist/inference/llm.js +30 -3
- package/dist/inference/llm.js.map +1 -1
- package/dist/ipc/inference_proc_executor.cjs.map +1 -1
- package/dist/ipc/job_proc_executor.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs +1 -1
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +1 -1
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/llm/chat_context.cjs +20 -2
- package/dist/llm/chat_context.cjs.map +1 -1
- package/dist/llm/chat_context.d.cts +9 -0
- package/dist/llm/chat_context.d.ts +9 -0
- package/dist/llm/chat_context.d.ts.map +1 -1
- package/dist/llm/chat_context.js +20 -2
- package/dist/llm/chat_context.js.map +1 -1
- 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.map +1 -1
- package/dist/llm/provider_format/openai.cjs +43 -20
- package/dist/llm/provider_format/openai.cjs.map +1 -1
- package/dist/llm/provider_format/openai.d.ts.map +1 -1
- package/dist/llm/provider_format/openai.js +43 -20
- package/dist/llm/provider_format/openai.js.map +1 -1
- package/dist/llm/provider_format/openai.test.cjs +35 -0
- package/dist/llm/provider_format/openai.test.cjs.map +1 -1
- package/dist/llm/provider_format/openai.test.js +35 -0
- package/dist/llm/provider_format/openai.test.js.map +1 -1
- package/dist/llm/provider_format/utils.cjs +1 -1
- package/dist/llm/provider_format/utils.cjs.map +1 -1
- package/dist/llm/provider_format/utils.d.ts.map +1 -1
- package/dist/llm/provider_format/utils.js +1 -1
- package/dist/llm/provider_format/utils.js.map +1 -1
- package/dist/voice/background_audio.cjs.map +1 -1
- package/dist/voice/generation.cjs +2 -1
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.ts.map +1 -1
- package/dist/voice/generation.js +2 -1
- package/dist/voice/generation.js.map +1 -1
- package/package.json +1 -1
- package/src/inference/llm.ts +42 -3
- package/src/ipc/job_proc_lazy_main.ts +1 -1
- package/src/llm/chat_context.ts +32 -2
- package/src/llm/llm.ts +1 -0
- package/src/llm/provider_format/openai.test.ts +40 -0
- package/src/llm/provider_format/openai.ts +46 -19
- package/src/llm/provider_format/utils.ts +5 -1
- package/src/voice/generation.ts +1 -0
package/src/llm/chat_context.ts
CHANGED
|
@@ -189,6 +189,12 @@ export class FunctionCall {
|
|
|
189
189
|
|
|
190
190
|
createdAt: number;
|
|
191
191
|
|
|
192
|
+
extra: Record<string, unknown>;
|
|
193
|
+
/**
|
|
194
|
+
* Optional grouping identifier for parallel tool calls.
|
|
195
|
+
*/
|
|
196
|
+
groupId?: string;
|
|
197
|
+
|
|
192
198
|
/**
|
|
193
199
|
* Opaque signature for Gemini thinking mode.
|
|
194
200
|
* When using Gemini 3+ models with thinking enabled, this signature must be
|
|
@@ -202,6 +208,8 @@ export class FunctionCall {
|
|
|
202
208
|
args: string;
|
|
203
209
|
id?: string;
|
|
204
210
|
createdAt?: number;
|
|
211
|
+
extra?: Record<string, unknown>;
|
|
212
|
+
groupId?: string;
|
|
205
213
|
thoughtSignature?: string;
|
|
206
214
|
}) {
|
|
207
215
|
const {
|
|
@@ -210,6 +218,8 @@ export class FunctionCall {
|
|
|
210
218
|
args,
|
|
211
219
|
id = shortuuid('item_'),
|
|
212
220
|
createdAt = Date.now(),
|
|
221
|
+
extra = {},
|
|
222
|
+
groupId,
|
|
213
223
|
thoughtSignature,
|
|
214
224
|
} = params;
|
|
215
225
|
this.id = id;
|
|
@@ -217,7 +227,15 @@ export class FunctionCall {
|
|
|
217
227
|
this.args = args;
|
|
218
228
|
this.name = name;
|
|
219
229
|
this.createdAt = createdAt;
|
|
220
|
-
this.
|
|
230
|
+
this.extra = { ...extra };
|
|
231
|
+
this.groupId = groupId;
|
|
232
|
+
this.thoughtSignature =
|
|
233
|
+
thoughtSignature ??
|
|
234
|
+
(typeof this.extra.google === 'object' && this.extra.google !== null
|
|
235
|
+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
236
|
+
(this.extra.google as any).thoughtSignature ||
|
|
237
|
+
(this.extra.google as any).thought_signature
|
|
238
|
+
: undefined);
|
|
221
239
|
}
|
|
222
240
|
|
|
223
241
|
static create(params: {
|
|
@@ -226,6 +244,8 @@ export class FunctionCall {
|
|
|
226
244
|
args: string;
|
|
227
245
|
id?: string;
|
|
228
246
|
createdAt?: number;
|
|
247
|
+
extra?: Record<string, unknown>;
|
|
248
|
+
groupId?: string;
|
|
229
249
|
thoughtSignature?: string;
|
|
230
250
|
}) {
|
|
231
251
|
return new FunctionCall(params);
|
|
@@ -241,6 +261,14 @@ export class FunctionCall {
|
|
|
241
261
|
args: this.args,
|
|
242
262
|
};
|
|
243
263
|
|
|
264
|
+
if (Object.keys(this.extra).length > 0) {
|
|
265
|
+
result.extra = this.extra as JSONValue;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (this.groupId) {
|
|
269
|
+
result.groupId = this.groupId;
|
|
270
|
+
}
|
|
271
|
+
|
|
244
272
|
if (this.thoughtSignature) {
|
|
245
273
|
result.thoughtSignature = this.thoughtSignature;
|
|
246
274
|
}
|
|
@@ -627,7 +655,9 @@ export class ChatContext {
|
|
|
627
655
|
a.name !== b.name ||
|
|
628
656
|
a.callId !== b.callId ||
|
|
629
657
|
a.args !== b.args ||
|
|
630
|
-
a.thoughtSignature !== b.thoughtSignature
|
|
658
|
+
a.thoughtSignature !== b.thoughtSignature ||
|
|
659
|
+
a.groupId !== b.groupId ||
|
|
660
|
+
JSON.stringify(a.extra) !== JSON.stringify(b.extra)
|
|
631
661
|
) {
|
|
632
662
|
return false;
|
|
633
663
|
}
|
package/src/llm/llm.ts
CHANGED
|
@@ -258,6 +258,46 @@ describe('toChatCtx', () => {
|
|
|
258
258
|
]);
|
|
259
259
|
});
|
|
260
260
|
|
|
261
|
+
it('should include provider-specific extra content on tool calls', async () => {
|
|
262
|
+
const ctx = ChatContext.empty();
|
|
263
|
+
const msg = ctx.addMessage({ role: 'assistant', content: 'Running tool' });
|
|
264
|
+
|
|
265
|
+
const toolCall = FunctionCall.create({
|
|
266
|
+
id: `${msg.id}/tool_1`,
|
|
267
|
+
callId: 'call_789',
|
|
268
|
+
name: 'google_call',
|
|
269
|
+
args: '{}',
|
|
270
|
+
extra: { google: { thoughtSignature: 'sig-123' } },
|
|
271
|
+
});
|
|
272
|
+
const toolOutput = FunctionCallOutput.create({
|
|
273
|
+
callId: 'call_789',
|
|
274
|
+
output: '{"result": "ok"}',
|
|
275
|
+
isError: false,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
ctx.insert([toolCall, toolOutput]);
|
|
279
|
+
|
|
280
|
+
const result = await toChatCtx(ctx);
|
|
281
|
+
|
|
282
|
+
expect(result[0]).toEqual({
|
|
283
|
+
role: 'assistant',
|
|
284
|
+
content: 'Running tool',
|
|
285
|
+
tool_calls: [
|
|
286
|
+
{
|
|
287
|
+
type: 'function',
|
|
288
|
+
id: 'call_789',
|
|
289
|
+
function: { name: 'google_call', arguments: '{}' },
|
|
290
|
+
extra_content: { google: { thoughtSignature: 'sig-123' } },
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
});
|
|
294
|
+
expect(result[1]).toEqual({
|
|
295
|
+
role: 'tool',
|
|
296
|
+
tool_call_id: 'call_789',
|
|
297
|
+
content: '{"result": "ok"}',
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
261
301
|
it('should handle multiple tool calls in one message', async () => {
|
|
262
302
|
const ctx = ChatContext.empty();
|
|
263
303
|
|
|
@@ -17,11 +17,20 @@ export async function toChatCtx(chatCtx: ChatContext, injectDummyUserMessage: bo
|
|
|
17
17
|
? await toChatItem(group.message)
|
|
18
18
|
: { role: 'assistant' };
|
|
19
19
|
|
|
20
|
-
const toolCalls = group.toolCalls.map((toolCall) =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
const toolCalls = group.toolCalls.map((toolCall) => {
|
|
21
|
+
const tc: Record<string, any> = {
|
|
22
|
+
type: 'function',
|
|
23
|
+
id: toolCall.callId,
|
|
24
|
+
function: { name: toolCall.name, arguments: toolCall.args },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Include provider-specific extra content (e.g., Google thought signatures)
|
|
28
|
+
const googleExtra = getGoogleExtra(toolCall);
|
|
29
|
+
if (googleExtra) {
|
|
30
|
+
tc.extra_content = { google: googleExtra };
|
|
31
|
+
}
|
|
32
|
+
return tc;
|
|
33
|
+
});
|
|
25
34
|
|
|
26
35
|
if (toolCalls.length > 0) {
|
|
27
36
|
message['tool_calls'] = toolCalls;
|
|
@@ -53,24 +62,33 @@ async function toChatItem(item: ChatItem) {
|
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
const result: Record<string, any> = { role: item.role };
|
|
66
|
+
if (listContent.length === 0) {
|
|
67
|
+
result.content = textContent;
|
|
68
|
+
} else {
|
|
69
|
+
if (textContent.length > 0) {
|
|
70
|
+
listContent.push({ type: 'text', text: textContent });
|
|
71
|
+
}
|
|
72
|
+
result.content = listContent;
|
|
73
|
+
}
|
|
62
74
|
|
|
63
|
-
return
|
|
75
|
+
return result;
|
|
64
76
|
} else if (item.type === 'function_call') {
|
|
77
|
+
const tc: Record<string, any> = {
|
|
78
|
+
id: item.callId,
|
|
79
|
+
type: 'function',
|
|
80
|
+
function: { name: item.name, arguments: item.args },
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Include provider-specific extra content (e.g., Google thought signatures)
|
|
84
|
+
const googleExtra = getGoogleExtra(item);
|
|
85
|
+
if (googleExtra) {
|
|
86
|
+
tc.extra_content = { google: googleExtra };
|
|
87
|
+
}
|
|
88
|
+
|
|
65
89
|
return {
|
|
66
90
|
role: 'assistant',
|
|
67
|
-
tool_calls: [
|
|
68
|
-
{
|
|
69
|
-
id: item.callId,
|
|
70
|
-
type: 'function',
|
|
71
|
-
function: { name: item.name, arguments: item.args },
|
|
72
|
-
},
|
|
73
|
-
],
|
|
91
|
+
tool_calls: [tc],
|
|
74
92
|
};
|
|
75
93
|
} else if (item.type === 'function_call_output') {
|
|
76
94
|
return {
|
|
@@ -84,6 +102,15 @@ async function toChatItem(item: ChatItem) {
|
|
|
84
102
|
throw new Error(`Unsupported item type: ${item['type']}`);
|
|
85
103
|
}
|
|
86
104
|
|
|
105
|
+
function getGoogleExtra(
|
|
106
|
+
item: Partial<{ extra?: Record<string, unknown>; thoughtSignature?: string }>,
|
|
107
|
+
): Record<string, unknown> | undefined {
|
|
108
|
+
const googleExtra =
|
|
109
|
+
(item.extra?.google as Record<string, unknown> | undefined) ||
|
|
110
|
+
(item.thoughtSignature ? { thoughtSignature: item.thoughtSignature } : undefined);
|
|
111
|
+
return googleExtra;
|
|
112
|
+
}
|
|
113
|
+
|
|
87
114
|
async function toImageContent(content: ImageContent) {
|
|
88
115
|
const cacheKey = 'serialized_image'; // TODO: use hash of encoding options if available
|
|
89
116
|
let serialized: SerializedImage;
|
|
@@ -133,7 +133,11 @@ export function groupToolCalls(chatCtx: ChatContext) {
|
|
|
133
133
|
|
|
134
134
|
if (isAssistantMessage || isFunctionCall) {
|
|
135
135
|
// only assistant messages and function calls can be grouped
|
|
136
|
-
|
|
136
|
+
// For function calls, use group_id if available (for parallel function calls),
|
|
137
|
+
// otherwise fall back to id-based grouping for backwards compatibility
|
|
138
|
+
const groupId =
|
|
139
|
+
item.type === 'function_call' && item.groupId ? item.groupId : item.id.split('/')[0]!;
|
|
140
|
+
|
|
137
141
|
if (itemGroups[groupId] === undefined) {
|
|
138
142
|
itemGroups[groupId] = ChatItemGroup.create();
|
|
139
143
|
|
package/src/voice/generation.ts
CHANGED