@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
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @fileoverview Tool intent labels.
3
+ *
4
+ * Lets a tool declare, as the FIRST property of its input schema, an `intent`
5
+ * string: one model-authored sentence stating what that specific call is about
6
+ * to do ("Searching for OAuth handling in the callback router"). Because the
7
+ * property is first, it is the first key providers stream in the tool-call
8
+ * args, so a host UI can render it as the call's live status label before the
9
+ * rest of the args exist. When the call settles, {@link applyOutcome} edits
10
+ * the sentence in place into its outcome form — a tool-supplied replacement
11
+ * (`outcome`), a tool-supplied span edit (`outcome_patch`), or a mechanical
12
+ * present-progressive→past-tense transform of the leading verb.
13
+ *
14
+ * The arg is always optional (never listed in `required`): the same schemas
15
+ * are callable from programmatic tool calling, where no UI renders a label
16
+ * and forcing generated code to fabricate one would be pure cost. Tool bodies
17
+ * must call {@link stripIntent} before using their args so no tool receives a
18
+ * parameter it did not declare.
19
+ */
20
+ import type { JsonSchemaType, OutcomePatch } from '@/types';
21
+ /** Argument carrying the model-authored label for a tool call. */
22
+ export declare const INTENT_ARG = "intent";
23
+ /** Model-facing instruction for the injected `intent` property. */
24
+ export declare const INTENT_DESCRIPTION: string;
25
+ /**
26
+ * Canonical (frozen) shape of the injected property. Always embed a COPY
27
+ * (`{ ...INTENT_PROPERTY }`): LangChain's JSON-schema validator stamps a
28
+ * `__absolute_uri__` marker onto every subschema it dereferences, which
29
+ * throws on a frozen object — and a single shared instance would be stamped
30
+ * with one schema's URI while embedded in many.
31
+ */
32
+ export declare const INTENT_PROPERTY: JsonSchemaType;
33
+ /**
34
+ * Discriminates the intent LABEL property from a tool's own business
35
+ * parameter that merely shares the name: the label contract always opens
36
+ * with the same instruction. Removal/sanitize passes must never strip a
37
+ * parameter the tool actually needs.
38
+ */
39
+ export declare function isIntentLabelProperty(property: unknown): boolean;
40
+ /**
41
+ * Returns a copy of the parameters schema with `intent` prepended as the
42
+ * FIRST property (object key order is insertion order and every provider
43
+ * serializer preserves it — first key in the schema means first key in the
44
+ * streamed input). Never mutates the input; no-op when the schema already
45
+ * declares `intent`. The property is not added to `required`.
46
+ */
47
+ export declare function withIntent(parameters?: JsonSchemaType): JsonSchemaType;
48
+ /**
49
+ * Reads the model-authored intent from tool-call args (handles stringified
50
+ * args). Returns undefined when absent, empty, or not a string.
51
+ */
52
+ export declare function readIntent(args: unknown): string | undefined;
53
+ /**
54
+ * Returns the args without the `intent` key so downstream consumers that did
55
+ * not declare it never receive it. Parses stringified JSON object args;
56
+ * returns the value unchanged when the key is absent.
57
+ */
58
+ export declare function stripIntent(args: unknown): unknown;
59
+ /**
60
+ * Resolves the settled label for a call from its model-authored `intent` and
61
+ * the tool's result fields, in precedence order:
62
+ *
63
+ * 1. `outcome` — full replacement authored by the tool.
64
+ * 2. `outcome_patch` — first occurrence of `from` in the intent replaced
65
+ * with `to` (case-sensitive); no-op when `from` is absent or empty.
66
+ * 3. Mechanical transform — the leading word mapped present-progressive →
67
+ * past tense; an unknown leading word leaves the intent unchanged.
68
+ *
69
+ * Returns undefined when there is neither an intent nor an outcome, so
70
+ * callers fall back to their default label. Pure and dependency-free — host
71
+ * UIs needing identical logic can import or mirror it.
72
+ */
73
+ export declare function applyOutcome(intent: string | undefined, result?: {
74
+ outcome?: string;
75
+ outcome_patch?: OutcomePatch;
76
+ }): string | undefined;
77
+ /**
78
+ * Resolves the settled label to emit on a completion event: only when the
79
+ * tool actually authored `outcome`/`outcome_patch` fields. Returns undefined
80
+ * otherwise — the mechanical transform of a bare intent is left to the host
81
+ * so the wire never carries a label the host can derive itself. The result
82
+ * is collapsed to a bounded single line before emission.
83
+ *
84
+ * For failed calls (`isError`), only tool-AUTHORED text may label the call:
85
+ * an explicit `outcome`, or a patch whose `from` actually matches the
86
+ * intent. An unmatched patch must not fall through to the mechanical
87
+ * past-tense transform — wording drift in a failure patch would otherwise
88
+ * render a success-looking label for an error.
89
+ */
90
+ export declare function resolveToolOutcome(args: unknown, fields?: {
91
+ outcome?: string;
92
+ outcome_patch?: OutcomePatch;
93
+ } | null, options?: {
94
+ isError?: boolean;
95
+ }): string | undefined;
96
+ /**
97
+ * Reads the outcome fields off a tool-execution result: the typed
98
+ * `outcome`/`outcome_patch` fields when present, else the artifact channel
99
+ * (see {@link readOutcomeFields}) — so a `content_and_artifact` tool authors
100
+ * its label the same way on the direct and event-driven paths.
101
+ */
102
+ export declare function outcomeFieldsFromResult(result: {
103
+ outcome?: string;
104
+ outcome_patch?: OutcomePatch;
105
+ artifact?: unknown;
106
+ }): {
107
+ outcome?: string;
108
+ outcome_patch?: OutcomePatch;
109
+ } | undefined;
110
+ /**
111
+ * Extracts validated `outcome`/`outcome_patch` fields from an arbitrary
112
+ * value — the artifact channel through which an in-process
113
+ * `content_and_artifact` tool authors its settled label. Returns undefined
114
+ * when neither field is usable.
115
+ */
116
+ export declare function readOutcomeFields(source: unknown): {
117
+ outcome?: string;
118
+ outcome_patch?: OutcomePatch;
119
+ } | undefined;
@@ -1,3 +1,4 @@
1
+ import type { JsonSchemaType } from '@/types';
1
2
  export declare const DEFAULT_CODE_API_RUN_TIMEOUT_MS = 15000;
