@librechat/agents 3.4.0 → 3.4.2

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 (204) hide show
  1. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  2. package/dist/cjs/graphs/Graph.cjs +165 -57
  3. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs +81 -33
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  6. package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs +14 -0
  7. package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs.map +1 -0
  8. package/dist/cjs/graphs/createGraph.cjs +15 -0
  9. package/dist/cjs/graphs/createGraph.cjs.map +1 -0
  10. package/dist/cjs/graphs/index.cjs +1 -0
  11. package/dist/cjs/hooks/HookRegistry.cjs +83 -0
  12. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  13. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
  14. package/dist/cjs/hooks/executeHooks.cjs +60 -14
  15. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  16. package/dist/cjs/hooks/index.cjs.map +1 -1
  17. package/dist/cjs/hooks/types.cjs +2 -0
  18. package/dist/cjs/hooks/types.cjs.map +1 -1
  19. package/dist/cjs/llm/init.cjs +3 -3
  20. package/dist/cjs/llm/invoke.cjs +2 -2
  21. package/dist/cjs/main.cjs +34 -24
  22. package/dist/cjs/messages/format.cjs +40 -23
  23. package/dist/cjs/messages/format.cjs.map +1 -1
  24. package/dist/cjs/run.cjs +130 -53
  25. package/dist/cjs/run.cjs.map +1 -1
  26. package/dist/cjs/session/AgentSession.cjs +37 -2
  27. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  28. package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
  29. package/dist/cjs/stream.cjs +1 -1
  30. package/dist/cjs/summarization/node.cjs +6 -3
  31. package/dist/cjs/summarization/node.cjs.map +1 -1
  32. package/dist/cjs/tools/BashExecutor.cjs +1 -1
  33. package/dist/cjs/tools/CodeExecutor.cjs +1 -1
  34. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +1 -1
  35. package/dist/cjs/tools/SubagentTool.cjs +4 -4
  36. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  37. package/dist/cjs/tools/ToolNode.cjs +321 -95
  38. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  39. package/dist/cjs/tools/ToolSearch.cjs +1 -1
  40. package/dist/cjs/tools/eagerEventExecution.cjs +1 -0
  41. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
  42. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +2 -2
  43. package/dist/cjs/tools/search/rerankers.cjs +154 -1
  44. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  45. package/dist/cjs/tools/search/tool.cjs +4 -1
  46. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  47. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +601 -0
  48. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -0
  49. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1114 -233
  50. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  51. package/dist/cjs/tools/subagent/SubagentReplay.cjs +177 -0
  52. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -0
  53. package/dist/cjs/tools/subagent/childGraphConfig.cjs +278 -0
  54. package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -0
  55. package/dist/cjs/tools/subagent/index.cjs +1 -0
  56. package/dist/cjs/tools/subagent/runtimeLimits.cjs +5 -0
  57. package/dist/cjs/tools/subagent/runtimeLimits.cjs.map +1 -0
  58. package/dist/cjs/tools/toolOutputReferences.cjs +20 -0
  59. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  60. package/dist/cjs/utils/index.cjs +2 -2
  61. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  62. package/dist/esm/graphs/Graph.mjs +165 -57
  63. package/dist/esm/graphs/Graph.mjs.map +1 -1
  64. package/dist/esm/graphs/MultiAgentGraph.mjs +81 -33
  65. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  66. package/dist/esm/graphs/applyGraphRuntimeConfig.mjs +14 -0
  67. package/dist/esm/graphs/applyGraphRuntimeConfig.mjs.map +1 -0
  68. package/dist/esm/graphs/createGraph.mjs +15 -0
  69. package/dist/esm/graphs/createGraph.mjs.map +1 -0
  70. package/dist/esm/graphs/index.mjs +1 -0
  71. package/dist/esm/hooks/HookRegistry.mjs +83 -0
  72. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  73. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
  74. package/dist/esm/hooks/executeHooks.mjs +60 -14
  75. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  76. package/dist/esm/hooks/index.mjs.map +1 -1
  77. package/dist/esm/hooks/types.mjs +2 -1
  78. package/dist/esm/hooks/types.mjs.map +1 -1
  79. package/dist/esm/llm/init.mjs +1 -1
  80. package/dist/esm/llm/invoke.mjs +2 -2
  81. package/dist/esm/main.mjs +21 -19
  82. package/dist/esm/messages/format.mjs +40 -23
  83. package/dist/esm/messages/format.mjs.map +1 -1
  84. package/dist/esm/run.mjs +131 -54
  85. package/dist/esm/run.mjs.map +1 -1
  86. package/dist/esm/session/AgentSession.mjs +37 -2
  87. package/dist/esm/session/AgentSession.mjs.map +1 -1
  88. package/dist/esm/session/JsonlSessionStore.mjs +2 -2
  89. package/dist/esm/stream.mjs +1 -1
  90. package/dist/esm/summarization/node.mjs +6 -3
  91. package/dist/esm/summarization/node.mjs.map +1 -1
  92. package/dist/esm/tools/BashExecutor.mjs +1 -1
  93. package/dist/esm/tools/CodeExecutor.mjs +1 -1
  94. package/dist/esm/tools/ProgrammaticToolCalling.mjs +1 -1
  95. package/dist/esm/tools/SubagentTool.mjs +4 -4
  96. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  97. package/dist/esm/tools/ToolNode.mjs +322 -96
  98. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  99. package/dist/esm/tools/ToolSearch.mjs +1 -1
  100. package/dist/esm/tools/eagerEventExecution.mjs +1 -1
  101. package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
  102. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +2 -2
  103. package/dist/esm/tools/search/rerankers.mjs +154 -1
  104. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  105. package/dist/esm/tools/search/tool.mjs +4 -1
  106. package/dist/esm/tools/search/tool.mjs.map +1 -1
  107. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +597 -0
  108. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -0
  109. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1114 -233
  110. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  111. package/dist/esm/tools/subagent/SubagentReplay.mjs +170 -0
  112. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -0
  113. package/dist/esm/tools/subagent/childGraphConfig.mjs +272 -0
  114. package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -0
  115. package/dist/esm/tools/subagent/index.mjs +1 -0
  116. package/dist/esm/tools/subagent/runtimeLimits.mjs +5 -0
  117. package/dist/esm/tools/subagent/runtimeLimits.mjs.map +1 -0
  118. package/dist/esm/tools/toolOutputReferences.mjs +20 -0
  119. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  120. package/dist/esm/utils/index.mjs +2 -2
  121. package/dist/types/agents/AgentContext.d.ts +1 -1
  122. package/dist/types/graphs/Graph.d.ts +22 -2
  123. package/dist/types/graphs/MultiAgentGraph.d.ts +7 -1
  124. package/dist/types/graphs/applyGraphRuntimeConfig.d.ts +3 -0
  125. package/dist/types/graphs/createGraph.d.ts +13 -0
  126. package/dist/types/graphs/graphFactory.d.ts +13 -0
  127. package/dist/types/graphs/index.d.ts +2 -0
  128. package/dist/types/hooks/HookRegistry.d.ts +10 -1
  129. package/dist/types/hooks/executeHooks.d.ts +5 -1
  130. package/dist/types/hooks/index.d.ts +2 -2
  131. package/dist/types/hooks/types.d.ts +12 -0
  132. package/dist/types/run.d.ts +6 -3
  133. package/dist/types/session/AgentSession.d.ts +1 -0
  134. package/dist/types/tools/SubagentTool.d.ts +1 -1
  135. package/dist/types/tools/ToolNode.d.ts +23 -15
  136. package/dist/types/tools/search/rerankers.d.ts +28 -0
  137. package/dist/types/tools/search/types.d.ts +38 -1
  138. package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +171 -0
  139. package/dist/types/tools/subagent/SubagentExecutor.d.ts +70 -36
  140. package/dist/types/tools/subagent/SubagentReplay.d.ts +85 -0
  141. package/dist/types/tools/subagent/childGraphConfig.d.ts +37 -0
  142. package/dist/types/tools/subagent/index.d.ts +1 -1
  143. package/dist/types/tools/subagent/runtimeLimits.d.ts +4 -0
  144. package/dist/types/tools/toolOutputReferences.d.ts +12 -0
  145. package/dist/types/types/graph.d.ts +189 -24
  146. package/dist/types/types/hitl.d.ts +15 -0
  147. package/package.json +8 -2
  148. package/src/agents/AgentContext.ts +1 -1
  149. package/src/graphs/Graph.ts +349 -104
  150. package/src/graphs/MultiAgentGraph.ts +149 -47
  151. package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +48 -9
  152. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1 -1
  153. package/src/graphs/__tests__/Graph.subagentResumeState.test.ts +80 -0
  154. package/src/graphs/__tests__/MultiAgentGraph.test.ts +86 -0
  155. package/src/graphs/__tests__/composition.smoke.test.ts +152 -0
  156. package/src/graphs/__tests__/createGraph.test.ts +206 -0
  157. package/src/graphs/applyGraphRuntimeConfig.ts +25 -0
  158. package/src/graphs/createGraph.ts +32 -0
  159. package/src/graphs/graphFactory.ts +12 -0
  160. package/src/graphs/index.ts +2 -0
  161. package/src/hooks/HookRegistry.ts +151 -1
  162. package/src/hooks/__tests__/HookRegistry.test.ts +96 -0
  163. package/src/hooks/__tests__/executeHooks.test.ts +160 -0
  164. package/src/hooks/executeHooks.ts +133 -15
  165. package/src/hooks/index.ts +3 -1
  166. package/src/hooks/types.ts +16 -0
  167. package/src/messages/format.ts +54 -26
  168. package/src/messages/formatAgentMessages.reducer.test.ts +162 -0
  169. package/src/messages/formatAgentMessages.steer.test.ts +16 -11
  170. package/src/messages/formatAgentMessages.test.ts +7 -2
  171. package/src/run.ts +214 -56
  172. package/src/session/AgentSession.ts +52 -2
  173. package/src/session/__tests__/JsonlSessionStore.test.ts +53 -0
  174. package/src/specs/graph-subagent.live.test.ts +242 -0
  175. package/src/specs/graph-subagent.test.ts +322 -0
  176. package/src/specs/langfuse-routing.integration.test.ts +120 -1
  177. package/src/specs/subagent.test.ts +130 -4
  178. package/src/summarization/__tests__/node.test.ts +32 -14
  179. package/src/summarization/node.ts +15 -11
  180. package/src/tools/SubagentTool.ts +4 -4
  181. package/src/tools/ToolNode.ts +643 -157
  182. package/src/tools/__tests__/SubagentExecutor.test.ts +740 -15
  183. package/src/tools/__tests__/SubagentReplay.test.ts +329 -0
  184. package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +208 -2
  185. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +512 -2
  186. package/src/tools/__tests__/hitl.test.ts +234 -5
  187. package/src/tools/__tests__/subagentHooks.test.ts +1126 -61
  188. package/src/tools/__tests__/toolOutputReferences.test.ts +19 -2
  189. package/src/tools/search/rag-api-reranker.test.ts +891 -0
  190. package/src/tools/search/rerankers.ts +260 -0
  191. package/src/tools/search/tool.ts +6 -0
  192. package/src/tools/search/types.ts +45 -1
  193. package/src/tools/subagent/SubagentExecutionRegistry.ts +1159 -0
  194. package/src/tools/subagent/SubagentExecutor.ts +2232 -312
  195. package/src/tools/subagent/SubagentReplay.ts +584 -0
  196. package/src/tools/subagent/__tests__/SubagentExecutionRegistry.test.ts +637 -0
  197. package/src/tools/subagent/__tests__/SubagentExecutor.lazy.test.ts +3054 -0
  198. package/src/tools/subagent/__tests__/childGraphConfig.test.ts +521 -0
  199. package/src/tools/subagent/childGraphConfig.ts +694 -0
  200. package/src/tools/subagent/index.ts +6 -0
  201. package/src/tools/subagent/runtimeLimits.ts +7 -0
  202. package/src/tools/toolOutputReferences.ts +40 -1
  203. package/src/types/graph.ts +222 -24
  204. package/src/types/hitl.ts +16 -0
