@librechat/agents 3.5.1 → 3.6.0
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 +5 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +148 -22
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +2 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/main.cjs +4 -0
- package/dist/cjs/run.cjs +29 -11
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +8 -6
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/BashExecutor.cjs +8 -7
- package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +5 -4
- package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +26 -7
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs +7 -6
- package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +33 -10
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/ToolSearch.cjs +1 -1
- package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
- package/dist/cjs/tools/runStepResume.cjs +51 -0
- package/dist/cjs/tools/runStepResume.cjs.map +1 -0
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +15 -43
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +6 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- package/dist/cjs/utils/toolSessions.cjs +63 -0
- package/dist/cjs/utils/toolSessions.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +5 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +148 -22
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +2 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/main.mjs +2 -2
- package/dist/esm/run.mjs +29 -11
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +8 -6
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/BashExecutor.mjs +9 -8
- package/dist/esm/tools/BashExecutor.mjs.map +1 -1
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs +6 -5
- package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +23 -8
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ProgrammaticToolCalling.mjs +8 -7
- package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +33 -10
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/ToolSearch.mjs +2 -2
- package/dist/esm/tools/ToolSearch.mjs.map +1 -1
- package/dist/esm/tools/runStepResume.mjs +48 -0
- package/dist/esm/tools/runStepResume.mjs.map +1 -0
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +15 -43
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +6 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- package/dist/esm/utils/toolSessions.mjs +62 -0
- package/dist/esm/utils/toolSessions.mjs.map +1 -0
- package/dist/types/agents/AgentContext.d.ts +4 -1
- package/dist/types/graphs/Graph.d.ts +11 -3
- package/dist/types/tools/CodeExecutor.d.ts +4 -0
- package/dist/types/tools/ProgrammaticToolCalling.d.ts +1 -1
- package/dist/types/tools/ToolNode.d.ts +3 -1
- package/dist/types/tools/runStepResume.d.ts +5 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +25 -0
- package/dist/types/tools/subagent/SubagentReplay.d.ts +2 -1
- package/dist/types/types/graph.d.ts +10 -1
- package/dist/types/types/stream.d.ts +18 -0
- package/dist/types/types/tools.d.ts +36 -16
- package/dist/types/utils/toolSessions.d.ts +18 -0
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +7 -0
- package/src/graphs/Graph.ts +192 -13
- package/src/graphs/MultiAgentGraph.ts +1 -0
- package/src/run.ts +62 -11
- package/src/stream.ts +28 -9
- package/src/tools/BashExecutor.ts +31 -13
- package/src/tools/BashProgrammaticToolCalling.ts +19 -9
- package/src/tools/CodeExecutor.ts +57 -16
- package/src/tools/ProgrammaticToolCalling.ts +26 -12
- package/src/tools/ToolNode.ts +58 -8
- package/src/tools/ToolSearch.ts +2 -2
- package/src/tools/runStepResume.ts +121 -0
- package/src/tools/subagent/SubagentExecutor.ts +67 -65
- package/src/tools/subagent/SubagentReplay.ts +22 -1
- package/src/types/graph.ts +10 -0
- package/src/types/stream.ts +17 -0
- package/src/types/tools.ts +50 -21
- package/src/utils/toolSessions.ts +113 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { StructuredToolInterface } from '@langchain/core/tools';
|
|
2
|
-
import type { RunnableToolLike } from '@langchain/core/runnables';
|
|
2
|
+
import type { RunnableConfig, RunnableToolLike } from '@langchain/core/runnables';
|
|
3
3
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
4
4
|
import type { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
|
|
5
5
|
import type { RunBreakerScope } from '@/llm/streamLimits';
|
|
6
|
-
import type { MessageContentComplex, ToolErrorData } from './stream';
|
|
6
|
+
import type { MessageContentComplex, RunStepResumeState, ToolErrorData } from './stream';
|
|
7
7
|
import type { HumanInTheLoopConfig } from './hitl';
|
|
8
8
|
import type { LangfuseConfig } from './graph';
|
|
9
9
|
import type { HookRegistry } from '@/hooks';
|
|
@@ -118,6 +118,8 @@ export type ToolNodeOptions = {
|
|
|
118
118
|
toolRegistry?: LCToolRegistry;
|
|
119
119
|
/** Reference to Graph's sessions map for automatic session injection */
|
|
120
120
|
sessions?: ToolSessionMap;
|
|
121
|
+
/** Partition within `sessions` used by this agent's code tools. */
|
|
122
|
+
codeSessionKey?: string;
|
|
121
123
|
/** When true, dispatches ON_TOOL_EXECUTE events instead of invoking tools directly */
|
|
122
124
|
eventDrivenMode?: boolean;
|
|
123
125
|
/** Tool definitions for event-driven mode (used for context, not invocation) */
|
|
@@ -264,6 +266,10 @@ export type ToolNodeOptions = {
|
|
|
264
266
|
* controller.
|
|
265
267
|
*/
|
|
266
268
|
getRunScope?: () => RunBreakerScope;
|
|
269
|
+
/** SDK-owned checkpoint bridge for open run-step lifecycle state. */
|
|
270
|
+
restoreRunStepResumeState?: (state?: RunStepResumeState, config?: RunnableConfig) => void;
|
|
271
|
+
/** SDK-owned checkpoint snapshot for open run-step lifecycle state. */
|
|
272
|
+
createRunStepResumeState?: () => RunStepResumeState;
|
|
267
273
|
};
|
|
268
274
|
export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
|
|
269
275
|
export type ToolEndEvent = {
|
|
@@ -361,6 +367,19 @@ export type CodeEnvFile = (CodeEnvFileBase & {
|
|
|
361
367
|
kind: 'user';
|
|
362
368
|
});
|
|
363
369
|
export type CodeExecutionToolParams = undefined | {
|
|
370
|
+
/** Trusted Code API endpoint selected by the host for this agent. */
|
|
371
|
+
baseUrl?: string;
|
|
372
|
+
/**
|
|
373
|
+
* Expected Code API execution profile. Sent as a request assertion so
|
|
374
|
+
* endpoint/configuration drift fails closed instead of silently using
|
|
375
|
+
* the wrong sandbox backend.
|
|
376
|
+
*/
|
|
377
|
+
executionProfile?: CodeApiExecutionProfile;
|
|
378
|
+
/**
|
|
379
|
+
* Trusted warm-runtime affinity hint selected by the host for this
|
|
380
|
+
* agent invocation. This overrides the legacy ToolNode-injected hint.
|
|
381
|
+
*/
|
|
382
|
+
runtimeSessionHint?: string;
|
|
364
383
|
/** Execution session — see `CodeSessionContext.session_id`. */
|
|
365
384
|
session_id?: string;
|
|
366
385
|
user_id?: string;
|
|
@@ -368,15 +387,14 @@ export type CodeExecutionToolParams = undefined | {
|
|
|
368
387
|
/** Optional host-supplied Code API auth headers. */
|
|
369
388
|
authHeaders?: CodeApiAuthHeaders;
|
|
370
389
|
/**
|
|
371
|
-
* Advertise
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* `toolExecution.sandbox.statefulSessions` gate, which drives the wire
|
|
376
|
-
* hint — set both from one flag so the prompt and the backend agree.
|
|
390
|
+
* Advertise filesystem-tier stateful sessions in the tool description
|
|
391
|
+
* and allow a trusted runtime affinity hint onto the wire. Resolve this,
|
|
392
|
+
* `baseUrl`, `executionProfile`, and `runtimeSessionHint` together from
|
|
393
|
+
* the executing agent so the prompt and backend agree.
|
|
377
394
|
*/
|
|
378
395
|
statefulSessions?: boolean;
|
|
379
396
|
};
|
|
397
|
+
export type CodeApiExecutionProfile = 'default' | 'stateful';
|
|
380
398
|
export type CodeApiAuthHeaderMap = Record<string, string>;
|
|
381
399
|
export type CodeApiAuthHeaders = CodeApiAuthHeaderMap | (() => CodeApiAuthHeaderMap | Promise<CodeApiAuthHeaderMap>);
|
|
382
400
|
export type FileRef = {
|
|
@@ -1032,19 +1050,17 @@ export type CloudflareSandboxExecutionConfig = {
|
|
|
1032
1050
|
};
|
|
1033
1051
|
export type SandboxExecutionConfig = {
|
|
1034
1052
|
/**
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1053
|
+
* Legacy run-scoped opt-in for warm runtime hint injection. New hosts that
|
|
1054
|
+
* need mixed execution profiles should resolve `statefulSessions`,
|
|
1055
|
+
* `baseUrl`, `executionProfile`, and `runtimeSessionHint` on each executing
|
|
1056
|
+
* agent's tool factories instead. Direct executors ignore this injected hint
|
|
1057
|
+
* unless their own factory has `statefulSessions: true`.
|
|
1039
1058
|
*
|
|
1040
1059
|
* It does NOT change the model-facing tool description. Tool descriptions are
|
|
1041
1060
|
* bound to the LLM at construction time (`createCodeExecutionTool` /
|
|
1042
1061
|
* `createBashExecutionTool`), before this run config is applied inside the
|
|
1043
1062
|
* graph, so they can only be adjusted via the tools' own `statefulSessions`
|
|
1044
|
-
* factory param.
|
|
1045
|
-
* the factory param off, the backend runs statefully while the model is still
|
|
1046
|
-
* told the environment is stateless (non-corrupting — the model just won't
|
|
1047
|
-
* exploit persistence).
|
|
1063
|
+
* factory param.
|
|
1048
1064
|
*/
|
|
1049
1065
|
statefulSessions?: boolean;
|
|
1050
1066
|
/**
|
|
@@ -1193,6 +1209,10 @@ export type BashProgrammaticToolCallingParams = ProgrammaticToolCallingParams;
|
|
|
1193
1209
|
export type ProgrammaticToolCallingParams = {
|
|
1194
1210
|
/** Code API base URL (or use CODE_BASEURL env var) */
|
|
1195
1211
|
baseUrl?: string;
|
|
1212
|
+
/** Expected Code API execution profile (host-controlled). */
|
|
1213
|
+
executionProfile?: CodeApiExecutionProfile;
|
|
1214
|
+
/** Trusted warm-runtime affinity hint for this agent invocation. */
|
|
1215
|
+
runtimeSessionHint?: string;
|
|
1196
1216
|
/** Safety limit for round-trips (default: 20) */
|
|
1197
1217
|
maxRoundTrips?: number;
|
|
1198
1218
|
/** Maximum per-sandbox-run timeout for PTC's legacy `timeout` field. */
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as t from '@/types';
|
|
2
|
+
type CodeSessionAgent = Pick<t.AgentInputs, 'codeSessionKey' | 'initialSessions'>;
|
|
3
|
+
/**
|
|
4
|
+
* Seeds a top-level graph while preserving the legacy run-wide session map.
|
|
5
|
+
* A legacy `execute_code` seed is copied into every custom agent partition
|
|
6
|
+
* unless the host already supplied an explicit seed for that partition.
|
|
7
|
+
*/
|
|
8
|
+
export declare function seedRunInitialSessions(args: {
|
|
9
|
+
sessions: t.ToolSessionMap;
|
|
10
|
+
initialSessions: t.ToolSessionMap;
|
|
11
|
+
agents: Iterable<Pick<t.AgentInputs, 'codeSessionKey'>>;
|
|
12
|
+
}): void;
|
|
13
|
+
/**
|
|
14
|
+
* Seeds an isolated child graph from each selected agent. Legacy code-session
|
|
15
|
+
* entries are remapped to the owning agent's partition before they are merged.
|
|
16
|
+
*/
|
|
17
|
+
export declare function seedAgentInitialSessions(sessions: t.ToolSessionMap, agents: Iterable<CodeSessionAgent>): void;
|
|
18
|
+
export {};
|
package/package.json
CHANGED
|
@@ -63,6 +63,7 @@ export class AgentContext {
|
|
|
63
63
|
): AgentContext {
|
|
64
64
|
const {
|
|
65
65
|
agentId,
|
|
66
|
+
codeSessionKey,
|
|
66
67
|
name,
|
|
67
68
|
provider,
|
|
68
69
|
clientOptions,
|
|
@@ -92,6 +93,7 @@ export class AgentContext {
|
|
|
92
93
|
|
|
93
94
|
const agentContext = new AgentContext({
|
|
94
95
|
agentId,
|
|
96
|
+
codeSessionKey,
|
|
95
97
|
name: name ?? agentId,
|
|
96
98
|
provider,
|
|
97
99
|
clientOptions,
|
|
@@ -167,6 +169,8 @@ export class AgentContext {
|
|
|
167
169
|
|
|
168
170
|
/** Agent identifier */
|
|
169
171
|
agentId: string;
|
|
172
|
+
/** Partition for this agent's transient code session and file refs. */
|
|
173
|
+
codeSessionKey?: string;
|
|
170
174
|
/** Human-readable name for this agent (used in handoff context). Falls back to agentId if not provided. */
|
|
171
175
|
name?: string;
|
|
172
176
|
/** Provider for this specific agent */
|
|
@@ -370,6 +374,7 @@ export class AgentContext {
|
|
|
370
374
|
|
|
371
375
|
constructor({
|
|
372
376
|
agentId,
|
|
377
|
+
codeSessionKey,
|
|
373
378
|
name,
|
|
374
379
|
provider,
|
|
375
380
|
clientOptions,
|
|
@@ -394,6 +399,7 @@ export class AgentContext {
|
|
|
394
399
|
maxToolResultChars,
|
|
395
400
|
}: {
|
|
396
401
|
agentId: string;
|
|
402
|
+
codeSessionKey?: string;
|
|
397
403
|
name?: string;
|
|
398
404
|
provider: Providers;
|
|
399
405
|
clientOptions?: t.ClientOptions;
|
|
@@ -418,6 +424,7 @@ export class AgentContext {
|
|
|
418
424
|
maxToolResultChars?: number;
|
|
419
425
|
}) {
|
|
420
426
|
this.agentId = agentId;
|
|
427
|
+
this.codeSessionKey = codeSessionKey;
|
|
421
428
|
this.name = name;
|
|
422
429
|
this.provider = provider;
|
|
423
430
|
this.clientOptions = clientOptions;
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
BaseMessage,
|
|
17
17
|
MessageContent,
|
|
18
18
|
} from '@langchain/core/messages';
|
|
19
|
+
import type { BaseChannel, OverwriteValue } from '@langchain/langgraph';
|
|
19
20
|
import type { ToolCall } from '@langchain/core/messages/tool';
|
|
20
21
|
import type {
|
|
21
22
|
ReplayableSubagentTool,
|
|
@@ -167,6 +168,7 @@ import { createSchemaOnlyTools } from '@/tools/schema';
|
|
|
167
168
|
import { AgentContext } from '@/agents/AgentContext';
|
|
168
169
|
import { createFakeStreamingLLM } from '@/llm/fake';
|
|
169
170
|
import { handleToolCalls } from '@/tools/handlers';
|
|
171
|
+
import { isRunStepResumeState } from '@/tools/runStepResume';
|
|
170
172
|
import { isThinkingEnabled } from '@/llm/request';
|
|
171
173
|
import { resolveMaxSeals } from '@/llm/preempt';
|
|
172
174
|
import { initializeModel } from '@/llm/init';
|
|
@@ -673,11 +675,36 @@ function getDispatchableFinalReasoningContent({
|
|
|
673
675
|
return responseReasoningContent;
|
|
674
676
|
}
|
|
675
677
|
|
|
678
|
+
function createEmptyRunStepResumeState(): t.RunStepResumeState {
|
|
679
|
+
return {
|
|
680
|
+
version: 1,
|
|
681
|
+
revision: 0,
|
|
682
|
+
nextIndex: 0,
|
|
683
|
+
toolCallSteps: [],
|
|
684
|
+
steps: [],
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
type RunStepStateChannel = BaseChannel<
|
|
689
|
+
t.RunStepResumeState,
|
|
690
|
+
t.RunStepResumeState | OverwriteValue<t.RunStepResumeState>
|
|
691
|
+
>;
|
|
692
|
+
|
|
693
|
+
function buildRunStepStateAnnotation(): RunStepStateChannel {
|
|
694
|
+
return Annotation<t.RunStepResumeState>({
|
|
695
|
+
reducer: (current, update) =>
|
|
696
|
+
update.revision >= current.revision ? update : current,
|
|
697
|
+
default: createEmptyRunStepResumeState,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
|
|
676
701
|
export abstract class Graph<
|
|
677
702
|
T extends t.BaseGraphState = t.BaseGraphState,
|
|
678
703
|
_TNodeName extends string = string,
|
|
679
704
|
> {
|
|
680
705
|
abstract resetValues(keepContent?: boolean, checkpointScope?: string): void;
|
|
706
|
+
abstract createRunStepResumeState(): t.RunStepResumeState;
|
|
707
|
+
abstract restoreRunStepResumeState(state?: t.RunStepResumeState): void;
|
|
681
708
|
restoreCheckpointMessages(
|
|
682
709
|
_messages: BaseMessage[],
|
|
683
710
|
_pendingMessages?: BaseMessage[]
|
|
@@ -739,6 +766,8 @@ export abstract class Graph<
|
|
|
739
766
|
prelimMessageIdsByStepKey: Map<string, string> = new Map();
|
|
740
767
|
config: RunnableConfig | undefined;
|
|
741
768
|
contentData: t.RunStep[] = [];
|
|
769
|
+
protected nextContentIndex = 0;
|
|
770
|
+
protected runStepStateRevision = 0;
|
|
742
771
|
stepKeyIds: Map<string, string[]> = new Map<string, string[]>();
|
|
743
772
|
contentIndexMap: Map<string, number> = new Map();
|
|
744
773
|
toolCallStepIds: Map<string, string> = new Map();
|
|
@@ -866,6 +895,8 @@ export abstract class Graph<
|
|
|
866
895
|
this.signal = undefined;
|
|
867
896
|
this.callerSignal = undefined;
|
|
868
897
|
this.contentData = [];
|
|
898
|
+
this.nextContentIndex = 0;
|
|
899
|
+
this.runStepStateRevision = 0;
|
|
869
900
|
this.contentIndexMap = new Map();
|
|
870
901
|
this.stepKeyIds = new Map();
|
|
871
902
|
this.toolCallStepIds.clear();
|
|
@@ -950,15 +981,18 @@ export abstract class Graph<
|
|
|
950
981
|
|
|
951
982
|
/**
|
|
952
983
|
* Tracks a tool call whose completion must arrive before its step can be
|
|
953
|
-
* considered finished. Registered wherever `toolCallStepIds` gains entries
|
|
954
|
-
* except cross-process subagent resume restoration, where pending state
|
|
955
|
-
* cannot be faithfully rebuilt and closes fall back to completions/sweep.
|
|
984
|
+
* considered finished. Registered wherever `toolCallStepIds` gains entries.
|
|
956
985
|
*/
|
|
957
986
|
registerPendingToolCall(toolCallId: string, stepId: string): void {
|
|
958
987
|
if (!toolCallId || !stepId) {
|
|
959
988
|
return;
|
|
960
989
|
}
|
|
961
|
-
this.getPendingToolCallSet(stepId)
|
|
990
|
+
const pending = this.getPendingToolCallSet(stepId);
|
|
991
|
+
const size = pending.size;
|
|
992
|
+
pending.add(toolCallId);
|
|
993
|
+
if (pending.size !== size) {
|
|
994
|
+
this.runStepStateRevision += 1;
|
|
995
|
+
}
|
|
962
996
|
}
|
|
963
997
|
|
|
964
998
|
/** Lazily creates a step's pending-completions set; callers registering a
|
|
@@ -1063,6 +1097,7 @@ export abstract class Graph<
|
|
|
1063
1097
|
),
|
|
1064
1098
|
],
|
|
1065
1099
|
eagerToolSuppressions: [...this.eagerEventToolSuppressions],
|
|
1100
|
+
runStepState: this.createRunStepResumeState(),
|
|
1066
1101
|
...(this._toolOutputRegistry == null
|
|
1067
1102
|
? {}
|
|
1068
1103
|
: {
|
|
@@ -1099,6 +1134,7 @@ export abstract class Graph<
|
|
|
1099
1134
|
throw new Error('Cannot restore disabled tool output references.');
|
|
1100
1135
|
}
|
|
1101
1136
|
|
|
1137
|
+
this.restoreRunStepResumeState(state.runStepState);
|
|
1102
1138
|
this.toolCallStepIds.clear();
|
|
1103
1139
|
for (const { toolCallId, stepId } of state.toolCallSteps) {
|
|
1104
1140
|
this.toolCallStepIds.set(toolCallId, stepId);
|
|
@@ -1469,6 +1505,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1469
1505
|
this.config = resetIfNotEmpty(this.config, undefined);
|
|
1470
1506
|
if (keepContent !== true) {
|
|
1471
1507
|
this.contentData = resetIfNotEmpty(this.contentData, []);
|
|
1508
|
+
this.nextContentIndex = 0;
|
|
1509
|
+
this.runStepStateRevision = 0;
|
|
1472
1510
|
this.contentIndexMap = resetIfNotEmpty(this.contentIndexMap, new Map());
|
|
1473
1511
|
}
|
|
1474
1512
|
this.stepKeyIds = resetIfNotEmpty(this.stepKeyIds, new Map());
|
|
@@ -1737,6 +1775,78 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1737
1775
|
|
|
1738
1776
|
/* Run Step Processing */
|
|
1739
1777
|
|
|
1778
|
+
createRunStepResumeState(): t.RunStepResumeState {
|
|
1779
|
+
const steps: t.RunStepResumeEntry[] = [];
|
|
1780
|
+
for (const runStep of this.contentData) {
|
|
1781
|
+
if (runStep.status != null && runStep.status !== 'in_progress') {
|
|
1782
|
+
continue;
|
|
1783
|
+
}
|
|
1784
|
+
const agentKey = runStep.agentId ?? '';
|
|
1785
|
+
steps.push({
|
|
1786
|
+
step: structuredClone(runStep),
|
|
1787
|
+
pendingToolCallIds: [
|
|
1788
|
+
...(this.pendingToolCallsByStep.get(runStep.id) ?? []),
|
|
1789
|
+
],
|
|
1790
|
+
...(this.latestCompletionByStep.has(runStep.id)
|
|
1791
|
+
? {
|
|
1792
|
+
latestCompletionAt: this.latestCompletionByStep.get(runStep.id),
|
|
1793
|
+
}
|
|
1794
|
+
: {}),
|
|
1795
|
+
openMessageStep:
|
|
1796
|
+
this.openMessageStepByAgent.get(agentKey) === runStep.id,
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
return {
|
|
1800
|
+
version: 1,
|
|
1801
|
+
revision: this.runStepStateRevision,
|
|
1802
|
+
nextIndex: this.nextContentIndex,
|
|
1803
|
+
toolCallSteps: [...this.toolCallStepIds].map(
|
|
1804
|
+
([toolCallId, stepId]) => ({ toolCallId, stepId })
|
|
1805
|
+
),
|
|
1806
|
+
steps,
|
|
1807
|
+
};
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
restoreRunStepResumeState(state?: t.RunStepResumeState): void {
|
|
1811
|
+
if (
|
|
1812
|
+
!isRunStepResumeState(state) ||
|
|
1813
|
+
this.contentData.length > 0 ||
|
|
1814
|
+
this.runStepStateRevision > 0
|
|
1815
|
+
) {
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
this.nextContentIndex = state.nextIndex;
|
|
1820
|
+
this.runStepStateRevision = state.revision;
|
|
1821
|
+
for (const { toolCallId, stepId } of state.toolCallSteps) {
|
|
1822
|
+
this.toolCallStepIds.set(toolCallId, stepId);
|
|
1823
|
+
}
|
|
1824
|
+
for (const entry of state.steps) {
|
|
1825
|
+
const runStep = structuredClone(entry.step);
|
|
1826
|
+
runStep.status = 'in_progress';
|
|
1827
|
+
this.nextContentIndex = Math.max(
|
|
1828
|
+
this.nextContentIndex,
|
|
1829
|
+
runStep.index + 1
|
|
1830
|
+
);
|
|
1831
|
+
const position = this.contentData.length;
|
|
1832
|
+
this.contentData.push(runStep);
|
|
1833
|
+
this.contentIndexMap.set(runStep.id, position);
|
|
1834
|
+
if (entry.pendingToolCallIds.length > 0) {
|
|
1835
|
+
const pending = new Set(entry.pendingToolCallIds);
|
|
1836
|
+
this.pendingToolCallsByStep.set(runStep.id, pending);
|
|
1837
|
+
}
|
|
1838
|
+
if (entry.latestCompletionAt != null) {
|
|
1839
|
+
this.latestCompletionByStep.set(
|
|
1840
|
+
runStep.id,
|
|
1841
|
+
entry.latestCompletionAt
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
if (entry.openMessageStep) {
|
|
1845
|
+
this.openMessageStepByAgent.set(runStep.agentId ?? '', runStep.id);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1740
1850
|
getRunStep(stepId: string): t.RunStep | undefined {
|
|
1741
1851
|
const index = this.contentIndexMap.get(stepId);
|
|
1742
1852
|
if (index !== undefined) {
|
|
@@ -1813,9 +1923,11 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1813
1923
|
* would mutate the wrong agent's step. Assigning the index at push time
|
|
1814
1924
|
* also supersedes whatever the caller computed before this await point.
|
|
1815
1925
|
*/
|
|
1816
|
-
runStep.index = this.contentData.length;
|
|
1926
|
+
runStep.index = Math.max(this.nextContentIndex, this.contentData.length);
|
|
1927
|
+
this.nextContentIndex = runStep.index + 1;
|
|
1928
|
+
const position = this.contentData.length;
|
|
1817
1929
|
this.contentData.push(runStep);
|
|
1818
|
-
this.contentIndexMap.set(runStep.id,
|
|
1930
|
+
this.contentIndexMap.set(runStep.id, position);
|
|
1819
1931
|
if (trackAsOpenMessageStep && runStep.type === StepTypes.MESSAGE_CREATION) {
|
|
1820
1932
|
this.openMessageStepByAgent.set(agentKey, runStep.id);
|
|
1821
1933
|
} else {
|
|
@@ -1846,6 +1958,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1846
1958
|
* absorb the latency of an arbitrarily slow predecessor handler.
|
|
1847
1959
|
*/
|
|
1848
1960
|
runStep.created_at = Date.now();
|
|
1961
|
+
this.runStepStateRevision += 1;
|
|
1849
1962
|
}
|
|
1850
1963
|
|
|
1851
1964
|
/**
|
|
@@ -1906,6 +2019,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1906
2019
|
closedEvent.stepIndex = runStep.stepIndex;
|
|
1907
2020
|
}
|
|
1908
2021
|
this.untrackRunStep(runStep);
|
|
2022
|
+
this.runStepStateRevision += 1;
|
|
1909
2023
|
|
|
1910
2024
|
const handler = this.handlerRegistry?.getHandler(
|
|
1911
2025
|
GraphEvents.ON_RUN_STEP_CLOSED
|
|
@@ -1950,10 +2064,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1950
2064
|
return;
|
|
1951
2065
|
}
|
|
1952
2066
|
const { toolCallId, metadata, at } = options ?? {};
|
|
2067
|
+
let lifecycleChanged = false;
|
|
1953
2068
|
if (at != null) {
|
|
1954
2069
|
const latest = this.latestCompletionByStep.get(stepId);
|
|
1955
2070
|
if (latest == null || at > latest) {
|
|
1956
2071
|
this.latestCompletionByStep.set(stepId, at);
|
|
2072
|
+
lifecycleChanged = true;
|
|
1957
2073
|
}
|
|
1958
2074
|
}
|
|
1959
2075
|
const closeAt = this.latestCompletionByStep.get(stepId) ?? at;
|
|
@@ -1963,9 +2079,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1963
2079
|
return;
|
|
1964
2080
|
}
|
|
1965
2081
|
if (toolCallId != null && toolCallId !== '') {
|
|
1966
|
-
pending.delete(toolCallId);
|
|
2082
|
+
lifecycleChanged = pending.delete(toolCallId) || lifecycleChanged;
|
|
1967
2083
|
}
|
|
1968
2084
|
if (pending.size > 0) {
|
|
2085
|
+
if (lifecycleChanged) {
|
|
2086
|
+
this.runStepStateRevision += 1;
|
|
2087
|
+
}
|
|
1969
2088
|
return;
|
|
1970
2089
|
}
|
|
1971
2090
|
await this.closeRunStep(stepId, 'completed', { metadata, at: closeAt });
|
|
@@ -2391,6 +2510,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2391
2510
|
agentLangfuse: agentContext?.langfuse,
|
|
2392
2511
|
eventDrivenMode: true,
|
|
2393
2512
|
sessions: this.sessions,
|
|
2513
|
+
codeSessionKey: agentContext?.codeSessionKey,
|
|
2394
2514
|
toolDefinitions: toolDefMap,
|
|
2395
2515
|
// `agentId` is the subagent-scope marker — set ONLY for child-run
|
|
2396
2516
|
// graphs (hooks fire for child scopes too, via the inherited
|
|
@@ -2417,6 +2537,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2417
2537
|
fileCheckpointer: this.getOrCreateFileCheckpointer(),
|
|
2418
2538
|
getBreakerSignal: (): AbortSignal => this.breakerAbort.signal,
|
|
2419
2539
|
getRunScope: (): RunBreakerScope => this.runScope,
|
|
2540
|
+
restoreRunStepResumeState: (state, config): void => {
|
|
2541
|
+
this.config = config;
|
|
2542
|
+
this.restoreRunStepResumeState(state);
|
|
2543
|
+
},
|
|
2544
|
+
createRunStepResumeState: (): t.RunStepResumeState =>
|
|
2545
|
+
this.createRunStepResumeState(),
|
|
2420
2546
|
errorHandler: (data, metadata): Promise<boolean> =>
|
|
2421
2547
|
StandardGraph.handleToolCallErrorStatic(this, data, metadata),
|
|
2422
2548
|
});
|
|
@@ -2471,6 +2597,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2471
2597
|
StandardGraph.handleToolCallErrorStatic(this, data, metadata),
|
|
2472
2598
|
toolRegistry: agentContext?.toolRegistry,
|
|
2473
2599
|
sessions: this.sessions,
|
|
2600
|
+
codeSessionKey: agentContext?.codeSessionKey,
|
|
2474
2601
|
toolExecution: this.toolExecution,
|
|
2475
2602
|
codeSessionToolNames: this.codeSessionToolNames,
|
|
2476
2603
|
interruptingToolNames: effectiveInterruptingToolNames,
|
|
@@ -2482,6 +2609,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
2482
2609
|
fileCheckpointer: this.getOrCreateFileCheckpointer(),
|
|
2483
2610
|
getBreakerSignal: (): AbortSignal => this.breakerAbort.signal,
|
|
2484
2611
|
getRunScope: (): RunBreakerScope => this.runScope,
|
|
2612
|
+
restoreRunStepResumeState: (state, config): void => {
|
|
2613
|
+
this.config = config;
|
|
2614
|
+
this.restoreRunStepResumeState(state);
|
|
2615
|
+
},
|
|
2616
|
+
createRunStepResumeState: (): t.RunStepResumeState =>
|
|
2617
|
+
this.createRunStepResumeState(),
|
|
2485
2618
|
});
|
|
2486
2619
|
this.registerCompiledToolNode(node);
|
|
2487
2620
|
return node;
|
|
@@ -4571,6 +4704,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4571
4704
|
};
|
|
4572
4705
|
}
|
|
4573
4706
|
|
|
4707
|
+
protected createRunStepStateAnnotation(): RunStepStateChannel {
|
|
4708
|
+
return buildRunStepStateAnnotation();
|
|
4709
|
+
}
|
|
4710
|
+
|
|
4574
4711
|
createAgentNode(agentId: string): t.CompiledAgentWorfklow {
|
|
4575
4712
|
const getConfig = (): RunnableConfig | undefined => this.config;
|
|
4576
4713
|
const agentContext = this.agentContexts.get(agentId);
|
|
@@ -4779,6 +4916,22 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4779
4916
|
const agentNode = `${AGENT}${agentId}` as const;
|
|
4780
4917
|
const toolNode = `${TOOLS}${agentId}` as const;
|
|
4781
4918
|
const summarizeNode = `${SUMMARIZE}${agentId}` as const;
|
|
4919
|
+
const callModel = this.createCallModel(agentId);
|
|
4920
|
+
const callTools = this.initializeTools({
|
|
4921
|
+
currentTools: agentContext.tools,
|
|
4922
|
+
currentToolMap: agentContext.toolMap,
|
|
4923
|
+
agentContext,
|
|
4924
|
+
});
|
|
4925
|
+
const invokeWithRunStepState = async (
|
|
4926
|
+
state: t.AgentSubgraphState,
|
|
4927
|
+
config: RunnableConfig | undefined,
|
|
4928
|
+
invoke: () => Promise<Partial<t.AgentSubgraphState>>
|
|
4929
|
+
): Promise<Partial<t.AgentSubgraphState>> => {
|
|
4930
|
+
this.config = config;
|
|
4931
|
+
this.restoreRunStepResumeState(state.runStepState);
|
|
4932
|
+
const result = await invoke();
|
|
4933
|
+
return { ...result, runStepState: this.createRunStepResumeState() };
|
|
4934
|
+
};
|
|
4782
4935
|
|
|
4783
4936
|
const routeMessage = (
|
|
4784
4937
|
state: t.AgentSubgraphState,
|
|
@@ -4815,6 +4968,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4815
4968
|
) => b,
|
|
4816
4969
|
default: () => undefined,
|
|
4817
4970
|
}),
|
|
4971
|
+
runStepState: this.createRunStepStateAnnotation(),
|
|
4818
4972
|
});
|
|
4819
4973
|
|
|
4820
4974
|
const readChargeCredits = ():
|
|
@@ -4833,14 +4987,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4833
4987
|
};
|
|
4834
4988
|
|
|
4835
4989
|
const workflow = new StateGraph(StateAnnotation)
|
|
4836
|
-
.addNode(agentNode,
|
|
4990
|
+
.addNode(agentNode, (state, config) =>
|
|
4991
|
+
invokeWithRunStepState(state, config, () => callModel(state, config))
|
|
4992
|
+
)
|
|
4837
4993
|
.addNode(
|
|
4838
4994
|
toolNode,
|
|
4839
|
-
|
|
4840
|
-
currentTools: agentContext.tools,
|
|
4841
|
-
currentToolMap: agentContext.toolMap,
|
|
4842
|
-
agentContext,
|
|
4843
|
-
})
|
|
4995
|
+
callTools
|
|
4844
4996
|
)
|
|
4845
4997
|
.addNode(
|
|
4846
4998
|
summarizeNode,
|
|
@@ -5019,6 +5171,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
5019
5171
|
},
|
|
5020
5172
|
default: () => [],
|
|
5021
5173
|
}),
|
|
5174
|
+
runStepState: this.createRunStepStateAnnotation(),
|
|
5022
5175
|
});
|
|
5023
5176
|
const workflow = new StateGraph(StateAnnotation)
|
|
5024
5177
|
.addNode(
|
|
@@ -5097,6 +5250,32 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
5097
5250
|
throw new Error('No config provided');
|
|
5098
5251
|
}
|
|
5099
5252
|
|
|
5253
|
+
if (stepDetails.type === StepTypes.TOOL_CALLS && stepDetails.tool_calls) {
|
|
5254
|
+
let replayStepId: string | undefined;
|
|
5255
|
+
let reusesOpenStep = stepDetails.tool_calls.length > 0;
|
|
5256
|
+
for (const toolCall of stepDetails.tool_calls) {
|
|
5257
|
+
const toolCallId = toolCall.id ?? '';
|
|
5258
|
+
const mappedStepId = this.toolCallStepIds.get(toolCallId);
|
|
5259
|
+
if (!toolCallId || mappedStepId == null) {
|
|
5260
|
+
reusesOpenStep = false;
|
|
5261
|
+
continue;
|
|
5262
|
+
}
|
|
5263
|
+
replayStepId ??= mappedStepId;
|
|
5264
|
+
if (mappedStepId !== replayStepId) {
|
|
5265
|
+
reusesOpenStep = false;
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
const replayStep =
|
|
5269
|
+
replayStepId == null ? undefined : this.getRunStep(replayStepId);
|
|
5270
|
+
if (
|
|
5271
|
+
reusesOpenStep &&
|
|
5272
|
+
replayStep != null &&
|
|
5273
|
+
(replayStep.status == null || replayStep.status === 'in_progress')
|
|
5274
|
+
) {
|
|
5275
|
+
return replayStep.id;
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5278
|
+
|
|
5100
5279
|
const [stepId, stepIndex] = this.generateStepId(stepKey);
|
|
5101
5280
|
if (stepDetails.type === StepTypes.TOOL_CALLS && stepDetails.tool_calls) {
|
|
5102
5281
|
let pendingToolCalls: Set<string> | undefined;
|
|
@@ -1036,6 +1036,7 @@ export class MultiAgentGraph extends StandardGraph {
|
|
|
1036
1036
|
reducer: (_current, update) => update,
|
|
1037
1037
|
default: () => undefined,
|
|
1038
1038
|
}),
|
|
1039
|
+
runStepState: this.createRunStepStateAnnotation(),
|
|
1039
1040
|
});
|
|
1040
1041
|
|
|
1041
1042
|
const builder = new StateGraph(StateAnnotation);
|