@librechat/agents 3.1.86 → 3.1.88
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/README.md +69 -0
- package/dist/cjs/events.cjs +23 -0
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +133 -18
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +251 -53
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +1 -5
- package/dist/cjs/llm/init.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +113 -24
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +3 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +18 -5
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/openai/index.cjs +253 -0
- package/dist/cjs/openai/index.cjs.map +1 -0
- package/dist/cjs/responses/index.cjs +448 -0
- package/dist/cjs/responses/index.cjs.map +1 -0
- package/dist/cjs/run.cjs +108 -7
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +1057 -0
- package/dist/cjs/session/AgentSession.cjs.map +1 -0
- package/dist/cjs/session/JsonlSessionStore.cjs +425 -0
- package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -0
- package/dist/cjs/session/handlers.cjs +221 -0
- package/dist/cjs/session/handlers.cjs.map +1 -0
- package/dist/cjs/session/ids.cjs +22 -0
- package/dist/cjs/session/ids.cjs.map +1 -0
- package/dist/cjs/session/messageSerialization.cjs +179 -0
- package/dist/cjs/session/messageSerialization.cjs.map +1 -0
- package/dist/cjs/stream.cjs +475 -11
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +1 -1
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +177 -59
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/eagerEventExecution.cjs +113 -0
- package/dist/cjs/tools/eagerEventExecution.cjs.map +1 -0
- package/dist/cjs/tools/handlers.cjs +1 -1
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/streamedToolCallSeals.cjs +42 -0
- package/dist/cjs/tools/streamedToolCallSeals.cjs.map +1 -0
- package/dist/esm/events.mjs +23 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +133 -18
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +251 -53
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -5
- package/dist/esm/llm/init.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +113 -25
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +4 -2
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/main.mjs +5 -1
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/openai/index.mjs +246 -0
- package/dist/esm/openai/index.mjs.map +1 -0
- package/dist/esm/responses/index.mjs +440 -0
- package/dist/esm/responses/index.mjs.map +1 -0
- package/dist/esm/run.mjs +108 -7
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +1054 -0
- package/dist/esm/session/AgentSession.mjs.map +1 -0
- package/dist/esm/session/JsonlSessionStore.mjs +422 -0
- package/dist/esm/session/JsonlSessionStore.mjs.map +1 -0
- package/dist/esm/session/handlers.mjs +219 -0
- package/dist/esm/session/handlers.mjs.map +1 -0
- package/dist/esm/session/ids.mjs +17 -0
- package/dist/esm/session/ids.mjs.map +1 -0
- package/dist/esm/session/messageSerialization.mjs +173 -0
- package/dist/esm/session/messageSerialization.mjs.map +1 -0
- package/dist/esm/stream.mjs +476 -12
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +1 -1
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +177 -59
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/eagerEventExecution.mjs +107 -0
- package/dist/esm/tools/eagerEventExecution.mjs.map +1 -0
- package/dist/esm/tools/handlers.mjs +1 -1
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/streamedToolCallSeals.mjs +36 -0
- package/dist/esm/tools/streamedToolCallSeals.mjs.map +1 -0
- package/dist/types/events.d.ts +1 -0
- package/dist/types/graphs/Graph.d.ts +24 -9
- package/dist/types/index.d.ts +1 -0
- package/dist/types/llm/openai/index.d.ts +1 -0
- package/dist/types/openai/index.d.ts +75 -0
- package/dist/types/responses/index.d.ts +97 -0
- package/dist/types/run.d.ts +2 -0
- package/dist/types/session/AgentSession.d.ts +32 -0
- package/dist/types/session/JsonlSessionStore.d.ts +67 -0
- package/dist/types/session/handlers.d.ts +8 -0
- package/dist/types/session/ids.d.ts +4 -0
- package/dist/types/session/index.d.ts +5 -0
- package/dist/types/session/messageSerialization.d.ts +7 -0
- package/dist/types/session/types.d.ts +191 -0
- package/dist/types/tools/ToolNode.d.ts +12 -1
- package/dist/types/tools/eagerEventExecution.d.ts +23 -0
- package/dist/types/tools/streamedToolCallSeals.d.ts +13 -0
- package/dist/types/types/hitl.d.ts +4 -0
- package/dist/types/types/run.d.ts +11 -1
- package/dist/types/types/tools.d.ts +36 -0
- package/package.json +19 -2
- package/src/__tests__/stream.eagerEventExecution.test.ts +2571 -0
- package/src/events.ts +29 -0
- package/src/graphs/Graph.ts +224 -50
- package/src/graphs/MultiAgentGraph.ts +1 -1
- package/src/graphs/__tests__/composition.smoke.test.ts +30 -0
- package/src/index.ts +3 -0
- package/src/llm/anthropic/index.ts +356 -84
- package/src/llm/anthropic/llm.spec.ts +64 -0
- package/src/llm/custom-chat-models.smoke.test.ts +175 -4
- package/src/llm/openai/contentBlocks.test.ts +35 -0
- package/src/llm/openai/deepseek.test.ts +201 -2
- package/src/llm/openai/index.ts +171 -26
- package/src/llm/openai/utils/index.ts +22 -0
- package/src/llm/openrouter/index.ts +4 -2
- package/src/openai/__tests__/openai.test.ts +337 -0
- package/src/openai/index.ts +404 -0
- package/src/responses/__tests__/responses.test.ts +652 -0
- package/src/responses/index.ts +677 -0
- package/src/run.ts +158 -8
- package/src/scripts/compare_pi_vs_ours.ts +592 -173
- package/src/scripts/session_live.ts +548 -0
- package/src/session/AgentSession.ts +1432 -0
- package/src/session/JsonlSessionStore.ts +572 -0
- package/src/session/__tests__/JsonlSessionStore.test.ts +1410 -0
- package/src/session/__tests__/handlers.test.ts +161 -0
- package/src/session/handlers.ts +272 -0
- package/src/session/ids.ts +17 -0
- package/src/session/index.ts +44 -0
- package/src/session/messageSerialization.ts +207 -0
- package/src/session/types.ts +275 -0
- package/src/specs/custom-event-await.test.ts +89 -0
- package/src/specs/summarization.test.ts +1 -1
- package/src/stream.ts +756 -48
- package/src/summarization/node.ts +1 -1
- package/src/tools/ToolNode.ts +299 -126
- package/src/tools/__tests__/ToolNode.eagerEventExecution.test.ts +373 -0
- package/src/tools/__tests__/handlers.test.ts +2 -1
- package/src/tools/__tests__/hitl.test.ts +206 -110
- package/src/tools/eagerEventExecution.ts +153 -0
- package/src/tools/handlers.ts +8 -4
- package/src/tools/streamedToolCallSeals.ts +57 -0
- package/src/types/hitl.ts +4 -0
- package/src/types/run.ts +11 -0
- package/src/types/tools.ts +36 -0
- package/dist/cjs/llm/text.cjs +0 -69
- package/dist/cjs/llm/text.cjs.map +0 -1
- package/dist/esm/llm/text.mjs +0 -67
- package/dist/esm/llm/text.mjs.map +0 -1
|
@@ -1137,7 +1137,7 @@ function createSummarizationChunkHandler({
|
|
|
1137
1137
|
? [{ type: ContentTypes.TEXT, text: raw } as t.MessageContentComplex]
|
|
1138
1138
|
: raw;
|
|
1139
1139
|
|
|
1140
|
-
safeDispatchCustomEvent(
|
|
1140
|
+
void safeDispatchCustomEvent(
|
|
1141
1141
|
GraphEvents.ON_SUMMARIZE_DELTA,
|
|
1142
1142
|
{
|
|
1143
1143
|
id: stepId,
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -50,6 +50,10 @@ import {
|
|
|
50
50
|
resolveLocalToolRegistry,
|
|
51
51
|
resolveLocalExecutionTools,
|
|
52
52
|
} from '@/tools/local';
|
|
53
|
+
import {
|
|
54
|
+
buildToolExecutionRequestPlan,
|
|
55
|
+
recordArgsEqual,
|
|
56
|
+
} from '@/tools/eagerEventExecution';
|
|
53
57
|
|
|
54
58
|
/**
|
|
55
59
|
* Per-call batch context for `runTool`. Bundles every optional
|
|
@@ -413,6 +417,12 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
413
417
|
private sessions?: t.ToolSessionMap;
|
|
414
418
|
/** When true, dispatches ON_TOOL_EXECUTE events instead of invoking tools directly */
|
|
415
419
|
private eventDrivenMode: boolean = false;
|
|
420
|
+
/** Opt-in stream-layer prestart config for event-driven tools. */
|
|
421
|
+
private eagerEventToolExecution?: t.EagerEventToolExecutionConfig;
|
|
422
|
+
/** Shared per-run prestarted tool registry populated by ChatModelStreamHandler. */
|
|
423
|
+
private eagerEventToolExecutions?: Map<string, t.EagerEventToolExecution>;
|
|
424
|
+
/** Shared per-run per-tool turn counter used by eager and normal event dispatch. */
|
|
425
|
+
private eagerEventToolUsageCount?: Map<string, number>;
|
|
416
426
|
/** Agent ID for event-driven mode */
|
|
417
427
|
private agentId?: string;
|
|
418
428
|
/** Tool names that bypass event dispatch and execute directly (e.g., graph-managed handoff tools) */
|
|
@@ -469,6 +479,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
469
479
|
toolRegistry,
|
|
470
480
|
sessions,
|
|
471
481
|
eventDrivenMode,
|
|
482
|
+
eagerEventToolExecution,
|
|
483
|
+
eagerEventToolExecutions,
|
|
484
|
+
eagerEventToolUsageCount,
|
|
472
485
|
agentId,
|
|
473
486
|
directToolNames,
|
|
474
487
|
maxContextTokens,
|
|
@@ -493,6 +506,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
493
506
|
});
|
|
494
507
|
this.sessions = sessions;
|
|
495
508
|
this.eventDrivenMode = eventDrivenMode ?? false;
|
|
509
|
+
this.eagerEventToolExecution = eagerEventToolExecution;
|
|
510
|
+
this.eagerEventToolExecutions = eagerEventToolExecutions;
|
|
511
|
+
this.eagerEventToolUsageCount = eagerEventToolUsageCount;
|
|
496
512
|
this.agentId = agentId;
|
|
497
513
|
this.directToolNames = directToolNames;
|
|
498
514
|
this.maxToolResultChars =
|
|
@@ -698,6 +714,34 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
698
714
|
return new Map(this.toolUsageCount); // Return a copy
|
|
699
715
|
}
|
|
700
716
|
|
|
717
|
+
private recordToolUsageTurn(
|
|
718
|
+
toolName: string,
|
|
719
|
+
turn: number,
|
|
720
|
+
callId?: string
|
|
721
|
+
): void {
|
|
722
|
+
this.toolUsageCount.set(
|
|
723
|
+
toolName,
|
|
724
|
+
Math.max(this.toolUsageCount.get(toolName) ?? 0, turn + 1)
|
|
725
|
+
);
|
|
726
|
+
if (callId != null && callId !== '') {
|
|
727
|
+
this.toolCallTurns.set(callId, turn);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
private recordEventToolPlanningTurn(
|
|
732
|
+
toolName: string,
|
|
733
|
+
turn: number,
|
|
734
|
+
callId?: string
|
|
735
|
+
): void {
|
|
736
|
+
this.recordToolUsageTurn(toolName, turn, callId);
|
|
737
|
+
if (this.canConsumeEagerEventExecution()) {
|
|
738
|
+
this.eagerEventToolUsageCount?.set(
|
|
739
|
+
toolName,
|
|
740
|
+
Math.max(this.eagerEventToolUsageCount.get(toolName) ?? 0, turn + 1)
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
701
745
|
/**
|
|
702
746
|
* Runs a single tool call with error handling.
|
|
703
747
|
*
|
|
@@ -1018,13 +1062,13 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1018
1062
|
handlerError:
|
|
1019
1063
|
handlerError instanceof Error
|
|
1020
1064
|
? {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1065
|
+
message: handlerError.message,
|
|
1066
|
+
stack: handlerError.stack ?? undefined,
|
|
1067
|
+
}
|
|
1024
1068
|
: {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1069
|
+
message: String(handlerError),
|
|
1070
|
+
stack: undefined,
|
|
1071
|
+
},
|
|
1028
1072
|
});
|
|
1029
1073
|
}
|
|
1030
1074
|
}
|
|
@@ -1032,11 +1076,11 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1032
1076
|
const refMeta =
|
|
1033
1077
|
unresolvedRefs.length > 0
|
|
1034
1078
|
? this.recordOutputReference(
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1079
|
+
runId,
|
|
1080
|
+
errorContent,
|
|
1081
|
+
undefined,
|
|
1082
|
+
unresolvedRefs
|
|
1083
|
+
)
|
|
1040
1084
|
: undefined;
|
|
1041
1085
|
return new ToolMessage({
|
|
1042
1086
|
status: 'error',
|
|
@@ -1678,12 +1722,12 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1678
1722
|
* by `runTool`. Threaded as a local map (instead of instance state)
|
|
1679
1723
|
* so concurrent batches cannot read each other's entries.
|
|
1680
1724
|
*/
|
|
1681
|
-
private handleRunToolCompletions(
|
|
1725
|
+
private async handleRunToolCompletions(
|
|
1682
1726
|
calls: ToolCall[],
|
|
1683
1727
|
outputs: (BaseMessage | Command)[],
|
|
1684
1728
|
config: RunnableConfig,
|
|
1685
1729
|
resolvedArgsByCallId?: ResolvedArgsByCallId
|
|
1686
|
-
): void {
|
|
1730
|
+
): Promise<void> {
|
|
1687
1731
|
for (let i = 0; i < calls.length; i++) {
|
|
1688
1732
|
const call = calls[i];
|
|
1689
1733
|
const output = outputs[i];
|
|
@@ -1741,7 +1785,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1741
1785
|
progress: 1,
|
|
1742
1786
|
};
|
|
1743
1787
|
|
|
1744
|
-
safeDispatchCustomEvent(
|
|
1788
|
+
await safeDispatchCustomEvent(
|
|
1745
1789
|
GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
1746
1790
|
{
|
|
1747
1791
|
result: {
|
|
@@ -1949,9 +1993,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
1949
1993
|
});
|
|
1950
1994
|
};
|
|
1951
1995
|
|
|
1952
|
-
const flushDeferredBlockedSideEffects = (): void => {
|
|
1996
|
+
const flushDeferredBlockedSideEffects = async (): Promise<void> => {
|
|
1953
1997
|
for (const item of deferredBlockedSideEffects) {
|
|
1954
|
-
this.dispatchStepCompleted(
|
|
1998
|
+
await this.dispatchStepCompleted(
|
|
1955
1999
|
item.callId,
|
|
1956
2000
|
item.toolName,
|
|
1957
2001
|
item.args,
|
|
@@ -2236,7 +2280,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2236
2280
|
* no risk of being rolled back by a subsequent throw, so
|
|
2237
2281
|
* no risk of a duplicate `ON_RUN_STEP_COMPLETED` event.
|
|
2238
2282
|
*/
|
|
2239
|
-
this.dispatchStepCompleted(
|
|
2283
|
+
await this.dispatchStepCompleted(
|
|
2240
2284
|
entry.call.id!,
|
|
2241
2285
|
entry.call.name,
|
|
2242
2286
|
entry.args,
|
|
@@ -2321,7 +2365,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2321
2365
|
* dispatches in the same relative position as the pre-deferral
|
|
2322
2366
|
* code did (after hook processing, before tool execution).
|
|
2323
2367
|
*/
|
|
2324
|
-
flushDeferredBlockedSideEffects();
|
|
2368
|
+
await flushDeferredBlockedSideEffects();
|
|
2325
2369
|
} else {
|
|
2326
2370
|
approvedEntries.push(...preToolCalls);
|
|
2327
2371
|
}
|
|
@@ -2331,67 +2375,118 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2331
2375
|
const batchIndexByCallId = new Map<string, number>();
|
|
2332
2376
|
|
|
2333
2377
|
if (approvedEntries.length > 0) {
|
|
2334
|
-
const
|
|
2335
|
-
|
|
2336
|
-
|
|
2378
|
+
const plan = buildToolExecutionRequestPlan({
|
|
2379
|
+
toolCalls: approvedEntries.map((entry) => {
|
|
2380
|
+
const codeSessionContext =
|
|
2381
|
+
CODE_EXECUTION_TOOLS.has(entry.call.name) ||
|
|
2382
|
+
entry.call.name === Constants.SKILL_TOOL ||
|
|
2383
|
+
entry.call.name === Constants.READ_FILE
|
|
2384
|
+
? this.getCodeSessionContext()
|
|
2385
|
+
: undefined;
|
|
2386
|
+
return {
|
|
2387
|
+
id: entry.call.id,
|
|
2388
|
+
name: entry.call.name,
|
|
2389
|
+
args: entry.args,
|
|
2390
|
+
stepId: entry.stepId,
|
|
2391
|
+
codeSessionContext,
|
|
2392
|
+
};
|
|
2393
|
+
}),
|
|
2394
|
+
usageCount: this.toolUsageCount,
|
|
2395
|
+
invalidArgsBehavior: 'error-result',
|
|
2396
|
+
recordTurn: (toolName, reservedTurn, callId) => {
|
|
2397
|
+
this.recordEventToolPlanningTurn(toolName, reservedTurn, callId);
|
|
2398
|
+
},
|
|
2399
|
+
});
|
|
2400
|
+
if (plan == null) {
|
|
2401
|
+
throw new Error('Unable to build event tool execution request plan');
|
|
2402
|
+
}
|
|
2403
|
+
const requests = plan.requests;
|
|
2337
2404
|
|
|
2405
|
+
for (const entry of approvedEntries) {
|
|
2338
2406
|
if (entry.batchIndex != null && entry.call.id != null) {
|
|
2339
2407
|
batchIndexByCallId.set(entry.call.id, entry.batchIndex);
|
|
2340
2408
|
}
|
|
2409
|
+
}
|
|
2341
2410
|
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
args: entry.args,
|
|
2346
|
-
stepId: entry.stepId,
|
|
2347
|
-
turn,
|
|
2348
|
-
};
|
|
2411
|
+
for (const result of plan.rejectedResults) {
|
|
2412
|
+
this.eagerEventToolExecutions?.delete(result.toolCallId);
|
|
2413
|
+
}
|
|
2349
2414
|
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
entry.call.name === Constants.SKILL_TOOL ||
|
|
2364
|
-
entry.call.name === Constants.READ_FILE
|
|
2365
|
-
) {
|
|
2366
|
-
request.codeSessionContext = this.getCodeSessionContext();
|
|
2415
|
+
const requestMap = new Map(plan.allRequests.map((r) => [r.id, r]));
|
|
2416
|
+
const eagerExecutions: Array<{
|
|
2417
|
+
request: t.ToolCallRequest;
|
|
2418
|
+
execution: t.EagerEventToolExecution;
|
|
2419
|
+
}> = [];
|
|
2420
|
+
const dispatchRequests: t.ToolCallRequest[] = [];
|
|
2421
|
+
|
|
2422
|
+
for (const request of requests) {
|
|
2423
|
+
const eagerExecution = this.takeMatchingEagerEventExecution(request);
|
|
2424
|
+
if (eagerExecution != null) {
|
|
2425
|
+
eagerExecutions.push({ request, execution: eagerExecution });
|
|
2426
|
+
} else {
|
|
2427
|
+
dispatchRequests.push(request);
|
|
2367
2428
|
}
|
|
2429
|
+
}
|
|
2368
2430
|
|
|
2369
|
-
|
|
2370
|
-
|
|
2431
|
+
const dispatchPromise =
|
|
2432
|
+
dispatchRequests.length === 0
|
|
2433
|
+
? Promise.resolve([] as t.ToolExecuteResult[])
|
|
2434
|
+
: new Promise<t.ToolExecuteResult[]>((resolve, reject) => {
|
|
2435
|
+
let dispatchSettled = false;
|
|
2436
|
+
let resultSettled = false;
|
|
2437
|
+
let settledResults: t.ToolExecuteResult[] | undefined;
|
|
2438
|
+
|
|
2439
|
+
const maybeResolve = (): void => {
|
|
2440
|
+
if (dispatchSettled && resultSettled) {
|
|
2441
|
+
resolve(settledResults ?? []);
|
|
2442
|
+
}
|
|
2443
|
+
};
|
|
2371
2444
|
|
|
2372
|
-
|
|
2445
|
+
const batchRequest: t.ToolExecuteBatchRequest = {
|
|
2446
|
+
toolCalls: dispatchRequests,
|
|
2447
|
+
userId: config.configurable?.user_id as string | undefined,
|
|
2448
|
+
agentId: this.agentId,
|
|
2449
|
+
configurable: config.configurable as
|
|
2450
|
+
| Record<string, unknown>
|
|
2451
|
+
| undefined,
|
|
2452
|
+
metadata: config.metadata as
|
|
2453
|
+
| Record<string, unknown>
|
|
2454
|
+
| undefined,
|
|
2455
|
+
resolve: (results): void => {
|
|
2456
|
+
resultSettled = true;
|
|
2457
|
+
settledResults = results;
|
|
2458
|
+
maybeResolve();
|
|
2459
|
+
},
|
|
2460
|
+
reject,
|
|
2461
|
+
};
|
|
2373
2462
|
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
reject,
|
|
2386
|
-
};
|
|
2463
|
+
void safeDispatchCustomEvent(
|
|
2464
|
+
GraphEvents.ON_TOOL_EXECUTE,
|
|
2465
|
+
batchRequest,
|
|
2466
|
+
config
|
|
2467
|
+
)
|
|
2468
|
+
.then(() => {
|
|
2469
|
+
dispatchSettled = true;
|
|
2470
|
+
maybeResolve();
|
|
2471
|
+
})
|
|
2472
|
+
.catch(reject);
|
|
2473
|
+
});
|
|
2387
2474
|
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2475
|
+
const eagerResultsPromise = Promise.all(
|
|
2476
|
+
eagerExecutions.map(({ request, execution }) =>
|
|
2477
|
+
this.resolveEagerEventExecution(request, execution)
|
|
2478
|
+
)
|
|
2479
|
+
).then((results) => results.flat());
|
|
2480
|
+
|
|
2481
|
+
const [eagerResults, dispatchedResults] = await Promise.all([
|
|
2482
|
+
eagerResultsPromise,
|
|
2483
|
+
dispatchPromise,
|
|
2484
|
+
]);
|
|
2485
|
+
const results = [
|
|
2486
|
+
...plan.rejectedResults,
|
|
2487
|
+
...eagerResults,
|
|
2488
|
+
...dispatchedResults,
|
|
2489
|
+
];
|
|
2395
2490
|
|
|
2396
2491
|
this.storeCodeSessionFromResults(results, requestMap);
|
|
2397
2492
|
|
|
@@ -2442,11 +2537,11 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2442
2537
|
const errorRefMeta =
|
|
2443
2538
|
unresolved.length > 0
|
|
2444
2539
|
? this.recordOutputReference(
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2540
|
+
registryRunId,
|
|
2541
|
+
contentString,
|
|
2542
|
+
undefined,
|
|
2543
|
+
unresolved
|
|
2544
|
+
)
|
|
2450
2545
|
: undefined;
|
|
2451
2546
|
toolMessage = new ToolMessage({
|
|
2452
2547
|
status: 'error',
|
|
@@ -2565,7 +2660,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2565
2660
|
});
|
|
2566
2661
|
}
|
|
2567
2662
|
|
|
2568
|
-
this.dispatchStepCompleted(
|
|
2663
|
+
await this.dispatchStepCompleted(
|
|
2569
2664
|
result.toolCallId,
|
|
2570
2665
|
toolName,
|
|
2571
2666
|
request?.args ?? {},
|
|
@@ -2606,6 +2701,84 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2606
2701
|
return { toolMessages, injected };
|
|
2607
2702
|
}
|
|
2608
2703
|
|
|
2704
|
+
private canConsumeEagerEventExecution(): boolean {
|
|
2705
|
+
return (
|
|
2706
|
+
this.eventDrivenMode &&
|
|
2707
|
+
this.eagerEventToolExecution?.enabled === true &&
|
|
2708
|
+
this.hookRegistry == null &&
|
|
2709
|
+
this.humanInTheLoop?.enabled !== true &&
|
|
2710
|
+
this.toolOutputRegistry == null
|
|
2711
|
+
);
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2714
|
+
private takeMatchingEagerEventExecution(
|
|
2715
|
+
request: t.ToolCallRequest
|
|
2716
|
+
): t.EagerEventToolExecution | undefined {
|
|
2717
|
+
if (!this.canConsumeEagerEventExecution()) {
|
|
2718
|
+
return undefined;
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2721
|
+
const execution = this.eagerEventToolExecutions?.get(request.id);
|
|
2722
|
+
if (execution == null) {
|
|
2723
|
+
return undefined;
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
this.eagerEventToolExecutions?.delete(request.id);
|
|
2727
|
+
|
|
2728
|
+
if (
|
|
2729
|
+
execution.toolName !== request.name ||
|
|
2730
|
+
!recordArgsEqual(execution.args, request.args) ||
|
|
2731
|
+
execution.request.turn !== request.turn
|
|
2732
|
+
) {
|
|
2733
|
+
return {
|
|
2734
|
+
toolCallId: request.id,
|
|
2735
|
+
toolName: request.name,
|
|
2736
|
+
args: request.args,
|
|
2737
|
+
request,
|
|
2738
|
+
promise: Promise.resolve({
|
|
2739
|
+
results: [
|
|
2740
|
+
{
|
|
2741
|
+
toolCallId: request.id,
|
|
2742
|
+
status: 'error',
|
|
2743
|
+
content: '',
|
|
2744
|
+
errorMessage:
|
|
2745
|
+
'Tool call changed after eager execution started; refusing to re-run the tool to avoid duplicate side effects.',
|
|
2746
|
+
},
|
|
2747
|
+
],
|
|
2748
|
+
}),
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
return execution;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
private async resolveEagerEventExecution(
|
|
2756
|
+
request: t.ToolCallRequest,
|
|
2757
|
+
execution: t.EagerEventToolExecution
|
|
2758
|
+
): Promise<t.ToolExecuteResult[]> {
|
|
2759
|
+
const outcome = await execution.promise;
|
|
2760
|
+
if (outcome.error != null) {
|
|
2761
|
+
throw outcome.error;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
const results = outcome.results.filter(
|
|
2765
|
+
(result) => result.toolCallId === request.id
|
|
2766
|
+
);
|
|
2767
|
+
if (results.length > 0) {
|
|
2768
|
+
return results;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
return [
|
|
2772
|
+
{
|
|
2773
|
+
toolCallId: request.id,
|
|
2774
|
+
status: 'error',
|
|
2775
|
+
content: '',
|
|
2776
|
+
errorMessage:
|
|
2777
|
+
'Tool execution completed without a result for this tool call',
|
|
2778
|
+
},
|
|
2779
|
+
];
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2609
2782
|
/**
|
|
2610
2783
|
* Fires the `PostToolBatch` hook (if registered) and appends the
|
|
2611
2784
|
* accumulated batch-level `additionalContext` strings to `injected`
|
|
@@ -2692,14 +2865,14 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2692
2865
|
}
|
|
2693
2866
|
}
|
|
2694
2867
|
|
|
2695
|
-
private dispatchStepCompleted(
|
|
2868
|
+
private async dispatchStepCompleted(
|
|
2696
2869
|
toolCallId: string,
|
|
2697
2870
|
toolName: string,
|
|
2698
2871
|
args: Record<string, unknown>,
|
|
2699
2872
|
output: string,
|
|
2700
2873
|
config: RunnableConfig,
|
|
2701
2874
|
turn?: number
|
|
2702
|
-
): void {
|
|
2875
|
+
): Promise<void> {
|
|
2703
2876
|
const stepId = this.toolCallStepIds?.get(toolCallId) ?? '';
|
|
2704
2877
|
if (!stepId) {
|
|
2705
2878
|
// eslint-disable-next-line no-console
|
|
@@ -2710,7 +2883,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2710
2883
|
);
|
|
2711
2884
|
}
|
|
2712
2885
|
|
|
2713
|
-
safeDispatchCustomEvent(
|
|
2886
|
+
await safeDispatchCustomEvent(
|
|
2714
2887
|
GraphEvents.ON_RUN_STEP_COMPLETED,
|
|
2715
2888
|
{
|
|
2716
2889
|
result: {
|
|
@@ -2842,17 +3015,17 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
2842
3015
|
outputs =
|
|
2843
3016
|
directAdditionalContexts.length > 0
|
|
2844
3017
|
? [
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
3018
|
+
sendOutput,
|
|
3019
|
+
new HumanMessage({
|
|
3020
|
+
content: directAdditionalContexts.join('\n\n'),
|
|
3021
|
+
// Match the event-driven path's marker so hosts /
|
|
3022
|
+
// model-side annotators treat this as system intent
|
|
3023
|
+
// rather than ordinary user text. Codex P2 [46].
|
|
3024
|
+
additional_kwargs: { role: 'system', source: 'hook' },
|
|
3025
|
+
}),
|
|
3026
|
+
]
|
|
2854
3027
|
: [sendOutput];
|
|
2855
|
-
this.handleRunToolCompletions(
|
|
3028
|
+
await this.handleRunToolCompletions(
|
|
2856
3029
|
[input.lg_tool_call],
|
|
2857
3030
|
// Pass only the tool output to completion handling; the
|
|
2858
3031
|
// HumanMessage isn't a tool result.
|
|
@@ -3001,21 +3174,21 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3001
3174
|
const directOutputs: (BaseMessage | Command)[] =
|
|
3002
3175
|
directCalls.length > 0
|
|
3003
3176
|
? await Promise.all(
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3177
|
+
directCalls.map((call, i) =>
|
|
3178
|
+
this.runDirectToolWithLifecycleHooks(call, config, {
|
|
3179
|
+
batchIndex: directIndices[i],
|
|
3180
|
+
turn,
|
|
3181
|
+
batchScopeId,
|
|
3182
|
+
resolvedArgsByCallId,
|
|
3183
|
+
preBatchSnapshot,
|
|
3184
|
+
additionalContextsSink: directAdditionalContexts,
|
|
3185
|
+
})
|
|
3186
|
+
)
|
|
3013
3187
|
)
|
|
3014
|
-
)
|
|
3015
3188
|
: [];
|
|
3016
3189
|
|
|
3017
3190
|
if (directCalls.length > 0 && directOutputs.length > 0) {
|
|
3018
|
-
this.handleRunToolCompletions(
|
|
3191
|
+
await this.handleRunToolCompletions(
|
|
3019
3192
|
directCalls,
|
|
3020
3193
|
directOutputs,
|
|
3021
3194
|
config,
|
|
@@ -3026,29 +3199,29 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3026
3199
|
const eventResult =
|
|
3027
3200
|
eventCalls.length > 0
|
|
3028
3201
|
? await this.dispatchToolEvents(eventCalls, config, {
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3202
|
+
batchIndices: eventIndices,
|
|
3203
|
+
turn,
|
|
3204
|
+
batchScopeId,
|
|
3205
|
+
preResolvedArgs: preResolvedEventArgs,
|
|
3206
|
+
preBatchSnapshot,
|
|
3207
|
+
})
|
|
3035
3208
|
: {
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3209
|
+
toolMessages: [] as ToolMessage[],
|
|
3210
|
+
injected: [] as BaseMessage[],
|
|
3211
|
+
};
|
|
3039
3212
|
|
|
3040
3213
|
const directInjected: BaseMessage[] =
|
|
3041
3214
|
directAdditionalContexts.length > 0
|
|
3042
3215
|
? [
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3216
|
+
new HumanMessage({
|
|
3217
|
+
content: directAdditionalContexts.join('\n\n'),
|
|
3218
|
+
// System-role metadata to match the event-driven
|
|
3219
|
+
// path so policy/recovery guidance is treated
|
|
3220
|
+
// consistently regardless of whether the tool ran
|
|
3221
|
+
// direct or dispatched. Codex P2 [46].
|
|
3222
|
+
additional_kwargs: { role: 'system', source: 'hook' },
|
|
3223
|
+
}),
|
|
3224
|
+
]
|
|
3052
3225
|
: [];
|
|
3053
3226
|
outputs = [
|
|
3054
3227
|
...directOutputs,
|
|
@@ -3076,7 +3249,7 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3076
3249
|
})
|
|
3077
3250
|
)
|
|
3078
3251
|
);
|
|
3079
|
-
this.handleRunToolCompletions(
|
|
3252
|
+
await this.handleRunToolCompletions(
|
|
3080
3253
|
filteredCalls,
|
|
3081
3254
|
toolOutputs,
|
|
3082
3255
|
config,
|
|
@@ -3087,15 +3260,15 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
|
|
|
3087
3260
|
outputs =
|
|
3088
3261
|
directAdditionalContexts.length > 0
|
|
3089
3262
|
? [
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3263
|
+
...toolOutputs,
|
|
3264
|
+
new HumanMessage({
|
|
3265
|
+
content: directAdditionalContexts.join('\n\n'),
|
|
3266
|
+
// Same system-role marker the event-driven path
|
|
3267
|
+
// uses so direct vs dispatched is invisible to
|
|
3268
|
+
// downstream consumers. Codex P2 [46].
|
|
3269
|
+
additional_kwargs: { role: 'system', source: 'hook' },
|
|
3270
|
+
}),
|
|
3271
|
+
]
|
|
3099
3272
|
: toolOutputs;
|
|
3100
3273
|
}
|
|
3101
3274
|
}
|