@tanstack/ai 0.41.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) 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 +10 -4
  5. package/dist/esm/activities/chat/agent-loop-strategies.js +75 -17
  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 -16
  11. package/dist/esm/activities/chat/index.js +2100 -1744
  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 +23 -5
  134. package/dist/esm/index.js +30 -97
  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.js +598 -732
  157. package/dist/esm/middlewares/otel.js.map +1 -1
  158. package/dist/esm/middlewares/usage-attributes.js +47 -40
  159. package/dist/esm/middlewares/usage-attributes.js.map +1 -1
  160. package/dist/esm/realtime/event-emitter.js +24 -25
  161. package/dist/esm/realtime/event-emitter.js.map +1 -1
  162. package/dist/esm/realtime/index.d.ts +5 -9
  163. package/dist/esm/realtime/index.js +29 -6
  164. package/dist/esm/realtime/index.js.map +1 -1
  165. package/dist/esm/scope.d.ts +47 -0
  166. package/dist/esm/stream-durability.d.ts +171 -0
  167. package/dist/esm/stream-durability.js +295 -0
  168. package/dist/esm/stream-durability.js.map +1 -0
  169. package/dist/esm/stream-to-response.d.ts +178 -13
  170. package/dist/esm/stream-to-response.js +663 -115
  171. package/dist/esm/stream-to-response.js.map +1 -1
  172. package/dist/esm/strip-to-spec-middleware.js +30 -16
  173. package/dist/esm/strip-to-spec-middleware.js.map +1 -1
  174. package/dist/esm/system-prompts.js +27 -21
  175. package/dist/esm/system-prompts.js.map +1 -1
  176. package/dist/esm/tool-registry.js +72 -45
  177. package/dist/esm/tool-registry.js.map +1 -1
  178. package/dist/esm/tools/provider-tool.js +14 -5
  179. package/dist/esm/tools/provider-tool.js.map +1 -1
  180. package/dist/esm/types.d.ts +332 -21
  181. package/dist/esm/types.js +2 -0
  182. package/dist/esm/utilities/ag-ui-wire.js +79 -93
  183. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  184. package/dist/esm/utilities/chat-params.d.ts +26 -4
  185. package/dist/esm/utilities/chat-params.js +218 -92
  186. package/dist/esm/utilities/chat-params.js.map +1 -1
  187. package/dist/esm/utilities/errors.js +28 -18
  188. package/dist/esm/utilities/errors.js.map +1 -1
  189. package/dist/esm/utilities/media-prompt.js +46 -41
  190. package/dist/esm/utilities/media-prompt.js.map +1 -1
  191. package/dist/esm/utilities/numbers.js +13 -10
  192. package/dist/esm/utilities/numbers.js.map +1 -1
  193. package/dist/esm/utilities/provider-executed.js +20 -11
  194. package/dist/esm/utilities/provider-executed.js.map +1 -1
  195. package/dist/esm/utilities/sampling-keys.js +31 -19
  196. package/dist/esm/utilities/sampling-keys.js.map +1 -1
  197. package/dist/esm/utilities/tool-result.js +42 -30
  198. package/dist/esm/utilities/tool-result.js.map +1 -1
  199. package/dist/esm/utilities/usage.js +27 -9
  200. package/dist/esm/utilities/usage.js.map +1 -1
  201. package/dist/esm/utils.js +26 -18
  202. package/dist/esm/utils.js.map +1 -1
  203. package/package.json +10 -6
  204. package/skills/ai-core/SKILL.md +69 -18
  205. package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
  206. package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
  207. package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
  208. package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
  209. package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
  210. package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
  211. package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
  212. package/skills/ai-core/chat-experience/SKILL.md +156 -11
  213. package/skills/ai-core/client-persistence/SKILL.md +277 -0
  214. package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
  215. package/skills/ai-core/debug-logging/SKILL.md +1 -1
  216. package/skills/ai-core/locks/SKILL.md +143 -0
  217. package/skills/ai-core/media-generation/SKILL.md +144 -12
  218. package/skills/ai-core/middleware/SKILL.md +258 -33
  219. package/skills/ai-core/structured-outputs/SKILL.md +1 -1
  220. package/skills/ai-core/tool-calling/SKILL.md +54 -59
  221. package/src/activities/chat/agent-loop-strategies.ts +10 -4
  222. package/src/activities/chat/cancel.ts +81 -0
  223. package/src/activities/chat/index.ts +1152 -153
  224. package/src/activities/chat/mcp/manager.ts +4 -4
  225. package/src/activities/chat/mcp/types.ts +2 -2
  226. package/src/activities/chat/messages.ts +5 -3
  227. package/src/activities/chat/middleware/builder.ts +1 -1
  228. package/src/activities/chat/middleware/compose.ts +186 -9
  229. package/src/activities/chat/middleware/index.ts +26 -0
  230. package/src/activities/chat/middleware/locks.ts +102 -0
  231. package/src/activities/chat/middleware/pending-turn.ts +47 -0
  232. package/src/activities/chat/middleware/run-disconnect.ts +62 -0
  233. package/src/activities/chat/middleware/run-store.ts +412 -0
  234. package/src/activities/chat/middleware/types.ts +62 -1
  235. package/src/activities/chat/stream/processor.ts +189 -5
  236. package/src/activities/chat/tools/approval-schema.ts +205 -0
  237. package/src/activities/chat/tools/tool-calls.ts +106 -13
  238. package/src/activities/chat/tools/tool-definition.ts +210 -39
  239. package/src/activities/generateAudio/index.ts +20 -3
  240. package/src/activities/generateImage/index.ts +20 -3
  241. package/src/activities/generateSpeech/index.ts +25 -3
  242. package/src/activities/generateTranscription/index.ts +26 -3
  243. package/src/activities/generateVideo/index.ts +345 -82
  244. package/src/activities/middleware/index.ts +2 -0
  245. package/src/activities/middleware/run.ts +31 -0
  246. package/src/activities/middleware/types.ts +49 -5
  247. package/src/activities/stream-generation-result.ts +30 -2
  248. package/src/activities/summarize/chat-stream-summarize.ts +5 -0
  249. package/src/activities/summarize/index.ts +200 -10
  250. package/src/adapter-internals.ts +10 -1
  251. package/src/client.ts +244 -0
  252. package/src/custom-events.ts +107 -0
  253. package/src/delivery-detach.ts +72 -0
  254. package/src/delivery-disconnect.ts +84 -0
  255. package/src/index.ts +138 -0
  256. package/src/interrupt-resume.ts +824 -0
  257. package/src/interrupt-serialization.ts +183 -0
  258. package/src/interrupts.ts +146 -0
  259. package/src/locks.ts +17 -0
  260. package/src/logger/types.ts +1 -1
  261. package/src/middlewares/otel.ts +1 -0
  262. package/src/realtime/index.ts +5 -9
  263. package/src/scope.ts +47 -0
  264. package/src/stream-durability.ts +598 -0
  265. package/src/stream-to-response.ts +1051 -95
  266. package/src/strip-to-spec-middleware.ts +3 -3
  267. package/src/types.ts +416 -24
  268. package/src/utilities/chat-params.ts +245 -55
  269. package/dist/esm/activities/index.js.map +0 -1
  270. package/dist/esm/adapter-internals.js.map +0 -1
  271. package/dist/esm/index.js.map +0 -1
  272. package/dist/esm/middlewares/index.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { ServerTool } from '../tools/tool-definition.js';
