@tanstack/ai 0.59.0 → 0.63.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 (123) hide show
  1. package/README.md +1 -0
  2. package/dist/esm/activities/chat/adapter.d.ts +9 -0
  3. package/dist/esm/activities/chat/adapter.js +1 -0
  4. package/dist/esm/activities/chat/adapter.js.map +1 -1
  5. package/dist/esm/activities/chat/agents/define-agent.d.ts +17 -5
  6. package/dist/esm/activities/chat/agents/define-agent.js.map +1 -1
  7. package/dist/esm/activities/chat/agents/spawn.d.ts +2 -0
  8. package/dist/esm/activities/chat/agents/spawn.js +8 -5
  9. package/dist/esm/activities/chat/agents/spawn.js.map +1 -1
  10. package/dist/esm/activities/chat/index.js +289 -78
  11. package/dist/esm/activities/chat/index.js.map +1 -1
  12. package/dist/esm/activities/chat/messages.js +35 -19
  13. package/dist/esm/activities/chat/messages.js.map +1 -1
  14. package/dist/esm/activities/chat/middleware/types.d.ts +1 -0
  15. package/dist/esm/activities/chat/middleware/types.js.map +1 -1
  16. package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -2
  17. package/dist/esm/activities/chat/stream/message-updaters.js +11 -3
  18. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
  19. package/dist/esm/activities/chat/stream/processor.d.ts +11 -10
  20. package/dist/esm/activities/chat/stream/processor.js +51 -28
  21. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  22. package/dist/esm/activities/chat/tools/tool-calls.d.ts +16 -2
  23. package/dist/esm/activities/chat/tools/tool-calls.js +57 -16
  24. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  25. package/dist/esm/activities/chat/tools/tool-definition.d.ts +4 -0
  26. package/dist/esm/activities/chat/tools/tool-definition.js +4 -0
  27. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  28. package/dist/esm/activities/embed/adapter.d.ts +7 -0
  29. package/dist/esm/activities/embed/adapter.js +1 -0
  30. package/dist/esm/activities/embed/adapter.js.map +1 -1
  31. package/dist/esm/activities/embed/index.js +2 -0
  32. package/dist/esm/activities/embed/index.js.map +1 -1
  33. package/dist/esm/activities/evaluate/adapter.d.ts +4 -0
  34. package/dist/esm/activities/evaluate/adapter.js.map +1 -1
  35. package/dist/esm/activities/evaluate/index.d.ts +4 -0
  36. package/dist/esm/activities/evaluate/index.js +3 -1
  37. package/dist/esm/activities/evaluate/index.js.map +1 -1
  38. package/dist/esm/activities/files/adapter.d.ts +97 -0
  39. package/dist/esm/activities/files/adapter.js +45 -0
  40. package/dist/esm/activities/files/adapter.js.map +1 -0
  41. package/dist/esm/activities/files/index.d.ts +66 -0
  42. package/dist/esm/activities/files/index.js +78 -0
  43. package/dist/esm/activities/files/index.js.map +1 -0
  44. package/dist/esm/activities/generateImage/adapter.d.ts +8 -0
  45. package/dist/esm/activities/generateImage/adapter.js +1 -0
  46. package/dist/esm/activities/generateImage/adapter.js.map +1 -1
  47. package/dist/esm/activities/generateImage/index.js +2 -0
  48. package/dist/esm/activities/generateImage/index.js.map +1 -1
  49. package/dist/esm/activities/generateVideo/adapter.d.ts +8 -0
  50. package/dist/esm/activities/generateVideo/adapter.js +1 -0
  51. package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
  52. package/dist/esm/activities/generateVideo/index.js +3 -0
  53. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  54. package/dist/esm/activities/generateWorld/adapter.d.ts +4 -2
  55. package/dist/esm/activities/generateWorld/adapter.js.map +1 -1
  56. package/dist/esm/activities/generateWorld/index.d.ts +4 -3
  57. package/dist/esm/activities/generateWorld/index.js +5 -4
  58. package/dist/esm/activities/generateWorld/index.js.map +1 -1
  59. package/dist/esm/activities/index.d.ts +6 -3
  60. package/dist/esm/activities/index.js +13 -11
  61. package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +2 -0
  62. package/dist/esm/activities/summarize/chat-stream-summarize.js +8 -8
  63. package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
  64. package/dist/esm/client.d.ts +3 -1
  65. package/dist/esm/client.js +2 -1
  66. package/dist/esm/client.js.map +1 -1
  67. package/dist/esm/index.d.ts +4 -3
  68. package/dist/esm/index.js +5 -3
  69. package/dist/esm/interrupt-resume.js +29 -4
  70. package/dist/esm/interrupt-resume.js.map +1 -1
  71. package/dist/esm/middlewares/otel.d.ts +5 -2
  72. package/dist/esm/middlewares/otel.js +114 -0
  73. package/dist/esm/middlewares/otel.js.map +1 -1
  74. package/dist/esm/types.d.ts +114 -14
  75. package/dist/esm/utilities/ag-ui-wire.js +39 -16
  76. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  77. package/dist/esm/utilities/content-source.d.ts +60 -0
  78. package/dist/esm/utilities/content-source.js +85 -0
  79. package/dist/esm/utilities/content-source.js.map +1 -0
  80. package/dist/esm/utilities/provider-executed.d.ts +7 -0
  81. package/dist/esm/utilities/provider-executed.js +10 -1
  82. package/dist/esm/utilities/provider-executed.js.map +1 -1
  83. package/dist/esm/utilities/tool-result.d.ts +14 -3
  84. package/dist/esm/utilities/tool-result.js +26 -3
  85. package/dist/esm/utilities/tool-result.js.map +1 -1
  86. package/package.json +4 -4
  87. package/skills/ai-core/adapter-configuration/SKILL.md +62 -0
  88. package/skills/ai-core/chat-experience/SKILL.md +134 -0
  89. package/skills/ai-core/media-generation/SKILL.md +8 -0
  90. package/skills/ai-core/tool-calling/SKILL.md +103 -0
  91. package/src/activities/chat/adapter.ts +10 -0
  92. package/src/activities/chat/agents/define-agent.ts +20 -3
  93. package/src/activities/chat/agents/spawn.ts +20 -12
  94. package/src/activities/chat/index.ts +458 -99
  95. package/src/activities/chat/messages.ts +52 -6
  96. package/src/activities/chat/middleware/types.ts +1 -0
  97. package/src/activities/chat/stream/message-updaters.ts +27 -2
  98. package/src/activities/chat/stream/processor.ts +81 -49
  99. package/src/activities/chat/tools/tool-calls.ts +104 -9
  100. package/src/activities/chat/tools/tool-definition.ts +8 -0
  101. package/src/activities/embed/adapter.ts +7 -0
  102. package/src/activities/embed/index.ts +5 -0
  103. package/src/activities/evaluate/adapter.ts +4 -0
  104. package/src/activities/evaluate/index.ts +6 -0
  105. package/src/activities/files/adapter.ts +120 -0
  106. package/src/activities/files/index.ts +113 -0
  107. package/src/activities/generateImage/adapter.ts +8 -0
  108. package/src/activities/generateImage/index.ts +4 -0
  109. package/src/activities/generateVideo/adapter.ts +8 -0
  110. package/src/activities/generateVideo/index.ts +7 -0
  111. package/src/activities/generateWorld/adapter.ts +4 -2
  112. package/src/activities/generateWorld/index.ts +7 -6
  113. package/src/activities/index.ts +25 -1
  114. package/src/activities/summarize/chat-stream-summarize.ts +22 -12
  115. package/src/client.ts +8 -0
  116. package/src/index.ts +17 -0
  117. package/src/interrupt-resume.ts +55 -4
  118. package/src/middlewares/otel.ts +161 -3
  119. package/src/types.ts +114 -14
  120. package/src/utilities/ag-ui-wire.ts +72 -17
  121. package/src/utilities/content-source.ts +138 -0
  122. package/src/utilities/provider-executed.ts +13 -0
  123. package/src/utilities/tool-result.ts +45 -3
@@ -1,6 +1,6 @@
1
1
  import { AdapterYieldChunk } from '../../../utilities/adapter-yield-chunk.js';
2
2
  import { ToolApprovalResolution } from '../../../interrupts.js';
3
- import { AnyTool, CustomEvent, EmitCustomEventOptions, Interrupt, ModelMessage, RunFinishedEvent, StreamChunk, Tool, ToolCall, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent, ToolExecutionContext } from '../../../types.js';
3
+ import { AnyTool, CustomEvent, EmitCustomEventOptions, Interrupt, ModelMessage, RunFinishedEvent, StreamChunk, Tool, ToolCall, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent, ToolExecutionContext, ToolInputResponse, ToolResultOutcome } from '../../../types.js';
4
4
  import { AfterToolCallInfo, BeforeToolCallDecision } from '../middleware/types.js';
5
5
  import { ContextFromTool, DefinedContext, MergeContext, UnionToIntersection } from '../runtime-context-types.js';
6
6
  /** Marks the synthetic tool that runs a subagent. */
