@librechat/agents 3.4.1 → 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 +57 -33
- 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/createWorkspacePolicyHook.cjs +1 -1
- package/dist/cjs/main.cjs +20 -11
- package/dist/cjs/run.cjs +48 -38
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +2 -2
- package/dist/cjs/tools/SubagentTool.cjs +4 -4
- package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +13 -9
- package/dist/cjs/tools/ToolNode.cjs.map +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 +672 -343
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs +3 -1
- package/dist/cjs/tools/subagent/SubagentReplay.cjs.map +1 -1
- 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/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +57 -33
- 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/createWorkspacePolicyHook.mjs +1 -1
- package/dist/esm/main.mjs +12 -10
- package/dist/esm/run.mjs +48 -38
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +2 -2
- package/dist/esm/tools/SubagentTool.mjs +4 -4
- package/dist/esm/tools/SubagentTool.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +13 -9
- package/dist/esm/tools/ToolNode.mjs.map +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 +672 -343
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs +3 -1
- package/dist/esm/tools/subagent/SubagentReplay.mjs.map +1 -1
- 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/types/agents/AgentContext.d.ts +1 -1
- package/dist/types/graphs/Graph.d.ts +7 -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/run.d.ts +2 -2
- package/dist/types/tools/SubagentTool.d.ts +1 -1
- 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 +32 -37
- package/dist/types/tools/subagent/SubagentReplay.d.ts +5 -1
- 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/types/graph.d.ts +184 -19
- package/package.json +3 -1
- package/src/agents/AgentContext.ts +1 -1
- package/src/graphs/Graph.ts +111 -60
- package/src/graphs/MultiAgentGraph.ts +149 -47
- 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/run.ts +50 -38
- 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/tools/SubagentTool.ts +4 -4
- package/src/tools/ToolNode.ts +22 -10
- package/src/tools/__tests__/SubagentExecutor.test.ts +198 -9
- package/src/tools/__tests__/SubagentReplay.test.ts +29 -0
- package/src/tools/__tests__/directToolHITLResumeScope.test.ts +28 -2
- package/src/tools/__tests__/subagentHooks.test.ts +90 -3
- 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 +1245 -563
- package/src/tools/subagent/SubagentReplay.ts +10 -1
- 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/types/graph.ts +217 -19
|
@@ -32,8 +32,13 @@ export type BaseGraphState = {
|
|
|
32
32
|
export type AgentSubgraphState = BaseGraphState & {
|
|
33
33
|
summarizationRequest?: SummarizationNodeInput;
|
|
34
34
|
};
|
|
35
|
+
export type SubagentGraphResult = {
|
|
36
|
+
agentId: string;
|
|
37
|
+
message?: BaseMessage;
|
|
38
|
+
};
|
|
35
39
|
export type MultiAgentGraphState = BaseGraphState & {
|
|
36
40
|
agentMessages?: BaseMessage[];
|
|
41
|
+
subagentResult?: SubagentGraphResult;
|
|
37
42
|
};
|
|
38
43
|
export type IState = BaseGraphState;
|
|
39
44
|
export interface AgentLogEvent {
|
|
@@ -223,9 +228,9 @@ export type StandardGraphInput = {
|
|
|
223
228
|
indexTokenCountMap?: Record<string, number>;
|
|
224
229
|
calibrationRatio?: number;
|
|
225
230
|
/**
|
|
226
|
-
* Receives a {@link SubagentUsageEvent} for every model call
|
|
227
|
-
* a subagent child run spawned from this graph
|
|
228
|
-
* subagents and child-side summarization calls). Child graphs run via
|
|
231
|
+
* Receives a {@link SubagentUsageEvent} for every model call that reports
|
|
232
|
+
* usage metadata inside a subagent child run spawned from this graph
|
|
233
|
+
* (including nested subagents and child-side summarization calls). Child graphs run via
|
|
229
234
|
* `invoke()` outside the host's `streamEvents` loop, so their
|
|
230
235
|
* `on_chat_model_end` events never reach the run's handler registry —
|
|
231
236
|
* this sink is the only way hosts can observe child token usage for
|
|
@@ -256,9 +261,11 @@ export type StandardGraphInput = {
|
|
|
256
261
|
* every streamed chunk event. See {@link StreamLimits}.
|
|
257
262
|
*/
|
|
258
263
|
streamLimits?: StreamLimits;
|
|
264
|
+
/** Structured lineage for a graph executing as a subagent child. */
|
|
265
|
+
subagentExecutionContext?: SubagentExecutionContext;
|
|
259
266
|
};
|
|
260
267
|
export type GraphEdge = {
|
|
261
|
-
/** Agent ID
|
|
268
|
+
/** Agent ID; direct edges use an array as an all-of waiting source group. */
|
|
262
269
|
from: string | string[];
|
|
263
270
|
/** Agent ID, use a list for multiple destinations */
|
|
264
271
|
to: string | string[];
|
|
@@ -288,40 +295,180 @@ export type GraphEdge = {
|
|
|
288
295
|
*/
|
|
289
296
|
promptKey?: string;
|
|
290
297
|
};
|
|
298
|
+
export type GraphSubagentEdge = Omit<GraphEdge, 'edgeType' | 'condition' | 'promptKey'> & {
|
|
299
|
+
edgeType: 'direct';
|
|
300
|
+
condition?: never;
|
|
301
|
+
promptKey?: never;
|
|
302
|
+
};
|
|
291
303
|
export type MultiAgentGraphInput = StandardGraphInput & {
|
|
292
304
|
edges: GraphEdge[];
|
|
305
|
+
/** Captures the designated member's final AI turn in graph state. */
|
|
306
|
+
resultAgentId?: string;
|
|
307
|
+
/** Optional per-member Pregel budget when the outer graph has its own topology budget. */
|
|
308
|
+
memberRecursionLimit?: number;
|
|
293
309
|
};
|
|
294
|
-
/**
|
|
295
|
-
export
|
|
296
|
-
/**
|
|
310
|
+
/** Lightweight identity advertised to the model for a spawnable subagent. */
|
|
311
|
+
export interface SubagentDescriptor {
|
|
312
|
+
/** Stable identifier used in the tool's `subagent_type` enum (e.g. 'researcher', 'coder'). */
|
|
297
313
|
type: string;
|
|
298
314
|
/** Human-readable display name. */
|
|
299
315
|
name: string;
|
|
300
316
|
/** What this subagent specializes in — shown to the LLM. */
|
|
301
317
|
description: string;
|
|
302
|
-
/**
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Opaque, versioned identity of the child configuration. Required when
|
|
320
|
+
* `resolveAgentInputs` is used and changed whenever its resolved inputs
|
|
321
|
+
* change incompatibly.
|
|
322
|
+
*/
|
|
323
|
+
configId?: string;
|
|
324
|
+
}
|
|
325
|
+
/** Lazy descriptor with the durable configuration identity required to resolve it. */
|
|
326
|
+
export interface LazySubagentDescriptor extends SubagentDescriptor {
|
|
327
|
+
configId: string;
|
|
328
|
+
}
|
|
329
|
+
/** Stable request identifiers exposed to a selected subagent resolver. */
|
|
330
|
+
export interface SubagentResolveRequestContext {
|
|
331
|
+
conversationId?: string;
|
|
332
|
+
messageId?: string;
|
|
333
|
+
parentMessageId?: string;
|
|
334
|
+
}
|
|
335
|
+
/** Stable user identifiers exposed to a selected subagent resolver. */
|
|
336
|
+
export interface SubagentResolveUserContext {
|
|
337
|
+
id?: string;
|
|
338
|
+
role?: string;
|
|
339
|
+
tenantId?: string;
|
|
340
|
+
}
|
|
341
|
+
/** Sanitized host runtime context safe for lazy subagent resolution. */
|
|
342
|
+
export interface SubagentResolveConfigurable {
|
|
343
|
+
requestBody?: Readonly<SubagentResolveRequestContext>;
|
|
344
|
+
user?: Readonly<SubagentResolveUserContext>;
|
|
345
|
+
user_id?: string;
|
|
346
|
+
}
|
|
347
|
+
/** Runtime context supplied when a host lazily resolves a selected subagent. */
|
|
348
|
+
export interface SubagentResolveContext {
|
|
349
|
+
/** Stable subagent identity selected by the model. */
|
|
350
|
+
descriptor: Readonly<LazySubagentDescriptor>;
|
|
351
|
+
/** Stable child execution identity, including across HITL reconstruction. */
|
|
352
|
+
executionId: string;
|
|
353
|
+
/** Parent run that dispatched this execution. */
|
|
354
|
+
parentRunId: string;
|
|
355
|
+
/** Parent agent that dispatched this execution. */
|
|
356
|
+
parentAgentId?: string;
|
|
357
|
+
/** Parent-side tool call that selected the subagent. */
|
|
358
|
+
parentToolCallId?: string;
|
|
359
|
+
/** Durable parent conversation thread, when supplied by the host. */
|
|
360
|
+
threadId?: string;
|
|
361
|
+
/** Parent/breaker cancellation composed for this child execution. */
|
|
362
|
+
signal: AbortSignal;
|
|
363
|
+
/** Stable, sanitized host context from the parent tool invocation. */
|
|
364
|
+
configurable?: Readonly<SubagentResolveConfigurable>;
|
|
365
|
+
}
|
|
366
|
+
/** Host contract for resolving a selected subagent's full graph inputs. */
|
|
367
|
+
export type SubagentAgentInputsResolver = (context: SubagentResolveContext) => Promise<AgentInputs>;
|
|
368
|
+
interface SubagentConfigBase extends SubagentDescriptor {
|
|
306
369
|
/** Max AGENT→TOOLS cycles before forced stop (default: 25). */
|
|
307
370
|
maxTurns?: number;
|
|
308
371
|
/** Allow this subagent to spawn its own subagents (default: false). */
|
|
309
372
|
allowNested?: boolean;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
|
|
373
|
+
}
|
|
374
|
+
export interface SubagentConfig extends SubagentConfigBase {
|
|
375
|
+
/** Full agent config for the child graph. Omit when `self` is true. */
|
|
376
|
+
agentInputs?: AgentInputs;
|
|
377
|
+
/**
|
|
378
|
+
* Resolve the full child config only after this descriptor is selected.
|
|
379
|
+
* Eager `agentInputs` take precedence when also supplied. `self` and a
|
|
380
|
+
* resolver are mutually exclusive and normalization rejects that pairing.
|
|
381
|
+
*
|
|
382
|
+
* Resolvers should rebuild inputs from the stable execution context instead
|
|
383
|
+
* of retaining request-owned state. The SDK keeps resolved inputs in memory
|
|
384
|
+
* only for the lifetime of the selected execution and supplies cancellation
|
|
385
|
+
* through `context.signal`. A reconstructed execution may invoke the
|
|
386
|
+
* resolver again, so the same `context.executionId` must produce equivalent
|
|
387
|
+
* child inputs. Durable resolver work should be idempotent on
|
|
388
|
+
* `(context.executionId, context.descriptor.configId)`.
|
|
389
|
+
*/
|
|
390
|
+
resolveAgentInputs?: SubagentAgentInputsResolver;
|
|
391
|
+
/** When true, reuse the parent's AgentInputs (context isolation without separate config). */
|
|
392
|
+
self?: boolean;
|
|
393
|
+
}
|
|
394
|
+
export interface SingleAgentSubagentConfig extends SubagentConfig {
|
|
395
|
+
kind?: 'agent';
|
|
396
|
+
agents?: never;
|
|
397
|
+
edges?: never;
|
|
398
|
+
entryAgentId?: never;
|
|
399
|
+
resultAgentId?: never;
|
|
400
|
+
}
|
|
401
|
+
export interface GraphSubagentConfig extends SubagentConfigBase {
|
|
402
|
+
kind: 'graph';
|
|
403
|
+
configId?: never;
|
|
404
|
+
resolveAgentInputs?: never;
|
|
405
|
+
allowNested?: false;
|
|
406
|
+
agents: AgentInputs[];
|
|
407
|
+
/**
|
|
408
|
+
* Explicit direct DAG edges. Array-valued sources are all-of waiting edges.
|
|
409
|
+
* Relative message order between parallel branches is implementation-dependent.
|
|
410
|
+
* Prompted edges are supported in chains or on the final converged result transition.
|
|
411
|
+
*/
|
|
412
|
+
edges: GraphSubagentEdge[];
|
|
413
|
+
entryAgentId: string;
|
|
414
|
+
resultAgentId: string;
|
|
415
|
+
agentInputs?: never;
|
|
416
|
+
self?: never;
|
|
417
|
+
}
|
|
418
|
+
/** Any configuration that can be spawned through the subagent tool. */
|
|
419
|
+
export type SubagentConfigEntry = SubagentConfig | GraphSubagentConfig;
|
|
420
|
+
/** Legacy single-agent config with self-spawn resolution completed. */
|
|
421
|
+
export interface ResolvedSubagentConfig extends SubagentConfig {
|
|
313
422
|
agentInputs: AgentInputs;
|
|
314
|
-
}
|
|
423
|
+
}
|
|
424
|
+
/** Explicit alias for graph-aware code that needs to name the legacy variant. */
|
|
425
|
+
export interface ResolvedSingleAgentSubagentConfig extends ResolvedSubagentConfig {
|
|
426
|
+
kind?: 'agent';
|
|
427
|
+
agents?: never;
|
|
428
|
+
edges?: never;
|
|
429
|
+
entryAgentId?: never;
|
|
430
|
+
resultAgentId?: never;
|
|
431
|
+
}
|
|
432
|
+
export type ResolvedSubagentConfigEntry = ResolvedSubagentConfig | GraphSubagentConfig;
|
|
433
|
+
/** Lazy single-agent entry accepted after descriptor validation. */
|
|
434
|
+
export interface LazySingleAgentSubagentConfig extends SingleAgentSubagentConfig {
|
|
435
|
+
configId: string;
|
|
436
|
+
resolveAgentInputs: SubagentAgentInputsResolver;
|
|
437
|
+
agentInputs?: never;
|
|
438
|
+
self?: never;
|
|
439
|
+
}
|
|
440
|
+
/** Single-agent config accepted after eager/self/lazy eligibility checks. */
|
|
441
|
+
export type ExecutableSubagentConfig = ResolvedSubagentConfig | LazySingleAgentSubagentConfig;
|
|
442
|
+
/** Graph-aware config accepted by the executor. Graph configs stay eager. */
|
|
443
|
+
export type ExecutableSubagentConfigEntry = ExecutableSubagentConfig | GraphSubagentConfig;
|
|
315
444
|
/** Lifecycle phase carried on {@link SubagentUpdateEvent}. */
|
|
316
445
|
export type SubagentUpdatePhase = 'start' | 'run_step' | 'run_step_delta' | 'run_step_completed' | 'message_delta' | 'reasoning_delta' | 'stop' | 'error';
|
|
446
|
+
export interface SubagentAncestryEntry {
|
|
447
|
+
readonly subagentRunId: string;
|
|
448
|
+
readonly subagentType: string;
|
|
449
|
+
readonly subagentKind: 'agent' | 'graph';
|
|
450
|
+
/** Execution subject ID; synthetic for graph subagents. */
|
|
451
|
+
readonly subagentAgentId: string;
|
|
452
|
+
readonly parentRunId: string;
|
|
453
|
+
readonly parentAgentId?: string;
|
|
454
|
+
readonly parentToolCallId?: string;
|
|
455
|
+
}
|
|
456
|
+
export interface SubagentExecutionContext {
|
|
457
|
+
readonly rootRunId: string;
|
|
458
|
+
readonly hookSessionId: string;
|
|
459
|
+
readonly depth: number;
|
|
460
|
+
readonly ancestry: readonly SubagentAncestryEntry[];
|
|
461
|
+
}
|
|
317
462
|
/**
|
|
318
463
|
* Wrapper event emitted when a subagent's child graph dispatches activity.
|
|
319
464
|
* Lets hosts show subagent progress in a UI surface separate from the parent
|
|
320
465
|
* conversation without having to untangle events by agent ID.
|
|
321
466
|
*/
|
|
322
467
|
export interface SubagentUpdateEvent {
|
|
323
|
-
/**
|
|
468
|
+
/** Root run ID that owns this execution tree. */
|
|
324
469
|
runId: string;
|
|
470
|
+
/** Immediate parent run that spawned this child. */
|
|
471
|
+
parentRunId?: string;
|
|
325
472
|
/** Child run ID (unique per subagent execution). */
|
|
326
473
|
subagentRunId: string;
|
|
327
474
|
/**
|
|
@@ -333,8 +480,16 @@ export interface SubagentUpdateEvent {
|
|
|
333
480
|
parentToolCallId?: string;
|
|
334
481
|
/** Subagent `type` identifier from the SubagentConfig. */
|
|
335
482
|
subagentType: string;
|
|
336
|
-
/**
|
|
483
|
+
/** Execution shape. Omitted by older emitters. */
|
|
484
|
+
subagentKind?: 'agent' | 'graph';
|
|
485
|
+
/** Execution subject ID; synthetic for graph subagents. */
|
|
337
486
|
subagentAgentId: string;
|
|
487
|
+
/** Graph member that produced this update, when attributable. */
|
|
488
|
+
memberAgentId?: string;
|
|
489
|
+
/** One-based nesting depth beneath the root graph. */
|
|
490
|
+
depth?: number;
|
|
491
|
+
/** Root-to-leaf execution lineage, without parsing composed run IDs. */
|
|
492
|
+
ancestry?: readonly SubagentAncestryEntry[];
|
|
338
493
|
/** Parent agent ID that spawned this subagent. */
|
|
339
494
|
parentAgentId?: string;
|
|
340
495
|
/** Lifecycle phase carried by this update. */
|
|
@@ -376,10 +531,20 @@ export interface SubagentUsageEvent {
|
|
|
376
531
|
provider?: string;
|
|
377
532
|
/** Subagent `type` identifier from the SubagentConfig. */
|
|
378
533
|
subagentType: string;
|
|
534
|
+
/** Execution shape. Omitted by older emitters. */
|
|
535
|
+
subagentKind?: 'agent' | 'graph';
|
|
379
536
|
/** Child run ID (unique per subagent execution). */
|
|
380
537
|
subagentRunId: string;
|
|
381
|
-
/**
|
|
538
|
+
/** Execution subject ID; synthetic for graph subagents. */
|
|
382
539
|
subagentAgentId: string;
|
|
540
|
+
/** Graph member whose model call produced this usage. */
|
|
541
|
+
memberAgentId?: string;
|
|
542
|
+
/** Immediate parent run that spawned this child. */
|
|
543
|
+
parentRunId?: string;
|
|
544
|
+
/** One-based nesting depth beneath the root graph. */
|
|
545
|
+
depth?: number;
|
|
546
|
+
/** Root-to-leaf execution lineage, without parsing composed run IDs. */
|
|
547
|
+
ancestry?: readonly SubagentAncestryEntry[];
|
|
383
548
|
/**
|
|
384
549
|
* ROOT run ID of the host run that owns billing. For nested subagents
|
|
385
550
|
* each forwarding layer rewrites this upward, so events from any depth
|
|
@@ -512,7 +677,7 @@ export interface AgentInputs {
|
|
|
512
677
|
/** Pre-computed tool schema token count (from cache). Skips recalculation when provided. */
|
|
513
678
|
toolSchemaTokens?: number;
|
|
514
679
|
/** Subagent configurations for hierarchical delegation. Each defines a child agent type. */
|
|
515
|
-
subagentConfigs?:
|
|
680
|
+
subagentConfigs?: SubagentConfigEntry[];
|
|
516
681
|
/** Maximum subagent nesting depth. Default 1 means top-level agents can spawn subagents but subagents cannot nest further. */
|
|
517
682
|
maxSubagentDepth?: number;
|
|
518
683
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@librechat/agents",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
4
4
|
"reova": {
|
|
5
5
|
"enabled": true,
|
|
6
6
|
"endpoint": "https://telemetry.reo.dev/data"
|
|
@@ -120,6 +120,8 @@
|
|
|
120
120
|
"prepublishOnly": "npm run build",
|
|
121
121
|
"build": "tsdown && tsc -p tsconfig.build.json",
|
|
122
122
|
"build:dev": "tsdown",
|
|
123
|
+
"check:circular-deps": "node config/circular-deps.mjs",
|
|
124
|
+
"test:circular-deps": "node --test config/circular-deps.test.mjs",
|
|
123
125
|
"sort-imports": "node scripts/sort-imports.ts",
|
|
124
126
|
"sort-imports:check": "node scripts/sort-imports.ts --check",
|
|
125
127
|
"start": "node dist/esm/main.js",
|
|
@@ -275,7 +275,7 @@ export class AgentContext {
|
|
|
275
275
|
/** Original AgentInputs used to create this context — used for self-spawn subagent resolution. */
|
|
276
276
|
_sourceInputs?: t.AgentInputs;
|
|
277
277
|
/** Subagent configurations for hierarchical delegation. */
|
|
278
|
-
subagentConfigs?: t.
|
|
278
|
+
subagentConfigs?: t.SubagentConfigEntry[];
|
|
279
279
|
/** Maximum subagent nesting depth. */
|
|
280
280
|
maxSubagentDepth?: number;
|
|
281
281
|
/** Instructions for this agent */
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -30,6 +30,10 @@ import type {
|
|
|
30
30
|
StreamedToolCallArgTally,
|
|
31
31
|
StreamDeltaEventTally,
|
|
32
32
|
} from '@/llm/streamLimits';
|
|
33
|
+
import type {
|
|
34
|
+
GraphFactory,
|
|
35
|
+
GraphFactoryDependencies,
|
|
36
|
+
} from '@/graphs/graphFactory';
|
|
33
37
|
import type { OverflowRecoveryPlan } from '@/llm/contextOverflowRecovery';
|
|
34
38
|
import type { FallbackErrorContext } from '@/llm/invoke';
|
|
35
39
|
import type { HookRegistry } from '@/hooks';
|
|
@@ -93,6 +97,12 @@ import {
|
|
|
93
97
|
STREAM_LIMIT_EPOCH_KEY,
|
|
94
98
|
RUN_BREAKER_SCOPE_CONFIG_KEY,
|
|
95
99
|
} from '@/llm/streamLimits';
|
|
100
|
+
import {
|
|
101
|
+
DEFAULT_SUBAGENT_DESCRIPTION,
|
|
102
|
+
SubagentExecutor,
|
|
103
|
+
isGraphSubagentConfig,
|
|
104
|
+
normalizeSubagentConfigEntries,
|
|
105
|
+
} from '@/tools/subagent';
|
|
96
106
|
import {
|
|
97
107
|
Constants,
|
|
98
108
|
GraphNodeKeys,
|
|
@@ -141,7 +151,7 @@ import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
|
|
|
141
151
|
import { shouldTraceToolNodeForLangfuse } from '@/langfuseToolOutputTracing';
|
|
142
152
|
import { createLocalCodingToolBundle } from '@/tools/local/LocalCodingTools';
|
|
143
153
|
import { SUBAGENT_REPLAY_CONTROLLER } from '@/tools/subagent/SubagentReplay';
|
|
144
|
-
import {
|
|
154
|
+
import { applyGraphRuntimeConfig } from '@/graphs/applyGraphRuntimeConfig';
|
|
145
155
|
import { partitionAndMarkBedrockToolCache } from '@/llm/bedrock/toolCache';
|
|
146
156
|
import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
|
|
147
157
|
import { createCloudflareCodingToolBundle } from '@/tools/cloudflare';
|
|
@@ -179,15 +189,21 @@ const EMPTY_PREEMPT_BOUNDARY: PreemptBoundaryResult = {
|
|
|
179
189
|
/** Minimum relative variance before calibrated toolSchemaTokens overrides current value. */
|
|
180
190
|
const CALIBRATION_VARIANCE_THRESHOLD = 0.15;
|
|
181
191
|
|
|
182
|
-
function
|
|
192
|
+
function createChildHandlerRegistry(
|
|
183
193
|
source: HandlerRegistry | undefined
|
|
184
194
|
): HandlerRegistry | undefined {
|
|
185
195
|
const toolHandler = source?.getHandler(GraphEvents.ON_TOOL_EXECUTE);
|
|
186
|
-
|
|
196
|
+
const updateHandler = source?.getHandler(GraphEvents.ON_SUBAGENT_UPDATE);
|
|
197
|
+
if (toolHandler == null && updateHandler == null) {
|
|
187
198
|
return undefined;
|
|
188
199
|
}
|
|
189
200
|
const registry = new HandlerRegistry();
|
|
190
|
-
|
|
201
|
+
if (toolHandler != null) {
|
|
202
|
+
registry.register(GraphEvents.ON_TOOL_EXECUTE, toolHandler);
|
|
203
|
+
}
|
|
204
|
+
if (updateHandler != null) {
|
|
205
|
+
registry.register(GraphEvents.ON_SUBAGENT_UPDATE, updateHandler);
|
|
206
|
+
}
|
|
191
207
|
return registry;
|
|
192
208
|
}
|
|
193
209
|
|
|
@@ -1148,6 +1164,8 @@ export abstract class Graph<
|
|
|
1148
1164
|
export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
1149
1165
|
overrideModel?: t.ChatModel;
|
|
1150
1166
|
private subagentModelOverride?: t.ChatModel;
|
|
1167
|
+
private readonly graphFactory: GraphFactory;
|
|
1168
|
+
private readonly supportsMultiAgentChildren: boolean;
|
|
1151
1169
|
/** Optional compile options passed into workflow.compile() */
|
|
1152
1170
|
compileOptions?: t.CompileOptions | undefined;
|
|
1153
1171
|
/** Whether the workflow was actually compiled with a checkpointer. */
|
|
@@ -1196,6 +1214,8 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1196
1214
|
subagentUsageSink?: t.SubagentUsageSink;
|
|
1197
1215
|
/** See {@link t.StandardGraphInput.subagentScope}. */
|
|
1198
1216
|
subagentScope: boolean;
|
|
1217
|
+
/** See {@link t.StandardGraphInput.subagentExecutionContext}. */
|
|
1218
|
+
private readonly subagentExecutionContext?: t.SubagentExecutionContext;
|
|
1199
1219
|
/** See {@link t.StandardGraphInput.preemption}. */
|
|
1200
1220
|
preemption?: t.StreamPreemption;
|
|
1201
1221
|
/**
|
|
@@ -1317,26 +1337,42 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1317
1337
|
*/
|
|
1318
1338
|
pendingPreemptReturn = new Set<string>();
|
|
1319
1339
|
|
|
1320
|
-
constructor(
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1340
|
+
constructor(
|
|
1341
|
+
{
|
|
1342
|
+
runId,
|
|
1343
|
+
signal,
|
|
1344
|
+
agents,
|
|
1345
|
+
langfuse,
|
|
1346
|
+
tokenCounter,
|
|
1347
|
+
indexTokenCountMap,
|
|
1348
|
+
calibrationRatio,
|
|
1349
|
+
subagentUsageSink,
|
|
1350
|
+
subagentScope,
|
|
1351
|
+
subagentExecutionContext,
|
|
1352
|
+
preemption,
|
|
1353
|
+
streamLimits,
|
|
1354
|
+
}: t.StandardGraphInput,
|
|
1355
|
+
dependencies?: GraphFactoryDependencies
|
|
1356
|
+
) {
|
|
1333
1357
|
super();
|
|
1358
|
+
this.supportsMultiAgentChildren = dependencies != null;
|
|
1359
|
+
this.graphFactory =
|
|
1360
|
+
dependencies?.graphFactory ??
|
|
1361
|
+
((request): StandardGraph => {
|
|
1362
|
+
if (request.kind !== 'standard') {
|
|
1363
|
+
throw new Error(
|
|
1364
|
+
'A polymorphic graph factory is required for multi-agent graph construction.'
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
return new StandardGraph(request.input);
|
|
1368
|
+
});
|
|
1334
1369
|
this.runId = runId;
|
|
1335
1370
|
this.langfuseScopeRunId = `${runId ?? 'graph'}:${nanoid()}`;
|
|
1336
1371
|
this.signal = signal;
|
|
1337
1372
|
this.langfuse = langfuse;
|
|
1338
1373
|
this.subagentUsageSink = subagentUsageSink;
|
|
1339
1374
|
this.subagentScope = subagentScope === true;
|
|
1375
|
+
this.subagentExecutionContext = subagentExecutionContext;
|
|
1340
1376
|
this.preemption = preemption;
|
|
1341
1377
|
this.streamLimits = resolveStreamLimits(streamLimits);
|
|
1342
1378
|
|
|
@@ -4211,15 +4247,57 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4211
4247
|
agentContext.subagentConfigs.length > 0 &&
|
|
4212
4248
|
effectiveSubagentDepth > 0
|
|
4213
4249
|
) {
|
|
4214
|
-
const
|
|
4250
|
+
const executableConfigs = normalizeSubagentConfigEntries(
|
|
4215
4251
|
agentContext.subagentConfigs,
|
|
4216
4252
|
agentContext
|
|
4217
4253
|
);
|
|
4218
|
-
if (
|
|
4254
|
+
if (executableConfigs.length > 0) {
|
|
4255
|
+
if (
|
|
4256
|
+
!this.supportsMultiAgentChildren &&
|
|
4257
|
+
executableConfigs.some(isGraphSubagentConfig)
|
|
4258
|
+
) {
|
|
4259
|
+
throw new Error(
|
|
4260
|
+
'Graph subagents require constructing the parent with createGraph() or an injected GraphFactory dependency.'
|
|
4261
|
+
);
|
|
4262
|
+
}
|
|
4219
4263
|
const getParentHandlerRegistry = (): HandlerRegistry | undefined =>
|
|
4220
4264
|
this.handlerRegistry ?? this.parentToolHandlerRegistry;
|
|
4265
|
+
const createConfiguredChildGraph: GraphFactory = (request) => {
|
|
4266
|
+
const childGraph = this.graphFactory(request);
|
|
4267
|
+
if (this.subagentModelOverride != null) {
|
|
4268
|
+
childGraph.overrideModel = this.subagentModelOverride;
|
|
4269
|
+
childGraph.setSubagentModelOverride(this.subagentModelOverride);
|
|
4270
|
+
}
|
|
4271
|
+
const childHandlerRegistry = createChildHandlerRegistry(
|
|
4272
|
+
getParentHandlerRegistry()
|
|
4273
|
+
);
|
|
4274
|
+
// Pure execution-ordering hint (unlike `humanInTheLoop`). It only
|
|
4275
|
+
// reorders tools already in the child's direct group; it does not
|
|
4276
|
+
// force a schema-only event tool onto the direct execution path.
|
|
4277
|
+
applyGraphRuntimeConfig(childGraph, {
|
|
4278
|
+
hookRegistry: this.hookRegistry,
|
|
4279
|
+
humanInTheLoop: this.humanInTheLoop,
|
|
4280
|
+
toolOutputReferences: this.toolOutputReferences,
|
|
4281
|
+
eagerEventToolExecution: this.eagerEventToolExecution,
|
|
4282
|
+
codeSessionToolNames: this.codeSessionToolNames,
|
|
4283
|
+
interruptingToolNames: this.interruptingToolNames,
|
|
4284
|
+
toolExecution: this.toolExecution,
|
|
4285
|
+
});
|
|
4286
|
+
if (this.humanInTheLoop?.enabled === true) {
|
|
4287
|
+
childGraph.compileOptions = {
|
|
4288
|
+
checkpointer: this.compileOptions?.checkpointer,
|
|
4289
|
+
};
|
|
4290
|
+
}
|
|
4291
|
+
childGraph.parentToolHandlerRegistry = childHandlerRegistry;
|
|
4292
|
+
childGraph.eventToolExecutionAvailable =
|
|
4293
|
+
childHandlerRegistry?.getHandler(GraphEvents.ON_TOOL_EXECUTE) !=
|
|
4294
|
+
null;
|
|
4295
|
+
return childGraph;
|
|
4296
|
+
};
|
|
4221
4297
|
const executor = new SubagentExecutor({
|
|
4222
|
-
configs: new Map(
|
|
4298
|
+
configs: new Map(
|
|
4299
|
+
executableConfigs.map((config) => [config.type, config])
|
|
4300
|
+
),
|
|
4223
4301
|
parentSignal: this.signal,
|
|
4224
4302
|
breakerScope: {
|
|
4225
4303
|
controller: (): AbortController => this.breakerAbort,
|
|
@@ -4231,6 +4309,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4231
4309
|
parentHandlerRegistry: getParentHandlerRegistry,
|
|
4232
4310
|
parentRunId: this.runId ?? '',
|
|
4233
4311
|
parentAgentId: agentContext.agentId,
|
|
4312
|
+
executionContext: this.subagentExecutionContext,
|
|
4234
4313
|
langfuse: this.langfuse,
|
|
4235
4314
|
tokenCounter: agentContext.tokenCounter,
|
|
4236
4315
|
usageSink: this.subagentUsageSink,
|
|
@@ -4238,42 +4317,12 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4238
4317
|
humanInTheLoop: this.humanInTheLoop,
|
|
4239
4318
|
checkpointer: this.compileOptions?.checkpointer,
|
|
4240
4319
|
maxDepth: effectiveSubagentDepth,
|
|
4241
|
-
createChildGraph: (input): StandardGraph =>
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
const toolHandlerRegistry = createToolHandlerRegistry(
|
|
4248
|
-
getParentHandlerRegistry()
|
|
4249
|
-
);
|
|
4250
|
-
childGraph.hookRegistry = this.hookRegistry;
|
|
4251
|
-
childGraph.humanInTheLoop = this.humanInTheLoop;
|
|
4252
|
-
if (this.humanInTheLoop?.enabled === true) {
|
|
4253
|
-
childGraph.compileOptions = {
|
|
4254
|
-
checkpointer: this.compileOptions?.checkpointer,
|
|
4255
|
-
};
|
|
4256
|
-
}
|
|
4257
|
-
childGraph.toolOutputReferences = this.toolOutputReferences;
|
|
4258
|
-
childGraph.eagerEventToolExecution = this.eagerEventToolExecution;
|
|
4259
|
-
childGraph.codeSessionToolNames = this.codeSessionToolNames;
|
|
4260
|
-
// Pure execution-ordering hint (unlike `humanInTheLoop` above).
|
|
4261
|
-
// It ONLY reorders tools already in the child's direct group;
|
|
4262
|
-
// it does not force a name onto the direct path (that fold-in
|
|
4263
|
-
// was removed — Codex review of #294). So for a self-spawned
|
|
4264
|
-
// child that scrubs inherited `graphTools` (keeping only the
|
|
4265
|
-
// event `toolDefinition` / schema-only stub for a name like
|
|
4266
|
-
// `ask_user_question`), the name isn't in the child's direct
|
|
4267
|
-
// group and this is a no-op — the stub is still dispatched via
|
|
4268
|
-
// ON_TOOL_EXECUTE, never invoked directly. Where the child DOES
|
|
4269
|
-
// have the executable graphTool, the guard correctly applies.
|
|
4270
|
-
childGraph.interruptingToolNames = this.interruptingToolNames;
|
|
4271
|
-
childGraph.toolExecution = this.toolExecution;
|
|
4272
|
-
childGraph.parentToolHandlerRegistry = toolHandlerRegistry;
|
|
4273
|
-
childGraph.eventToolExecutionAvailable =
|
|
4274
|
-
toolHandlerRegistry != null;
|
|
4275
|
-
return childGraph;
|
|
4276
|
-
},
|
|
4320
|
+
createChildGraph: (input): StandardGraph =>
|
|
4321
|
+
createConfiguredChildGraph({
|
|
4322
|
+
kind: 'standard',
|
|
4323
|
+
input,
|
|
4324
|
+
}),
|
|
4325
|
+
createChildGraphByKind: createConfiguredChildGraph,
|
|
4277
4326
|
});
|
|
4278
4327
|
this.registerSubagentExecutor(executor);
|
|
4279
4328
|
|
|
@@ -4286,7 +4335,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4286
4335
|
typeof input.description === 'string' &&
|
|
4287
4336
|
input.description.trim().length > 0
|
|
4288
4337
|
? input.description
|
|
4289
|
-
:
|
|
4338
|
+
: DEFAULT_SUBAGENT_DESCRIPTION;
|
|
4290
4339
|
const subagentType =
|
|
4291
4340
|
typeof input.subagent_type === 'string' ? input.subagent_type : '';
|
|
4292
4341
|
const threadId = config.configurable?.thread_id as string | undefined;
|
|
@@ -4317,6 +4366,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4317
4366
|
description,
|
|
4318
4367
|
subagentType,
|
|
4319
4368
|
threadId,
|
|
4369
|
+
signal: config.signal,
|
|
4320
4370
|
parentToolCallId,
|
|
4321
4371
|
breaker: batchScope?.controller,
|
|
4322
4372
|
/**
|
|
@@ -4330,14 +4380,15 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
4330
4380
|
| undefined,
|
|
4331
4381
|
});
|
|
4332
4382
|
return result.content;
|
|
4333
|
-
}, buildSubagentToolParams(
|
|
4383
|
+
}, buildSubagentToolParams(executableConfigs));
|
|
4334
4384
|
const replayableSubagentTool = subagentTool as typeof subagentTool &
|
|
4335
4385
|
ReplayableSubagentTool;
|
|
4336
4386
|
replayableSubagentTool[SUBAGENT_REPLAY_CONTROLLER] = {
|
|
4337
4387
|
getResumeManifest: (
|
|
4338
|
-
parentToolCallIds
|
|
4388
|
+
parentToolCallIds,
|
|
4389
|
+
config
|
|
4339
4390
|
): Promise<SubagentResumeManifest | undefined> =>
|
|
4340
|
-
executor.getResumeManifest(parentToolCallIds),
|
|
4391
|
+
executor.getResumeManifest(parentToolCallIds, config),
|
|
4341
4392
|
getSettledOutput: (
|
|
4342
4393
|
call,
|
|
4343
4394
|
config
|