@livekit/agents 1.0.46 → 1.0.48
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/cli.cjs +14 -20
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -20
- package/dist/cli.js.map +1 -1
- 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/ipc/job_proc_lazy_main.cjs +14 -5
- package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
- package/dist/ipc/job_proc_lazy_main.js +14 -5
- package/dist/ipc/job_proc_lazy_main.js.map +1 -1
- package/dist/llm/chat_context.cjs +108 -1
- package/dist/llm/chat_context.cjs.map +1 -1
- package/dist/llm/chat_context.d.cts +14 -1
- package/dist/llm/chat_context.d.ts +14 -1
- package/dist/llm/chat_context.d.ts.map +1 -1
- package/dist/llm/chat_context.js +108 -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.cjs +2 -0
- package/dist/llm/provider_format/index.cjs.map +1 -1
- package/dist/llm/provider_format/index.d.cts +2 -2
- package/dist/llm/provider_format/index.d.ts +2 -2
- package/dist/llm/provider_format/index.d.ts.map +1 -1
- package/dist/llm/provider_format/index.js +6 -1
- package/dist/llm/provider_format/index.js.map +1 -1
- package/dist/llm/provider_format/openai.cjs +82 -2
- package/dist/llm/provider_format/openai.cjs.map +1 -1
- package/dist/llm/provider_format/openai.d.cts +1 -0
- package/dist/llm/provider_format/openai.d.ts +1 -0
- package/dist/llm/provider_format/openai.d.ts.map +1 -1
- package/dist/llm/provider_format/openai.js +80 -1
- package/dist/llm/provider_format/openai.js.map +1 -1
- package/dist/llm/provider_format/openai.test.cjs +326 -0
- package/dist/llm/provider_format/openai.test.cjs.map +1 -1
- package/dist/llm/provider_format/openai.test.js +327 -1
- package/dist/llm/provider_format/openai.test.js.map +1 -1
- package/dist/llm/provider_format/utils.cjs +4 -3
- 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 +4 -3
- package/dist/llm/provider_format/utils.js.map +1 -1
- package/dist/llm/realtime.cjs.map +1 -1
- package/dist/llm/realtime.d.cts +1 -0
- package/dist/llm/realtime.d.ts +1 -0
- package/dist/llm/realtime.d.ts.map +1 -1
- package/dist/llm/realtime.js.map +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/log.cjs +5 -2
- package/dist/log.cjs.map +1 -1
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +5 -2
- package/dist/log.js.map +1 -1
- package/dist/stream/deferred_stream.cjs +15 -6
- package/dist/stream/deferred_stream.cjs.map +1 -1
- package/dist/stream/deferred_stream.d.ts.map +1 -1
- package/dist/stream/deferred_stream.js +15 -6
- package/dist/stream/deferred_stream.js.map +1 -1
- package/dist/utils.cjs +32 -2
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +7 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +32 -2
- package/dist/utils.js.map +1 -1
- package/dist/utils.test.cjs +71 -0
- package/dist/utils.test.cjs.map +1 -1
- package/dist/utils.test.js +71 -0
- package/dist/utils.test.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/voice/agent.cjs +153 -12
- package/dist/voice/agent.cjs.map +1 -1
- package/dist/voice/agent.d.cts +30 -4
- package/dist/voice/agent.d.ts +30 -4
- package/dist/voice/agent.d.ts.map +1 -1
- package/dist/voice/agent.js +149 -11
- package/dist/voice/agent.js.map +1 -1
- package/dist/voice/agent.test.cjs +120 -0
- package/dist/voice/agent.test.cjs.map +1 -1
- package/dist/voice/agent.test.js +122 -2
- package/dist/voice/agent.test.js.map +1 -1
- package/dist/voice/agent_activity.cjs +406 -298
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +41 -7
- package/dist/voice/agent_activity.d.ts +41 -7
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +407 -294
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +140 -40
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +19 -7
- package/dist/voice/agent_session.d.ts +19 -7
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +137 -37
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +4 -0
- 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 +4 -0
- package/dist/voice/audio_recognition.js.map +1 -1
- package/dist/voice/generation.cjs +39 -19
- package/dist/voice/generation.cjs.map +1 -1
- package/dist/voice/generation.d.ts.map +1 -1
- package/dist/voice/generation.js +44 -20
- 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 -1
- package/dist/voice/index.d.ts +1 -1
- package/dist/voice/index.d.ts.map +1 -1
- package/dist/voice/index.js +2 -1
- package/dist/voice/index.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/speech_handle.cjs +7 -1
- package/dist/voice/speech_handle.cjs.map +1 -1
- package/dist/voice/speech_handle.d.cts +2 -0
- package/dist/voice/speech_handle.d.ts +2 -0
- package/dist/voice/speech_handle.d.ts.map +1 -1
- package/dist/voice/speech_handle.js +8 -2
- package/dist/voice/speech_handle.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/voice/testing/run_result.cjs +66 -15
- package/dist/voice/testing/run_result.cjs.map +1 -1
- package/dist/voice/testing/run_result.d.cts +14 -3
- package/dist/voice/testing/run_result.d.ts +14 -3
- package/dist/voice/testing/run_result.d.ts.map +1 -1
- package/dist/voice/testing/run_result.js +66 -15
- package/dist/voice/testing/run_result.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/cli.ts +20 -33
- package/src/index.ts +2 -1
- package/src/ipc/job_proc_lazy_main.ts +16 -5
- package/src/llm/chat_context.test.ts +48 -0
- package/src/llm/chat_context.ts +158 -0
- package/src/llm/index.ts +1 -0
- package/src/llm/provider_format/index.ts +7 -2
- package/src/llm/provider_format/openai.test.ts +385 -1
- package/src/llm/provider_format/openai.ts +103 -0
- package/src/llm/provider_format/utils.ts +6 -4
- package/src/llm/realtime.ts +1 -0
- package/src/llm/tool_context.ts +14 -0
- package/src/log.ts +5 -2
- package/src/stream/deferred_stream.ts +17 -6
- package/src/utils.test.ts +87 -0
- package/src/utils.ts +41 -2
- package/src/version.ts +1 -1
- package/src/voice/agent.test.ts +140 -2
- package/src/voice/agent.ts +200 -10
- package/src/voice/agent_activity.ts +466 -290
- package/src/voice/agent_session.ts +178 -40
- package/src/voice/audio_recognition.ts +4 -0
- package/src/voice/generation.ts +52 -23
- package/src/voice/index.ts +1 -1
- package/src/voice/room_io/room_io.ts +14 -3
- package/src/voice/speech_handle.ts +9 -2
- package/src/voice/testing/fake_llm.ts +138 -0
- package/src/voice/testing/index.ts +2 -0
- package/src/voice/testing/run_result.ts +81 -23
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { initializeLogger } from '../log.js';
|
|
6
|
+
import { FakeLLM } from '../voice/testing/fake_llm.js';
|
|
5
7
|
import {
|
|
6
8
|
type AudioContent,
|
|
7
9
|
ChatContext,
|
|
@@ -13,6 +15,8 @@ import {
|
|
|
13
15
|
ReadonlyChatContext,
|
|
14
16
|
} from './chat_context.js';
|
|
15
17
|
|
|
18
|
+
initializeLogger({ pretty: false, level: 'error' });
|
|
19
|
+
|
|
16
20
|
describe('ChatContext.toJSON', () => {
|
|
17
21
|
it('should match snapshot for empty context', () => {
|
|
18
22
|
const context = new ChatContext();
|
|
@@ -283,6 +287,50 @@ describe('ChatContext.toJSON', () => {
|
|
|
283
287
|
});
|
|
284
288
|
});
|
|
285
289
|
|
|
290
|
+
describe('ChatContext._summarize', () => {
|
|
291
|
+
it('keeps chronological timestamps with summary + tail', async () => {
|
|
292
|
+
const ctx = new ChatContext();
|
|
293
|
+
ctx.addMessage({ role: 'system', content: 'System prompt', createdAt: 0 });
|
|
294
|
+
ctx.addMessage({ role: 'user', content: 'hello', createdAt: 1000 });
|
|
295
|
+
ctx.addMessage({ role: 'assistant', content: 'hi there', createdAt: 2000 });
|
|
296
|
+
ctx.insert(
|
|
297
|
+
new FunctionCallOutput({
|
|
298
|
+
callId: 'call_1',
|
|
299
|
+
name: 'lookup',
|
|
300
|
+
output: '{"ok":true}',
|
|
301
|
+
isError: false,
|
|
302
|
+
createdAt: 3500,
|
|
303
|
+
}),
|
|
304
|
+
);
|
|
305
|
+
ctx.addMessage({ role: 'user', content: 'my color is blue', createdAt: 3000 });
|
|
306
|
+
ctx.addMessage({ role: 'assistant', content: 'noted', createdAt: 4000 });
|
|
307
|
+
|
|
308
|
+
const fake = new FakeLLM([
|
|
309
|
+
{
|
|
310
|
+
input: 'Conversation to summarize:\n\nuser: hello\nassistant: hi there',
|
|
311
|
+
content: 'condensed head',
|
|
312
|
+
},
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
await ctx._summarize(fake, { keepLastTurns: 1 });
|
|
316
|
+
|
|
317
|
+
const summary = ctx.items.find(
|
|
318
|
+
(item) =>
|
|
319
|
+
item.type === 'message' && item.role === 'assistant' && item.extra?.is_summary === true,
|
|
320
|
+
);
|
|
321
|
+
expect(summary).toBeDefined();
|
|
322
|
+
if (!summary || summary.type !== 'message') {
|
|
323
|
+
throw new Error('summary message is missing');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
expect(summary.createdAt).toBeCloseTo(2999.999, 6);
|
|
327
|
+
|
|
328
|
+
const createdAts = ctx.items.map((item) => item.createdAt);
|
|
329
|
+
const sorted = [...createdAts].sort((a, b) => a - b);
|
|
330
|
+
expect(createdAts).toEqual(sorted);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
286
334
|
describe('ReadonlyChatContext with immutable array', () => {
|
|
287
335
|
it('should have readonly property set to true', () => {
|
|
288
336
|
const items: ChatItem[] = [
|
package/src/llm/chat_context.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import type { AudioFrame, VideoFrame } from '@livekit/rtc-node';
|
|
5
5
|
import { createImmutableArray, shortuuid } from '../utils.js';
|
|
6
|
+
import type { LLM } from './llm.js';
|
|
6
7
|
import { type ProviderFormat, toChatCtx } from './provider_format/index.js';
|
|
7
8
|
import type { JSONObject, JSONValue, ToolContext } from './tool_context.js';
|
|
8
9
|
|
|
@@ -95,12 +96,15 @@ export class ChatMessage {
|
|
|
95
96
|
|
|
96
97
|
createdAt: number;
|
|
97
98
|
|
|
99
|
+
extra: Record<string, unknown>;
|
|
100
|
+
|
|
98
101
|
constructor(params: {
|
|
99
102
|
role: ChatRole;
|
|
100
103
|
content: ChatContent[] | string;
|
|
101
104
|
id?: string;
|
|
102
105
|
interrupted?: boolean;
|
|
103
106
|
createdAt?: number;
|
|
107
|
+
extra?: Record<string, unknown>;
|
|
104
108
|
}) {
|
|
105
109
|
const {
|
|
106
110
|
role,
|
|
@@ -108,12 +112,14 @@ export class ChatMessage {
|
|
|
108
112
|
id = shortuuid('item_'),
|
|
109
113
|
interrupted = false,
|
|
110
114
|
createdAt = Date.now(),
|
|
115
|
+
extra = {},
|
|
111
116
|
} = params;
|
|
112
117
|
this.id = id;
|
|
113
118
|
this.role = role;
|
|
114
119
|
this.content = Array.isArray(content) ? content : [content];
|
|
115
120
|
this.interrupted = interrupted;
|
|
116
121
|
this.createdAt = createdAt;
|
|
122
|
+
this.extra = extra;
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
static create(params: {
|
|
@@ -122,6 +128,7 @@ export class ChatMessage {
|
|
|
122
128
|
id?: string;
|
|
123
129
|
interrupted?: boolean;
|
|
124
130
|
createdAt?: number;
|
|
131
|
+
extra?: Record<string, unknown>;
|
|
125
132
|
}) {
|
|
126
133
|
return new ChatMessage(params);
|
|
127
134
|
}
|
|
@@ -401,6 +408,7 @@ export class AgentHandoffItem {
|
|
|
401
408
|
}
|
|
402
409
|
}
|
|
403
410
|
|
|
411
|
+
// TODO(parity): Add AgentConfigUpdate type to ChatItem union
|
|
404
412
|
export type ChatItem = ChatMessage | FunctionCall | FunctionCallOutput | AgentHandoffItem;
|
|
405
413
|
|
|
406
414
|
export class ChatContext {
|
|
@@ -431,6 +439,7 @@ export class ChatContext {
|
|
|
431
439
|
id?: string;
|
|
432
440
|
interrupted?: boolean;
|
|
433
441
|
createdAt?: number;
|
|
442
|
+
extra?: Record<string, unknown>;
|
|
434
443
|
}): ChatMessage {
|
|
435
444
|
const msg = new ChatMessage(params);
|
|
436
445
|
if (params.createdAt !== undefined) {
|
|
@@ -463,11 +472,13 @@ export class ChatContext {
|
|
|
463
472
|
return idx !== -1 ? idx : undefined;
|
|
464
473
|
}
|
|
465
474
|
|
|
475
|
+
// TODO(parity): Add excludeConfigUpdate option when AgentConfigUpdate is ported
|
|
466
476
|
copy(
|
|
467
477
|
options: {
|
|
468
478
|
excludeFunctionCall?: boolean;
|
|
469
479
|
excludeInstructions?: boolean;
|
|
470
480
|
excludeEmptyMessage?: boolean;
|
|
481
|
+
excludeHandoff?: boolean;
|
|
471
482
|
toolCtx?: ToolContext<any>; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
472
483
|
} = {},
|
|
473
484
|
): ChatContext {
|
|
@@ -475,6 +486,7 @@ export class ChatContext {
|
|
|
475
486
|
excludeFunctionCall = false,
|
|
476
487
|
excludeInstructions = false,
|
|
477
488
|
excludeEmptyMessage = false,
|
|
489
|
+
excludeHandoff = false,
|
|
478
490
|
toolCtx,
|
|
479
491
|
} = options;
|
|
480
492
|
const items: ChatItem[] = [];
|
|
@@ -500,6 +512,10 @@ export class ChatContext {
|
|
|
500
512
|
continue;
|
|
501
513
|
}
|
|
502
514
|
|
|
515
|
+
if (excludeHandoff && item.type === 'agent_handoff') {
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
|
|
503
519
|
if (toolCtx !== undefined && isToolCallOrOutput(item) && toolCtx[item.name] === undefined) {
|
|
504
520
|
continue;
|
|
505
521
|
}
|
|
@@ -510,6 +526,42 @@ export class ChatContext {
|
|
|
510
526
|
return new ChatContext(items);
|
|
511
527
|
}
|
|
512
528
|
|
|
529
|
+
// TODO(parity): Add excludeConfigUpdate option when AgentConfigUpdate is ported
|
|
530
|
+
merge(
|
|
531
|
+
other: ChatContext,
|
|
532
|
+
options: {
|
|
533
|
+
excludeFunctionCall?: boolean;
|
|
534
|
+
excludeInstructions?: boolean;
|
|
535
|
+
} = {},
|
|
536
|
+
): ChatContext {
|
|
537
|
+
const { excludeFunctionCall = false, excludeInstructions = false } = options;
|
|
538
|
+
const existingIds = new Set(this._items.map((item) => item.id));
|
|
539
|
+
|
|
540
|
+
for (const item of other.items) {
|
|
541
|
+
if (excludeFunctionCall && ['function_call', 'function_call_output'].includes(item.type)) {
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (
|
|
546
|
+
excludeInstructions &&
|
|
547
|
+
item.type === 'message' &&
|
|
548
|
+
(item.role === 'system' || item.role === 'developer')
|
|
549
|
+
) {
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (existingIds.has(item.id)) {
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const idx = this.findInsertionIndex(item.createdAt);
|
|
558
|
+
this._items.splice(idx, 0, item);
|
|
559
|
+
existingIds.add(item.id);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return this;
|
|
563
|
+
}
|
|
564
|
+
|
|
513
565
|
truncate(maxItems: number): ChatContext {
|
|
514
566
|
if (maxItems <= 0) return this;
|
|
515
567
|
|
|
@@ -727,6 +779,112 @@ export class ChatContext {
|
|
|
727
779
|
return true;
|
|
728
780
|
}
|
|
729
781
|
|
|
782
|
+
async _summarize(llm: LLM, options: { keepLastTurns?: number } = {}): Promise<ChatContext> {
|
|
783
|
+
const { keepLastTurns = 2 } = options;
|
|
784
|
+
|
|
785
|
+
const toSummarize: ChatMessage[] = [];
|
|
786
|
+
for (const item of this._items) {
|
|
787
|
+
if (item.type !== 'message') continue;
|
|
788
|
+
if (item.role !== 'user' && item.role !== 'assistant') continue;
|
|
789
|
+
if (item.extra?.is_summary === true) continue;
|
|
790
|
+
|
|
791
|
+
const text = (item.textContent ?? '').trim();
|
|
792
|
+
if (text) {
|
|
793
|
+
toSummarize.push(item);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (toSummarize.length === 0) {
|
|
798
|
+
return this;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
const tailN = Math.max(0, Math.min(toSummarize.length, keepLastTurns * 2));
|
|
802
|
+
let head: ChatMessage[];
|
|
803
|
+
let tail: ChatMessage[];
|
|
804
|
+
if (tailN === 0) {
|
|
805
|
+
head = toSummarize;
|
|
806
|
+
tail = [];
|
|
807
|
+
} else {
|
|
808
|
+
head = toSummarize.slice(0, -tailN);
|
|
809
|
+
tail = toSummarize.slice(-tailN);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (head.length === 0) {
|
|
813
|
+
return this;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const sourceText = head
|
|
817
|
+
.map((m) => `${m.role}: ${(m.textContent ?? '').trim()}`)
|
|
818
|
+
.join('\n')
|
|
819
|
+
.trim();
|
|
820
|
+
|
|
821
|
+
if (!sourceText) {
|
|
822
|
+
return this;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// TODO: refactor this into LLMStream.collect API.
|
|
826
|
+
const promptCtx = new ChatContext();
|
|
827
|
+
promptCtx.addMessage({
|
|
828
|
+
role: 'system',
|
|
829
|
+
content:
|
|
830
|
+
'Compress older chat history into a short, faithful summary.\n' +
|
|
831
|
+
'Focus on user goals, constraints, decisions, key facts/preferences/entities, and pending tasks.\n' +
|
|
832
|
+
'Exclude chit-chat and greetings. Be concise.',
|
|
833
|
+
});
|
|
834
|
+
promptCtx.addMessage({
|
|
835
|
+
role: 'user',
|
|
836
|
+
content: `Conversation to summarize:\n\n${sourceText}`,
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
const chunks: string[] = [];
|
|
840
|
+
for await (const chunk of llm.chat({ chatCtx: promptCtx })) {
|
|
841
|
+
if (chunk.delta?.content) {
|
|
842
|
+
chunks.push(chunk.delta.content);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const summary = chunks.join('').trim();
|
|
847
|
+
if (!summary) {
|
|
848
|
+
return this;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const tailStartTs = tail.length > 0 ? tail[0]!.createdAt : Infinity;
|
|
852
|
+
|
|
853
|
+
const preserved: ChatItem[] = [];
|
|
854
|
+
for (const it of this._items) {
|
|
855
|
+
if (
|
|
856
|
+
(it.type === 'function_call' || it.type === 'function_call_output') &&
|
|
857
|
+
it.createdAt < tailStartTs
|
|
858
|
+
) {
|
|
859
|
+
continue;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (it.type === 'message' && (it.role === 'user' || it.role === 'assistant')) {
|
|
863
|
+
continue;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
preserved.push(it);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
this._items = preserved;
|
|
870
|
+
|
|
871
|
+
const createdAtHint =
|
|
872
|
+
tail.length > 0 ? tail[0]!.createdAt - 1e-3 : head[head.length - 1]!.createdAt + 1e-3;
|
|
873
|
+
|
|
874
|
+
this.addMessage({
|
|
875
|
+
role: 'assistant',
|
|
876
|
+
content: `[history summary]\n${summary}`,
|
|
877
|
+
createdAt: createdAtHint,
|
|
878
|
+
extra: { is_summary: true },
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
for (const msg of tail) {
|
|
882
|
+
this.insert(msg);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return this;
|
|
886
|
+
}
|
|
887
|
+
|
|
730
888
|
/**
|
|
731
889
|
* Indicates whether the context is read-only
|
|
732
890
|
*/
|
package/src/llm/index.ts
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import type { ChatContext } from '../chat_context.js';
|
|
5
5
|
import { toChatCtx as toChatCtxGoogle } from './google.js';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
toChatCtx as toChatCtxOpenai,
|
|
8
|
+
toResponsesChatCtx as toResponsesChatCtxOpenai,
|
|
9
|
+
} from './openai.js';
|
|
7
10
|
|
|
8
|
-
export type ProviderFormat = 'openai' | 'google';
|
|
11
|
+
export type ProviderFormat = 'openai' | 'openai.responses' | 'google';
|
|
9
12
|
|
|
10
13
|
export async function toChatCtx(
|
|
11
14
|
format: ProviderFormat,
|
|
@@ -15,6 +18,8 @@ export async function toChatCtx(
|
|
|
15
18
|
switch (format) {
|
|
16
19
|
case 'openai':
|
|
17
20
|
return await toChatCtxOpenai(chatCtx, injectDummyUserMessage);
|
|
21
|
+
case 'openai.responses':
|
|
22
|
+
return await toResponsesChatCtxOpenai(chatCtx, injectDummyUserMessage);
|
|
18
23
|
case 'google':
|
|
19
24
|
return await toChatCtxGoogle(chatCtx, injectDummyUserMessage);
|
|
20
25
|
default:
|