@librechat/agents 3.1.68 → 3.1.71-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +23 -3
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/enum.cjs +16 -1
  4. package/dist/cjs/common/enum.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +136 -0
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/hooks/HookRegistry.cjs +162 -0
  8. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -0
  9. package/dist/cjs/hooks/executeHooks.cjs +276 -0
  10. package/dist/cjs/hooks/executeHooks.cjs.map +1 -0
  11. package/dist/cjs/hooks/matchers.cjs +256 -0
  12. package/dist/cjs/hooks/matchers.cjs.map +1 -0
  13. package/dist/cjs/hooks/types.cjs +27 -0
  14. package/dist/cjs/hooks/types.cjs.map +1 -0
  15. package/dist/cjs/main.cjs +57 -0
  16. package/dist/cjs/main.cjs.map +1 -1
  17. package/dist/cjs/messages/format.cjs +74 -12
  18. package/dist/cjs/messages/format.cjs.map +1 -1
  19. package/dist/cjs/messages/prune.cjs +9 -2
  20. package/dist/cjs/messages/prune.cjs.map +1 -1
  21. package/dist/cjs/run.cjs +115 -0
  22. package/dist/cjs/run.cjs.map +1 -1
  23. package/dist/cjs/summarization/node.cjs +44 -0
  24. package/dist/cjs/summarization/node.cjs.map +1 -1
  25. package/dist/cjs/tools/BashExecutor.cjs +208 -0
  26. package/dist/cjs/tools/BashExecutor.cjs.map +1 -0
  27. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +287 -0
  28. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -0
  29. package/dist/cjs/tools/CodeExecutor.cjs +0 -9
  30. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  31. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +7 -23
  32. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  33. package/dist/cjs/tools/ReadFile.cjs +43 -0
  34. package/dist/cjs/tools/ReadFile.cjs.map +1 -0
  35. package/dist/cjs/tools/SkillTool.cjs +50 -0
  36. package/dist/cjs/tools/SkillTool.cjs.map +1 -0
  37. package/dist/cjs/tools/SubagentTool.cjs +92 -0
  38. package/dist/cjs/tools/SubagentTool.cjs.map +1 -0
  39. package/dist/cjs/tools/ToolNode.cjs +746 -174
  40. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  41. package/dist/cjs/tools/ToolSearch.cjs +2 -13
  42. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  43. package/dist/cjs/tools/skillCatalog.cjs +84 -0
  44. package/dist/cjs/tools/skillCatalog.cjs.map +1 -0
  45. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +511 -0
  46. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -0
  47. package/dist/cjs/tools/toolOutputReferences.cjs +475 -0
  48. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -0
  49. package/dist/cjs/utils/truncation.cjs +28 -0
  50. package/dist/cjs/utils/truncation.cjs.map +1 -1
  51. package/dist/esm/agents/AgentContext.mjs +23 -3
  52. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  53. package/dist/esm/common/enum.mjs +15 -2
  54. package/dist/esm/common/enum.mjs.map +1 -1
  55. package/dist/esm/graphs/Graph.mjs +136 -0
  56. package/dist/esm/graphs/Graph.mjs.map +1 -1
  57. package/dist/esm/hooks/HookRegistry.mjs +160 -0
  58. package/dist/esm/hooks/HookRegistry.mjs.map +1 -0
  59. package/dist/esm/hooks/executeHooks.mjs +273 -0
  60. package/dist/esm/hooks/executeHooks.mjs.map +1 -0
  61. package/dist/esm/hooks/matchers.mjs +251 -0
  62. package/dist/esm/hooks/matchers.mjs.map +1 -0
  63. package/dist/esm/hooks/types.mjs +25 -0
  64. package/dist/esm/hooks/types.mjs.map +1 -0
  65. package/dist/esm/main.mjs +13 -2
  66. package/dist/esm/main.mjs.map +1 -1
  67. package/dist/esm/messages/format.mjs +66 -4
  68. package/dist/esm/messages/format.mjs.map +1 -1
  69. package/dist/esm/messages/prune.mjs +9 -2
  70. package/dist/esm/messages/prune.mjs.map +1 -1
  71. package/dist/esm/run.mjs +115 -0
  72. package/dist/esm/run.mjs.map +1 -1
  73. package/dist/esm/summarization/node.mjs +44 -0
  74. package/dist/esm/summarization/node.mjs.map +1 -1
  75. package/dist/esm/tools/BashExecutor.mjs +200 -0
  76. package/dist/esm/tools/BashExecutor.mjs.map +1 -0
  77. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +278 -0
  78. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -0
  79. package/dist/esm/tools/CodeExecutor.mjs +0 -9
  80. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  81. package/dist/esm/tools/ProgrammaticToolCalling.mjs +8 -24
  82. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  83. package/dist/esm/tools/ReadFile.mjs +38 -0
  84. package/dist/esm/tools/ReadFile.mjs.map +1 -0
  85. package/dist/esm/tools/SkillTool.mjs +45 -0
  86. package/dist/esm/tools/SkillTool.mjs.map +1 -0
  87. package/dist/esm/tools/SubagentTool.mjs +85 -0
  88. package/dist/esm/tools/SubagentTool.mjs.map +1 -0
  89. package/dist/esm/tools/ToolNode.mjs +748 -176
  90. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  91. package/dist/esm/tools/ToolSearch.mjs +3 -14
  92. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  93. package/dist/esm/tools/skillCatalog.mjs +82 -0
  94. package/dist/esm/tools/skillCatalog.mjs.map +1 -0
  95. package/dist/esm/tools/subagent/SubagentExecutor.mjs +505 -0
  96. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -0
  97. package/dist/esm/tools/toolOutputReferences.mjs +468 -0
  98. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -0
  99. package/dist/esm/utils/truncation.mjs +27 -1
  100. package/dist/esm/utils/truncation.mjs.map +1 -1
  101. package/dist/types/agents/AgentContext.d.ts +6 -0
  102. package/dist/types/common/enum.d.ts +10 -2
  103. package/dist/types/graphs/Graph.d.ts +23 -0
  104. package/dist/types/hooks/HookRegistry.d.ts +56 -0
  105. package/dist/types/hooks/executeHooks.d.ts +79 -0
  106. package/dist/types/hooks/index.d.ts +6 -0
  107. package/dist/types/hooks/matchers.d.ts +95 -0
  108. package/dist/types/hooks/types.d.ts +320 -0
  109. package/dist/types/index.d.ts +8 -0
  110. package/dist/types/messages/format.d.ts +2 -1
  111. package/dist/types/run.d.ts +2 -0
  112. package/dist/types/summarization/node.d.ts +2 -0
  113. package/dist/types/tools/BashExecutor.d.ts +76 -0
  114. package/dist/types/tools/BashProgrammaticToolCalling.d.ts +72 -0
  115. package/dist/types/tools/ProgrammaticToolCalling.d.ts +4 -9
  116. package/dist/types/tools/ReadFile.d.ts +28 -0
  117. package/dist/types/tools/SkillTool.d.ts +40 -0
  118. package/dist/types/tools/SubagentTool.d.ts +36 -0
  119. package/dist/types/tools/ToolNode.d.ts +109 -4
  120. package/dist/types/tools/ToolSearch.d.ts +2 -2
  121. package/dist/types/tools/skillCatalog.d.ts +19 -0
  122. package/dist/types/tools/subagent/SubagentExecutor.d.ts +137 -0
  123. package/dist/types/tools/subagent/index.d.ts +2 -0
  124. package/dist/types/tools/toolOutputReferences.d.ts +205 -0
  125. package/dist/types/types/graph.d.ts +61 -2
  126. package/dist/types/types/index.d.ts +1 -0
  127. package/dist/types/types/run.d.ts +28 -0
  128. package/dist/types/types/skill.d.ts +9 -0
  129. package/dist/types/types/tools.d.ts +108 -10
  130. package/dist/types/utils/truncation.d.ts +21 -0
  131. package/package.json +5 -1
  132. package/src/agents/AgentContext.ts +26 -2
  133. package/src/common/enum.ts +15 -1
  134. package/src/graphs/Graph.ts +161 -0
  135. package/src/hooks/HookRegistry.ts +208 -0
  136. package/src/hooks/__tests__/HookRegistry.test.ts +190 -0
  137. package/src/hooks/__tests__/compactHooks.test.ts +214 -0
  138. package/src/hooks/__tests__/executeHooks.test.ts +1013 -0
  139. package/src/hooks/__tests__/integration.test.ts +337 -0
  140. package/src/hooks/__tests__/matchers.test.ts +238 -0
  141. package/src/hooks/__tests__/toolHooks.test.ts +669 -0
  142. package/src/hooks/executeHooks.ts +375 -0
  143. package/src/hooks/index.ts +57 -0
  144. package/src/hooks/matchers.ts +280 -0
  145. package/src/hooks/types.ts +404 -0
  146. package/src/index.ts +10 -0
  147. package/src/messages/format.ts +74 -4
  148. package/src/messages/formatAgentMessages.skills.test.ts +334 -0
  149. package/src/messages/prune.ts +9 -2
  150. package/src/run.ts +130 -0
  151. package/src/scripts/multi-agent-subagent.ts +246 -0
  152. package/src/scripts/programmatic_exec.ts +1 -10
  153. package/src/scripts/subagent-event-driven-debug.ts +190 -0
  154. package/src/scripts/subagent-tools-debug.ts +160 -0
  155. package/src/scripts/test_code_api.ts +0 -7
  156. package/src/scripts/tool_search.ts +1 -10
  157. package/src/specs/prune.test.ts +413 -0
  158. package/src/specs/subagent.test.ts +305 -0
  159. package/src/summarization/node.ts +53 -0
  160. package/src/tools/BashExecutor.ts +238 -0
  161. package/src/tools/BashProgrammaticToolCalling.ts +381 -0
  162. package/src/tools/CodeExecutor.ts +0 -11
  163. package/src/tools/ProgrammaticToolCalling.ts +4 -29
  164. package/src/tools/ReadFile.ts +39 -0
  165. package/src/tools/SkillTool.ts +46 -0
  166. package/src/tools/SubagentTool.ts +100 -0
  167. package/src/tools/ToolNode.ts +999 -214
  168. package/src/tools/ToolSearch.ts +3 -19
  169. package/src/tools/__tests__/BashExecutor.test.ts +36 -0
  170. package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +7 -8
  171. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +0 -1
  172. package/src/tools/__tests__/ReadFile.test.ts +44 -0
  173. package/src/tools/__tests__/SkillTool.test.ts +442 -0
  174. package/src/tools/__tests__/SubagentExecutor.test.ts +1148 -0
  175. package/src/tools/__tests__/SubagentTool.test.ts +149 -0
  176. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +1395 -0
  177. package/src/tools/__tests__/ToolNode.session.test.ts +12 -12
  178. package/src/tools/__tests__/ToolSearch.integration.test.ts +7 -8
  179. package/src/tools/__tests__/skillCatalog.test.ts +161 -0
  180. package/src/tools/__tests__/subagentHooks.test.ts +215 -0
  181. package/src/tools/__tests__/toolOutputReferences.test.ts +415 -0
  182. package/src/tools/skillCatalog.ts +126 -0
  183. package/src/tools/subagent/SubagentExecutor.ts +676 -0
  184. package/src/tools/subagent/index.ts +13 -0
  185. package/src/tools/toolOutputReferences.ts +590 -0
  186. package/src/types/graph.ts +80 -1
  187. package/src/types/index.ts +1 -0
  188. package/src/types/run.ts +28 -0
  189. package/src/types/skill.ts +11 -0
  190. package/src/types/tools.ts +112 -10
  191. package/src/utils/__tests__/truncation.test.ts +66 -0
  192. package/src/utils/truncation.ts +30 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Tool output reference registry.
