@librechat/agents 3.7.21 → 3.7.22
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/graphs/Graph.cjs +21 -4
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +21 -6
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/main.cjs +2 -0
- package/dist/cjs/stream.cjs +38 -1
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +95 -18
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +130 -24
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/local/resolveLocalExecutionTools.cjs +1 -1
- package/dist/cjs/tools/preparedSubagents.cjs +129 -0
- package/dist/cjs/tools/preparedSubagents.cjs.map +1 -0
- package/dist/esm/graphs/Graph.mjs +21 -4
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +21 -6
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/stream.mjs +39 -2
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +95 -18
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +129 -25
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/local/resolveLocalExecutionTools.mjs +1 -1
- package/dist/esm/tools/preparedSubagents.mjs +128 -0
- package/dist/esm/tools/preparedSubagents.mjs.map +1 -0
- package/dist/types/graphs/Graph.d.ts +6 -1
- package/dist/types/tools/ToolNode.d.ts +13 -1
- package/dist/types/tools/ToolSearch.d.ts +46 -2
- package/dist/types/tools/preparedSubagents.d.ts +26 -0
- package/dist/types/types/tools.d.ts +17 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +63 -5
- package/src/llm/invoke.ts +35 -8
- package/src/stream.ts +70 -1
- package/src/tools/ToolNode.ts +189 -43
- package/src/tools/ToolSearch.ts +278 -28
- package/src/tools/preparedSubagents.ts +228 -0
- package/src/types/tools.ts +17 -0
|
@@ -3,6 +3,7 @@ import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
|
3
3
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
4
4
|
import type { MessageContentComplex, RunStepResumeState, ToolErrorData } from './stream';
|
|
5
5
|
import type { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
|
|
6
|
+
import type { PreparedSubagents } from '@/tools/preparedSubagents';
|
|
6
7
|
import type { RunBreakerScope } from '@/llm/streamLimits';
|
|
7
8
|
import type { HumanInTheLoopConfig } from './hitl';
|
|
8
9
|
import type { LangfuseConfig } from './graph';
|
|
@@ -42,6 +43,13 @@ export type EagerEventToolExecutionConfig = {
|
|
|
42
43
|
* execution with final args.
|
|
43
44
|
*/
|
|
44
45
|
excludeToolNames?: string[];
|
|
46
|
+
/**
|
|
47
|
+
* Maximum retained early foreground subagent invocations per graph. Defaults
|
|
48
|
+
* to 4; 0 disables them. Checkpoints, parent tool hooks, background calls and
|
|
49
|
+
* control-flow graph tools retain normal batch execution. Once a child has
|
|
50
|
+
* started, a failed/revised model attempt fails instead of automatically retrying.
|
|
51
|
+
*/
|
|
52
|
+
maxPendingSubagents?: number;
|
|
45
53
|
};
|
|
46
54
|
export type EagerEventToolExecutionOutcome = {
|
|
47
55
|
results: ToolExecuteResult[];
|
|
@@ -273,6 +281,8 @@ export type ToolNodeOptions = {
|
|
|
273
281
|
* controller.
|
|
274
282
|
*/
|
|
275
283
|
getRunScope?: () => RunBreakerScope;
|
|
284
|
+
/** Internal graph-owned prepared invocation registry. */
|
|
285
|
+
preparedSubagents?: PreparedSubagents;
|
|
276
286
|
/** SDK-owned checkpoint bridge for open run-step lifecycle state. */
|
|
277
287
|
restoreRunStepResumeState?: (state?: RunStepResumeState, config?: RunnableConfig) => void;
|
|
278
288
|
/** SDK-owned checkpoint snapshot for open run-step lifecycle state. */
|
|
@@ -1160,6 +1170,13 @@ export type ToolSearchArtifact = {
|
|
|
1160
1170
|
total_searched: number;
|
|
1161
1171
|
pattern: string;
|
|
1162
1172
|
error?: string;
|
|
1173
|
+
/** Servers that had tools to search, emitted when a server filter matched
|
|
1174
|
+
* nothing so the caller can see what it could have asked for. */
|
|
1175
|
+
available_mcp_servers?: string[];
|
|
1176
|
+
/** Requested servers that matched no registered server. */
|
|
1177
|
+
unmatched_mcp_servers?: string[];
|
|
1178
|
+
/** Requested servers that exist but had no tools left to search. */
|
|
1179
|
+
idle_mcp_servers?: string[];
|
|
1163
1180
|
};
|
|
1164
1181
|
};
|
|
1165
1182
|
/**
|
package/package.json
CHANGED
package/src/graphs/Graph.ts
CHANGED
|
@@ -146,6 +146,7 @@ import {
|
|
|
146
146
|
findCallback,
|
|
147
147
|
type CallbackEntry,
|
|
148
148
|
} from '@/utils/callbacks';
|
|
149
|
+
import { PreparedSubagents, PreparedSubagentError } from '@/tools/preparedSubagents';
|
|
149
150
|
import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
|
|
150
151
|
import { shouldTraceToolNodeForLangfuse } from '@/langfuseToolOutputTracing';
|
|
151
152
|
import { createLocalCodingToolBundle } from '@/tools/local/LocalCodingTools';
|
|
@@ -898,6 +899,7 @@ export abstract class Graph<
|
|
|
898
899
|
* Call after a run completes and content has been extracted.
|
|
899
900
|
*/
|
|
900
901
|
clearHeavyState(): void {
|
|
902
|
+
this.preparedSubagents.clear();
|
|
901
903
|
this.config = undefined;
|
|
902
904
|
this.signal = undefined;
|
|
903
905
|
this.callerSignal = undefined;
|
|
@@ -1239,6 +1241,8 @@ export abstract class Graph<
|
|
|
1239
1241
|
restoreSubagentResumeState(state: SubagentToolNodeResumeState): void;
|
|
1240
1242
|
}> = new Set();
|
|
1241
1243
|
private _subagentExecutors = new Set<SubagentExecutor>();
|
|
1244
|
+
readonly preparedSubagents = new PreparedSubagents();
|
|
1245
|
+
protected readonly subagentToolNodes = new Map<string, CustomToolNode<t.BaseGraphState>>();
|
|
1242
1246
|
public getOrCreateFileCheckpointer(): t.LocalFileCheckpointer | undefined {
|
|
1243
1247
|
// Return the cached instance unconditionally if one exists. The
|
|
1244
1248
|
// toolExecution check below decides whether to *create* a new
|
|
@@ -1397,16 +1401,16 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1397
1401
|
* paths must not run in that state. */
|
|
1398
1402
|
protected resolveTrippedBreakerReason(
|
|
1399
1403
|
breakerSignal: AbortSignal = this.breakerAbort.signal
|
|
1400
|
-
): StreamLimitExceededError | undefined {
|
|
1404
|
+
): StreamLimitExceededError | PreparedSubagentError | undefined {
|
|
1401
1405
|
if (
|
|
1402
1406
|
breakerSignal.aborted &&
|
|
1403
|
-
breakerSignal.reason instanceof StreamLimitExceededError
|
|
1407
|
+
(breakerSignal.reason instanceof StreamLimitExceededError || breakerSignal.reason instanceof PreparedSubagentError)
|
|
1404
1408
|
) {
|
|
1405
1409
|
return breakerSignal.reason;
|
|
1406
1410
|
}
|
|
1407
1411
|
if (
|
|
1408
1412
|
this.signal?.aborted === true &&
|
|
1409
|
-
this.signal.reason instanceof StreamLimitExceededError
|
|
1413
|
+
(this.signal.reason instanceof StreamLimitExceededError || this.signal.reason instanceof PreparedSubagentError)
|
|
1410
1414
|
) {
|
|
1411
1415
|
return this.signal.reason;
|
|
1412
1416
|
}
|
|
@@ -1581,6 +1585,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1581
1585
|
/* Init */
|
|
1582
1586
|
|
|
1583
1587
|
resetValues(keepContent?: boolean, checkpointScope?: string): void {
|
|
1588
|
+
this.preparedSubagents.clear();
|
|
1584
1589
|
this.resetSubagentCheckpointThreadIds();
|
|
1585
1590
|
this.messages = [];
|
|
1586
1591
|
this.hasRestoredCheckpointMessages = false;
|
|
@@ -2717,6 +2722,49 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2717
2722
|
|
|
2718
2723
|
/* Graph */
|
|
2719
2724
|
|
|
2725
|
+
canPrestartSubagents(agentContext?: AgentContext): boolean {
|
|
2726
|
+
if (
|
|
2727
|
+
this.eagerEventToolExecution?.enabled !== true ||
|
|
2728
|
+
(this.eagerEventToolExecution.maxPendingSubagents ?? 4) <= 0 ||
|
|
2729
|
+
this.compileOptions?.checkpointer != null ||
|
|
2730
|
+
this.humanInTheLoop?.enabled === true ||
|
|
2731
|
+
(this.interruptingToolNames?.length ?? 0) > 0 ||
|
|
2732
|
+
agentContext == null ||
|
|
2733
|
+
!this.subagentToolNodes.has(agentContext.agentId)
|
|
2734
|
+
) {
|
|
2735
|
+
return false;
|
|
2736
|
+
}
|
|
2737
|
+
const graphTools = agentContext.graphTools as t.GenericTool[] | undefined;
|
|
2738
|
+
return (
|
|
2739
|
+
graphTools?.length === 1 &&
|
|
2740
|
+
graphTools[0].name === Constants.SUBAGENT &&
|
|
2741
|
+
SUBAGENT_REPLAY_CONTROLLER in graphTools[0]
|
|
2742
|
+
);
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
prestartSubagent(
|
|
2746
|
+
call: ToolCall,
|
|
2747
|
+
attempt: string,
|
|
2748
|
+
agentContext?: AgentContext
|
|
2749
|
+
): void {
|
|
2750
|
+
const config = this.preparedSubagents.getConfig(attempt);
|
|
2751
|
+
if (
|
|
2752
|
+
!this.canPrestartSubagents(agentContext) ||
|
|
2753
|
+
config == null ||
|
|
2754
|
+
agentContext == null
|
|
2755
|
+
) {
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
this.subagentToolNodes
|
|
2759
|
+
.get(agentContext.agentId)
|
|
2760
|
+
?.prestartSubagent(
|
|
2761
|
+
call,
|
|
2762
|
+
attempt,
|
|
2763
|
+
config,
|
|
2764
|
+
this.eagerEventToolExecution?.maxPendingSubagents ?? 4
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2720
2768
|
initializeTools({
|
|
2721
2769
|
currentTools,
|
|
2722
2770
|
currentToolMap,
|
|
@@ -2791,6 +2839,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2791
2839
|
hookRegistry: this.hookRegistry,
|
|
2792
2840
|
humanInTheLoop: this.humanInTheLoop,
|
|
2793
2841
|
eagerEventToolExecution: this.eagerEventToolExecution,
|
|
2842
|
+
preparedSubagents: this.preparedSubagents,
|
|
2794
2843
|
codeSessionToolNames: this.codeSessionToolNames,
|
|
2795
2844
|
eagerEventToolExecutions: this.eagerEventToolExecutions,
|
|
2796
2845
|
eagerEventToolUsageCount: this.getEagerEventToolUsageCount(
|
|
@@ -2816,6 +2865,9 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2816
2865
|
StandardGraph.handleToolCallErrorStatic(this, data, metadata),
|
|
2817
2866
|
});
|
|
2818
2867
|
this.registerCompiledToolNode(node);
|
|
2868
|
+
if (agentContext != null) {
|
|
2869
|
+
this.subagentToolNodes.set(agentContext.agentId, node);
|
|
2870
|
+
}
|
|
2819
2871
|
return node;
|
|
2820
2872
|
}
|
|
2821
2873
|
|
|
@@ -4092,7 +4144,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4092
4144
|
* succeeding fallback would resolve a run the public contract says
|
|
4093
4145
|
* must reject. Rethrow before any recovery path.
|
|
4094
4146
|
*/
|
|
4095
|
-
if (
|
|
4147
|
+
if (
|
|
4148
|
+
primaryError instanceof StreamLimitExceededError ||
|
|
4149
|
+
primaryError instanceof PreparedSubagentError
|
|
4150
|
+
) {
|
|
4096
4151
|
/** Tripped before rethrowing so parallel agent nodes' in-flight
|
|
4097
4152
|
* model calls and subagents stop while the rejection propagates. */
|
|
4098
4153
|
attemptBreaker.abort(primaryError);
|
|
@@ -4342,7 +4397,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4342
4397
|
})
|
|
4343
4398
|
);
|
|
4344
4399
|
} catch (fallbackError) {
|
|
4345
|
-
if (
|
|
4400
|
+
if (
|
|
4401
|
+
fallbackError instanceof StreamLimitExceededError ||
|
|
4402
|
+
fallbackError instanceof PreparedSubagentError
|
|
4403
|
+
) {
|
|
4346
4404
|
/** Same treatment as the primary path: a fallback stream that
|
|
4347
4405
|
* trips the breaker must stop parallel agent nodes' model calls
|
|
4348
4406
|
* and subagents before the rejection propagates. */
|
package/src/llm/invoke.ts
CHANGED
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
} from '@/llm/providers';
|
|
52
52
|
import { ChatModelStreamHandler, dispatchesChatModelStream } from '@/stream';
|
|
53
53
|
import { Constants, ContentTypes, GraphEvents, Providers } from '@/common';
|
|
54
|
+
import { PreparedSubagentError } from '@/tools/preparedSubagents';
|
|
54
55
|
import { assertNotTruncatedToolCall } from '@/llm/truncation';
|
|
55
56
|
import { resolveClientOptionsModel } from '@/llm/request';
|
|
56
57
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
@@ -702,9 +703,8 @@ export async function attemptInvoke(
|
|
|
702
703
|
},
|
|
703
704
|
};
|
|
704
705
|
const request = resolveAttemptRequest(params, providerStampedConfig);
|
|
705
|
-
const configuredModel =
|
|
706
|
-
Constants.INVOKED_MODEL
|
|
707
|
-
];
|
|
706
|
+
const configuredModel =
|
|
707
|
+
providerStampedConfig.metadata?.[Constants.INVOKED_MODEL];
|
|
708
708
|
const modelId =
|
|
709
709
|
request.modelId ??
|
|
710
710
|
(typeof configuredModel === 'string' ? configuredModel : undefined);
|
|
@@ -745,8 +745,14 @@ export async function attemptInvoke(
|
|
|
745
745
|
if (leaseTarget != null && generationKey != null) {
|
|
746
746
|
registerActiveStreamLimitGeneration(leaseTarget, generationKey);
|
|
747
747
|
}
|
|
748
|
+
const prepared =
|
|
749
|
+
params.context?.eagerEventToolExecution?.enabled === true
|
|
750
|
+
? params.context.preparedSubagents
|
|
751
|
+
: undefined;
|
|
752
|
+
const preparedAttempt = resolveGenerationKey(stampedConfig.metadata);
|
|
753
|
+
prepared?.begin(preparedAttempt, stampedConfig);
|
|
748
754
|
try {
|
|
749
|
-
|
|
755
|
+
const result = await attemptInvokeBody(
|
|
750
756
|
{
|
|
751
757
|
request,
|
|
752
758
|
context: params.context,
|
|
@@ -755,7 +761,27 @@ export async function attemptInvoke(
|
|
|
755
761
|
},
|
|
756
762
|
stampedConfig
|
|
757
763
|
);
|
|
764
|
+
const calls =
|
|
765
|
+
result.messages?.flatMap((message) =>
|
|
766
|
+
'tool_calls' in message
|
|
767
|
+
? ((message.tool_calls as ToolCall[] | undefined) ?? [])
|
|
768
|
+
: []
|
|
769
|
+
) ?? [];
|
|
770
|
+
prepared?.finish(preparedAttempt, calls);
|
|
771
|
+
return result;
|
|
772
|
+
} catch (error) {
|
|
773
|
+
prepared?.finish(preparedAttempt, undefined, error);
|
|
774
|
+
throw error;
|
|
758
775
|
} finally {
|
|
776
|
+
const chunks = params.context?.eagerEventToolCallChunks;
|
|
777
|
+
if (prepared != null && chunks != null) {
|
|
778
|
+
const prefix = `prepared:${preparedAttempt}\u0000`;
|
|
779
|
+
for (const key of chunks.keys()) {
|
|
780
|
+
if (key.startsWith(prefix)) {
|
|
781
|
+
chunks.delete(key);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
759
785
|
if (leaseTarget != null && generationKey != null) {
|
|
760
786
|
releaseStreamLimitGeneration(leaseTarget, generationKey);
|
|
761
787
|
}
|
|
@@ -1053,7 +1079,7 @@ async function attemptInvokeBody(
|
|
|
1053
1079
|
const signal = config.signal;
|
|
1054
1080
|
if (
|
|
1055
1081
|
signal?.aborted === true &&
|
|
1056
|
-
signal.reason instanceof StreamLimitExceededError
|
|
1082
|
+
(signal.reason instanceof StreamLimitExceededError || signal.reason instanceof PreparedSubagentError)
|
|
1057
1083
|
) {
|
|
1058
1084
|
throw signal.reason;
|
|
1059
1085
|
}
|
|
@@ -1290,6 +1316,7 @@ async function attemptInvokeBody(
|
|
|
1290
1316
|
const ownAbort =
|
|
1291
1317
|
restartRoute === 'aborted' &&
|
|
1292
1318
|
!(error instanceof StreamLimitExceededError) &&
|
|
1319
|
+
!(error instanceof PreparedSubagentError) &&
|
|
1293
1320
|
config.signal?.aborted !== true;
|
|
1294
1321
|
if (!ownAbort) {
|
|
1295
1322
|
throw error;
|
|
@@ -1639,7 +1666,7 @@ export async function tryFallbackProviders({
|
|
|
1639
1666
|
* a run that must reject. Check before every fallback invocation. */
|
|
1640
1667
|
if (
|
|
1641
1668
|
config?.signal?.aborted === true &&
|
|
1642
|
-
config.signal.reason instanceof StreamLimitExceededError
|
|
1669
|
+
(config.signal.reason instanceof StreamLimitExceededError || config.signal.reason instanceof PreparedSubagentError)
|
|
1643
1670
|
) {
|
|
1644
1671
|
throw config.signal.reason;
|
|
1645
1672
|
}
|
|
@@ -1673,7 +1700,7 @@ export async function tryFallbackProviders({
|
|
|
1673
1700
|
* provider failure. Continuing would try the remaining fallbacks and a
|
|
1674
1701
|
* succeeding one would resolve a run that must reject.
|
|
1675
1702
|
*/
|
|
1676
|
-
if (e instanceof StreamLimitExceededError) {
|
|
1703
|
+
if (e instanceof StreamLimitExceededError || e instanceof PreparedSubagentError) {
|
|
1677
1704
|
throw e;
|
|
1678
1705
|
}
|
|
1679
1706
|
/** A parallel sibling's trip aborts this branch's composed signal, and
|
|
@@ -1682,7 +1709,7 @@ export async function tryFallbackProviders({
|
|
|
1682
1709
|
* abort. Rethrow the breaker's own reason instead. */
|
|
1683
1710
|
if (
|
|
1684
1711
|
config?.signal?.aborted === true &&
|
|
1685
|
-
config.signal.reason instanceof StreamLimitExceededError
|
|
1712
|
+
(config.signal.reason instanceof StreamLimitExceededError || config.signal.reason instanceof PreparedSubagentError)
|
|
1686
1713
|
) {
|
|
1687
1714
|
throw config.signal.reason;
|
|
1688
1715
|
}
|
package/src/stream.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
requiresStreamLimitAccounting,
|
|
16
16
|
StreamLimitExceededError,
|
|
17
17
|
STREAM_LIMIT_EPOCH_KEY,
|
|
18
|
+
resolveGenerationKey,
|
|
18
19
|
} from '@/llm/streamLimits';
|
|
19
20
|
import {
|
|
20
21
|
getStreamedToolCallSeal,
|
|
@@ -56,6 +57,7 @@ import {
|
|
|
56
57
|
} from '@/utils/truncation';
|
|
57
58
|
import { resolveToolOutcome, outcomeFieldsFromResult } from '@/tools/intentArg';
|
|
58
59
|
import { TOOL_OUTPUT_REF_PATTERN } from '@/tools/toolOutputReferences';
|
|
60
|
+
import { PreparedSubagentError } from '@/tools/preparedSubagents';
|
|
59
61
|
import { isReasoningContentBlock } from '@/messages/core';
|
|
60
62
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
61
63
|
import { composeAbortSignals } from '@/utils/misc';
|
|
@@ -1319,6 +1321,65 @@ function startReadyStreamedEagerToolExecutions(args: {
|
|
|
1319
1321
|
});
|
|
1320
1322
|
}
|
|
1321
1323
|
|
|
1324
|
+
/** Shares provider sealing/parsing with event tools, but never relaxes their batch guard. */
|
|
1325
|
+
function startPreparedSubagents(
|
|
1326
|
+
graph: StandardGraph,
|
|
1327
|
+
agentContext: AgentContext | undefined,
|
|
1328
|
+
chunk: Partial<AIMessageChunk>,
|
|
1329
|
+
metadata?: Record<string, unknown>
|
|
1330
|
+
): void {
|
|
1331
|
+
const attempt = resolveGenerationKey(metadata);
|
|
1332
|
+
if (
|
|
1333
|
+
(graph as Partial<StandardGraph>).canPrestartSubagents?.(agentContext) !==
|
|
1334
|
+
true ||
|
|
1335
|
+
graph.preparedSubagents.isOpen(attempt) !== true ||
|
|
1336
|
+
graph.hookRegistry?.hasResultAlteringHooks(
|
|
1337
|
+
graph.preparedSubagents.getConfig(attempt)?.configurable?.run_id
|
|
1338
|
+
) === true
|
|
1339
|
+
) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
let calls: ToolCall[];
|
|
1343
|
+
if (hasOnArrivalToolCallSeal(chunk) && (chunk.tool_calls?.length ?? 0) > 0) {
|
|
1344
|
+
calls = chunk.tool_calls!;
|
|
1345
|
+
} else {
|
|
1346
|
+
const seal = getStreamedToolCallSeal(chunk.response_metadata);
|
|
1347
|
+
const allowSequentialSeal =
|
|
1348
|
+
canPrestartSequentialStreamedToolChunks(agentContext) ||
|
|
1349
|
+
streamedToolCallAdapterAllowsSequentialSeal(chunk.response_metadata);
|
|
1350
|
+
if (!hasExplicitStreamedToolCallSeals(chunk) && !allowSequentialSeal) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
const stepKey = `prepared:${attempt}`;
|
|
1354
|
+
recordEagerToolCallChunks({
|
|
1355
|
+
graph,
|
|
1356
|
+
stepKey,
|
|
1357
|
+
toolCallChunks: chunk.tool_call_chunks ?? [],
|
|
1358
|
+
seal,
|
|
1359
|
+
});
|
|
1360
|
+
calls = getStreamedReadyToolCalls({
|
|
1361
|
+
graph,
|
|
1362
|
+
stepKey,
|
|
1363
|
+
toolCallChunks: chunk.tool_call_chunks,
|
|
1364
|
+
seal,
|
|
1365
|
+
allowSequentialSeal,
|
|
1366
|
+
});
|
|
1367
|
+
pruneEagerToolCallChunkStates({
|
|
1368
|
+
graph,
|
|
1369
|
+
stepKey,
|
|
1370
|
+
toolCallIds: new Set(calls.map((call) => call.id!)),
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
for (const call of calls) {
|
|
1374
|
+
if (
|
|
1375
|
+
call.name === Constants.SUBAGENT &&
|
|
1376
|
+
!hasToolOutputReference(call.args)
|
|
1377
|
+
) {
|
|
1378
|
+
graph.prestartSubagent(call, attempt, agentContext);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1322
1383
|
export function getChunkContent({
|
|
1323
1384
|
chunk,
|
|
1324
1385
|
provider,
|
|
@@ -1597,7 +1658,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
1597
1658
|
if (
|
|
1598
1659
|
eventBreaker != null &&
|
|
1599
1660
|
eventBreaker.signal.aborted &&
|
|
1600
|
-
eventBreaker.signal.reason instanceof StreamLimitExceededError
|
|
1661
|
+
(eventBreaker.signal.reason instanceof StreamLimitExceededError || eventBreaker.signal.reason instanceof PreparedSubagentError)
|
|
1601
1662
|
) {
|
|
1602
1663
|
throw eventBreaker.signal.reason;
|
|
1603
1664
|
}
|
|
@@ -1743,6 +1804,9 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
1743
1804
|
return;
|
|
1744
1805
|
}
|
|
1745
1806
|
throwIfRunBreakerTripped();
|
|
1807
|
+
if (hasOnArrivalToolCallSeal(chunk)) {
|
|
1808
|
+
startPreparedSubagents(graph, agentContext, chunk, metadata);
|
|
1809
|
+
}
|
|
1746
1810
|
if (hasFinalToolCallSignal(chunk)) {
|
|
1747
1811
|
startEagerToolExecutions({
|
|
1748
1812
|
graph,
|
|
@@ -1839,6 +1903,11 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
1839
1903
|
}
|
|
1840
1904
|
}
|
|
1841
1905
|
|
|
1906
|
+
if (!hasOnArrivalToolCallSeal(chunk) && !runScopeInvalidated()) {
|
|
1907
|
+
throwIfRunBreakerTripped();
|
|
1908
|
+
startPreparedSubagents(graph, agentContext, chunk, metadata);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1842
1911
|
if (isEmptyContent) {
|
|
1843
1912
|
return;
|
|
1844
1913
|
}
|