@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.
Files changed (228) hide show
  1. package/dist/beta/index.cjs +29 -0
  2. package/dist/beta/index.cjs.map +1 -0
  3. package/dist/beta/index.d.cts +2 -0
  4. package/dist/beta/index.d.ts +2 -0
  5. package/dist/beta/index.d.ts.map +1 -0
  6. package/dist/beta/index.js +7 -0
  7. package/dist/beta/index.js.map +1 -0
  8. package/dist/beta/workflows/index.cjs +29 -0
  9. package/dist/beta/workflows/index.cjs.map +1 -0
  10. package/dist/beta/workflows/index.d.cts +2 -0
  11. package/dist/beta/workflows/index.d.ts +2 -0
  12. package/dist/beta/workflows/index.d.ts.map +1 -0
  13. package/dist/beta/workflows/index.js +7 -0
  14. package/dist/beta/workflows/index.js.map +1 -0
  15. package/dist/beta/workflows/task_group.cjs +162 -0
  16. package/dist/beta/workflows/task_group.cjs.map +1 -0
  17. package/dist/beta/workflows/task_group.d.cts +32 -0
  18. package/dist/beta/workflows/task_group.d.ts +32 -0
  19. package/dist/beta/workflows/task_group.d.ts.map +1 -0
  20. package/dist/beta/workflows/task_group.js +138 -0
  21. package/dist/beta/workflows/task_group.js.map +1 -0
  22. package/dist/cli.cjs +14 -20
  23. package/dist/cli.cjs.map +1 -1
  24. package/dist/cli.d.ts.map +1 -1
  25. package/dist/cli.js +14 -20
  26. package/dist/cli.js.map +1 -1
  27. package/dist/index.cjs +3 -0
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +2 -1
  30. package/dist/index.d.ts +2 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/inference/api_protos.d.cts +59 -59
  35. package/dist/inference/api_protos.d.ts +59 -59
  36. package/dist/ipc/job_proc_lazy_main.cjs +14 -5
  37. package/dist/ipc/job_proc_lazy_main.cjs.map +1 -1
  38. package/dist/ipc/job_proc_lazy_main.js +14 -5
  39. package/dist/ipc/job_proc_lazy_main.js.map +1 -1
  40. package/dist/llm/chat_context.cjs +108 -1
  41. package/dist/llm/chat_context.cjs.map +1 -1
  42. package/dist/llm/chat_context.d.cts +14 -1
  43. package/dist/llm/chat_context.d.ts +14 -1
  44. package/dist/llm/chat_context.d.ts.map +1 -1
  45. package/dist/llm/chat_context.js +108 -1
  46. package/dist/llm/chat_context.js.map +1 -1
  47. package/dist/llm/chat_context.test.cjs +43 -0
  48. package/dist/llm/chat_context.test.cjs.map +1 -1
  49. package/dist/llm/chat_context.test.js +43 -0
  50. package/dist/llm/chat_context.test.js.map +1 -1
  51. package/dist/llm/index.cjs +2 -0
  52. package/dist/llm/index.cjs.map +1 -1
  53. package/dist/llm/index.d.cts +1 -1
  54. package/dist/llm/index.d.ts +1 -1
  55. package/dist/llm/index.d.ts.map +1 -1
  56. package/dist/llm/index.js +3 -1
  57. package/dist/llm/index.js.map +1 -1
  58. package/dist/llm/provider_format/index.cjs +2 -0
  59. package/dist/llm/provider_format/index.cjs.map +1 -1
  60. package/dist/llm/provider_format/index.d.cts +2 -2
  61. package/dist/llm/provider_format/index.d.ts +2 -2
  62. package/dist/llm/provider_format/index.d.ts.map +1 -1
  63. package/dist/llm/provider_format/index.js +6 -1
  64. package/dist/llm/provider_format/index.js.map +1 -1
  65. package/dist/llm/provider_format/openai.cjs +82 -2
  66. package/dist/llm/provider_format/openai.cjs.map +1 -1
  67. package/dist/llm/provider_format/openai.d.cts +1 -0
  68. package/dist/llm/provider_format/openai.d.ts +1 -0
  69. package/dist/llm/provider_format/openai.d.ts.map +1 -1
  70. package/dist/llm/provider_format/openai.js +80 -1
  71. package/dist/llm/provider_format/openai.js.map +1 -1
  72. package/dist/llm/provider_format/openai.test.cjs +326 -0
  73. package/dist/llm/provider_format/openai.test.cjs.map +1 -1
  74. package/dist/llm/provider_format/openai.test.js +327 -1
  75. package/dist/llm/provider_format/openai.test.js.map +1 -1
  76. package/dist/llm/provider_format/utils.cjs +4 -3
  77. package/dist/llm/provider_format/utils.cjs.map +1 -1
  78. package/dist/llm/provider_format/utils.d.ts.map +1 -1
  79. package/dist/llm/provider_format/utils.js +4 -3
  80. package/dist/llm/provider_format/utils.js.map +1 -1
  81. package/dist/llm/realtime.cjs.map +1 -1
  82. package/dist/llm/realtime.d.cts +1 -0
  83. package/dist/llm/realtime.d.ts +1 -0
  84. package/dist/llm/realtime.d.ts.map +1 -1
  85. package/dist/llm/realtime.js.map +1 -1
  86. package/dist/llm/tool_context.cjs +7 -0
  87. package/dist/llm/tool_context.cjs.map +1 -1
  88. package/dist/llm/tool_context.d.cts +10 -2
  89. package/dist/llm/tool_context.d.ts +10 -2
  90. package/dist/llm/tool_context.d.ts.map +1 -1
  91. package/dist/llm/tool_context.js +6 -0
  92. package/dist/llm/tool_context.js.map +1 -1
  93. package/dist/log.cjs +5 -2
  94. package/dist/log.cjs.map +1 -1
  95. package/dist/log.d.ts.map +1 -1
  96. package/dist/log.js +5 -2
  97. package/dist/log.js.map +1 -1
  98. package/dist/stream/deferred_stream.cjs +15 -6
  99. package/dist/stream/deferred_stream.cjs.map +1 -1
  100. package/dist/stream/deferred_stream.d.ts.map +1 -1
  101. package/dist/stream/deferred_stream.js +15 -6
  102. package/dist/stream/deferred_stream.js.map +1 -1
  103. package/dist/utils.cjs +32 -2
  104. package/dist/utils.cjs.map +1 -1
  105. package/dist/utils.d.cts +7 -0
  106. package/dist/utils.d.ts +7 -0
  107. package/dist/utils.d.ts.map +1 -1
  108. package/dist/utils.js +32 -2
  109. package/dist/utils.js.map +1 -1
  110. package/dist/utils.test.cjs +71 -0
  111. package/dist/utils.test.cjs.map +1 -1
  112. package/dist/utils.test.js +71 -0
  113. package/dist/utils.test.js.map +1 -1
  114. package/dist/version.cjs +1 -1
  115. package/dist/version.cjs.map +1 -1
  116. package/dist/version.d.cts +1 -1
  117. package/dist/version.d.ts +1 -1
  118. package/dist/version.d.ts.map +1 -1
  119. package/dist/version.js +1 -1
  120. package/dist/version.js.map +1 -1
  121. package/dist/voice/agent.cjs +153 -12
  122. package/dist/voice/agent.cjs.map +1 -1
  123. package/dist/voice/agent.d.cts +30 -4
  124. package/dist/voice/agent.d.ts +30 -4
  125. package/dist/voice/agent.d.ts.map +1 -1
  126. package/dist/voice/agent.js +149 -11
  127. package/dist/voice/agent.js.map +1 -1
  128. package/dist/voice/agent.test.cjs +120 -0
  129. package/dist/voice/agent.test.cjs.map +1 -1
  130. package/dist/voice/agent.test.js +122 -2
  131. package/dist/voice/agent.test.js.map +1 -1
  132. package/dist/voice/agent_activity.cjs +406 -298
  133. package/dist/voice/agent_activity.cjs.map +1 -1
  134. package/dist/voice/agent_activity.d.cts +41 -7
  135. package/dist/voice/agent_activity.d.ts +41 -7
  136. package/dist/voice/agent_activity.d.ts.map +1 -1
  137. package/dist/voice/agent_activity.js +407 -294
  138. package/dist/voice/agent_activity.js.map +1 -1
  139. package/dist/voice/agent_session.cjs +140 -40
  140. package/dist/voice/agent_session.cjs.map +1 -1
  141. package/dist/voice/agent_session.d.cts +19 -7
  142. package/dist/voice/agent_session.d.ts +19 -7
  143. package/dist/voice/agent_session.d.ts.map +1 -1
  144. package/dist/voice/agent_session.js +137 -37
  145. package/dist/voice/agent_session.js.map +1 -1
  146. package/dist/voice/audio_recognition.cjs +4 -0
  147. package/dist/voice/audio_recognition.cjs.map +1 -1
  148. package/dist/voice/audio_recognition.d.ts.map +1 -1
  149. package/dist/voice/audio_recognition.js +4 -0
  150. package/dist/voice/audio_recognition.js.map +1 -1
  151. package/dist/voice/generation.cjs +39 -19
  152. package/dist/voice/generation.cjs.map +1 -1
  153. package/dist/voice/generation.d.ts.map +1 -1
  154. package/dist/voice/generation.js +44 -20
  155. package/dist/voice/generation.js.map +1 -1
  156. package/dist/voice/index.cjs +2 -0
  157. package/dist/voice/index.cjs.map +1 -1
  158. package/dist/voice/index.d.cts +1 -1
  159. package/dist/voice/index.d.ts +1 -1
  160. package/dist/voice/index.d.ts.map +1 -1
  161. package/dist/voice/index.js +2 -1
  162. package/dist/voice/index.js.map +1 -1
  163. package/dist/voice/room_io/room_io.cjs +11 -2
  164. package/dist/voice/room_io/room_io.cjs.map +1 -1
  165. package/dist/voice/room_io/room_io.d.ts.map +1 -1
  166. package/dist/voice/room_io/room_io.js +12 -3
  167. package/dist/voice/room_io/room_io.js.map +1 -1
  168. package/dist/voice/speech_handle.cjs +7 -1
  169. package/dist/voice/speech_handle.cjs.map +1 -1
  170. package/dist/voice/speech_handle.d.cts +2 -0
  171. package/dist/voice/speech_handle.d.ts +2 -0
  172. package/dist/voice/speech_handle.d.ts.map +1 -1
  173. package/dist/voice/speech_handle.js +8 -2
  174. package/dist/voice/speech_handle.js.map +1 -1
  175. package/dist/voice/testing/fake_llm.cjs +127 -0
  176. package/dist/voice/testing/fake_llm.cjs.map +1 -0
  177. package/dist/voice/testing/fake_llm.d.cts +30 -0
  178. package/dist/voice/testing/fake_llm.d.ts +30 -0
  179. package/dist/voice/testing/fake_llm.d.ts.map +1 -0
  180. package/dist/voice/testing/fake_llm.js +103 -0
  181. package/dist/voice/testing/fake_llm.js.map +1 -0
  182. package/dist/voice/testing/index.cjs +3 -0
  183. package/dist/voice/testing/index.cjs.map +1 -1
  184. package/dist/voice/testing/index.d.cts +1 -0
  185. package/dist/voice/testing/index.d.ts +1 -0
  186. package/dist/voice/testing/index.d.ts.map +1 -1
  187. package/dist/voice/testing/index.js +2 -0
  188. package/dist/voice/testing/index.js.map +1 -1
  189. package/dist/voice/testing/run_result.cjs +66 -15
  190. package/dist/voice/testing/run_result.cjs.map +1 -1
  191. package/dist/voice/testing/run_result.d.cts +14 -3
  192. package/dist/voice/testing/run_result.d.ts +14 -3
  193. package/dist/voice/testing/run_result.d.ts.map +1 -1
  194. package/dist/voice/testing/run_result.js +66 -15
  195. package/dist/voice/testing/run_result.js.map +1 -1
  196. package/package.json +1 -1
  197. package/src/beta/index.ts +9 -0
  198. package/src/beta/workflows/index.ts +9 -0
  199. package/src/beta/workflows/task_group.ts +194 -0
  200. package/src/cli.ts +20 -33
  201. package/src/index.ts +2 -1
  202. package/src/ipc/job_proc_lazy_main.ts +16 -5
  203. package/src/llm/chat_context.test.ts +48 -0
  204. package/src/llm/chat_context.ts +158 -0
  205. package/src/llm/index.ts +1 -0
  206. package/src/llm/provider_format/index.ts +7 -2
  207. package/src/llm/provider_format/openai.test.ts +385 -1
  208. package/src/llm/provider_format/openai.ts +103 -0
  209. package/src/llm/provider_format/utils.ts +6 -4
  210. package/src/llm/realtime.ts +1 -0
  211. package/src/llm/tool_context.ts +14 -0
  212. package/src/log.ts +5 -2
  213. package/src/stream/deferred_stream.ts +17 -6
  214. package/src/utils.test.ts +87 -0
  215. package/src/utils.ts +41 -2
  216. package/src/version.ts +1 -1
  217. package/src/voice/agent.test.ts +140 -2
  218. package/src/voice/agent.ts +200 -10
  219. package/src/voice/agent_activity.ts +466 -290
  220. package/src/voice/agent_session.ts +178 -40
  221. package/src/voice/audio_recognition.ts +4 -0
  222. package/src/voice/generation.ts +52 -23
  223. package/src/voice/index.ts +1 -1
  224. package/src/voice/room_io/room_io.ts +14 -3
  225. package/src/voice/speech_handle.ts +9 -2
  226. package/src/voice/testing/fake_llm.ts +138 -0
  227. package/src/voice/testing/index.ts +2 -0
  228. 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[] = [
@@ -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
@@ -6,6 +6,7 @@ export {
6
6
  isFunctionTool,
7
7
  tool,
8
8
  ToolError,
9
+ ToolFlag,
9
10
  type AgentHandoff,
10
11
  type FunctionTool,
11
12
  type ProviderDefinedTool,
@@ -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 { toChatCtx as toChatCtxOpenai } from './openai.js';
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: