@tanstack/ai 0.42.0 → 0.43.1

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 (273) hide show
  1. package/README.md +15 -1
  2. package/dist/esm/activities/chat/adapter.js +23 -16
  3. package/dist/esm/activities/chat/adapter.js.map +1 -1
  4. package/dist/esm/activities/chat/agent-loop-strategies.d.ts +5 -36
  5. package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
  6. package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
  7. package/dist/esm/activities/chat/cancel.d.ts +40 -0
  8. package/dist/esm/activities/chat/cancel.js +54 -0
  9. package/dist/esm/activities/chat/cancel.js.map +1 -0
  10. package/dist/esm/activities/chat/index.d.ts +28 -21
  11. package/dist/esm/activities/chat/index.js +2100 -1813
  12. package/dist/esm/activities/chat/index.js.map +1 -1
  13. package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
  14. package/dist/esm/activities/chat/mcp/manager.js +90 -77
  15. package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
  16. package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
  17. package/dist/esm/activities/chat/messages.js +397 -346
  18. package/dist/esm/activities/chat/messages.js.map +1 -1
  19. package/dist/esm/activities/chat/middleware/builder.js +17 -15
  20. package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
  21. package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
  22. package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
  23. package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
  24. package/dist/esm/activities/chat/middleware/compose.js +623 -531
  25. package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
  26. package/dist/esm/activities/chat/middleware/define.js +12 -5
  27. package/dist/esm/activities/chat/middleware/define.js.map +1 -1
  28. package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
  29. package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
  30. package/dist/esm/activities/chat/middleware/locks.js +71 -0
  31. package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
  32. package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
  33. package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
  34. package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
  35. package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
  36. package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
  37. package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
  38. package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
  39. package/dist/esm/activities/chat/middleware/run-store.js +176 -0
  40. package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
  41. package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
  42. package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
  43. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
  44. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
  45. package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
  46. package/dist/esm/activities/chat/middleware/validate.js +23 -28
  47. package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
  48. package/dist/esm/activities/chat/stream/json-parser.js +39 -25
  49. package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
  50. package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
  51. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  52. package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
  53. package/dist/esm/activities/chat/stream/processor.js +1341 -1542
  54. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  55. package/dist/esm/activities/chat/stream/strategies.js +69 -53
  56. package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
  57. package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
  58. package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
  59. package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
  60. package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
  61. package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
  62. package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
  63. package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
  64. package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
  65. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
  66. package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
  67. package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
  68. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  69. package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
  70. package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
  71. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  72. package/dist/esm/activities/error-payload.js +85 -47
  73. package/dist/esm/activities/error-payload.js.map +1 -1
  74. package/dist/esm/activities/generateAudio/adapter.js +22 -15
  75. package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
  76. package/dist/esm/activities/generateAudio/index.d.ts +4 -0
  77. package/dist/esm/activities/generateAudio/index.js +141 -105
  78. package/dist/esm/activities/generateAudio/index.js.map +1 -1
  79. package/dist/esm/activities/generateImage/adapter.js +22 -15
  80. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  81. package/dist/esm/activities/generateImage/index.d.ts +4 -0
  82. package/dist/esm/activities/generateImage/index.js +155 -111
  83. package/dist/esm/activities/generateImage/index.js.map +1 -1
  84. package/dist/esm/activities/generateSpeech/adapter.js +22 -15
  85. package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
  86. package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
  87. package/dist/esm/activities/generateSpeech/index.js +159 -110
  88. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  89. package/dist/esm/activities/generateTranscription/adapter.js +22 -15
  90. package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
  91. package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
  92. package/dist/esm/activities/generateTranscription/index.js +159 -100
  93. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  94. package/dist/esm/activities/generateVideo/adapter.js +36 -29
  95. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  96. package/dist/esm/activities/generateVideo/index.d.ts +143 -19
  97. package/dist/esm/activities/generateVideo/index.js +456 -279
  98. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  99. package/dist/esm/activities/generateVideo/snap.js +60 -48
  100. package/dist/esm/activities/generateVideo/snap.js.map +1 -1
  101. package/dist/esm/activities/index.js +8 -34
  102. package/dist/esm/activities/middleware/index.d.ts +1 -1
  103. package/dist/esm/activities/middleware/run.d.ts +10 -0
  104. package/dist/esm/activities/middleware/run.js +53 -29
  105. package/dist/esm/activities/middleware/run.js.map +1 -1
  106. package/dist/esm/activities/middleware/types.d.ts +44 -6
  107. package/dist/esm/activities/stream-generation-result.d.ts +4 -1
  108. package/dist/esm/activities/stream-generation-result.js +79 -44
  109. package/dist/esm/activities/stream-generation-result.js.map +1 -1
  110. package/dist/esm/activities/summarize/adapter.js +22 -15
  111. package/dist/esm/activities/summarize/adapter.js.map +1 -1
  112. package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
  113. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  114. package/dist/esm/activities/summarize/index.d.ts +27 -0
  115. package/dist/esm/activities/summarize/index.js +268 -102
  116. package/dist/esm/activities/summarize/index.js.map +1 -1
  117. package/dist/esm/adapter-internals.d.ts +2 -1
  118. package/dist/esm/adapter-internals.js +4 -11
  119. package/dist/esm/client.d.ts +25 -3
  120. package/dist/esm/client.js +131 -64
  121. package/dist/esm/client.js.map +1 -1
  122. package/dist/esm/custom-events.d.ts +76 -0
  123. package/dist/esm/custom-events.js +37 -0
  124. package/dist/esm/custom-events.js.map +1 -0
  125. package/dist/esm/delivery-detach.d.ts +50 -0
  126. package/dist/esm/delivery-detach.js +71 -0
  127. package/dist/esm/delivery-detach.js.map +1 -0
  128. package/dist/esm/delivery-disconnect.d.ts +62 -0
  129. package/dist/esm/delivery-disconnect.js +81 -0
  130. package/dist/esm/delivery-disconnect.js.map +1 -0
  131. package/dist/esm/extend-adapter.js +19 -17
  132. package/dist/esm/extend-adapter.js.map +1 -1
  133. package/dist/esm/index.d.ts +24 -6
  134. package/dist/esm/index.js +30 -98
  135. package/dist/esm/interrupt-resume.d.ts +71 -0
  136. package/dist/esm/interrupt-resume.js +438 -0
  137. package/dist/esm/interrupt-resume.js.map +1 -0
  138. package/dist/esm/interrupt-serialization.d.ts +12 -0
  139. package/dist/esm/interrupt-serialization.js +178 -0
  140. package/dist/esm/interrupt-serialization.js.map +1 -0
  141. package/dist/esm/interrupts.d.ts +84 -0
  142. package/dist/esm/interrupts.js +31 -0
  143. package/dist/esm/interrupts.js.map +1 -0
  144. package/dist/esm/locks.d.ts +10 -0
  145. package/dist/esm/locks.js +2 -0
  146. package/dist/esm/logger/console-logger.js +101 -78
  147. package/dist/esm/logger/console-logger.js.map +1 -1
  148. package/dist/esm/logger/internal-logger.js +104 -89
  149. package/dist/esm/logger/internal-logger.js.map +1 -1
  150. package/dist/esm/logger/resolve.js +54 -49
  151. package/dist/esm/logger/resolve.js.map +1 -1
  152. package/dist/esm/logger/types.d.ts +1 -1
  153. package/dist/esm/middlewares/content-guard.js +142 -148
  154. package/dist/esm/middlewares/content-guard.js.map +1 -1
  155. package/dist/esm/middlewares/index.js +2 -6
  156. package/dist/esm/middlewares/otel.d.ts +3 -1
  157. package/dist/esm/middlewares/otel.js +599 -732
  158. package/dist/esm/middlewares/otel.js.map +1 -1
  159. package/dist/esm/middlewares/usage-attributes.js +47 -40
  160. package/dist/esm/middlewares/usage-attributes.js.map +1 -1
  161. package/dist/esm/realtime/event-emitter.js +24 -25
  162. package/dist/esm/realtime/event-emitter.js.map +1 -1
  163. package/dist/esm/realtime/index.d.ts +5 -9
  164. package/dist/esm/realtime/index.js +29 -6
  165. package/dist/esm/realtime/index.js.map +1 -1
  166. package/dist/esm/scope.d.ts +47 -0
  167. package/dist/esm/stream-durability.d.ts +171 -0
  168. package/dist/esm/stream-durability.js +295 -0
  169. package/dist/esm/stream-durability.js.map +1 -0
  170. package/dist/esm/stream-to-response.d.ts +178 -13
  171. package/dist/esm/stream-to-response.js +663 -115
  172. package/dist/esm/stream-to-response.js.map +1 -1
  173. package/dist/esm/strip-to-spec-middleware.js +30 -16
  174. package/dist/esm/strip-to-spec-middleware.js.map +1 -1
  175. package/dist/esm/system-prompts.js +27 -21
  176. package/dist/esm/system-prompts.js.map +1 -1
  177. package/dist/esm/tool-registry.js +72 -45
  178. package/dist/esm/tool-registry.js.map +1 -1
  179. package/dist/esm/tools/provider-tool.js +14 -5
  180. package/dist/esm/tools/provider-tool.js.map +1 -1
  181. package/dist/esm/types.d.ts +321 -42
  182. package/dist/esm/types.js +2 -0
  183. package/dist/esm/utilities/ag-ui-wire.js +79 -93
  184. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  185. package/dist/esm/utilities/chat-params.d.ts +26 -4
  186. package/dist/esm/utilities/chat-params.js +218 -92
  187. package/dist/esm/utilities/chat-params.js.map +1 -1
  188. package/dist/esm/utilities/errors.js +28 -18
  189. package/dist/esm/utilities/errors.js.map +1 -1
  190. package/dist/esm/utilities/media-prompt.js +46 -41
  191. package/dist/esm/utilities/media-prompt.js.map +1 -1
  192. package/dist/esm/utilities/numbers.js +13 -10
  193. package/dist/esm/utilities/numbers.js.map +1 -1
  194. package/dist/esm/utilities/provider-executed.js +20 -11
  195. package/dist/esm/utilities/provider-executed.js.map +1 -1
  196. package/dist/esm/utilities/sampling-keys.js +31 -19
  197. package/dist/esm/utilities/sampling-keys.js.map +1 -1
  198. package/dist/esm/utilities/tool-result.js +42 -30
  199. package/dist/esm/utilities/tool-result.js.map +1 -1
  200. package/dist/esm/utilities/usage.js +27 -9
  201. package/dist/esm/utilities/usage.js.map +1 -1
  202. package/dist/esm/utils.js +26 -18
  203. package/dist/esm/utils.js.map +1 -1
  204. package/package.json +10 -6
  205. package/skills/ai-core/SKILL.md +69 -18
  206. package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
  207. package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
  208. package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
  209. package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
  210. package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
  211. package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
  212. package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
  213. package/skills/ai-core/chat-experience/SKILL.md +98 -11
  214. package/skills/ai-core/client-persistence/SKILL.md +277 -0
  215. package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
  216. package/skills/ai-core/debug-logging/SKILL.md +1 -1
  217. package/skills/ai-core/locks/SKILL.md +143 -0
  218. package/skills/ai-core/media-generation/SKILL.md +144 -12
  219. package/skills/ai-core/middleware/SKILL.md +258 -33
  220. package/skills/ai-core/structured-outputs/SKILL.md +1 -1
  221. package/skills/ai-core/tool-calling/SKILL.md +54 -61
  222. package/src/activities/chat/agent-loop-strategies.ts +5 -39
  223. package/src/activities/chat/cancel.ts +81 -0
  224. package/src/activities/chat/index.ts +1091 -200
  225. package/src/activities/chat/mcp/manager.ts +4 -4
  226. package/src/activities/chat/mcp/types.ts +2 -2
  227. package/src/activities/chat/messages.ts +5 -3
  228. package/src/activities/chat/middleware/builder.ts +1 -1
  229. package/src/activities/chat/middleware/compose.ts +186 -9
  230. package/src/activities/chat/middleware/index.ts +26 -0
  231. package/src/activities/chat/middleware/locks.ts +102 -0
  232. package/src/activities/chat/middleware/pending-turn.ts +47 -0
  233. package/src/activities/chat/middleware/run-disconnect.ts +62 -0
  234. package/src/activities/chat/middleware/run-store.ts +412 -0
  235. package/src/activities/chat/middleware/types.ts +62 -1
  236. package/src/activities/chat/stream/processor.ts +189 -5
  237. package/src/activities/chat/tools/approval-schema.ts +205 -0
  238. package/src/activities/chat/tools/tool-calls.ts +106 -13
  239. package/src/activities/chat/tools/tool-definition.ts +210 -39
  240. package/src/activities/generateAudio/index.ts +20 -3
  241. package/src/activities/generateImage/index.ts +20 -3
  242. package/src/activities/generateSpeech/index.ts +25 -3
  243. package/src/activities/generateTranscription/index.ts +26 -3
  244. package/src/activities/generateVideo/index.ts +345 -82
  245. package/src/activities/middleware/index.ts +2 -0
  246. package/src/activities/middleware/run.ts +31 -0
  247. package/src/activities/middleware/types.ts +49 -5
  248. package/src/activities/stream-generation-result.ts +30 -2
  249. package/src/activities/summarize/chat-stream-summarize.ts +5 -0
  250. package/src/activities/summarize/index.ts +200 -10
  251. package/src/adapter-internals.ts +10 -1
  252. package/src/client.ts +244 -0
  253. package/src/custom-events.ts +107 -0
  254. package/src/delivery-detach.ts +72 -0
  255. package/src/delivery-disconnect.ts +84 -0
  256. package/src/index.ts +138 -1
  257. package/src/interrupt-resume.ts +824 -0
  258. package/src/interrupt-serialization.ts +183 -0
  259. package/src/interrupts.ts +146 -0
  260. package/src/locks.ts +17 -0
  261. package/src/logger/types.ts +1 -1
  262. package/src/middlewares/otel.ts +23 -5
  263. package/src/realtime/index.ts +5 -9
  264. package/src/scope.ts +47 -0
  265. package/src/stream-durability.ts +598 -0
  266. package/src/stream-to-response.ts +1051 -95
  267. package/src/strip-to-spec-middleware.ts +3 -3
  268. package/src/types.ts +405 -45
  269. package/src/utilities/chat-params.ts +245 -55
  270. package/dist/esm/activities/index.js.map +0 -1
  271. package/dist/esm/adapter-internals.js.map +0 -1
  272. package/dist/esm/index.js.map +0 -1
  273. package/dist/esm/middlewares/index.js.map +0 -1