2
3
  export declare const MIN_CODE_API_RUN_TIMEOUT_MS = 1000;
3
4
  export declare const MAX_CODE_API_RUN_TIMEOUT_SCHEMA_MS = 300000;
@@ -11,6 +12,7 @@ type TimeoutSchema = {
11
12
  export type ProgrammaticToolCallingJsonSchema = {
12
13
  type: 'object';
13
14
  properties: {
15
+ intent: JsonSchemaType;
14
16
  code: {
15
17
  type: 'string';
16
18
  minLength: number;
@@ -0,0 +1,15 @@
1
+ import type * as t from './types';
2
+ export declare class KeenableScraper implements t.BaseScraper {
3
+ private apiKey;
4
+ private apiUrl;
5
+ private timeout;
6
+ private attributionTitle;
7
+ private logger;
8
+ constructor(config?: t.KeenableScraperConfig);
9
+ private buildHeaders;
10
+ scrapeUrl(url: string, options?: t.KeenableScrapeOptions): Promise<[string, t.KeenableScrapeResponse]>;
11
+ scrapeUrls(urls: string[], options?: t.KeenableScrapeOptions): Promise<Array<[string, t.KeenableScrapeResponse]>>;
12
+ extractContent(response: t.KeenableScrapeResponse): [string, undefined | t.References];
13
+ extractMetadata(response: t.KeenableScrapeResponse): t.GenericScrapeMetadata;
14
+ }
15
+ export declare const createKeenableScraper: (config?: t.KeenableScraperConfig) => KeenableScraper;
@@ -36,6 +36,15 @@ export declare const newsSchema: {
36
36
  export declare const WebSearchToolSchema: {
37
37
  readonly type: "object";
38
38
  readonly properties: {
39
+ readonly intent: {
40
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
41
+ readonly enum?: string[];
42
+ readonly items?: import("../..").JsonSchemaType;
43
+ readonly properties?: Record<string, import("../..").JsonSchemaType>;
44
+ readonly required?: string[];
45
+ readonly description?: string;
46
+ readonly additionalProperties?: boolean | import("../..").JsonSchemaType;
47
+ };
39
48
  readonly query: {
40
49
  readonly type: "string";
41
50
  readonly description: string;
@@ -72,6 +81,15 @@ export declare const WebSearchToolDefinition: {
72
81
  readonly schema: {
73
82
  readonly type: "object";
74
83
  readonly properties: {
84
+ readonly intent: {
85
+ readonly type: "string" | "number" | "integer" | "float" | "boolean" | "array" | "object";
86
+ readonly enum?: string[];
87
+ readonly items?: import("../..").JsonSchemaType;
88
+ readonly properties?: Record<string, import("../..").JsonSchemaType>;
89
+ readonly required?: string[];
90
+ readonly description?: string;
91
+ readonly additionalProperties?: boolean | import("../..").JsonSchemaType;
92
+ };
75
93
  readonly query: {
76
94
  readonly type: "string";
77
95
  readonly description: string;
@@ -2,6 +2,24 @@ import { DynamicStructuredTool } from '@langchain/core/tools';
2
2
  import type * as t from './types';
3
3
  import { DATE_RANGE } from './schema';
4
4
  import { createSearchAPI } from './search';
5
+ /**
6
+ * Settled label for a `web_search` call's intent (see `intentArg.ts`).
7
+ *
8
+ * Counts the result kinds `formatResultsForLLM` actually renders —
9
+ * `references` only tracks links embedded in extracted highlights, so it
10
+ * undercounts ordinary results and can overcount when one highlight embeds
11
+ * several links.
12
+ *
13
+ * A caught provider or processing failure is reported through `data.error`
14
+ * while the tool still returns NORMALLY, so that case must author its own
15
+ * label: the `ToolMessage` carries success status, and a bare intent would
16
+ * otherwise settle mechanically from "Searching…" to "Searched…" and present
17
+ * a failed search as a successful one.
18
+ *
19
+ * Returns undefined for a genuine zero-result search, leaving the host's
20
+ * mechanical past-tense transform to label it.
21
+ */
22
+ export declare function resolveSearchOutcome(data: t.SearchResultData, query: string): string | undefined;
5
23
  /**
6
24
  * Executes parallel searches and merges the results,
7
25
  * deduplicating top stories by link
@@ -3,7 +3,7 @@ import type { Logger as WinstonLogger } from 'winston';
3
3
  import type { BaseReranker } from './rerankers';
4
4
  import { DATE_RANGE } from './schema';
5
5
  export type SearchProvider = 'serper' | 'searxng' | 'tavily' | 'keenable' | 'crw';
6
- export type ScraperProvider = 'firecrawl' | 'serper' | 'tavily' | 'crw';
6
+ export type ScraperProvider = 'firecrawl' | 'serper' | 'tavily' | 'crw' | 'keenable';
7
7
  export type RerankerType = 'infinity' | 'jina' | 'cohere' | 'none';
8
8
  export interface Highlight {
9
9
  score: number;
@@ -172,6 +172,34 @@ export interface KeenableSearchResult {
172
172
  export interface KeenableSearchResponse {
173
173
  results?: KeenableSearchResult[];
174
174
  }
175
+ export interface KeenableScraperConfig {
176
+ apiKey?: string;
177
+ /** Override the fetch endpoint base (default: public keyless, keyed when a
178
+ * key is set). Env fallback: KEENABLE_FETCH_URL. */
179
+ apiUrl?: string;
180
+ timeout?: number;
181
+ logger?: Logger;
182
+ /** Sent as the X-Keenable-Title attribution header. Defaults to "LibreChat". */
183
+ attributionTitle?: string;
184
+ }
185
+ export type KeenableScrapeOptions = Omit<KeenableScraperConfig, 'apiKey' | 'apiUrl' | 'logger'>;
186
+ /** Raw JSON shape returned by GET /v1/fetch{,/public}?url=... */
187
+ export interface KeenableFetchResult {
188
+ url?: string;
189
+ title?: string;
190
+ content?: string;
191
+ description?: string;
192
+ }
193
+ export interface KeenableScrapeResponse {
194
+ success: boolean;
195
+ data?: {
196
+ content: string;
197
+ title?: string;
198
+ description?: string;
199
+ url?: string;
200
+ };
201
+ error?: string;
202
+ }
175
203
  export type References = {
176
204
  links: MediaReference[];
177
205
  images: MediaReference[];
@@ -272,6 +300,7 @@ export type Logger = WinstonLogger;
272
300
  export interface SearchToolConfig extends SearchConfig, ProcessSourcesConfig, FirecrawlConfig {
273
301
  tavilyScraperOptions?: TavilyScraperConfig;
274
302
  crwScraperOptions?: CrwScraperConfig;
303
+ keenableScraperOptions?: KeenableScraperConfig;
275
304
  /** Max chars of highlight content this tool feeds the MODEL per search (the
276
305
  * dominant, otherwise-unbounded part of the output). Distinct from
277
306
  * `maxContentLength`, which caps scraped/reranked content per source — full
@@ -303,7 +332,7 @@ export type UsedReferences = {
303
332
  originalIndex: number;
304
333
  reference: MediaReference;
305
334
  }[];
306
- export type AnyScraperResponse = FirecrawlScrapeResponse | SerperScrapeResponse | TavilyScrapeResponse | CrwScrapeResponse;
335
+ export type AnyScraperResponse = FirecrawlScrapeResponse | SerperScrapeResponse | TavilyScrapeResponse | CrwScrapeResponse | KeenableScrapeResponse;
307
336
  /** Base Scraper Interface */
308
337
  export interface BaseScraper {
309
338
  scrapeUrl(url: string, options?: unknown): Promise<[string, AnyScraperResponse]>;
@@ -69,8 +69,18 @@ export type ResolveResult<T> = {
69
69
  * point in time, ignoring any subsequent registrations.
70
70
  */
71
71
  export interface ToolOutputResolveView {
72
- resolve<T>(args: T): ResolveResult<T>;
72
+ resolve<T>(args: T, options?: ResolveOptions): ResolveResult<T>;
73
73
  }
74
+ /**
75
+ * Per-call resolution options. `substituteIntentKey` opts the top-level
76
+ * `intent` key back INTO placeholder substitution: the exemption protects
77
+ * the injected display label, but a tool whose own schema declares a
78
+ * business parameter named `intent` (the injectors skip such tools) still
79
+ * needs references piped into it like any other argument.
80
+ */
81
+ export type ResolveOptions = {
82
+ substituteIntentKey?: boolean;
83
+ };
74
84
  /**
75
85
  * Pre-resolved arg map keyed by `toolCallId`. Used by the mixed
76
86
  * direct+event dispatch path to feed event calls' resolved args
@@ -166,7 +176,7 @@ export declare class ToolOutputReferenceRegistry {
166
176
  * the serialized args, the original input is returned without
167
177
  * walking the tree.
168
178
  */
169
- resolve<T>(runId: string | undefined, args: T): ResolveResult<T>;
179
+ resolve<T>(runId: string | undefined, args: T, options?: ResolveOptions): ResolveResult<T>;
170
180
  /**
171
181
  * Captures a frozen snapshot of `runId`'s current entries and
172
182
  * returns a view that resolves placeholders against *only* that
@@ -7,7 +7,7 @@ import type { GoogleAIToolType } from '@langchain/google-common';
7
7
  import type { SummarizationNodeInput, SummarizeCompleteEvent, SummarizationConfig, SummarizeStartEvent, SummarizeDeltaEvent } from '@/types/summarize';
8
8
  import type { ToolMap, ToolEndEvent, GenericTool, LCTool, ToolExecuteBatchRequest } from '@/types/tools';
9
9
  import type { RunStep, RunStepDeltaEvent, MessageDeltaEvent, ReasoningDeltaEvent } from '@/types/stream';
10
- import type { TokenCounter, TokenBudgetBreakdown } from '@/types/run';
10
+ import type { TokenCounter, StreamPreemption, TokenBudgetBreakdown } from '@/types/run';
11
11
  import type { Providers, Callback, GraphNodeKeys } from '@/common';
12
12
  import type { StandardGraph, MultiAgentGraph } from '@/graphs';
13
13
  import type { ClientOptions } from '@/types/llm';
@@ -243,6 +243,13 @@ export type StandardGraphInput = {
243
243
  * hook inputs carry only `executingAgentId`.
244
244
  */
245
245
  subagentScope?: boolean;
246
+ /**
247
+ * Cooperative preemption, forwarded from `RunConfig.preemption`. Only ever
248
+ * set on the top-level graph: a steer targets the conversation, so subagent
249
+ * children must run to completion and `buildChildInputs` does not propagate
250
+ * this field.
251
+ */
252
+ preemption?: StreamPreemption;
246
253
  };
247
254
  export type GraphEdge = {
248
255
  /** Agent ID, use a list for multiple sources */
@@ -101,6 +101,63 @@ export type StandardGraphConfig = Omit<MultiAgentGraphConfig, 'edges' | 'type'>
101
101
  type?: 'standard';
102
102
  signal?: AbortSignal;
103
103
  };
104
+ /**
105
+ * Cooperative mid-generation preemption. Lets a host seal the live model
106
+ * stream at the next provider-safe token boundary — the run is never
107
+ * aborted, the partial assistant turn is kept, and the graph self-loops
108
+ * into a fresh model call once the `PreemptBoundary` hook has injected
109
+ * whatever the host queued.
110
+ *
111
+ * Preconditions the host MUST satisfy:
112
+ * - `shouldPreempt` is polled once per streamed chunk on the top-level
113
+ * graph. It must be synchronous, allocation-free and O(1) — never I/O.
114
+ * It must also be LEVEL-TRIGGERED (non-consuming): the SDK never clears
115
+ * the host's request, and a true result is only honored once the
116
+ * accumulated chunk is provider-safe, so the predicate may be polled
117
+ * many times before a seal. A one-shot read that clears its own pending
118
+ * flag would silently lose the request on an unsafe chunk (leading
119
+ * whitespace/reasoning, an in-flight tool call) — keep returning true
120
+ * until the `PreemptBoundary` drain hands over the queued injection,
121
+ * then disarm there.
122
+ * - Sealing is only honored on the SDK's own dispatch loop. A run whose
123
+ * registered `CHAT_MODEL_STREAM` handler IS the SDK dispatcher — or wraps
124
+ * it, which `composeEventHandlers` and `createRunHandlers` both do —
125
+ * consumes chunks through a decoupled `streamEvents` reader that can lag
126
+ * the accumulated chunk, so those runs never seal.
127
+ *
128
+ * Detection is by capability, not identity: the dispatcher carries
129
+ * `SDK_STREAM_DISPATCH` and the SDK's wrappers propagate it. A handler
130
+ * that merely OBSERVES the raw chunk echo — LibreChat's no-op
131
+ * `OpenAIChatModelStreamHandler`, say — is unbranded and does NOT disable
132
+ * sealing, because it assigns no content-part indices and so cannot be
133
+ * inverted. A host that renders from the raw feed and wants the opt-out
134
+ * should brand its handler with `SDK_STREAM_DISPATCH`.
135
+ * - `RunConfig.tokenCounter` should be set. A sealed turn ends before most
136
+ * providers send their usage chunk, so the synthetic `CHAT_MODEL_END`
137
+ * falls back to the counter to report `output_tokens`. Without one that
138
+ * fallback silently no-ops and the sealed turn's usage is lost — verified
139
+ * live: OpenAI, Azure OpenAI and DeepSeek report no usage for the sealed
140
+ * segment without a counter, while Anthropic streams usage incrementally
141
+ * and reports it either way.
142
+ */
143
+ export interface StreamPreemption {
144
+ /**
145
+ * Polled once per streamed chunk. Synchronous, allocation-free, O(1), and
146
+ * level-triggered — keep returning true until the `PreemptBoundary` drain
147
+ * consumes the request; a self-clearing read loses it on an unsafe chunk.
148
+ */
149
+ shouldPreempt: () => boolean;
150
+ /**
151
+ * Max cooperative seals per run. Each seal costs one extra superstep, so
152
+ * this also bounds the recursion-limit headroom the run reserves.
153
+ */
154
+ maxSeals?: number;
155
+ }
156
+ /** Seals honored and boundaries that had nothing to inject, per run. */
157
+ export type PreemptStats = {
158
+ seals: number;
159
+ emptyBoundaries: number;
160
+ };
104
161
  export type RunConfig = {
105
162
  runId: string;
106
163
  graphConfig: LegacyGraphConfig | StandardGraphConfig | MultiAgentGraphConfig;
@@ -132,6 +189,14 @@ export type RunConfig = {
132
189
  * block to prevent leaks.
133
190
  */
134
191
  hooks?: HookRegistry;
192
+ /**
193
+ * Opt-in cooperative preemption for this run. Requires a `hooks` registry
194
+ * with a `PreemptBoundary` matcher — the seal only stops the stream, the
195
+ * hook is what supplies the messages to resume with. Omit to keep the
196
+ * pre-preemption behavior, where a mid-run injection can only land at a
197
+ * tool boundary.
198
+ */
199
+ preemption?: StreamPreemption;
135
200
  returnContent?: boolean;
136
201
  tokenCounter?: TokenCounter;
137
202
  indexTokenCountMap?: Record<string, number>;
@@ -2,7 +2,6 @@ import type { MessageContentImageUrl, MessageContentText, ToolMessage, BaseMessa
2
2
  import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
3
3
  import type { LLMResult, Generation } from '@langchain/core/outputs';
4
4
  import type { Command } from '@langchain/langgraph';
5
- import type OpenAITypes from 'openai';
6
5
  import type { AnthropicContentBlock } from '@/llm/anthropic/types';
7
6
  import type { SummarizeCompleteEvent } from '@/types/summarize';
8
7
  import type { ToolEndEvent } from '@/types/tools';
@@ -99,6 +98,13 @@ export type ProcessedToolCall = {
99
98
  id: string;
100
99
  output: string;
101
100
  progress: number;
101
+ /**
102
+ * Settled label for the call, resolved from the tool-supplied
103
+ * `outcome`/`outcome_patch` result fields against the model-authored
104
+ * `intent` arg. Only present when the tool authored one — hosts apply
105
+ * the mechanical intent transform themselves when absent.
106
+ */
107
+ outcome?: string;
102
108
  };
103
109
  export type ProcessedContent = {
104
110
  type: ContentType;
@@ -266,6 +272,11 @@ export type ToolCallPart = {
266
272
  id?: string;
267
273
  /** If provided, the output of the tool call */
268
274
  output?: ToolResultContent['content'];
275
+ /**
276
+ * Tool-authored settled label for the call (see `ProcessedToolCall.outcome`),
277
+ * preserved through aggregation so it survives persistence/reload.
278
+ */
279
+ outcome?: string;
269
280
  /** Auth URL */
270
281
  auth?: string;
271
282
  /** Expiration time */
@@ -297,30 +308,6 @@ export interface TMessage {
297
308
  [key: string]: unknown;
298
309
  }
299
310
  export type TPayload = Array<Partial<TMessage>>;
300
- export type CustomChunkDelta = null | undefined | (Partial<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice.Delta> & {
301
- reasoning?: string | null;
302
- reasoning_content?: string | null;
303
- });
304
- export type CustomChunkChoice = Partial<Omit<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice, 'delta'> & {
305
- delta?: CustomChunkDelta;
306
- }>;
307
- export type CustomChunk = Partial<OpenAITypes.ChatCompletionChunk> & {
308
- choices?: Partial<Array<CustomChunkChoice>>;
309
- };
310
- export type SplitStreamHandlers = Partial<{
311
- [GraphEvents.ON_RUN_STEP]: ({ event, data, }: {
312
- event: GraphEvents;
313
- data: RunStep;
314
- }) => void;
315
- [GraphEvents.ON_MESSAGE_DELTA]: ({ event, data, }: {
316
- event: GraphEvents;
317
- data: MessageDeltaEvent;
318
- }) => void;
319
- [GraphEvents.ON_REASONING_DELTA]: ({ event, data, }: {
320
- event: GraphEvents;
321
- data: ReasoningDeltaEvent;
322
- }) => void;
323
- }>;
324
311
  export type SummarizeDeltaData = {
325
312
  id: string;
326
313
  delta: {
@@ -224,8 +224,16 @@ export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
224
224
  export type ToolEndEvent = {
225
225
  /** The Step Id of the Tool Call */
226
226
  id: string;
227
- /** The Completed Tool Call */
228
- tool_call: ToolCall;
227
+ /**
228
+ * The Completed Tool Call. Carries the tool-authored `outcome` label when
229
+ * present (see `ProcessedToolCall.outcome`) so `ON_RUN_STEP_COMPLETED`
230
+ * consumers can read it without an unsafe cast.
231
+ */
232
+ tool_call: ToolCall & {
233
+ output?: string;
234
+ progress?: number;
235
+ outcome?: string;
236
+ };
229
237
  /** The content index of the tool call */
230
238
  index: number;
231
239
  type?: 'tool_call';
@@ -486,6 +494,16 @@ export type InjectedMessage = {
486
494
  /** Only set when source is 'skill', for compaction preservation */
487
495
  skillName?: string;
488
496
  };
497
+ /**
498
+ * In-place edit of a call's model-authored `intent` label: the first
499
+ * occurrence of `from` in the intent is replaced with `to` (case-sensitive).
500
+ * Lets a tool settle the label while preserving the model's own phrasing,
501
+ * e.g. `{ from: 'Searching', to: 'Searched' }`.
502
+ */
503
+ export type OutcomePatch = {
504
+ from: string;
505
+ to: string;
506
+ };
489
507
  /** Result for a single tool call in event-driven execution */
490
508
  export type ToolExecuteResult = {
491
509
  /** Matches ToolCallRequest.id */
@@ -498,6 +516,13 @@ export type ToolExecuteResult = {
498
516
  status: 'success' | 'error';
499
517
  /** Error message if status is 'error' */
500
518
  errorMessage?: string;
519
+ /**
520
+ * Settled human-readable label for this call, replacing the model-authored
521
+ * `intent` arg in the UI. Full replacement; wins over `outcome_patch`.
522
+ */
523
+ outcome?: string;
524
+ /** In-place edit of the model-authored `intent` label (see {@link OutcomePatch}). */
525
+ outcome_patch?: OutcomePatch;
501
526
  /**
502
527
  * Messages to inject into graph state after the ToolMessage for this call.
503
528
  * Placed after tool results to respect provider message ordering (tool_call -> tool_result adjacency).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.3.4",
3
+ "version": "3.3.6",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",