@librechat/agents 3.3.4 → 3.3.6

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 (263) hide show
  1. package/dist/cjs/common/constants.cjs +21 -0
  2. package/dist/cjs/common/constants.cjs.map +1 -1
  3. package/dist/cjs/events.cjs +10 -1
  4. package/dist/cjs/events.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +456 -7
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/hooks/HookRegistry.cjs +25 -0
  8. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  9. package/dist/cjs/hooks/createWorkspacePolicyHook.cjs +1 -1
  10. package/dist/cjs/hooks/index.cjs +12 -0
  11. package/dist/cjs/hooks/index.cjs.map +1 -1
  12. package/dist/cjs/hooks/types.cjs +1 -0
  13. package/dist/cjs/hooks/types.cjs.map +1 -1
  14. package/dist/cjs/langfuse.cjs +8 -0
  15. package/dist/cjs/langfuse.cjs.map +1 -1
  16. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +1 -3
  17. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  18. package/dist/cjs/llm/invoke.cjs +268 -3
  19. package/dist/cjs/llm/invoke.cjs.map +1 -1
  20. package/dist/cjs/llm/openai/index.cjs +51 -6
  21. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  22. package/dist/cjs/llm/preempt.cjs +132 -0
  23. package/dist/cjs/llm/preempt.cjs.map +1 -0
  24. package/dist/cjs/main.cjs +31 -3
  25. package/dist/cjs/messages/alternation.cjs +92 -0
  26. package/dist/cjs/messages/alternation.cjs.map +1 -0
  27. package/dist/cjs/messages/format.cjs +72 -0
  28. package/dist/cjs/messages/format.cjs.map +1 -1
  29. package/dist/cjs/messages/handoffCue.cjs +63 -0
  30. package/dist/cjs/messages/handoffCue.cjs.map +1 -0
  31. package/dist/cjs/messages/index.cjs +3 -0
  32. package/dist/cjs/messages/injected.cjs +60 -0
  33. package/dist/cjs/messages/injected.cjs.map +1 -0
  34. package/dist/cjs/run.cjs +80 -7
  35. package/dist/cjs/run.cjs.map +1 -1
  36. package/dist/cjs/session/JsonlSessionStore.cjs +1 -1
  37. package/dist/cjs/session/handlers.cjs +18 -9
  38. package/dist/cjs/session/handlers.cjs.map +1 -1
  39. package/dist/cjs/stream.cjs +34 -8
  40. package/dist/cjs/stream.cjs.map +1 -1
  41. package/dist/cjs/tools/BashExecutor.cjs +3 -1
  42. package/dist/cjs/tools/BashExecutor.cjs.map +1 -1
  43. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs +2 -0
  44. package/dist/cjs/tools/BashProgrammaticToolCalling.cjs.map +1 -1
  45. package/dist/cjs/tools/CodeExecutor.cjs +19 -16
  46. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  47. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +2 -0
  48. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  49. package/dist/cjs/tools/ReadFile.cjs +8 -4
  50. package/dist/cjs/tools/ReadFile.cjs.map +1 -1
  51. package/dist/cjs/tools/SkillTool.cjs +2 -0
  52. package/dist/cjs/tools/SkillTool.cjs.map +1 -1
  53. package/dist/cjs/tools/SubagentTool.cjs +3 -0
  54. package/dist/cjs/tools/SubagentTool.cjs.map +1 -1
  55. package/dist/cjs/tools/ToolNode.cjs +91 -50
  56. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  57. package/dist/cjs/tools/ToolSearch.cjs +5 -1
  58. package/dist/cjs/tools/ToolSearch.cjs.map +1 -1
  59. package/dist/cjs/tools/intentArg.cjs +230 -0
  60. package/dist/cjs/tools/intentArg.cjs.map +1 -0
  61. package/dist/cjs/tools/local/CompileCheckTool.cjs +3 -2
  62. package/dist/cjs/tools/local/CompileCheckTool.cjs.map +1 -1
  63. package/dist/cjs/tools/local/LocalCodingTools.cjs +13 -12
  64. package/dist/cjs/tools/local/LocalCodingTools.cjs.map +1 -1
  65. package/dist/cjs/tools/local/LocalExecutionEngine.cjs +2 -2
  66. package/dist/cjs/tools/ptcTimeout.cjs.map +1 -1
  67. package/dist/cjs/tools/search/keenable-scraper.cjs +90 -0
  68. package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -0
  69. package/dist/cjs/tools/search/schema.cjs +2 -0
  70. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  71. package/dist/cjs/tools/search/tool.cjs +40 -2
  72. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  73. package/dist/cjs/tools/subagent/SubagentExecutor.cjs +1 -0
  74. package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
  75. package/dist/cjs/tools/toolOutputReferences.cjs +41 -7
  76. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  77. package/dist/esm/common/constants.mjs +19 -1
  78. package/dist/esm/common/constants.mjs.map +1 -1
  79. package/dist/esm/events.mjs +10 -1
  80. package/dist/esm/events.mjs.map +1 -1
  81. package/dist/esm/graphs/Graph.mjs +455 -6
  82. package/dist/esm/graphs/Graph.mjs.map +1 -1
  83. package/dist/esm/hooks/HookRegistry.mjs +25 -0
  84. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  85. package/dist/esm/hooks/createWorkspacePolicyHook.mjs +1 -1
  86. package/dist/esm/hooks/index.mjs +12 -1
  87. package/dist/esm/hooks/index.mjs.map +1 -1
  88. package/dist/esm/hooks/types.mjs +1 -0
  89. package/dist/esm/hooks/types.mjs.map +1 -1
  90. package/dist/esm/langfuse.mjs +9 -1
  91. package/dist/esm/langfuse.mjs.map +1 -1
  92. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +1 -3
  93. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  94. package/dist/esm/llm/invoke.mjs +270 -6
  95. package/dist/esm/llm/invoke.mjs.map +1 -1
  96. package/dist/esm/llm/openai/index.mjs +51 -6
  97. package/dist/esm/llm/openai/index.mjs.map +1 -1
  98. package/dist/esm/llm/preempt.mjs +131 -0
  99. package/dist/esm/llm/preempt.mjs.map +1 -0
  100. package/dist/esm/main.mjs +11 -7
  101. package/dist/esm/messages/alternation.mjs +91 -0
  102. package/dist/esm/messages/alternation.mjs.map +1 -0
  103. package/dist/esm/messages/format.mjs +72 -0
  104. package/dist/esm/messages/format.mjs.map +1 -1
  105. package/dist/esm/messages/handoffCue.mjs +61 -0
  106. package/dist/esm/messages/handoffCue.mjs.map +1 -0
  107. package/dist/esm/messages/index.mjs +3 -0
  108. package/dist/esm/messages/injected.mjs +60 -0
  109. package/dist/esm/messages/injected.mjs.map +1 -0
  110. package/dist/esm/run.mjs +80 -7
  111. package/dist/esm/run.mjs.map +1 -1
  112. package/dist/esm/session/JsonlSessionStore.mjs +1 -1
  113. package/dist/esm/session/handlers.mjs +19 -10
  114. package/dist/esm/session/handlers.mjs.map +1 -1
  115. package/dist/esm/stream.mjs +33 -9
  116. package/dist/esm/stream.mjs.map +1 -1
  117. package/dist/esm/tools/BashExecutor.mjs +3 -1
  118. package/dist/esm/tools/BashExecutor.mjs.map +1 -1
  119. package/dist/esm/tools/BashProgrammaticToolCalling.mjs +2 -0
  120. package/dist/esm/tools/BashProgrammaticToolCalling.mjs.map +1 -1
  121. package/dist/esm/tools/CodeExecutor.mjs +19 -16
  122. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  123. package/dist/esm/tools/ProgrammaticToolCalling.mjs +2 -0
  124. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  125. package/dist/esm/tools/ReadFile.mjs +8 -4
  126. package/dist/esm/tools/ReadFile.mjs.map +1 -1
  127. package/dist/esm/tools/SkillTool.mjs +2 -0
  128. package/dist/esm/tools/SkillTool.mjs.map +1 -1
  129. package/dist/esm/tools/SubagentTool.mjs +3 -0
  130. package/dist/esm/tools/SubagentTool.mjs.map +1 -1
  131. package/dist/esm/tools/ToolNode.mjs +91 -51
  132. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  133. package/dist/esm/tools/ToolSearch.mjs +5 -1
  134. package/dist/esm/tools/ToolSearch.mjs.map +1 -1
  135. package/dist/esm/tools/intentArg.mjs +220 -0
  136. package/dist/esm/tools/intentArg.mjs.map +1 -0
  137. package/dist/esm/tools/local/CompileCheckTool.mjs +3 -2
  138. package/dist/esm/tools/local/CompileCheckTool.mjs.map +1 -1
  139. package/dist/esm/tools/local/LocalCodingTools.mjs +13 -12
  140. package/dist/esm/tools/local/LocalCodingTools.mjs.map +1 -1
  141. package/dist/esm/tools/local/LocalExecutionEngine.mjs +2 -2
  142. package/dist/esm/tools/ptcTimeout.mjs.map +1 -1
  143. package/dist/esm/tools/search/keenable-scraper.mjs +88 -0
  144. package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -0
  145. package/dist/esm/tools/search/schema.mjs +2 -0
  146. package/dist/esm/tools/search/schema.mjs.map +1 -1
  147. package/dist/esm/tools/search/tool.mjs +40 -3
  148. package/dist/esm/tools/search/tool.mjs.map +1 -1
  149. package/dist/esm/tools/subagent/SubagentExecutor.mjs +1 -0
  150. package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
  151. package/dist/esm/tools/toolOutputReferences.mjs +41 -7
  152. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  153. package/dist/types/common/constants.d.ts +18 -0
  154. package/dist/types/graphs/Graph.d.ts +138 -1
  155. package/dist/types/hooks/HookRegistry.d.ts +15 -0
  156. package/dist/types/hooks/index.d.ts +12 -1
  157. package/dist/types/hooks/types.d.ts +45 -6
  158. package/dist/types/index.d.ts +2 -1
  159. package/dist/types/llm/invoke.d.ts +7 -0
  160. package/dist/types/llm/openai/index.d.ts +0 -11
  161. package/dist/types/llm/preempt.d.ts +40 -0
  162. package/dist/types/messages/alternation.d.ts +23 -0
  163. package/dist/types/messages/handoffCue.d.ts +40 -0
  164. package/dist/types/messages/index.d.ts +3 -0
  165. package/dist/types/messages/injected.d.ts +3 -0
  166. package/dist/types/run.d.ts +7 -0
  167. package/dist/types/stream.d.ts +14 -0
  168. package/dist/types/tools/BashExecutor.d.ts +18 -0
  169. package/dist/types/tools/CodeExecutor.d.ts +18 -0
  170. package/dist/types/tools/ReadFile.d.ts +18 -0
  171. package/dist/types/tools/SkillTool.d.ts +18 -0
  172. package/dist/types/tools/SubagentTool.d.ts +9 -0
  173. package/dist/types/tools/ToolNode.d.ts +37 -12
  174. package/dist/types/tools/ToolSearch.d.ts +18 -0
  175. package/dist/types/tools/intentArg.d.ts +119 -0
  176. package/dist/types/tools/ptcTimeout.d.ts +2 -0
  177. package/dist/types/tools/search/keenable-scraper.d.ts +15 -0
  178. package/dist/types/tools/search/schema.d.ts +18 -0
  179. package/dist/types/tools/search/tool.d.ts +18 -0
  180. package/dist/types/tools/search/types.d.ts +31 -2
  181. package/dist/types/tools/toolOutputReferences.d.ts +12 -2
  182. package/dist/types/types/graph.d.ts +8 -1
  183. package/dist/types/types/run.d.ts +65 -0
  184. package/dist/types/types/stream.d.ts +12 -25
  185. package/dist/types/types/tools.d.ts +27 -2
  186. package/package.json +1 -1
  187. package/src/{splitStream.test.ts → aggregator.test.ts} +59 -666
  188. package/src/common/constants.ts +21 -0
  189. package/src/events.ts +15 -1
  190. package/src/graphs/Graph.ts +568 -3
  191. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +18 -7
  192. package/src/graphs/__tests__/Graph.preemptSignal.test.ts +126 -0
  193. package/src/hooks/HookRegistry.ts +40 -0
  194. package/src/hooks/__tests__/preemptBoundary.test.ts +152 -0
  195. package/src/hooks/index.ts +16 -2
  196. package/src/hooks/types.ts +47 -3
  197. package/src/index.ts +2 -1
  198. package/src/langfuse.ts +26 -1
  199. package/src/llm/bedrock/utils/message_inputs.test.ts +82 -0
  200. package/src/llm/bedrock/utils/message_inputs.ts +14 -11
  201. package/src/llm/bedrock/utils/toolResultCachePoint.test.ts +15 -0
  202. package/src/llm/invoke.alternation.test.ts +87 -0
  203. package/src/llm/invoke.handoffCue.test.ts +112 -0
  204. package/src/llm/invoke.ts +417 -8
  205. package/src/llm/openai/index.ts +74 -10
  206. package/src/llm/openai/llm.spec.ts +105 -0
  207. package/src/llm/preempt.test.ts +323 -0
  208. package/src/llm/preempt.ts +178 -0
  209. package/src/messages/alternation.test.ts +212 -0
  210. package/src/messages/alternation.ts +112 -0
  211. package/src/messages/format.ts +91 -0
  212. package/src/messages/formatAgentMessages.steer.test.ts +267 -0
  213. package/src/messages/handoffCue.test.ts +96 -0
  214. package/src/messages/handoffCue.ts +78 -0
  215. package/src/messages/index.ts +3 -0
  216. package/src/messages/injected.test.ts +90 -0
  217. package/src/messages/injected.ts +74 -0
  218. package/src/run.ts +91 -6
  219. package/src/scripts/preempt-probe.ts +330 -0
  220. package/src/scripts/preempt-scenarios.ts +388 -0
  221. package/src/session/handlers.ts +32 -12
  222. package/src/specs/handoffCue.test.ts +165 -0
  223. package/src/specs/langfuse-callbacks.test.ts +352 -2
  224. package/src/specs/preemptSeal.test.ts +309 -0
  225. package/src/stream.dispatch.test.ts +63 -0
  226. package/src/stream.ts +48 -9
  227. package/src/tools/BashExecutor.ts +6 -0
  228. package/src/tools/BashProgrammaticToolCalling.ts +2 -0
  229. package/src/tools/CodeExecutor.ts +6 -0
  230. package/src/tools/ProgrammaticToolCalling.ts +2 -0
  231. package/src/tools/ReadFile.ts +2 -0
  232. package/src/tools/SkillTool.ts +2 -0
  233. package/src/tools/SubagentTool.ts +3 -0
  234. package/src/tools/ToolNode.ts +193 -74
  235. package/src/tools/ToolSearch.ts +3 -0
  236. package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +174 -0
  237. package/src/tools/__tests__/intentArg.test.ts +281 -0
  238. package/src/tools/__tests__/intentCoverage.test.ts +139 -0
  239. package/src/tools/__tests__/toolOutputReferences.test.ts +83 -0
  240. package/src/tools/intentArg.ts +323 -0
  241. package/src/tools/local/CompileCheckTool.ts +4 -3
  242. package/src/tools/local/LocalCodingTools.ts +14 -13
  243. package/src/tools/ptcTimeout.ts +2 -0
  244. package/src/tools/search/keenable-scraper.test.ts +153 -0
  245. package/src/tools/search/keenable-scraper.ts +137 -0
  246. package/src/tools/search/outcome.test.ts +90 -0
  247. package/src/tools/search/schema.ts +3 -0
  248. package/src/tools/search/tool.ts +60 -3
  249. package/src/tools/search/types.ts +50 -3
  250. package/src/tools/subagent/SubagentExecutor.ts +2 -1
  251. package/src/tools/toolOutputReferences.ts +77 -9
  252. package/src/types/graph.ts +12 -1
  253. package/src/types/run.ts +67 -0
  254. package/src/types/stream.ts +12 -41
  255. package/src/types/tools.ts +24 -2
  256. package/dist/cjs/splitStream.cjs +0 -151
  257. package/dist/cjs/splitStream.cjs.map +0 -1
  258. package/dist/esm/splitStream.mjs +0 -150
  259. package/dist/esm/splitStream.mjs.map +0 -1
  260. package/dist/types/mockStream.d.ts +0 -32
  261. package/dist/types/splitStream.d.ts +0 -37
  262. package/src/mockStream.ts +0 -99
  263. package/src/splitStream.ts +0 -234