@@ -1,548 +1,539 @@
1
- import { normalizeToolResult } from "../../../utilities/tool-result.js";
2
1
  import { isStandardSchema, parseWithStandardSchema } from "./schema-converter.js";
2
+ import { normalizeToolResult } from "../../../utilities/tool-result.js";
3
+ //#region src/activities/chat/tools/tool-calls.ts
3
4
  function safeJsonParse(value) {
4
- try {
5
- return JSON.parse(value);
6
- } catch {
7
- return value;
8
- }
5
+ try {
6
+ return JSON.parse(value);
7
+ } catch {
8
+ return value;
9
+ }
9
10
  }
10
11
  function readMcpAppMeta(tool) {
11
- const meta = tool.metadata?.mcp;
12
- return meta;
12
+ return tool.metadata?.mcp;
13
13
  }
14
+ /**
15
+ * Eagerly read a tool's linked `ui://` resource (MCP Apps) and emit a
16
+ * `ui-resource` CUSTOM event so the client can render the widget. The model
17
+ * still receives the normal text tool-result; the widget rides alongside and
18
+ * never enters model input.
19
+ *
20
+ * Fail-soft: any read error logs a warning and emits nothing — it never throws,
21
+ * so the normal tool-result still flows and a broken widget cannot break the run.
22
+ */
14
23
  async function emitUiResourceIfLinked(tool, context) {
15
- const mcp = readMcpAppMeta(tool);
16
- const uiUri = mcp?.uiResourceUri;
17
- if (!uiUri || !mcp.readResource) return;
18
- let matched;
19
- try {
20
- const res = await mcp.readResource(uiUri);
21
- matched = res.contents.find((c) => c.uri === uiUri);
22
- } catch (err) {
23
- console.warn(`[mcp-apps] failed to read ui resource ${uiUri}:`, err);
24
- return;
25
- }
26
- if (!matched) {
27
- console.warn(
28
- `[mcp-apps] ui resource ${uiUri} returned no content matching that uri; not emitting`
29
- );
30
- return;
31
- }
32
- context.emitCustomEvent("ui-resource", {
33
- resource: {
34
- uri: matched.uri,
35
- mimeType: matched.mimeType ?? "text/html",
36
- text: matched.text,
37
- blob: matched.blob
38
- },
39
- serverId: mcp.serverId,
40
- toolName: mcp.serverToolName ?? tool.name,
41
- meta: void 0
42
- });
24
+ const mcp = readMcpAppMeta(tool);
25
+ const uiUri = mcp?.uiResourceUri;
26
+ if (!uiUri || !mcp.readResource) return;
27
+ let matched;
28
+ try {
29
+ matched = (await mcp.readResource(uiUri)).contents.find((c) => c.uri === uiUri);
30
+ } catch (err) {
31
+ console.warn(`[mcp-apps] failed to read ui resource ${uiUri}:`, err);
32
+ return;
33
+ }
34
+ if (!matched) {
35
+ console.warn(`[mcp-apps] ui resource ${uiUri} returned no content matching that uri; not emitting`);
36
+ return;
37
+ }
38
+ context.emitCustomEvent("ui-resource", {
39
+ resource: {
40
+ uri: matched.uri,
41
+ mimeType: matched.mimeType ?? "text/html",
42
+ text: matched.text,
43
+ blob: matched.blob
44
+ },
45
+ serverId: mcp.serverId,
46
+ toolName: mcp.serverToolName ?? tool.name,
47
+ meta: void 0
48
+ });
43
49
  }
44
- class MiddlewareAbortError extends Error {
45
- constructor(reason) {
46
- super(reason);
47
- this.name = "MiddlewareAbortError";
48
- }
50
+ /**
51
+ * Error thrown when middleware decides to abort the chat run during tool execution.
52
+ */
53
+ var MiddlewareAbortError = class extends Error {
54
+ constructor(reason) {
55
+ super(reason);
56
+ this.name = "MiddlewareAbortError";
57
+ }
58
+ };
59
+ /**
60
+ * Manages tool call accumulation and execution for the chat() method's automatic tool execution loop.
61
+ *
62
+ * Responsibilities:
63
+ * - Accumulates streaming tool call events (ID, name, arguments)
64
+ * - Validates tool calls (filters out incomplete ones)
65
+ * - Executes tool `execute` functions with parsed arguments
66
+ * - Emits `TOOL_CALL_END` events for client visibility
67
+ * - Returns tool result messages for conversation history
68
+ *
69
+ * This class is used internally by the AI.chat() method to handle the automatic
70
+ * tool execution loop. It can also be used independently for custom tool execution logic.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const manager = new ToolCallManager(tools);
75
+ *
76
+ * // During streaming, accumulate tool calls
77
+ * for await (const chunk of stream) {
78
+ * if (chunk.type === 'TOOL_CALL_START') {
79
+ * manager.addToolCallStartEvent(chunk);
80
+ * } else if (chunk.type === 'TOOL_CALL_ARGS') {
81
+ * manager.addToolCallArgsEvent(chunk);
82
+ * }
83
+ * }
84
+ *
85
+ * // After stream completes, execute tools
86
+ * if (manager.hasToolCalls()) {
87
+ * const toolResults = yield* manager.executeTools(finishEvent);
88
+ * messages = [...messages, ...toolResults];
89
+ * manager.clear();
90
+ * }
91
+ * ```
92
+ */
93
+ var ToolCallManager = class {
94
+ toolCallsMap = /* @__PURE__ */ new Map();
95
+ tools;
96
+ constructor(tools) {
97
+ this.tools = tools;
98
+ }
99
+ /**
100
+ * Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)
101
+ */
102
+ addToolCallStartEvent(event) {
103
+ const index = event.index ?? this.toolCallsMap.size;
104
+ const runtimeEvent = event;
105
+ const name = runtimeEvent.toolCallName ?? runtimeEvent.toolName;
106
+ this.toolCallsMap.set(index, {
107
+ id: event.toolCallId,
108
+ type: "function",
109
+ function: {
110
+ name,
111
+ arguments: ""
112
+ },
113
+ ...event.metadata !== void 0 && { metadata: event.metadata }
114
+ });
115
+ }
116
+ /**
117
+ * Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)
118
+ */
119
+ addToolCallArgsEvent(event) {
120
+ for (const [, toolCall] of this.toolCallsMap.entries()) if (toolCall.id === event.toolCallId) {
121
+ toolCall.function.arguments += event.delta;
122
+ break;
123
+ }
124
+ }
125
+ /**
126
+ * Complete a tool call with its final input
127
+ * Called when TOOL_CALL_END is received
128
+ */
129
+ completeToolCall(event) {
130
+ for (const [, toolCall] of this.toolCallsMap.entries()) if (toolCall.id === event.toolCallId) {
131
+ if (event.input !== void 0) {
132
+ const normalized = event.input && typeof event.input === "object" ? event.input : {};
133
+ toolCall.function.arguments = JSON.stringify(normalized);
134
+ }
135
+ break;
136
+ }
137
+ }
138
+ /**
139
+ * Check if there are any complete tool calls to execute
140
+ */
141
+ hasToolCalls() {
142
+ return this.getToolCalls().length > 0;
143
+ }
144
+ /**
145
+ * Get all complete tool calls (filtered for valid ID and name)
146
+ */
147
+ getToolCalls() {
148
+ return Array.from(this.toolCallsMap.values()).filter((tc) => tc.id && tc.function.name && tc.function.name.trim().length > 0);
149
+ }
150
+ /**
151
+ * Execute all tool calls and return tool result messages
152
+ * Yields TOOL_CALL_END events for streaming
153
+ * @param finishEvent - RUN_FINISHED event from the stream
154
+ */
155
+ async *executeTools(finishEvent, ...contextArgs) {
156
+ const toolCallsArray = this.getToolCalls();
157
+ const toolResults = [];
158
+ const hasRuntimeContext = contextArgs.length > 0;
159
+ const userContext = contextArgs[0];
160
+ for (const toolCall of toolCallsArray) {
161
+ const tool = this.tools.find((t) => t.name === toolCall.function.name);
162
+ let toolResultContent;
163
+ let toolResultState;
164
+ let toolOutput;
165
+ if (tool?.execute) try {
166
+ let args;
167
+ try {
168
+ const argsString = toolCall.function.arguments.trim() || "{}";
169
+ const parsed = JSON.parse(argsString);
170
+ args = parsed && typeof parsed === "object" ? parsed : {};
171
+ } catch (parseError) {
172
+ throw new Error(`Failed to parse tool arguments as JSON: ${toolCall.function.arguments}`);
173
+ }
174
+ if (tool.inputSchema && isStandardSchema(tool.inputSchema)) try {
175
+ args = parseWithStandardSchema(tool.inputSchema, args);
176
+ } catch (validationError) {
177
+ const message = validationError instanceof Error ? validationError.message : "Validation failed";
178
+ throw new Error(`Input validation failed for tool ${tool.name}: ${message}`);
179
+ }
180
+ const executionContext = {
181
+ toolCallId: toolCall.id,
182
+ context: userContext,
183
+ emitCustomEvent: () => {}
184
+ };
185
+ let result = hasRuntimeContext ? await tool.execute(args, executionContext) : await tool.execute(args);
186
+ if (tool.outputSchema && isStandardSchema(tool.outputSchema)) try {
187
+ result = parseWithStandardSchema(tool.outputSchema, result);
188
+ } catch (validationError) {
189
+ const message = validationError instanceof Error ? validationError.message : "Validation failed";
190
+ throw new Error(`Output validation failed for tool ${tool.name}: ${message}`);
191
+ }
192
+ toolOutput = result;
193
+ toolResultContent = normalizeToolResult(result);
194
+ } catch (error) {
195
+ toolResultContent = `Error executing tool: ${error instanceof Error ? error.message : "Unknown error"}`;
196
+ toolResultState = "output-error";
197
+ }
198
+ else toolResultContent = `Tool ${toolCall.function.name} does not have an execute function`;
199
+ yield {
200
+ type: "TOOL_CALL_END",
201
+ toolCallId: toolCall.id,
202
+ toolCallName: toolCall.function.name,
203
+ toolName: toolCall.function.name,
204
+ model: finishEvent.model,
205
+ timestamp: Date.now(),
206
+ ...toolOutput !== void 0 ? { output: toolOutput } : {},
207
+ result: toolResultContent,
208
+ ...toolResultState !== void 0 && { state: toolResultState }
209
+ };
210
+ toolResults.push({
211
+ role: "tool",
212
+ content: toolResultContent,
213
+ toolCallId: toolCall.id
214
+ });
215
+ }
216
+ return toolResults;
217
+ }
218
+ /**
219
+ * Clear the tool calls map for the next iteration
220
+ */
221
+ clear() {
222
+ this.toolCallsMap.clear();
223
+ }
224
+ };
225
+ function approvalResolution(approvals, toolCallId) {
226
+ return approvals.get(toolCallId) ?? approvals.get(`approval_${toolCallId}`);
49
227
  }
50
- class ToolCallManager {
51
- toolCallsMap = /* @__PURE__ */ new Map();
52
- tools;
53
- constructor(tools) {
54
- this.tools = tools;
55
- }
56
- /**
57
- * Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)
58
- */
59
- addToolCallStartEvent(event) {
60
- const index = event.index ?? this.toolCallsMap.size;
61
- const runtimeEvent = event;
62
- const name = runtimeEvent.toolCallName ?? runtimeEvent.toolName;
63
- this.toolCallsMap.set(index, {
64
- id: event.toolCallId,
65
- type: "function",
66
- function: {
67
- name,
68
- arguments: ""
69
- },
70
- ...event.metadata !== void 0 && { metadata: event.metadata }
71
- });
72
- }
73
- /**
74
- * Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)
75
- */
76
- addToolCallArgsEvent(event) {
77
- for (const [, toolCall] of this.toolCallsMap.entries()) {
78
- if (toolCall.id === event.toolCallId) {
79
- toolCall.function.arguments += event.delta;
80
- break;
81
- }
82
- }
83
- }
84
- /**
85
- * Complete a tool call with its final input
86
- * Called when TOOL_CALL_END is received
87
- */
88
- completeToolCall(event) {
89
- for (const [, toolCall] of this.toolCallsMap.entries()) {
90
- if (toolCall.id === event.toolCallId) {
91
- if (event.input !== void 0) {
92
- const normalized = event.input && typeof event.input === "object" ? event.input : {};
93
- toolCall.function.arguments = JSON.stringify(normalized);
94
- }
95
- break;
96
- }
97
- }
98
- }
99
- /**
100
- * Check if there are any complete tool calls to execute
101
- */
102
- hasToolCalls() {
103
- return this.getToolCalls().length > 0;
104
- }
105
- /**
106
- * Get all complete tool calls (filtered for valid ID and name)
107
- */
108
- getToolCalls() {
109
- return Array.from(this.toolCallsMap.values()).filter(
110
- (tc) => tc.id && tc.function.name && tc.function.name.trim().length > 0
111
- );
112
- }
113
- /**
114
- * Execute all tool calls and return tool result messages
115
- * Yields TOOL_CALL_END events for streaming
116
- * @param finishEvent - RUN_FINISHED event from the stream
117
- */
118
- async *executeTools(finishEvent, ...contextArgs) {
119
- const toolCallsArray = this.getToolCalls();
120
- const toolResults = [];
121
- const hasRuntimeContext = contextArgs.length > 0;
122
- const userContext = contextArgs[0];
123
- for (const toolCall of toolCallsArray) {
124
- const tool = this.tools.find((t) => t.name === toolCall.function.name);
125
- let toolResultContent;
126
- let toolResultState;
127
- if (tool?.execute) {
128
- try {
129
- let args;
130
- try {
131
- const argsString = toolCall.function.arguments.trim() || "{}";
132
- const parsed = JSON.parse(argsString);
133
- args = parsed && typeof parsed === "object" ? parsed : {};
134
- } catch (parseError) {
135
- throw new Error(
136
- `Failed to parse tool arguments as JSON: ${toolCall.function.arguments}`
137
- );
138
- }
139
- if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {
140
- try {
141
- args = parseWithStandardSchema(tool.inputSchema, args);
142
- } catch (validationError) {
143
- const message = validationError instanceof Error ? validationError.message : "Validation failed";
144
- throw new Error(
145
- `Input validation failed for tool ${tool.name}: ${message}`
146
- );
147
- }
148
- }
149
- const executionContext = {
150
- toolCallId: toolCall.id,
151
- context: userContext,
152
- emitCustomEvent: () => {
153
- }
154
- };
155
- let result = hasRuntimeContext ? await tool.execute(args, executionContext) : await tool.execute(args);
156
- if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {
157
- try {
158
- result = parseWithStandardSchema(tool.outputSchema, result);
159
- } catch (validationError) {
160
- const message = validationError instanceof Error ? validationError.message : "Validation failed";
161
- throw new Error(
162
- `Output validation failed for tool ${tool.name}: ${message}`
163
- );
164
- }
165
- }
166
- toolResultContent = normalizeToolResult(result);
167
- } catch (error) {
168
- const message = error instanceof Error ? error.message : "Unknown error";
169
- toolResultContent = `Error executing tool: ${message}`;
170
- toolResultState = "output-error";
171
- }
172
- } else {
173
- toolResultContent = `Tool ${toolCall.function.name} does not have an execute function`;
174
- }
175
- yield {
176
- type: "TOOL_CALL_END",
177
- toolCallId: toolCall.id,
178
- toolCallName: toolCall.function.name,
179
- toolName: toolCall.function.name,
180
- model: finishEvent.model,
181
- timestamp: Date.now(),
182
- result: toolResultContent,
183
- ...toolResultState !== void 0 && { state: toolResultState }
184
- };
185
- toolResults.push({
186
- role: "tool",
187
- content: toolResultContent,
188
- toolCallId: toolCall.id
189
- });
190
- }
191
- return toolResults;
192
- }
193
- /**
194
- * Clear the tool calls map for the next iteration
195
- */
196
- clear() {
197
- this.toolCallsMap.clear();
198
- }
228
+ function isApproved(resolution) {
229
+ return typeof resolution === "boolean" ? resolution : resolution.approved;
199
230
  }
231
+ function editedApprovalArgs(resolution) {
232
+ return typeof resolution === "object" && resolution.approved ? resolution.editedArgs : void 0;
233
+ }
234
+ function deniedApprovalResult(resolution) {
235
+ return typeof resolution === "object" && !resolution.approved ? resolution.payload ?? { error: "User declined tool execution" } : { error: "User declined tool execution" };
236
+ }
237
+ /**
238
+ * Helper that runs a tool execution promise while polling for pending custom events.
239
+ * Yields any custom events that are emitted during execution, then returns the
240
+ * execution result.
241
+ */
200
242
  async function* executeWithEventPolling(executionPromise, pendingEvents) {
201
- const state = { done: false, result: void 0 };
202
- const executionWithFlag = executionPromise.then((r) => {
203
- state.done = true;
204
- state.result = r;
205
- return r;
206
- });
207
- while (!state.done) {
208
- await Promise.race([
209
- executionWithFlag,
210
- new Promise((resolve) => setTimeout(resolve, 10))
211
- ]);
212
- let event2;
213
- while ((event2 = pendingEvents.shift()) !== void 0) {
214
- yield event2;
215
- }
216
- }
217
- let event;
218
- while ((event = pendingEvents.shift()) !== void 0) {
219
- yield event;
220
- }
221
- return state.result;
243
+ const state = {
244
+ done: false,
245
+ result: void 0
246
+ };
247
+ const executionWithFlag = executionPromise.then((r) => {
248
+ state.done = true;
249
+ state.result = r;
250
+ return r;
251
+ });
252
+ while (!state.done) {
253
+ await Promise.race([executionWithFlag, new Promise((resolve) => setTimeout(resolve, 10))]);
254
+ let event;
255
+ while ((event = pendingEvents.shift()) !== void 0) yield event;
256
+ }
257
+ let event;
258
+ while ((event = pendingEvents.shift()) !== void 0) yield event;
259
+ return state.result;
222
260
  }
261
+ /**
262
+ * Apply a middleware onBeforeToolCall decision.
263
+ * Returns the (possibly transformed) input if execution should proceed,
264
+ * or undefined if the tool call was skipped (result already pushed).
265
+ * Throws MiddlewareAbortError if the decision is 'abort'.
266
+ */
223
267
  async function applyBeforeToolCallDecision(toolCall, tool, input, toolName, middlewareHooks, results) {
224
- if (!middlewareHooks.onBeforeToolCall) {
225
- return { proceed: true, input };
226
- }
227
- const decision = await middlewareHooks.onBeforeToolCall(toolCall, tool, input);
228
- if (!decision) {
229
- return { proceed: true, input };
230
- }
231
- if (decision.type === "abort") {
232
- throw new MiddlewareAbortError(decision.reason || "Aborted by middleware");
233
- }
234
- if (decision.type === "skip") {
235
- const skipResult = decision.result;
236
- results.push({
237
- toolCallId: toolCall.id,
238
- toolName,
239
- result: typeof skipResult === "string" ? safeJsonParse(skipResult) : skipResult ?? null,
240
- duration: 0
241
- });
242
- if (middlewareHooks.onAfterToolCall) {
243
- await middlewareHooks.onAfterToolCall({
244
- toolCall,
245
- tool,
246
- toolName,
247
- toolCallId: toolCall.id,
248
- ok: true,
249
- duration: 0,
250
- result: skipResult
251
- });
252
- }
253
- return { proceed: false };
254
- }
255
- return { proceed: true, input: decision.args };
268
+ if (!middlewareHooks.onBeforeToolCall) return {
269
+ proceed: true,
270
+ input
271
+ };
272
+ const decision = await middlewareHooks.onBeforeToolCall(toolCall, tool, input);
273
+ if (!decision) return {
274
+ proceed: true,
275
+ input
276
+ };
277
+ if (decision.type === "abort") throw new MiddlewareAbortError(decision.reason || "Aborted by middleware");
278
+ if (decision.type === "skip") {
279
+ const skipResult = decision.result;
280
+ results.push({
281
+ toolCallId: toolCall.id,
282
+ toolName,
283
+ result: typeof skipResult === "string" ? safeJsonParse(skipResult) : skipResult ?? null,
284
+ duration: 0
285
+ });
286
+ if (middlewareHooks.onAfterToolCall) await middlewareHooks.onAfterToolCall({
287
+ toolCall,
288
+ tool,
289
+ toolName,
290
+ toolCallId: toolCall.id,
291
+ ok: true,
292
+ duration: 0,
293
+ result: skipResult
294
+ });
295
+ return { proceed: false };
296
+ }
297
+ return {
298
+ proceed: true,
299
+ input: decision.args
300
+ };
256
301
  }
302
+ /**
303
+ * Execute a server-side tool with event polling, output validation, and middleware hooks.
304
+ * Yields CustomEvent chunks during execution and pushes the result to the results array.
305
+ */
257
306
  async function* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks) {
258
- const startTime = Date.now();
259
- try {
260
- if (!tool.execute) {
261
- throw new Error(`Tool ${toolName} has no execute() implementation`);
262
- }
263
- const executionPromise = Promise.resolve(tool.execute(input, context));
264
- let result = yield* executeWithEventPolling(executionPromise, pendingEvents);
265
- const duration = Date.now() - startTime;
266
- await emitUiResourceIfLinked(tool, context);
267
- let pendingEvent;
268
- while ((pendingEvent = pendingEvents.shift()) !== void 0) {
269
- yield pendingEvent;
270
- }
271
- if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {
272
- result = parseWithStandardSchema(tool.outputSchema, result);
273
- }
274
- const finalResult = typeof result === "string" ? safeJsonParse(result) : result ?? null;
275
- results.push({
276
- toolCallId: toolCall.id,
277
- toolName,
278
- result: finalResult,
279
- duration
280
- });
281
- if (middlewareHooks?.onAfterToolCall) {
282
- await middlewareHooks.onAfterToolCall({
283
- toolCall,
284
- tool,
285
- toolName,
286
- toolCallId: toolCall.id,
287
- ok: true,
288
- duration,
289
- result: finalResult
290
- });
291
- }
292
- } catch (error) {
293
- const duration = Date.now() - startTime;
294
- let pendingEvent;
295
- while ((pendingEvent = pendingEvents.shift()) !== void 0) {
296
- yield pendingEvent;
297
- }
298
- if (error instanceof MiddlewareAbortError) {
299
- throw error;
300
- }
301
- const message = error instanceof Error ? error.message : "Unknown error";
302
- results.push({
303
- toolCallId: toolCall.id,
304
- toolName,
305
- result: { error: message },
306
- state: "output-error",
307
- duration
308
- });
309
- if (middlewareHooks?.onAfterToolCall) {
310
- await middlewareHooks.onAfterToolCall({
311
- toolCall,
312
- tool,
313
- toolName,
314
- toolCallId: toolCall.id,
315
- ok: false,
316
- duration,
317
- error
318
- });
319
- }
320
- }
307
+ const startTime = Date.now();
308
+ try {
309
+ if (!tool.execute) throw new Error(`Tool ${toolName} has no execute() implementation`);
310
+ let result = yield* executeWithEventPolling(Promise.resolve(tool.execute(input, context)), pendingEvents);
311
+ const duration = Date.now() - startTime;
312
+ await emitUiResourceIfLinked(tool, context);
313
+ let pendingEvent;
314
+ while ((pendingEvent = pendingEvents.shift()) !== void 0) yield pendingEvent;
315
+ if (tool.outputSchema && isStandardSchema(tool.outputSchema)) result = parseWithStandardSchema(tool.outputSchema, result);
316
+ const finalResult = typeof result === "string" ? safeJsonParse(result) : result ?? null;
317
+ results.push({
318
+ toolCallId: toolCall.id,
319
+ toolName,
320
+ result: finalResult,
321
+ input,
322
+ output: finalResult,
323
+ duration
324
+ });
325
+ if (middlewareHooks?.onAfterToolCall) await middlewareHooks.onAfterToolCall({
326
+ toolCall,
327
+ tool,
328
+ toolName,
329
+ toolCallId: toolCall.id,
330
+ ok: true,
331
+ duration,
332
+ result: finalResult
333
+ });
334
+ } catch (error) {
335
+ const duration = Date.now() - startTime;
336
+ let pendingEvent;
337
+ while ((pendingEvent = pendingEvents.shift()) !== void 0) yield pendingEvent;
338
+ if (error instanceof MiddlewareAbortError) throw error;
339
+ const message = error instanceof Error ? error.message : "Unknown error";
340
+ results.push({
341
+ toolCallId: toolCall.id,
342
+ toolName,
343
+ result: { error: message },
344
+ input,
345
+ state: "output-error",
346
+ duration
347
+ });
348
+ if (middlewareHooks?.onAfterToolCall) await middlewareHooks.onAfterToolCall({
349
+ toolCall,
350
+ tool,
351
+ toolName,
352
+ toolCallId: toolCall.id,
353
+ ok: false,
354
+ duration,
355
+ error
356
+ });
357
+ }
321
358
  }
322
- function buildClientToolResult(toolCallId, toolName, tool, rawResult) {
323
- try {
324
- let result = rawResult;
325
- if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {
326
- result = parseWithStandardSchema(tool.outputSchema, result);
327
- }
328
- return {
329
- toolCallId,
330
- toolName,
331
- result: typeof result === "string" ? safeJsonParse(result) : result ?? null
332
- };
333
- } catch (error) {
334
- const message = error instanceof Error ? error.message : "Validation failed";
335
- return {
336
- toolCallId,
337
- toolName,
338
- result: { error: message },
339
- state: "output-error"
340
- };
341
- }
359
+ function buildClientToolResult(toolCallId, toolName, tool, rawResult, input) {
360
+ try {
361
+ let result = rawResult;
362
+ if (tool.outputSchema && isStandardSchema(tool.outputSchema)) result = parseWithStandardSchema(tool.outputSchema, result);
363
+ const parsed = typeof result === "string" ? safeJsonParse(result) : result ?? null;
364
+ return {
365
+ toolCallId,
366
+ toolName,
367
+ result: parsed,
368
+ input,
369
+ output: parsed
370
+ };
371
+ } catch (error) {
372
+ return {
373
+ toolCallId,
374
+ toolName,
375
+ result: { error: error instanceof Error ? error.message : "Validation failed" },
376
+ input,
377
+ state: "output-error"
378
+ };
379
+ }
342
380
  }
343
- async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ new Map(), clientResults = /* @__PURE__ */ new Map(), createCustomEventChunk, middlewareHooks, userContext, abortSignal) {
344
- const results = [];
345
- const needsApproval = [];
346
- const needsClientExecution = [];
347
- const toolMap = /* @__PURE__ */ new Map();
348
- for (const tool of tools) {
349
- toolMap.set(tool.name, tool);
350
- }
351
- const hasPendingApprovals = toolCalls.some((tc) => {
352
- const t = toolMap.get(tc.function.name);
353
- return t?.needsApproval && !approvals.has(`approval_${tc.id}`);
354
- });
355
- for (const toolCall of toolCalls) {
356
- const tool = toolMap.get(toolCall.function.name);
357
- const toolName = toolCall.function.name;
358
- if (!tool) {
359
- results.push({
360
- toolCallId: toolCall.id,
361
- toolName,
362
- result: { error: `Unknown tool: ${toolName}` },
363
- state: "output-error"
364
- });
365
- continue;
366
- }
367
- if (hasPendingApprovals) {
368
- if (!tool.needsApproval || approvals.has(`approval_${toolCall.id}`)) {
369
- continue;
370
- }
371
- }
372
- let input = {};
373
- const argsStr = toolCall.function.arguments.trim() || "{}";
374
- {
375
- try {
376
- const parsed = JSON.parse(argsStr);
377
- input = parsed && typeof parsed === "object" ? parsed : {};
378
- } catch (parseError) {
379
- throw new Error(`Failed to parse tool arguments as JSON: ${argsStr}`);
380
- }
381
- }
382
- if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {
383
- try {
384
- input = parseWithStandardSchema(tool.inputSchema, input);
385
- } catch (validationError) {
386
- const message = validationError instanceof Error ? validationError.message : "Validation failed";
387
- results.push({
388
- toolCallId: toolCall.id,
389
- toolName,
390
- result: {
391
- error: `Input validation failed for tool ${tool.name}: ${message}`
392
- },
393
- state: "output-error"
394
- });
395
- continue;
396
- }
397
- }
398
- const pendingEvents = [];
399
- const context = {
400
- toolCallId: toolCall.id,
401
- context: userContext,
402
- abortSignal,
403
- emitCustomEvent: (eventName, value) => {
404
- if (createCustomEventChunk) {
405
- pendingEvents.push(
406
- createCustomEventChunk(eventName, {
407
- ...value,
408
- toolCallId: toolCall.id
409
- })
410
- );
411
- }
412
- }
413
- };
414
- if (!tool.execute) {
415
- if (tool.needsApproval) {
416
- const approvalId = `approval_${toolCall.id}`;
417
- if (approvals.has(approvalId)) {
418
- const approved = approvals.get(approvalId);
419
- if (approved) {
420
- if (clientResults.has(toolCall.id)) {
421
- results.push(
422
- buildClientToolResult(
423
- toolCall.id,
424
- toolName,
425
- tool,
426
- clientResults.get(toolCall.id)
427
- )
428
- );
429
- } else {
430
- needsClientExecution.push({
431
- toolCallId: toolCall.id,
432
- toolName,
433
- input
434
- });
435
- }
436
- } else {
437
- results.push({
438
- toolCallId: toolCall.id,
439
- toolName,
440
- result: { error: "User declined tool execution" },
441
- state: "output-error"
442
- });
443
- }
444
- } else {
445
- needsApproval.push({
446
- toolCallId: toolCall.id,
447
- toolName: toolCall.function.name,
448
- input,
449
- approvalId
450
- });
451
- }
452
- } else {
453
- if (clientResults.has(toolCall.id)) {
454
- results.push(
455
- buildClientToolResult(
456
- toolCall.id,
457
- toolName,
458
- tool,
459
- clientResults.get(toolCall.id)
460
- )
461
- );
462
- } else {
463
- needsClientExecution.push({
464
- toolCallId: toolCall.id,
465
- toolName,
466
- input
467
- });
468
- }
469
- }
470
- continue;
471
- }
472
- if (tool.needsApproval) {
473
- const approvalId = `approval_${toolCall.id}`;
474
- if (approvals.has(approvalId)) {
475
- const approved = approvals.get(approvalId);
476
- if (approved) {
477
- if (middlewareHooks) {
478
- const decision = await applyBeforeToolCallDecision(
479
- toolCall,
480
- tool,
481
- input,
482
- toolName,
483
- middlewareHooks,
484
- results
485
- );
486
- if (!decision.proceed) continue;
487
- input = decision.input;
488
- }
489
- yield* executeServerTool(
490
- toolCall,
491
- tool,
492
- toolName,
493
- input,
494
- context,
495
- pendingEvents,
496
- results,
497
- middlewareHooks
498
- );
499
- } else {
500
- results.push({
501
- toolCallId: toolCall.id,
502
- toolName,
503
- result: { error: "User declined tool execution" },
504
- state: "output-error"
505
- });
506
- }
507
- } else {
508
- needsApproval.push({
509
- toolCallId: toolCall.id,
510
- toolName,
511
- input,
512
- approvalId
513
- });
514
- }
515
- continue;
516
- }
517
- if (middlewareHooks) {
518
- const decision = await applyBeforeToolCallDecision(
519
- toolCall,
520
- tool,
521
- input,
522
- toolName,
523
- middlewareHooks,
524
- results
525
- );
526
- if (!decision.proceed) continue;
527
- input = decision.input;
528
- }
529
- yield* executeServerTool(
530
- toolCall,
531
- tool,
532
- toolName,
533
- input,
534
- context,
535
- pendingEvents,
536
- results,
537
- middlewareHooks
538
- );
539
- }
540
- return { results, needsApproval, needsClientExecution };
381
+ /**
382
+ * Execute tool calls based on their configuration.
383
+ * Yields CustomEvent chunks during tool execution for real-time progress updates.
384
+ *
385
+ * Handles three cases:
386
+ * 1. Client tools (no execute) - request client to execute
387
+ * 2. Server tools with approval - check approval before executing
388
+ * 3. Normal server tools - execute immediately
389
+ *
390
+ * @param toolCalls - Tool calls from the LLM
391
+ * @param tools - Available tools with their configurations
392
+ * @param approvals - Map keyed by toolCallId (or `approval_${toolCallId}`) → ToolApprovalResolution
393
+ * @param clientResults - Map of client-side execution results (toolCallId -> result)
394
+ * @param createCustomEventChunk - Factory to create CustomEvent chunks (optional)
395
+ */
396
+ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ new Map(), clientResults = /* @__PURE__ */ new Map(), createCustomEventChunk, middlewareHooks, userContext, abortSignal, resumeState) {
397
+ const results = [];
398
+ const needsApproval = [];
399
+ const needsClientExecution = [];
400
+ const toolMap = /* @__PURE__ */ new Map();
401
+ for (const tool of tools) toolMap.set(tool.name, tool);
402
+ const hasPendingApprovals = toolCalls.some((tc) => {
403
+ return toolMap.get(tc.function.name)?.needsApproval && approvalResolution(approvals, tc.id) === void 0 && !resumeState?.cancelledToolCallIds?.has(tc.id);
404
+ });
405
+ for (const toolCall of toolCalls) {
406
+ const tool = toolMap.get(toolCall.function.name);
407
+ const toolName = toolCall.function.name;
408
+ if (!tool) {
409
+ results.push({
410
+ toolCallId: toolCall.id,
411
+ toolName,
412
+ result: { error: `Unknown tool: ${toolName}` },
413
+ state: "output-error"
414
+ });
415
+ continue;
416
+ }
417
+ if (hasPendingApprovals) {
418
+ const isPendingApproval = tool.needsApproval && approvalResolution(approvals, toolCall.id) === void 0;
419
+ const isPlainClientRequest = !tool.needsApproval && !tool.execute;
420
+ if (!isPendingApproval && !isPlainClientRequest) continue;
421
+ }
422
+ if (resumeState?.cancelledToolCallIds?.has(toolCall.id)) {
423
+ results.push({
424
+ toolCallId: toolCall.id,
425
+ toolName,
426
+ result: { error: "Tool execution cancelled" },
427
+ state: "output-error"
428
+ });
429
+ continue;
430
+ }
431
+ let input = {};
432
+ const argsStr = toolCall.function.arguments.trim() || "{}";
433
+ if (argsStr) try {
434
+ const parsed = JSON.parse(argsStr);
435
+ input = parsed && typeof parsed === "object" ? parsed : {};
436
+ } catch (parseError) {
437
+ throw new Error(`Failed to parse tool arguments as JSON: ${argsStr}`);
438
+ }
439
+ if (tool.inputSchema && isStandardSchema(tool.inputSchema)) try {
440
+ input = parseWithStandardSchema(tool.inputSchema, input);
441
+ } catch (validationError) {
442
+ const message = validationError instanceof Error ? validationError.message : "Validation failed";
443
+ results.push({
444
+ toolCallId: toolCall.id,
445
+ toolName,
446
+ result: { error: `Input validation failed for tool ${tool.name}: ${message}` },
447
+ input,
448
+ state: "output-error"
449
+ });
450
+ continue;
451
+ }
452
+ const pendingEvents = [];
453
+ const context = {
454
+ toolCallId: toolCall.id,
455
+ context: userContext,
456
+ abortSignal,
457
+ emitCustomEvent: (eventName, value) => {
458
+ if (createCustomEventChunk) pendingEvents.push(createCustomEventChunk(eventName, {
459
+ ...value,
460
+ toolCallId: toolCall.id
461
+ }));
462
+ }
463
+ };
464
+ if (!tool.execute) {
465
+ if (tool.needsApproval) {
466
+ const approvalId = `approval_${toolCall.id}`;
467
+ const resolution = approvalResolution(approvals, toolCall.id);
468
+ if (resolution !== void 0) if (isApproved(resolution)) {
469
+ input = editedApprovalArgs(resolution) ?? input;
470
+ if (clientResults.has(toolCall.id)) results.push(buildClientToolResult(toolCall.id, toolName, tool, clientResults.get(toolCall.id), input));
471
+ else needsClientExecution.push({
472
+ toolCallId: toolCall.id,
473
+ toolName,
474
+ input
475
+ });
476
+ } else results.push({
477
+ toolCallId: toolCall.id,
478
+ toolName,
479
+ result: resumeState?.deniedToolResults?.get(toolCall.id) ?? deniedApprovalResult(resolution),
480
+ input,
481
+ state: "output-error"
482
+ });
483
+ else needsApproval.push({
484
+ toolCallId: toolCall.id,
485
+ toolName: toolCall.function.name,
486
+ input,
487
+ approvalId
488
+ });
489
+ } else if (clientResults.has(toolCall.id)) results.push(buildClientToolResult(toolCall.id, toolName, tool, clientResults.get(toolCall.id), input));
490
+ else needsClientExecution.push({
491
+ toolCallId: toolCall.id,
492
+ toolName,
493
+ input
494
+ });
495
+ continue;
496
+ }
497
+ if (tool.needsApproval) {
498
+ const approvalId = `approval_${toolCall.id}`;
499
+ const resolution = approvalResolution(approvals, toolCall.id);
500
+ if (resolution !== void 0) if (isApproved(resolution)) {
501
+ input = editedApprovalArgs(resolution) ?? input;
502
+ if (middlewareHooks) {
503
+ const decision = await applyBeforeToolCallDecision(toolCall, tool, input, toolName, middlewareHooks, results);
504
+ if (!decision.proceed) continue;
505
+ input = decision.input;
506
+ }
507
+ yield* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks);
508
+ } else results.push({
509
+ toolCallId: toolCall.id,
510
+ toolName,
511
+ result: resumeState?.deniedToolResults?.get(toolCall.id) ?? deniedApprovalResult(resolution),
512
+ input,
513
+ state: "output-error"
514
+ });
515
+ else needsApproval.push({
516
+ toolCallId: toolCall.id,
517
+ toolName,
518
+ input,
519
+ approvalId
520
+ });
521
+ continue;
522
+ }
523
+ if (middlewareHooks) {
524
+ const decision = await applyBeforeToolCallDecision(toolCall, tool, input, toolName, middlewareHooks, results);
525
+ if (!decision.proceed) continue;
526
+ input = decision.input;
527
+ }
528
+ yield* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks);
529
+ }
530
+ return {
531
+ results,
532
+ needsApproval,
533
+ needsClientExecution
534
+ };
541
535
  }
542
- export {
543
- MiddlewareAbortError,
544
- ToolCallManager,
545
- executeServerTool,
546
- executeToolCalls
547
- };
548
- //# sourceMappingURL=tool-calls.js.map
536
+ //#endregion
537
+ export { MiddlewareAbortError, ToolCallManager, executeServerTool, executeToolCalls };
538
+
539
+ //# sourceMappingURL=tool-calls.js.map