@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
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import type { ToolCall, ToolMessage } from '@langchain/core/messages/tool';
|
|
2
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
3
|
+
import type { ToolOutputReferenceState } from '@/tools/toolOutputReferences';
|
|
4
|
+
import type { ToolApprovalReplaySnapshot } from '@/hooks';
|
|
5
|
+
import type { ToolSessionContext } from '@/types';
|
|
6
|
+
|
|
7
|
+
export const SUBAGENT_RESUME_MANIFEST_CONFIG_KEY =
|
|
8
|
+
'__librechat_subagent_resume_manifest';
|
|
9
|
+
export const SUBAGENT_RESUME_ATTEMPT_CONFIG_KEY =
|
|
10
|
+
'__librechat_subagent_resume_attempt';
|
|
11
|
+
export const SUBAGENT_PARENT_BATCH_CONFIG_KEY =
|
|
12
|
+
'__librechat_subagent_parent_batch';
|
|
13
|
+
|
|
14
|
+
const SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY =
|
|
15
|
+
'__librechat_subagent_resume_manifest';
|
|
16
|
+
const SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY =
|
|
17
|
+
'__librechat_subagent_resume_payload';
|
|
18
|
+
const SUBAGENT_RESUME_WRAPPER_VERSION_KEY =
|
|
19
|
+
'__librechat_subagent_resume_wrapper';
|
|
20
|
+
const SUBAGENT_RESUME_PRIVATE_PAYLOAD_KEYS = [
|
|
21
|
+
SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY,
|
|
22
|
+
SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY,
|
|
23
|
+
SUBAGENT_RESUME_WRAPPER_VERSION_KEY,
|
|
24
|
+
] as const;
|
|
25
|
+
const MAX_RESUME_MANIFEST_DEPTH = 32;
|
|
26
|
+
|
|
27
|
+
export interface SubagentCheckpointReference {
|
|
28
|
+
threadId: string;
|
|
29
|
+
checkpointId: string;
|
|
30
|
+
checkpointNs: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SubagentToolCallStepReference {
|
|
34
|
+
toolCallId: string;
|
|
35
|
+
stepId: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface SubagentToolSessionReference {
|
|
39
|
+
toolName: string;
|
|
40
|
+
context: ToolSessionContext;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SubagentToolNodeResumeState {
|
|
44
|
+
stateKey: string;
|
|
45
|
+
toolUsageCounts: Array<{ toolName: string; count: number }>;
|
|
46
|
+
directPathTurns: Array<{ toolCallId: string; turn: number }>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface SubagentEagerToolUsageState {
|
|
50
|
+
agentId: string;
|
|
51
|
+
toolUsageCounts: Array<{ toolName: string; count: number }>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface SubagentGraphResumeState {
|
|
55
|
+
toolCallSteps: SubagentToolCallStepReference[];
|
|
56
|
+
toolSessions: SubagentToolSessionReference[];
|
|
57
|
+
toolNodes: SubagentToolNodeResumeState[];
|
|
58
|
+
eagerToolUsage: SubagentEagerToolUsageState[];
|
|
59
|
+
eagerToolSuppressions: string[];
|
|
60
|
+
toolOutputReferences?: ToolOutputReferenceState;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Private checkpoint payload linking a parent pause to an exact child state. */
|
|
64
|
+
export interface SubagentResumeExecution {
|
|
65
|
+
parentToolCallId: string;
|
|
66
|
+
childRunId: string;
|
|
67
|
+
/** Effective child type bound when this execution first ran. */
|
|
68
|
+
subagentType?: string;
|
|
69
|
+
/** Lazy child revision bound when this execution first resolved. */
|
|
70
|
+
configId?: string;
|
|
71
|
+
approvalExecutionScope: string;
|
|
72
|
+
checkpoints: SubagentCheckpointReference[];
|
|
73
|
+
graphState: SubagentGraphResumeState;
|
|
74
|
+
approvalReplays: ToolApprovalReplaySnapshot[];
|
|
75
|
+
descendant?: SubagentResumeManifest;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Private checkpoint payload linking a parent pause to every child state. */
|
|
79
|
+
export interface SubagentResumeManifest {
|
|
80
|
+
version: 1;
|
|
81
|
+
executions: SubagentResumeExecution[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
type PayloadWithSubagentResumeManifest = {
|
|
85
|
+
[SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY]?: unknown;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
type WrappedSubagentResumePayload = PayloadWithSubagentResumeManifest & {
|
|
89
|
+
[SUBAGENT_RESUME_WRAPPER_VERSION_KEY]: 1;
|
|
90
|
+
[SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY]: unknown;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
function isString(value: unknown): value is string {
|
|
94
|
+
return typeof value === 'string' && value.length > 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isNonnegativeInteger(value: unknown): value is number {
|
|
98
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isApprovalReplaySnapshot(
|
|
102
|
+
value: unknown
|
|
103
|
+
): value is ToolApprovalReplaySnapshot {
|
|
104
|
+
if (value == null || typeof value !== 'object') {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const snapshot = value as Partial<ToolApprovalReplaySnapshot>;
|
|
108
|
+
const key = snapshot.key;
|
|
109
|
+
const result = snapshot.result;
|
|
110
|
+
return (
|
|
111
|
+
key != null &&
|
|
112
|
+
isString(key.executionScope) &&
|
|
113
|
+
typeof key.agentId === 'string' &&
|
|
114
|
+
isString(key.toolUseId) &&
|
|
115
|
+
result != null &&
|
|
116
|
+
result.decision === 'ask' &&
|
|
117
|
+
Array.isArray(result.additionalContexts) &&
|
|
118
|
+
Array.isArray(result.injectedMessages) &&
|
|
119
|
+
Array.isArray(result.errors)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function isCheckpointReference(
|
|
124
|
+
value: unknown
|
|
125
|
+
): value is SubagentCheckpointReference {
|
|
126
|
+
if (value == null || typeof value !== 'object') {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
const checkpoint = value as Partial<SubagentCheckpointReference>;
|
|
130
|
+
return (
|
|
131
|
+
isString(checkpoint.threadId) &&
|
|
132
|
+
isString(checkpoint.checkpointId) &&
|
|
133
|
+
typeof checkpoint.checkpointNs === 'string'
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isToolCallStepReference(
|
|
138
|
+
value: unknown
|
|
139
|
+
): value is SubagentToolCallStepReference {
|
|
140
|
+
if (value == null || typeof value !== 'object') {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const reference = value as Partial<SubagentToolCallStepReference>;
|
|
144
|
+
return isString(reference.toolCallId) && isString(reference.stepId);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isToolSessionReference(
|
|
148
|
+
value: unknown
|
|
149
|
+
): value is SubagentToolSessionReference {
|
|
150
|
+
if (value == null || typeof value !== 'object') {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
const reference = value as Partial<SubagentToolSessionReference>;
|
|
154
|
+
const context = reference.context;
|
|
155
|
+
return (
|
|
156
|
+
isString(reference.toolName) &&
|
|
157
|
+
context != null &&
|
|
158
|
+
typeof context === 'object' &&
|
|
159
|
+
isString(context.session_id) &&
|
|
160
|
+
Number.isFinite(context.lastUpdated) &&
|
|
161
|
+
(context.files == null || Array.isArray(context.files))
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function isToolUsageCountReference(
|
|
166
|
+
value: unknown
|
|
167
|
+
): value is SubagentToolNodeResumeState['toolUsageCounts'][number] {
|
|
168
|
+
if (value == null || typeof value !== 'object') {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
const entry = value as Partial<
|
|
172
|
+
SubagentToolNodeResumeState['toolUsageCounts'][number]
|
|
173
|
+
>;
|
|
174
|
+
return isString(entry.toolName) && isNonnegativeInteger(entry.count);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function isDirectPathTurnReference(
|
|
178
|
+
value: unknown
|
|
179
|
+
): value is SubagentToolNodeResumeState['directPathTurns'][number] {
|
|
180
|
+
if (value == null || typeof value !== 'object') {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const entry = value as Partial<
|
|
184
|
+
SubagentToolNodeResumeState['directPathTurns'][number]
|
|
185
|
+
>;
|
|
186
|
+
return isString(entry.toolCallId) && isNonnegativeInteger(entry.turn);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function isToolNodeResumeState(
|
|
190
|
+
value: unknown
|
|
191
|
+
): value is SubagentToolNodeResumeState {
|
|
192
|
+
if (value == null || typeof value !== 'object') {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
const state = value as Partial<SubagentToolNodeResumeState>;
|
|
196
|
+
if (
|
|
197
|
+
!isString(state.stateKey) ||
|
|
198
|
+
!Array.isArray(state.toolUsageCounts) ||
|
|
199
|
+
!Array.isArray(state.directPathTurns)
|
|
200
|
+
) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
const validUsageCounts = state.toolUsageCounts.every(
|
|
204
|
+
isToolUsageCountReference
|
|
205
|
+
);
|
|
206
|
+
const validDirectTurns = state.directPathTurns.every(
|
|
207
|
+
isDirectPathTurnReference
|
|
208
|
+
);
|
|
209
|
+
if (!validUsageCounts || !validDirectTurns) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
const usageToolNames = new Set(
|
|
213
|
+
state.toolUsageCounts.map((entry) => entry.toolName)
|
|
214
|
+
);
|
|
215
|
+
const directToolCallIds = new Set(
|
|
216
|
+
state.directPathTurns.map((entry) => entry.toolCallId)
|
|
217
|
+
);
|
|
218
|
+
return (
|
|
219
|
+
usageToolNames.size === state.toolUsageCounts.length &&
|
|
220
|
+
directToolCallIds.size === state.directPathTurns.length
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function isEagerToolUsageState(
|
|
225
|
+
value: unknown
|
|
226
|
+
): value is SubagentEagerToolUsageState {
|
|
227
|
+
if (value == null || typeof value !== 'object') {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
const state = value as Partial<SubagentEagerToolUsageState>;
|
|
231
|
+
if (
|
|
232
|
+
typeof state.agentId !== 'string' ||
|
|
233
|
+
!Array.isArray(state.toolUsageCounts) ||
|
|
234
|
+
!state.toolUsageCounts.every(isToolUsageCountReference)
|
|
235
|
+
) {
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
const toolNames = new Set(
|
|
239
|
+
state.toolUsageCounts.map((entry) => entry.toolName)
|
|
240
|
+
);
|
|
241
|
+
return toolNames.size === state.toolUsageCounts.length;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function isToolOutputReferenceEntry(
|
|
245
|
+
value: unknown
|
|
246
|
+
): value is ToolOutputReferenceState['entries'][number] {
|
|
247
|
+
if (value == null || typeof value !== 'object') {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
const entry = value as Partial<ToolOutputReferenceState['entries'][number]>;
|
|
251
|
+
return isString(entry.key) && typeof entry.value === 'string';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function isToolOutputReferenceState(
|
|
255
|
+
value: unknown
|
|
256
|
+
): value is ToolOutputReferenceState {
|
|
257
|
+
if (value == null || typeof value !== 'object') {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
const state = value as Partial<ToolOutputReferenceState>;
|
|
261
|
+
if (
|
|
262
|
+
!Array.isArray(state.entries) ||
|
|
263
|
+
!state.entries.every(isToolOutputReferenceEntry) ||
|
|
264
|
+
!isNonnegativeInteger(state.turnCounter) ||
|
|
265
|
+
!Array.isArray(state.warnedNonStringTools) ||
|
|
266
|
+
!state.warnedNonStringTools.every(isString)
|
|
267
|
+
) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
const entryKeys = new Set(state.entries.map((entry) => entry.key));
|
|
271
|
+
const warnedTools = new Set(state.warnedNonStringTools);
|
|
272
|
+
return (
|
|
273
|
+
entryKeys.size === state.entries.length &&
|
|
274
|
+
warnedTools.size === state.warnedNonStringTools.length
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function isGraphResumeState(value: unknown): value is SubagentGraphResumeState {
|
|
279
|
+
if (value == null || typeof value !== 'object') {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
const state = value as Partial<SubagentGraphResumeState>;
|
|
283
|
+
if (
|
|
284
|
+
!Array.isArray(state.toolCallSteps) ||
|
|
285
|
+
!state.toolCallSteps.every(isToolCallStepReference) ||
|
|
286
|
+
!Array.isArray(state.toolSessions) ||
|
|
287
|
+
!state.toolSessions.every(isToolSessionReference) ||
|
|
288
|
+
!Array.isArray(state.toolNodes) ||
|
|
289
|
+
!state.toolNodes.every(isToolNodeResumeState) ||
|
|
290
|
+
!Array.isArray(state.eagerToolUsage) ||
|
|
291
|
+
!state.eagerToolUsage.every(isEagerToolUsageState) ||
|
|
292
|
+
!Array.isArray(state.eagerToolSuppressions) ||
|
|
293
|
+
!state.eagerToolSuppressions.every(isString) ||
|
|
294
|
+
(state.toolOutputReferences != null &&
|
|
295
|
+
!isToolOutputReferenceState(state.toolOutputReferences))
|
|
296
|
+
) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
const toolCallIds = new Set(
|
|
300
|
+
state.toolCallSteps.map((reference) => reference.toolCallId)
|
|
301
|
+
);
|
|
302
|
+
const toolNames = new Set(
|
|
303
|
+
state.toolSessions.map((reference) => reference.toolName)
|
|
304
|
+
);
|
|
305
|
+
const toolNodeKeys = new Set(state.toolNodes.map((node) => node.stateKey));
|
|
306
|
+
const eagerAgentIds = new Set(
|
|
307
|
+
state.eagerToolUsage.map((usage) => usage.agentId)
|
|
308
|
+
);
|
|
309
|
+
const eagerSuppressions = new Set(state.eagerToolSuppressions);
|
|
310
|
+
return (
|
|
311
|
+
toolCallIds.size === state.toolCallSteps.length &&
|
|
312
|
+
toolNames.size === state.toolSessions.length &&
|
|
313
|
+
toolNodeKeys.size === state.toolNodes.length &&
|
|
314
|
+
eagerAgentIds.size === state.eagerToolUsage.length &&
|
|
315
|
+
eagerSuppressions.size === state.eagerToolSuppressions.length
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function isSubagentResumeExecution(
|
|
320
|
+
value: unknown,
|
|
321
|
+
seen: Set<object>,
|
|
322
|
+
depth: number
|
|
323
|
+
): value is SubagentResumeExecution {
|
|
324
|
+
if (value == null || typeof value !== 'object') {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
const execution = value as Partial<SubagentResumeExecution>;
|
|
328
|
+
const childRunId = execution.childRunId;
|
|
329
|
+
const subagentType = execution.subagentType;
|
|
330
|
+
const configId = execution.configId;
|
|
331
|
+
const approvalExecutionScope = execution.approvalExecutionScope;
|
|
332
|
+
const checkpoints = execution.checkpoints;
|
|
333
|
+
const graphState = execution.graphState;
|
|
334
|
+
const approvalReplays = execution.approvalReplays;
|
|
335
|
+
if (
|
|
336
|
+
!isString(execution.parentToolCallId) ||
|
|
337
|
+
!isString(childRunId) ||
|
|
338
|
+
(subagentType != null && !isString(subagentType)) ||
|
|
339
|
+
(configId != null && !isString(configId)) ||
|
|
340
|
+
!isString(approvalExecutionScope) ||
|
|
341
|
+
!Array.isArray(checkpoints) ||
|
|
342
|
+
checkpoints.length === 0 ||
|
|
343
|
+
!checkpoints.every(isCheckpointReference) ||
|
|
344
|
+
!isGraphResumeState(graphState) ||
|
|
345
|
+
!Array.isArray(approvalReplays)
|
|
346
|
+
) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
const checkpointThreadId = checkpoints[0].threadId;
|
|
350
|
+
const checkpointNamespaces = new Set(
|
|
351
|
+
checkpoints.map((checkpoint) => checkpoint.checkpointNs)
|
|
352
|
+
);
|
|
353
|
+
const validApprovalReplays = approvalReplays.every(
|
|
354
|
+
(snapshot) =>
|
|
355
|
+
isApprovalReplaySnapshot(snapshot) &&
|
|
356
|
+
snapshot.key.executionScope === approvalExecutionScope
|
|
357
|
+
);
|
|
358
|
+
if (!validApprovalReplays) {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
const approvalKeys = new Set(
|
|
362
|
+
approvalReplays.map((snapshot) =>
|
|
363
|
+
JSON.stringify([
|
|
364
|
+
snapshot.key.executionScope,
|
|
365
|
+
snapshot.key.agentId,
|
|
366
|
+
snapshot.key.toolUseId,
|
|
367
|
+
])
|
|
368
|
+
)
|
|
369
|
+
);
|
|
370
|
+
return (
|
|
371
|
+
checkpoints.every(
|
|
372
|
+
(checkpoint) => checkpoint.threadId === checkpointThreadId
|
|
373
|
+
) &&
|
|
374
|
+
checkpointNamespaces.size === checkpoints.length &&
|
|
375
|
+
approvalKeys.size === approvalReplays.length &&
|
|
376
|
+
(execution.descendant == null ||
|
|
377
|
+
isSubagentResumeManifest(execution.descendant, seen, depth + 1))
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function isSubagentResumeManifest(
|
|
382
|
+
value: unknown,
|
|
383
|
+
seen: Set<object> = new Set(),
|
|
384
|
+
depth = 0
|
|
385
|
+
): value is SubagentResumeManifest {
|
|
386
|
+
if (
|
|
387
|
+
value == null ||
|
|
388
|
+
typeof value !== 'object' ||
|
|
389
|
+
depth > MAX_RESUME_MANIFEST_DEPTH ||
|
|
390
|
+
seen.has(value)
|
|
391
|
+
) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
seen.add(value);
|
|
395
|
+
const manifest = value as Partial<SubagentResumeManifest>;
|
|
396
|
+
if (
|
|
397
|
+
manifest.version !== 1 ||
|
|
398
|
+
!Array.isArray(manifest.executions) ||
|
|
399
|
+
manifest.executions.length === 0 ||
|
|
400
|
+
!manifest.executions.every((execution) =>
|
|
401
|
+
isSubagentResumeExecution(execution, seen, depth)
|
|
402
|
+
)
|
|
403
|
+
) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
const parentToolCallIds = new Set(
|
|
407
|
+
manifest.executions.map((execution) => execution.parentToolCallId)
|
|
408
|
+
);
|
|
409
|
+
return parentToolCallIds.size === manifest.executions.length;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export function getSubagentResumeManifest(
|
|
413
|
+
payload: unknown
|
|
414
|
+
): SubagentResumeManifest | undefined {
|
|
415
|
+
if (payload == null || typeof payload !== 'object') {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
if (
|
|
419
|
+
!Object.prototype.hasOwnProperty.call(
|
|
420
|
+
payload,
|
|
421
|
+
SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY
|
|
422
|
+
)
|
|
423
|
+
) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
const manifest = (payload as PayloadWithSubagentResumeManifest)[
|
|
427
|
+
SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY
|
|
428
|
+
];
|
|
429
|
+
return isSubagentResumeManifest(manifest) ? manifest : undefined;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export function requireValidSubagentResumeManifest(
|
|
433
|
+
payload: unknown
|
|
434
|
+
): SubagentResumeManifest | undefined {
|
|
435
|
+
if (
|
|
436
|
+
payload == null ||
|
|
437
|
+
typeof payload !== 'object' ||
|
|
438
|
+
!Object.prototype.hasOwnProperty.call(
|
|
439
|
+
payload,
|
|
440
|
+
SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY
|
|
441
|
+
)
|
|
442
|
+
) {
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
const manifest = getSubagentResumeManifest(payload);
|
|
446
|
+
if (manifest == null) {
|
|
447
|
+
throw new Error('Invalid subagent resume manifest.');
|
|
448
|
+
}
|
|
449
|
+
return manifest;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function canAttachSubagentResumeManifestInline(
|
|
453
|
+
payload: unknown
|
|
454
|
+
): payload is Record<string, unknown> {
|
|
455
|
+
if (
|
|
456
|
+
payload == null ||
|
|
457
|
+
typeof payload !== 'object' ||
|
|
458
|
+
Array.isArray(payload) ||
|
|
459
|
+
Object.getPrototypeOf(payload) !== Object.prototype
|
|
460
|
+
) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
return SUBAGENT_RESUME_PRIVATE_PAYLOAD_KEYS.every(
|
|
464
|
+
(key) => !Object.prototype.hasOwnProperty.call(payload, key)
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function isInlineSubagentResumePayload(
|
|
469
|
+
payload: unknown
|
|
470
|
+
): payload is PayloadWithSubagentResumeManifest & Record<string, unknown> {
|
|
471
|
+
return (
|
|
472
|
+
payload != null &&
|
|
473
|
+
typeof payload === 'object' &&
|
|
474
|
+
!Array.isArray(payload) &&
|
|
475
|
+
Object.getPrototypeOf(payload) === Object.prototype &&
|
|
476
|
+
!Object.prototype.hasOwnProperty.call(
|
|
477
|
+
payload,
|
|
478
|
+
SUBAGENT_RESUME_WRAPPER_VERSION_KEY
|
|
479
|
+
) &&
|
|
480
|
+
!Object.prototype.hasOwnProperty.call(
|
|
481
|
+
payload,
|
|
482
|
+
SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY
|
|
483
|
+
) &&
|
|
484
|
+
getSubagentResumeManifest(payload) != null
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export function attachSubagentResumeManifest(
|
|
489
|
+
payload: unknown,
|
|
490
|
+
manifest: SubagentResumeManifest
|
|
491
|
+
): object {
|
|
492
|
+
if (
|
|
493
|
+
isWrappedSubagentResumePayload(payload) ||
|
|
494
|
+
isInlineSubagentResumePayload(payload)
|
|
495
|
+
) {
|
|
496
|
+
return {
|
|
497
|
+
...payload,
|
|
498
|
+
[SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY]: manifest,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
if (!canAttachSubagentResumeManifestInline(payload)) {
|
|
502
|
+
return {
|
|
503
|
+
[SUBAGENT_RESUME_WRAPPER_VERSION_KEY]: 1,
|
|
504
|
+
[SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY]: payload,
|
|
505
|
+
[SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY]: manifest,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
...payload,
|
|
510
|
+
[SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY]: manifest,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export function stripSubagentResumeManifest(payload: unknown): unknown {
|
|
515
|
+
if (isWrappedSubagentResumePayload(payload)) {
|
|
516
|
+
return payload[SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY];
|
|
517
|
+
}
|
|
518
|
+
if (
|
|
519
|
+
payload == null ||
|
|
520
|
+
typeof payload !== 'object' ||
|
|
521
|
+
getSubagentResumeManifest(payload) == null
|
|
522
|
+
) {
|
|
523
|
+
return payload;
|
|
524
|
+
}
|
|
525
|
+
return Object.fromEntries(
|
|
526
|
+
Object.entries(payload).filter(
|
|
527
|
+
([key]) => key !== SUBAGENT_RESUME_MANIFEST_PAYLOAD_KEY
|
|
528
|
+
)
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function isWrappedSubagentResumePayload(
|
|
533
|
+
payload: unknown
|
|
534
|
+
): payload is WrappedSubagentResumePayload {
|
|
535
|
+
if (
|
|
536
|
+
payload == null ||
|
|
537
|
+
typeof payload !== 'object' ||
|
|
538
|
+
Array.isArray(payload) ||
|
|
539
|
+
Object.getPrototypeOf(payload) !== Object.prototype ||
|
|
540
|
+
Object.keys(payload).length !== SUBAGENT_RESUME_PRIVATE_PAYLOAD_KEYS.length
|
|
541
|
+
) {
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
544
|
+
const wrapper = payload as Partial<WrappedSubagentResumePayload>;
|
|
545
|
+
return (
|
|
546
|
+
wrapper[SUBAGENT_RESUME_WRAPPER_VERSION_KEY] === 1 &&
|
|
547
|
+
Object.prototype.hasOwnProperty.call(
|
|
548
|
+
wrapper,
|
|
549
|
+
SUBAGENT_RESUME_WRAPPED_PAYLOAD_KEY
|
|
550
|
+
) &&
|
|
551
|
+
getSubagentResumeManifest(wrapper) != null
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
export const SUBAGENT_REPLAY_CONTROLLER = Symbol.for(
|
|
556
|
+
'@librechat/agents/subagent-replay-controller'
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
export type SettledSubagentToolOutput = {
|
|
560
|
+
output: ToolMessage;
|
|
561
|
+
additionalContexts: string[];
|
|
562
|
+
resolvedArgs?: Record<string, unknown>;
|
|
563
|
+
referenceContent?: string;
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
export interface SubagentReplayController {
|
|
567
|
+
getResumeManifest?(
|
|
568
|
+
parentToolCallIds?: ReadonlySet<string>,
|
|
569
|
+
config?: RunnableConfig
|
|
570
|
+
): Promise<SubagentResumeManifest | undefined>;
|
|
571
|
+
getSettledOutput(
|
|
572
|
+
call: ToolCall,
|
|
573
|
+
config: RunnableConfig
|
|
574
|
+
): Promise<SettledSubagentToolOutput | undefined>;
|
|
575
|
+
persistSettledOutput(
|
|
576
|
+
call: ToolCall,
|
|
577
|
+
config: RunnableConfig,
|
|
578
|
+
settled: SettledSubagentToolOutput
|
|
579
|
+
): Promise<void>;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
export type ReplayableSubagentTool = {
|
|
583
|
+
[SUBAGENT_REPLAY_CONTROLLER]?: SubagentReplayController;
|
|
584
|
+
};
|