@@ -5,8 +5,8 @@ import {
5
5
  AIMessageChunk,
6
6
  HumanMessage,
7
7
  } from '@langchain/core/messages';
8
+ import type { UsageMetadata, BaseMessage } from '@langchain/core/messages';
8
9
  import type { RunnableConfig } from '@langchain/core/runnables';
9
- import type { UsageMetadata } from '@langchain/core/messages';
10
10
  import type { ToolCall } from '@langchain/core/messages/tool';
11
11
  import type * as t from '@/types';
12
12
  import {
@@ -371,6 +371,8 @@ describe('Subagent Integration', () => {
371
371
  }
372
372
  );
373
373
  const parentUpdateHandler = jest.fn();
374
+ const rootModelEndHandler = jest.fn();
375
+ const nestedUsageEvents: t.SubagentUsageEvent[] = [];
374
376
  let specialistToolDefinitions: t.LCTool[] | undefined;
375
377
  let forwardedToolResults: t.ToolExecuteResult[] | undefined;
376
378
 
@@ -409,7 +411,12 @@ describe('Subagent Integration', () => {
409
411
  const invokeOptions = options as
410
412
  | { callbacks?: unknown[] }
411
413
  | undefined;
412
- const forwarder = (invokeOptions?.callbacks ?? [])[0] as
414
+ const callbacks = invokeOptions?.callbacks ?? [];
415
+ const forwarder = callbacks.find(
416
+ (callback) =>
417
+ typeof (callback as { handleCustomEvent?: unknown })
418
+ .handleCustomEvent === 'function'
419
+ ) as
413
420
  | {
414
421
  handleCustomEvent?: (
415
422
  eventName: string,
@@ -418,6 +425,27 @@ describe('Subagent Integration', () => {
418
425
  ) => Promise<void> | void;
419
426
  }
420
427
  | undefined;
428
+ const usageHandler = callbacks.find(
429
+ (callback) =>
430
+ typeof (callback as { handleLLMEnd?: unknown })
431
+ .handleLLMEnd === 'function'
432
+ ) as
433
+ | {
434
+ handleChatModelStart?: (
435
+ llm: unknown,
436
+ messages: BaseMessage[][],
437
+ runId: string,
438
+ parentRunId?: string,
439
+ extraParams?: unknown,
440
+ tags?: string[],
441
+ metadata?: Record<string, unknown>
442
+ ) => Promise<void> | void;
443
+ handleLLMEnd?: (
444
+ output: unknown,
445
+ runId: string
446
+ ) => Promise<void> | void;
447
+ }
448
+ | undefined;
421
449
  if (forwarder?.handleCustomEvent != null) {
422
450
  forwardedToolResults = await new Promise<t.ToolExecuteResult[]>(
423
451
  (resolve, reject) => {
@@ -442,6 +470,38 @@ describe('Subagent Integration', () => {
442
470
  'specialist-run'
443
471
  );
444
472
  }
473
+ await usageHandler?.handleChatModelStart?.(
474
+ {},
475
+ [[]],
476
+ 'specialist-model-call',
477
+ undefined,
478
+ undefined,
479
+ undefined,
480
+ {
481
+ agentId: 'specialist',
482
+ ls_model_name: 'gpt-4o-mini',
483
+ }
484
+ );
485
+ await usageHandler?.handleLLMEnd?.(
486
+ {
487
+ generations: [
488
+ [
489
+ {
490
+ text: 'specialist done',
491
+ message: new AIMessage({
492
+ content: 'specialist done',
493
+ usage_metadata: {
494
+ input_tokens: 5,
495
+ output_tokens: 3,
496
+ total_tokens: 8,
497
+ },
498
+ }),
499
+ },
500
+ ],
501
+ ],
502
+ },
503
+ 'specialist-model-call'
504
+ );
445
505
  return { messages: [new AIMessage('specialist done')] };
446
506
  }),
447
507
  } as unknown as ReturnType<StandardGraph['createWorkflow']>;
@@ -492,17 +552,22 @@ describe('Subagent Integration', () => {
492
552
  };
493
553
 
494
554
  try {
555
+ const rootRunId = `nested-event-tools-${Date.now()}`;
495
556
  const run = await Run.create<t.IState>({
496
- runId: `nested-event-tools-${Date.now()}`,
557
+ runId: rootRunId,
497
558
  graphConfig: { type: 'standard', agents: [rootAgent] },
498
559
  customHandlers: {
499
560
  [GraphEvents.ON_TOOL_EXECUTE]: { handle: parentToolHandler },
561
+ [GraphEvents.CHAT_MODEL_END]: { handle: rootModelEndHandler },
500
562
  [GraphEvents.ON_SUBAGENT_UPDATE]: {
501
563
  handle: parentUpdateHandler,
502
564
  },
503
565
  },
504
566
  returnContent: true,
505
567
  skipCleanup: true,
568
+ subagentUsageSink: (event) => {
569
+ nestedUsageEvents.push(event);
570
+ },
506
571
  });
507
572
  const rootContext = (run.Graph as StandardGraph).agentContexts.get(
508
573
  'root'
@@ -530,7 +595,68 @@ describe('Subagent Integration', () => {
530
595
  ([, data]) => (data as t.SubagentUpdateEvent).subagentType
531
596
  );
532
597
  expect(forwardedSubagentTypes).toContain('router');
533
- expect(forwardedSubagentTypes).not.toContain('specialist');
598
+ expect(forwardedSubagentTypes).toContain('specialist');
599
+ const specialistStepUpdates = parentUpdateHandler.mock.calls.filter(
600
+ ([, data]) => {
601
+ const event = data as t.SubagentUpdateEvent;
602
+ return (
603
+ event.subagentType === 'specialist' &&
604
+ (event.data as { id?: string } | undefined)?.id ===
605
+ 'specialist-step'
606
+ );
607
+ }
608
+ );
609
+ expect(specialistStepUpdates).toHaveLength(1);
610
+ const routerEvent = parentUpdateHandler.mock.calls
611
+ .map(([, data]) => data as t.SubagentUpdateEvent)
612
+ .find((event) => event.subagentType === 'router');
613
+ const specialistEvent =
614
+ specialistStepUpdates[0][1] as t.SubagentUpdateEvent;
615
+ expect(routerEvent).toMatchObject({
616
+ runId: rootRunId,
617
+ parentRunId: rootRunId,
618
+ depth: 1,
619
+ });
620
+ expect(routerEvent?.ancestry?.map((entry) => entry.subagentType)).toEqual(
621
+ ['router']
622
+ );
623
+ expect(specialistEvent).toMatchObject({
624
+ runId: rootRunId,
625
+ parentRunId: routerEvent?.subagentRunId,
626
+ depth: 2,
627
+ });
628
+ expect(
629
+ specialistEvent.ancestry?.map((entry) => ({
630
+ type: entry.subagentType,
631
+ kind: entry.subagentKind,
632
+ }))
633
+ ).toEqual([
634
+ { type: 'router', kind: 'agent' },
635
+ { type: 'specialist', kind: 'agent' },
636
+ ]);
637
+ expect(nestedUsageEvents).toHaveLength(1);
638
+ expect(rootModelEndHandler).not.toHaveBeenCalled();
639
+ expect(nestedUsageEvents[0]).toMatchObject({
640
+ runId: rootRunId,
641
+ parentRunId: routerEvent?.subagentRunId,
642
+ subagentType: 'specialist',
643
+ subagentAgentId: 'specialist',
644
+ depth: 2,
645
+ usage: {
646
+ input_tokens: 5,
647
+ output_tokens: 3,
648
+ total_tokens: 8,
649
+ },
650
+ });
651
+ expect(
652
+ nestedUsageEvents[0].ancestry?.map((entry) => ({
653
+ type: entry.subagentType,
654
+ kind: entry.subagentKind,
655
+ }))
656
+ ).toEqual([
657
+ { type: 'router', kind: 'agent' },
658
+ { type: 'specialist', kind: 'agent' },
659
+ ]);
534
660
  } finally {
535
661
  createWorkflowSpy.mockRestore();
536
662
  }
@@ -1059,6 +1059,24 @@ describe('recency window — first-turn protection', () => {
1059
1059
  expect(summaryBlock?.coverage).toEqual({ retainedFromMessageId: 'm2' });
1060
1060
  });
1061
1061
 
1062
+ it('anchors a derived retained message on its persisted source id', async () => {
1063
+ const summaryBlock = await runCompaction([
1064
+ new HumanMessage({ content: 'turn 1 query', id: 'm1' }),
1065
+ new AIMessage({ content: 'pre-steer reply', id: 'm2' }),
1066
+ new HumanMessage({
1067
+ content: 'steer',
1068
+ id: 'reducer-uuid',
1069
+ additional_kwargs: {
1070
+ role: 'user',
1071
+ source: 'steer',
1072
+ sourceMessageId: 'm2',
1073
+ },
1074
+ }),
1075
+ ]);
1076
+
1077
+ expect(summaryBlock?.coverage).toEqual({ retainedFromMessageId: 'm2' });
1078
+ });
1079
+
1062
1080
  /** `formatAgentMessages` reconstructs skill bodies inside its payload loop
1063
1081
  * and keeps processing payload entries after, so this unstamped entry — a
1064
1082
  * reducer UUID by the time compaction sees it — precedes stamped messages.
@@ -1770,13 +1788,13 @@ describe('summarize node breaker capture', () => {
1770
1788
  const entryBreaker = new AbortController();
1771
1789
  /** The trip lands while ON_SUMMARIZE_START is awaited — after the
1772
1790
  * entry check already passed. */
1773
- jest.spyOn(eventUtils, 'safeDispatchCustomEvent').mockImplementation((async (
1774
- ...args: unknown[]
1775
- ) => {
1776
- if (args[0] === GraphEvents.ON_SUMMARIZE_START) {
1777
- entryBreaker.abort(trip);
1778
- }
1779
- }) as never);
1791
+ jest
1792
+ .spyOn(eventUtils, 'safeDispatchCustomEvent')
1793
+ .mockImplementation((async (...args: unknown[]) => {
1794
+ if (args[0] === GraphEvents.ON_SUMMARIZE_START) {
1795
+ entryBreaker.abort(trip);
1796
+ }
1797
+ }) as never);
1780
1798
  const modelClassSpy = jest
1781
1799
  .spyOn(providers, 'getChatModelClass')
1782
1800
  .mockReturnValue(
@@ -1915,13 +1933,13 @@ describe('summarize node breaker capture', () => {
1915
1933
  const entryBreaker = new AbortController();
1916
1934
  const lateBreaker = new AbortController();
1917
1935
  let started = false;
1918
- jest.spyOn(eventUtils, 'safeDispatchCustomEvent').mockImplementation((async (
1919
- ...args: unknown[]
1920
- ) => {
1921
- if (args[0] === GraphEvents.ON_SUMMARIZE_START) {
1922
- started = true;
1923
- }
1924
- }) as never);
1936
+ jest
1937
+ .spyOn(eventUtils, 'safeDispatchCustomEvent')
1938
+ .mockImplementation((async (...args: unknown[]) => {
1939
+ if (args[0] === GraphEvents.ON_SUMMARIZE_START) {
1940
+ started = true;
1941
+ }
1942
+ }) as never);
1925
1943
 
1926
1944
  const capturedSignals: Array<AbortSignal | undefined> = [];
1927
1945
  jest.spyOn(providers, 'getChatModelClass').mockReturnValue(
@@ -17,6 +17,11 @@ import {
17
17
  isComputerCallOutputMessage,
18
18
  serializeToolContentBounded,
19
19
  } from '@/utils/toolContent';
20
+ import {
21
+ enforceStreamLimitsForWireChunk,
22
+ StreamLimitExceededError,
23
+ STREAM_LIMIT_EPOCH_KEY,
24
+ } from '@/llm/streamLimits';
20
25
  import {
21
26
  addTailCacheControl,
22
27
  resolvePromptCacheTtl,
@@ -34,11 +39,6 @@ import {
34
39
  Providers,
35
40
  } from '@/common';
36
41
  import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
37
- import {
38
- enforceStreamLimitsForWireChunk,
39
- StreamLimitExceededError,
40
- STREAM_LIMIT_EPOCH_KEY,
41
- } from '@/llm/streamLimits';
42
42
  import { attemptInvoke, tryFallbackProviders } from '@/llm/invoke';
43
43
  import { calculateMaxToolResultChars } from '@/utils/truncation';
44
44
  import { createRemoveAllMessage } from '@/messages/reducer';
@@ -418,8 +418,9 @@ function computeSummaryTokenCount(
418
418
  * in `ToolNode` and `StandardGraph`, handoff cues, reconstructed skill bodies.
419
419
  *
420
420
  * `steer` is exempt from the `source` check because a replayed steer *is*
421
- * stamped from its payload entry; rejecting every marked `source` once dropped
422
- * exactly those retained steers. Injected steers are still caught, by `injected`.
421
+ * correlated with its payload entry; rejecting every marked `source` once
422
+ * dropped exactly those retained steers. Injected steers are still caught, by
423
+ * `injected`.
423
424
  *
424
425
  * Known limitation: a payload entry that omits `messageId` is never stamped, so
425
426
  * the reducer's UUID is recorded and cannot resolve on the next run. There is no
@@ -443,7 +444,10 @@ function resolveSummaryCoverage(
443
444
  if (isSyntheticContext(message)) {
444
445
  continue;
445
446
  }
446
- const id = message.id?.trim();
447
+ const sourceMessageId = message.additional_kwargs.sourceMessageId;
448
+ const sourceId =
449
+ typeof sourceMessageId === 'string' ? sourceMessageId.trim() : '';
450
+ const id = sourceId !== '' ? sourceId : message.id?.trim();
447
451
  if (id != null && id !== '') {
448
452
  return { retainedFromMessageId: id };
449
453
  }
@@ -1244,9 +1248,9 @@ export function createSummarizeNode({
1244
1248
  ? { [Constants.INVOKED_MODEL]: clientConfig.modelName }
1245
1249
  : {}),
1246
1250
  /** Entry-captured breaker epoch: the wire consumer epoch-gates
1247
- * old-run summary chunks exactly like model-attempt chunks —
1248
- * without the stamp, a straggling summary from a failed run
1249
- * reads as current and could abort the next run's controller. */
1251
+ * old-run summary chunks exactly like model-attempt chunks —
1252
+ * without the stamp, a straggling summary from a failed run
1253
+ * reads as current and could abort the next run's controller. */
1250
1254
  ...(entryBreakerEpoch != null
1251
1255
  ? { [STREAM_LIMIT_EPOCH_KEY]: entryBreakerEpoch }
1252
1256
  : {}),
@@ -5,7 +5,7 @@ import { Constants } from '@/common';
5
5
 
6
6
  export const SubagentToolName = Constants.SUBAGENT;
7
7
 
8
- export const SubagentToolDescription = `Delegate a task to a specialized subagent that runs in an isolated context window. The subagent executes independently and returns only its final text result — all intermediate tool calls, reasoning, and context stay isolated.
8
+ export const SubagentToolDescription = `Delegate a task to a specialized subagent or bounded agent team that runs in an isolated context window. The delegated execution returns only its designated final text result — all intermediate tool calls, reasoning, and context stay isolated.
9
9
 
10
10
  WHEN TO USE:
11
11
  - The task is self-contained and can be described in a single prompt.
@@ -13,9 +13,9 @@ WHEN TO USE:
13
13
  - A specialized subagent is available for the task domain.
14
14
 
15
15
  WHAT HAPPENS:
16
- - A fresh agent is created with the task description as its only input.
17
- - The subagent runs to completion using its own tools and context.
18
- - Only the final text response is returned to you.
16
+ - A fresh agent or configured agent graph is created with the task description as its only input.
17
+ - The delegated agent or team runs to completion using isolated tools and context.
18
+ - Only the single agent's final response or the graph's designated result-agent response is returned to you.
19
19
 
20
20
  CONSTRAINTS:
21
21
  - subagent_type must match one of the available types listed below.