3
+ *
4
+ * When enabled via `RunConfig.toolOutputReferences.enabled`, ToolNode
5
+ * stores each successful tool output under a stable key
6
+ * (`tool<idx>turn<turn>`) where `idx` is the tool's position within a
7
+ * ToolNode batch and `turn` is the batch index within the run
8
+ * (incremented once per ToolNode invocation).
9
+ *
10
+ * Subsequent tool calls can pipe a previous output into their args by
11
+ * embedding `{{tool<idx>turn<turn>}}` inside any string argument;
12
+ * {@link ToolOutputReferenceRegistry.resolve} walks the args and
13
+ * substitutes the placeholders immediately before invocation.
14
+ *
15
+ * The registry stores the *raw, untruncated* tool output so a later
16
+ * `{{…}}` substitution pipes the full payload into the next tool —
17
+ * even when the LLM only saw a head+tail-truncated preview in
18
+ * `ToolMessage.content`. Outputs are stored without any annotation
19
+ * (the `_ref` key or the `[ref: ...]` prefix seen by the LLM is
20
+ * strictly a UX signal attached to `ToolMessage.content`). Keeping the
21
+ * registry pristine means downstream bash/jq piping receives the
22
+ * complete, verbatim output with no injected fields.
23
+ */
24
+ /**
25
+ * Non-global matcher for a single `{{tool<i>turn<n>}}` placeholder.
26
+ * Exported for consumers that want to detect references (e.g., syntax
27
+ * highlighting, docs). The stateful `g` variant lives inside the
28
+ * registry so nobody trips on `lastIndex`.
29
+ */
30
+ export declare const TOOL_OUTPUT_REF_PATTERN: RegExp;
31
+ /** Object key used when a parsed-object output has `_ref` injected. */
32
+ export declare const TOOL_OUTPUT_REF_KEY = "_ref";
33
+ /**
34
+ * Object key used to carry unresolved reference warnings on a parsed-
35
+ * object output. Using a dedicated field instead of a trailing text
36
+ * line keeps the annotated `ToolMessage.content` parseable as JSON for
37
+ * downstream consumers that rely on the object shape.
38
+ */
39
+ export declare const TOOL_OUTPUT_UNRESOLVED_KEY = "_unresolved_refs";
40
+ /** Single-line prefix prepended to non-object tool outputs so the LLM sees the reference key. */
41
+ export declare function buildReferencePrefix(key: string): string;
42
+ /** Stable registry key for a tool output. */
43
+ export declare function buildReferenceKey(toolIndex: number, turn: number): string;
44
+ export type ToolOutputReferenceRegistryOptions = {
45
+ /** Maximum characters stored per registered output. */
46
+ maxOutputSize?: number;
47
+ /** Maximum total characters retained across all registered outputs. */
48
+ maxTotalSize?: number;
49
+ /**
50
+ * Upper bound on the number of concurrently-tracked runs. When
51
+ * exceeded, the oldest run bucket is evicted (FIFO). Defaults to 32.
52
+ */
53
+ maxActiveRuns?: number;
54
+ };
55
+ /**
56
+ * Result of resolving placeholders in tool args.
57
+ */
58
+ export type ResolveResult<T> = {
59
+ /** Arguments with placeholders replaced. Same shape as the input. */
60
+ resolved: T;
61
+ /** Reference keys that were referenced but had no stored value. */
62
+ unresolved: string[];
63
+ };
64
+ /**
65
+ * Read-only view over a frozen registry snapshot. Returned by
66
+ * {@link ToolOutputReferenceRegistry.snapshot} for callers that need
67
+ * to resolve placeholders against the registry state at a specific
68
+ * point in time, ignoring any subsequent registrations.
69
+ */
70
+ export interface ToolOutputResolveView {
71
+ resolve<T>(args: T): ResolveResult<T>;
72
+ }
73
+ /**
74
+ * Pre-resolved arg map keyed by `toolCallId`. Used by the mixed
75
+ * direct+event dispatch path to feed event calls' resolved args
76
+ * (captured pre-batch) into the dispatcher without re-resolving
77
+ * against the now-stale live registry.
78
+ */
79
+ export type PreResolvedArgsMap = Map<string, {
80
+ resolved: Record<string, unknown>;
81
+ unresolved: string[];
82
+ }>;
83
+ /**
84
+ * Per-call sink for resolved args, keyed by `toolCallId`. Threaded
85
+ * as a per-batch local map so concurrent `ToolNode.run()` calls do
86
+ * not race on shared sink state.
87
+ */
88
+ export type ResolvedArgsByCallId = Map<string, Record<string, unknown>>;
89
+ /**
90
+ * Ordered map of reference-key → stored output, partitioned by run so
91
+ * concurrent / interleaved runs sharing one registry cannot leak
92
+ * outputs between each other.
93
+ *
94
+ * Each public method takes a `runId` which selects the run's bucket.
95
+ * Hosts typically get one registry per run via `Graph`, in which
96
+ * case only a single bucket is ever populated; the partitioning
97
+ * exists so the registry also behaves correctly when a single
98
+ * instance is reused directly.
99
+ */
100
+ export declare class ToolOutputReferenceRegistry {
101
+ private runStates;
102
+ private readonly maxOutputSize;
103
+ private readonly maxTotalSize;
104
+ private readonly maxActiveRuns;
105
+ /**
106
+ * Local stateful matcher used only by `replaceInString`. Kept
107
+ * off-module so callers of the exported `TOOL_OUTPUT_REF_PATTERN`
108
+ * never see a stale `lastIndex`.
109
+ */
110
+ private static readonly PLACEHOLDER_MATCHER;
111
+ constructor(options?: ToolOutputReferenceRegistryOptions);
112
+ private keyFor;
113
+ private getOrCreate;
114
+ /** Registers (or replaces) the output stored under `key` for `runId`. */
115
+ set(runId: string | undefined, key: string, value: string): void;
116
+ /** Returns the stored value for `key` in `runId`'s bucket, or `undefined`. */
117
+ get(runId: string | undefined, key: string): string | undefined;
118
+ /** Total number of registered outputs across every run bucket. */
119
+ get size(): number;
120
+ /** Maximum characters retained per output (post-clip). */
121
+ get perOutputLimit(): number;
122
+ /** Maximum total characters retained *per run*. */
123
+ get totalLimit(): number;
124
+ /** Drops every run's state. */
125
+ clear(): void;
126
+ /**
127
+ * Explicitly release `runId`'s state. Safe to call when a run has
128
+ * finished. Hosts sharing one registry across runs should call this
129
+ * to reclaim memory deterministically; otherwise LRU eviction kicks
130
+ * in when `maxActiveRuns` runs accumulate.
131
+ */
132
+ releaseRun(runId: string | undefined): void;
133
+ /**
134
+ * Claims the next batch turn synchronously from `runId`'s bucket.
135
+ *
136
+ * Must be called once at the start of each ToolNode batch before
137
+ * any `await`, so concurrent invocations within the same run see
138
+ * distinct turn values (reads are effectively atomic by JS's
139
+ * single-threaded execution of the sync prefix).
140
+ *
141
+ * If `runId` is missing the anonymous bucket is dropped and a
142
+ * fresh one created so each anonymous call behaves as its own run.
143
+ */
144
+ nextTurn(runId: string | undefined): number;
145
+ /**
146
+ * Records that `toolName` has been warned about in `runId` (returns
147
+ * `true` on the first call per run, `false` after). Used by
148
+ * ToolNode to emit one log line per offending tool per run when a
149
+ * `ToolMessage.content` isn't a string.
150
+ */
151
+ claimWarnOnce(runId: string | undefined, toolName: string): boolean;
152
+ /**
153
+ * Walks `args` and replaces every `{{tool<i>turn<n>}}` placeholder in
154
+ * string values with the stored output *from `runId`'s bucket*. Non-
155
+ * string values and object keys are left untouched. Unresolved
156
+ * references are left in-place and reported so the caller can
157
+ * surface them to the LLM. When no placeholder appears anywhere in
158
+ * the serialized args, the original input is returned without
159
+ * walking the tree.
160
+ */
161
+ resolve<T>(runId: string | undefined, args: T): ResolveResult<T>;
162
+ /**
163
+ * Captures a frozen snapshot of `runId`'s current entries and
164
+ * returns a view that resolves placeholders against *only* that
165
+ * snapshot. The snapshot is decoupled from the live registry, so
166
+ * subsequent `set()` calls (for example, same-turn direct outputs
167
+ * registering while an event branch is still in flight) are
168
+ * invisible to the snapshot's `resolve`. Used by the mixed
169
+ * direct+event dispatch path to preserve same-turn isolation when
170
+ * a `PreToolUse` hook rewrites event args after directs have
171
+ * completed.
172
+ */
173
+ snapshot(runId: string | undefined): ToolOutputResolveView;
174
+ private resolveAgainst;
175
+ private transform;
176
+ private replaceInString;
177
+ private evictWithinBucket;
178
+ }
179
+ /**
180
+ * Annotates `content` with a reference key and/or unresolved-ref
181
+ * warnings so the LLM sees both alongside the tool output.
182
+ *
183
+ * Behavior:
184
+ * - If `content` parses as a plain (non-array, non-null) JSON object
185
+ * and the object does not already have a conflicting `_ref` key,
186
+ * the reference key and (when present) `_unresolved_refs` array
187
+ * are injected as object fields, preserving JSON validity for
188
+ * downstream consumers that parse the output.
189
+ * - Otherwise (string output, JSON array/primitive, parse failure,
190
+ * or `_ref` collision), a `[ref: <key>]\n` prefix line is
191
+ * prepended and unresolved refs are appended as a trailing
192
+ * `[unresolved refs: …]` line.
193
+ *
194
+ * The annotated string is what the LLM sees as `ToolMessage.content`.
195
+ * The *original* (un-annotated) value is what gets stored in the
196
+ * registry, so downstream piping remains pristine.
197
+ *
198
+ * @param content Raw (post-truncation) tool output.
199
+ * @param key Reference key for this output, or undefined when
200
+ * there is nothing to register (errors etc.).
201
+ * @param unresolved Reference keys that failed to resolve during
202
+ * argument substitution. Surfaced so the LLM can
203
+ * self-correct its next tool call.
204
+ */
205
+ export declare function annotateToolOutputWithReference(content: string, key: string | undefined, unresolved?: string[]): string;
@@ -4,7 +4,7 @@ import type { BaseMessage, AIMessageChunk, SystemMessage } from '@langchain/core
4
4
  import type { RunnableConfig, Runnable } from '@langchain/core/runnables';
