@librechat/agents 3.1.67-dev.0 → 3.1.67-dev.4

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.
@@ -1,5 +1,7 @@
1
1
  import { nanoid } from 'nanoid';
2
+ import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
3
  import { HumanMessage } from '@langchain/core/messages';
4
+ import { GraphEvents, Callback } from '../../common/enum.mjs';
3
5
  import { executeHooks } from '../../hooks/executeHooks.mjs';
4
6
 
5
7
  const DEFAULT_MAX_TURNS = 25;
@@ -18,6 +20,7 @@ class SubagentExecutor {
18
20
  tokenCounter;
19
21
  maxDepth;
20
22
  createChildGraph;
23
+ resolveParentHandlerRegistry;
21
24
  constructor(options) {
22
25
  this.configs = options.configs;
23
26
  this.parentSignal = options.parentSignal;
@@ -27,9 +30,20 @@ class SubagentExecutor {
27
30
  this.tokenCounter = options.tokenCounter;
28
31
  this.maxDepth = options.maxDepth ?? 1;
29
32
  this.createChildGraph = options.createChildGraph;
33
+ const rawRegistry = options.parentHandlerRegistry;
34
+ if (typeof rawRegistry === 'function') {
35
+ this.resolveParentHandlerRegistry = rawRegistry;
36
+ }
37
+ else if (rawRegistry != null) {
38
+ this.resolveParentHandlerRegistry = () => rawRegistry;
39
+ }
40
+ }
41
+ /** Snapshot of the parent's registry at the moment a subagent is dispatched. */
42
+ getParentHandlerRegistry() {
43
+ return this.resolveParentHandlerRegistry?.();
30
44
  }
31
45
  async execute(params) {
32
- const { description, subagentType, threadId } = params;
46
+ const { description, subagentType, threadId, parentToolCallId } = params;
33
47
  const config = this.configs.get(subagentType);
34
48
  if (!config) {
35
49
  const available = [...this.configs.keys()].join(', ');
@@ -73,7 +87,20 @@ class SubagentExecutor {
73
87
  };
74
88
  }
75
89
  }
76
- const childInputs = buildChildInputs(config, childAgentId, this.maxDepth);
90
+ const parentRegistry = this.getParentHandlerRegistry();
91
+ const forwardingEnabled = parentRegistry != null;
92
+ /**
93
+ * Keep `toolDefinitions` only when the host has actually wired an
94
+ * `ON_TOOL_EXECUTE` handler. `Run` always constructs a `HandlerRegistry`,
95
+ * so treating any registry as "forwarding enabled" would leak
96
+ * `toolDefinitions` into children whose hosts cannot execute them — the
97
+ * child's `ToolNode` batch promise would hang forever with no handler to
98
+ * resolve/reject. Gating on the tool-execute handler preserves the
99
+ * recoverable "no tools" path for registry-but-no-handler configs.
100
+ */
101
+ const hasToolExecuteHandler = parentRegistry?.getHandler(GraphEvents.ON_TOOL_EXECUTE) != null;
102
+ const childInputs = buildChildInputs(config, childAgentId, this.maxDepth,
103
+ /* keepToolDefinitions */ hasToolExecuteHandler);
77
104
  const childRunId = `${this.parentRunId}_sub_${nanoid(8)}`;
78
105
  const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;
79
106
  const childGraph = this.createChildGraph({
@@ -82,28 +109,50 @@ class SubagentExecutor {
82
109
  agents: [childInputs],
83
110
  tokenCounter: this.tokenCounter,
84
111
  });
112
+ const forwarder = forwardingEnabled
113
+ ? this.createForwarderCallback({
114
+ parentRegistry: parentRegistry,
115
+ subagentType,
116
+ subagentAgentId: childAgentId,
117
+ childRunId,
118
+ parentToolCallId,
119
+ })
120
+ : undefined;
121
+ if (forwarder) {
122
+ await this.emitSubagentUpdate(parentRegistry, {
123
+ childRunId,
124
+ subagentType,
125
+ subagentAgentId: childAgentId,
126
+ parentToolCallId,
127
+ phase: 'start',
128
+ label: `Subagent "${subagentType}" started`,
129
+ });
130
+ }
85
131
  let result;
86
132
  try {
87
133
  const workflow = childGraph.createWorkflow();
88
134
  /**
89
- * Detach the child invocation from the parent's callback chain.
90
- * Without this, `streamEvents` in the parent's `Run.processStream`
91
- * captures events from the child graph's LLM calls (e.g.
92
- * `on_chat_model_stream` for the "researcher" agent) and delivers
93
- * them to the parent's handlers. The parent then tries to resolve
94
- * the child's agent ID in its own `agentContexts` map and throws
95
- * "No agent context found for agent ID …". Setting `callbacks: []`
96
- * overrides the inherited callbacks for this invoke; combined with
97
- * the child's own empty `handlerRegistry`/`hookRegistry`, the child
98
- * runs fully isolated.
135
+ * When `parentHandlerRegistry` is provided (forwarding mode), attach a
136
+ * lightweight callback that intercepts the child's `on_custom_event`
137
+ * dispatches and routes them to the parent's registry either as
138
+ * operational events (ON_TOOL_EXECUTE) or wrapped ON_SUBAGENT_UPDATE
139
+ * envelopes. Native LangChain streaming events (on_chat_model_stream,
140
+ * etc.) still do NOT propagate to the parent's outer streamEvents
141
+ * iterator the `callbacks` array REPLACES the inherited chain, so
142
+ * parent handlers won't receive child stream chunks and raise "No
143
+ * agent context found" lookups on the parent's agentContexts map.
144
+ *
145
+ * When no registry is provided (legacy isolation), `callbacks: []`
146
+ * fully detaches the child.
99
147
  *
100
148
  * `runName` gives the child a distinct LangSmith trace root (avoids
101
149
  * nested trace pollution).
102
150
  */
151
+ const callbacks = forwarder ? [forwarder] : [];
103
152
  result = await workflow.invoke({ messages: [new HumanMessage(description)] }, {
104
153
  recursionLimit: maxTurns * RECURSION_MULTIPLIER,
105
154
  signal: this.parentSignal,
106
- callbacks: [],
155
+ callbacks,
107
156
  runName: `subagent:${subagentType}`,
108
157
  configurable: {
109
158
  thread_id: childRunId,
@@ -111,9 +160,21 @@ class SubagentExecutor {
111
160
  });
112
161
  }
113
162
  catch (error) {
163
+ const errorMessage = truncateErrorMessage(error);
164
+ if (forwarder) {
165
+ await this.emitSubagentUpdate(parentRegistry, {
166
+ childRunId,
167
+ subagentType,
168
+ subagentAgentId: childAgentId,
169
+ parentToolCallId,
170
+ phase: 'error',
171
+ label: `Subagent "${subagentType}" errored: ${errorMessage}`,
172
+ data: { message: errorMessage },
173
+ });
174
+ }
114
175
  childGraph.clearHeavyState();
115
176
  return {
116
- content: `Subagent error: ${truncateErrorMessage(error)}`,
177
+ content: `Subagent error: ${errorMessage}`,
117
178
  messages: [],
118
179
  };
119
180
  }
@@ -141,9 +202,179 @@ class SubagentExecutor {
141
202
  /* SubagentStop is observational — swallow errors */
142
203
  });
143
204
  }
205
+ if (forwarder) {
206
+ await this.emitSubagentUpdate(parentRegistry, {
207
+ childRunId,
208
+ subagentType,
209
+ subagentAgentId: childAgentId,
210
+ parentToolCallId,
211
+ phase: 'stop',
212
+ label: `Subagent "${subagentType}" finished`,
213
+ });
214
+ }
144
215
  childGraph.clearHeavyState();
145
216
  return { content: filteredContent, messages: result.messages };
146
217
  }
218
+ /**
219
+ * Emits a single {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope through the
220
+ * parent's handler registry. Silent no-op when no parent registry is set.
221
+ * Errors are swallowed — update events are observational.
222
+ */
223
+ async emitSubagentUpdate(parentRegistry, args) {
224
+ const handler = parentRegistry.getHandler(GraphEvents.ON_SUBAGENT_UPDATE);
225
+ if (!handler) {
226
+ return;
227
+ }
228
+ const event = {
229
+ runId: this.parentRunId,
230
+ subagentRunId: args.childRunId,
231
+ subagentType: args.subagentType,
232
+ subagentAgentId: args.subagentAgentId,
233
+ parentAgentId: this.parentAgentId,
234
+ parentToolCallId: args.parentToolCallId,
235
+ phase: args.phase,
236
+ data: args.data,
237
+ label: args.label,
238
+ timestamp: new Date().toISOString(),
239
+ };
240
+ try {
241
+ await handler.handle(GraphEvents.ON_SUBAGENT_UPDATE, event);
242
+ }
243
+ catch {
244
+ /* observational — swallow */
245
+ }
246
+ }
247
+ /**
248
+ * Builds a BaseCallbackHandler that intercepts the child graph's custom
249
+ * events. Routing rules:
250
+ * - `ON_TOOL_EXECUTE` → forwarded as-is to the parent's ON_TOOL_EXECUTE
251
+ * handler (so event-driven tools work identically for child and parent).
252
+ * - `ON_RUN_STEP` / `ON_RUN_STEP_DELTA` / `ON_RUN_STEP_COMPLETED` /
253
+ * `ON_MESSAGE_DELTA` / `ON_REASONING_DELTA` → wrapped in a
254
+ * {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope with a human-readable
255
+ * label, delivered to the parent's subagent-update handler.
256
+ * - Everything else → ignored (keeps parent's UI scoped to the events it
257
+ * cares about; host apps can extend by registering more phases).
258
+ */
259
+ createForwarderCallback(args) {
260
+ const { parentRegistry, subagentType, subagentAgentId, childRunId, parentToolCallId, } = args;
261
+ const parentRunId = this.parentRunId;
262
+ const parentAgentId = this.parentAgentId;
263
+ const wrap = async (eventName, phase, data) => {
264
+ const handler = parentRegistry.getHandler(GraphEvents.ON_SUBAGENT_UPDATE);
265
+ if (!handler) {
266
+ return;
267
+ }
268
+ const event = {
269
+ runId: parentRunId,
270
+ subagentRunId: childRunId,
271
+ subagentType,
272
+ subagentAgentId,
273
+ parentAgentId,
274
+ parentToolCallId,
275
+ phase,
276
+ data,
277
+ label: summarizeEvent(eventName, data),
278
+ timestamp: new Date().toISOString(),
279
+ };
280
+ try {
281
+ await handler.handle(GraphEvents.ON_SUBAGENT_UPDATE, event);
282
+ }
283
+ catch {
284
+ /* observational — swallow */
285
+ }
286
+ };
287
+ const handler = BaseCallbackHandler.fromMethods({
288
+ [Callback.CUSTOM_EVENT]: async (eventName, data) => {
289
+ if (eventName === GraphEvents.ON_TOOL_EXECUTE) {
290
+ const toolHandler = parentRegistry.getHandler(GraphEvents.ON_TOOL_EXECUTE);
291
+ if (toolHandler) {
292
+ await toolHandler.handle(GraphEvents.ON_TOOL_EXECUTE, data);
293
+ }
294
+ /**
295
+ * We also surface a short notice in the subagent-update stream so
296
+ * the UI can show "calling <tool>" for each tool the child spawns.
297
+ */
298
+ await wrap(eventName, 'run_step', data);
299
+ return;
300
+ }
301
+ if (eventName === GraphEvents.ON_RUN_STEP) {
302
+ await wrap(eventName, 'run_step', data);
303
+ return;
304
+ }
305
+ if (eventName === GraphEvents.ON_RUN_STEP_DELTA) {
306
+ await wrap(eventName, 'run_step_delta', data);
307
+ return;
308
+ }
309
+ if (eventName === GraphEvents.ON_RUN_STEP_COMPLETED) {
310
+ await wrap(eventName, 'run_step_completed', data);
311
+ return;
312
+ }
313
+ if (eventName === GraphEvents.ON_MESSAGE_DELTA) {
314
+ await wrap(eventName, 'message_delta', data);
315
+ return;
316
+ }
317
+ if (eventName === GraphEvents.ON_REASONING_DELTA) {
318
+ await wrap(eventName, 'reasoning_delta', data);
319
+ return;
320
+ }
321
+ },
322
+ });
323
+ /**
324
+ * `awaitHandlers = true` is required so the child's `ToolNode` actually
325
+ * blocks on the parent's `ON_TOOL_EXECUTE` handler until it resolves
326
+ * the batch request. The same flag applies to observational events
327
+ * (message_delta, run_step, …), which means a slow
328
+ * `ON_SUBAGENT_UPDATE` handler on the host serializes the child
329
+ * stream. If host-side latency becomes a concern, a future
330
+ * refinement could split operational and observational events into
331
+ * separate callback handlers with distinct await semantics.
332
+ */
333
+ handler.awaitHandlers = true;
334
+ return handler;
335
+ }
336
+ }
337
+ /**
338
+ * Produces a short single-line label for an arbitrary forwarded child event.
339
+ * Used to populate {@link SubagentUpdateEvent.label} so the host UI can show
340
+ * a compact status ticker without parsing the raw payload.
341
+ */
342
+ function summarizeEvent(eventName, data) {
343
+ if (eventName === GraphEvents.ON_TOOL_EXECUTE) {
344
+ const req = data;
345
+ const names = (req.toolCalls ?? [])
346
+ .map((c) => c.name)
347
+ .filter((n) => typeof n === 'string');
348
+ return names.length > 0 ? `Calling ${names.join(', ')}` : 'Calling tool';
349
+ }
350
+ if (eventName === GraphEvents.ON_RUN_STEP) {
351
+ const step = data;
352
+ const detailType = step.stepDetails?.type ?? step.type ?? 'step';
353
+ if (detailType === 'tool_calls') {
354
+ const names = (step.stepDetails?.tool_calls ?? [])
355
+ .map((c) => c.name)
356
+ .filter((n) => typeof n === 'string');
357
+ return names.length > 0
358
+ ? `Using tool: ${names.join(', ')}`
359
+ : 'Planning tool call';
360
+ }
361
+ if (detailType === 'message_creation') {
362
+ return 'Thinking…';
363
+ }
364
+ return `Step: ${detailType}`;
365
+ }
366
+ if (eventName === GraphEvents.ON_RUN_STEP_COMPLETED) {
367
+ const step = data;
368
+ const tool = step.result?.tool_call;
369
+ if (tool?.name != null && tool.name !== '') {
370
+ return `Tool ${tool.name} complete`;
371
+ }
372
+ return 'Step complete';
373
+ }
374
+ if (eventName === GraphEvents.ON_MESSAGE_DELTA) {
375
+ return 'Streaming…';
376
+ }
377
+ return eventName;
147
378
  }
148
379
  /**
149
380
  * Walk messages from last to first, returning the text content of the most
@@ -215,11 +446,16 @@ function resolveSubagentConfigs(configs, parentContext) {
215
446
  }
216
447
  /**
217
448
  * Build child AgentInputs from a resolved config, stripping nesting and
218
- * event-driven fields. When `allowNested: true`, the child's
449
+ * (optionally) event-driven fields. When `allowNested: true`, the child's
219
450
  * `maxSubagentDepth` is decremented so that depth is consumed as the call
220
451
  * chain deepens across graph boundaries — the parent's executor-level check
221
452
  * alone cannot see into the child graph's separate executor.
222
453
  *
454
+ * When `keepToolDefinitions` is `true`, the child retains the parent's
455
+ * `toolDefinitions` so event-driven tools remain usable. This is only safe
456
+ * when the caller has wired a forwarder for `ON_TOOL_EXECUTE` to a
457
+ * registered handler — otherwise the child will hang on tool dispatch.
458
+ *
223
459
  * @remarks Advanced utility: exported primarily for testing and by
224
460
  * {@link SubagentExecutor}. Host applications configuring subagents should
225
461
  * not need to call this directly — it is invoked internally when a subagent
@@ -228,12 +464,25 @@ function resolveSubagentConfigs(configs, parentContext) {
228
464
  * mechanism that bounds nesting across graph boundaries; callers must
229
465
  * respect it.
230
466
  */
231
- function buildChildInputs(config, childAgentId, parentMaxDepth) {
467
+ function buildChildInputs(config, childAgentId, parentMaxDepth, keepToolDefinitions = false) {
232
468
  const { agentInputs } = config;
233
469
  const childInputs = {
234
470
  ...agentInputs,
235
471
  agentId: childAgentId,
236
- toolDefinitions: undefined,
472
+ toolDefinitions: keepToolDefinitions
473
+ ? agentInputs.toolDefinitions
474
+ : undefined,
475
+ /**
476
+ * Subagents run in an isolated context by contract. Parent-run-scoped
477
+ * fields that would otherwise survive the shallow-spread clone — the
478
+ * cross-run conversation summary and the prior-turn tool-discovery
479
+ * set — are cleared here so the child starts fresh. Host applications
480
+ * that want a subagent to see parent context must thread it in
481
+ * explicitly (e.g. via the `description` argument to the subagent
482
+ * tool), not via inherited state.
483
+ */
484
+ initialSummary: undefined,
485
+ discoveredTools: undefined,
237
486
  };
238
487
  if (config.allowNested === true) {
239
488
  childInputs.maxSubagentDepth = Math.max(0, parentMaxDepth - 1);
@@ -252,5 +501,5 @@ function truncateErrorMessage(error) {
252
501
  return `${message.slice(0, ERROR_MESSAGE_MAX_CHARS)}...`;
253
502
  }
254
503
 
255
- export { SubagentExecutor, buildChildInputs, filterSubagentResult, resolveSubagentConfigs };
504
+ export { SubagentExecutor, buildChildInputs, filterSubagentResult, resolveSubagentConfigs, summarizeEvent };
256
505
  //# sourceMappingURL=SubagentExecutor.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SubagentExecutor.mjs","sources":["../../../../src/tools/subagent/SubagentExecutor.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\nimport { HumanMessage } from '@langchain/core/messages';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type {\n AgentInputs,\n StandardGraphInput,\n ResolvedSubagentConfig,\n SubagentConfig,\n TokenCounter,\n} from '@/types';\nimport type { AggregatedHookResult, HookRegistry } from '@/hooks';\nimport type { AgentContext } from '@/agents/AgentContext';\nimport type { StandardGraph } from '@/graphs/Graph';\nimport { executeHooks } from '@/hooks';\n\nconst DEFAULT_MAX_TURNS = 25;\nconst RECURSION_MULTIPLIER = 3;\nconst ERROR_MESSAGE_MAX_CHARS = 200;\n\nconst HOOK_FALLBACK: AggregatedHookResult = Object.freeze({\n additionalContexts: [] as string[],\n errors: [] as string[],\n});\n\nexport type SubagentExecuteParams = {\n description: string;\n subagentType: string;\n threadId?: string;\n};\n\nexport type SubagentExecuteResult = {\n content: string;\n messages: BaseMessage[];\n};\n\n/**\n * Factory that constructs a child graph for subagent execution. Injected\n * rather than imported so that `SubagentExecutor` does not have a runtime\n * dependency on `StandardGraph` — this avoids a circular dependency between\n * `src/graphs/Graph.ts` and `src/tools/subagent/` that would otherwise break\n * Rollup's chunking under `preserveModules`.\n */\nexport type ChildGraphFactory = (input: StandardGraphInput) => StandardGraph;\n\nexport type SubagentExecutorOptions = {\n configs: Map<string, ResolvedSubagentConfig>;\n parentSignal?: AbortSignal;\n hookRegistry?: HookRegistry;\n parentRunId: string;\n parentAgentId?: string;\n tokenCounter?: TokenCounter;\n /** Remaining nesting budget. 0 or negative blocks execution. */\n maxDepth?: number;\n /**\n * Factory for constructing the isolated child graph. Callers pass\n * `(input) => new StandardGraph(input)` — injected to break a circular\n * module dependency.\n */\n createChildGraph: ChildGraphFactory;\n};\n\nexport class SubagentExecutor {\n private readonly configs: Map<string, ResolvedSubagentConfig>;\n private readonly parentSignal?: AbortSignal;\n private readonly hookRegistry?: HookRegistry;\n private readonly parentRunId: string;\n private readonly parentAgentId?: string;\n private readonly tokenCounter?: TokenCounter;\n private readonly maxDepth: number;\n private readonly createChildGraph: ChildGraphFactory;\n\n constructor(options: SubagentExecutorOptions) {\n this.configs = options.configs;\n this.parentSignal = options.parentSignal;\n this.hookRegistry = options.hookRegistry;\n this.parentRunId = options.parentRunId;\n this.parentAgentId = options.parentAgentId;\n this.tokenCounter = options.tokenCounter;\n this.maxDepth = options.maxDepth ?? 1;\n this.createChildGraph = options.createChildGraph;\n }\n\n async execute(params: SubagentExecuteParams): Promise<SubagentExecuteResult> {\n const { description, subagentType, threadId } = params;\n const config = this.configs.get(subagentType);\n\n if (!config) {\n const available = [...this.configs.keys()].join(', ');\n return {\n content: `Error: Unknown subagent type \"${subagentType}\". Available types: ${available}`,\n messages: [],\n };\n }\n\n if (this.maxDepth <= 0) {\n return {\n content: 'Error: Maximum subagent nesting depth exceeded.',\n messages: [],\n };\n }\n\n const childAgentId =\n config.agentInputs.agentId ||\n `${this.parentAgentId ?? 'agent'}_sub_${nanoid(8)}`;\n\n if (\n this.hookRegistry?.hasHookFor('SubagentStart', this.parentRunId) === true\n ) {\n const hookResult = await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'SubagentStart',\n runId: this.parentRunId,\n threadId,\n parentAgentId: this.parentAgentId,\n agentId: childAgentId,\n agentType: subagentType,\n inputs: [new HumanMessage(description)],\n },\n sessionId: this.parentRunId,\n matchQuery: subagentType,\n }).catch((): AggregatedHookResult => HOOK_FALLBACK);\n\n /**\n * `ask` is treated identically to `deny` in the subagent context:\n * subagents are non-interactive, so there is no prompt path for `ask`.\n * Both decisions block execution and return a \"Blocked\" tool result.\n */\n if (hookResult.decision === 'deny' || hookResult.decision === 'ask') {\n return {\n content: `Blocked: ${hookResult.reason ?? 'Blocked by hook'}`,\n messages: [],\n };\n }\n }\n\n const childInputs = buildChildInputs(config, childAgentId, this.maxDepth);\n const childRunId = `${this.parentRunId}_sub_${nanoid(8)}`;\n const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;\n\n const childGraph = this.createChildGraph({\n runId: childRunId,\n signal: this.parentSignal,\n agents: [childInputs],\n tokenCounter: this.tokenCounter,\n });\n\n let result: { messages: BaseMessage[] };\n try {\n const workflow = childGraph.createWorkflow();\n /**\n * Detach the child invocation from the parent's callback chain.\n * Without this, `streamEvents` in the parent's `Run.processStream`\n * captures events from the child graph's LLM calls (e.g.\n * `on_chat_model_stream` for the \"researcher\" agent) and delivers\n * them to the parent's handlers. The parent then tries to resolve\n * the child's agent ID in its own `agentContexts` map and throws\n * \"No agent context found for agent ID …\". Setting `callbacks: []`\n * overrides the inherited callbacks for this invoke; combined with\n * the child's own empty `handlerRegistry`/`hookRegistry`, the child\n * runs fully isolated.\n *\n * `runName` gives the child a distinct LangSmith trace root (avoids\n * nested trace pollution).\n */\n result = await workflow.invoke(\n { messages: [new HumanMessage(description)] },\n {\n recursionLimit: maxTurns * RECURSION_MULTIPLIER,\n signal: this.parentSignal,\n callbacks: [],\n runName: `subagent:${subagentType}`,\n configurable: {\n thread_id: childRunId,\n },\n }\n );\n } catch (error) {\n childGraph.clearHeavyState();\n return {\n content: `Subagent error: ${truncateErrorMessage(error)}`,\n messages: [],\n };\n }\n\n const filteredContent = filterSubagentResult(result.messages);\n\n if (\n this.hookRegistry?.hasHookFor('SubagentStop', this.parentRunId) === true\n ) {\n /**\n * Awaited (not fire-and-forget) for deterministic test synchronization\n * and consistency with PostCompact. The parent is already waiting on the\n * tool result, so the small extra latency is acceptable. Errors are\n * swallowed — SubagentStop is observational.\n */\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'SubagentStop',\n runId: this.parentRunId,\n threadId,\n agentId: childAgentId,\n agentType: subagentType,\n messages: result.messages,\n },\n sessionId: this.parentRunId,\n matchQuery: subagentType,\n }).catch(() => {\n /* SubagentStop is observational — swallow errors */\n });\n }\n\n childGraph.clearHeavyState();\n\n return { content: filteredContent, messages: result.messages };\n }\n}\n\n/**\n * Walk messages from last to first, returning the text content of the most\n * recent AIMessage that has any. Non-text blocks (tool_use, thinking,\n * redacted_thinking, tool_result) are stripped. If the last AIMessage is\n * pure tool_use (e.g. the subagent hit `maxTurns` mid-tool-call), the walk\n * continues to earlier AIMessages so partial progress is salvaged — this\n * matches Claude Code's behavior in `agentToolUtils.finalizeAgentTool`.\n * Returns \"Task completed\" only when no AIMessage in the history contains\n * any text.\n */\nexport function filterSubagentResult(messages: BaseMessage[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]._getType() !== 'ai') {\n continue;\n }\n\n const content = messages[i].content;\n\n if (typeof content === 'string') {\n if (content) return content;\n continue;\n }\n\n if (!Array.isArray(content)) {\n continue;\n }\n\n const textParts: string[] = [];\n for (const block of content) {\n if (typeof block === 'string') {\n textParts.push(block);\n } else if ('type' in block && block.type === 'text' && 'text' in block) {\n textParts.push(block.text as string);\n }\n }\n\n if (textParts.length > 0) {\n return textParts.join('\\n');\n }\n }\n\n return 'Task completed';\n}\n\n/**\n * Resolve self-spawn configs by filling in agentInputs from the parent context.\n * Returns configs with agentInputs guaranteed present. Throws on duplicate\n * `type` values to prevent silent config shadowing.\n */\nexport function resolveSubagentConfigs(\n configs: SubagentConfig[],\n parentContext: AgentContext\n): ResolvedSubagentConfig[] {\n const resolved = configs\n .map((config) => {\n if (config.agentInputs != null) {\n return config as ResolvedSubagentConfig;\n }\n if (config.self !== true || parentContext._sourceInputs == null) {\n return null;\n }\n return {\n ...config,\n agentInputs: { ...parentContext._sourceInputs },\n } as ResolvedSubagentConfig;\n })\n .filter((c): c is ResolvedSubagentConfig => c != null);\n\n const seenTypes = new Set<string>();\n for (const config of resolved) {\n if (seenTypes.has(config.type)) {\n throw new Error(\n `Duplicate subagent type \"${config.type}\". Each SubagentConfig must have a unique \"type\" field.`\n );\n }\n seenTypes.add(config.type);\n }\n\n return resolved;\n}\n\n/**\n * Build child AgentInputs from a resolved config, stripping nesting and\n * event-driven fields. When `allowNested: true`, the child's\n * `maxSubagentDepth` is decremented so that depth is consumed as the call\n * chain deepens across graph boundaries — the parent's executor-level check\n * alone cannot see into the child graph's separate executor.\n *\n * @remarks Advanced utility: exported primarily for testing and by\n * {@link SubagentExecutor}. Host applications configuring subagents should\n * not need to call this directly — it is invoked internally when a subagent\n * tool is dispatched. The depth-countdown contract (parent's `maxDepth` in,\n * child's decremented `maxSubagentDepth` on the returned inputs) is the\n * mechanism that bounds nesting across graph boundaries; callers must\n * respect it.\n */\nexport function buildChildInputs(\n config: ResolvedSubagentConfig,\n childAgentId: string,\n parentMaxDepth: number\n): AgentInputs {\n const { agentInputs } = config;\n const childInputs: AgentInputs = {\n ...agentInputs,\n agentId: childAgentId,\n toolDefinitions: undefined,\n };\n\n if (config.allowNested === true) {\n childInputs.maxSubagentDepth = Math.max(0, parentMaxDepth - 1);\n } else {\n childInputs.subagentConfigs = undefined;\n childInputs.maxSubagentDepth = undefined;\n }\n\n return childInputs;\n}\n\nfunction truncateErrorMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n if (message.length <= ERROR_MESSAGE_MAX_CHARS) {\n return message;\n }\n return `${message.slice(0, ERROR_MESSAGE_MAX_CHARS)}...`;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SubagentExecutor.mjs","sources":["../../../../src/tools/subagent/SubagentExecutor.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\nimport { BaseCallbackHandler } from '@langchain/core/callbacks/base';\nimport { HumanMessage } from '@langchain/core/messages';\nimport type { BaseMessage } from '@langchain/core/messages';\nimport type { Callbacks } from '@langchain/core/callbacks/manager';\nimport type {\n AgentInputs,\n StandardGraphInput,\n ResolvedSubagentConfig,\n SubagentConfig,\n SubagentUpdateEvent,\n SubagentUpdatePhase,\n ToolExecuteBatchRequest,\n TokenCounter,\n} from '@/types';\nimport type { AggregatedHookResult, HookRegistry } from '@/hooks';\nimport type { AgentContext } from '@/agents/AgentContext';\nimport type { StandardGraph } from '@/graphs/Graph';\nimport { GraphEvents, Callback } from '@/common';\nimport type { HandlerRegistry } from '@/events';\nimport { executeHooks } from '@/hooks';\n\nconst DEFAULT_MAX_TURNS = 25;\nconst RECURSION_MULTIPLIER = 3;\nconst ERROR_MESSAGE_MAX_CHARS = 200;\n\nconst HOOK_FALLBACK: AggregatedHookResult = Object.freeze({\n additionalContexts: [] as string[],\n errors: [] as string[],\n});\n\nexport type SubagentExecuteParams = {\n description: string;\n subagentType: string;\n threadId?: string;\n /**\n * Parent-side `tool_call_id` of the `subagent` tool invocation that\n * triggered this execution. Surfaced on {@link SubagentUpdateEvent} so\n * hosts can correlate child updates back to the originating tool call\n * without relying on event ordering heuristics.\n */\n parentToolCallId?: string;\n};\n\nexport type SubagentExecuteResult = {\n content: string;\n messages: BaseMessage[];\n};\n\n/**\n * Factory that constructs a child graph for subagent execution. Injected\n * rather than imported so that `SubagentExecutor` does not have a runtime\n * dependency on `StandardGraph` — this avoids a circular dependency between\n * `src/graphs/Graph.ts` and `src/tools/subagent/` that would otherwise break\n * Rollup's chunking under `preserveModules`.\n */\nexport type ChildGraphFactory = (input: StandardGraphInput) => StandardGraph;\n\nexport type SubagentExecutorOptions = {\n configs: Map<string, ResolvedSubagentConfig>;\n parentSignal?: AbortSignal;\n hookRegistry?: HookRegistry;\n parentRunId: string;\n parentAgentId?: string;\n tokenCounter?: TokenCounter;\n /** Remaining nesting budget. 0 or negative blocks execution. */\n maxDepth?: number;\n /**\n * Factory for constructing the isolated child graph. Callers pass\n * `(input) => new StandardGraph(input)` — injected to break a circular\n * module dependency.\n */\n createChildGraph: ChildGraphFactory;\n /**\n * Parent's event handler registry. When provided, child-graph events are\n * forwarded through this registry so hosts can:\n * (a) execute event-driven tools (`ON_TOOL_EXECUTE` routed to parent's handler),\n * (b) surface child activity to a UI via wrapped {@link GraphEvents.ON_SUBAGENT_UPDATE}.\n * When omitted, the child runs fully isolated (legacy behavior).\n *\n * Can be a direct `HandlerRegistry` or a zero-arg getter — use the getter\n * form when the registry is assigned to the graph AFTER the executor is\n * constructed (the current `Run.create` flow sets `handlerRegistry`\n * post-`createWorkflow`, so `createAgentNode` must capture lazily).\n */\n parentHandlerRegistry?: HandlerRegistry | (() => HandlerRegistry | undefined);\n};\n\nexport class SubagentExecutor {\n private readonly configs: Map<string, ResolvedSubagentConfig>;\n private readonly parentSignal?: AbortSignal;\n private readonly hookRegistry?: HookRegistry;\n private readonly parentRunId: string;\n private readonly parentAgentId?: string;\n private readonly tokenCounter?: TokenCounter;\n private readonly maxDepth: number;\n private readonly createChildGraph: ChildGraphFactory;\n private readonly resolveParentHandlerRegistry?: () =>\n | HandlerRegistry\n | undefined;\n\n constructor(options: SubagentExecutorOptions) {\n this.configs = options.configs;\n this.parentSignal = options.parentSignal;\n this.hookRegistry = options.hookRegistry;\n this.parentRunId = options.parentRunId;\n this.parentAgentId = options.parentAgentId;\n this.tokenCounter = options.tokenCounter;\n this.maxDepth = options.maxDepth ?? 1;\n this.createChildGraph = options.createChildGraph;\n const rawRegistry = options.parentHandlerRegistry;\n if (typeof rawRegistry === 'function') {\n this.resolveParentHandlerRegistry = rawRegistry;\n } else if (rawRegistry != null) {\n this.resolveParentHandlerRegistry = (): HandlerRegistry => rawRegistry;\n }\n }\n\n /** Snapshot of the parent's registry at the moment a subagent is dispatched. */\n private getParentHandlerRegistry(): HandlerRegistry | undefined {\n return this.resolveParentHandlerRegistry?.();\n }\n\n async execute(params: SubagentExecuteParams): Promise<SubagentExecuteResult> {\n const { description, subagentType, threadId, parentToolCallId } = params;\n const config = this.configs.get(subagentType);\n\n if (!config) {\n const available = [...this.configs.keys()].join(', ');\n return {\n content: `Error: Unknown subagent type \"${subagentType}\". Available types: ${available}`,\n messages: [],\n };\n }\n\n if (this.maxDepth <= 0) {\n return {\n content: 'Error: Maximum subagent nesting depth exceeded.',\n messages: [],\n };\n }\n\n const childAgentId =\n config.agentInputs.agentId ||\n `${this.parentAgentId ?? 'agent'}_sub_${nanoid(8)}`;\n\n if (\n this.hookRegistry?.hasHookFor('SubagentStart', this.parentRunId) === true\n ) {\n const hookResult = await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'SubagentStart',\n runId: this.parentRunId,\n threadId,\n parentAgentId: this.parentAgentId,\n agentId: childAgentId,\n agentType: subagentType,\n inputs: [new HumanMessage(description)],\n },\n sessionId: this.parentRunId,\n matchQuery: subagentType,\n }).catch((): AggregatedHookResult => HOOK_FALLBACK);\n\n /**\n * `ask` is treated identically to `deny` in the subagent context:\n * subagents are non-interactive, so there is no prompt path for `ask`.\n * Both decisions block execution and return a \"Blocked\" tool result.\n */\n if (hookResult.decision === 'deny' || hookResult.decision === 'ask') {\n return {\n content: `Blocked: ${hookResult.reason ?? 'Blocked by hook'}`,\n messages: [],\n };\n }\n }\n\n const parentRegistry = this.getParentHandlerRegistry();\n const forwardingEnabled = parentRegistry != null;\n /**\n * Keep `toolDefinitions` only when the host has actually wired an\n * `ON_TOOL_EXECUTE` handler. `Run` always constructs a `HandlerRegistry`,\n * so treating any registry as \"forwarding enabled\" would leak\n * `toolDefinitions` into children whose hosts cannot execute them — the\n * child's `ToolNode` batch promise would hang forever with no handler to\n * resolve/reject. Gating on the tool-execute handler preserves the\n * recoverable \"no tools\" path for registry-but-no-handler configs.\n */\n const hasToolExecuteHandler =\n parentRegistry?.getHandler(GraphEvents.ON_TOOL_EXECUTE) != null;\n const childInputs = buildChildInputs(\n config,\n childAgentId,\n this.maxDepth,\n /* keepToolDefinitions */ hasToolExecuteHandler\n );\n const childRunId = `${this.parentRunId}_sub_${nanoid(8)}`;\n const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;\n\n const childGraph = this.createChildGraph({\n runId: childRunId,\n signal: this.parentSignal,\n agents: [childInputs],\n tokenCounter: this.tokenCounter,\n });\n\n const forwarder = forwardingEnabled\n ? this.createForwarderCallback({\n parentRegistry: parentRegistry!,\n subagentType,\n subagentAgentId: childAgentId,\n childRunId,\n parentToolCallId,\n })\n : undefined;\n\n if (forwarder) {\n await this.emitSubagentUpdate(parentRegistry!, {\n childRunId,\n subagentType,\n subagentAgentId: childAgentId,\n parentToolCallId,\n phase: 'start',\n label: `Subagent \"${subagentType}\" started`,\n });\n }\n\n let result: { messages: BaseMessage[] };\n try {\n const workflow = childGraph.createWorkflow();\n /**\n * When `parentHandlerRegistry` is provided (forwarding mode), attach a\n * lightweight callback that intercepts the child's `on_custom_event`\n * dispatches and routes them to the parent's registry — either as\n * operational events (ON_TOOL_EXECUTE) or wrapped ON_SUBAGENT_UPDATE\n * envelopes. Native LangChain streaming events (on_chat_model_stream,\n * etc.) still do NOT propagate to the parent's outer streamEvents\n * iterator — the `callbacks` array REPLACES the inherited chain, so\n * parent handlers won't receive child stream chunks and raise \"No\n * agent context found\" lookups on the parent's agentContexts map.\n *\n * When no registry is provided (legacy isolation), `callbacks: []`\n * fully detaches the child.\n *\n * `runName` gives the child a distinct LangSmith trace root (avoids\n * nested trace pollution).\n */\n const callbacks: Callbacks = forwarder ? [forwarder] : [];\n result = await workflow.invoke(\n { messages: [new HumanMessage(description)] },\n {\n recursionLimit: maxTurns * RECURSION_MULTIPLIER,\n signal: this.parentSignal,\n callbacks,\n runName: `subagent:${subagentType}`,\n configurable: {\n thread_id: childRunId,\n },\n }\n );\n } catch (error) {\n const errorMessage = truncateErrorMessage(error);\n if (forwarder) {\n await this.emitSubagentUpdate(parentRegistry!, {\n childRunId,\n subagentType,\n subagentAgentId: childAgentId,\n parentToolCallId,\n phase: 'error',\n label: `Subagent \"${subagentType}\" errored: ${errorMessage}`,\n data: { message: errorMessage },\n });\n }\n childGraph.clearHeavyState();\n return {\n content: `Subagent error: ${errorMessage}`,\n messages: [],\n };\n }\n\n const filteredContent = filterSubagentResult(result.messages);\n\n if (\n this.hookRegistry?.hasHookFor('SubagentStop', this.parentRunId) === true\n ) {\n /**\n * Awaited (not fire-and-forget) for deterministic test synchronization\n * and consistency with PostCompact. The parent is already waiting on the\n * tool result, so the small extra latency is acceptable. Errors are\n * swallowed — SubagentStop is observational.\n */\n await executeHooks({\n registry: this.hookRegistry,\n input: {\n hook_event_name: 'SubagentStop',\n runId: this.parentRunId,\n threadId,\n agentId: childAgentId,\n agentType: subagentType,\n messages: result.messages,\n },\n sessionId: this.parentRunId,\n matchQuery: subagentType,\n }).catch(() => {\n /* SubagentStop is observational — swallow errors */\n });\n }\n\n if (forwarder) {\n await this.emitSubagentUpdate(parentRegistry!, {\n childRunId,\n subagentType,\n subagentAgentId: childAgentId,\n parentToolCallId,\n phase: 'stop',\n label: `Subagent \"${subagentType}\" finished`,\n });\n }\n\n childGraph.clearHeavyState();\n\n return { content: filteredContent, messages: result.messages };\n }\n\n /**\n * Emits a single {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope through the\n * parent's handler registry. Silent no-op when no parent registry is set.\n * Errors are swallowed — update events are observational.\n */\n private async emitSubagentUpdate(\n parentRegistry: HandlerRegistry,\n args: {\n childRunId: string;\n subagentType: string;\n subagentAgentId: string;\n parentToolCallId?: string;\n phase: SubagentUpdatePhase;\n data?: unknown;\n label?: string;\n }\n ): Promise<void> {\n const handler = parentRegistry.getHandler(GraphEvents.ON_SUBAGENT_UPDATE);\n if (!handler) {\n return;\n }\n const event: SubagentUpdateEvent = {\n runId: this.parentRunId,\n subagentRunId: args.childRunId,\n subagentType: args.subagentType,\n subagentAgentId: args.subagentAgentId,\n parentAgentId: this.parentAgentId,\n parentToolCallId: args.parentToolCallId,\n phase: args.phase,\n data: args.data,\n label: args.label,\n timestamp: new Date().toISOString(),\n };\n try {\n await handler.handle(GraphEvents.ON_SUBAGENT_UPDATE, event);\n } catch {\n /* observational — swallow */\n }\n }\n\n /**\n * Builds a BaseCallbackHandler that intercepts the child graph's custom\n * events. Routing rules:\n * - `ON_TOOL_EXECUTE` → forwarded as-is to the parent's ON_TOOL_EXECUTE\n * handler (so event-driven tools work identically for child and parent).\n * - `ON_RUN_STEP` / `ON_RUN_STEP_DELTA` / `ON_RUN_STEP_COMPLETED` /\n * `ON_MESSAGE_DELTA` / `ON_REASONING_DELTA` → wrapped in a\n * {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope with a human-readable\n * label, delivered to the parent's subagent-update handler.\n * - Everything else → ignored (keeps parent's UI scoped to the events it\n * cares about; host apps can extend by registering more phases).\n */\n private createForwarderCallback(args: {\n parentRegistry: HandlerRegistry;\n subagentType: string;\n subagentAgentId: string;\n childRunId: string;\n parentToolCallId?: string;\n }): BaseCallbackHandler {\n const {\n parentRegistry,\n subagentType,\n subagentAgentId,\n childRunId,\n parentToolCallId,\n } = args;\n const parentRunId = this.parentRunId;\n const parentAgentId = this.parentAgentId;\n\n const wrap = async (\n eventName: string,\n phase: SubagentUpdatePhase,\n data: unknown\n ): Promise<void> => {\n const handler = parentRegistry.getHandler(GraphEvents.ON_SUBAGENT_UPDATE);\n if (!handler) {\n return;\n }\n const event: SubagentUpdateEvent = {\n runId: parentRunId,\n subagentRunId: childRunId,\n subagentType,\n subagentAgentId,\n parentAgentId,\n parentToolCallId,\n phase,\n data,\n label: summarizeEvent(eventName, data),\n timestamp: new Date().toISOString(),\n };\n try {\n await handler.handle(GraphEvents.ON_SUBAGENT_UPDATE, event);\n } catch {\n /* observational — swallow */\n }\n };\n\n const handler = BaseCallbackHandler.fromMethods({\n [Callback.CUSTOM_EVENT]: async (\n eventName: string,\n data: unknown\n ): Promise<void> => {\n if (eventName === GraphEvents.ON_TOOL_EXECUTE) {\n const toolHandler = parentRegistry.getHandler(\n GraphEvents.ON_TOOL_EXECUTE\n );\n if (toolHandler) {\n await toolHandler.handle(\n GraphEvents.ON_TOOL_EXECUTE,\n data as ToolExecuteBatchRequest\n );\n }\n /**\n * We also surface a short notice in the subagent-update stream so\n * the UI can show \"calling <tool>\" for each tool the child spawns.\n */\n await wrap(eventName, 'run_step', data);\n return;\n }\n\n if (eventName === GraphEvents.ON_RUN_STEP) {\n await wrap(eventName, 'run_step', data);\n return;\n }\n if (eventName === GraphEvents.ON_RUN_STEP_DELTA) {\n await wrap(eventName, 'run_step_delta', data);\n return;\n }\n if (eventName === GraphEvents.ON_RUN_STEP_COMPLETED) {\n await wrap(eventName, 'run_step_completed', data);\n return;\n }\n if (eventName === GraphEvents.ON_MESSAGE_DELTA) {\n await wrap(eventName, 'message_delta', data);\n return;\n }\n if (eventName === GraphEvents.ON_REASONING_DELTA) {\n await wrap(eventName, 'reasoning_delta', data);\n return;\n }\n },\n });\n /**\n * `awaitHandlers = true` is required so the child's `ToolNode` actually\n * blocks on the parent's `ON_TOOL_EXECUTE` handler until it resolves\n * the batch request. The same flag applies to observational events\n * (message_delta, run_step, …), which means a slow\n * `ON_SUBAGENT_UPDATE` handler on the host serializes the child\n * stream. If host-side latency becomes a concern, a future\n * refinement could split operational and observational events into\n * separate callback handlers with distinct await semantics.\n */\n handler.awaitHandlers = true;\n return handler;\n }\n}\n\n/**\n * Produces a short single-line label for an arbitrary forwarded child event.\n * Used to populate {@link SubagentUpdateEvent.label} so the host UI can show\n * a compact status ticker without parsing the raw payload.\n */\nexport function summarizeEvent(eventName: string, data: unknown): string {\n if (eventName === GraphEvents.ON_TOOL_EXECUTE) {\n const req = data as { toolCalls?: Array<{ name?: string }> };\n const names = (req.toolCalls ?? [])\n .map((c) => c.name)\n .filter((n): n is string => typeof n === 'string');\n return names.length > 0 ? `Calling ${names.join(', ')}` : 'Calling tool';\n }\n if (eventName === GraphEvents.ON_RUN_STEP) {\n const step = data as {\n type?: string;\n stepDetails?: { type?: string; tool_calls?: Array<{ name?: string }> };\n };\n const detailType = step.stepDetails?.type ?? step.type ?? 'step';\n if (detailType === 'tool_calls') {\n const names = (step.stepDetails?.tool_calls ?? [])\n .map((c) => c.name)\n .filter((n): n is string => typeof n === 'string');\n return names.length > 0\n ? `Using tool: ${names.join(', ')}`\n : 'Planning tool call';\n }\n if (detailType === 'message_creation') {\n return 'Thinking…';\n }\n return `Step: ${detailType}`;\n }\n if (eventName === GraphEvents.ON_RUN_STEP_COMPLETED) {\n const step = data as {\n result?: {\n type?: string;\n tool_call?: { name?: string; output?: string };\n };\n };\n const tool = step.result?.tool_call;\n if (tool?.name != null && tool.name !== '') {\n return `Tool ${tool.name} complete`;\n }\n return 'Step complete';\n }\n if (eventName === GraphEvents.ON_MESSAGE_DELTA) {\n return 'Streaming…';\n }\n return eventName;\n}\n\n/**\n * Walk messages from last to first, returning the text content of the most\n * recent AIMessage that has any. Non-text blocks (tool_use, thinking,\n * redacted_thinking, tool_result) are stripped. If the last AIMessage is\n * pure tool_use (e.g. the subagent hit `maxTurns` mid-tool-call), the walk\n * continues to earlier AIMessages so partial progress is salvaged — this\n * matches Claude Code's behavior in `agentToolUtils.finalizeAgentTool`.\n * Returns \"Task completed\" only when no AIMessage in the history contains\n * any text.\n */\nexport function filterSubagentResult(messages: BaseMessage[]): string {\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]._getType() !== 'ai') {\n continue;\n }\n\n const content = messages[i].content;\n\n if (typeof content === 'string') {\n if (content) return content;\n continue;\n }\n\n if (!Array.isArray(content)) {\n continue;\n }\n\n const textParts: string[] = [];\n for (const block of content) {\n if (typeof block === 'string') {\n textParts.push(block);\n } else if ('type' in block && block.type === 'text' && 'text' in block) {\n textParts.push(block.text as string);\n }\n }\n\n if (textParts.length > 0) {\n return textParts.join('\\n');\n }\n }\n\n return 'Task completed';\n}\n\n/**\n * Resolve self-spawn configs by filling in agentInputs from the parent context.\n * Returns configs with agentInputs guaranteed present. Throws on duplicate\n * `type` values to prevent silent config shadowing.\n */\nexport function resolveSubagentConfigs(\n configs: SubagentConfig[],\n parentContext: AgentContext\n): ResolvedSubagentConfig[] {\n const resolved = configs\n .map((config) => {\n if (config.agentInputs != null) {\n return config as ResolvedSubagentConfig;\n }\n if (config.self !== true || parentContext._sourceInputs == null) {\n return null;\n }\n return {\n ...config,\n agentInputs: { ...parentContext._sourceInputs },\n } as ResolvedSubagentConfig;\n })\n .filter((c): c is ResolvedSubagentConfig => c != null);\n\n const seenTypes = new Set<string>();\n for (const config of resolved) {\n if (seenTypes.has(config.type)) {\n throw new Error(\n `Duplicate subagent type \"${config.type}\". Each SubagentConfig must have a unique \"type\" field.`\n );\n }\n seenTypes.add(config.type);\n }\n\n return resolved;\n}\n\n/**\n * Build child AgentInputs from a resolved config, stripping nesting and\n * (optionally) event-driven fields. When `allowNested: true`, the child's\n * `maxSubagentDepth` is decremented so that depth is consumed as the call\n * chain deepens across graph boundaries — the parent's executor-level check\n * alone cannot see into the child graph's separate executor.\n *\n * When `keepToolDefinitions` is `true`, the child retains the parent's\n * `toolDefinitions` so event-driven tools remain usable. This is only safe\n * when the caller has wired a forwarder for `ON_TOOL_EXECUTE` to a\n * registered handler — otherwise the child will hang on tool dispatch.\n *\n * @remarks Advanced utility: exported primarily for testing and by\n * {@link SubagentExecutor}. Host applications configuring subagents should\n * not need to call this directly — it is invoked internally when a subagent\n * tool is dispatched. The depth-countdown contract (parent's `maxDepth` in,\n * child's decremented `maxSubagentDepth` on the returned inputs) is the\n * mechanism that bounds nesting across graph boundaries; callers must\n * respect it.\n */\nexport function buildChildInputs(\n config: ResolvedSubagentConfig,\n childAgentId: string,\n parentMaxDepth: number,\n keepToolDefinitions: boolean = false\n): AgentInputs {\n const { agentInputs } = config;\n const childInputs: AgentInputs = {\n ...agentInputs,\n agentId: childAgentId,\n toolDefinitions: keepToolDefinitions\n ? agentInputs.toolDefinitions\n : undefined,\n /**\n * Subagents run in an isolated context by contract. Parent-run-scoped\n * fields that would otherwise survive the shallow-spread clone — the\n * cross-run conversation summary and the prior-turn tool-discovery\n * set — are cleared here so the child starts fresh. Host applications\n * that want a subagent to see parent context must thread it in\n * explicitly (e.g. via the `description` argument to the subagent\n * tool), not via inherited state.\n */\n initialSummary: undefined,\n discoveredTools: undefined,\n };\n\n if (config.allowNested === true) {\n childInputs.maxSubagentDepth = Math.max(0, parentMaxDepth - 1);\n } else {\n childInputs.subagentConfigs = undefined;\n childInputs.maxSubagentDepth = undefined;\n }\n\n return childInputs;\n}\n\nfunction truncateErrorMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n if (message.length <= ERROR_MESSAGE_MAX_CHARS) {\n return message;\n }\n return `${message.slice(0, ERROR_MESSAGE_MAX_CHARS)}...`;\n}\n"],"names":[],"mappings":"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"}
@@ -25,6 +25,8 @@ export declare enum GraphEvents {
25
25
  ON_SUMMARIZE_DELTA = "on_summarize_delta",
26
26
  /** [Custom] Emitted when the summarize node completes with the final summary */
27
27
  ON_SUMMARIZE_COMPLETE = "on_summarize_complete",
28
+ /** [Custom] Progress update from a running subagent (wraps child-graph events so hosts can display activity separately from parent). */
29
+ ON_SUBAGENT_UPDATE = "on_subagent_update",
28
30
  /** [Custom] Diagnostic logging event for context management observability */
29
31
  ON_AGENT_LOG = "on_agent_log",
30
32
  /** Custom event, emitted by system */
@@ -3,10 +3,18 @@ import type { AgentInputs, StandardGraphInput, ResolvedSubagentConfig, SubagentC
3
3
  import type { HookRegistry } from '@/hooks';
4
4
  import type { AgentContext } from '@/agents/AgentContext';
5
5
  import type { StandardGraph } from '@/graphs/Graph';
6
+ import type { HandlerRegistry } from '@/events';
6
7
  export type SubagentExecuteParams = {
7
8
  description: string;
8
9
  subagentType: string;
9
10
  threadId?: string;
11
+ /**
12
+ * Parent-side `tool_call_id` of the `subagent` tool invocation that
13
+ * triggered this execution. Surfaced on {@link SubagentUpdateEvent} so
14
+ * hosts can correlate child updates back to the originating tool call
15
+ * without relying on event ordering heuristics.
16
+ */
17
+ parentToolCallId?: string;
10
18
  };
11
19
  export type SubagentExecuteResult = {
12
20
  content: string;
@@ -35,6 +43,19 @@ export type SubagentExecutorOptions = {
35
43
  * module dependency.
36
44
  */
37
45
  createChildGraph: ChildGraphFactory;
46
+ /**
47
+ * Parent's event handler registry. When provided, child-graph events are
48
+ * forwarded through this registry so hosts can:
49
+ * (a) execute event-driven tools (`ON_TOOL_EXECUTE` routed to parent's handler),
50
+ * (b) surface child activity to a UI via wrapped {@link GraphEvents.ON_SUBAGENT_UPDATE}.
51
+ * When omitted, the child runs fully isolated (legacy behavior).
52
+ *
53
+ * Can be a direct `HandlerRegistry` or a zero-arg getter — use the getter
54
+ * form when the registry is assigned to the graph AFTER the executor is
55
+ * constructed (the current `Run.create` flow sets `handlerRegistry`
56
+ * post-`createWorkflow`, so `createAgentNode` must capture lazily).
57
+ */
58
+ parentHandlerRegistry?: HandlerRegistry | (() => HandlerRegistry | undefined);
38
59
  };
39
60
  export declare class SubagentExecutor {
40
61
  private readonly configs;
@@ -45,9 +66,37 @@ export declare class SubagentExecutor {
45
66
  private readonly tokenCounter?;
46
67
  private readonly maxDepth;
47
68
  private readonly createChildGraph;
69
+ private readonly resolveParentHandlerRegistry?;
48
70
  constructor(options: SubagentExecutorOptions);
71
+ /** Snapshot of the parent's registry at the moment a subagent is dispatched. */
72
+ private getParentHandlerRegistry;
49
73
  execute(params: SubagentExecuteParams): Promise<SubagentExecuteResult>;
74
+ /**
75
+ * Emits a single {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope through the
76
+ * parent's handler registry. Silent no-op when no parent registry is set.
77
+ * Errors are swallowed — update events are observational.
78
+ */
79
+ private emitSubagentUpdate;
80
+ /**
81
+ * Builds a BaseCallbackHandler that intercepts the child graph's custom
82
+ * events. Routing rules:
83
+ * - `ON_TOOL_EXECUTE` → forwarded as-is to the parent's ON_TOOL_EXECUTE
84
+ * handler (so event-driven tools work identically for child and parent).
85
+ * - `ON_RUN_STEP` / `ON_RUN_STEP_DELTA` / `ON_RUN_STEP_COMPLETED` /
86
+ * `ON_MESSAGE_DELTA` / `ON_REASONING_DELTA` → wrapped in a
87
+ * {@link GraphEvents.ON_SUBAGENT_UPDATE} envelope with a human-readable
88
+ * label, delivered to the parent's subagent-update handler.
89
+ * - Everything else → ignored (keeps parent's UI scoped to the events it
90
+ * cares about; host apps can extend by registering more phases).
91
+ */
92
+ private createForwarderCallback;
50
93
  }
94
+ /**
95
+ * Produces a short single-line label for an arbitrary forwarded child event.
96
+ * Used to populate {@link SubagentUpdateEvent.label} so the host UI can show
97
+ * a compact status ticker without parsing the raw payload.
98
+ */
99
+ export declare function summarizeEvent(eventName: string, data: unknown): string;
51
100
  /**
52
101
  * Walk messages from last to first, returning the text content of the most
53
102
  * recent AIMessage that has any. Non-text blocks (tool_use, thinking,
@@ -67,11 +116,16 @@ export declare function filterSubagentResult(messages: BaseMessage[]): string;
67
116
  export declare function resolveSubagentConfigs(configs: SubagentConfig[], parentContext: AgentContext): ResolvedSubagentConfig[];
68
117
  /**
69
118
  * Build child AgentInputs from a resolved config, stripping nesting and
70
- * event-driven fields. When `allowNested: true`, the child's
119
+ * (optionally) event-driven fields. When `allowNested: true`, the child's
71
120
  * `maxSubagentDepth` is decremented so that depth is consumed as the call
72
121
  * chain deepens across graph boundaries — the parent's executor-level check
73
122
  * alone cannot see into the child graph's separate executor.
74
123
  *
124
+ * When `keepToolDefinitions` is `true`, the child retains the parent's
125
+ * `toolDefinitions` so event-driven tools remain usable. This is only safe
126
+ * when the caller has wired a forwarder for `ON_TOOL_EXECUTE` to a
127
+ * registered handler — otherwise the child will hang on tool dispatch.
128
+ *
75
129
  * @remarks Advanced utility: exported primarily for testing and by
76
130
  * {@link SubagentExecutor}. Host applications configuring subagents should
77
131
  * not need to call this directly — it is invoked internally when a subagent
@@ -80,4 +134,4 @@ export declare function resolveSubagentConfigs(configs: SubagentConfig[], parent
80
134
  * mechanism that bounds nesting across graph boundaries; callers must
81
135
  * respect it.
82
136
  */
83
- export declare function buildChildInputs(config: ResolvedSubagentConfig, childAgentId: string, parentMaxDepth: number): AgentInputs;
137
+ export declare function buildChildInputs(config: ResolvedSubagentConfig, childAgentId: string, parentMaxDepth: number, keepToolDefinitions?: boolean): AgentInputs;
@@ -1,2 +1,2 @@
1
- export { SubagentExecutor, filterSubagentResult, resolveSubagentConfigs, buildChildInputs, } from './SubagentExecutor';
1
+ export { SubagentExecutor, filterSubagentResult, resolveSubagentConfigs, buildChildInputs, summarizeEvent, } from './SubagentExecutor';
2
2
  export type { SubagentExecuteParams, SubagentExecuteResult, SubagentExecutorOptions, ChildGraphFactory, } from './SubagentExecutor';