@@ -8,7 +8,7 @@ import type { InjectedMessage } from '@/types/tools';
8
8
  * `docs/hooks-design-report.md` §3.2 for the mapping to existing
9
9
  * `@librechat/agents` emission points.
10
10
  */
11
- export declare const HOOK_EVENTS: readonly ["RunStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PostToolUseFailure", "PostToolBatch", "PermissionDenied", "SubagentStart", "SubagentStop", "Stop", "StopFailure", "PreCompact", "PostCompact"];
11
+ export declare const HOOK_EVENTS: readonly ["RunStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PostToolUseFailure", "PostToolBatch", "PreemptBoundary", "PermissionDenied", "SubagentStart", "SubagentStop", "Stop", "StopFailure", "PreCompact", "PostCompact"];
12
12
  export type HookEvent = (typeof HOOK_EVENTS)[number];
13
13
  /** Tool-gating decision; executeHooks folds with `deny > ask > allow` precedence. */
14
14
  export type ToolDecision = 'allow' | 'deny' | 'ask';
@@ -117,6 +117,38 @@ export interface PostToolBatchHookInput extends BaseHookInput {
117
117
  /** All tool calls (and their outcomes) from this batch, in batch order. */
118
118
  entries: PostToolBatchEntry[];
119
119
  }