@@ -113,6 +113,8 @@ export interface ToolResult {
113
113
  toolName: string;
114
114
  result: any;
115
115
  state?: 'output-available' | 'output-error';
116
+ /** Set when the user or middleware cancelled or denied the tool call; state is output-error. */
117
+ outcome?: ToolResultOutcome;
116
118
  /** Duration of tool execution in milliseconds (only for server-executed tools) */
117
119
  duration?: number;
118
120
  /**
@@ -138,9 +140,19 @@ export interface ClientToolRequest {
138
140
  toolName: string;
139
141
  input: any;
140
142
  }
143
+ /** Form or sampling input that paused a server tool. */
144
+ export interface McpInputRequest {
145
+ toolCallId: string;
146
+ toolName: string;
147
+ kind: 'form' | 'sampling';
148
+ request: unknown;
149
+ }
141
150
  export interface ToolResumeExecutionState {
151
+ clientToolErrors?: ReadonlyMap<string, string>;
142
152
  deniedToolResults?: ReadonlyMap<string, unknown>;
143
153
  cancelledToolCallIds?: ReadonlySet<string>;
154
+ /** Answers to `mcp_input` interrupts, by tool call id. */
155
+ inputResponses?: ReadonlyMap<string, ToolInputResponse>;
144
156
  }
145
157
  interface ExecuteToolCallsResult {
146
158
  /** Tool results ready to send to LLM */
@@ -149,6 +161,8 @@ interface ExecuteToolCallsResult {
149
161
  needsApproval: Array<ApprovalRequest>;
150
162
  /** Tools that need client-side execution */
151
163
  needsClientExecution: Array<ClientToolRequest>;
164
+ /** Server tools that paused for MCP form or sampling input */
165
+ inputRequired: Array<McpInputRequest>;
152
166
  /** Interrupts raised by subagents that run as tools */
153
167
  subagentInterrupts: Array<Interrupt>;
154
168
  }
@@ -156,7 +170,7 @@ interface ExecuteToolCallsResult {
156
170
  * Execute a server-side tool with event polling, output validation, and middleware hooks.
157
171
  * Yields CustomEvent chunks during execution and pushes the result to the results array.
158
172
  */
159
- export declare function executeServerTool<TContext = unknown>(toolCall: ToolCall, tool: AnyTool, toolName: string, input: unknown, context: ToolExecutionContext<TContext>, pendingEvents: Array<CustomEvent | StreamChunk>, results: Array<ToolResult>, middlewareHooks?: ToolExecutionMiddlewareHooks, subagentInterrupts?: Array<Interrupt>): AsyncGenerator<CustomEvent | StreamChunk, void, void>;
173
+ export declare function executeServerTool<TContext = unknown>(toolCall: ToolCall, tool: AnyTool, toolName: string, input: unknown, context: ToolExecutionContext<TContext>, pendingEvents: Array<CustomEvent | StreamChunk>, results: Array<ToolResult>, middlewareHooks?: ToolExecutionMiddlewareHooks, inputRequired?: Array<McpInputRequest>, subagentInterrupts?: Array<Interrupt>): AsyncGenerator<CustomEvent | StreamChunk, void, void>;
160
174
  /**
161
175
  * Execute tool calls based on their configuration.
162
176
  * Yields CustomEvent chunks during tool execution for real-time progress updates.
@@ -1,5 +1,6 @@
1
1
  import { tanstackMetadata } from "../../../utilities/merge-metadata.js";
2
- import { isStandardSchema, parseWithStandardSchema } from "./schema-converter.js";
2
+ import { StandardSchemaValidationError, isStandardSchema, parseWithStandardSchema, validateWithStandardSchema } from "./schema-converter.js";
3
+ import { isProviderExecutedToolCall } from "../../../utilities/provider-executed.js";
3
4
  import { normalizeToolResult } from "../../../utilities/tool-result.js";
4
5
  //#region src/activities/chat/tools/tool-calls.ts
5
6
  function safeJsonParse(value) {
@@ -235,6 +236,13 @@ var ToolCallManager = class {
235
236
  this.toolCallsMap.clear();
236
237
  }
237
238
  };
239
+ function isMcpInputRequired(value) {
240
+ if (typeof value !== "object" || value === null) return false;
241
+ if (!("name" in value) || value.name !== "MCPInputRequiredError") return false;
242
+ if (!("kind" in value)) return false;
243
+ if (!(value.kind === "form" || value.kind === "sampling")) return false;
244
+ return "request" in value;
245
+ }
238
246
  function approvalResolution(approvals, toolCallId) {
239
247
  return approvals.get(toolCallId) ?? approvals.get(`approval_${toolCallId}`);
240
248
  }
@@ -316,7 +324,7 @@ async function applyBeforeToolCallDecision(toolCall, tool, input, toolName, midd
316
324
  * Execute a server-side tool with event polling, output validation, and middleware hooks.
317
325
  * Yields CustomEvent chunks during execution and pushes the result to the results array.
318
326
  */
319
- async function* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks, subagentInterrupts) {
327
+ async function* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks, inputRequired, subagentInterrupts) {
320
328
  const startTime = Date.now();
321
329
  try {
322
330
  if (!tool.execute) throw new Error(`Tool ${toolName} has no execute() implementation`);
@@ -389,6 +397,16 @@ async function* executeServerTool(toolCall, tool, toolName, input, context, pend
389
397
  let pendingEvent;
390
398
  while ((pendingEvent = pendingEvents.shift()) !== void 0) yield pendingEvent;
391
399
  if (error instanceof MiddlewareAbortError) throw error;
400
+ if (isMcpInputRequired(error)) {
401
+ if (!inputRequired) throw error;
402
+ inputRequired.push({
403
+ toolCallId: toolCall.id,
404
+ toolName,
405
+ kind: error.kind,
406
+ request: error.request
407
+ });
408
+ return;
409
+ }
392
410
  const message = error instanceof Error ? error.message : "Unknown error";
393
411
  results.push({
394
412
  toolCallId: toolCall.id,
@@ -409,10 +427,21 @@ async function* executeServerTool(toolCall, tool, toolName, input, context, pend
409
427
  });
410
428
  }
411
429
  }
412
- function buildClientToolResult(toolCallId, toolName, tool, rawResult, input) {
430
+ async function buildClientToolResult(toolCallId, toolName, tool, rawResult, input, errorText) {
431
+ if (errorText !== void 0) return {
432
+ toolCallId,
433
+ toolName,
434
+ result: { error: errorText },
435
+ input,
436
+ state: "output-error"
437
+ };
413
438
  try {
414
439
  let result = rawResult;
415
- if (tool.outputSchema && isStandardSchema(tool.outputSchema)) result = parseWithStandardSchema(tool.outputSchema, result);
440
+ if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {
441
+ const validation = await validateWithStandardSchema(tool.outputSchema, result);
442
+ if (!validation.success) throw new StandardSchemaValidationError(validation.issues);
443
+ result = validation.data;
444
+ }
416
445
  const parsed = typeof result === "string" ? safeJsonParse(result) : result ?? null;
417
446
  return {
418
447
  toolCallId,
@@ -450,6 +479,7 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
450
479
  const results = [];
451
480
  const needsApproval = [];
452
481
  const needsClientExecution = [];
482
+ const inputRequired = [];
453
483
  const subagentInterrupts = [];
454
484
  const toolMap = /* @__PURE__ */ new Map();
455
485
  for (const tool of tools) toolMap.set(tool.name, tool);
@@ -457,6 +487,7 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
457
487
  return toolMap.get(tc.function.name)?.needsApproval && approvalResolution(approvals, tc.id) === void 0 && !resumeState?.cancelledToolCallIds?.has(tc.id);
458
488
  });
459
489
  for (const toolCall of toolCalls) {
490
+ if (isProviderExecutedToolCall(toolCall)) continue;
460
491
  const tool = toolMap.get(toolCall.function.name);
461
492
  const toolName = toolCall.function.name;
462
493
  if (!tool) {
@@ -478,7 +509,8 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
478
509
  toolCallId: toolCall.id,
479
510
  toolName,
480
511
  result: { error: "Tool execution cancelled" },
481
- state: "output-error"
512
+ state: "output-error",
513
+ outcome: "cancelled"
482
514
  });
483
515
  continue;
484
516
  }
@@ -511,10 +543,12 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
511
543
  continue;
512
544
  }
513
545
  const pendingEvents = [];
546
+ const inputResponse = resumeState?.inputResponses?.get(toolCall.id);
514
547
  const context = {
515
548
  toolCallId: toolCall.id,
516
549
  context: userContext,
517
550
  abortSignal,
551
+ ...inputResponse !== void 0 ? { inputResponse } : {},
518
552
  emitCustomEvent: (eventName, value, options) => {
519
553
  if (createCustomEventChunk) pendingEvents.push(createCustomEventChunk(eventName, {
520
554
  ...value,
@@ -529,7 +563,8 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
529
563
  if (resolution !== void 0) {
530
564
  if (isApproved(resolution)) {
531
565
  input = editedApprovalArgs(resolution) ?? input;
532
- if (clientResults.has(toolCall.id)) results.push(buildClientToolResult(toolCall.id, toolName, tool, clientResults.get(toolCall.id), input));
566
+ const clientError = resumeState?.clientToolErrors?.get(toolCall.id);
567
+ if (clientResults.has(toolCall.id) || clientError !== void 0) results.push(await buildClientToolResult(toolCall.id, toolName, tool, clientResults.get(toolCall.id), input, clientError));
533
568
  else needsClientExecution.push({
534
569
  toolCallId: toolCall.id,
535
570
  toolName,
@@ -540,7 +575,8 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
540
575
  toolName,
541
576
  result: resumeState?.deniedToolResults?.get(toolCall.id) ?? deniedApprovalResult(resolution),
542
577
  input,
543
- state: "output-error"
578
+ state: "output-error",
579
+ outcome: "denied"
544
580
  });
545
581
  } else needsApproval.push({
546
582
  toolCallId: toolCall.id,
@@ -548,12 +584,15 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
548
584
  input,
549
585
  approvalId
550
586
  });
551
- } else if (clientResults.has(toolCall.id)) results.push(buildClientToolResult(toolCall.id, toolName, tool, clientResults.get(toolCall.id), input));
552
- else needsClientExecution.push({
553
- toolCallId: toolCall.id,
554
- toolName,
555
- input
556
- });
587
+ } else {
588
+ const clientError = resumeState?.clientToolErrors?.get(toolCall.id);
589
+ if (clientResults.has(toolCall.id) || clientError !== void 0) results.push(await buildClientToolResult(toolCall.id, toolName, tool, clientResults.get(toolCall.id), input, clientError));
590
+ else needsClientExecution.push({
591
+ toolCallId: toolCall.id,
592
+ toolName,
593
+ input
594
+ });
595
+ }
557
596
  continue;
558
597
  }
559
598
  if (tool.needsApproval) {
@@ -567,13 +606,14 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
567
606
  if (!decision.proceed) continue;
568
607
  input = decision.input;
569
608
  }
570
- yield* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks, subagentInterrupts);
609
+ yield* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks, inputRequired, subagentInterrupts);
571
610
  } else results.push({
572
611
  toolCallId: toolCall.id,
573
612
  toolName,
574
613
  result: resumeState?.deniedToolResults?.get(toolCall.id) ?? deniedApprovalResult(resolution),
575
614
  input,
576
- state: "output-error"
615
+ state: "output-error",
616
+ outcome: "denied"
577
617
  });
578
618
  } else needsApproval.push({
579
619
  toolCallId: toolCall.id,
@@ -588,12 +628,13 @@ async function* executeToolCalls(toolCalls, tools, approvals = /* @__PURE__ */ n
588
628
  if (!decision.proceed) continue;
589
629
  input = decision.input;
590
630
  }
591
- yield* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks, subagentInterrupts);
631
+ yield* executeServerTool(toolCall, tool, toolName, input, context, pendingEvents, results, middlewareHooks, inputRequired, subagentInterrupts);
592
632
  }
593
633
  return {
594
634
  results,
595
635
  needsApproval,
596
636
  needsClientExecution,
637
+ inputRequired,
597
638
  subagentInterrupts
598
639
  };
599
640
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-calls.js","names":[],"sources":["../../../../../src/activities/chat/tools/tool-calls.ts"],"sourcesContent":["import { normalizeToolResult } from '../../../utilities/tool-result'\nimport { tanstackMetadata } from '../../../utilities/merge-metadata'\nimport type { AdapterYieldChunk } from '../../../utilities/adapter-yield-chunk'\nimport { isStandardSchema, parseWithStandardSchema } from './schema-converter'\nimport type { ToolApprovalResolution } from '../../../interrupts'\nimport type {\n AnyTool,\n ContentPart,\n CustomEvent,\n EmitCustomEventOptions,\n Interrupt,\n ModelMessage,\n RunFinishedEvent,\n StreamChunk,\n Tool,\n ToolCall,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolExecutionContext,\n ToolOutputState,\n} from '../../../types'\nimport type {\n AfterToolCallInfo,\n BeforeToolCallDecision,\n} from '../middleware/types'\nimport type { McpResourceReadResult } from '../mcp/types'\nimport type {\n ContextFromTool,\n DefinedContext,\n MergeContext,\n UnionToIntersection,\n} from '../runtime-context-types'\n\nfunction safeJsonParse(value: string): unknown {\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n\n/** Marks the synthetic tool that runs a subagent. */\nexport const SUBAGENT_TOOL = Symbol.for('tanstack.ai.subagentTool')\n\n/** Set on the tool context of a subagent tool. Streams a child chunk live. */\nexport const EMIT_STREAM_CHUNK = Symbol.for('tanstack.ai.emitStreamChunk')\n\n/** What a subagent tool's `execute` returns. */\nexport interface SubagentToolOutcome {\n subagentRunId: string\n text: string\n error?: string\n /** Set when the child stopped for outside input. The tool call stays open. */\n interrupts?: Array<Interrupt>\n}\n\nfunction isSubagentTool(tool: AnyTool): boolean {\n return (tool as { [SUBAGENT_TOOL]?: true })[SUBAGENT_TOOL] === true\n}\n\n/**\n * MCP Apps metadata attached to a server tool at discovery (see\n * `@tanstack/ai-mcp` discovery + `MCPManager.discover()`).\n *\n * - `uiResourceUri` / `serverId` are stamped by ai-mcp at tool discovery.\n * - `readResource` is bound by `MCPManager.discover()` (the one site that has\n * both the tool and its originating source) so the resource can be eagerly\n * read at the emit site. Under `chat()`-managed MCP lifecycle\n * (`connection:'close'`), the MCP source is not disposed until the run\n * drains, so `readResource` is still live at this emit point. Note: a caller\n * who closes the MCP source early (outside `chat()`'s managed lifecycle)\n * degrades fail-soft — `readResource` may reject, the widget is absent, but\n * the tool result still flows to the model.\n * `@tanstack/ai` never imports `@tanstack/ai-mcp`; this travels structurally\n * on the tool.\n */\ninterface McpToolAppMeta {\n uiResourceUri?: string\n serverId?: string\n /** Server-native (unprefixed) MCP tool name — used as the renderer's toolName. */\n serverToolName?: string\n readResource?: (uri: string) => Promise<McpResourceReadResult>\n}\n\nfunction readMcpAppMeta(tool: AnyTool): McpToolAppMeta | undefined {\n const meta = (tool.metadata as { mcp?: McpToolAppMeta } | undefined)?.mcp\n return meta\n}\n\n/**\n * Eagerly read a tool's linked `ui://` resource (MCP Apps) and emit a\n * `ui-resource` CUSTOM event so the client can render the widget. The model\n * still receives the normal text tool-result; the widget rides alongside and\n * never enters model input.\n *\n * Fail-soft: any read error logs a warning and emits nothing — it never throws,\n * so the normal tool-result still flows and a broken widget cannot break the run.\n */\nasync function emitUiResourceIfLinked<TContext>(\n tool: AnyTool,\n context: ToolExecutionContext<TContext>,\n): Promise<void> {\n const mcp = readMcpAppMeta(tool)\n const uiUri = mcp?.uiResourceUri\n if (!uiUri || !mcp.readResource) return\n\n // The try covers ONLY the fallible read — keep `emitCustomEvent` out of it so\n // an exception from the emit path can't be mislabeled as a read failure.\n let matched: McpResourceReadResult['contents'][number] | undefined\n try {\n const res = await mcp.readResource(uiUri)\n // Emit ONLY the content whose uri matches the requested `uiUri`. A source\n // can return unrelated contents; falling back to `contents[0]` would risk\n // rendering a widget that doesn't correspond to the linked resource. This\n // is a display widget — a mismatched resource is worse than none, so if no\n // content matches we fail-soft (warn + return) rather than emit.\n matched = res.contents.find((c) => c.uri === uiUri)\n } catch (err) {\n // fail-soft — the text tool-result already flows; a broken widget must\n // not break the run.\n console.warn(`[mcp-apps] failed to read ui resource ${uiUri}:`, err)\n return\n }\n if (!matched) {\n console.warn(\n `[mcp-apps] ui resource ${uiUri} returned no content matching that uri; not emitting`,\n )\n return\n }\n // NOTE: `toolCallId` is intentionally NOT set here — it is stamped onto\n // every emitted event by the `executeToolCalls` context wrapper, so the\n // UIResourceEvent.value.toolCallId / UIResourcePart.toolCallId contract is\n // still satisfied downstream.\n context.emitCustomEvent('ui-resource', {\n resource: {\n uri: matched.uri,\n mimeType: matched.mimeType ?? 'text/html',\n text: matched.text,\n blob: matched.blob,\n },\n serverId: mcp.serverId,\n toolName: mcp.serverToolName ?? tool.name,\n meta: undefined,\n })\n}\n\n/**\n * Optional middleware hooks for tool execution.\n * When provided, these callbacks are invoked before/after each tool execution.\n */\nexport interface ToolExecutionMiddlewareHooks {\n onBeforeToolCall?: (\n toolCall: ToolCall,\n tool: Tool | undefined,\n args: unknown,\n ) => Promise<BeforeToolCallDecision>\n onAfterToolCall?: (info: AfterToolCallInfo) => Promise<void>\n}\n\n/**\n * Error thrown when middleware decides to abort the chat run during tool execution.\n */\nexport class MiddlewareAbortError extends Error {\n constructor(reason: string) {\n super(reason)\n this.name = 'MiddlewareAbortError'\n }\n}\n\n// The leaf context-inference primitives (ContextFromTool, MergeContext,\n// UnionToIntersection, DefinedContext) are shared with the chat activity\n// options layer — see ../runtime-context-types.\ntype RequiredContextFromToolUnion<T> = T extends unknown\n ? undefined extends ContextFromTool<T>\n ? never\n : ContextFromTool<T>\n : never\n\ntype ContextFromToolUnion<T> = [\n UnionToIntersection<DefinedContext<ContextFromTool<T>>>,\n] extends [never]\n ? unknown\n : [RequiredContextFromToolUnion<T>] extends [never]\n ? UnionToIntersection<DefinedContext<ContextFromTool<T>>> | undefined\n : UnionToIntersection<DefinedContext<ContextFromTool<T>>>\n\ntype ContextFromTools<TTools> = TTools extends readonly [\n infer THead,\n ...infer TTail,\n]\n ? MergeContext<ContextFromTool<THead>, ContextFromTools<TTail>>\n : TTools extends ReadonlyArray<infer TTool>\n ? ContextFromToolUnion<TTool>\n : unknown\n\ntype ExecuteToolsContextArgs<TContext> = undefined extends TContext\n ? [userContext?: TContext]\n : [userContext: TContext]\n\n/**\n * Manages tool call accumulation and execution for the chat() method's automatic tool execution loop.\n *\n * Responsibilities:\n * - Accumulates streaming tool call events (ID, name, arguments)\n * - Validates tool calls (filters out incomplete ones)\n * - Executes tool `execute` functions with parsed arguments\n * - Emits `TOOL_CALL_END` events for client visibility\n * - Returns tool result messages for conversation history\n *\n * This class is used internally by the AI.chat() method to handle the automatic\n * tool execution loop. It can also be used independently for custom tool execution logic.\n *\n * @example\n * ```typescript\n * const manager = new ToolCallManager(tools);\n *\n * // During streaming, accumulate tool calls\n * for await (const chunk of stream) {\n * if (chunk.type === 'TOOL_CALL_START') {\n * manager.addToolCallStartEvent(chunk);\n * } else if (chunk.type === 'TOOL_CALL_ARGS') {\n * manager.addToolCallArgsEvent(chunk);\n * }\n * }\n *\n * // After stream completes, execute tools\n * if (manager.hasToolCalls()) {\n * const toolResults = yield* manager.executeTools(finishEvent);\n * messages = [...messages, ...toolResults];\n * manager.clear();\n * }\n * ```\n */\nexport class ToolCallManager<\n TToolsOrContext = ReadonlyArray<AnyTool>,\n TContext = TToolsOrContext extends ReadonlyArray<AnyTool>\n ? ContextFromTools<TToolsOrContext>\n : TToolsOrContext,\n> {\n private readonly toolCallsMap = new Map<number, ToolCall>()\n private readonly tools: TToolsOrContext extends ReadonlyArray<AnyTool>\n ? TToolsOrContext\n : ReadonlyArray<AnyTool>\n\n constructor(\n tools: TToolsOrContext extends ReadonlyArray<AnyTool>\n ? TToolsOrContext\n : ReadonlyArray<AnyTool>,\n ) {\n this.tools = tools\n }\n\n /**\n * Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)\n */\n addToolCallStartEvent(event: ToolCallStartEvent): void {\n // AG-UI's TOOL_CALL_START carries no index, and a non-first-party or\n // malformed producer can send a second START for a toolCallId that is\n // already tracked. Without this guard, a repeat with the same index\n // overwrites the slot (wiping any TOOL_CALL_ARGS already accumulated),\n // and a repeat with a missing/different index inserts a duplicate row\n // that getToolCalls() returns twice, running the tool twice.\n for (const toolCall of this.toolCallsMap.values()) {\n if (toolCall.id === event.toolCallId) return\n }\n const index = (event as AdapterYieldChunk).index ?? this.toolCallsMap.size\n const name = event.toolCallName ?? event.toolName\n this.toolCallsMap.set(index, {\n id: event.toolCallId,\n type: 'function',\n function: {\n name,\n arguments: '',\n },\n ...(event.metadata !== undefined && { metadata: event.metadata }),\n })\n }\n\n /**\n * Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)\n */\n addToolCallArgsEvent(event: ToolCallArgsEvent): void {\n const extra = event as AdapterYieldChunk\n for (const [, toolCall] of this.toolCallsMap.entries()) {\n if (toolCall.id === event.toolCallId) {\n if (typeof extra.args === 'string' && extra.args !== '') {\n toolCall.function.arguments = extra.args\n } else {\n toolCall.function.arguments += event.delta\n }\n break\n }\n }\n }\n\n /**\n * Complete a tool call with its final input\n * Called when TOOL_CALL_END is received\n */\n completeToolCall(event: ToolCallEndEvent): void {\n for (const toolCall of this.toolCallsMap.values()) {\n if (toolCall.id !== event.toolCallId) continue\n if (event.input === undefined) return\n const normalized =\n event.input && typeof event.input === 'object' ? event.input : {}\n toolCall.function.arguments = JSON.stringify(normalized)\n return\n }\n }\n\n /**\n * Check if there are any complete tool calls to execute\n */\n hasToolCalls(): boolean {\n return this.getToolCalls().length > 0\n }\n\n /**\n * Get all complete tool calls (filtered for valid ID and name)\n */\n getToolCalls(): Array<ToolCall> {\n return Array.from(this.toolCallsMap.values()).filter(\n (tc) => tc.id && tc.function.name && tc.function.name.trim().length > 0,\n )\n }\n\n /**\n * Execute all tool calls and return tool result messages\n * Yields TOOL_CALL_END events for streaming\n * @param finishEvent - RUN_FINISHED event from the stream\n */\n async *executeTools(\n finishEvent: RunFinishedEvent,\n ...contextArgs: ExecuteToolsContextArgs<TContext>\n ): AsyncGenerator<AdapterYieldChunk, Array<ModelMessage>, void> {\n const toolCallsArray = this.getToolCalls()\n const toolResults: Array<ModelMessage> = []\n const hasRuntimeContext = contextArgs.length > 0\n const userContext = contextArgs[0]\n\n for (const toolCall of toolCallsArray) {\n const tool = this.tools.find((t) => t.name === toolCall.function.name)\n\n let toolResultContent: string | Array<ContentPart>\n let toolResultState: ToolOutputState | undefined\n // Holds the parsed/validated execution output before serialization.\n // Stays `undefined` when the tool has no `execute` (client-only\n // tools) or when execution throws.\n let toolOutput: unknown\n if (tool?.execute) {\n try {\n // Parse arguments (normalize null/non-object to {} for empty tool_use blocks)\n let args: unknown\n try {\n const argsString = toolCall.function.arguments.trim() || '{}'\n const parsed = JSON.parse(argsString)\n args = parsed && typeof parsed === 'object' ? parsed : {}\n } catch (parseError) {\n throw new Error(\n `Failed to parse tool arguments as JSON: ${toolCall.function.arguments}`,\n )\n }\n\n // Validate input against inputSchema (for Standard Schema compliant schemas)\n if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {\n try {\n args = parseWithStandardSchema(tool.inputSchema, args)\n } catch (validationError: unknown) {\n const message =\n validationError instanceof Error\n ? validationError.message\n : 'Validation failed'\n throw new Error(\n `Input validation failed for tool ${tool.name}: ${message}`,\n )\n }\n }\n\n // Execute the tool\n const executionContext = {\n toolCallId: toolCall.id,\n context: userContext,\n emitCustomEvent: () => {},\n } as ToolExecutionContext<TContext>\n let result = hasRuntimeContext\n ? await tool.execute(args, executionContext)\n : await tool.execute(args)\n\n // Validate output against outputSchema if provided (for Standard\n // Schema compliant schemas). Unlike the previous implementation we\n // intentionally validate `undefined`/`null` results too, so a tool\n // whose schema forbids them surfaces a validation error instead of\n // silently passing — the schema itself decides whether they're valid.\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n try {\n result = parseWithStandardSchema(tool.outputSchema, result)\n } catch (validationError: unknown) {\n const message =\n validationError instanceof Error\n ? validationError.message\n : 'Validation failed'\n throw new Error(\n `Output validation failed for tool ${tool.name}: ${message}`,\n )\n }\n }\n\n toolOutput = result\n toolResultContent = normalizeToolResult(result)\n } catch (error: unknown) {\n // If tool execution fails, add error message\n const message =\n error instanceof Error ? error.message : 'Unknown error'\n toolResultContent = `Error executing tool: ${message}`\n toolResultState = 'output-error'\n }\n } else {\n // Tool doesn't have execute function, add placeholder\n toolResultContent = `Tool ${toolCall.function.name} does not have an execute function`\n }\n\n // Emit TOOL_CALL_END event\n yield {\n type: 'TOOL_CALL_END',\n toolCallId: toolCall.id,\n toolCallName: toolCall.function.name,\n toolName: toolCall.function.name,\n model: (() => {\n const model = tanstackMetadata(finishEvent)?.model\n return typeof model === 'string' ? model : undefined\n })(),\n timestamp: Date.now(),\n // Typed parsed output (undefined for failed exec / client-only tools).\n ...(toolOutput !== undefined ? { output: toolOutput } : {}),\n result: toolResultContent,\n ...(toolResultState !== undefined && { state: toolResultState }),\n }\n\n // Add tool result message\n toolResults.push({\n role: 'tool',\n content: toolResultContent,\n toolCallId: toolCall.id,\n })\n }\n\n return toolResults\n }\n\n /**\n * Clear the tool calls map for the next iteration\n */\n clear(): void {\n this.toolCallsMap.clear()\n }\n}\n\nexport interface ToolResult {\n toolCallId: string\n toolName: string\n result: any\n state?: 'output-available' | 'output-error'\n /** Duration of tool execution in milliseconds (only for server-executed tools) */\n duration?: number\n /**\n * Parsed tool input (after JSON parse + optional Standard Schema validation).\n * Parsed tool input after JSON parse + optional Standard Schema validation.\n */\n input?: unknown\n /**\n * Parsed tool output before wire serialization. Surfaced on engine-emitted\n * `TOOL_CALL_END` events so consumers can read typed `output` without\n * re-parsing `result`. Undefined on error paths and when execution is skipped.\n */\n output?: unknown\n}\n\nexport interface ApprovalRequest {\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n}\n\nexport interface ClientToolRequest {\n toolCallId: string\n toolName: string\n input: any\n}\n\nexport interface ToolResumeExecutionState {\n deniedToolResults?: ReadonlyMap<string, unknown>\n cancelledToolCallIds?: ReadonlySet<string>\n}\n\nfunction approvalResolution(\n approvals: ReadonlyMap<string, ToolApprovalResolution>,\n toolCallId: string,\n): ToolApprovalResolution | undefined {\n return approvals.get(toolCallId) ?? approvals.get(`approval_${toolCallId}`)\n}\n\nfunction isApproved(resolution: ToolApprovalResolution): boolean {\n return typeof resolution === 'boolean' ? resolution : resolution.approved\n}\n\nfunction editedApprovalArgs(\n resolution: ToolApprovalResolution,\n): unknown | undefined {\n return typeof resolution === 'object' && resolution.approved\n ? resolution.editedArgs\n : undefined\n}\n\nfunction deniedApprovalResult(resolution: ToolApprovalResolution): unknown {\n return typeof resolution === 'object' && !resolution.approved\n ? (resolution.payload ?? { error: 'User declined tool execution' })\n : { error: 'User declined tool execution' }\n}\n\ninterface ExecuteToolCallsResult {\n /** Tool results ready to send to LLM */\n results: Array<ToolResult>\n /** Tools that need user approval before execution */\n needsApproval: Array<ApprovalRequest>\n /** Tools that need client-side execution */\n needsClientExecution: Array<ClientToolRequest>\n /** Interrupts raised by subagents that run as tools */\n subagentInterrupts: Array<Interrupt>\n}\n\n/**\n * Helper that runs a tool execution promise while polling for pending custom events.\n * Yields any custom events that are emitted during execution, then returns the\n * execution result.\n */\nasync function* executeWithEventPolling<T>(\n executionPromise: Promise<T>,\n pendingEvents: Array<CustomEvent | StreamChunk>,\n): AsyncGenerator<CustomEvent | StreamChunk, T, void> {\n // Use an object to track mutable state across the async boundary\n const state = { done: false, result: undefined as T }\n const executionWithFlag = executionPromise.then((r) => {\n state.done = true\n state.result = r\n return r\n })\n\n while (!state.done) {\n // Wait for either the execution to complete or a short timeout\n await Promise.race([\n executionWithFlag,\n new Promise((resolve) => setTimeout(resolve, 10)),\n ])\n\n // Flush any pending events\n let event: CustomEvent | StreamChunk | undefined\n while ((event = pendingEvents.shift()) !== undefined) {\n yield event\n }\n }\n\n // Final flush in case events were emitted right at completion\n let event: CustomEvent | StreamChunk | undefined\n while ((event = pendingEvents.shift()) !== undefined) {\n yield event\n }\n\n return state.result\n}\n\n/**\n * Apply a middleware onBeforeToolCall decision.\n * Returns the (possibly transformed) input if execution should proceed,\n * or undefined if the tool call was skipped (result already pushed).\n * Throws MiddlewareAbortError if the decision is 'abort'.\n */\nasync function applyBeforeToolCallDecision(\n toolCall: ToolCall,\n tool: Tool,\n input: unknown,\n toolName: string,\n middlewareHooks: ToolExecutionMiddlewareHooks,\n results: Array<ToolResult>,\n): Promise<{ proceed: true; input: unknown } | { proceed: false }> {\n if (!middlewareHooks.onBeforeToolCall) {\n return { proceed: true, input }\n }\n\n const decision = await middlewareHooks.onBeforeToolCall(toolCall, tool, input)\n if (!decision) {\n return { proceed: true, input }\n }\n\n if (decision.type === 'abort') {\n throw new MiddlewareAbortError(decision.reason || 'Aborted by middleware')\n }\n\n if (decision.type === 'skip') {\n const skipResult = decision.result\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n typeof skipResult === 'string'\n ? safeJsonParse(skipResult)\n : (skipResult ?? null),\n duration: 0,\n })\n if (middlewareHooks.onAfterToolCall) {\n await middlewareHooks.onAfterToolCall({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n ok: true,\n duration: 0,\n result: skipResult,\n })\n }\n return { proceed: false }\n }\n\n return { proceed: true, input: decision.args }\n}\n\n/**\n * Execute a server-side tool with event polling, output validation, and middleware hooks.\n * Yields CustomEvent chunks during execution and pushes the result to the results array.\n */\nexport async function* executeServerTool<TContext = unknown>(\n toolCall: ToolCall,\n tool: AnyTool,\n toolName: string,\n input: unknown,\n context: ToolExecutionContext<TContext>,\n pendingEvents: Array<CustomEvent | StreamChunk>,\n results: Array<ToolResult>,\n middlewareHooks?: ToolExecutionMiddlewareHooks,\n subagentInterrupts?: Array<Interrupt>,\n): AsyncGenerator<CustomEvent | StreamChunk, void, void> {\n const startTime = Date.now()\n try {\n if (!tool.execute) {\n throw new Error(`Tool ${toolName} has no execute() implementation`)\n }\n const subagent = isSubagentTool(tool)\n if (subagent) {\n Object.assign(context, {\n [EMIT_STREAM_CHUNK]: (chunk: StreamChunk) => pendingEvents.push(chunk),\n })\n }\n const executionPromise = Promise.resolve(tool.execute(input, context))\n let result = yield* executeWithEventPolling(executionPromise, pendingEvents)\n const duration = Date.now() - startTime\n\n if (subagent) {\n const outcome = result as SubagentToolOutcome\n if (outcome.interrupts?.length) {\n // The child waits for outside input. Leave the call open so the\n // resume run executes it again and continues the same child.\n subagentInterrupts?.push(...outcome.interrupts)\n return\n }\n const modelResult = outcome.error\n ? { subagentRunId: outcome.subagentRunId, error: outcome.error }\n : { subagentRunId: outcome.subagentRunId, result: outcome.text }\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: modelResult,\n input,\n output: modelResult,\n duration,\n ...(outcome.error ? { state: 'output-error' as const } : {}),\n })\n await middlewareHooks?.onAfterToolCall?.({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n duration,\n ...(outcome.error\n ? { ok: false as const, error: new Error(outcome.error) }\n : { ok: true as const, result: modelResult }),\n })\n return\n }\n\n // MCP Apps: if this tool links a ui:// resource, eagerly read it and queue\n // a `ui-resource` CUSTOM event. The MCP source stays live until the run\n // drains (MCPManager's `connection:'close'` policy disposes on completion),\n // so `readResource` is callable here. Fail-soft: a read error warns and\n // emits nothing — the text result still flows.\n await emitUiResourceIfLinked(tool, context)\n\n // Flush remaining events (including any queued ui-resource event)\n let pendingEvent: CustomEvent | StreamChunk | undefined\n while ((pendingEvent = pendingEvents.shift()) !== undefined) {\n yield pendingEvent\n }\n\n // Validate output against outputSchema if provided. Validates\n // `undefined`/`null` too — the schema decides whether they're valid.\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n const finalResult =\n typeof result === 'string' ? safeJsonParse(result) : (result ?? null)\n\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: finalResult,\n input,\n output: finalResult,\n duration,\n })\n\n if (middlewareHooks?.onAfterToolCall) {\n await middlewareHooks.onAfterToolCall({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n ok: true,\n duration,\n result: finalResult,\n })\n }\n } catch (error: unknown) {\n const duration = Date.now() - startTime\n\n // Flush remaining events\n let pendingEvent: CustomEvent | StreamChunk | undefined\n while ((pendingEvent = pendingEvents.shift()) !== undefined) {\n yield pendingEvent\n }\n\n if (error instanceof MiddlewareAbortError) {\n throw error\n }\n\n const message = error instanceof Error ? error.message : 'Unknown error'\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: message },\n input,\n state: 'output-error',\n duration,\n })\n\n if (middlewareHooks?.onAfterToolCall) {\n await middlewareHooks.onAfterToolCall({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n ok: false,\n duration,\n error,\n })\n }\n }\n}\n\nfunction buildClientToolResult(\n toolCallId: string,\n toolName: string,\n tool: AnyTool,\n rawResult: unknown,\n input?: unknown,\n): ToolResult {\n try {\n let result = rawResult\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n const parsed =\n typeof result === 'string' ? safeJsonParse(result) : (result ?? null)\n return {\n toolCallId,\n toolName,\n result: parsed,\n input,\n output: parsed,\n }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : 'Validation failed'\n return {\n toolCallId,\n toolName,\n result: { error: message },\n input,\n state: 'output-error',\n }\n }\n}\n\n/**\n * Execute tool calls based on their configuration.\n * Yields CustomEvent chunks during tool execution for real-time progress updates.\n *\n * Handles three cases:\n * 1. Client tools (no execute) - request client to execute\n * 2. Server tools with approval - check approval before executing\n * 3. Normal server tools - execute immediately\n *\n * @param toolCalls - Tool calls from the LLM\n * @param tools - Available tools with their configurations\n * @param approvals - Map keyed by toolCallId (or `approval_${toolCallId}`) → ToolApprovalResolution\n * @param clientResults - Map of client-side execution results (toolCallId -> result)\n * @param createCustomEventChunk - Factory to create CustomEvent chunks (optional)\n */\nexport async function* executeToolCalls<TContext = unknown>(\n toolCalls: Array<ToolCall>,\n tools: ReadonlyArray<AnyTool>,\n approvals: Map<string, ToolApprovalResolution> = new Map(),\n clientResults: Map<string, any> = new Map(),\n createCustomEventChunk?: (\n eventName: string,\n value: Record<string, any>,\n options?: EmitCustomEventOptions,\n ) => CustomEvent,\n middlewareHooks?: ToolExecutionMiddlewareHooks,\n userContext?: TContext,\n abortSignal?: AbortSignal,\n resumeState?: ToolResumeExecutionState,\n): AsyncGenerator<CustomEvent | StreamChunk, ExecuteToolCallsResult, void> {\n const results: Array<ToolResult> = []\n const needsApproval: Array<ApprovalRequest> = []\n const needsClientExecution: Array<ClientToolRequest> = []\n const subagentInterrupts: Array<Interrupt> = []\n\n // Create tool lookup map\n const toolMap = new Map<string, AnyTool>()\n for (const tool of tools) {\n toolMap.set(tool.name, tool)\n }\n\n // Batch gating: when any tool in the batch still needs an approval decision,\n // defer all execution so side effects don't happen before the user decides.\n const hasPendingApprovals = toolCalls.some((tc) => {\n const t = toolMap.get(tc.function.name)\n return (\n t?.needsApproval &&\n approvalResolution(approvals, tc.id) === undefined &&\n !resumeState?.cancelledToolCallIds?.has(tc.id)\n )\n })\n\n for (const toolCall of toolCalls) {\n const tool = toolMap.get(toolCall.function.name)\n const toolName = toolCall.function.name\n\n if (!tool) {\n // Unknown tool - return error\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: `Unknown tool: ${toolName}` },\n state: 'output-error',\n })\n continue\n }\n\n // Skip non-pending tools while approvals are outstanding\n if (hasPendingApprovals) {\n const isPendingApproval =\n tool.needsApproval &&\n approvalResolution(approvals, toolCall.id) === undefined\n const isPlainClientRequest = !tool.needsApproval && !tool.execute\n if (!isPendingApproval && !isPlainClientRequest) {\n continue\n }\n }\n\n if (resumeState?.cancelledToolCallIds?.has(toolCall.id)) {\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: 'Tool execution cancelled' },\n state: 'output-error',\n })\n continue\n }\n\n // Parse arguments\n let input: unknown = {}\n const argsStr = toolCall.function.arguments.trim() || '{}'\n if (argsStr) {\n try {\n const parsed = JSON.parse(argsStr)\n // Normalize null/non-object to {} (e.g. Anthropic empty tool_use blocks)\n input = parsed && typeof parsed === 'object' ? parsed : {}\n } catch {\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: {\n error: `Failed to parse tool arguments as JSON: ${argsStr}`,\n },\n input,\n state: 'output-error',\n })\n continue\n }\n }\n\n // Validate input against inputSchema (for Standard Schema compliant schemas)\n if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {\n try {\n input = parseWithStandardSchema(tool.inputSchema, input)\n } catch (validationError: unknown) {\n const message =\n validationError instanceof Error\n ? validationError.message\n : 'Validation failed'\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: {\n error: `Input validation failed for tool ${tool.name}: ${message}`,\n },\n // raw parse may have failed validation — still attach best-effort input\n input,\n state: 'output-error',\n })\n continue\n }\n }\n\n // Create a ToolExecutionContext for this tool call with event emission\n const pendingEvents: Array<CustomEvent | StreamChunk> = []\n const context = {\n toolCallId: toolCall.id,\n context: userContext,\n abortSignal,\n emitCustomEvent: (\n eventName: string,\n value: Record<string, any>,\n options?: EmitCustomEventOptions,\n ) => {\n if (createCustomEventChunk) {\n pendingEvents.push(\n createCustomEventChunk(\n eventName,\n {\n ...value,\n toolCallId: toolCall.id,\n },\n options,\n ),\n )\n }\n },\n } as ToolExecutionContext<TContext>\n\n // CASE 1: Client-side tool (no execute function)\n if (!tool.execute) {\n // Check if tool needs approval\n if (tool.needsApproval) {\n const approvalId = `approval_${toolCall.id}`\n const resolution = approvalResolution(approvals, toolCall.id)\n\n // Check if approval decision exists\n if (resolution !== undefined) {\n const approved = isApproved(resolution)\n\n if (approved) {\n input = editedApprovalArgs(resolution) ?? input\n // Approved - check if client has executed\n if (clientResults.has(toolCall.id)) {\n results.push(\n buildClientToolResult(\n toolCall.id,\n toolName,\n tool,\n clientResults.get(toolCall.id),\n input,\n ),\n )\n } else {\n // Approved but not executed yet - request client execution\n needsClientExecution.push({\n toolCallId: toolCall.id,\n toolName,\n input,\n })\n }\n } else {\n // User declined\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n resumeState?.deniedToolResults?.get(toolCall.id) ??\n deniedApprovalResult(resolution),\n input,\n state: 'output-error',\n })\n }\n } else {\n // Need approval first\n needsApproval.push({\n toolCallId: toolCall.id,\n toolName: toolCall.function.name,\n input,\n approvalId,\n })\n }\n } else {\n // No approval needed - check if client has executed\n if (clientResults.has(toolCall.id)) {\n results.push(\n buildClientToolResult(\n toolCall.id,\n toolName,\n tool,\n clientResults.get(toolCall.id),\n input,\n ),\n )\n } else {\n // Request client execution\n needsClientExecution.push({\n toolCallId: toolCall.id,\n toolName,\n input,\n })\n }\n }\n continue\n }\n\n // CASE 2: Server tool with approval required\n if (tool.needsApproval) {\n const approvalId = `approval_${toolCall.id}`\n const resolution = approvalResolution(approvals, toolCall.id)\n\n // Check if approval decision exists\n if (resolution !== undefined) {\n const approved = isApproved(resolution)\n\n if (approved) {\n input = editedApprovalArgs(resolution) ?? input\n // Apply middleware before-hook for approved tools\n if (middlewareHooks) {\n const decision = await applyBeforeToolCallDecision(\n toolCall,\n tool,\n input,\n toolName,\n middlewareHooks,\n results,\n )\n if (!decision.proceed) continue\n input = decision.input\n }\n\n yield* executeServerTool(\n toolCall,\n tool,\n toolName,\n input,\n context,\n pendingEvents,\n results,\n middlewareHooks,\n subagentInterrupts,\n )\n } else {\n // User declined\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n resumeState?.deniedToolResults?.get(toolCall.id) ??\n deniedApprovalResult(resolution),\n input,\n state: 'output-error',\n })\n }\n } else {\n // Need approval\n needsApproval.push({\n toolCallId: toolCall.id,\n toolName,\n input,\n approvalId,\n })\n }\n continue\n }\n\n // CASE 3: Normal server tool - execute immediately\n if (middlewareHooks) {\n const decision = await applyBeforeToolCallDecision(\n toolCall,\n tool,\n input,\n toolName,\n middlewareHooks,\n results,\n )\n if (!decision.proceed) continue\n input = decision.input\n }\n\n yield* executeServerTool(\n toolCall,\n tool,\n toolName,\n input,\n context,\n pendingEvents,\n results,\n middlewareHooks,\n subagentInterrupts,\n )\n }\n\n return { results, needsApproval, needsClientExecution, subagentInterrupts }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tool-calls.js","names":[],"sources":["../../../../../src/activities/chat/tools/tool-calls.ts"],"sourcesContent":["import { normalizeToolResult } from '../../../utilities/tool-result'\nimport { tanstackMetadata } from '../../../utilities/merge-metadata'\nimport { isProviderExecutedToolCall } from '../../../utilities/provider-executed'\nimport type { AdapterYieldChunk } from '../../../utilities/adapter-yield-chunk'\nimport {\n StandardSchemaValidationError,\n isStandardSchema,\n parseWithStandardSchema,\n validateWithStandardSchema,\n} from './schema-converter'\nimport type { ToolApprovalResolution } from '../../../interrupts'\nimport type {\n AnyTool,\n ContentPart,\n CustomEvent,\n EmitCustomEventOptions,\n Interrupt,\n ModelMessage,\n RunFinishedEvent,\n StreamChunk,\n Tool,\n ToolCall,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolExecutionContext,\n ToolInputResponse,\n ToolResultOutcome,\n ToolOutputState,\n} from '../../../types'\nimport type {\n AfterToolCallInfo,\n BeforeToolCallDecision,\n} from '../middleware/types'\nimport type { McpResourceReadResult } from '../mcp/types'\nimport type {\n ContextFromTool,\n DefinedContext,\n MergeContext,\n UnionToIntersection,\n} from '../runtime-context-types'\n\nfunction safeJsonParse(value: string): unknown {\n try {\n return JSON.parse(value)\n } catch {\n return value\n }\n}\n\n/** Marks the synthetic tool that runs a subagent. */\nexport const SUBAGENT_TOOL = Symbol.for('tanstack.ai.subagentTool')\n\n/** Set on the tool context of a subagent tool. Streams a child chunk live. */\nexport const EMIT_STREAM_CHUNK = Symbol.for('tanstack.ai.emitStreamChunk')\n\n/** What a subagent tool's `execute` returns. */\nexport interface SubagentToolOutcome {\n subagentRunId: string\n text: string\n error?: string\n /** Set when the child stopped for outside input. The tool call stays open. */\n interrupts?: Array<Interrupt>\n}\n\nfunction isSubagentTool(tool: AnyTool): boolean {\n return (tool as { [SUBAGENT_TOOL]?: true })[SUBAGENT_TOOL] === true\n}\n\n/**\n * MCP Apps metadata attached to a server tool at discovery (see\n * `@tanstack/ai-mcp` discovery + `MCPManager.discover()`).\n *\n * - `uiResourceUri` / `serverId` are stamped by ai-mcp at tool discovery.\n * - `readResource` is bound by `MCPManager.discover()` (the one site that has\n * both the tool and its originating source) so the resource can be eagerly\n * read at the emit site. Under `chat()`-managed MCP lifecycle\n * (`connection:'close'`), the MCP source is not disposed until the run\n * drains, so `readResource` is still live at this emit point. Note: a caller\n * who closes the MCP source early (outside `chat()`'s managed lifecycle)\n * degrades fail-soft — `readResource` may reject, the widget is absent, but\n * the tool result still flows to the model.\n * `@tanstack/ai` never imports `@tanstack/ai-mcp`; this travels structurally\n * on the tool.\n */\ninterface McpToolAppMeta {\n uiResourceUri?: string\n serverId?: string\n /** Server-native (unprefixed) MCP tool name — used as the renderer's toolName. */\n serverToolName?: string\n readResource?: (uri: string) => Promise<McpResourceReadResult>\n}\n\nfunction readMcpAppMeta(tool: AnyTool): McpToolAppMeta | undefined {\n const meta = (tool.metadata as { mcp?: McpToolAppMeta } | undefined)?.mcp\n return meta\n}\n\n/**\n * Eagerly read a tool's linked `ui://` resource (MCP Apps) and emit a\n * `ui-resource` CUSTOM event so the client can render the widget. The model\n * still receives the normal text tool-result; the widget rides alongside and\n * never enters model input.\n *\n * Fail-soft: any read error logs a warning and emits nothing — it never throws,\n * so the normal tool-result still flows and a broken widget cannot break the run.\n */\nasync function emitUiResourceIfLinked<TContext>(\n tool: AnyTool,\n context: ToolExecutionContext<TContext>,\n): Promise<void> {\n const mcp = readMcpAppMeta(tool)\n const uiUri = mcp?.uiResourceUri\n if (!uiUri || !mcp.readResource) return\n\n // The try covers ONLY the fallible read — keep `emitCustomEvent` out of it so\n // an exception from the emit path can't be mislabeled as a read failure.\n let matched: McpResourceReadResult['contents'][number] | undefined\n try {\n const res = await mcp.readResource(uiUri)\n // Emit ONLY the content whose uri matches the requested `uiUri`. A source\n // can return unrelated contents; falling back to `contents[0]` would risk\n // rendering a widget that doesn't correspond to the linked resource. This\n // is a display widget — a mismatched resource is worse than none, so if no\n // content matches we fail-soft (warn + return) rather than emit.\n matched = res.contents.find((c) => c.uri === uiUri)\n } catch (err) {\n // fail-soft — the text tool-result already flows; a broken widget must\n // not break the run.\n console.warn(`[mcp-apps] failed to read ui resource ${uiUri}:`, err)\n return\n }\n if (!matched) {\n console.warn(\n `[mcp-apps] ui resource ${uiUri} returned no content matching that uri; not emitting`,\n )\n return\n }\n // NOTE: `toolCallId` is intentionally NOT set here — it is stamped onto\n // every emitted event by the `executeToolCalls` context wrapper, so the\n // UIResourceEvent.value.toolCallId / UIResourcePart.toolCallId contract is\n // still satisfied downstream.\n context.emitCustomEvent('ui-resource', {\n resource: {\n uri: matched.uri,\n mimeType: matched.mimeType ?? 'text/html',\n text: matched.text,\n blob: matched.blob,\n },\n serverId: mcp.serverId,\n toolName: mcp.serverToolName ?? tool.name,\n meta: undefined,\n })\n}\n\n/**\n * Optional middleware hooks for tool execution.\n * When provided, these callbacks are invoked before/after each tool execution.\n */\nexport interface ToolExecutionMiddlewareHooks {\n onBeforeToolCall?: (\n toolCall: ToolCall,\n tool: Tool | undefined,\n args: unknown,\n ) => Promise<BeforeToolCallDecision>\n onAfterToolCall?: (info: AfterToolCallInfo) => Promise<void>\n}\n\n/**\n * Error thrown when middleware decides to abort the chat run during tool execution.\n */\nexport class MiddlewareAbortError extends Error {\n constructor(reason: string) {\n super(reason)\n this.name = 'MiddlewareAbortError'\n }\n}\n\n// The leaf context-inference primitives (ContextFromTool, MergeContext,\n// UnionToIntersection, DefinedContext) are shared with the chat activity\n// options layer — see ../runtime-context-types.\ntype RequiredContextFromToolUnion<T> = T extends unknown\n ? undefined extends ContextFromTool<T>\n ? never\n : ContextFromTool<T>\n : never\n\ntype ContextFromToolUnion<T> = [\n UnionToIntersection<DefinedContext<ContextFromTool<T>>>,\n] extends [never]\n ? unknown\n : [RequiredContextFromToolUnion<T>] extends [never]\n ? UnionToIntersection<DefinedContext<ContextFromTool<T>>> | undefined\n : UnionToIntersection<DefinedContext<ContextFromTool<T>>>\n\ntype ContextFromTools<TTools> = TTools extends readonly [\n infer THead,\n ...infer TTail,\n]\n ? MergeContext<ContextFromTool<THead>, ContextFromTools<TTail>>\n : TTools extends ReadonlyArray<infer TTool>\n ? ContextFromToolUnion<TTool>\n : unknown\n\ntype ExecuteToolsContextArgs<TContext> = undefined extends TContext\n ? [userContext?: TContext]\n : [userContext: TContext]\n\n/**\n * Manages tool call accumulation and execution for the chat() method's automatic tool execution loop.\n *\n * Responsibilities:\n * - Accumulates streaming tool call events (ID, name, arguments)\n * - Validates tool calls (filters out incomplete ones)\n * - Executes tool `execute` functions with parsed arguments\n * - Emits `TOOL_CALL_END` events for client visibility\n * - Returns tool result messages for conversation history\n *\n * This class is used internally by the AI.chat() method to handle the automatic\n * tool execution loop. It can also be used independently for custom tool execution logic.\n *\n * @example\n * ```typescript\n * const manager = new ToolCallManager(tools);\n *\n * // During streaming, accumulate tool calls\n * for await (const chunk of stream) {\n * if (chunk.type === 'TOOL_CALL_START') {\n * manager.addToolCallStartEvent(chunk);\n * } else if (chunk.type === 'TOOL_CALL_ARGS') {\n * manager.addToolCallArgsEvent(chunk);\n * }\n * }\n *\n * // After stream completes, execute tools\n * if (manager.hasToolCalls()) {\n * const toolResults = yield* manager.executeTools(finishEvent);\n * messages = [...messages, ...toolResults];\n * manager.clear();\n * }\n * ```\n */\nexport class ToolCallManager<\n TToolsOrContext = ReadonlyArray<AnyTool>,\n TContext = TToolsOrContext extends ReadonlyArray<AnyTool>\n ? ContextFromTools<TToolsOrContext>\n : TToolsOrContext,\n> {\n private readonly toolCallsMap = new Map<number, ToolCall>()\n private readonly tools: TToolsOrContext extends ReadonlyArray<AnyTool>\n ? TToolsOrContext\n : ReadonlyArray<AnyTool>\n\n constructor(\n tools: TToolsOrContext extends ReadonlyArray<AnyTool>\n ? TToolsOrContext\n : ReadonlyArray<AnyTool>,\n ) {\n this.tools = tools\n }\n\n /**\n * Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)\n */\n addToolCallStartEvent(event: ToolCallStartEvent): void {\n // AG-UI's TOOL_CALL_START carries no index, and a non-first-party or\n // malformed producer can send a second START for a toolCallId that is\n // already tracked. Without this guard, a repeat with the same index\n // overwrites the slot (wiping any TOOL_CALL_ARGS already accumulated),\n // and a repeat with a missing/different index inserts a duplicate row\n // that getToolCalls() returns twice, running the tool twice.\n for (const toolCall of this.toolCallsMap.values()) {\n if (toolCall.id === event.toolCallId) return\n }\n const index = (event as AdapterYieldChunk).index ?? this.toolCallsMap.size\n const name = event.toolCallName ?? event.toolName\n this.toolCallsMap.set(index, {\n id: event.toolCallId,\n type: 'function',\n function: {\n name,\n arguments: '',\n },\n ...(event.metadata !== undefined && { metadata: event.metadata }),\n })\n }\n\n /**\n * Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)\n */\n addToolCallArgsEvent(event: ToolCallArgsEvent): void {\n const extra = event as AdapterYieldChunk\n for (const [, toolCall] of this.toolCallsMap.entries()) {\n if (toolCall.id === event.toolCallId) {\n if (typeof extra.args === 'string' && extra.args !== '') {\n toolCall.function.arguments = extra.args\n } else {\n toolCall.function.arguments += event.delta\n }\n break\n }\n }\n }\n\n /**\n * Complete a tool call with its final input\n * Called when TOOL_CALL_END is received\n */\n completeToolCall(event: ToolCallEndEvent): void {\n for (const toolCall of this.toolCallsMap.values()) {\n if (toolCall.id !== event.toolCallId) continue\n if (event.input === undefined) return\n const normalized =\n event.input && typeof event.input === 'object' ? event.input : {}\n toolCall.function.arguments = JSON.stringify(normalized)\n return\n }\n }\n\n /**\n * Check if there are any complete tool calls to execute\n */\n hasToolCalls(): boolean {\n return this.getToolCalls().length > 0\n }\n\n /**\n * Get all complete tool calls (filtered for valid ID and name)\n */\n getToolCalls(): Array<ToolCall> {\n return Array.from(this.toolCallsMap.values()).filter(\n (tc) => tc.id && tc.function.name && tc.function.name.trim().length > 0,\n )\n }\n\n /**\n * Execute all tool calls and return tool result messages\n * Yields TOOL_CALL_END events for streaming\n * @param finishEvent - RUN_FINISHED event from the stream\n */\n async *executeTools(\n finishEvent: RunFinishedEvent,\n ...contextArgs: ExecuteToolsContextArgs<TContext>\n ): AsyncGenerator<AdapterYieldChunk, Array<ModelMessage>, void> {\n const toolCallsArray = this.getToolCalls()\n const toolResults: Array<ModelMessage> = []\n const hasRuntimeContext = contextArgs.length > 0\n const userContext = contextArgs[0]\n\n for (const toolCall of toolCallsArray) {\n const tool = this.tools.find((t) => t.name === toolCall.function.name)\n\n let toolResultContent: string | Array<ContentPart>\n let toolResultState: ToolOutputState | undefined\n // Holds the parsed/validated execution output before serialization.\n // Stays `undefined` when the tool has no `execute` (client-only\n // tools) or when execution throws.\n let toolOutput: unknown\n if (tool?.execute) {\n try {\n // Parse arguments (normalize null/non-object to {} for empty tool_use blocks)\n let args: unknown\n try {\n const argsString = toolCall.function.arguments.trim() || '{}'\n const parsed = JSON.parse(argsString)\n args = parsed && typeof parsed === 'object' ? parsed : {}\n } catch (parseError) {\n throw new Error(\n `Failed to parse tool arguments as JSON: ${toolCall.function.arguments}`,\n )\n }\n\n // Validate input against inputSchema (for Standard Schema compliant schemas)\n if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {\n try {\n args = parseWithStandardSchema(tool.inputSchema, args)\n } catch (validationError: unknown) {\n const message =\n validationError instanceof Error\n ? validationError.message\n : 'Validation failed'\n throw new Error(\n `Input validation failed for tool ${tool.name}: ${message}`,\n )\n }\n }\n\n // Execute the tool\n const executionContext = {\n toolCallId: toolCall.id,\n context: userContext,\n emitCustomEvent: () => {},\n } as ToolExecutionContext<TContext>\n let result = hasRuntimeContext\n ? await tool.execute(args, executionContext)\n : await tool.execute(args)\n\n // Validate output against outputSchema if provided (for Standard\n // Schema compliant schemas). Unlike the previous implementation we\n // intentionally validate `undefined`/`null` results too, so a tool\n // whose schema forbids them surfaces a validation error instead of\n // silently passing — the schema itself decides whether they're valid.\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n try {\n result = parseWithStandardSchema(tool.outputSchema, result)\n } catch (validationError: unknown) {\n const message =\n validationError instanceof Error\n ? validationError.message\n : 'Validation failed'\n throw new Error(\n `Output validation failed for tool ${tool.name}: ${message}`,\n )\n }\n }\n\n toolOutput = result\n toolResultContent = normalizeToolResult(result)\n } catch (error: unknown) {\n // If tool execution fails, add error message\n const message =\n error instanceof Error ? error.message : 'Unknown error'\n toolResultContent = `Error executing tool: ${message}`\n toolResultState = 'output-error'\n }\n } else {\n // Tool doesn't have execute function, add placeholder\n toolResultContent = `Tool ${toolCall.function.name} does not have an execute function`\n }\n\n // Emit TOOL_CALL_END event\n yield {\n type: 'TOOL_CALL_END',\n toolCallId: toolCall.id,\n toolCallName: toolCall.function.name,\n toolName: toolCall.function.name,\n model: (() => {\n const model = tanstackMetadata(finishEvent)?.model\n return typeof model === 'string' ? model : undefined\n })(),\n timestamp: Date.now(),\n // Typed parsed output (undefined for failed exec / client-only tools).\n ...(toolOutput !== undefined ? { output: toolOutput } : {}),\n result: toolResultContent,\n ...(toolResultState !== undefined && { state: toolResultState }),\n }\n\n // Add tool result message\n toolResults.push({\n role: 'tool',\n content: toolResultContent,\n toolCallId: toolCall.id,\n })\n }\n\n return toolResults\n }\n\n /**\n * Clear the tool calls map for the next iteration\n */\n clear(): void {\n this.toolCallsMap.clear()\n }\n}\n\nexport interface ToolResult {\n toolCallId: string\n toolName: string\n result: any\n state?: 'output-available' | 'output-error'\n /** Set when the user or middleware cancelled or denied the tool call; state is output-error. */\n outcome?: ToolResultOutcome\n /** Duration of tool execution in milliseconds (only for server-executed tools) */\n duration?: number\n /**\n * Parsed tool input (after JSON parse + optional Standard Schema validation).\n * Parsed tool input after JSON parse + optional Standard Schema validation.\n */\n input?: unknown\n /**\n * Parsed tool output before wire serialization. Surfaced on engine-emitted\n * `TOOL_CALL_END` events so consumers can read typed `output` without\n * re-parsing `result`. Undefined on error paths and when execution is skipped.\n */\n output?: unknown\n}\n\nexport interface ApprovalRequest {\n toolCallId: string\n toolName: string\n input: any\n approvalId: string\n}\n\nexport interface ClientToolRequest {\n toolCallId: string\n toolName: string\n input: any\n}\n\n/** Form or sampling input that paused a server tool. */\nexport interface McpInputRequest {\n toolCallId: string\n toolName: string\n kind: 'form' | 'sampling'\n request: unknown\n}\n\ninterface McpInputRequiredThrow {\n name: 'MCPInputRequiredError'\n kind: 'form' | 'sampling'\n request: unknown\n}\n\nfunction isMcpInputRequired(value: unknown): value is McpInputRequiredThrow {\n if (typeof value !== 'object' || value === null) return false\n if (!('name' in value) || value.name !== 'MCPInputRequiredError') {\n return false\n }\n if (!('kind' in value)) return false\n const kindIsFormOrSampling =\n value.kind === 'form' || value.kind === 'sampling'\n if (!kindIsFormOrSampling) return false\n return 'request' in value\n}\n\nexport interface ToolResumeExecutionState {\n clientToolErrors?: ReadonlyMap<string, string>\n deniedToolResults?: ReadonlyMap<string, unknown>\n cancelledToolCallIds?: ReadonlySet<string>\n /** Answers to `mcp_input` interrupts, by tool call id. */\n inputResponses?: ReadonlyMap<string, ToolInputResponse>\n}\n\nfunction approvalResolution(\n approvals: ReadonlyMap<string, ToolApprovalResolution>,\n toolCallId: string,\n): ToolApprovalResolution | undefined {\n return approvals.get(toolCallId) ?? approvals.get(`approval_${toolCallId}`)\n}\n\nfunction isApproved(resolution: ToolApprovalResolution): boolean {\n return typeof resolution === 'boolean' ? resolution : resolution.approved\n}\n\nfunction editedApprovalArgs(\n resolution: ToolApprovalResolution,\n): unknown | undefined {\n return typeof resolution === 'object' && resolution.approved\n ? resolution.editedArgs\n : undefined\n}\n\nfunction deniedApprovalResult(resolution: ToolApprovalResolution): unknown {\n return typeof resolution === 'object' && !resolution.approved\n ? (resolution.payload ?? { error: 'User declined tool execution' })\n : { error: 'User declined tool execution' }\n}\n\ninterface ExecuteToolCallsResult {\n /** Tool results ready to send to LLM */\n results: Array<ToolResult>\n /** Tools that need user approval before execution */\n needsApproval: Array<ApprovalRequest>\n /** Tools that need client-side execution */\n needsClientExecution: Array<ClientToolRequest>\n /** Server tools that paused for MCP form or sampling input */\n inputRequired: Array<McpInputRequest>\n /** Interrupts raised by subagents that run as tools */\n subagentInterrupts: Array<Interrupt>\n}\n\n/**\n * Helper that runs a tool execution promise while polling for pending custom events.\n * Yields any custom events that are emitted during execution, then returns the\n * execution result.\n */\nasync function* executeWithEventPolling<T>(\n executionPromise: Promise<T>,\n pendingEvents: Array<CustomEvent | StreamChunk>,\n): AsyncGenerator<CustomEvent | StreamChunk, T, void> {\n // Use an object to track mutable state across the async boundary\n const state = { done: false, result: undefined as T }\n const executionWithFlag = executionPromise.then((r) => {\n state.done = true\n state.result = r\n return r\n })\n\n while (!state.done) {\n // Wait for either the execution to complete or a short timeout\n await Promise.race([\n executionWithFlag,\n new Promise((resolve) => setTimeout(resolve, 10)),\n ])\n\n // Flush any pending events\n let event: CustomEvent | StreamChunk | undefined\n while ((event = pendingEvents.shift()) !== undefined) {\n yield event\n }\n }\n\n // Final flush in case events were emitted right at completion\n let event: CustomEvent | StreamChunk | undefined\n while ((event = pendingEvents.shift()) !== undefined) {\n yield event\n }\n\n return state.result\n}\n\n/**\n * Apply a middleware onBeforeToolCall decision.\n * Returns the (possibly transformed) input if execution should proceed,\n * or undefined if the tool call was skipped (result already pushed).\n * Throws MiddlewareAbortError if the decision is 'abort'.\n */\nasync function applyBeforeToolCallDecision(\n toolCall: ToolCall,\n tool: Tool,\n input: unknown,\n toolName: string,\n middlewareHooks: ToolExecutionMiddlewareHooks,\n results: Array<ToolResult>,\n): Promise<{ proceed: true; input: unknown } | { proceed: false }> {\n if (!middlewareHooks.onBeforeToolCall) {\n return { proceed: true, input }\n }\n\n const decision = await middlewareHooks.onBeforeToolCall(toolCall, tool, input)\n if (!decision) {\n return { proceed: true, input }\n }\n\n if (decision.type === 'abort') {\n throw new MiddlewareAbortError(decision.reason || 'Aborted by middleware')\n }\n\n if (decision.type === 'skip') {\n const skipResult = decision.result\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n typeof skipResult === 'string'\n ? safeJsonParse(skipResult)\n : (skipResult ?? null),\n duration: 0,\n })\n if (middlewareHooks.onAfterToolCall) {\n await middlewareHooks.onAfterToolCall({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n ok: true,\n duration: 0,\n result: skipResult,\n })\n }\n return { proceed: false }\n }\n\n return { proceed: true, input: decision.args }\n}\n\n/**\n * Execute a server-side tool with event polling, output validation, and middleware hooks.\n * Yields CustomEvent chunks during execution and pushes the result to the results array.\n */\nexport async function* executeServerTool<TContext = unknown>(\n toolCall: ToolCall,\n tool: AnyTool,\n toolName: string,\n input: unknown,\n context: ToolExecutionContext<TContext>,\n pendingEvents: Array<CustomEvent | StreamChunk>,\n results: Array<ToolResult>,\n middlewareHooks?: ToolExecutionMiddlewareHooks,\n inputRequired?: Array<McpInputRequest>,\n subagentInterrupts?: Array<Interrupt>,\n): AsyncGenerator<CustomEvent | StreamChunk, void, void> {\n const startTime = Date.now()\n try {\n if (!tool.execute) {\n throw new Error(`Tool ${toolName} has no execute() implementation`)\n }\n const subagent = isSubagentTool(tool)\n if (subagent) {\n Object.assign(context, {\n [EMIT_STREAM_CHUNK]: (chunk: StreamChunk) => pendingEvents.push(chunk),\n })\n }\n const executionPromise = Promise.resolve(tool.execute(input, context))\n let result = yield* executeWithEventPolling(executionPromise, pendingEvents)\n const duration = Date.now() - startTime\n\n if (subagent) {\n const outcome = result as SubagentToolOutcome\n if (outcome.interrupts?.length) {\n // The child waits for outside input. Leave the call open so the\n // resume run executes it again and continues the same child.\n subagentInterrupts?.push(...outcome.interrupts)\n return\n }\n const modelResult = outcome.error\n ? { subagentRunId: outcome.subagentRunId, error: outcome.error }\n : { subagentRunId: outcome.subagentRunId, result: outcome.text }\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: modelResult,\n input,\n output: modelResult,\n duration,\n ...(outcome.error ? { state: 'output-error' as const } : {}),\n })\n await middlewareHooks?.onAfterToolCall?.({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n duration,\n ...(outcome.error\n ? { ok: false as const, error: new Error(outcome.error) }\n : { ok: true as const, result: modelResult }),\n })\n return\n }\n\n // MCP Apps: if this tool links a ui:// resource, eagerly read it and queue\n // a `ui-resource` CUSTOM event. The MCP source stays live until the run\n // drains (MCPManager's `connection:'close'` policy disposes on completion),\n // so `readResource` is callable here. Fail-soft: a read error warns and\n // emits nothing — the text result still flows.\n await emitUiResourceIfLinked(tool, context)\n\n // Flush remaining events (including any queued ui-resource event)\n let pendingEvent: CustomEvent | StreamChunk | undefined\n while ((pendingEvent = pendingEvents.shift()) !== undefined) {\n yield pendingEvent\n }\n\n // Validate output against outputSchema if provided. Validates\n // `undefined`/`null` too — the schema decides whether they're valid.\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n const finalResult =\n typeof result === 'string' ? safeJsonParse(result) : (result ?? null)\n\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: finalResult,\n input,\n output: finalResult,\n duration,\n })\n\n if (middlewareHooks?.onAfterToolCall) {\n await middlewareHooks.onAfterToolCall({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n ok: true,\n duration,\n result: finalResult,\n })\n }\n } catch (error: unknown) {\n const duration = Date.now() - startTime\n\n // Flush remaining events\n let pendingEvent: CustomEvent | StreamChunk | undefined\n while ((pendingEvent = pendingEvents.shift()) !== undefined) {\n yield pendingEvent\n }\n\n if (error instanceof MiddlewareAbortError) {\n throw error\n }\n\n // Same shape as MCPInputRequiredError. Pause instead of a tool error.\n if (isMcpInputRequired(error)) {\n if (!inputRequired) throw error\n inputRequired.push({\n toolCallId: toolCall.id,\n toolName,\n kind: error.kind,\n request: error.request,\n })\n return\n }\n\n const message = error instanceof Error ? error.message : 'Unknown error'\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: message },\n input,\n state: 'output-error',\n duration,\n })\n\n if (middlewareHooks?.onAfterToolCall) {\n await middlewareHooks.onAfterToolCall({\n toolCall,\n tool,\n toolName,\n toolCallId: toolCall.id,\n ok: false,\n duration,\n error,\n })\n }\n }\n}\n\nasync function buildClientToolResult(\n toolCallId: string,\n toolName: string,\n tool: AnyTool,\n rawResult: unknown,\n input?: unknown,\n errorText?: string,\n): Promise<ToolResult> {\n if (errorText !== undefined) {\n return {\n toolCallId,\n toolName,\n result: { error: errorText },\n input,\n state: 'output-error',\n }\n }\n\n try {\n let result = rawResult\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n const validation = await validateWithStandardSchema<unknown>(\n tool.outputSchema,\n result,\n )\n if (!validation.success) {\n throw new StandardSchemaValidationError(validation.issues)\n }\n result = validation.data\n }\n\n const parsed =\n typeof result === 'string' ? safeJsonParse(result) : (result ?? null)\n return {\n toolCallId,\n toolName,\n result: parsed,\n input,\n output: parsed,\n }\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : 'Validation failed'\n return {\n toolCallId,\n toolName,\n result: { error: message },\n input,\n state: 'output-error',\n }\n }\n}\n\n/**\n * Execute tool calls based on their configuration.\n * Yields CustomEvent chunks during tool execution for real-time progress updates.\n *\n * Handles three cases:\n * 1. Client tools (no execute) - request client to execute\n * 2. Server tools with approval - check approval before executing\n * 3. Normal server tools - execute immediately\n *\n * @param toolCalls - Tool calls from the LLM\n * @param tools - Available tools with their configurations\n * @param approvals - Map keyed by toolCallId (or `approval_${toolCallId}`) → ToolApprovalResolution\n * @param clientResults - Map of client-side execution results (toolCallId -> result)\n * @param createCustomEventChunk - Factory to create CustomEvent chunks (optional)\n */\nexport async function* executeToolCalls<TContext = unknown>(\n toolCalls: Array<ToolCall>,\n tools: ReadonlyArray<AnyTool>,\n approvals: Map<string, ToolApprovalResolution> = new Map(),\n clientResults: Map<string, any> = new Map(),\n createCustomEventChunk?: (\n eventName: string,\n value: Record<string, any>,\n options?: EmitCustomEventOptions,\n ) => CustomEvent,\n middlewareHooks?: ToolExecutionMiddlewareHooks,\n userContext?: TContext,\n abortSignal?: AbortSignal,\n resumeState?: ToolResumeExecutionState,\n): AsyncGenerator<CustomEvent | StreamChunk, ExecuteToolCallsResult, void> {\n const results: Array<ToolResult> = []\n const needsApproval: Array<ApprovalRequest> = []\n const needsClientExecution: Array<ClientToolRequest> = []\n const inputRequired: Array<McpInputRequest> = []\n const subagentInterrupts: Array<Interrupt> = []\n\n // Create tool lookup map\n const toolMap = new Map<string, AnyTool>()\n for (const tool of tools) {\n toolMap.set(tool.name, tool)\n }\n\n // Batch gating: when any tool in the batch still needs an approval decision,\n // defer all execution so side effects don't happen before the user decides.\n const hasPendingApprovals = toolCalls.some((tc) => {\n const t = toolMap.get(tc.function.name)\n return (\n t?.needsApproval &&\n approvalResolution(approvals, tc.id) === undefined &&\n !resumeState?.cancelledToolCallIds?.has(tc.id)\n )\n })\n\n for (const toolCall of toolCalls) {\n // Provider-executed tools (Anthropic web_search / web_fetch) already ran\n // inside the provider response and carry their result on the call's\n // metadata. They have no execute() and must not become client requests.\n if (isProviderExecutedToolCall(toolCall)) continue\n\n const tool = toolMap.get(toolCall.function.name)\n const toolName = toolCall.function.name\n\n if (!tool) {\n // Unknown tool - return error\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: `Unknown tool: ${toolName}` },\n state: 'output-error',\n })\n continue\n }\n\n // Skip non-pending tools while approvals are outstanding\n if (hasPendingApprovals) {\n const isPendingApproval =\n tool.needsApproval &&\n approvalResolution(approvals, toolCall.id) === undefined\n const isPlainClientRequest = !tool.needsApproval && !tool.execute\n if (!isPendingApproval && !isPlainClientRequest) {\n continue\n }\n }\n\n if (resumeState?.cancelledToolCallIds?.has(toolCall.id)) {\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: 'Tool execution cancelled' },\n state: 'output-error',\n outcome: 'cancelled',\n })\n continue\n }\n\n // Parse arguments\n let input: unknown = {}\n const argsStr = toolCall.function.arguments.trim() || '{}'\n if (argsStr) {\n try {\n const parsed = JSON.parse(argsStr)\n // Normalize null/non-object to {} (e.g. Anthropic empty tool_use blocks)\n input = parsed && typeof parsed === 'object' ? parsed : {}\n } catch {\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: {\n error: `Failed to parse tool arguments as JSON: ${argsStr}`,\n },\n input,\n state: 'output-error',\n })\n continue\n }\n }\n\n // Validate input against inputSchema (for Standard Schema compliant schemas)\n if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {\n try {\n input = parseWithStandardSchema(tool.inputSchema, input)\n } catch (validationError: unknown) {\n const message =\n validationError instanceof Error\n ? validationError.message\n : 'Validation failed'\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: {\n error: `Input validation failed for tool ${tool.name}: ${message}`,\n },\n // raw parse may have failed validation — still attach best-effort input\n input,\n state: 'output-error',\n })\n continue\n }\n }\n\n // Create a ToolExecutionContext for this tool call with event emission\n const pendingEvents: Array<CustomEvent | StreamChunk> = []\n const inputResponse = resumeState?.inputResponses?.get(toolCall.id)\n const context = {\n toolCallId: toolCall.id,\n context: userContext,\n abortSignal,\n ...(inputResponse !== undefined ? { inputResponse } : {}),\n emitCustomEvent: (\n eventName: string,\n value: Record<string, any>,\n options?: EmitCustomEventOptions,\n ) => {\n if (createCustomEventChunk) {\n pendingEvents.push(\n createCustomEventChunk(\n eventName,\n {\n ...value,\n toolCallId: toolCall.id,\n },\n options,\n ),\n )\n }\n },\n } as ToolExecutionContext<TContext>\n\n // CASE 1: Client-side tool (no execute function)\n if (!tool.execute) {\n // Check if tool needs approval\n if (tool.needsApproval) {\n const approvalId = `approval_${toolCall.id}`\n const resolution = approvalResolution(approvals, toolCall.id)\n\n // Check if approval decision exists\n if (resolution !== undefined) {\n const approved = isApproved(resolution)\n\n if (approved) {\n input = editedApprovalArgs(resolution) ?? input\n // Approved - check if client has executed\n const clientError = resumeState?.clientToolErrors?.get(toolCall.id)\n if (clientResults.has(toolCall.id) || clientError !== undefined) {\n results.push(\n await buildClientToolResult(\n toolCall.id,\n toolName,\n tool,\n clientResults.get(toolCall.id),\n input,\n clientError,\n ),\n )\n } else {\n // Approved but not executed yet - request client execution\n needsClientExecution.push({\n toolCallId: toolCall.id,\n toolName,\n input,\n })\n }\n } else {\n // User declined\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n resumeState?.deniedToolResults?.get(toolCall.id) ??\n deniedApprovalResult(resolution),\n input,\n state: 'output-error',\n outcome: 'denied',\n })\n }\n } else {\n // Need approval first\n needsApproval.push({\n toolCallId: toolCall.id,\n toolName: toolCall.function.name,\n input,\n approvalId,\n })\n }\n } else {\n // No approval needed - check if client has executed\n const clientError = resumeState?.clientToolErrors?.get(toolCall.id)\n if (clientResults.has(toolCall.id) || clientError !== undefined) {\n results.push(\n await buildClientToolResult(\n toolCall.id,\n toolName,\n tool,\n clientResults.get(toolCall.id),\n input,\n clientError,\n ),\n )\n } else {\n // Request client execution\n needsClientExecution.push({\n toolCallId: toolCall.id,\n toolName,\n input,\n })\n }\n }\n continue\n }\n\n // CASE 2: Server tool with approval required\n if (tool.needsApproval) {\n const approvalId = `approval_${toolCall.id}`\n const resolution = approvalResolution(approvals, toolCall.id)\n\n // Check if approval decision exists\n if (resolution !== undefined) {\n const approved = isApproved(resolution)\n\n if (approved) {\n input = editedApprovalArgs(resolution) ?? input\n // Apply middleware before-hook for approved tools\n if (middlewareHooks) {\n const decision = await applyBeforeToolCallDecision(\n toolCall,\n tool,\n input,\n toolName,\n middlewareHooks,\n results,\n )\n if (!decision.proceed) continue\n input = decision.input\n }\n\n yield* executeServerTool(\n toolCall,\n tool,\n toolName,\n input,\n context,\n pendingEvents,\n results,\n middlewareHooks,\n inputRequired,\n subagentInterrupts,\n )\n } else {\n // User declined\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n resumeState?.deniedToolResults?.get(toolCall.id) ??\n deniedApprovalResult(resolution),\n input,\n state: 'output-error',\n outcome: 'denied',\n })\n }\n } else {\n // Need approval\n needsApproval.push({\n toolCallId: toolCall.id,\n toolName,\n input,\n approvalId,\n })\n }\n continue\n }\n\n // CASE 3: Normal server tool - execute immediately\n if (middlewareHooks) {\n const decision = await applyBeforeToolCallDecision(\n toolCall,\n tool,\n input,\n toolName,\n middlewareHooks,\n results,\n )\n if (!decision.proceed) continue\n input = decision.input\n }\n\n yield* executeServerTool(\n toolCall,\n tool,\n toolName,\n input,\n context,\n pendingEvents,\n results,\n middlewareHooks,\n inputRequired,\n subagentInterrupts,\n )\n }\n\n return {\n results,\n needsApproval,\n needsClientExecution,\n inputRequired,\n subagentInterrupts,\n }\n}\n"],"mappings":"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"}
@@ -52,6 +52,7 @@ export interface ServerTool<TInput extends SchemaInput | undefined = undefined,
52
52
  outputSchema?: TOutput;
53
53
  needsApproval?: TNeedsApproval;
54
54
  approvalSchema?: TApprovalSchema;
55
+ execution?: 'task';
55
56
  }
56
57
  /**
57
58
  * Marker type for client-side tools
@@ -64,6 +65,7 @@ export interface ClientTool<TInput extends SchemaInput | undefined = undefined,
64
65
  outputSchema?: TOutput;
65
66
  needsApproval?: TNeedsApproval;
66
67
  approvalSchema?: TApprovalSchema;
68
+ execution?: 'task';
67
69
  lazy?: boolean;
68
70
  metadata?: Record<string, unknown>;
69
71
  execute?: ToolExecuteFunction<TInput, TOutput, TContext>;
@@ -81,6 +83,7 @@ export interface ToolDefinitionInstance<TInput extends SchemaInput | undefined =
81
83
  outputSchema: TOutput;
82
84
  needsApproval?: TNeedsApproval;
83
85
  approvalSchema: TApprovalSchema;
86
+ execution?: 'task';
84
87
  readonly [toolApprovalCapability]?: {
85
88
  needsApproval: TNeedsApproval;
86
89
  approvalSchema: TApprovalSchema;
@@ -122,6 +125,7 @@ export type ToolDefinitionConfig<TInput extends SchemaInput | undefined = undefi
122
125
  outputSchema?: TOutput;
123
126
  lazy?: boolean;
124
127
  metadata?: Record<string, unknown>;
128
+ execution?: 'task';
125
129
  } & ApprovalConfig<TNeedsApproval, TApprovalSchema>;
126
130
  /**
127
131
  * Tool definition builder that allows creating server or client tools from a shared definition
@@ -60,6 +60,7 @@ function toolDefinition(config) {
60
60
  const outputSchema = config.outputSchema;
61
61
  const approvalSchema = config.approvalSchema;
62
62
  const needsApproval = config.needsApproval;
63
+ const execution = config.execution;
63
64
  return {
64
65
  __toolSide: "definition",
65
66
  ...config,
@@ -67,6 +68,7 @@ function toolDefinition(config) {
67
68
  outputSchema,
68
69
  approvalSchema,
69
70
  needsApproval,
71
+ execution,
70
72
  server(execute) {
71
73
  return {
72
74
  __toolSide: "server",
@@ -75,6 +77,7 @@ function toolDefinition(config) {
75
77
  outputSchema,
76
78
  approvalSchema,
77
79
  needsApproval,
80
+ execution,
78
81
  execute
79
82
  };
80
83
  },
@@ -86,6 +89,7 @@ function toolDefinition(config) {
86
89
  outputSchema,
87
90
  approvalSchema,
88
91
  needsApproval,
92
+ execution,
89
93
  ...execute !== void 0 && { execute }
90
94
  };
91
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-definition.js","names":[],"sources":["../../../../../src/activities/chat/tools/tool-definition.ts"],"sourcesContent":["import type {\n InferSchemaType,\n JSONSchema,\n SchemaInput,\n Tool,\n ToolExecuteFunction,\n} from '../../../types'\nimport type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\n\n/**\n * Type-level brand key for {@link ToolApprovalCapabilityMarker}. Only ever used\n * in type positions, but it must stay exported: a `unique symbol` referenced by\n * an exported interface has to be nameable in the emitted declarations.\n *\n * @public\n */\nexport declare const toolApprovalCapability: unique symbol\n\nexport interface ToolApprovalCapabilityMarker<\n TNeedsApproval extends boolean,\n TApprovalSchema,\n> {\n readonly [toolApprovalCapability]?: {\n needsApproval: TNeedsApproval\n approvalSchema: TApprovalSchema\n }\n}\n\nexport type ApprovalSchemaConfig =\n | SchemaInput\n | { approve: SchemaInput; reject?: SchemaInput }\n | { approve?: SchemaInput; reject: SchemaInput }\n\ntype ApprovalConfig<\n TNeedsApproval extends boolean,\n TApprovalSchema extends ApprovalSchemaConfig | undefined,\n> = TNeedsApproval extends true\n ? { needsApproval: TNeedsApproval; approvalSchema?: TApprovalSchema }\n : { needsApproval?: TNeedsApproval; approvalSchema?: never }\n\nexport type ApprovalCapabilityOf<TTool> =\n TTool extends ToolApprovalCapabilityMarker<infer TNeeds, unknown>\n ? TNeeds\n : false\n\nexport type ApprovalSchemaOf<TTool> =\n TTool extends ToolApprovalCapabilityMarker<boolean, infer TSchema>\n ? TSchema\n : undefined\n\nexport declare const noSchema: unique symbol\nexport type NoSchema = typeof noSchema\n\nexport type InputSchemaOf<TTool> = TTool extends {\n inputSchema: infer TInput\n}\n ? TInput extends undefined\n ? NoSchema\n : TInput\n : NoSchema\n\nexport type OutputSchemaOf<TTool> = TTool extends {\n outputSchema: infer TOutput\n}\n ? TOutput extends undefined\n ? NoSchema\n : TOutput\n : NoSchema\n\ntype BuiltToolSchemaFields<\n TInput extends SchemaInput | undefined,\n TOutput extends SchemaInput | undefined,\n TApprovalSchema extends ApprovalSchemaConfig | undefined,\n> = {\n inputSchema: TInput\n outputSchema: TOutput\n approvalSchema: TApprovalSchema\n}\n\n/**\n * Marker type for server-side tools\n */\nexport interface ServerTool<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TContext = unknown,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n>\n extends\n Tool<TInput, TOutput, TName, TContext>,\n ToolApprovalCapabilityMarker<TNeedsApproval, TApprovalSchema> {\n __toolSide: 'server'\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: TNeedsApproval\n approvalSchema?: TApprovalSchema\n}\n\n/**\n * Marker type for client-side tools\n */\nexport interface ClientTool<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TContext = unknown,\n // Captured as a literal (`true` / `false`) so downstream types — notably\n // the tool-call part's `approval` field — can be gated on it. Defaults to\n // `false` when the tool config omits `needsApproval`.\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> extends ToolApprovalCapabilityMarker<TNeedsApproval, TApprovalSchema> {\n __toolSide: 'client'\n name: TName\n description: string\n // Note: `inputSchema` / `outputSchema` stay as bare optionals (not\n // widened to `| undefined`). They participate in inference via\n // `InferToolInput` / `InferToolOutput` — widening with `| undefined`\n // breaks the `infer TInput extends StandardJSONSchemaV1<...>` chain\n // because `undefined` doesn't extend the schema constraint.\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: TNeedsApproval\n approvalSchema?: TApprovalSchema\n lazy?: boolean\n metadata?: Record<string, unknown>\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>\n}\n\n/** Broad server-tool shape for heterogeneous internal collections. */\nexport type AnyServerTool = Omit<\n ServerTool<any, any, string, any, boolean, any>,\n 'execute'\n> & {\n execute?: ((args: any, context?: any) => any) | undefined\n}\n\n/**\n * Tool definition that can be used directly or instantiated for server/client\n */\nexport interface ToolDefinitionInstance<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TContext = unknown,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'definition'\n // Narrow the base `needsApproval?: boolean` to the captured literal so it\n // survives into `ToolCallPartForTool`'s approval gate.\n inputSchema: TInput\n outputSchema: TOutput\n needsApproval?: TNeedsApproval\n approvalSchema: TApprovalSchema\n readonly [toolApprovalCapability]?: {\n needsApproval: TNeedsApproval\n approvalSchema: TApprovalSchema\n }\n}\n\n/**\n * Union type for any kind of client-side tool (client tool or definition)\n */\nexport type AnyClientTool =\n | (Omit<ClientTool<any, any, string, any, boolean, any>, 'execute'> & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n | (Omit<\n ToolDefinitionInstance<any, any, string, any, boolean, any>,\n 'execute'\n > & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n\n/**\n * Extract the tool name as a literal type\n */\nexport type InferToolName<T> = T extends { name: infer N } ? N : never\n\n/**\n * Extract the input type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)\n */\nexport type InferToolInput<T> = T extends { inputSchema?: infer TInput }\n ? TInput extends JSONSchema\n ? unknown\n : InferSchemaType<TInput>\n : unknown\n\n/**\n * Extract the output type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)\n */\nexport type InferToolOutput<T> = T extends { outputSchema?: infer TOutput }\n ? TOutput extends StandardJSONSchemaV1<any, any>\n ? InferSchemaType<TOutput>\n : TOutput extends StandardSchemaV1<any, any>\n ? InferSchemaType<TOutput>\n : TOutput extends JSONSchema\n ? unknown\n : InferSchemaType<TOutput>\n : unknown\n\n/**\n * Tool definition configuration\n */\nexport type ToolDefinitionConfig<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> = {\n name: TName\n description: string\n inputSchema?: TInput\n outputSchema?: TOutput\n lazy?: boolean\n metadata?: Record<string, unknown>\n} & ApprovalConfig<TNeedsApproval, TApprovalSchema>\n\n/**\n * Tool definition builder that allows creating server or client tools from a shared definition\n */\nexport interface ToolDefinition<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> extends ToolDefinitionInstance<\n TInput,\n TOutput,\n TName,\n unknown,\n TNeedsApproval,\n TApprovalSchema\n> {\n /**\n * Create a server-side tool with execute function\n */\n server: <TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ServerTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema>\n\n /**\n * Create a client-side tool with optional execute function.\n * Carries the definition's `needsApproval` literal through to the client\n * tool so the tool-call part's `approval` field stays gated on it.\n */\n client: <TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ClientTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema>\n}\n\n/**\n * Create an isomorphic tool definition that can be used directly or instantiated for server/client\n *\n * The definition contains all tool metadata (name, description, schemas) and can be:\n * 1. Used directly in chat() on the server (as a tool definition without execute)\n * 2. Instantiated as a server tool with .server()\n * 3. Instantiated as a client tool with .client()\n *\n * Supports any Standard JSON Schema compliant library (Zod v4+, ArkType, Valibot, etc.)\n * or plain JSON Schema objects.\n *\n * @example\n * ```typescript\n * import { toolDefinition } from '@tanstack/ai';\n * import { z } from 'zod';\n *\n * // Using Zod (natively supports Standard JSON Schema)\n * const addToCartTool = toolDefinition({\n * name: 'addToCart',\n * description: 'Add a guitar to the shopping cart (requires approval)',\n * needsApproval: true,\n * inputSchema: z.object({\n * guitarId: z.string(),\n * quantity: z.number(),\n * }),\n * outputSchema: z.object({\n * success: z.boolean(),\n * cartId: z.string(),\n * totalItems: z.number(),\n * }),\n * });\n *\n * // Use directly in chat (server-side, no execute function)\n * chat({\n * tools: [addToCartTool],\n * // ...\n * });\n *\n * // Or create server-side implementation\n * const addToCartServer = addToCartTool.server(async (args) => {\n * // args is typed as { guitarId: string; quantity: number }\n * return {\n * success: true,\n * cartId: 'CART_' + Date.now(),\n * totalItems: args.quantity,\n * };\n * });\n *\n * // Or create client-side implementation\n * const addToCartClient = addToCartTool.client(async (args) => {\n * // Client-specific logic (e.g., localStorage)\n * return { success: true, cartId: 'local', totalItems: 1 };\n * });\n * ```\n */\nexport function toolDefinition<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n // `const` forces the literal (`true` / `false`) to be captured from the\n // config's optional `needsApproval` — without it TS widens to `boolean`,\n // which collapses the approval gate in `ToolCallPartForTool`.\n const TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n>(\n config: ToolDefinitionConfig<\n TInput,\n TOutput,\n TName,\n TNeedsApproval,\n TApprovalSchema\n >,\n): ToolDefinition<TInput, TOutput, TName, TNeedsApproval, TApprovalSchema> {\n if (config.approvalSchema !== undefined && config.needsApproval !== true) {\n throw new TypeError('approvalSchema requires needsApproval: true.')\n }\n const inputSchema = config.inputSchema as TInput\n const outputSchema = config.outputSchema as TOutput\n const approvalSchema = config.approvalSchema as TApprovalSchema\n const needsApproval = config.needsApproval as TNeedsApproval | undefined\n\n const definition: ToolDefinition<\n TInput,\n TOutput,\n TName,\n TNeedsApproval,\n TApprovalSchema\n > = {\n __toolSide: 'definition',\n ...config,\n inputSchema,\n outputSchema,\n approvalSchema,\n needsApproval,\n server<TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ServerTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema> {\n return {\n __toolSide: 'server',\n ...config,\n inputSchema,\n outputSchema,\n approvalSchema,\n needsApproval,\n execute,\n }\n },\n\n client<TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ClientTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema> {\n return {\n __toolSide: 'client',\n ...config,\n inputSchema,\n outputSchema,\n approvalSchema,\n needsApproval,\n ...(execute !== undefined && { execute }),\n }\n },\n }\n\n return definition\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0UA,SAAgB,eAUd,QAOyE;CACzE,IAAI,OAAO,mBAAmB,KAAA,KAAa,OAAO,kBAAkB,MAClE,MAAM,IAAI,UAAU,8CAA8C;CAEpE,MAAM,cAAc,OAAO;CAC3B,MAAM,eAAe,OAAO;CAC5B,MAAM,iBAAiB,OAAO;CAC9B,MAAM,gBAAgB,OAAO;CA4D7B,OAAO;EAnDL,YAAY;EACZ,GAAG;EACH;EACA;EACA;EACA;EACA,OACE,SASwD;GACxD,OAAO;IACL,YAAY;IACZ,GAAG;IACH;IACA;IACA;IACA;IACA;GACF;EACF;EAEA,OACE,SASwD;GACxD,OAAO;IACL,YAAY;IACZ,GAAG;IACH;IACA;IACA;IACA;IACA,GAAI,YAAY,KAAA,KAAa,EAAE,QAAQ;GACzC;EACF;CAGK;AACT"}
1
+ {"version":3,"file":"tool-definition.js","names":[],"sources":["../../../../../src/activities/chat/tools/tool-definition.ts"],"sourcesContent":["import type {\n InferSchemaType,\n JSONSchema,\n SchemaInput,\n Tool,\n ToolExecuteFunction,\n} from '../../../types'\nimport type {\n StandardJSONSchemaV1,\n StandardSchemaV1,\n} from '@standard-schema/spec'\n\n/**\n * Type-level brand key for {@link ToolApprovalCapabilityMarker}. Only ever used\n * in type positions, but it must stay exported: a `unique symbol` referenced by\n * an exported interface has to be nameable in the emitted declarations.\n *\n * @public\n */\nexport declare const toolApprovalCapability: unique symbol\n\nexport interface ToolApprovalCapabilityMarker<\n TNeedsApproval extends boolean,\n TApprovalSchema,\n> {\n readonly [toolApprovalCapability]?: {\n needsApproval: TNeedsApproval\n approvalSchema: TApprovalSchema\n }\n}\n\nexport type ApprovalSchemaConfig =\n | SchemaInput\n | { approve: SchemaInput; reject?: SchemaInput }\n | { approve?: SchemaInput; reject: SchemaInput }\n\ntype ApprovalConfig<\n TNeedsApproval extends boolean,\n TApprovalSchema extends ApprovalSchemaConfig | undefined,\n> = TNeedsApproval extends true\n ? { needsApproval: TNeedsApproval; approvalSchema?: TApprovalSchema }\n : { needsApproval?: TNeedsApproval; approvalSchema?: never }\n\nexport type ApprovalCapabilityOf<TTool> =\n TTool extends ToolApprovalCapabilityMarker<infer TNeeds, unknown>\n ? TNeeds\n : false\n\nexport type ApprovalSchemaOf<TTool> =\n TTool extends ToolApprovalCapabilityMarker<boolean, infer TSchema>\n ? TSchema\n : undefined\n\nexport declare const noSchema: unique symbol\nexport type NoSchema = typeof noSchema\n\nexport type InputSchemaOf<TTool> = TTool extends {\n inputSchema: infer TInput\n}\n ? TInput extends undefined\n ? NoSchema\n : TInput\n : NoSchema\n\nexport type OutputSchemaOf<TTool> = TTool extends {\n outputSchema: infer TOutput\n}\n ? TOutput extends undefined\n ? NoSchema\n : TOutput\n : NoSchema\n\ntype BuiltToolSchemaFields<\n TInput extends SchemaInput | undefined,\n TOutput extends SchemaInput | undefined,\n TApprovalSchema extends ApprovalSchemaConfig | undefined,\n> = {\n inputSchema: TInput\n outputSchema: TOutput\n approvalSchema: TApprovalSchema\n}\n\n/**\n * Marker type for server-side tools\n */\nexport interface ServerTool<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TContext = unknown,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n>\n extends\n Tool<TInput, TOutput, TName, TContext>,\n ToolApprovalCapabilityMarker<TNeedsApproval, TApprovalSchema> {\n __toolSide: 'server'\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: TNeedsApproval\n approvalSchema?: TApprovalSchema\n execution?: 'task'\n}\n\n/**\n * Marker type for client-side tools\n */\nexport interface ClientTool<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TContext = unknown,\n // Captured as a literal (`true` / `false`) so downstream types — notably\n // the tool-call part's `approval` field — can be gated on it. Defaults to\n // `false` when the tool config omits `needsApproval`.\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> extends ToolApprovalCapabilityMarker<TNeedsApproval, TApprovalSchema> {\n __toolSide: 'client'\n name: TName\n description: string\n // Note: `inputSchema` / `outputSchema` stay as bare optionals (not\n // widened to `| undefined`). They participate in inference via\n // `InferToolInput` / `InferToolOutput` — widening with `| undefined`\n // breaks the `infer TInput extends StandardJSONSchemaV1<...>` chain\n // because `undefined` doesn't extend the schema constraint.\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: TNeedsApproval\n approvalSchema?: TApprovalSchema\n execution?: 'task'\n lazy?: boolean\n metadata?: Record<string, unknown>\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>\n}\n\n/** Broad server-tool shape for heterogeneous internal collections. */\nexport type AnyServerTool = Omit<\n ServerTool<any, any, string, any, boolean, any>,\n 'execute'\n> & {\n execute?: ((args: any, context?: any) => any) | undefined\n}\n\n/**\n * Tool definition that can be used directly or instantiated for server/client\n */\nexport interface ToolDefinitionInstance<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TContext = unknown,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'definition'\n // Narrow the base `needsApproval?: boolean` to the captured literal so it\n // survives into `ToolCallPartForTool`'s approval gate.\n inputSchema: TInput\n outputSchema: TOutput\n needsApproval?: TNeedsApproval\n approvalSchema: TApprovalSchema\n execution?: 'task'\n readonly [toolApprovalCapability]?: {\n needsApproval: TNeedsApproval\n approvalSchema: TApprovalSchema\n }\n}\n\n/**\n * Union type for any kind of client-side tool (client tool or definition)\n */\nexport type AnyClientTool =\n | (Omit<ClientTool<any, any, string, any, boolean, any>, 'execute'> & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n | (Omit<\n ToolDefinitionInstance<any, any, string, any, boolean, any>,\n 'execute'\n > & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n\n/**\n * Extract the tool name as a literal type\n */\nexport type InferToolName<T> = T extends { name: infer N } ? N : never\n\n/**\n * Extract the input type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)\n */\nexport type InferToolInput<T> = T extends { inputSchema?: infer TInput }\n ? TInput extends JSONSchema\n ? unknown\n : InferSchemaType<TInput>\n : unknown\n\n/**\n * Extract the output type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)\n */\nexport type InferToolOutput<T> = T extends { outputSchema?: infer TOutput }\n ? TOutput extends StandardJSONSchemaV1<any, any>\n ? InferSchemaType<TOutput>\n : TOutput extends StandardSchemaV1<any, any>\n ? InferSchemaType<TOutput>\n : TOutput extends JSONSchema\n ? unknown\n : InferSchemaType<TOutput>\n : unknown\n\n/**\n * Tool definition configuration\n */\nexport type ToolDefinitionConfig<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> = {\n name: TName\n description: string\n inputSchema?: TInput\n outputSchema?: TOutput\n lazy?: boolean\n metadata?: Record<string, unknown>\n execution?: 'task'\n} & ApprovalConfig<TNeedsApproval, TApprovalSchema>\n\n/**\n * Tool definition builder that allows creating server or client tools from a shared definition\n */\nexport interface ToolDefinition<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n> extends ToolDefinitionInstance<\n TInput,\n TOutput,\n TName,\n unknown,\n TNeedsApproval,\n TApprovalSchema\n> {\n /**\n * Create a server-side tool with execute function\n */\n server: <TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ServerTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema>\n\n /**\n * Create a client-side tool with optional execute function.\n * Carries the definition's `needsApproval` literal through to the client\n * tool so the tool-call part's `approval` field stays gated on it.\n */\n client: <TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ClientTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema>\n}\n\n/**\n * Create an isomorphic tool definition that can be used directly or instantiated for server/client\n *\n * The definition contains all tool metadata (name, description, schemas) and can be:\n * 1. Used directly in chat() on the server (as a tool definition without execute)\n * 2. Instantiated as a server tool with .server()\n * 3. Instantiated as a client tool with .client()\n *\n * Supports any Standard JSON Schema compliant library (Zod v4+, ArkType, Valibot, etc.)\n * or plain JSON Schema objects.\n *\n * @example\n * ```typescript\n * import { toolDefinition } from '@tanstack/ai';\n * import { z } from 'zod';\n *\n * // Using Zod (natively supports Standard JSON Schema)\n * const addToCartTool = toolDefinition({\n * name: 'addToCart',\n * description: 'Add a guitar to the shopping cart (requires approval)',\n * needsApproval: true,\n * inputSchema: z.object({\n * guitarId: z.string(),\n * quantity: z.number(),\n * }),\n * outputSchema: z.object({\n * success: z.boolean(),\n * cartId: z.string(),\n * totalItems: z.number(),\n * }),\n * });\n *\n * // Use directly in chat (server-side, no execute function)\n * chat({\n * tools: [addToCartTool],\n * // ...\n * });\n *\n * // Or create server-side implementation\n * const addToCartServer = addToCartTool.server(async (args) => {\n * // args is typed as { guitarId: string; quantity: number }\n * return {\n * success: true,\n * cartId: 'CART_' + Date.now(),\n * totalItems: args.quantity,\n * };\n * });\n *\n * // Or create client-side implementation\n * const addToCartClient = addToCartTool.client(async (args) => {\n * // Client-specific logic (e.g., localStorage)\n * return { success: true, cartId: 'local', totalItems: 1 };\n * });\n * ```\n */\nexport function toolDefinition<\n TInput extends SchemaInput | undefined = undefined,\n TOutput extends SchemaInput | undefined = undefined,\n TName extends string = string,\n // `const` forces the literal (`true` / `false`) to be captured from the\n // config's optional `needsApproval` — without it TS widens to `boolean`,\n // which collapses the approval gate in `ToolCallPartForTool`.\n const TNeedsApproval extends boolean = false,\n TApprovalSchema extends ApprovalSchemaConfig | undefined = undefined,\n>(\n config: ToolDefinitionConfig<\n TInput,\n TOutput,\n TName,\n TNeedsApproval,\n TApprovalSchema\n >,\n): ToolDefinition<TInput, TOutput, TName, TNeedsApproval, TApprovalSchema> {\n if (config.approvalSchema !== undefined && config.needsApproval !== true) {\n throw new TypeError('approvalSchema requires needsApproval: true.')\n }\n const inputSchema = config.inputSchema as TInput\n const outputSchema = config.outputSchema as TOutput\n const approvalSchema = config.approvalSchema as TApprovalSchema\n const needsApproval = config.needsApproval as TNeedsApproval | undefined\n const execution = config.execution\n\n const definition: ToolDefinition<\n TInput,\n TOutput,\n TName,\n TNeedsApproval,\n TApprovalSchema\n > = {\n __toolSide: 'definition',\n ...config,\n inputSchema,\n outputSchema,\n approvalSchema,\n needsApproval,\n execution,\n server<TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ServerTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema> {\n return {\n __toolSide: 'server',\n ...config,\n inputSchema,\n outputSchema,\n approvalSchema,\n needsApproval,\n execution,\n execute,\n }\n },\n\n client<TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ClientTool<\n TInput,\n TOutput,\n TName,\n TContext,\n TNeedsApproval,\n TApprovalSchema\n > &\n BuiltToolSchemaFields<TInput, TOutput, TApprovalSchema> {\n return {\n __toolSide: 'client',\n ...config,\n inputSchema,\n outputSchema,\n approvalSchema,\n needsApproval,\n execution,\n ...(execute !== undefined && { execute }),\n }\n },\n }\n\n return definition\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8UA,SAAgB,eAUd,QAOyE;CACzE,IAAI,OAAO,mBAAmB,KAAA,KAAa,OAAO,kBAAkB,MAClE,MAAM,IAAI,UAAU,8CAA8C;CAEpE,MAAM,cAAc,OAAO;CAC3B,MAAM,eAAe,OAAO;CAC5B,MAAM,iBAAiB,OAAO;CAC9B,MAAM,gBAAgB,OAAO;CAC7B,MAAM,YAAY,OAAO;CA+DzB,OAAO;EAtDL,YAAY;EACZ,GAAG;EACH;EACA;EACA;EACA;EACA;EACA,OACE,SASwD;GACxD,OAAO;IACL,YAAY;IACZ,GAAG;IACH;IACA;IACA;IACA;IACA;IACA;GACF;EACF;EAEA,OACE,SASwD;GACxD,OAAO;IACL,YAAY;IACZ,GAAG;IACH;IACA;IACA;IACA;IACA;IACA,GAAI,YAAY,KAAA,KAAa,EAAE,QAAQ;GACzC;EACF;CAGK;AACT"}