@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.
Files changed (204) hide show
  1. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  2. package/dist/cjs/graphs/Graph.cjs +165 -57
  3. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs +81 -33
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  6. package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs +14 -0
  7. package/dist/cjs/graphs/applyGraphRuntimeConfig.cjs.map +1 -0
  8. package/dist/cjs/graphs/createGraph.cjs +15 -0
  9. package/dist/cjs/graphs/createGraph.cjs.map +1 -0
  10. package/dist/cjs/graphs/index.cjs +1 -0
  11. package/dist/cjs/hooks/HookRegistry.cjs +83 -0
  12. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  13. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
  14. package/dist/cjs/hooks/executeHooks.cjs +60 -14
  15. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  16. package/dist/cjs/hooks/index.cjs.map +1 -1
  17. package/dist/cjs/hooks/types.cjs +2 -0
  18. package/dist/cjs/hooks/types.cjs.map +1 -1
  19. package/dist/cjs/llm/init.cjs +3 -3
  20. package/dist/cjs/llm/invoke.cjs +2 -2
  21. package/dist/cjs/main.cjs +34 -24
  22. package/dist/cjs/messages/format.cjs +40 -23
  23. package/dist/cjs/messages/format.cjs.map +1 -1
  24. package/dist/cjs/run.cjs +130 -53
  25. package/dist/cjs/run.cjs.map +1 -1
  26. package/dist/cjs/session/AgentSession.cjs +37 -2
  27. package/dist/cjs/session/AgentSession.cjs.map +1 -1
  28. package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
  29. package/dist/cjs/stream.cjs +1 -1
  30. package/dist/cjs/summarization/node.cjs +6 -3
  31. package/dist/cjs/summarization/node.cjs.map +1 -1
  32. package/dist/cjs/tools/BashExecutor.cjs +1 -1
  33. package/dist/cjs/tools/CodeExecutor.cjs +1 -1
  34. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +1 -1
  35. package/dist/cjs/tools/SubagentTool.cjs +4 -4
  36. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  37. package/dist/cjs/tools/ToolNode.cjs +321 -95
  38. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  39. package/dist/cjs/tools/ToolSearch.cjs +1 -1
  40. package/dist/cjs/tools/eagerEventExecution.cjs +1 -0
  41. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +3 -3
  42. package/dist/cjs/tools/local/LocalProgrammaticToolCalling.cjs +2 -2
  43. package/dist/cjs/tools/search/rerankers.cjs +154 -1
  44. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  45. package/dist/cjs/tools/search/tool.cjs +4 -1
  46. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  47. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs +601 -0
  48. package/dist/cjs/tools/subagent/SubagentExecutionRegistry.cjs.map +1 -0
  49. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1114 -233
  50. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  51. package/dist/cjs/tools/subagent/SubagentReplay.cjs +177 -0
  52. package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -0
  53. package/dist/cjs/tools/subagent/childGraphConfig.cjs +278 -0
  54. package/dist/cjs/tools/subagent/childGraphConfig.cjs.map +1 -0
  55. package/dist/cjs/tools/subagent/index.cjs +1 -0
  56. package/dist/cjs/tools/subagent/runtimeLimits.cjs +5 -0
  57. package/dist/cjs/tools/subagent/runtimeLimits.cjs.map +1 -0
  58. package/dist/cjs/tools/toolOutputReferences.cjs +20 -0
  59. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  60. package/dist/cjs/utils/index.cjs +2 -2
  61. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  62. package/dist/esm/graphs/Graph.mjs +165 -57
  63. package/dist/esm/graphs/Graph.mjs.map +1 -1
  64. package/dist/esm/graphs/MultiAgentGraph.mjs +81 -33
  65. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  66. package/dist/esm/graphs/applyGraphRuntimeConfig.mjs +14 -0
  67. package/dist/esm/graphs/applyGraphRuntimeConfig.mjs.map +1 -0
  68. package/dist/esm/graphs/createGraph.mjs +15 -0
  69. package/dist/esm/graphs/createGraph.mjs.map +1 -0
  70. package/dist/esm/graphs/index.mjs +1 -0
  71. package/dist/esm/hooks/HookRegistry.mjs +83 -0
  72. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  73. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
  74. package/dist/esm/hooks/executeHooks.mjs +60 -14
  75. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  76. package/dist/esm/hooks/index.mjs.map +1 -1
  77. package/dist/esm/hooks/types.mjs +2 -1
  78. package/dist/esm/hooks/types.mjs.map +1 -1
  79. package/dist/esm/llm/init.mjs +1 -1
  80. package/dist/esm/llm/invoke.mjs +2 -2
  81. package/dist/esm/main.mjs +21 -19
  82. package/dist/esm/messages/format.mjs +40 -23
  83. package/dist/esm/messages/format.mjs.map +1 -1
  84. package/dist/esm/run.mjs +131 -54
  85. package/dist/esm/run.mjs.map +1 -1
  86. package/dist/esm/session/AgentSession.mjs +37 -2
  87. package/dist/esm/session/AgentSession.mjs.map +1 -1
  88. package/dist/esm/session/JsonlSessionStore.mjs +2 -2
  89. package/dist/esm/stream.mjs +1 -1
  90. package/dist/esm/summarization/node.mjs +6 -3
  91. package/dist/esm/summarization/node.mjs.map +1 -1
  92. package/dist/esm/tools/BashExecutor.mjs +1 -1
  93. package/dist/esm/tools/CodeExecutor.mjs +1 -1
  94. package/dist/esm/tools/ProgrammaticToolCalling.mjs +1 -1
  95. package/dist/esm/tools/SubagentTool.mjs +4 -4
  96. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  97. package/dist/esm/tools/ToolNode.mjs +322 -96
  98. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  99. package/dist/esm/tools/ToolSearch.mjs +1 -1
  100. package/dist/esm/tools/eagerEventExecution.mjs +1 -1
  101. package/dist/esm/tools/local/LocalExecutionEngine.mjs +3 -3
  102. package/dist/esm/tools/local/LocalProgrammaticToolCalling.mjs +2 -2
  103. package/dist/esm/tools/search/rerankers.mjs +154 -1
  104. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  105. package/dist/esm/tools/search/tool.mjs +4 -1
  106. package/dist/esm/tools/search/tool.mjs.map +1 -1
  107. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs +597 -0
  108. package/dist/esm/tools/subagent/SubagentExecutionRegistry.mjs.map +1 -0
  109. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1114 -233
  110. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  111. package/dist/esm/tools/subagent/SubagentReplay.mjs +170 -0
  112. package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -0
  113. package/dist/esm/tools/subagent/childGraphConfig.mjs +272 -0
  114. package/dist/esm/tools/subagent/childGraphConfig.mjs.map +1 -0
  115. package/dist/esm/tools/subagent/index.mjs +1 -0
  116. package/dist/esm/tools/subagent/runtimeLimits.mjs +5 -0
  117. package/dist/esm/tools/subagent/runtimeLimits.mjs.map +1 -0
  118. package/dist/esm/tools/toolOutputReferences.mjs +20 -0
  119. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  120. package/dist/esm/utils/index.mjs +2 -2
  121. package/dist/types/agents/AgentContext.d.ts +1 -1
  122. package/dist/types/graphs/Graph.d.ts +22 -2
  123. package/dist/types/graphs/MultiAgentGraph.d.ts +7 -1
  124. package/dist/types/graphs/applyGraphRuntimeConfig.d.ts +3 -0
  125. package/dist/types/graphs/createGraph.d.ts +13 -0
  126. package/dist/types/graphs/graphFactory.d.ts +13 -0
  127. package/dist/types/graphs/index.d.ts +2 -0
  128. package/dist/types/hooks/HookRegistry.d.ts +10 -1
  129. package/dist/types/hooks/executeHooks.d.ts +5 -1
  130. package/dist/types/hooks/index.d.ts +2 -2
  131. package/dist/types/hooks/types.d.ts +12 -0
  132. package/dist/types/run.d.ts +6 -3
  133. package/dist/types/session/AgentSession.d.ts +1 -0
  134. package/dist/types/tools/SubagentTool.d.ts +1 -1
  135. package/dist/types/tools/ToolNode.d.ts +23 -15
  136. package/dist/types/tools/search/rerankers.d.ts +28 -0
  137. package/dist/types/tools/search/types.d.ts +38 -1
  138. package/dist/types/tools/subagent/SubagentExecutionRegistry.d.ts +171 -0
  139. package/dist/types/tools/subagent/SubagentExecutor.d.ts +70 -36
  140. package/dist/types/tools/subagent/SubagentReplay.d.ts +85 -0
  141. package/dist/types/tools/subagent/childGraphConfig.d.ts +37 -0
  142. package/dist/types/tools/subagent/index.d.ts +1 -1
  143. package/dist/types/tools/subagent/runtimeLimits.d.ts +4 -0
  144. package/dist/types/tools/toolOutputReferences.d.ts +12 -0
  145. package/dist/types/types/graph.d.ts +189 -24
  146. package/dist/types/types/hitl.d.ts +15 -0
  147. package/package.json +8 -2
  148. package/src/agents/AgentContext.ts +1 -1
  149. package/src/graphs/Graph.ts +349 -104
  150. package/src/graphs/MultiAgentGraph.ts +149 -47
  151. package/src/graphs/__tests__/Graph.breakerLifecycle.test.ts +48 -9
  152. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1 -1
  153. package/src/graphs/__tests__/Graph.subagentResumeState.test.ts +80 -0
  154. package/src/graphs/__tests__/MultiAgentGraph.test.ts +86 -0
  155. package/src/graphs/__tests__/composition.smoke.test.ts +152 -0
  156. package/src/graphs/__tests__/createGraph.test.ts +206 -0
  157. package/src/graphs/applyGraphRuntimeConfig.ts +25 -0
  158. package/src/graphs/createGraph.ts +32 -0
  159. package/src/graphs/graphFactory.ts +12 -0
  160. package/src/graphs/index.ts +2 -0
  161. package/src/hooks/HookRegistry.ts +151 -1
  162. package/src/hooks/__tests__/HookRegistry.test.ts +96 -0
  163. package/src/hooks/__tests__/executeHooks.test.ts +160 -0
  164. package/src/hooks/executeHooks.ts +133 -15
  165. package/src/hooks/index.ts +3 -1
  166. package/src/hooks/types.ts +16 -0
  167. package/src/messages/format.ts +54 -26
  168. package/src/messages/formatAgentMessages.reducer.test.ts +162 -0
  169. package/src/messages/formatAgentMessages.steer.test.ts +16 -11
  170. package/src/messages/formatAgentMessages.test.ts +7 -2
  171. package/src/run.ts +214 -56
  172. package/src/session/AgentSession.ts +52 -2
  173. package/src/session/__tests__/JsonlSessionStore.test.ts +53 -0
  174. package/src/specs/graph-subagent.live.test.ts +242 -0
  175. package/src/specs/graph-subagent.test.ts +322 -0
  176. package/src/specs/langfuse-routing.integration.test.ts +120 -1
  177. package/src/specs/subagent.test.ts +130 -4
  178. package/src/summarization/__tests__/node.test.ts +32 -14
  179. package/src/summarization/node.ts +15 -11
  180. package/src/tools/SubagentTool.ts +4 -4
  181. package/src/tools/ToolNode.ts +643 -157
  182. package/src/tools/__tests__/SubagentExecutor.test.ts +740 -15
  183. package/src/tools/__tests__/SubagentReplay.test.ts +329 -0
  184. package/src/tools/__tests__/ToolNode.breakerSignal.test.ts +208 -2
  185. package/src/tools/__tests__/directToolHITLResumeScope.test.ts +512 -2
  186. package/src/tools/__tests__/hitl.test.ts +234 -5
  187. package/src/tools/__tests__/subagentHooks.test.ts +1126 -61
  188. package/src/tools/__tests__/toolOutputReferences.test.ts +19 -2
  189. package/src/tools/search/rag-api-reranker.test.ts +891 -0
  190. package/src/tools/search/rerankers.ts +260 -0
  191. package/src/tools/search/tool.ts +6 -0
  192. package/src/tools/search/types.ts +45 -1
  193. package/src/tools/subagent/SubagentExecutionRegistry.ts +1159 -0
  194. package/src/tools/subagent/SubagentExecutor.ts +2232 -312
  195. package/src/tools/subagent/SubagentReplay.ts +584 -0
  196. package/src/tools/subagent/__tests__/SubagentExecutionRegistry.test.ts +637 -0
  197. package/src/tools/subagent/__tests__/SubagentExecutor.lazy.test.ts +3054 -0
  198. package/src/tools/subagent/__tests__/childGraphConfig.test.ts +521 -0
  199. package/src/tools/subagent/childGraphConfig.ts +694 -0
  200. package/src/tools/subagent/index.ts +6 -0
  201. package/src/tools/subagent/runtimeLimits.ts +7 -0
  202. package/src/tools/toolOutputReferences.ts +40 -1
  203. package/src/types/graph.ts +222 -24
  204. 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
+ };