120
+ /**
121
+ * Fires when a cooperative preemption seals the model stream mid-generation
122
+ * — the second injection boundary, and the only one that exists during a
123
+ * long text answer with no tool calls in it.
124
+ *
125
+ * Order: fires after the model stream is sealed and BEFORE the next model
126
+ * call. The `injectedMessages` a hook returns here are appended verbatim and
127
+ * the agent node self-loops. Returning nothing is a valid outcome (the host's
128
+ * queue was cancelled or already drained): the run stops honestly rather than
129
+ * self-looping into an empty turn.
130
+ *
131
+ * The sealed turn is NOT yet observable from graph state when this fires.
132
+ * Dispatch happens inside the agent node, and only the outer graph's reducer
133
+ * writes `StandardGraph.messages` — which cannot run until the node returns.
134
+ * A hook calling `Run.getRunMessages()` here sees the state as of the last
135
+ * completed superstep, so the sealed text is absent. `PostToolBatch` behaves
136
+ * the same way: a tool-boundary hook cannot see the assistant turn that
137
+ * requested the tool. This is a property of the single-node outer graph, not
138
+ * of preemption, and committing first would mean returning from the node and
139
+ * re-entering — precisely what the self-loop exists to avoid.
140
+ *
141
+ * A hook that needs the sealed text should therefore not go looking for it in
142
+ * graph state. Decide from the host's own queue, or read it after the run.
143
+ *
144
+ * Requires `RunConfig.preemption`. This event is deliberately NOT
145
+ * result-altering, so registering it never disables eager tool execution.
146
+ */
147
+ export interface PreemptBoundaryHookInput extends BaseHookInput {
148
+ hook_event_name: 'PreemptBoundary';
149
+ /** 1-based index of this seal within the run. */
150
+ sealCount: number;
151
+ }
120
152
  export interface PermissionDeniedHookInput extends BaseHookInput {
121
153
  hook_event_name: 'PermissionDenied';
122
154
  toolName: string;
@@ -170,7 +202,7 @@ export interface PostCompactHookInput extends BaseHookInput {
170
202
  messagesAfterCount: number;
171
203
  }
172
204
  /** Discriminated union of every hook input shape. */
173
- export type HookInput = RunStartHookInput | UserPromptSubmitHookInput | PreToolUseHookInput | PostToolUseHookInput | PostToolUseFailureHookInput | PostToolBatchHookInput | PermissionDeniedHookInput | SubagentStartHookInput | SubagentStopHookInput | StopHookInput | StopFailureHookInput | PreCompactHookInput | PostCompactHookInput;
205
+ export type HookInput = RunStartHookInput | UserPromptSubmitHookInput | PreToolUseHookInput | PostToolUseHookInput | PostToolUseFailureHookInput | PostToolBatchHookInput | PreemptBoundaryHookInput | PermissionDeniedHookInput | SubagentStartHookInput | SubagentStopHookInput | StopHookInput | StopFailureHookInput | PreCompactHookInput | PostCompactHookInput;
174
206
  /** Compile-time map from event name to its input shape. */
175
207
  export type HookInputByEvent = {
176
208
  RunStart: RunStartHookInput;
@@ -179,6 +211,7 @@ export type HookInputByEvent = {
179
211
  PostToolUse: PostToolUseHookInput;
180
212
  PostToolUseFailure: PostToolUseFailureHookInput;
181
213
  PostToolBatch: PostToolBatchHookInput;
214
+ PreemptBoundary: PreemptBoundaryHookInput;
182
215
  PermissionDenied: PermissionDeniedHookInput;
183
216
  SubagentStart: SubagentStartHookInput;
184
217
  SubagentStop: SubagentStopHookInput;
@@ -196,14 +229,18 @@ export interface BaseHookOutput {
196
229
  additionalContext?: string;
197
230
  /**
198
231
  * Messages to inject into graph state, one `HumanMessage` per entry
199
- * (converted via `ToolNode.convertInjectedMessages`, which preserves
232
+ * (converted via `convertInjectedMessages`, which preserves
200
233
  * `role`/`source`/`isMeta` in `additional_kwargs`). Unlike
201
234
  * `additionalContext` — which is consolidated across hooks into a single
202
235
  * system-flavored message — each entry keeps its own identity and role,
203
236
  * making this the channel for injecting verbatim user speech (e.g. a
204
237
  * mid-run steering message). Accumulated across hooks in registration
205
- * order. Currently consumed only at the `PostToolBatch` dispatch site;
206
- * other events ignore the field.
238
+ * order.
239
+ *
240
+ * Consumed at exactly two dispatch sites, both of which run the same
241
+ * converter so the emitted shapes cannot drift: `PostToolBatch` (the tool
242
+ * boundary) and `PreemptBoundary` (a cooperative mid-generation seal).
243
+ * Every other event ignores the field.
207
244
  */
208
245
  injectedMessages?: InjectedMessage[];
209
246
  /** True to prevent the next model turn. Any hook can set this. */
@@ -305,6 +342,7 @@ export interface PostToolUseHookOutput extends BaseHookOutput {
305
342
  }
306
343
  export type PostToolUseFailureHookOutput = BaseHookOutput;
307
344
  export type PostToolBatchHookOutput = BaseHookOutput;
345
+ export type PreemptBoundaryHookOutput = BaseHookOutput;
308
346
  export type PermissionDeniedHookOutput = BaseHookOutput;
309
347
  export interface SubagentStartHookOutput extends BaseHookOutput {
310
348
  decision?: ToolDecision;
@@ -326,6 +364,7 @@ export type HookOutputByEvent = {
326
364
  PostToolUse: PostToolUseHookOutput;
327
365
  PostToolUseFailure: PostToolUseFailureHookOutput;
328
366
  PostToolBatch: PostToolBatchHookOutput;
367
+ PreemptBoundary: PreemptBoundaryHookOutput;
329
368
  PermissionDenied: PermissionDeniedHookOutput;
330
369
  SubagentStart: SubagentStartHookOutput;
331
370
  SubagentStop: SubagentStopHookOutput;
@@ -335,7 +374,7 @@ export type HookOutputByEvent = {
335
374
  PostCompact: PostCompactHookOutput;
336
375
  };
337
376
  /** Superset output shape used by the executor's fold loop. */
338
- export type HookOutput = RunStartHookOutput | UserPromptSubmitHookOutput | PreToolUseHookOutput | PostToolUseHookOutput | PostToolUseFailureHookOutput | PostToolBatchHookOutput | PermissionDeniedHookOutput | SubagentStartHookOutput | SubagentStopHookOutput | StopHookOutput | StopFailureHookOutput | PreCompactHookOutput | PostCompactHookOutput;
377
+ export type HookOutput = RunStartHookOutput | UserPromptSubmitHookOutput | PreToolUseHookOutput | PostToolUseHookOutput | PostToolUseFailureHookOutput | PostToolBatchHookOutput | PreemptBoundaryHookOutput | PermissionDeniedHookOutput | SubagentStartHookOutput | SubagentStopHookOutput | StopHookOutput | StopFailureHookOutput | PreCompactHookOutput | PostCompactHookOutput;
339
378
  /**
340
379
  * A hook callback is a plain async function registered against a specific
341
380
  * event. The `signal` is always supplied by `executeHooks` and combines the
@@ -1,6 +1,5 @@
1
1
  export * from './run';
2
2
  export * from './stream';
3
- export * from './splitStream';
4
3
  export * from './events';
5
4
  export * from './messages';
6
5
  export * from './graphs';
@@ -18,6 +17,7 @@ export * from './tools/ReadFile';
18
17
  export * from './tools/skillCatalog';
19
18
  export * from './tools/ToolSearch';
20
19
  export * from './tools/ToolNode';
20
+ export * from './tools/intentArg';
21
21
  export * from './tools/schema';
22
22
  export * from './tools/handlers';
23
23
  export * from './tools/local';
@@ -45,4 +45,5 @@ export { getChatModelClass } from './llm/providers';
45
45
  export { FakeChatModel, createFakeStreamingLLM } from './llm/fake';
46
46
  export { initializeModel } from './llm/init';
47
47
  export { attemptInvoke, tryFallbackProviders } from './llm/invoke';
48
+ export { canSealPreempt } from './llm/preempt';
48
49
  export { isThinkingEnabled, getMaxOutputTokensKey } from './llm/request';
@@ -54,6 +54,13 @@ export declare function projectMessagesForProvider({ model, messages, provider,
54
54
  maxToolResultChars?: number;
55
55
  callOptions?: unknown;
56
56
  }): BaseMessage[];
57
+ /**
58
+ * The serving model's id, read through the same wrapper stack
59
+ * `collectModelCallbackSources` walks — `bindTools` returns a
60
+ * `RunnableBinding` and a system runnable pipes a `RunnableSequence`, and
61
+ * neither exposes the chat model's `model` at the top level.
62
+ */
63
+ export declare function resolveServingModelId(model: unknown): string | undefined;
57
64
  /**
58
65
  * Invokes a chat model with the given messages, handling both streaming and
59
66
  * non-streaming paths.
@@ -42,17 +42,6 @@ export declare function shouldIncludeEncryptedReasoning(model: string, params: {
42
42
  reasoning?: unknown;
43
43
  }): boolean;
44
44
  export declare function emitStreamChunkCallback(chunk: ChatGenerationChunk, runManager?: CallbackManagerForLLMRun): Promise<void>;
45
- /**
46
- * Formats a tool in either OpenAI format, or LangChain structured tool format
47
- * into an OpenAI tool format. If the tool is already in OpenAI format, return without
48
- * any changes. If it is in LangChain structured tool format, convert it to OpenAI tool format
49
- * using OpenAI's `zodFunction` util, falling back to `convertToOpenAIFunction` if the parameters
50
- * returned from the `zodFunction` util are not defined.
51
- *
52
- * @param {BindToolsInput} tool The tool to convert to an OpenAI tool.
53
- * @param {Object} [fields] Additional fields to add to the OpenAI tool.
54
- * @returns {ToolDefinition} The inputted tool in OpenAI tool format.
55
- */
56
45
  export declare function _convertToOpenAITool(tool: BindToolsInput, fields?: {
57
46
  /**
58
47
  * If `true`, model output is guaranteed to exactly match the JSON Schema
@@ -0,0 +1,40 @@
1
+ import type { AIMessageChunk } from '@langchain/core/messages';
2
+ /**
3
+ * Normalizes a host-supplied seal budget.
4
+ *
5
+ * Read in two places that interpret it differently — a numeric comparison in
6
+ * the seal gate and an addition into the recursion limit — so a value like
7
+ * `1.5` would permit two seals while reserving fractional headroom, `NaN`
8
+ * would poison the recursion limit outright, and `Infinity` would remove both
9
+ * bounds at once. Normalizing once keeps the two readings in agreement.
10
+ *
11
+ * `0` is honored as a deliberate "never seal"; anything not finite falls back
12
+ * to the default rather than silently disabling the feature.
13
+ */
14
+ export declare function resolveMaxSeals(maxSeals: number | undefined): number;
15
+ /**
16
+ * Cooperative mid-generation seal gate. Returns true ONLY when sealing here
17
+ * yields a message sequence valid on EVERY supported provider:
18
+ * - non-whitespace TEXT content, so the FIRST injected user turn is preceded
19
+ * by a non-empty assistant turn — no empty-content 400s. Note this says
20
+ * nothing about adjacency AMONG several injected turns: a boundary that
21
+ * drains two steers emits two consecutive user messages, which strict
22
+ * providers reject. That is normalized at the provider-facing hop by
23
+ * `coalesceAdjacentUserTurns`, not here;
24
+ * - no tool call in flight, so no `tool_use` can be orphaned AND no eagerly
25
+ * prestarted execution can be stripped out from under the model.
26
+ *
27
+ * Anthropic's server-side tools need no check of their own. Every
28
+ * `server_tool_use` content block also emits a `tool_call_chunk`
29
+ * (`_makeMessageChunkFromAnthropicEvent`), and `concat` keeps that chunk on
30
+ * the accumulated message for the remainder of the turn, so the tool-call
31
+ * gates below already cover it. The practical consequence is worth stating
32
+ * plainly: once a turn starts a web search it is no longer preemptible, and
33
+ * a queued message waits for the ordinary tool boundary instead.
34
+ *
35
+ * Nothing is stripped and nothing is repaired: when the accumulated shape is
36
+ * not already safe the stream simply runs on, and whatever the host queued
37
+ * lands at the next tool boundary instead. Chunks accumulate monotonically
38
+ * through `concat`, so an unsafe shape can never be observed at a seal point.
39
+ */
40
+ export declare function canSealPreempt(chunk: AIMessageChunk | undefined): boolean;
@@ -0,0 +1,23 @@
1
+ import type { BaseMessage } from '@langchain/core/messages';
2
+ import { Providers } from '@/common';
3
+ /**
4
+ * Providers whose APIs specify strict user/assistant alternation. Mistral
5
+ * rejects consecutive user turns outright. Bedrock's Converse API documents
6
+ * the alternation requirement across many model families; enforcement varies
7
+ * by family — Claude on Converse currently tolerates adjacent user turns
8
+ * (verified live, 2026-07-28) — so the payload is normalized for all of them
9
+ * rather than betting on per-family leniency. Anthropic's own Messages API,
10
+ * OpenAI and Gemini all accept consecutive user turns, so they are
11
+ * deliberately absent.
12
+ */
13
+ export declare const strictAlternationProviders: ReadonlySet<Providers>;
14
+ /**
15
+ * Merges runs of consecutive human turns into one, for providers that reject
16
+ * them. Purely a wire-shaping pass: it returns a new array of new messages,
17
+ * so graph state and the host's persisted messages keep the per-message
18
+ * identity that steer rendering and the trailing-steer anchor rely on.
19
+ *
20
+ * Tool-result turns are excluded — the converters merge those themselves, and
21
+ * combining one with a text turn would orphan the pairing.
22
+ */
23
+ export declare function coalesceAdjacentUserTurns(messages: BaseMessage[]): BaseMessage[];
@@ -0,0 +1,40 @@
1
+ import type { BaseMessage } from '@langchain/core/messages';
2
+ /**
3
+ * Bracketed-meta convention, like the handoff path's
4
+ * `[Processed tool result and transferring to …]` bridge. The wording makes
5
+ * two things unambiguous to the model: the assistant turn above is FINISHED,
6
+ * and it belongs to a previous stage — so the successor answers as itself
7
+ * instead of continuing someone else's sentence.
8
+ */
9
+ export declare const PREDECESSOR_HANDOFF_CUE: string;
10
+ /**
11
+ * Appends a user-turn handoff cue when a payload ends with an assistant turn
12
+ * that THIS RUN produced — which only happens when a different agent in a
13
+ * multi-agent workflow produced it (an agent's own self-loops always re-enter
14
+ * on a tool result or an injected user turn).
15
+ *
16
+ * Why: providers with prefill semantics (Anthropic, Bedrock-Claude) treat a
17
+ * trailing assistant message as a prefill and CONTINUE it. A bare direct-edge
18
+ * successor therefore speaks in its predecessor's voice — or, when the
19
+ * trailing turn reads complete (a preemption steer's short resume, say),
20
+ * returns empty content (danny-avila/agents#345, reproduced live 3/3).
21
+ * Handoff edges with instructions and prompt-instruction edges already break
22
+ * the prefill with a user turn; this closes the same gap for bare edges.
23
+ *
24
+ * Fail-safe OFF by provenance: the trailing payload message must be one the
25
+ * run itself produced (`isRunProduced`, backed by the graph's run-produced id
26
+ * set — immune to summarization compaction, which rewrites the live array
27
+ * and stales index-based boundaries). Host-supplied trailing assistant
28
+ * turns (deliberate prefill flows) never match — the run has not produced
29
+ * them — so single-agent prefill behavior is untouched. Wire-only: the cue is
30
+ * appended to the provider projection, never to graph state or host history.
31
+ */
32
+ export declare function appendPredecessorHandoffCue(messages: BaseMessage[], isRunProduced: ((message: BaseMessage) => boolean) | undefined): BaseMessage[];
33
+ /**
34
+ * Strips a trailing handoff cue. The counterpart for the serving-provider
35
+ * funnel: an Anthropic-like PRIMARY bakes the cue into its measured payload,
36
+ * and a tolerant fallback (OpenAI, Mistral, Bedrock-Nova) re-sending that
37
+ * payload must not ship the Claude-only synthetic turn. Identity on the
38
+ * no-op path.
39
+ */
40
+ export declare function removePredecessorHandoffCue(messages: BaseMessage[]): BaseMessage[];
@@ -7,6 +7,9 @@ export * from './cache';
7
7
  export * from './anthropicToolCache';
8
8
  export * from './content';
9
9
  export * from './tools';
10
+ export * from './injected';
11
+ export * from './alternation';
12
+ export * from './handoffCue';
10
13
  export * from './contextPruning';
11
14
  export * from './contextPruningSettings';
12
15
  export * from './reducer';
@@ -0,0 +1,3 @@
1
+ import type { BaseMessage } from '@langchain/core/messages';
2
+ import type { InjectedMessage } from '@/types/tools';
3
+ export declare function convertInjectedMessages(messages: InjectedMessage[]): BaseMessage[];
@@ -17,6 +17,7 @@ export declare class Run<_T extends t.BaseGraphState> {
17
17
  private interruptingToolNames?;
18
18
  private toolExecution?;
19
19
  private subagentUsageSink?;
20
+ private preemption?;
20
21
  private indexTokenCountMap?;
21
22
  calibrationRatio: number;
22
23
  graphRunnable?: t.CompiledStateWorkflow;
@@ -109,6 +110,12 @@ export declare class Run<_T extends t.BaseGraphState> {
109
110
  */
110
111
  getCalibrationRatio(): number;
111
112
  getResolvedInstructionOverhead(): number | undefined;
113
+ /**
114
+ * Cooperative-seal counters for this run. `emptyBoundaries` is the one to
115
+ * watch: it counts seals whose `PreemptBoundary` produced nothing to
116
+ * inject, which ends the turn early and leaves the answer unfinished.
117
+ */
118
+ getPreemptStats(): t.PreemptStats;
112
119
  getToolCount(): number;
113
120
  /**
114
121
  * Creates a custom event callback handler that intercepts custom events
@@ -8,7 +8,21 @@ export declare function getChunkContent({ chunk, provider, reasoningKey, }: {
8
8
  provider?: Providers;
9
9
  reasoningKey: 'reasoning_content' | 'reasoning';
10
10
  }): string | t.MessageContentComplex[] | undefined;
11
+ /**
12
+ * Brands a handler as one that dispatches content parts for the SDK — either
13
+ * `ChatModelStreamHandler` itself or a wrapper forwarding to one.
14
+ *
15
+ * Identity alone is not a usable contract here. Hosts compose and wrap
16
+ * handlers (`composeEventHandlers`, `createRunHandlers`), and every wrapper
17
+ * fails `instanceof` while still driving the same dispatch. A brand survives
18
+ * wrapping, so "does this handler own content-part dispatch" can be answered
19
+ * about a value the SDK did not construct.
20
+ */
21
+ export declare const SDK_STREAM_DISPATCH: unique symbol;
22
+ /** True when `handler` is, or forwards to, the SDK's stream dispatcher. */
23
+ export declare function dispatchesChatModelStream(handler?: t.EventHandler): boolean;
11
24
  export declare class ChatModelStreamHandler implements t.EventHandler {
25
+ readonly [SDK_STREAM_DISPATCH] = true;
12
26
  handle(event: string, data: t.StreamEventData, metadata?: Record<string, unknown>, graph?: StandardGraph): Promise<void>;
13
27
  handleReasoning(chunk: Partial<AIMessageChunk>, agentContext: AgentContext): void;
14
28
  }
@@ -4,6 +4,15 @@ import { Constants } from '@/common';
4
4
  export declare const BashExecutionToolSchema: {
5
5
  readonly type: "object";
6
6
  readonly properties: {
7
+ readonly intent: {
8
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
9
+ readonly enum?: string[];
10
+ readonly items?: t.JsonSchemaType;
11
+ readonly properties?: Record<string, t.JsonSchemaType>;
12
+ readonly required?: string[];
13
+ readonly description?: string;
14
+ readonly additionalProperties?: boolean | t.JsonSchemaType;
15
+ };
7
16
  readonly command: {
8
17
  readonly type: "string";
9
18
  readonly description: "The bash command or script to execute.\n- The environment is stateless; variables and state don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.\n- Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- Use `echo`, `printf`, or `cat` for all outputs.";
@@ -71,6 +80,15 @@ export declare const BashExecutionToolDefinition: {
71
80
  readonly schema: {
72
81
  readonly type: "object";
73
82
  readonly properties: {
83
+ readonly intent: {
84
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
85
+ readonly enum?: string[];
86
+ readonly items?: t.JsonSchemaType;
87
+ readonly properties?: Record<string, t.JsonSchemaType>;
88
+ readonly required?: string[];
89
+ readonly description?: string;
90
+ readonly additionalProperties?: boolean | t.JsonSchemaType;
91
+ };
74
92
  readonly command: {
75
93
  readonly type: "string";
76
94
  readonly description: "The bash command or script to execute.\n- The environment is stateless; variables and state don't persist between executions.\n- Prior /mnt/data files are available and can be modified in place.\n- Persist handoff artifacts in `/mnt/data` with standard extensions (.json/.txt/.csv/.tsv/.log/.parquet/.png/.jpg/.pdf/.xlsx); failed executions do not register new files; `/tmp` and odd extensions are same-call scratch only, not later-call storage.\n- Bash: multi-line files use heredoc/printf; run Python via python3 -c/heredoc, not bare Python.\n- Input code **IS ALREADY** displayed to the user, so **DO NOT** repeat it in your response unless asked.\n- Output code **IS NOT** displayed to the user, so **DO** write all desired output explicitly.\n- IMPORTANT: You MUST explicitly print/output ALL results you want the user to see.\n- Use `echo`, `printf`, or `cat` for all outputs.";
@@ -13,6 +13,15 @@ export declare function appendFailedExecutionFileReminder(output: string, code:
13
13
  export declare const CodeExecutionToolSchema: {
14
14
  readonly type: "object";
15
15
  readonly properties: {
16
+ readonly intent: {
17
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
18
+ readonly enum?: string[];
19
+ readonly items?: t.JsonSchemaType;
20
+ readonly properties?: Record<string, t.JsonSchemaType>;
21
+ readonly required?: string[];
22
+ readonly description?: string;
23
+ readonly additionalProperties?: boolean | t.JsonSchemaType;
24
+ };
16
25
  readonly lang: {
17
26
  readonly type: "string";
18
27
  readonly enum: readonly ["py", "js", "ts", "c", "cpp", "java", "php", "rs", "go", "d", "f90", "r", "bash"];
@@ -74,6 +83,15 @@ export declare const CodeExecutionToolDefinition: {
74
83
  readonly schema: {
75
84
  readonly type: "object";
76
85
  readonly properties: {
86
+ readonly intent: {
87
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
88
+ readonly enum?: string[];
89
+ readonly items?: t.JsonSchemaType;
90
+ readonly properties?: Record<string, t.JsonSchemaType>;
91
+ readonly required?: string[];
92
+ readonly description?: string;
93
+ readonly additionalProperties?: boolean | t.JsonSchemaType;
94
+ };
77
95
  readonly lang: {
78
96
  readonly type: "string";
79
97
  readonly enum: readonly ["py", "js", "ts", "c", "cpp", "java", "php", "rs", "go", "d", "f90", "r", "bash"];
@@ -4,6 +4,15 @@ export declare const ReadFileToolDescription = "Read the contents of a file. Ret
4
4
  export declare const ReadFileToolSchema: {
5
5
  readonly type: "object";
6
6
  readonly properties: {
7
+ readonly intent: {
8
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
9
+ readonly enum?: string[];
10
+ readonly items?: import("..").JsonSchemaType;
11
+ readonly properties?: Record<string, import("..").JsonSchemaType>;
12
+ readonly required?: string[];
13
+ readonly description?: string;
14
+ readonly additionalProperties?: boolean | import("..").JsonSchemaType;
15
+ };
7
16
  readonly path: {
8
17
  readonly type: "string";
9
18
  readonly description: "Path to the file. For skill files: \"{skillName}/{path}\" (e.g. \"pdf-analyzer/src/utils.py\"). For code execution output: the path as returned by the execution tool.";
@@ -17,6 +26,15 @@ export declare const ReadFileToolDefinition: {
17
26
  readonly parameters: {
18
27
  readonly type: "object";
19
28
  readonly properties: {
29
+ readonly intent: {
30
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
31
+ readonly enum?: string[];
32
+ readonly items?: import("..").JsonSchemaType;
33
+ readonly properties?: Record<string, import("..").JsonSchemaType>;
34
+ readonly required?: string[];
35
+ readonly description?: string;
36
+ readonly additionalProperties?: boolean | import("..").JsonSchemaType;
37
+ };
20
38
  readonly path: {
21
39
  readonly type: "string";
22
40
  readonly description: "Path to the file. For skill files: \"{skillName}/{path}\" (e.g. \"pdf-analyzer/src/utils.py\"). For code execution output: the path as returned by the execution tool.";
@@ -9,6 +9,15 @@ export declare const SkillToolDescription = "Invoke a skill from the user's libr
9
9
  export declare const SkillToolSchema: {
10
10
  readonly type: "object";
11
11
  readonly properties: {
12
+ readonly intent: {
13
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
14
+ readonly enum?: string[];
15
+ readonly items?: import("..").JsonSchemaType;
16
+ readonly properties?: Record<string, import("..").JsonSchemaType>;
17
+ readonly required?: string[];
18
+ readonly description?: string;
19
+ readonly additionalProperties?: boolean | import("..").JsonSchemaType;
20
+ };
12
21
  readonly skillName: {
13
22
  readonly type: "string";
14
23
  readonly description: "The kebab-case identifier of the skill to invoke (e.g. \"financial-analyzer\", \"meeting-notes\"). Must match a name from the \"Available Skills\" section.";
@@ -26,6 +35,15 @@ export declare const SkillToolDefinition: {
26
35
  readonly parameters: {
27
36
  readonly type: "object";
28
37
  readonly properties: {
38
+ readonly intent: {
39
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
40
+ readonly enum?: string[];
41
+ readonly items?: import("..").JsonSchemaType;
42
+ readonly properties?: Record<string, import("..").JsonSchemaType>;
43
+ readonly required?: string[];
44
+ readonly description?: string;
45
+ readonly additionalProperties?: boolean | import("..").JsonSchemaType;
46
+ };
29
47
  readonly skillName: {
30
48
  readonly type: "string";
31
49
  readonly description: "The kebab-case identifier of the skill to invoke (e.g. \"financial-analyzer\", \"meeting-notes\"). Must match a name from the \"Available Skills\" section.";
@@ -6,6 +6,15 @@ export declare const SubagentToolDescription = "Delegate a task to a specialized
6
6
  export declare const SubagentToolSchema: {
7
7
  readonly type: "object";
8
8
  readonly properties: {
9
+ readonly intent: {
10
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
11
+ readonly enum?: string[];
12
+ readonly items?: JsonSchemaType;
13
+ readonly properties?: Record<string, JsonSchemaType>;
14
+ readonly required?: string[];
15
+ readonly description?: string;
16
+ readonly additionalProperties?: boolean | JsonSchemaType;
17
+ };
9
18
  readonly description: {
10
19
  readonly type: "string";
11
20
  readonly description: "Complete task description for the subagent. This is the ONLY information it receives — include all necessary context, requirements, and constraints.";
@@ -57,7 +57,32 @@ type RunToolBatchContext<T = unknown> = {
57
57
  * which relies on `node:async_hooks` and is browser-incompatible).
58
58
  */
59
59
  runInput?: T;
60
+ /** Batch-local error-completion ownership (see {@link ToolErrorOwnership}). */
61
+ errorOwnership?: ToolErrorOwnership;
60
62
  };
63
+ /**
64
+ * Batch-local record of who owns each failed call's completion event.
65
+ *
66
+ * Kept per invocation rather than on the instance: tool-call ids are
67
+ * provider-scoped (and synthetic ids can repeat), so concurrent `run()`s on
68
+ * one ToolNode would otherwise share and cross-consume these markers — one
69
+ * invocation's thrown-error marker suppressing another's only completion,
70
+ * or leaving a stale marker behind when an interrupt aborts a batch before
71
+ * the output loop reads it.
72
+ *
73
+ * - `handlerOwned`: the errorHandler ran and dispatched (or threw — a throw
74
+ * is not proof it didn't dispatch). The output loop must skip these.
75
+ * - `undispatched`: the handler explicitly reported it could NOT dispatch,
76
+ * so the output loop owns the completion instead.
77
+ *
78
+ * A call in NEITHER set returned an error `ToolMessage` without ever
79
+ * entering the catch path, so the output loop owns it too.
80
+ */
81
+ export type ToolErrorOwnership = {
82
+ handlerOwned: Set<string>;
83
+ undispatched: Set<string>;
84
+ };
85
+ export declare function createToolErrorOwnership(): ToolErrorOwnership;
61
86
  export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
62
87
  private toolMap;
63
88
  private loadRuntimeTools?;
@@ -68,12 +93,12 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
68
93
  toolCallStepIds?: Map<string, string>;
69
94
  errorHandler?: t.ToolNodeConstructorParams['errorHandler'];
70
95
  /**
71
- * Tool call ids whose `errorHandler` did NOT dispatch the error completion
72
- * event (it returned `false` or threw). The output loop must dispatch the
73
- * completion for these itself skipping them there would strand the
74
- * client's tool-call part without a terminal event.
96
+ * Fallback error-completion ownership for calls that reach `runTool`
97
+ * outside a batch context (direct `runTool` use in tests / embedders).
98
+ * Batch-scoped ownership is threaded via `RunToolBatchContext` instead
99
+ * see {@link ToolErrorOwnership} for why per-invocation scoping matters.
75
100
  */
76
- private undispatchedToolErrors;
101
+ private looseErrorOwnership;
77
102
  private toolUsageCount;
78
103
  /** Maps toolCallId → turn captured in runTool, used by handleRunToolCompletions */
79
104
  private toolCallTurns;
@@ -392,6 +417,13 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
392
417
  * those arrays and consumes them right after this returns.
393
418
  */
394
419
  private dispatchPostToolBatchAndInjectContext;
420
+ /**
421
+ * Whether `name`'s own schema declares a BUSINESS parameter called
422
+ * `intent` (declared, and not the injected label contract — see
423
+ * `isIntentLabelProperty`). Such a parameter must keep participating in
424
+ * `{{tool…}}` placeholder substitution; only the display label is exempt.
425
+ */
426
+ private toolDeclaresBusinessIntent;
395
427
  private dispatchStepCompleted;
396
428
  /**
397
429
  * Emits the completed run step for a single host-reported result before
@@ -401,13 +433,6 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
401
433
  * actually dispatched so the caller can fall back to batch-time emission.
402
434
  */
403
435
  private dispatchEarlyToolCompletion;
404
- /**
405
- * Converts InjectedMessage instances to LangChain HumanMessage objects.
406
- * Both 'user' and 'system' roles become HumanMessage to avoid provider
407
- * rejections (Anthropic/Google reject non-leading SystemMessages).
408
- * The original role is preserved in additional_kwargs for downstream consumers.
409
- */
410
- private convertInjectedMessages;
411
436
  /**
412
437
  * Execute a group of direct (in-process) tool calls with interrupt-safe
413
438
  * ordering, returning outputs aligned 1:1 with `directCalls`.
@@ -6,6 +6,15 @@ export declare const ToolSearchToolDescription = "Searches deferred tools using
6
6
  export declare const ToolSearchToolSchema: {
7
7
  readonly type: "object";
8
8
  readonly properties: {
9
+ readonly intent: {
10
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
11
+ readonly enum?: string[];
12
+ readonly items?: t.JsonSchemaType;
13
+ readonly properties?: Record<string, t.JsonSchemaType>;
14
+ readonly required?: string[];
15
+ readonly description?: string;
16
+ readonly additionalProperties?: boolean | t.JsonSchemaType;
17
+ };
9
18
  readonly query: {
10
19
  readonly type: "string";
11
20
  readonly maxLength: 200;
@@ -48,6 +57,15 @@ export declare const ToolSearchToolDefinition: {
48
57
  readonly schema: {
49
58
  readonly type: "object";
50
59
  readonly properties: {
60
+ readonly intent: {
61
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
62
+ readonly enum?: string[];
63
+ readonly items?: t.JsonSchemaType;
64
+ readonly properties?: Record<string, t.JsonSchemaType>;
65
+ readonly required?: string[];
66
+ readonly description?: string;
67
+ readonly additionalProperties?: boolean | t.JsonSchemaType;
68
+ };
51
69
  readonly query: {
52
70
  readonly type: "string";
53
71
  readonly maxLength: 200;