@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.
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +165 -57
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +81 -33
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs +14 -0
- package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs.map +1 -0
- package/dist/cjs/graphs/createGraph.cjs +15 -0
- package/dist/cjs/graphs/createGraph.cjs.map +1 -0
- package/dist/cjs/graphs/index.cjs +1 -0
- package/dist/cjs/hooks/HookRegistry.cjs +83 -0
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
- package/dist/cjs/hooks/executeHooks.cjs +60 -14
- package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +2 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +3 -3
- package/dist/cjs/llm/invoke.cjs +2 -2
- package/dist/cjs/main.cjs +34 -24
- package/dist/cjs/messages/format.cjs +40 -23
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/run.cjs +130 -53
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +37 -2
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/summarization/node.cjs +6 -3
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +1 -1
- package/dist/cjs/tools/SubagentTool.cjs +4 -4
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +321 -95
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +1 -1
- package/dist/cjs/tools/eagerEventExecution.cjs +1 -0
- package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
- package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +2 -2
- package/dist/cjs/tools/search/rerankers.cjs +154 -1
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +4 -1
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +601 -0
- package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1114 -233
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +177 -0
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -0
- package/dist/cjs/tools/subagent/childGraphConfig.cjs +278 -0
- package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -0
- package/dist/cjs/tools/subagent/index.cjs +1 -0
- package/dist/cjs/tools/subagent/runtimeLimits.cjs +5 -0
- package/dist/cjs/tools/subagent/runtimeLimits.cjs.map +1 -0
- package/dist/cjs/tools/toolOutputReferences.cjs +20 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +2 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +165 -57
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +81 -33
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/graphs/applyGraphRuntimeConfig.mjs +14 -0
- package/dist/esm/graphs/applyGraphRuntimeConfig.mjs.map +1 -0
- package/dist/esm/graphs/createGraph.mjs +15 -0
- package/dist/esm/graphs/createGraph.mjs.map +1 -0
- package/dist/esm/graphs/index.mjs +1 -0
- package/dist/esm/hooks/HookRegistry.mjs +83 -0
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
- package/dist/esm/hooks/executeHooks.mjs +60 -14
- package/dist/esm/hooks/executeHooks.mjs.map +1 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +2 -1
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +2 -2
- package/dist/esm/main.mjs +21 -19
- package/dist/esm/messages/format.mjs +40 -23
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/run.mjs +131 -54
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +37 -2
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +2 -2
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/summarization/node.mjs +6 -3
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +1 -1
- package/dist/esm/tools/SubagentTool.mjs +4 -4
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +322 -96
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +1 -1
- package/dist/esm/tools/eagerEventExecution.mjs +1 -1
- package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
- package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +2 -2
- package/dist/esm/tools/search/rerankers.mjs +154 -1
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +4 -1
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +597 -0
- package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +1114 -233
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +170 -0
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -0
- package/dist/esm/tools/subagent/childGraphConfig.mjs +272 -0
- package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -0
- package/dist/esm/tools/subagent/index.mjs +1 -0
- package/dist/esm/tools/subagent/runtimeLimits.mjs +5 -0
- package/dist/esm/tools/subagent/runtimeLimits.mjs.map +1 -0
- package/dist/esm/tools/toolOutputReferences.mjs +20 -0
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +2 -2
- package/dist/types/agents/AgentContext.d.ts +1 -1
- package/dist/types/graphs/Graph.d.ts +22 -2
- package/dist/types/graphs/MultiAgentGraph.d.ts +7 -1
- package/dist/types/graphs/applyGraphRuntimeConfig.d.ts +3 -0
- package/dist/types/graphs/createGraph.d.ts +13 -0
- package/dist/types/graphs/graphFactory.d.ts +13 -0
- package/dist/types/graphs/index.d.ts +2 -0
- package/dist/types/hooks/HookRegistry.d.ts +10 -1
- package/dist/types/hooks/executeHooks.d.ts +5 -1
- package/dist/types/hooks/index.d.ts +2 -2
- package/dist/types/hooks/types.d.ts +12 -0
- package/dist/types/run.d.ts +6 -3
- package/dist/types/session/AgentSession.d.ts +1 -0
- package/dist/types/tools/SubagentTool.d.ts +1 -1
- package/dist/types/tools/ToolNode.d.ts +23 -15
- package/dist/types/tools/search/rerankers.d.ts +28 -0
- package/dist/types/tools/search/types.d.ts +38 -1
- package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +171 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +70 -36
- package/dist/types/tools/subagent/SubagentReplay.d.ts +85 -0
- package/dist/types/tools/subagent/childGraphConfig.d.ts +37 -0
- package/dist/types/tools/subagent/index.d.ts +1 -1
- package/dist/types/tools/subagent/runtimeLimits.d.ts +4 -0
- package/dist/types/tools/toolOutputReferences.d.ts +12 -0
- package/dist/types/types/graph.d.ts +189 -24
- package/dist/types/types/hitl.d.ts +15 -0
- package/package.json +8 -2
- package/src/agents/AgentContext.ts +1 -1
- package/src/graphs/Graph.ts +349 -104
- package/src/graphs/MultiAgentGraph.ts +149 -47
- package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +48 -9
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1 -1
- package/src/graphs/__tests__/Graph.subagentResumeState.test.ts +80 -0
- package/src/graphs/__tests__/MultiAgentGraph.test.ts +86 -0
- package/src/graphs/__tests__/composition.smoke.test.ts +152 -0
- package/src/graphs/__tests__/createGraph.test.ts +206 -0
- package/src/graphs/applyGraphRuntimeConfig.ts +25 -0
- package/src/graphs/createGraph.ts +32 -0
- package/src/graphs/graphFactory.ts +12 -0
- package/src/graphs/index.ts +2 -0
- package/src/hooks/HookRegistry.ts +151 -1
- package/src/hooks/__tests__/HookRegistry.test.ts +96 -0
- package/src/hooks/__tests__/executeHooks.test.ts +160 -0
- package/src/hooks/executeHooks.ts +133 -15
- package/src/hooks/index.ts +3 -1
- package/src/hooks/types.ts +16 -0
- package/src/messages/format.ts +54 -26
- package/src/messages/formatAgentMessages.reducer.test.ts +162 -0
- package/src/messages/formatAgentMessages.steer.test.ts +16 -11
- package/src/messages/formatAgentMessages.test.ts +7 -2
- package/src/run.ts +214 -56
- package/src/session/AgentSession.ts +52 -2
- package/src/session/__tests__/JsonlSessionStore.test.ts +53 -0
- package/src/specs/graph-subagent.live.test.ts +242 -0
- package/src/specs/graph-subagent.test.ts +322 -0
- package/src/specs/langfuse-routing.integration.test.ts +120 -1
- package/src/specs/subagent.test.ts +130 -4
- package/src/summarization/__tests__/node.test.ts +32 -14
- package/src/summarization/node.ts +15 -11
- package/src/tools/SubagentTool.ts +4 -4
- package/src/tools/ToolNode.ts +643 -157
- package/src/tools/__tests__/SubagentExecutor.test.ts +740 -15
- package/src/tools/__tests__/SubagentReplay.test.ts +329 -0
- package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +208 -2
- package/src/tools/__tests__/directToolHITLResumeScope.test.ts +512 -2
- package/src/tools/__tests__/hitl.test.ts +234 -5
- package/src/tools/__tests__/subagentHooks.test.ts +1126 -61
- package/src/tools/__tests__/toolOutputReferences.test.ts +19 -2
- package/src/tools/search/rag-api-reranker.test.ts +891 -0
- package/src/tools/search/rerankers.ts +260 -0
- package/src/tools/search/tool.ts +6 -0
- package/src/tools/search/types.ts +45 -1
- package/src/tools/subagent/SubagentExecutionRegistry.ts +1159 -0
- package/src/tools/subagent/SubagentExecutor.ts +2232 -312
- package/src/tools/subagent/SubagentReplay.ts +584 -0
- package/src/tools/subagent/__tests__/SubagentExecutionRegistry.test.ts +637 -0
- package/src/tools/subagent/__tests__/SubagentExecutor.lazy.test.ts +3054 -0
- package/src/tools/subagent/__tests__/childGraphConfig.test.ts +521 -0
- package/src/tools/subagent/childGraphConfig.ts +694 -0
- package/src/tools/subagent/index.ts +6 -0
- package/src/tools/subagent/runtimeLimits.ts +7 -0
- package/src/tools/toolOutputReferences.ts +40 -1
- package/src/types/graph.ts +222 -24
- 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
|
|
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:
|
|
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).
|
|
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
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
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
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
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
|
-
*
|
|
422
|
-
* exactly those retained steers. Injected steers are still caught, by
|
|
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
|
|
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
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
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
|
|
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
|
|
18
|
-
- Only the final
|
|
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.
|