@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
package/src/types/run.ts CHANGED
@@ -115,6 +115,65 @@ export type StandardGraphConfig = Omit<
115
115
  'edges' | 'type'
116
116
  > & { type?: 'standard'; signal?: AbortSignal };
117
117
 
118
+ /**
119
+ * Cooperative mid-generation preemption. Lets a host seal the live model
120
+ * stream at the next provider-safe token boundary — the run is never
121
+ * aborted, the partial assistant turn is kept, and the graph self-loops
122
+ * into a fresh model call once the `PreemptBoundary` hook has injected
123
+ * whatever the host queued.
124
+ *
125
+ * Preconditions the host MUST satisfy:
126
+ * - `shouldPreempt` is polled once per streamed chunk on the top-level
127
+ * graph. It must be synchronous, allocation-free and O(1) — never I/O.
128
+ * It must also be LEVEL-TRIGGERED (non-consuming): the SDK never clears
129
+ * the host's request, and a true result is only honored once the
130
+ * accumulated chunk is provider-safe, so the predicate may be polled
131
+ * many times before a seal. A one-shot read that clears its own pending
132
+ * flag would silently lose the request on an unsafe chunk (leading
133
+ * whitespace/reasoning, an in-flight tool call) — keep returning true
134
+ * until the `PreemptBoundary` drain hands over the queued injection,
135
+ * then disarm there.
136
+ * - Sealing is only honored on the SDK's own dispatch loop. A run whose
137
+ * registered `CHAT_MODEL_STREAM` handler IS the SDK dispatcher — or wraps
138
+ * it, which `composeEventHandlers` and `createRunHandlers` both do —
139
+ * consumes chunks through a decoupled `streamEvents` reader that can lag
140
+ * the accumulated chunk, so those runs never seal.
141
+ *
142
+ * Detection is by capability, not identity: the dispatcher carries
143
+ * `SDK_STREAM_DISPATCH` and the SDK's wrappers propagate it. A handler
144
+ * that merely OBSERVES the raw chunk echo — LibreChat's no-op
145
+ * `OpenAIChatModelStreamHandler`, say — is unbranded and does NOT disable
146
+ * sealing, because it assigns no content-part indices and so cannot be
147
+ * inverted. A host that renders from the raw feed and wants the opt-out
148
+ * should brand its handler with `SDK_STREAM_DISPATCH`.
149
+ * - `RunConfig.tokenCounter` should be set. A sealed turn ends before most
150
+ * providers send their usage chunk, so the synthetic `CHAT_MODEL_END`
151
+ * falls back to the counter to report `output_tokens`. Without one that
152
+ * fallback silently no-ops and the sealed turn's usage is lost — verified
153
+ * live: OpenAI, Azure OpenAI and DeepSeek report no usage for the sealed
154
+ * segment without a counter, while Anthropic streams usage incrementally
155
+ * and reports it either way.
156
+ */
157
+ export interface StreamPreemption {
158
+ /**
159
+ * Polled once per streamed chunk. Synchronous, allocation-free, O(1), and
160
+ * level-triggered — keep returning true until the `PreemptBoundary` drain
161
+ * consumes the request; a self-clearing read loses it on an unsafe chunk.
162
+ */
163
+ shouldPreempt: () => boolean;
164
+ /**
165
+ * Max cooperative seals per run. Each seal costs one extra superstep, so
166
+ * this also bounds the recursion-limit headroom the run reserves.
167
+ */
168
+ maxSeals?: number;
169
+ }
170
+
171
+ /** Seals honored and boundaries that had nothing to inject, per run. */
172
+ export type PreemptStats = {
173
+ seals: number;
174
+ emptyBoundaries: number;
175
+ };
176
+
118
177
  export type RunConfig = {
119
178
  runId: string;
120
179
  graphConfig: LegacyGraphConfig | StandardGraphConfig | MultiAgentGraphConfig;
@@ -146,6 +205,14 @@ export type RunConfig = {
146
205
  * block to prevent leaks.
147
206
  */
148
207
  hooks?: HookRegistry;
208
+ /**
209
+ * Opt-in cooperative preemption for this run. Requires a `hooks` registry
210
+ * with a `PreemptBoundary` matcher — the seal only stops the stream, the
211
+ * hook is what supplies the messages to resume with. Omit to keep the
212
+ * pre-preemption behavior, where a mid-run injection can only land at a
213
+ * tool boundary.
214
+ */
215
+ preemption?: StreamPreemption;
149
216
  returnContent?: boolean;
150
217
  tokenCounter?: TokenCounter;
151
218
  indexTokenCountMap?: Record<string, number>;
@@ -8,7 +8,6 @@ import type {
8
8
  import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
9
9
  import type { LLMResult, Generation } from '@langchain/core/outputs';
10
10
  import type { Command } from '@langchain/langgraph';
11
- import type OpenAITypes from 'openai';
12
11
  import type { AnthropicContentBlock } from '@/llm/anthropic/types';
13
12
  import type { SummarizeCompleteEvent } from '@/types/summarize';
14
13
  import type { ToolEndEvent } from '@/types/tools';
@@ -143,6 +142,13 @@ export type ProcessedToolCall = {
143
142
  id: string;
144
143
  output: string;
145
144
  progress: number;
145
+ /**
146
+ * Settled label for the call, resolved from the tool-supplied
147
+ * `outcome`/`outcome_patch` result fields against the model-authored
148
+ * `intent` arg. Only present when the tool authored one — hosts apply
149
+ * the mechanical intent transform themselves when absent.
150
+ */
151
+ outcome?: string;
146
152
  };
147
153
 
148
154
  export type ProcessedContent = {
@@ -337,6 +343,11 @@ export type ToolCallPart = {
337
343
  id?: string;
338
344
  /** If provided, the output of the tool call */
339
345
  output?: ToolResultContent['content'];
346
+ /**
347
+ * Tool-authored settled label for the call (see `ProcessedToolCall.outcome`),
348
+ * preserved through aggregation so it survives persistence/reload.
349
+ */
350
+ outcome?: string;
340
351
  /** Auth URL */
341
352
  auth?: string;
342
353
  /** Expiration time */
@@ -393,46 +404,6 @@ export interface TMessage {
393
404
 
394
405
  export type TPayload = Array<Partial<TMessage>>;
395
406
 
396
- export type CustomChunkDelta =
397
- | null
398
- | undefined
399
- | (Partial<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice.Delta> & {
400
- reasoning?: string | null;
401
- reasoning_content?: string | null;
402
- });
403
- export type CustomChunkChoice = Partial<
404
- Omit<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice, 'delta'> & {
405
- delta?: CustomChunkDelta;
406
- }
407
- >;
408
- export type CustomChunk = Partial<OpenAITypes.ChatCompletionChunk> & {
409
- choices?: Partial<Array<CustomChunkChoice>>;
410
- };
411
-
412
- export type SplitStreamHandlers = Partial<{
413
- [GraphEvents.ON_RUN_STEP]: ({
414
- event,
415
- data,
416
- }: {
417
- event: GraphEvents;
418
- data: RunStep;
419
- }) => void;
420
- [GraphEvents.ON_MESSAGE_DELTA]: ({
421
- event,
422
- data,
423
- }: {
424
- event: GraphEvents;
425
- data: MessageDeltaEvent;
426
- }) => void;
427
- [GraphEvents.ON_REASONING_DELTA]: ({
428
- event,
429
- data,
430
- }: {
431
- event: GraphEvents;
432
- data: ReasoningDeltaEvent;
433
- }) => void;
434
- }>;
435
-
436
407
  export type SummarizeDeltaData = {
437
408
  id: string;
438
409
  delta: {
@@ -236,8 +236,12 @@ export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
236
236
  export type ToolEndEvent = {
237
237
  /** The Step Id of the Tool Call */
238
238
  id: string;
239
- /** The Completed Tool Call */
240
- tool_call: ToolCall;
239
+ /**
240
+ * The Completed Tool Call. Carries the tool-authored `outcome` label when
241
+ * present (see `ProcessedToolCall.outcome`) so `ON_RUN_STEP_COMPLETED`
242
+ * consumers can read it without an unsafe cast.
243
+ */
244
+ tool_call: ToolCall & { output?: string; progress?: number; outcome?: string };
241
245
  /** The content index of the tool call */
242
246
  index: number;
243
247
  type?: 'tool_call';
@@ -521,6 +525,17 @@ export type InjectedMessage = {
521
525
  skillName?: string;
522
526
  };
523
527
 
528
+ /**
529
+ * In-place edit of a call's model-authored `intent` label: the first
530
+ * occurrence of `from` in the intent is replaced with `to` (case-sensitive).
531
+ * Lets a tool settle the label while preserving the model's own phrasing,
532
+ * e.g. `{ from: 'Searching', to: 'Searched' }`.
533
+ */
534
+ export type OutcomePatch = {
535
+ from: string;
536
+ to: string;
537
+ };
538
+
524
539
  /** Result for a single tool call in event-driven execution */
525
540
  export type ToolExecuteResult = {
526
541
  /** Matches ToolCallRequest.id */
@@ -533,6 +548,13 @@ export type ToolExecuteResult = {
533
548
  status: 'success' | 'error';
534
549
  /** Error message if status is 'error' */
535
550
  errorMessage?: string;
551
+ /**
552
+ * Settled human-readable label for this call, replacing the model-authored
553
+ * `intent` arg in the UI. Full replacement; wins over `outcome_patch`.
554
+ */
555
+ outcome?: string;
556
+ /** In-place edit of the model-authored `intent` label (see {@link OutcomePatch}). */
557
+ outcome_patch?: OutcomePatch;
536
558
  /**
537
559
  * Messages to inject into graph state after the ToolMessage for this call.
538
560
  * Placed after tool results to respect provider message ordering (tool_call -> tool_result adjacency).
@@ -1,151 +0,0 @@
1
- require("./common/enum.cjs");
2
- require("./common/index.cjs");
3
- let nanoid = require("nanoid");
4
- //#region src/splitStream.ts
5
- const SEPARATORS = [
6
- ". ",
7
- "?",
8
- "!",
9
- "۔",
10
- "- ",
11
- "。",
12
- "‥",
13
- ";",
14
- "¡",
15
- "¿",
16
- "\n",
17
- "```"
18
- ];
19
- var SplitStreamHandler = class {
20
- inCodeBlock = false;
21
- inThinkBlock = false;
22
- accumulate;
23
- tokens = [];
24
- lastToken = "";
25
- reasoningTokens = [];
26
- currentStepId;
27
- currentMessageId;
28
- currentType;
29
- currentLength = 0;
30
- reasoningKey = "reasoning_content";
31
- currentIndex = -1;
32
- blockThreshold = 4500;
33
- /** The run ID AKA the Message ID associated with the complete generation */
34
- runId;
35
- handlers;
36
- constructor({ runId, handlers, accumulate, reasoningKey, blockThreshold }) {
37
- this.runId = runId;
38
- this.handlers = handlers;
39
- if (reasoningKey) this.reasoningKey = reasoningKey;
40
- if (blockThreshold != null) this.blockThreshold = blockThreshold;
41
- this.accumulate = accumulate ?? false;
42
- }
43
- getMessageId = () => {
44
- const messageId = this.currentMessageId;
45
- if (messageId != null && messageId) return messageId;
46
- };
47
- createMessageStep = (type) => {
48
- if (type != null && this.currentType !== type) this.currentType = type;
49
- this.currentLength = 0;
50
- this.currentIndex += 1;
51
- this.currentStepId = `step_${(0, nanoid.nanoid)()}`;
52
- this.currentMessageId = `msg_${(0, nanoid.nanoid)()}`;
53
- return [this.currentStepId, this.currentMessageId];
54
- };
55
- dispatchRunStep = (stepId, stepDetails) => {
56
- const runStep = {
57
- id: stepId,
58
- runId: this.runId,
59
- type: stepDetails.type,
60
- index: this.currentIndex,
61
- stepDetails
62
- };
63
- this.handlers?.["on_run_step"]?.({
64
- event: "on_run_step",
65
- data: runStep
66
- });
67
- };
68
- dispatchMessageDelta = (stepId, delta) => {
69
- const messageDelta = {
70
- id: stepId,
71
- delta
72
- };
73
- this.handlers?.["on_message_delta"]?.({
74
- event: "on_message_delta",
75
- data: messageDelta
76
- });
77
- };
78
- dispatchReasoningDelta = (stepId, delta) => {
79
- const reasoningDelta = {
80
- id: stepId,
81
- delta
82
- };
83
- this.handlers?.["on_reasoning_delta"]?.({
84
- event: "on_reasoning_delta",
85
- data: reasoningDelta
86
- });
87
- };
88
- handleContent = (content, _type) => {
89
- let type = _type;
90
- if (this.inThinkBlock && type === "text") type = "think";
91
- if (this.accumulate) if (type === "think") this.reasoningTokens.push(content);
92
- else this.tokens.push(content);
93
- if (this.currentType !== type) {
94
- const [newStepId, newMessageId] = this.createMessageStep(type);
95
- this.dispatchRunStep(newStepId, {
96
- type: "message_creation",
97
- message_creation: { message_id: newMessageId }
98
- });
99
- }
100
- const stepId = this.currentStepId ?? "";
101
- if (type === "think") this.dispatchReasoningDelta(stepId, { content: [{
102
- type: "think",
103
- think: content
104
- }] });
105
- else this.dispatchMessageDelta(stepId, { content: [{
106
- type: "text",
107
- text: content
108
- }] });
109
- this.currentLength += content.length;
110
- if (this.inCodeBlock) return;
111
- if (this.currentLength > this.blockThreshold && SEPARATORS.some((sep) => content.includes(sep))) {
112
- const [newStepId, newMessageId] = this.createMessageStep(type);
113
- this.dispatchRunStep(newStepId, {
114
- type: "message_creation",
115
- message_creation: { message_id: newMessageId }
116
- });
117
- }
118
- };
119
- getDeltaContent(chunk) {
120
- return (chunk?.choices?.[0]?.delta)?.content ?? "";
121
- }
122
- getReasoningDelta(chunk) {
123
- return (chunk?.choices?.[0]?.delta)?.[this.reasoningKey] ?? "";
124
- }
125
- handle(chunk) {
126
- if (!chunk) return;
127
- const content = this.getDeltaContent(chunk);
128
- const reasoning_content = this.getReasoningDelta(chunk);
129
- if (!content.length && !reasoning_content.length) return;
130
- if (content.includes("```")) this.inCodeBlock = !this.inCodeBlock;
131
- if (content.includes("<think>") && !this.inCodeBlock) this.inThinkBlock = true;
132
- else if (this.lastToken.includes("</think>") && !this.inCodeBlock) this.inThinkBlock = false;
133
- this.lastToken = content;
134
- if (!(this.getMessageId() ?? "")) {
135
- const initialContentType = this.inThinkBlock ? "think" : "text";
136
- const initialType = reasoning_content ? "think" : initialContentType;
137
- const [stepId, message_id] = this.createMessageStep(initialType);
138
- this.dispatchRunStep(stepId, {
139
- type: "message_creation",
140
- message_creation: { message_id }
141
- });
142
- }
143
- if (reasoning_content) this.handleContent(reasoning_content, "think");
144
- else this.handleContent(content, "text");
145
- }
146
- };
147
- //#endregion
148
- exports.SEPARATORS = SEPARATORS;
149
- exports.SplitStreamHandler = SplitStreamHandler;
150
-
151
- //# sourceMappingURL=splitStream.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"splitStream.cjs","names":[],"sources":["../../src/splitStream.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\nimport type * as t from '@/types';\nimport { ContentTypes, GraphEvents, StepTypes } from '@/common';\n\nexport const SEPARATORS = [\n '. ',\n '?',\n '!',\n '۔',\n '- ',\n '。',\n '‥',\n ';',\n '¡',\n '¿',\n '\\n',\n '```',\n];\n\nexport class SplitStreamHandler {\n private inCodeBlock = false;\n private inThinkBlock = false;\n private accumulate: boolean;\n tokens: string[] = [];\n lastToken = '';\n reasoningTokens: string[] = [];\n currentStepId?: string;\n currentMessageId?: string;\n currentType?: ContentTypes.TEXT | ContentTypes.THINK;\n currentLength = 0;\n reasoningKey: 'reasoning_content' | 'reasoning' = 'reasoning_content';\n currentIndex = -1;\n blockThreshold = 4500;\n /** The run ID AKA the Message ID associated with the complete generation */\n runId: string;\n handlers?: t.SplitStreamHandlers;\n constructor({\n runId,\n handlers,\n accumulate,\n reasoningKey,\n blockThreshold,\n }: {\n runId: string;\n accumulate?: boolean;\n handlers: t.SplitStreamHandlers;\n blockThreshold?: number;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n }) {\n this.runId = runId;\n this.handlers = handlers;\n if (reasoningKey) {\n this.reasoningKey = reasoningKey;\n }\n if (blockThreshold != null) {\n this.blockThreshold = blockThreshold;\n }\n this.accumulate = accumulate ?? false;\n }\n getMessageId = (): string | undefined => {\n const messageId = this.currentMessageId;\n if (messageId != null && messageId) {\n return messageId;\n }\n return undefined;\n };\n createMessageStep = (\n type?: ContentTypes.TEXT | ContentTypes.THINK\n ): [string, string] => {\n if (type != null && this.currentType !== type) {\n this.currentType = type;\n }\n this.currentLength = 0;\n this.currentIndex += 1;\n this.currentStepId = `step_${nanoid()}`;\n this.currentMessageId = `msg_${nanoid()}`;\n return [this.currentStepId, this.currentMessageId];\n };\n dispatchRunStep = (stepId: string, stepDetails: t.StepDetails): void => {\n const runStep: t.RunStep = {\n id: stepId,\n runId: this.runId,\n type: stepDetails.type,\n index: this.currentIndex,\n stepDetails,\n // usage: null,\n };\n this.handlers?.[GraphEvents.ON_RUN_STEP]?.({\n event: GraphEvents.ON_RUN_STEP,\n data: runStep,\n });\n };\n dispatchMessageDelta = (stepId: string, delta: t.MessageDelta): void => {\n const messageDelta: t.MessageDeltaEvent = {\n id: stepId,\n delta,\n };\n this.handlers?.[GraphEvents.ON_MESSAGE_DELTA]?.({\n event: GraphEvents.ON_MESSAGE_DELTA,\n data: messageDelta,\n });\n };\n dispatchReasoningDelta = (stepId: string, delta: t.ReasoningDelta): void => {\n const reasoningDelta: t.ReasoningDeltaEvent = {\n id: stepId,\n delta,\n };\n this.handlers?.[GraphEvents.ON_REASONING_DELTA]?.({\n event: GraphEvents.ON_REASONING_DELTA,\n data: reasoningDelta,\n });\n };\n handleContent = (\n content: string,\n _type: ContentTypes.TEXT | ContentTypes.THINK\n ): void => {\n let type = _type;\n if (this.inThinkBlock && type === ContentTypes.TEXT) {\n type = ContentTypes.THINK;\n }\n if (this.accumulate) {\n if (type === ContentTypes.THINK) {\n this.reasoningTokens.push(content);\n } else {\n this.tokens.push(content);\n }\n }\n\n if (this.currentType !== type) {\n const [newStepId, newMessageId] = this.createMessageStep(type);\n this.dispatchRunStep(newStepId, {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id: newMessageId,\n },\n });\n }\n\n const stepId = this.currentStepId ?? '';\n if (type === ContentTypes.THINK) {\n this.dispatchReasoningDelta(stepId, {\n content: [\n {\n type: ContentTypes.THINK,\n think: content,\n },\n ],\n });\n } else {\n this.dispatchMessageDelta(stepId, {\n content: [\n {\n type: ContentTypes.TEXT,\n text: content,\n },\n ],\n });\n }\n\n this.currentLength += content.length;\n if (this.inCodeBlock) {\n return;\n }\n\n if (\n this.currentLength > this.blockThreshold &&\n SEPARATORS.some((sep) => content.includes(sep))\n ) {\n const [newStepId, newMessageId] = this.createMessageStep(type);\n this.dispatchRunStep(newStepId, {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id: newMessageId,\n },\n });\n }\n };\n getDeltaContent(chunk?: t.CustomChunk): string {\n return (chunk?.choices?.[0]?.delta as t.CustomChunkDelta)?.content ?? '';\n }\n getReasoningDelta(chunk?: t.CustomChunk): string {\n return (\n (chunk?.choices?.[0]?.delta as t.CustomChunkDelta)?.[this.reasoningKey] ??\n ''\n );\n }\n handle(chunk?: t.CustomChunk): void {\n if (!chunk) {\n return;\n }\n\n const content = this.getDeltaContent(chunk);\n const reasoning_content = this.getReasoningDelta(chunk);\n if (!content.length && !reasoning_content.length) {\n return;\n }\n\n if (content.includes('```')) {\n this.inCodeBlock = !this.inCodeBlock;\n }\n\n if (content.includes('<think>') && !this.inCodeBlock) {\n this.inThinkBlock = true;\n } else if (this.lastToken.includes('</think>') && !this.inCodeBlock) {\n this.inThinkBlock = false;\n }\n\n this.lastToken = content;\n\n const message_id = this.getMessageId() ?? '';\n\n if (!message_id) {\n const initialContentType = this.inThinkBlock\n ? ContentTypes.THINK\n : ContentTypes.TEXT;\n const initialType = reasoning_content\n ? ContentTypes.THINK\n : initialContentType;\n const [stepId, message_id] = this.createMessageStep(initialType);\n this.dispatchRunStep(stepId, {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id,\n },\n });\n }\n\n if (reasoning_content) {\n this.handleContent(reasoning_content, ContentTypes.THINK);\n } else {\n this.handleContent(content, ContentTypes.TEXT);\n }\n }\n}\n"],"mappings":";;;;AAIA,MAAa,aAAa;CACxB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,IAAa,qBAAb,MAAgC;CAC9B,cAAsB;CACtB,eAAuB;CACvB;CACA,SAAmB,CAAC;CACpB,YAAY;CACZ,kBAA4B,CAAC;CAC7B;CACA;CACA;CACA,gBAAgB;CAChB,eAAkD;CAClD,eAAe;CACf,iBAAiB;;CAEjB;CACA;CACA,YAAY,EACV,OACA,UACA,YACA,cACA,kBAOC;EACD,KAAK,QAAQ;EACb,KAAK,WAAW;EAChB,IAAI,cACF,KAAK,eAAe;EAEtB,IAAI,kBAAkB,MACpB,KAAK,iBAAiB;EAExB,KAAK,aAAa,cAAc;CAClC;CACA,qBAAyC;EACvC,MAAM,YAAY,KAAK;EACvB,IAAI,aAAa,QAAQ,WACvB,OAAO;CAGX;CACA,qBACE,SACqB;EACrB,IAAI,QAAQ,QAAQ,KAAK,gBAAgB,MACvC,KAAK,cAAc;EAErB,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,gBAAgB,SAAA,GAAA,OAAA,OAAA,CAAe;EACpC,KAAK,mBAAmB,QAAA,GAAA,OAAA,OAAA,CAAc;EACtC,OAAO,CAAC,KAAK,eAAe,KAAK,gBAAgB;CACnD;CACA,mBAAmB,QAAgB,gBAAqC;EACtE,MAAM,UAAqB;GACzB,IAAI;GACJ,OAAO,KAAK;GACZ,MAAM,YAAY;GAClB,OAAO,KAAK;GACZ;EAEF;EACA,KAAK,WAAA,cAAmC,GAAG;GACzC,OAAA;GACA,MAAM;EACR,CAAC;CACH;CACA,wBAAwB,QAAgB,UAAgC;EACtE,MAAM,eAAoC;GACxC,IAAI;GACJ;EACF;EACA,KAAK,WAAA,mBAAwC,GAAG;GAC9C,OAAA;GACA,MAAM;EACR,CAAC;CACH;CACA,0BAA0B,QAAgB,UAAkC;EAC1E,MAAM,iBAAwC;GAC5C,IAAI;GACJ;EACF;EACA,KAAK,WAAA,qBAA0C,GAAG;GAChD,OAAA;GACA,MAAM;EACR,CAAC;CACH;CACA,iBACE,SACA,UACS;EACT,IAAI,OAAO;EACX,IAAI,KAAK,gBAAgB,SAAA,QACvB,OAAA;EAEF,IAAI,KAAK,YACP,IAAI,SAAA,SACF,KAAK,gBAAgB,KAAK,OAAO;OAEjC,KAAK,OAAO,KAAK,OAAO;EAI5B,IAAI,KAAK,gBAAgB,MAAM;GAC7B,MAAM,CAAC,WAAW,gBAAgB,KAAK,kBAAkB,IAAI;GAC7D,KAAK,gBAAgB,WAAW;IAC9B,MAAA;IACA,kBAAkB,EAChB,YAAY,aACd;GACF,CAAC;EACH;EAEA,MAAM,SAAS,KAAK,iBAAiB;EACrC,IAAI,SAAA,SACF,KAAK,uBAAuB,QAAQ,EAClC,SAAS,CACP;GACE,MAAA;GACA,OAAO;EACT,CACF,EACF,CAAC;OAED,KAAK,qBAAqB,QAAQ,EAChC,SAAS,CACP;GACE,MAAA;GACA,MAAM;EACR,CACF,EACF,CAAC;EAGH,KAAK,iBAAiB,QAAQ;EAC9B,IAAI,KAAK,aACP;EAGF,IACE,KAAK,gBAAgB,KAAK,kBAC1B,WAAW,MAAM,QAAQ,QAAQ,SAAS,GAAG,CAAC,GAC9C;GACA,MAAM,CAAC,WAAW,gBAAgB,KAAK,kBAAkB,IAAI;GAC7D,KAAK,gBAAgB,WAAW;IAC9B,MAAA;IACA,kBAAkB,EAChB,YAAY,aACd;GACF,CAAC;EACH;CACF;CACA,gBAAgB,OAA+B;EAC7C,QAAQ,OAAO,UAAU,EAAE,EAAE,MAAA,EAA8B,WAAW;CACxE;CACA,kBAAkB,OAA+B;EAC/C,QACG,OAAO,UAAU,EAAE,EAAE,MAAA,GAA+B,KAAK,iBAC1D;CAEJ;CACA,OAAO,OAA6B;EAClC,IAAI,CAAC,OACH;EAGF,MAAM,UAAU,KAAK,gBAAgB,KAAK;EAC1C,MAAM,oBAAoB,KAAK,kBAAkB,KAAK;EACtD,IAAI,CAAC,QAAQ,UAAU,CAAC,kBAAkB,QACxC;EAGF,IAAI,QAAQ,SAAS,KAAK,GACxB,KAAK,cAAc,CAAC,KAAK;EAG3B,IAAI,QAAQ,SAAS,SAAS,KAAK,CAAC,KAAK,aACvC,KAAK,eAAe;OACf,IAAI,KAAK,UAAU,SAAS,UAAU,KAAK,CAAC,KAAK,aACtD,KAAK,eAAe;EAGtB,KAAK,YAAY;EAIjB,IAAI,EAFe,KAAK,aAAa,KAAK,KAEzB;GACf,MAAM,qBAAqB,KAAK,eAAA,UAAA;GAGhC,MAAM,cAAc,oBAAA,UAEhB;GACJ,MAAM,CAAC,QAAQ,cAAc,KAAK,kBAAkB,WAAW;GAC/D,KAAK,gBAAgB,QAAQ;IAC3B,MAAA;IACA,kBAAkB,EAChB,WACF;GACF,CAAC;EACH;EAEA,IAAI,mBACF,KAAK,cAAc,mBAAA,OAAqC;OAExD,KAAK,cAAc,SAAA,MAA0B;CAEjD;AACF"}
@@ -1,150 +0,0 @@
1
- import "./common/enum.mjs";
2
- import "./common/index.mjs";
3
- import { nanoid } from "nanoid";
4
- //#region src/splitStream.ts
5
- const SEPARATORS = [
6
- ". ",
7
- "?",
8
- "!",
9
- "۔",
10
- "- ",
11
- "。",
12
- "‥",
13
- ";",
14
- "¡",
15
- "¿",
16
- "\n",
17
- "```"
18
- ];
19
- var SplitStreamHandler = class {
20
- inCodeBlock = false;
21
- inThinkBlock = false;
22
- accumulate;
23
- tokens = [];
24
- lastToken = "";
25
- reasoningTokens = [];
26
- currentStepId;
27
- currentMessageId;
28
- currentType;
29
- currentLength = 0;
30
- reasoningKey = "reasoning_content";
31
- currentIndex = -1;
32
- blockThreshold = 4500;
33
- /** The run ID AKA the Message ID associated with the complete generation */
34
- runId;
35
- handlers;
36
- constructor({ runId, handlers, accumulate, reasoningKey, blockThreshold }) {
37
- this.runId = runId;
38
- this.handlers = handlers;
39
- if (reasoningKey) this.reasoningKey = reasoningKey;
40
- if (blockThreshold != null) this.blockThreshold = blockThreshold;
41
- this.accumulate = accumulate ?? false;
42
- }
43
- getMessageId = () => {
44
- const messageId = this.currentMessageId;
45
- if (messageId != null && messageId) return messageId;
46
- };
47
- createMessageStep = (type) => {
48
- if (type != null && this.currentType !== type) this.currentType = type;
49
- this.currentLength = 0;
50
- this.currentIndex += 1;
51
- this.currentStepId = `step_${nanoid()}`;
52
- this.currentMessageId = `msg_${nanoid()}`;
53
- return [this.currentStepId, this.currentMessageId];
54
- };
55
- dispatchRunStep = (stepId, stepDetails) => {
56
- const runStep = {
57
- id: stepId,
58
- runId: this.runId,
59
- type: stepDetails.type,
60
- index: this.currentIndex,
61
- stepDetails
62
- };
63
- this.handlers?.["on_run_step"]?.({
64
- event: "on_run_step",
65
- data: runStep
66
- });
67
- };
68
- dispatchMessageDelta = (stepId, delta) => {
69
- const messageDelta = {
70
- id: stepId,
71
- delta
72
- };
73
- this.handlers?.["on_message_delta"]?.({
74
- event: "on_message_delta",
75
- data: messageDelta
76
- });
77
- };
78
- dispatchReasoningDelta = (stepId, delta) => {
79
- const reasoningDelta = {
80
- id: stepId,
81
- delta
82
- };
83
- this.handlers?.["on_reasoning_delta"]?.({
84
- event: "on_reasoning_delta",
85
- data: reasoningDelta
86
- });
87
- };
88
- handleContent = (content, _type) => {
89
- let type = _type;
90
- if (this.inThinkBlock && type === "text") type = "think";
91
- if (this.accumulate) if (type === "think") this.reasoningTokens.push(content);
92
- else this.tokens.push(content);
93
- if (this.currentType !== type) {
94
- const [newStepId, newMessageId] = this.createMessageStep(type);
95
- this.dispatchRunStep(newStepId, {
96
- type: "message_creation",
97
- message_creation: { message_id: newMessageId }
98
- });
99
- }
100
- const stepId = this.currentStepId ?? "";
101
- if (type === "think") this.dispatchReasoningDelta(stepId, { content: [{
102
- type: "think",
103
- think: content
104
- }] });
105
- else this.dispatchMessageDelta(stepId, { content: [{
106
- type: "text",
107
- text: content
108
- }] });
109
- this.currentLength += content.length;
110
- if (this.inCodeBlock) return;
111
- if (this.currentLength > this.blockThreshold && SEPARATORS.some((sep) => content.includes(sep))) {
112
- const [newStepId, newMessageId] = this.createMessageStep(type);
113
- this.dispatchRunStep(newStepId, {
114
- type: "message_creation",
115
- message_creation: { message_id: newMessageId }
116
- });
117
- }
118
- };
119
- getDeltaContent(chunk) {
120
- return (chunk?.choices?.[0]?.delta)?.content ?? "";
121
- }
122
- getReasoningDelta(chunk) {
123
- return (chunk?.choices?.[0]?.delta)?.[this.reasoningKey] ?? "";
124
- }
125
- handle(chunk) {
126
- if (!chunk) return;
127
- const content = this.getDeltaContent(chunk);
128
- const reasoning_content = this.getReasoningDelta(chunk);
129
- if (!content.length && !reasoning_content.length) return;
130
- if (content.includes("```")) this.inCodeBlock = !this.inCodeBlock;
131
- if (content.includes("<think>") && !this.inCodeBlock) this.inThinkBlock = true;
132
- else if (this.lastToken.includes("</think>") && !this.inCodeBlock) this.inThinkBlock = false;
133
- this.lastToken = content;
134
- if (!(this.getMessageId() ?? "")) {
135
- const initialContentType = this.inThinkBlock ? "think" : "text";
136
- const initialType = reasoning_content ? "think" : initialContentType;
137
- const [stepId, message_id] = this.createMessageStep(initialType);
138
- this.dispatchRunStep(stepId, {
139
- type: "message_creation",
140
- message_creation: { message_id }
141
- });
142
- }
143
- if (reasoning_content) this.handleContent(reasoning_content, "think");
144
- else this.handleContent(content, "text");
145
- }
146
- };
147
- //#endregion
148
- export { SEPARATORS, SplitStreamHandler };
149
-
150
- //# sourceMappingURL=splitStream.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"splitStream.mjs","names":[],"sources":["../../src/splitStream.ts"],"sourcesContent":["import { nanoid } from 'nanoid';\nimport type * as t from '@/types';\nimport { ContentTypes, GraphEvents, StepTypes } from '@/common';\n\nexport const SEPARATORS = [\n '. ',\n '?',\n '!',\n '۔',\n '- ',\n '。',\n '‥',\n ';',\n '¡',\n '¿',\n '\\n',\n '```',\n];\n\nexport class SplitStreamHandler {\n private inCodeBlock = false;\n private inThinkBlock = false;\n private accumulate: boolean;\n tokens: string[] = [];\n lastToken = '';\n reasoningTokens: string[] = [];\n currentStepId?: string;\n currentMessageId?: string;\n currentType?: ContentTypes.TEXT | ContentTypes.THINK;\n currentLength = 0;\n reasoningKey: 'reasoning_content' | 'reasoning' = 'reasoning_content';\n currentIndex = -1;\n blockThreshold = 4500;\n /** The run ID AKA the Message ID associated with the complete generation */\n runId: string;\n handlers?: t.SplitStreamHandlers;\n constructor({\n runId,\n handlers,\n accumulate,\n reasoningKey,\n blockThreshold,\n }: {\n runId: string;\n accumulate?: boolean;\n handlers: t.SplitStreamHandlers;\n blockThreshold?: number;\n reasoningKey?: 'reasoning_content' | 'reasoning';\n }) {\n this.runId = runId;\n this.handlers = handlers;\n if (reasoningKey) {\n this.reasoningKey = reasoningKey;\n }\n if (blockThreshold != null) {\n this.blockThreshold = blockThreshold;\n }\n this.accumulate = accumulate ?? false;\n }\n getMessageId = (): string | undefined => {\n const messageId = this.currentMessageId;\n if (messageId != null && messageId) {\n return messageId;\n }\n return undefined;\n };\n createMessageStep = (\n type?: ContentTypes.TEXT | ContentTypes.THINK\n ): [string, string] => {\n if (type != null && this.currentType !== type) {\n this.currentType = type;\n }\n this.currentLength = 0;\n this.currentIndex += 1;\n this.currentStepId = `step_${nanoid()}`;\n this.currentMessageId = `msg_${nanoid()}`;\n return [this.currentStepId, this.currentMessageId];\n };\n dispatchRunStep = (stepId: string, stepDetails: t.StepDetails): void => {\n const runStep: t.RunStep = {\n id: stepId,\n runId: this.runId,\n type: stepDetails.type,\n index: this.currentIndex,\n stepDetails,\n // usage: null,\n };\n this.handlers?.[GraphEvents.ON_RUN_STEP]?.({\n event: GraphEvents.ON_RUN_STEP,\n data: runStep,\n });\n };\n dispatchMessageDelta = (stepId: string, delta: t.MessageDelta): void => {\n const messageDelta: t.MessageDeltaEvent = {\n id: stepId,\n delta,\n };\n this.handlers?.[GraphEvents.ON_MESSAGE_DELTA]?.({\n event: GraphEvents.ON_MESSAGE_DELTA,\n data: messageDelta,\n });\n };\n dispatchReasoningDelta = (stepId: string, delta: t.ReasoningDelta): void => {\n const reasoningDelta: t.ReasoningDeltaEvent = {\n id: stepId,\n delta,\n };\n this.handlers?.[GraphEvents.ON_REASONING_DELTA]?.({\n event: GraphEvents.ON_REASONING_DELTA,\n data: reasoningDelta,\n });\n };\n handleContent = (\n content: string,\n _type: ContentTypes.TEXT | ContentTypes.THINK\n ): void => {\n let type = _type;\n if (this.inThinkBlock && type === ContentTypes.TEXT) {\n type = ContentTypes.THINK;\n }\n if (this.accumulate) {\n if (type === ContentTypes.THINK) {\n this.reasoningTokens.push(content);\n } else {\n this.tokens.push(content);\n }\n }\n\n if (this.currentType !== type) {\n const [newStepId, newMessageId] = this.createMessageStep(type);\n this.dispatchRunStep(newStepId, {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id: newMessageId,\n },\n });\n }\n\n const stepId = this.currentStepId ?? '';\n if (type === ContentTypes.THINK) {\n this.dispatchReasoningDelta(stepId, {\n content: [\n {\n type: ContentTypes.THINK,\n think: content,\n },\n ],\n });\n } else {\n this.dispatchMessageDelta(stepId, {\n content: [\n {\n type: ContentTypes.TEXT,\n text: content,\n },\n ],\n });\n }\n\n this.currentLength += content.length;\n if (this.inCodeBlock) {\n return;\n }\n\n if (\n this.currentLength > this.blockThreshold &&\n SEPARATORS.some((sep) => content.includes(sep))\n ) {\n const [newStepId, newMessageId] = this.createMessageStep(type);\n this.dispatchRunStep(newStepId, {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id: newMessageId,\n },\n });\n }\n };\n getDeltaContent(chunk?: t.CustomChunk): string {\n return (chunk?.choices?.[0]?.delta as t.CustomChunkDelta)?.content ?? '';\n }\n getReasoningDelta(chunk?: t.CustomChunk): string {\n return (\n (chunk?.choices?.[0]?.delta as t.CustomChunkDelta)?.[this.reasoningKey] ??\n ''\n );\n }\n handle(chunk?: t.CustomChunk): void {\n if (!chunk) {\n return;\n }\n\n const content = this.getDeltaContent(chunk);\n const reasoning_content = this.getReasoningDelta(chunk);\n if (!content.length && !reasoning_content.length) {\n return;\n }\n\n if (content.includes('```')) {\n this.inCodeBlock = !this.inCodeBlock;\n }\n\n if (content.includes('<think>') && !this.inCodeBlock) {\n this.inThinkBlock = true;\n } else if (this.lastToken.includes('</think>') && !this.inCodeBlock) {\n this.inThinkBlock = false;\n }\n\n this.lastToken = content;\n\n const message_id = this.getMessageId() ?? '';\n\n if (!message_id) {\n const initialContentType = this.inThinkBlock\n ? ContentTypes.THINK\n : ContentTypes.TEXT;\n const initialType = reasoning_content\n ? ContentTypes.THINK\n : initialContentType;\n const [stepId, message_id] = this.createMessageStep(initialType);\n this.dispatchRunStep(stepId, {\n type: StepTypes.MESSAGE_CREATION,\n message_creation: {\n message_id,\n },\n });\n }\n\n if (reasoning_content) {\n this.handleContent(reasoning_content, ContentTypes.THINK);\n } else {\n this.handleContent(content, ContentTypes.TEXT);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,32 +0,0 @@
1
- import type * as t from '@/types';
2
- export declare const createMockStream: (options?: {
3
- text?: string;
4
- reasoningText?: string;
5
- streamRate?: number;
6
- reasoningKey?: "reasoning" | "reasoning_content";
7
- }) => () => AsyncGenerator<t.CustomChunk>;
8
- /**
9
- (async function testStream(): Promise<void> {
10
- const runId = nanoid();
11
-
12
- const streamHandler = new SplitStreamHandler({
13
- runId,
14
- handlers: {
15
- [GraphEvents.ON_RUN_STEP]: (data): void => {
16
- console.dir(data, { depth: null });
17
- },
18
- [GraphEvents.ON_MESSAGE_DELTA]: (): void => {
19
- // console.dir(data, { depth: null });
20
- },
21
- },
22
- });
23
- const stream = createMockStream({
24
- reasoningText: 'This is a test reasoning text.',
25
- streamRate: 5,
26
- })();
27
-
28
- for await (const chunk of stream) {
29
- streamHandler.handle(chunk);
30
- }
31
- })();
32
- */
@@ -1,37 +0,0 @@
1
- import type * as t from '@/types';
2
- import { ContentTypes } from '@/common';
3
- export declare const SEPARATORS: string[];
4
- export declare class SplitStreamHandler {
5
- private inCodeBlock;
6
- private inThinkBlock;
7
- private accumulate;
8
- tokens: string[];
9
- lastToken: string;
10
- reasoningTokens: string[];
11
- currentStepId?: string;
12
- currentMessageId?: string;
13
- currentType?: ContentTypes.TEXT | ContentTypes.THINK;
14
- currentLength: number;
15
- reasoningKey: 'reasoning_content' | 'reasoning';
16
- currentIndex: number;
17
- blockThreshold: number;
18
- /** The run ID AKA the Message ID associated with the complete generation */
19
- runId: string;
20
- handlers?: t.SplitStreamHandlers;
21
- constructor({ runId, handlers, accumulate, reasoningKey, blockThreshold, }: {
22
- runId: string;
23
- accumulate?: boolean;
24
- handlers: t.SplitStreamHandlers;
25
- blockThreshold?: number;
26
- reasoningKey?: 'reasoning_content' | 'reasoning';
27
- });
28
- getMessageId: () => string | undefined;
29
- createMessageStep: (type?: ContentTypes.TEXT | ContentTypes.THINK) => [string, string];
30
- dispatchRunStep: (stepId: string, stepDetails: t.StepDetails) => void;
31
- dispatchMessageDelta: (stepId: string, delta: t.MessageDelta) => void;
32
- dispatchReasoningDelta: (stepId: string, delta: t.ReasoningDelta) => void;
33
- handleContent: (content: string, _type: ContentTypes.TEXT | ContentTypes.THINK) => void;
34
- getDeltaContent(chunk?: t.CustomChunk): string;
35
- getReasoningDelta(chunk?: t.CustomChunk): string;
36
- handle(chunk?: t.CustomChunk): void;
37
- }