5
5
  import type { ChatGenerationChunk } from '@langchain/core/outputs';
6
6
  import type { GoogleAIToolType } from '@langchain/google-common';
7
- import type { ToolMap, ToolEndEvent, GenericTool, LCTool } from '@/types/tools';
7
+ import type { ToolMap, ToolEndEvent, GenericTool, LCTool, ToolExecuteBatchRequest } from '@/types/tools';
8
8
  import type { Providers, Callback, GraphNodeKeys } from '@/common';
9
9
  import type { StandardGraph, MultiAgentGraph } from '@/graphs';
10
10
  import type { ClientOptions } from '@/types/llm';
@@ -45,7 +45,7 @@ export interface AgentLogEvent {
45
45
  agentId?: string;
46
46
  }
47
47
  export interface EventHandler {
48
- handle(event: string, data: StreamEventData | ModelEndData | RunStep | RunStepDeltaEvent | MessageDeltaEvent | ReasoningDeltaEvent | SummarizeStartEvent | SummarizeDeltaEvent | SummarizeCompleteEvent | AgentLogEvent | {
48
+ handle(event: string, data: StreamEventData | ModelEndData | RunStep | RunStepDeltaEvent | MessageDeltaEvent | ReasoningDeltaEvent | SummarizeStartEvent | SummarizeDeltaEvent | SummarizeCompleteEvent | SubagentUpdateEvent | AgentLogEvent | ToolExecuteBatchRequest | {
49
49
  result: ToolEndEvent;
50
50
  }, metadata?: Record<string, unknown>, graph?: StandardGraph | MultiAgentGraph): void | Promise<void>;
51
51
  }
@@ -248,6 +248,61 @@ export type GraphEdge = {
248
248
  export type MultiAgentGraphInput = StandardGraphInput & {
249
249
  edges: GraphEdge[];
250
250
  };
251
+ /** Configuration for a subagent type that can be spawned by a parent agent. */
252
+ export type SubagentConfig = {
253
+ /** Identifier used in the tool's `subagent_type` enum (e.g. 'researcher', 'coder'). */
254
+ type: string;
255
+ /** Human-readable display name. */
256
+ name: string;
257
+ /** What this subagent specializes in — shown to the LLM. */
258
+ description: string;
259
+ /** Full agent config for the child graph. Omit when `self` is true. */
260
+ agentInputs?: AgentInputs;
261
+ /** When true, reuse the parent's AgentInputs (context isolation without separate config). */
262
+ self?: boolean;
263
+ /** Max AGENT→TOOLS cycles before forced stop (default: 25). */
264
+ maxTurns?: number;
265
+ /** Allow this subagent to spawn its own subagents (default: false). */
266
+ allowNested?: boolean;
267
+ };
268
+ /** SubagentConfig with agentInputs guaranteed present (self-spawn resolved). */
269
+ export type ResolvedSubagentConfig = SubagentConfig & {
270
+ agentInputs: AgentInputs;
271
+ };
272
+ /** Lifecycle phase carried on {@link SubagentUpdateEvent}. */
273
+ export type SubagentUpdatePhase = 'start' | 'run_step' | 'run_step_delta' | 'run_step_completed' | 'message_delta' | 'reasoning_delta' | 'stop' | 'error';
274
+ /**
275
+ * Wrapper event emitted when a subagent's child graph dispatches activity.
276
+ * Lets hosts show subagent progress in a UI surface separate from the parent
277
+ * conversation without having to untangle events by agent ID.
278
+ */
279
+ export interface SubagentUpdateEvent {
280
+ /** Parent run ID. */
281
+ runId: string;
282
+ /** Child run ID (unique per subagent execution). */
283
+ subagentRunId: string;
284
+ /**
285
+ * Parent-side `tool_call_id` for the `subagent` tool invocation that
286
+ * triggered this run. Stable for the duration of the child; lets hosts
287
+ * correlate updates deterministically instead of inferring by ordering.
288
+ * Omitted when the executor was invoked outside of a tool-call context.
289
+ */
290
+ parentToolCallId?: string;
291
+ /** Subagent `type` identifier from the SubagentConfig. */
292
+ subagentType: string;
293
+ /** Child agent ID assigned to this subagent execution. */
294
+ subagentAgentId: string;
295
+ /** Parent agent ID that spawned this subagent. */
296
+ parentAgentId?: string;
297
+ /** Lifecycle phase carried by this update. */
298
+ phase: SubagentUpdatePhase;
299
+ /** Underlying event payload (shape depends on phase). */
300
+ data?: unknown;
301
+ /** Short human-readable description. Hosts can render this directly. */
302
+ label?: string;
303
+ /** ISO timestamp for ordering / display. */
304
+ timestamp: string;
305
+ }
251
306
  export interface AgentInputs {
252
307
  agentId: string;
253
308
  /** Human-readable name for the agent (used in handoff context). Defaults to agentId if not provided. */
@@ -294,6 +349,10 @@ export interface AgentInputs {
294
349
  maxToolResultChars?: number;
295
350
  /** Pre-computed tool schema token count (from cache). Skips recalculation when provided. */
296
351
  toolSchemaTokens?: number;
352
+ /** Subagent configurations for hierarchical delegation. Each defines a child agent type. */
353
+ subagentConfigs?: SubagentConfig[];
354
+ /** Maximum subagent nesting depth. Default 1 means top-level agents can spawn subagents but subagents cannot nest further. */
355
+ maxSubagentDepth?: number;
297
356
  }
298
357
  export interface ContextPruningConfig {
299
358
  enabled?: boolean;
@@ -1,6 +1,7 @@
1
1
  export * from './graph';
2
2
  export * from './llm';
3
3
  export * from './run';
4
+ export * from './skill';
4
5
  export * from './stream';
5
6
  export * from './tools';
6
7
  export * from './summarize';
@@ -7,6 +7,8 @@ import type * as s from '@/types/stream';
7
7
  import type * as e from '@/common/enum';
8
8
  import type * as g from '@/types/graph';
9
9
  import type * as l from '@/types/llm';
10
+ import type { ToolSessionMap, ToolOutputReferencesConfig } from '@/types/tools';
11
+ import type { HookRegistry } from '@/hooks';
10
12
  export type ZodObjectAny = z.ZodObject<any, any, any, any>;
11
13
  export type BaseGraphConfig = {
12
14
  llmConfig: l.LLMConfig;
@@ -100,6 +102,18 @@ export type RunConfig = {
100
102
  runId: string;
101
103
  graphConfig: LegacyGraphConfig | StandardGraphConfig | MultiAgentGraphConfig;
102
104
  customHandlers?: Record<string, g.EventHandler>;
105
+ /**
106
+ * Pre-constructed hook registry for this run. Hooks fire at lifecycle
107
+ * points in `processStream` (RunStart, UserPromptSubmit, Stop,
108
+ * StopFailure) and around tool calls (PreToolUse, PostToolUse,
109
+ * PostToolUseFailure, PermissionDenied).
110
+ *
111
+ * Pass `undefined` (the default) to skip all hook dispatch. When a
112
+ * registry is provided, the run attaches it to the `Graph` so internal
113
+ * nodes can fire hooks too, and clears the session in the `finally`
114
+ * block to prevent leaks.
115
+ */
116
+ hooks?: HookRegistry;
103
117
  returnContent?: boolean;
104
118
  tokenCounter?: TokenCounter;
105
119
  indexTokenCountMap?: Record<string, number>;
@@ -114,6 +128,20 @@ export type RunConfig = {
114
128
  calibrationRatio?: number;
115
129
  /** Skip post-stream cleanup (clearHeavyState) — useful for tests that inspect graph state after processStream */
116
130
  skipCleanup?: boolean;
131
+ /**
132
+ * Initial session state to seed the Graph's ToolSessionMap.
133
+ * Used to carry over code environment sessions from skill file priming
134
+ * at run start, so ToolNode can inject session_id + files into tool calls.
135
+ */
136
+ initialSessions?: ToolSessionMap;
137
+ /**
138
+ * Run-scoped tool output reference configuration. When `enabled` is
139
+ * `true`, tool outputs are registered under stable keys
140
+ * (`tool<idx>turn<turn>`) and subsequent tool calls can pipe previous
141
+ * outputs into their arguments via `{{tool<idx>turn<turn>}}`
142
+ * placeholders. Disabled by default so existing runs are unaffected.
143
+ */
144
+ toolOutputReferences?: ToolOutputReferencesConfig;
117
145
  };
118
146
  export type ProvidedCallbacks = (BaseCallbackHandler | CallbackHandlerMethods)[] | undefined;
119
147
  export type TokenCounter = (message: BaseMessage) => number;
@@ -0,0 +1,9 @@
1
+ /** Minimal skill metadata for catalog assembly. The host provides these from its own data layer. */
2
+ export type SkillCatalogEntry = {
3
+ /** Kebab-case identifier (what the model passes to SkillTool) */
4
+ name: string;
5
+ /** One-line description for the catalog listing */
6
+ description: string;
7
+ /** Optional human-readable label (UI only, not shown to model) */
8
+ displayTitle?: string;
9
+ };
@@ -1,8 +1,9 @@
1
1
  import type { StructuredToolInterface } from '@langchain/core/tools';
2
2
  import type { RunnableToolLike } from '@langchain/core/runnables';
3
3
  import type { ToolCall } from '@langchain/core/messages/tool';
4
- import type { ToolErrorData } from './stream';
5
- import { EnvVar } from '@/common';
4
+ import type { HookRegistry } from '@/hooks';
5
+ import type { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
6
+ import type { MessageContentComplex, ToolErrorData } from './stream';
6
7
  /** Replacement type for `import type { ToolCall } from '@langchain/core/messages/tool'` in order to have stringified args typed */
7
8
  export type CustomToolCall = {
8
9
  name: string;
@@ -39,6 +40,12 @@ export type ToolNodeOptions = {
39
40
  agentId?: string;
40
41
  /** Tool names that must be executed directly (via runTool) even in event-driven mode (e.g., graph-managed handoff tools) */
41
42
  directToolNames?: Set<string>;
43
+ /**
44
+ * Hook registry for PreToolUse/PostToolUse lifecycle hooks.
45
+ * Only fires for event-driven tool calls (`dispatchToolEvents`). Tools
46
+ * routed through `directToolNames` bypass hook dispatch entirely.
47
+ */
48
+ hookRegistry?: HookRegistry;
42
49
  /** Max context tokens for the agent — used to compute tool result truncation limits. */
43
50
  maxContextTokens?: number;
44
51
  /**
@@ -46,6 +53,22 @@ export type ToolNodeOptions = {
46
53
  * When provided, takes precedence over the value computed from maxContextTokens.
47
54
  */
48
55
  maxToolResultChars?: number;
56
+ /**
57
+ * Run-scoped tool output reference configuration. When `enabled` is
58
+ * `true`, ToolNode registers successful outputs and substitutes
59
+ * `{{tool<idx>turn<turn>}}` placeholders found in string args.
60
+ *
61
+ * Ignored when `toolOutputRegistry` is also provided (host-supplied
62
+ * registry wins).
63
+ */
64
+ toolOutputReferences?: ToolOutputReferencesConfig;
65
+ /**
66
+ * Pre-constructed registry instance shared across ToolNodes for the
67
+ * run. Graphs pass the same registry to every ToolNode they compile
68
+ * so cross-agent `{{tool<i>turn<n>}}` substitutions resolve. Takes
69
+ * precedence over `toolOutputReferences` when both are set.
70
+ */
71
+ toolOutputRegistry?: ToolOutputReferenceRegistry;
49
72
  };
50
73
  export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
51
74
  export type ToolEndEvent = {
@@ -65,9 +88,7 @@ export type CodeEnvFile = {
65
88
  export type CodeExecutionToolParams = undefined | {
66
89
  session_id?: string;
67
90
  user_id?: string;
68
- apiKey?: string;
69
91
  files?: CodeEnvFile[];
70
- [EnvVar.CODE_API_KEY]?: string;
71
92
  };
72
93
  export type FileRef = {
73
94
  id: string;
@@ -154,6 +175,25 @@ export type ToolExecuteBatchRequest = {
154
175
  /** Promise rejector - handler calls this on fatal error */
155
176
  reject: (error: Error) => void;
156
177
  };
178
+ /**
179
+ * A message injected into graph state by any tool execution handler.
180
+ * Generic mechanism: any tool returning `injectedMessages` in its `ToolExecuteResult`
181
+ * will have these appended to state after the ToolMessage for this call.
182
+ */
183
+ export type InjectedMessage = {
184
+ /** 'user' for skill body injection, 'system' for context hints.
185
+ * Both are converted to HumanMessage at runtime; the original role
186
+ * is preserved in additional_kwargs.role. */
187
+ role: 'user' | 'system';
188
+ /** Message content: string for simple text, array for complex multi-part content */
189
+ content: string | MessageContentComplex[];
190
+ /** When true, the message is framework-internal: not shown in UI, not counted as a user turn */
191
+ isMeta?: boolean;
192
+ /** Origin tag for downstream consumers (UI, pruner, compaction) */
193
+ source?: 'skill' | 'hook' | 'system';
194
+ /** Only set when source is 'skill', for compaction preservation */
195
+ skillName?: string;
196
+ };
157
197
  /** Result for a single tool call in event-driven execution */
158
198
  export type ToolExecuteResult = {
159
199
  /** Matches ToolCallRequest.id */
@@ -166,9 +206,69 @@ export type ToolExecuteResult = {
166
206
  status: 'success' | 'error';
167
207
  /** Error message if status is 'error' */
168
208
  errorMessage?: string;
209
+ /**
210
+ * Messages to inject into graph state after the ToolMessage for this call.
211
+ * Placed after tool results to respect provider message ordering (tool_call -> tool_result adjacency).
212
+ * The host's message formatter may merge injected user messages with the preceding tool_result turn.
213
+ * Generic mechanism: any tool execution handler can use this.
214
+ */
215
+ injectedMessages?: InjectedMessage[];
169
216
  };
170
217
  /** Map of tool names to tool definitions */
171
218
  export type LCToolRegistry = Map<string, LCTool>;
219
+ /**
220
+ * Run-scoped configuration for tool output references.
221
+ *
222
+ * When enabled, each successful tool result is registered under a stable
223
+ * key (`tool<idx>turn<turn>`). Later tool calls can pipe a previous
224
+ * output into their arguments by including the literal placeholder
225
+ * `{{tool<idx>turn<turn>}}` anywhere in a string argument; ToolNode
226
+ * substitutes it with the stored output immediately before invoking
227
+ * the tool.
228
+ *
229
+ * The registry stores the *raw, untruncated* tool output (subject to
230
+ * its own size caps) so a later substitution can pipe the full payload
231
+ * into the next tool even when the LLM only saw a head+tail-truncated
232
+ * preview in `ToolMessage.content`. Size limits are decoupled from the
233
+ * LLM-visible truncation budget and default to 5 MB total.
234
+ *
235
+ * Known limitations:
236
+ * - Tools that return a `ToolMessage` with array-type content
237
+ * (multi-part content blocks such as text + image) are not
238
+ * registered and cannot be cited via `{{tool<i>turn<n>}}`. A
239
+ * warning is logged so the missing reference is visible.
240
+ * - When a `PostToolUse` hook replaces `ToolMessage.content`, the
241
+ * *post-hook* content is what gets stored in the registry (and
242
+ * what the model sees), so `{{…}}` substitutions deliver the
243
+ * hooked output rather than the raw tool return. This matches the
244
+ * hook's "authoritative" role for output shaping.
245
+ */
246
+ export type ToolOutputReferencesConfig = {
247
+ /** Enable the registry and placeholder substitution. Defaults to `false`. */
248
+ enabled?: boolean;
249
+ /**
250
+ * Maximum characters stored (and substituted) per registered output.
251
+ * Applied to the *raw* output before storage. Defaults to
252
+ * `HARD_MAX_TOOL_RESULT_CHARS` (~400 KB) — matching the
253
+ * LLM-visible tool-result truncation budget, which is also a safe
254
+ * payload size for shell `ARG_MAX` limits when a `{{…}}` expansion
255
+ * gets piped into a bash `command`. Hosts that want to preserve
256
+ * fuller fidelity (for example for non-bash API consumers) can
257
+ * raise this up to `maxTotalSize` (defaults to 5 MB) — be aware
258
+ * that large single-output substitutions may exceed shell
259
+ * argument-size limits on typical Linux/macOS.
260
+ */
261
+ maxOutputSize?: number;
262
+ /**
263
+ * Hard cap on total characters retained across all registered outputs
264
+ * for the run. When exceeded, the oldest entries are evicted FIFO
265
+ * until the total fits. The effective per-output cap is
266
+ * `min(maxOutputSize, maxTotalSize)` so a single stored output can
267
+ * never exceed the aggregate bound. Defaults to
268
+ * `calculateMaxTotalToolOutputSize(maxOutputSize)` (5 MB).
269
+ */
270
+ maxTotalSize?: number;
271
+ };
172
272
  export type ProgrammaticCache = {
173
273
  toolMap: ToolMap;
174
274
  toolDefs: LCTool[];
@@ -179,7 +279,6 @@ export type ToolSearchMode = 'code_interpreter' | 'local';
179
279
  export type McpNameFormat = 'full' | 'base';
180
280
  /** Parameters for creating a Tool Search tool */
181
281
  export type ToolSearchParams = {
182
- apiKey?: string;
183
282
  toolRegistry?: LCToolRegistry;
184
283
  onlyDeferred?: boolean;
185
284
  baseUrl?: string;
@@ -189,7 +288,6 @@ export type ToolSearchParams = {
189
288
  mcpServer?: string | string[];
190
289
  /** Format for MCP tool names: 'full' (tool_mcp_server) or 'base' (tool only). Default: 'full' */
191
290
  mcpNameFormat?: McpNameFormat;
192
- [key: string]: unknown;
193
291
  };
194
292
  /** Simplified tool metadata for search purposes */
195
293
  export type ToolMetadata = {
@@ -266,12 +364,14 @@ export type ProgrammaticExecutionArtifact = {
266
364
  session_id?: string;
267
365
  files?: FileRefs;
268
366
  };
367
+ /** Parameters for creating a bash execution tool (same API as CodeExecutor, bash-only) */
368
+ export type BashExecutionToolParams = CodeExecutionToolParams;
369
+ /** Parameters for creating a bash programmatic tool calling tool (same API as PTC, bash-only) */
370
+ export type BashProgrammaticToolCallingParams = ProgrammaticToolCallingParams;
269
371
  /**
270
372
  * Initialization parameters for the PTC tool
271
373
  */
272
374
  export type ProgrammaticToolCallingParams = {
273
- /** Code API key (or use CODE_API_KEY env var) */
274
- apiKey?: string;
275
375
  /** Code API base URL (or use CODE_BASEURL env var) */
276
376
  baseUrl?: string;
277
377
  /** Safety limit for round-trips (default: 20) */
@@ -280,8 +380,6 @@ export type ProgrammaticToolCallingParams = {
280
380
  proxy?: string;
281
381
  /** Enable debug logging (or set PTC_DEBUG=true env var) */
282
382
  debug?: boolean;
283
- /** Environment variable key for API key */
284
- [key: string]: unknown;
285
383
  };
286
384
  /**
287
385
  * Tracks code execution session state for automatic file persistence.
@@ -10,6 +10,15 @@
10
10
  * larger than this is almost certainly a bug (e.g., dumping a binary file).
11
11
  */
12
12
  export declare const HARD_MAX_TOOL_RESULT_CHARS = 400000;
13
+ /**
14
+ * Absolute hard cap on the aggregate size (characters) of all registered
15
+ * tool outputs kept for `{{tool<i>turn<n>}}` substitution. Set at 5 MB
16
+ * because the registry stores *raw, untruncated* tool output — full
17
+ * fidelity for piping into downstream bash/jq — so the budget needs
18
+ * enough headroom to keep a handful of large responses without
19
+ * ballooning unbounded.
20
+ */
21
+ export declare const HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE = 5000000;
13
22
  /**
14
23
  * Computes the dynamic max tool result size based on the model's context window.
15
24
  * Uses 30% of the context window (in estimated characters, ~4 chars/token)
@@ -19,6 +28,18 @@ export declare const HARD_MAX_TOOL_RESULT_CHARS = 400000;
19
28
  * @returns Maximum allowed characters for a single tool result.
20
29
  */
21
30
  export declare function calculateMaxToolResultChars(contextWindowTokens?: number): number;
31
+ /**
32
+ * Computes the default aggregate size (characters) for the tool output
33
+ * reference registry based on the per-output budget. Mirrors
34
+ * `calculateMaxToolResultChars`'s shape: a multiple of the per-output
35
+ * cap, clamped to `HARD_MAX_TOTAL_TOOL_OUTPUT_SIZE`.
36
+ *
37
+ * @param maxOutputSize - Per-output maximum characters (e.g., the
38
+ * ToolNode's `maxToolResultChars`). When omitted or non-positive,
39
+ * falls back to the absolute total cap.
40
+ * @returns Maximum total characters retained across the registry.
41
+ */
42
+ export declare function calculateMaxTotalToolOutputSize(maxOutputSize?: number): number;
22
43
  /**
23
44
  * Truncates a tool-call input (the arguments/payload of a tool_use block)
24
45
  * using head+tail strategy. Returns an object with `_truncated` (the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.1.68",
3
+ "version": "3.1.71-dev.0",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -61,6 +61,9 @@
61
61
  "tool": "node --trace-warnings -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tools.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
62
62
  "search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/search.ts --provider 'bedrock' --name 'Jo' --location 'New York, NY'",
63
63
  "tool_search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tool_search.ts",
64
+ "subagent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-subagent.ts",
65
+ "subagent:events": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/subagent-event-driven-debug.ts",
66
+ "subagent:tools": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/subagent-tools-debug.ts",
64
67
  "programmatic_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec.ts",
65
68
  "code_exec_ptc": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_ptc.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
66
69
  "programmatic_exec_agent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/programmatic_exec_agent.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
@@ -77,6 +80,7 @@
77
80
  "multi-agent-chain": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-chain.ts",
78
81
  "multi-agent-sequence": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-sequence.ts",
79
82
  "multi-agent-conditional": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-conditional.ts",
83
+ "multi-agent-subagent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-subagent.ts",
80
84
  "multi-agent-supervisor": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-supervisor.ts",
81
85
  "test-handoff-preamble": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-handoff-preamble.ts",
82
86
  "multi-agent-list-handoff": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/test-multi-agent-list-handoff.ts",