1
+ import { AnyServerTool } from '../tools/tool-definition.js';
2
2
  import { ChatMCPOptions } from './types.js';
3
3
  export declare class MCPDuplicateToolNameError extends Error {
4
4
  readonly toolName: string;
@@ -19,7 +19,7 @@ export declare class MCPManager {
19
19
  * (no `onDiscoveryError`, or it re-threw) or a duplicate tool name; in that
20
20
  * case it first closes any connected sources when the policy is 'close'.
21
21
  */
22
- discover(): Promise<Array<ServerTool>>;
22
+ discover(): Promise<Array<AnyServerTool>>;
23
23
  /** Close sources iff policy is 'close'. Idempotent; never throws. */
24
24
  dispose(): Promise<void>;
25
25
  }
@@ -1,80 +1,93 @@
1
+ //#region src/activities/chat/mcp/manager.ts
2
+ /**
3
+ * Bind the source's `readResource` onto a ui-linked tool's `metadata.mcp` so it
4
+ * travels with the tool to the server-tool execution/emit site (`tool-calls.ts`).
5
+ *
6
+ * `discover()` is the single place in `@tanstack/ai` that has both a tool and
7
+ * its originating source, and `@tanstack/ai` must not import `@tanstack/ai-mcp`,
8
+ * so this is where the source handle is threaded onto the tool. Only tools that
9
+ * actually link a `ui://` resource (their discovery stamped
10
+ * `metadata.mcp.uiResourceUri`) and whose source can read resources get bound;
11
+ * everything else is left untouched.
12
+ *
13
+ * This mutates the discovered tool's `metadata.mcp` in place. That is safe
14
+ * because discovery returns fresh tool objects per `discover()` call: the bound
15
+ * `readResource` closes over `source`, whose connection stays live until the run
16
+ * drains. If discovery results were ever cached and reused across runs, this
17
+ * would bind a closure over an already-closed source — bind onto a copy then.
18
+ */
1
19
  function bindReadResource(tool, source) {
2
- if (!source.readResource) return;
3
- const meta = tool.metadata?.mcp;
4
- if (!meta?.uiResourceUri) return;
5
- meta.readResource = source.readResource.bind(source);
20
+ if (!source.readResource) return;
21
+ const meta = tool.metadata?.mcp;
22
+ if (!meta?.uiResourceUri) return;
23
+ meta.readResource = source.readResource.bind(source);
6
24
  }
7
- class MCPDuplicateToolNameError extends Error {
8
- constructor(toolName) {
9
- super(
10
- `Duplicate MCP tool name "${toolName}" in chat({ mcp.clients }). Set a unique \`prefix\` on one of the MCP clients (or use a pool, which auto-prefixes) to disambiguate.`
11
- );
12
- this.toolName = toolName;
13
- this.name = "MCPDuplicateToolNameError";
14
- }
15
- toolName;
16
- }
17
- class MCPManager {
18
- static from(options) {
19
- return new MCPManager(options);
20
- }
21
- #sources;
22
- #shouldClose;
23
- #lazyTools;
24
- #onDiscoveryError;
25
- constructor(options) {
26
- this.#sources = options?.clients ?? [];
27
- this.#shouldClose = options ? options.connection !== "keep-alive" : false;
28
- this.#lazyTools = options?.lazyTools ?? false;
29
- this.#onDiscoveryError = options?.onDiscoveryError;
30
- }
31
- /**
32
- * Discover + merge tools from all sources. Throws on a fatal discovery error
33
- * (no `onDiscoveryError`, or it re-threw) or a duplicate tool name; in that
34
- * case it first closes any connected sources when the policy is 'close'.
35
- */
36
- async discover() {
37
- if (this.#sources.length === 0) return [];
38
- try {
39
- const settled = await Promise.allSettled(
40
- this.#sources.map((s) => s.tools({ lazy: this.#lazyTools }))
41
- );
42
- const tools = [];
43
- const zipped = this.#sources.map(
44
- (source, i) => [source, settled[i]]
45
- );
46
- for (const [source, result] of zipped) {
47
- if (result === void 0) continue;
48
- if (result.status === "fulfilled") {
49
- for (const t of result.value) {
50
- bindReadResource(t, source);
51
- tools.push(t);
52
- }
53
- } else if (this.#onDiscoveryError) {
54
- await this.#onDiscoveryError(result.reason, source);
55
- } else {
56
- throw result.reason;
57
- }
58
- }
59
- const seen = /* @__PURE__ */ new Set();
60
- for (const t of tools) {
61
- if (seen.has(t.name)) throw new MCPDuplicateToolNameError(t.name);
62
- seen.add(t.name);
63
- }
64
- return tools;
65
- } catch (err) {
66
- await this.dispose();
67
- throw err;
68
- }
69
- }
70
- /** Close sources iff policy is 'close'. Idempotent; never throws. */
71
- async dispose() {
72
- if (!this.#shouldClose || this.#sources.length === 0) return;
73
- await Promise.allSettled(this.#sources.map((s) => s.close()));
74
- }
75
- }
76
- export {
77
- MCPDuplicateToolNameError,
78
- MCPManager
25
+ var MCPDuplicateToolNameError = class extends Error {
26
+ toolName;
27
+ constructor(toolName) {
28
+ super(`Duplicate MCP tool name "${toolName}" in chat({ mcp.clients }). Set a unique \`prefix\` on one of the MCP clients (or use a pool, which auto-prefixes) to disambiguate.`);
29
+ this.toolName = toolName;
30
+ this.name = "MCPDuplicateToolNameError";
31
+ }
32
+ };
33
+ /**
34
+ * Encapsulates MCP tool discovery + connection lifecycle for chat().
35
+ * Built from chat()'s `mcp` option; runners only call `discover()` then
36
+ * `dispose()`. A manager built from `undefined` is an inert no-op
37
+ * (`discover()` → `[]`, `dispose()` → no-op), so runners need no branching.
38
+ */
39
+ var MCPManager = class MCPManager {
40
+ static from(options) {
41
+ return new MCPManager(options);
42
+ }
43
+ #sources;
44
+ #shouldClose;
45
+ #lazyTools;
46
+ #onDiscoveryError;
47
+ constructor(options) {
48
+ this.#sources = options?.clients ?? [];
49
+ this.#shouldClose = options ? options.connection !== "keep-alive" : false;
50
+ this.#lazyTools = options?.lazyTools ?? false;
51
+ this.#onDiscoveryError = options?.onDiscoveryError;
52
+ }
53
+ /**
54
+ * Discover + merge tools from all sources. Throws on a fatal discovery error
55
+ * (no `onDiscoveryError`, or it re-threw) or a duplicate tool name; in that
56
+ * case it first closes any connected sources when the policy is 'close'.
57
+ */
58
+ async discover() {
59
+ if (this.#sources.length === 0) return [];
60
+ try {
61
+ const settled = await Promise.allSettled(this.#sources.map((s) => s.tools({ lazy: this.#lazyTools })));
62
+ const tools = [];
63
+ const zipped = this.#sources.map((source, i) => [source, settled[i]]);
64
+ for (const [source, result] of zipped) {
65
+ if (result === void 0) continue;
66
+ if (result.status === "fulfilled") for (const t of result.value) {
67
+ bindReadResource(t, source);
68
+ tools.push(t);
69
+ }
70
+ else if (this.#onDiscoveryError) await this.#onDiscoveryError(result.reason, source);
71
+ else throw result.reason;
72
+ }
73
+ const seen = /* @__PURE__ */ new Set();
74
+ for (const t of tools) {
75
+ if (seen.has(t.name)) throw new MCPDuplicateToolNameError(t.name);
76
+ seen.add(t.name);
77
+ }
78
+ return tools;
79
+ } catch (err) {
80
+ await this.dispose();
81
+ throw err;
82
+ }
83
+ }
84
+ /** Close sources iff policy is 'close'. Idempotent; never throws. */
85
+ async dispose() {
86
+ if (!this.#shouldClose || this.#sources.length === 0) return;
87
+ await Promise.allSettled(this.#sources.map((s) => s.close()));
88
+ }
79
89
  };
80
- //# sourceMappingURL=manager.js.map
90
+ //#endregion
91
+ export { MCPDuplicateToolNameError, MCPManager };
92
+
93
+ //# sourceMappingURL=manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sources":["../../../../../src/activities/chat/mcp/manager.ts"],"sourcesContent":["import type { ServerTool } from '../tools/tool-definition'\nimport type { ChatMCPOptions, MCPToolSource } from './types'\n\n/**\n * Bind the source's `readResource` onto a ui-linked tool's `metadata.mcp` so it\n * travels with the tool to the server-tool execution/emit site (`tool-calls.ts`).\n *\n * `discover()` is the single place in `@tanstack/ai` that has both a tool and\n * its originating source, and `@tanstack/ai` must not import `@tanstack/ai-mcp`,\n * so this is where the source handle is threaded onto the tool. Only tools that\n * actually link a `ui://` resource (their discovery stamped\n * `metadata.mcp.uiResourceUri`) and whose source can read resources get bound;\n * everything else is left untouched.\n *\n * This mutates the discovered tool's `metadata.mcp` in place. That is safe\n * because discovery returns fresh tool objects per `discover()` call: the bound\n * `readResource` closes over `source`, whose connection stays live until the run\n * drains. If discovery results were ever cached and reused across runs, this\n * would bind a closure over an already-closed source — bind onto a copy then.\n */\nfunction bindReadResource(tool: ServerTool, source: MCPToolSource): void {\n if (!source.readResource) return\n const meta = (\n tool.metadata as { mcp?: { uiResourceUri?: string } } | undefined\n )?.mcp\n if (!meta?.uiResourceUri) return\n ;(meta as { readResource?: MCPToolSource['readResource'] }).readResource =\n source.readResource.bind(source)\n}\n\nexport class MCPDuplicateToolNameError extends Error {\n constructor(public readonly toolName: string) {\n super(\n `Duplicate MCP tool name \"${toolName}\" in chat({ mcp.clients }). ` +\n `Set a unique \\`prefix\\` on one of the MCP clients (or use a pool, ` +\n `which auto-prefixes) to disambiguate.`,\n )\n this.name = 'MCPDuplicateToolNameError'\n }\n}\n\n/**\n * Encapsulates MCP tool discovery + connection lifecycle for chat().\n * Built from chat()'s `mcp` option; runners only call `discover()` then\n * `dispose()`. A manager built from `undefined` is an inert no-op\n * (`discover()` → `[]`, `dispose()` → no-op), so runners need no branching.\n */\nexport class MCPManager {\n static from(options: ChatMCPOptions | undefined): MCPManager {\n return new MCPManager(options)\n }\n\n readonly #sources: ReadonlyArray<MCPToolSource>\n readonly #shouldClose: boolean\n readonly #lazyTools: boolean\n readonly #onDiscoveryError?: (\n error: unknown,\n source: MCPToolSource,\n ) => void | Promise<void>\n\n private constructor(options: ChatMCPOptions | undefined) {\n this.#sources = options?.clients ?? []\n // default 'close'; only 'keep-alive' disables closing\n this.#shouldClose = options ? options.connection !== 'keep-alive' : false\n this.#lazyTools = options?.lazyTools ?? false\n this.#onDiscoveryError = options?.onDiscoveryError\n }\n\n /**\n * Discover + merge tools from all sources. Throws on a fatal discovery error\n * (no `onDiscoveryError`, or it re-threw) or a duplicate tool name; in that\n * case it first closes any connected sources when the policy is 'close'.\n */\n async discover(): Promise<Array<ServerTool>> {\n if (this.#sources.length === 0) return []\n try {\n const settled = await Promise.allSettled(\n this.#sources.map((s) => s.tools({ lazy: this.#lazyTools })),\n )\n const tools: Array<ServerTool> = []\n const zipped = this.#sources.map(\n (source, i) => [source, settled[i]] as const,\n )\n for (const [source, result] of zipped) {\n if (result === undefined) continue\n if (result.status === 'fulfilled') {\n for (const t of result.value) {\n bindReadResource(t, source)\n tools.push(t)\n }\n } else if (this.#onDiscoveryError) {\n // throw/reject inside handler ⇒ propagate (fail-fast); return ⇒ skip\n await this.#onDiscoveryError(result.reason, source)\n } else {\n throw result.reason\n }\n }\n const seen = new Set<string>()\n for (const t of tools) {\n if (seen.has(t.name)) throw new MCPDuplicateToolNameError(t.name)\n seen.add(t.name)\n }\n return tools\n } catch (err) {\n await this.dispose() // cleanup-on-failure (no-op if keep-alive)\n throw err\n }\n }\n\n /** Close sources iff policy is 'close'. Idempotent; never throws. */\n async dispose(): Promise<void> {\n if (!this.#shouldClose || this.#sources.length === 0) return\n await Promise.allSettled(this.#sources.map((s) => s.close()))\n }\n}\n"],"names":[],"mappings":"AAoBA,SAAS,iBAAiB,MAAkB,QAA6B;AACvE,MAAI,CAAC,OAAO,aAAc;AAC1B,QAAM,OACJ,KAAK,UACJ;AACH,MAAI,CAAC,MAAM,cAAe;AACxB,OAA0D,eAC1D,OAAO,aAAa,KAAK,MAAM;AACnC;AAEO,MAAM,kCAAkC,MAAM;AAAA,EACnD,YAA4B,UAAkB;AAC5C;AAAA,MACE,4BAA4B,QAAQ;AAAA,IAAA;AAFZ,SAAA,WAAA;AAM1B,SAAK,OAAO;AAAA,EACd;AAAA,EAP4B;AAQ9B;AAQO,MAAM,WAAW;AAAA,EACtB,OAAO,KAAK,SAAiD;AAC3D,WAAO,IAAI,WAAW,OAAO;AAAA,EAC/B;AAAA,EAES;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAKD,YAAY,SAAqC;AACvD,SAAK,WAAW,SAAS,WAAW,CAAA;AAEpC,SAAK,eAAe,UAAU,QAAQ,eAAe,eAAe;AACpE,SAAK,aAAa,SAAS,aAAa;AACxC,SAAK,oBAAoB,SAAS;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAuC;AAC3C,QAAI,KAAK,SAAS,WAAW,UAAU,CAAA;AACvC,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ;AAAA,QAC5B,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,YAAY,CAAC;AAAA,MAAA;AAE7D,YAAM,QAA2B,CAAA;AACjC,YAAM,SAAS,KAAK,SAAS;AAAA,QAC3B,CAAC,QAAQ,MAAM,CAAC,QAAQ,QAAQ,CAAC,CAAC;AAAA,MAAA;AAEpC,iBAAW,CAAC,QAAQ,MAAM,KAAK,QAAQ;AACrC,YAAI,WAAW,OAAW;AAC1B,YAAI,OAAO,WAAW,aAAa;AACjC,qBAAW,KAAK,OAAO,OAAO;AAC5B,6BAAiB,GAAG,MAAM;AAC1B,kBAAM,KAAK,CAAC;AAAA,UACd;AAAA,QACF,WAAW,KAAK,mBAAmB;AAEjC,gBAAM,KAAK,kBAAkB,OAAO,QAAQ,MAAM;AAAA,QACpD,OAAO;AACL,gBAAM,OAAO;AAAA,QACf;AAAA,MACF;AACA,YAAM,2BAAW,IAAA;AACjB,iBAAW,KAAK,OAAO;AACrB,YAAI,KAAK,IAAI,EAAE,IAAI,EAAG,OAAM,IAAI,0BAA0B,EAAE,IAAI;AAChE,aAAK,IAAI,EAAE,IAAI;AAAA,MACjB;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,KAAK,QAAA;AACX,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,QAAI,CAAC,KAAK,gBAAgB,KAAK,SAAS,WAAW,EAAG;AACtD,UAAM,QAAQ,WAAW,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,MAAA,CAAO,CAAC;AAAA,EAC9D;AACF;"}
1
+ {"version":3,"file":"manager.js","names":["#sources","#shouldClose","#lazyTools","#onDiscoveryError"],"sources":["../../../../../src/activities/chat/mcp/manager.ts"],"sourcesContent":["import type { AnyServerTool } from '../tools/tool-definition'\nimport type { ChatMCPOptions, MCPToolSource } from './types'\n\n/**\n * Bind the source's `readResource` onto a ui-linked tool's `metadata.mcp` so it\n * travels with the tool to the server-tool execution/emit site (`tool-calls.ts`).\n *\n * `discover()` is the single place in `@tanstack/ai` that has both a tool and\n * its originating source, and `@tanstack/ai` must not import `@tanstack/ai-mcp`,\n * so this is where the source handle is threaded onto the tool. Only tools that\n * actually link a `ui://` resource (their discovery stamped\n * `metadata.mcp.uiResourceUri`) and whose source can read resources get bound;\n * everything else is left untouched.\n *\n * This mutates the discovered tool's `metadata.mcp` in place. That is safe\n * because discovery returns fresh tool objects per `discover()` call: the bound\n * `readResource` closes over `source`, whose connection stays live until the run\n * drains. If discovery results were ever cached and reused across runs, this\n * would bind a closure over an already-closed source — bind onto a copy then.\n */\nfunction bindReadResource(tool: AnyServerTool, source: MCPToolSource): void {\n if (!source.readResource) return\n const meta = (\n tool.metadata as { mcp?: { uiResourceUri?: string } } | undefined\n )?.mcp\n if (!meta?.uiResourceUri) return\n ;(meta as { readResource?: MCPToolSource['readResource'] }).readResource =\n source.readResource.bind(source)\n}\n\nexport class MCPDuplicateToolNameError extends Error {\n constructor(public readonly toolName: string) {\n super(\n `Duplicate MCP tool name \"${toolName}\" in chat({ mcp.clients }). ` +\n `Set a unique \\`prefix\\` on one of the MCP clients (or use a pool, ` +\n `which auto-prefixes) to disambiguate.`,\n )\n this.name = 'MCPDuplicateToolNameError'\n }\n}\n\n/**\n * Encapsulates MCP tool discovery + connection lifecycle for chat().\n * Built from chat()'s `mcp` option; runners only call `discover()` then\n * `dispose()`. A manager built from `undefined` is an inert no-op\n * (`discover()` → `[]`, `dispose()` → no-op), so runners need no branching.\n */\nexport class MCPManager {\n static from(options: ChatMCPOptions | undefined): MCPManager {\n return new MCPManager(options)\n }\n\n readonly #sources: ReadonlyArray<MCPToolSource>\n readonly #shouldClose: boolean\n readonly #lazyTools: boolean\n readonly #onDiscoveryError?: (\n error: unknown,\n source: MCPToolSource,\n ) => void | Promise<void>\n\n private constructor(options: ChatMCPOptions | undefined) {\n this.#sources = options?.clients ?? []\n // default 'close'; only 'keep-alive' disables closing\n this.#shouldClose = options ? options.connection !== 'keep-alive' : false\n this.#lazyTools = options?.lazyTools ?? false\n this.#onDiscoveryError = options?.onDiscoveryError\n }\n\n /**\n * Discover + merge tools from all sources. Throws on a fatal discovery error\n * (no `onDiscoveryError`, or it re-threw) or a duplicate tool name; in that\n * case it first closes any connected sources when the policy is 'close'.\n */\n async discover(): Promise<Array<AnyServerTool>> {\n if (this.#sources.length === 0) return []\n try {\n const settled = await Promise.allSettled(\n this.#sources.map((s) => s.tools({ lazy: this.#lazyTools })),\n )\n const tools: Array<AnyServerTool> = []\n const zipped = this.#sources.map(\n (source, i) => [source, settled[i]] as const,\n )\n for (const [source, result] of zipped) {\n if (result === undefined) continue\n if (result.status === 'fulfilled') {\n for (const t of result.value) {\n bindReadResource(t, source)\n tools.push(t)\n }\n } else if (this.#onDiscoveryError) {\n // throw/reject inside handler ⇒ propagate (fail-fast); return ⇒ skip\n await this.#onDiscoveryError(result.reason, source)\n } else {\n throw result.reason\n }\n }\n const seen = new Set<string>()\n for (const t of tools) {\n if (seen.has(t.name)) throw new MCPDuplicateToolNameError(t.name)\n seen.add(t.name)\n }\n return tools\n } catch (err) {\n await this.dispose() // cleanup-on-failure (no-op if keep-alive)\n throw err\n }\n }\n\n /** Close sources iff policy is 'close'. Idempotent; never throws. */\n async dispose(): Promise<void> {\n if (!this.#shouldClose || this.#sources.length === 0) return\n await Promise.allSettled(this.#sources.map((s) => s.close()))\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAoBA,SAAS,iBAAiB,MAAqB,QAA6B;CAC1E,IAAI,CAAC,OAAO,cAAc;CAC1B,MAAM,OACJ,KAAK,UACJ;CACH,IAAI,CAAC,MAAM,eAAe;CACzB,KAA2D,eAC1D,OAAO,aAAa,KAAK,MAAM;AACnC;AAEA,IAAa,4BAAb,cAA+C,MAAM;CACvB;CAA5B,YAAY,UAAkC;EAC5C,MACE,4BAA4B,SAAS,oIAGvC;EAL0B,KAAA,WAAA;EAM1B,KAAK,OAAO;CACd;AACF;;;;;;;AAQA,IAAa,aAAb,MAAa,WAAW;CACtB,OAAO,KAAK,SAAiD;EAC3D,OAAO,IAAI,WAAW,OAAO;CAC/B;CAEA;CACA;CACA;CACA;CAKA,YAAoB,SAAqC;EACvD,KAAKA,WAAW,SAAS,WAAW,CAAC;EAErC,KAAKC,eAAe,UAAU,QAAQ,eAAe,eAAe;EACpE,KAAKC,aAAa,SAAS,aAAa;EACxC,KAAKC,oBAAoB,SAAS;CACpC;;;;;;CAOA,MAAM,WAA0C;EAC9C,IAAI,KAAKH,SAAS,WAAW,GAAG,OAAO,CAAC;EACxC,IAAI;GACF,MAAM,UAAU,MAAM,QAAQ,WAC5B,KAAKA,SAAS,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,KAAKE,WAAW,CAAC,CAAC,CAC7D;GACA,MAAM,QAA8B,CAAC;GACrC,MAAM,SAAS,KAAKF,SAAS,KAC1B,QAAQ,MAAM,CAAC,QAAQ,QAAQ,EAAE,CACpC;GACA,KAAK,MAAM,CAAC,QAAQ,WAAW,QAAQ;IACrC,IAAI,WAAW,KAAA,GAAW;IAC1B,IAAI,OAAO,WAAW,aACpB,KAAK,MAAM,KAAK,OAAO,OAAO;KAC5B,iBAAiB,GAAG,MAAM;KAC1B,MAAM,KAAK,CAAC;IACd;SACK,IAAI,KAAKG,mBAEd,MAAM,KAAKA,kBAAkB,OAAO,QAAQ,MAAM;SAElD,MAAM,OAAO;GAEjB;GACA,MAAM,uBAAO,IAAI,IAAY;GAC7B,KAAK,MAAM,KAAK,OAAO;IACrB,IAAI,KAAK,IAAI,EAAE,IAAI,GAAG,MAAM,IAAI,0BAA0B,EAAE,IAAI;IAChE,KAAK,IAAI,EAAE,IAAI;GACjB;GACA,OAAO;EACT,SAAS,KAAK;GACZ,MAAM,KAAK,QAAQ;GACnB,MAAM;EACR;CACF;;CAGA,MAAM,UAAyB;EAC7B,IAAI,CAAC,KAAKF,gBAAgB,KAAKD,SAAS,WAAW,GAAG;EACtD,MAAM,QAAQ,WAAW,KAAKA,SAAS,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9D;AACF"}
@@ -1,4 +1,4 @@
1
- import { ServerTool } from '../tools/tool-definition.js';
1
+ import { AnyServerTool } from '../tools/tool-definition.js';
2
2
  /**
3
3
  * The shape `readResource` resolves to — a structural subset of MCP's
4
4
  * `ReadResourceResult`. Single source of truth shared by
@@ -23,7 +23,7 @@ export interface McpResourceReadResult {
23
23
  export interface MCPToolSource {
24
24
  tools: (options?: {
25
25
  lazy?: boolean;
26
- }) => Promise<Array<ServerTool>>;
26
+ }) => Promise<Array<AnyServerTool>>;
27
27
  close: () => Promise<void>;
28
28
  /**
29
29
  * Reads an MCP resource by URI. Used by the chat manager to eagerly fetch