@livekit/agents-plugin-openai 1.2.3 → 1.2.5
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 +1 -1
- package/dist/index.js +1 -1
- package/dist/realtime/realtime_model.cjs +73 -9
- package/dist/realtime/realtime_model.cjs.map +1 -1
- package/dist/realtime/realtime_model.d.ts.map +1 -1
- package/dist/realtime/realtime_model.js +73 -9
- package/dist/realtime/realtime_model.js.map +1 -1
- package/dist/realtime/realtime_model_beta.cjs +5 -1
- package/dist/realtime/realtime_model_beta.cjs.map +1 -1
- package/dist/realtime/realtime_model_beta.d.ts.map +1 -1
- package/dist/realtime/realtime_model_beta.js +5 -1
- package/dist/realtime/realtime_model_beta.js.map +1 -1
- package/dist/responses/llm.cjs +5 -1
- package/dist/responses/llm.cjs.map +1 -1
- package/dist/responses/llm.d.cts +2 -0
- package/dist/responses/llm.d.ts +2 -0
- package/dist/responses/llm.d.ts.map +1 -1
- package/dist/responses/llm.js +5 -1
- package/dist/responses/llm.js.map +1 -1
- package/dist/ws/llm.cjs +5 -1
- package/dist/ws/llm.cjs.map +1 -1
- package/dist/ws/llm.d.cts +2 -0
- package/dist/ws/llm.d.ts +2 -0
- package/dist/ws/llm.d.ts.map +1 -1
- package/dist/ws/llm.js +5 -1
- package/dist/ws/llm.js.map +1 -1
- package/dist/ws/types.cjs +1 -0
- package/dist/ws/types.cjs.map +1 -1
- package/dist/ws/types.d.cts +2 -0
- package/dist/ws/types.d.ts +2 -0
- package/dist/ws/types.d.ts.map +1 -1
- package/dist/ws/types.js +1 -0
- package/dist/ws/types.js.map +1 -1
- package/package.json +7 -7
- package/src/realtime/realtime_model.ts +80 -10
- package/src/realtime/realtime_model_beta.ts +4 -0
- package/src/responses/llm.ts +7 -0
- package/src/ws/llm.ts +7 -0
- package/src/ws/types.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/agents-plugin-openai",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "OpenAI plugin for LiveKit Node Agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"require": "dist/index.cjs",
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@livekit/rtc-node": "^0.13.
|
|
28
|
+
"@livekit/rtc-node": "^0.13.25",
|
|
29
29
|
"@microsoft/api-extractor": "^7.35.0",
|
|
30
30
|
"@types/ws": "^8.5.10",
|
|
31
31
|
"tsup": "^8.3.5",
|
|
32
32
|
"typescript": "^5.0.0",
|
|
33
|
-
"@livekit/agents": "1.2.
|
|
34
|
-
"@livekit/agents-plugin-silero": "1.2.
|
|
35
|
-
"@livekit/agents-plugins-test": "1.2.
|
|
33
|
+
"@livekit/agents": "1.2.5",
|
|
34
|
+
"@livekit/agents-plugin-silero": "1.2.5",
|
|
35
|
+
"@livekit/agents-plugins-test": "1.2.5"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@livekit/mutex": "^1.1.1",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"ws": "^8.18.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@livekit/rtc-node": "^0.13.
|
|
43
|
+
"@livekit/rtc-node": "^0.13.25",
|
|
44
44
|
"zod": "^3.25.76 || ^4.1.8",
|
|
45
|
-
"@livekit/agents": "1.2.
|
|
45
|
+
"@livekit/agents": "1.2.5"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "tsup --onSuccess \"pnpm build:types\"",
|
|
@@ -185,6 +185,10 @@ export class RealtimeModel extends llm.RealtimeModel {
|
|
|
185
185
|
autoToolReplyGeneration: false,
|
|
186
186
|
audioOutput: modalities.includes('audio'),
|
|
187
187
|
manualFunctionCalls: true,
|
|
188
|
+
midSessionChatCtxUpdate: true,
|
|
189
|
+
midSessionInstructionsUpdate: true,
|
|
190
|
+
midSessionToolsUpdate: true,
|
|
191
|
+
perResponseToolChoice: true,
|
|
188
192
|
});
|
|
189
193
|
|
|
190
194
|
const isAzure = !!(options.apiVersion || options.entraToken || options.azureDeployment);
|
|
@@ -477,17 +481,75 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
477
481
|
async updateChatCtx(_chatCtx: llm.ChatContext): Promise<void> {
|
|
478
482
|
const unlock = await this.updateChatCtxLock.lock();
|
|
479
483
|
try {
|
|
484
|
+
const validation = llm.validateChatContextStructure(_chatCtx);
|
|
485
|
+
const blockingErrors = validation.issues.filter(
|
|
486
|
+
(issue: llm.ChatContextValidationIssue) =>
|
|
487
|
+
issue.severity === 'error' && issue.code !== 'timestamp_order',
|
|
488
|
+
);
|
|
489
|
+
const timestampOrderIssue = validation.issues.find(
|
|
490
|
+
(issue: llm.ChatContextValidationIssue) => issue.code === 'timestamp_order',
|
|
491
|
+
);
|
|
492
|
+
if (blockingErrors.length > 0) {
|
|
493
|
+
this.#logger.error(
|
|
494
|
+
{ issues: validation.issues, blockingErrors },
|
|
495
|
+
'Invalid chat context supplied to updateChatCtx',
|
|
496
|
+
);
|
|
497
|
+
throw new Error(
|
|
498
|
+
`Invalid chat context: ${validation.errors} errors, ${validation.warnings} warnings`,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
if (timestampOrderIssue) {
|
|
502
|
+
this.#logger.warn(
|
|
503
|
+
{ timestampOrderIssue },
|
|
504
|
+
'Proceeding with non-monotonic createdAt ordering in realtime chat context',
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
if (lkOaiDebug > 0 && validation.warnings > 0) {
|
|
508
|
+
this.#logger.debug(
|
|
509
|
+
{
|
|
510
|
+
warnings: validation.warnings,
|
|
511
|
+
issues: validation.issues,
|
|
512
|
+
},
|
|
513
|
+
'Chat context warnings detected before realtime update',
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
480
517
|
const events = await this.createChatCtxUpdateEvents(_chatCtx);
|
|
481
518
|
const futures: Future<void>[] = [];
|
|
519
|
+
const ownedCreateFutures: { [id: string]: Future<void> } = {};
|
|
520
|
+
const ownedDeleteFutures: { [id: string]: Future<void> } = {};
|
|
521
|
+
|
|
522
|
+
const cleanupTimedOutFutures = () => {
|
|
523
|
+
// remove timed-out entries so late server acks
|
|
524
|
+
// don't resolve stale futures from a previous updateChatCtx call.
|
|
525
|
+
for (const [itemId, future] of Object.entries(ownedDeleteFutures)) {
|
|
526
|
+
if (this.itemDeleteFutures[itemId] === future) {
|
|
527
|
+
delete this.itemDeleteFutures[itemId];
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
for (const [itemId, future] of Object.entries(ownedCreateFutures)) {
|
|
531
|
+
if (this.itemCreateFutures[itemId] === future) {
|
|
532
|
+
delete this.itemCreateFutures[itemId];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
};
|
|
482
536
|
|
|
483
537
|
for (const event of events) {
|
|
484
|
-
const future = new Future<void>();
|
|
485
|
-
futures.push(future);
|
|
486
|
-
|
|
487
538
|
if (event.type === 'conversation.item.create') {
|
|
539
|
+
const future = new Future<void>();
|
|
540
|
+
futures.push(future);
|
|
488
541
|
this.itemCreateFutures[event.item.id] = future;
|
|
542
|
+
ownedCreateFutures[event.item.id] = future;
|
|
489
543
|
} else if (event.type == 'conversation.item.delete') {
|
|
544
|
+
const existingDeleteFuture = this.itemDeleteFutures[event.item_id];
|
|
545
|
+
if (existingDeleteFuture) {
|
|
546
|
+
futures.push(existingDeleteFuture);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const future = new Future<void>();
|
|
550
|
+
futures.push(future);
|
|
490
551
|
this.itemDeleteFutures[event.item_id] = future;
|
|
552
|
+
ownedDeleteFutures[event.item_id] = future;
|
|
491
553
|
}
|
|
492
554
|
|
|
493
555
|
this.sendEvent(event);
|
|
@@ -497,13 +559,21 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
497
559
|
return;
|
|
498
560
|
}
|
|
499
561
|
|
|
500
|
-
// wait for futures to resolve or timeout
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
562
|
+
// wait for futures to resolve or timeout.
|
|
563
|
+
// Cancel the timeout branch once futures resolve to avoid stale cleanup.
|
|
564
|
+
const timeoutController = new AbortController();
|
|
565
|
+
const timeoutPromise = delay(5000, { signal: timeoutController.signal }).then(() => {
|
|
566
|
+
cleanupTimedOutFutures();
|
|
567
|
+
throw new Error('Chat ctx update events timed out');
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
await Promise.race([Promise.all(futures), timeoutPromise]);
|
|
572
|
+
} finally {
|
|
573
|
+
if (!timeoutController.signal.aborted) {
|
|
574
|
+
timeoutController.abort();
|
|
575
|
+
}
|
|
576
|
+
}
|
|
507
577
|
} catch (e) {
|
|
508
578
|
this.#logger.error((e as Error).message);
|
|
509
579
|
throw e;
|
|
@@ -177,6 +177,10 @@ export class RealtimeModel extends llm.RealtimeModel {
|
|
|
177
177
|
autoToolReplyGeneration: false,
|
|
178
178
|
audioOutput: modalities.includes('audio'),
|
|
179
179
|
manualFunctionCalls: true,
|
|
180
|
+
midSessionChatCtxUpdate: true,
|
|
181
|
+
midSessionInstructionsUpdate: true,
|
|
182
|
+
midSessionToolsUpdate: true,
|
|
183
|
+
perResponseToolChoice: true,
|
|
180
184
|
});
|
|
181
185
|
|
|
182
186
|
const isAzure = !!(options.apiVersion || options.entraToken || options.azureDeployment);
|
package/src/responses/llm.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface LLMOptions {
|
|
|
26
26
|
store?: boolean;
|
|
27
27
|
metadata?: Record<string, string>;
|
|
28
28
|
strictToolSchema?: boolean;
|
|
29
|
+
/** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */
|
|
30
|
+
serviceTier?: string;
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
33
|
* Whether to use the WebSocket API.
|
|
@@ -114,6 +116,10 @@ class ResponsesHttpLLM extends llm.LLM {
|
|
|
114
116
|
modelOptions.metadata = this.#opts.metadata;
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
if (this.#opts.serviceTier) {
|
|
120
|
+
modelOptions.service_tier = this.#opts.serviceTier;
|
|
121
|
+
}
|
|
122
|
+
|
|
117
123
|
return new ResponsesHttpLLMStream(this, {
|
|
118
124
|
model: this.#opts.model,
|
|
119
125
|
client: this.#client,
|
|
@@ -333,6 +339,7 @@ class ResponsesHttpLLMStream extends llm.LLMStream {
|
|
|
333
339
|
promptTokens: event.response.usage.input_tokens,
|
|
334
340
|
promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,
|
|
335
341
|
totalTokens: event.response.usage.total_tokens,
|
|
342
|
+
serviceTier: event.response.service_tier ?? undefined,
|
|
336
343
|
},
|
|
337
344
|
};
|
|
338
345
|
}
|
package/src/ws/llm.ts
CHANGED
|
@@ -141,6 +141,8 @@ export interface WSLLMOptions {
|
|
|
141
141
|
store?: boolean;
|
|
142
142
|
metadata?: Record<string, string>;
|
|
143
143
|
strictToolSchema?: boolean;
|
|
144
|
+
/** Specifies the processing tier (e.g. 'auto', 'default', 'priority', 'flex'). */
|
|
145
|
+
serviceTier?: string;
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
const defaultLLMOptions: WSLLMOptions = {
|
|
@@ -266,6 +268,10 @@ export class WSLLM extends llm.LLM {
|
|
|
266
268
|
modelOptions.metadata = this.#opts.metadata;
|
|
267
269
|
}
|
|
268
270
|
|
|
271
|
+
if (this.#opts.serviceTier) {
|
|
272
|
+
modelOptions.service_tier = this.#opts.serviceTier;
|
|
273
|
+
}
|
|
274
|
+
|
|
269
275
|
let inputChatCtx = chatCtx;
|
|
270
276
|
let prevResponseId: string | undefined;
|
|
271
277
|
const canUseStoredResponse = modelOptions.store !== false;
|
|
@@ -584,6 +590,7 @@ export class WSLLMStream extends llm.LLMStream {
|
|
|
584
590
|
promptTokens: event.response.usage.input_tokens,
|
|
585
591
|
promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,
|
|
586
592
|
totalTokens: event.response.usage.total_tokens,
|
|
593
|
+
serviceTier: event.response.service_tier ?? undefined,
|
|
587
594
|
},
|
|
588
595
|
};
|
|
589
596
|
}
|