@tanstack/ai 0.36.0 → 0.37.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.
- package/dist/esm/activities/chat/adapter.d.ts +163 -0
- package/dist/esm/activities/chat/adapter.js +17 -0
- package/dist/esm/activities/chat/adapter.js.map +1 -0
- package/dist/esm/activities/chat/agent-loop-strategies.d.ts +59 -0
- package/dist/esm/activities/chat/agent-loop-strategies.js +23 -0
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +270 -0
- package/dist/esm/activities/chat/index.js +1724 -0
- package/dist/esm/activities/chat/index.js.map +1 -0
- package/dist/esm/activities/chat/mcp/manager.d.ts +25 -0
- package/dist/esm/activities/chat/mcp/manager.js +71 -0
- package/dist/esm/activities/chat/mcp/manager.js.map +1 -0
- package/dist/esm/activities/chat/mcp/types.d.ts +56 -0
- package/dist/esm/activities/chat/messages.d.ts +78 -0
- package/dist/esm/activities/chat/messages.js +374 -0
- package/dist/esm/activities/chat/messages.js.map +1 -0
- package/dist/esm/activities/chat/middleware/builder.d.ts +46 -0
- package/dist/esm/activities/chat/middleware/builder.js +17 -0
- package/dist/esm/activities/chat/middleware/builder.js.map +1 -0
- package/dist/esm/activities/chat/middleware/capabilities.d.ts +93 -0
- package/dist/esm/activities/chat/middleware/capabilities.js +45 -0
- package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -0
- package/dist/esm/activities/chat/middleware/compose.d.ts +87 -0
- package/dist/esm/activities/chat/middleware/compose.js +510 -0
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -0
- package/dist/esm/activities/chat/middleware/define.d.ts +20 -0
- package/dist/esm/activities/chat/middleware/define.js +7 -0
- package/dist/esm/activities/chat/middleware/define.js.map +1 -0
- package/dist/esm/activities/chat/middleware/index.d.ts +10 -0
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.d.ts +89 -0
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +76 -0
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -0
- package/dist/esm/activities/chat/middleware/types.d.ts +405 -0
- package/dist/esm/activities/chat/middleware/validate.d.ts +19 -0
- package/dist/esm/activities/chat/middleware/validate.js +30 -0
- package/dist/esm/activities/chat/middleware/validate.js.map +1 -0
- package/dist/esm/activities/chat/runtime-context-types.d.ts +43 -0
- package/dist/esm/activities/chat/stream/index.d.ts +11 -0
- package/dist/esm/activities/chat/stream/json-parser.d.ts +38 -0
- package/dist/esm/activities/chat/stream/json-parser.js +28 -0
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -0
- package/dist/esm/activities/chat/stream/message-updaters.d.ts +81 -0
- package/dist/esm/activities/chat/stream/message-updaters.js +253 -0
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -0
- package/dist/esm/activities/chat/stream/processor.d.ts +439 -0
- package/dist/esm/activities/chat/stream/processor.js +1426 -0
- package/dist/esm/activities/chat/stream/processor.js.map +1 -0
- package/dist/esm/activities/chat/stream/strategies.d.ts +43 -0
- package/dist/esm/activities/chat/stream/strategies.js +54 -0
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -0
- package/dist/esm/activities/chat/stream/types.d.ts +90 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.d.ts +82 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +194 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -0
- package/dist/esm/activities/chat/tools/lazy-tools.d.ts +15 -0
- package/dist/esm/activities/chat/tools/lazy-tools.js +16 -0
- package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -0
- package/dist/esm/activities/chat/tools/schema-converter.d.ts +140 -0
- package/dist/esm/activities/chat/tools/schema-converter.js +167 -0
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -0
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +140 -0
- package/dist/esm/activities/chat/tools/tool-calls.js +512 -0
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -0
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +135 -0
- package/dist/esm/activities/chat/tools/tool-definition.js +25 -0
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -0
- package/dist/esm/activities/error-payload.d.ts +30 -0
- package/dist/esm/activities/error-payload.js +54 -0
- package/dist/esm/activities/error-payload.js.map +1 -0
- package/dist/esm/activities/generateAudio/adapter.d.ts +62 -0
- package/dist/esm/activities/generateAudio/adapter.js +16 -0
- package/dist/esm/activities/generateAudio/adapter.js.map +1 -0
- package/dist/esm/activities/generateAudio/index.d.ts +85 -0
- package/dist/esm/activities/generateAudio/index.js +114 -0
- package/dist/esm/activities/generateAudio/index.js.map +1 -0
- package/dist/esm/activities/generateImage/adapter.d.ts +78 -0
- package/dist/esm/activities/generateImage/adapter.js +16 -0
- package/dist/esm/activities/generateImage/adapter.js.map +1 -0
- package/dist/esm/activities/generateImage/index.d.ts +134 -0
- package/dist/esm/activities/generateImage/index.js +121 -0
- package/dist/esm/activities/generateImage/index.js.map +1 -0
- package/dist/esm/activities/generateSpeech/adapter.d.ts +62 -0
- package/dist/esm/activities/generateSpeech/adapter.js +16 -0
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -0
- package/dist/esm/activities/generateSpeech/index.d.ts +96 -0
- package/dist/esm/activities/generateSpeech/index.js +119 -0
- package/dist/esm/activities/generateSpeech/index.js.map +1 -0
- package/dist/esm/activities/generateTranscription/adapter.d.ts +62 -0
- package/dist/esm/activities/generateTranscription/adapter.js +16 -0
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -0
- package/dist/esm/activities/generateTranscription/index.d.ts +109 -0
- package/dist/esm/activities/generateTranscription/index.js +109 -0
- package/dist/esm/activities/generateTranscription/index.js.map +1 -0
- package/dist/esm/activities/generateVideo/adapter.d.ts +145 -0
- package/dist/esm/activities/generateVideo/adapter.js +30 -0
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -0
- package/dist/esm/activities/generateVideo/index.d.ts +223 -0
- package/dist/esm/activities/generateVideo/index.js +295 -0
- package/dist/esm/activities/generateVideo/index.js.map +1 -0
- package/dist/esm/activities/generateVideo/snap.d.ts +14 -0
- package/dist/esm/activities/generateVideo/snap.js +54 -0
- package/dist/esm/activities/generateVideo/snap.js.map +1 -0
- package/dist/esm/activities/index.d.ts +27 -0
- package/dist/esm/activities/index.js +43 -0
- package/dist/esm/activities/index.js.map +1 -0
- package/dist/esm/activities/middleware/index.d.ts +2 -0
- package/dist/esm/activities/middleware/run.d.ts +20 -0
- package/dist/esm/activities/middleware/run.js +42 -0
- package/dist/esm/activities/middleware/run.js.map +1 -0
- package/dist/esm/activities/middleware/types.d.ts +118 -0
- package/dist/esm/activities/stream-generation-result.d.ts +15 -0
- package/dist/esm/activities/stream-generation-result.js +49 -0
- package/dist/esm/activities/stream-generation-result.js.map +1 -0
- package/dist/esm/activities/summarize/adapter.d.ts +74 -0
- package/dist/esm/activities/summarize/adapter.js +16 -0
- package/dist/esm/activities/summarize/adapter.js.map +1 -0
- package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +45 -0
- package/dist/esm/activities/summarize/chat-stream-summarize.js +212 -0
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -0
- package/dist/esm/activities/summarize/index.d.ts +108 -0
- package/dist/esm/activities/summarize/index.js +113 -0
- package/dist/esm/activities/summarize/index.js.map +1 -0
- package/dist/esm/adapter-internals.d.ts +5 -0
- package/dist/esm/adapter-internals.js +10 -0
- package/dist/esm/adapter-internals.js.map +1 -0
- package/dist/esm/client.d.ts +44 -0
- package/dist/esm/client.js +67 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/extend-adapter.d.ts +152 -0
- package/dist/esm/extend-adapter.js +21 -0
- package/dist/esm/extend-adapter.js.map +1 -0
- package/dist/esm/index.d.ts +45 -0
- package/dist/esm/index.js +109 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/logger/console-logger.d.ts +29 -0
- package/dist/esm/logger/console-logger.js +83 -0
- package/dist/esm/logger/console-logger.js.map +1 -0
- package/dist/esm/logger/internal-logger.d.ts +41 -0
- package/dist/esm/logger/internal-logger.js +86 -0
- package/dist/esm/logger/internal-logger.js.map +1 -0
- package/dist/esm/logger/resolve.d.ts +14 -0
- package/dist/esm/logger/resolve.js +54 -0
- package/dist/esm/logger/resolve.js.map +1 -0
- package/dist/esm/logger/types.d.ts +75 -0
- package/dist/esm/middlewares/content-guard.d.ts +77 -0
- package/dist/esm/middlewares/content-guard.js +156 -0
- package/dist/esm/middlewares/content-guard.js.map +1 -0
- package/dist/esm/middlewares/index.d.ts +2 -0
- package/dist/esm/middlewares/index.js +7 -0
- package/dist/esm/middlewares/index.js.map +1 -0
- package/dist/esm/middlewares/otel.d.ts +81 -0
- package/dist/esm/middlewares/otel.js +745 -0
- package/dist/esm/middlewares/otel.js.map +1 -0
- package/dist/esm/middlewares/tool-cache.d.ts +1 -0
- package/dist/esm/middlewares/usage-attributes.d.ts +24 -0
- package/dist/esm/middlewares/usage-attributes.js +43 -0
- package/dist/esm/middlewares/usage-attributes.js.map +1 -0
- package/dist/esm/realtime/index.d.ts +28 -0
- package/dist/esm/realtime/index.js +8 -0
- package/dist/esm/realtime/index.js.map +1 -0
- package/dist/esm/realtime/types.d.ts +282 -0
- package/dist/esm/stream-to-response.d.ts +102 -0
- package/dist/esm/stream-to-response.js +121 -0
- package/dist/esm/stream-to-response.js.map +1 -0
- package/dist/esm/strip-to-spec-middleware.d.ts +18 -0
- package/dist/esm/strip-to-spec-middleware.js +20 -0
- package/dist/esm/strip-to-spec-middleware.js.map +1 -0
- package/dist/esm/system-prompts.d.ts +66 -0
- package/dist/esm/system-prompts.js +23 -0
- package/dist/esm/system-prompts.js.map +1 -0
- package/dist/esm/tool-registry.d.ts +81 -0
- package/dist/esm/tool-registry.js +49 -0
- package/dist/esm/tool-registry.js.map +1 -0
- package/dist/esm/tools/provider-tool.d.ts +30 -0
- package/dist/esm/tools/provider-tool.js +7 -0
- package/dist/esm/tools/provider-tool.js.map +1 -0
- package/dist/esm/types.d.ts +1594 -0
- package/dist/esm/utilities/ag-ui-wire.d.ts +44 -0
- package/dist/esm/utilities/ag-ui-wire.js +107 -0
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -0
- package/dist/esm/utilities/chat-params.d.ts +85 -0
- package/dist/esm/utilities/chat-params.js +100 -0
- package/dist/esm/utilities/chat-params.js.map +1 -0
- package/dist/esm/utilities/errors.d.ts +13 -0
- package/dist/esm/utilities/errors.js +22 -0
- package/dist/esm/utilities/errors.js.map +1 -0
- package/dist/esm/utilities/media-prompt.d.ts +35 -0
- package/dist/esm/utilities/media-prompt.js +43 -0
- package/dist/esm/utilities/media-prompt.js.map +1 -0
- package/dist/esm/utilities/numbers.d.ts +8 -0
- package/dist/esm/utilities/numbers.js +12 -0
- package/dist/esm/utilities/numbers.js.map +1 -0
- package/dist/esm/utilities/sampling-keys.d.ts +20 -0
- package/dist/esm/utilities/sampling-keys.js +20 -0
- package/dist/esm/utilities/sampling-keys.js.map +1 -0
- package/dist/esm/utilities/tool-result.d.ts +21 -0
- package/dist/esm/utilities/tool-result.js +37 -0
- package/dist/esm/utilities/tool-result.js.map +1 -0
- package/dist/esm/utilities/usage.d.ts +31 -0
- package/dist/esm/utilities/usage.js +11 -0
- package/dist/esm/utilities/usage.js.map +1 -0
- package/dist/esm/utils.d.ts +17 -0
- package/dist/esm/utils.js +20 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-calls.js","sources":["../../../../../src/activities/chat/tools/tool-calls.ts"],"sourcesContent":["import { normalizeToolResult } from '../../../utilities/tool-result'\nimport { isStandardSchema, parseWithStandardSchema } from './schema-converter'\nimport type {\n AnyTool,\n ContentPart,\n CustomEvent,\n ModelMessage,\n RunFinishedEvent,\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 {\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/**\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 const index = event.index ?? this.toolCallsMap.size\n const runtimeEvent = event as Partial<ToolCallStartEvent> &\n Pick<ToolCallStartEvent, 'toolName'>\n const name = runtimeEvent.toolCallName ?? runtimeEvent.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 // Find the tool call by ID\n for (const [, toolCall] of this.toolCallsMap.entries()) {\n if (toolCall.id === event.toolCallId) {\n toolCall.function.arguments += event.delta\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.entries()) {\n if (toolCall.id === event.toolCallId) {\n if (event.input !== undefined) {\n // Normalize null/non-object to {} (e.g. Anthropic empty tool_use blocks)\n const normalized =\n event.input && typeof event.input === 'object' ? event.input : {}\n toolCall.function.arguments = JSON.stringify(normalized)\n }\n break\n }\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<ToolCallEndEvent, 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 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 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: finishEvent.model,\n timestamp: Date.now(),\n result: toolResultContent,\n ...(toolResultState !== undefined && { state: toolResultState }),\n } as ToolCallEndEvent\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\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\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}\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>,\n): AsyncGenerator<CustomEvent, 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 | 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 | 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 */\nasync function* executeServerTool<TContext = unknown>(\n toolCall: ToolCall,\n tool: AnyTool,\n toolName: string,\n input: unknown,\n context: ToolExecutionContext<TContext>,\n pendingEvents: Array<CustomEvent>,\n results: Array<ToolResult>,\n middlewareHooks?: ToolExecutionMiddlewareHooks,\n): AsyncGenerator<CustomEvent, 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 executionPromise = Promise.resolve(tool.execute(input, context))\n let result = yield* executeWithEventPolling(executionPromise, pendingEvents)\n const duration = Date.now() - startTime\n\n // Flush remaining events\n let pendingEvent: CustomEvent | 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 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 | 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 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): ToolResult {\n try {\n let result = rawResult\n if (tool.outputSchema && isStandardSchema(tool.outputSchema)) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n return {\n toolCallId,\n toolName,\n result:\n typeof result === 'string' ? safeJsonParse(result) : (result ?? null),\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 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 of approval decisions (approval.id -> approved boolean)\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, boolean> = new Map(),\n clientResults: Map<string, any> = new Map(),\n createCustomEventChunk?: (\n eventName: string,\n value: Record<string, any>,\n ) => CustomEvent,\n middlewareHooks?: ToolExecutionMiddlewareHooks,\n userContext?: TContext,\n abortSignal?: AbortSignal,\n): AsyncGenerator<CustomEvent, ExecuteToolCallsResult, void> {\n const results: Array<ToolResult> = []\n const needsApproval: Array<ApprovalRequest> = []\n const needsClientExecution: Array<ClientToolRequest> = []\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 t?.needsApproval && !approvals.has(`approval_${tc.id}`)\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 if (!tool.needsApproval || approvals.has(`approval_${toolCall.id}`)) {\n continue\n }\n }\n\n // Parse arguments, throwing error if invalid JSON\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 (parseError) {\n // If parsing fails, throw error to fail fast\n throw new Error(`Failed to parse tool arguments as JSON: ${argsStr}`)\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 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> = []\n const context = {\n toolCallId: toolCall.id,\n context: userContext,\n abortSignal,\n emitCustomEvent: (eventName: string, value: Record<string, any>) => {\n if (createCustomEventChunk) {\n pendingEvents.push(\n createCustomEventChunk(eventName, {\n ...value,\n toolCallId: toolCall.id,\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\n // Check if approval decision exists\n if (approvals.has(approvalId)) {\n const approved = approvals.get(approvalId)\n\n if (approved) {\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 ),\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: { error: 'User declined tool execution' },\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 ),\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\n // Check if approval decision exists\n if (approvals.has(approvalId)) {\n const approved = approvals.get(approvalId)\n\n if (approved) {\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 )\n } else {\n // User declined\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result: { error: 'User declined tool execution' },\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 )\n }\n\n return { results, needsApproval, needsClientExecution }\n}\n"],"names":["event"],"mappings":"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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { StandardJSONSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import { JSONSchema, SchemaInput, Tool, ToolExecuteFunction } from '../../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Marker type for server-side tools
|
|
5
|
+
*/
|
|
6
|
+
export interface ServerTool<TInput extends SchemaInput = SchemaInput, TOutput extends SchemaInput = SchemaInput, TName extends string = string, TContext = unknown> extends Tool<TInput, TOutput, TName, TContext> {
|
|
7
|
+
__toolSide: 'server';
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Marker type for client-side tools
|
|
11
|
+
*/
|
|
12
|
+
export interface ClientTool<TInput extends SchemaInput = SchemaInput, TOutput extends SchemaInput = SchemaInput, TName extends string = string, TContext = unknown> {
|
|
13
|
+
__toolSide: 'client';
|
|
14
|
+
name: TName;
|
|
15
|
+
description: string;
|
|
16
|
+
inputSchema?: TInput;
|
|
17
|
+
outputSchema?: TOutput;
|
|
18
|
+
needsApproval?: boolean;
|
|
19
|
+
lazy?: boolean;
|
|
20
|
+
metadata?: Record<string, unknown>;
|
|
21
|
+
execute?: ToolExecuteFunction<TInput, TOutput, TContext>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Tool definition that can be used directly or instantiated for server/client
|
|
25
|
+
*/
|
|
26
|
+
export interface ToolDefinitionInstance<TInput extends SchemaInput = SchemaInput, TOutput extends SchemaInput = SchemaInput, TName extends string = string, TContext = unknown> extends Tool<TInput, TOutput, TName, TContext> {
|
|
27
|
+
__toolSide: 'definition';
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Union type for any kind of client-side tool (client tool or definition)
|
|
31
|
+
*/
|
|
32
|
+
export type AnyClientTool = (Omit<ClientTool<any, any, string, any>, 'execute'> & {
|
|
33
|
+
execute?: ((args: any, context?: any) => any) | undefined;
|
|
34
|
+
}) | (Omit<ToolDefinitionInstance<any, any, string, any>, 'execute'> & {
|
|
35
|
+
execute?: ((args: any, context?: any) => any) | undefined;
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Extract the tool name as a literal type
|
|
39
|
+
*/
|
|
40
|
+
export type InferToolName<T> = T extends {
|
|
41
|
+
name: infer N;
|
|
42
|
+
} ? N : never;
|
|
43
|
+
/**
|
|
44
|
+
* Extract the input type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)
|
|
45
|
+
*/
|
|
46
|
+
export type InferToolInput<T> = T extends {
|
|
47
|
+
inputSchema?: infer TInput;
|
|
48
|
+
} ? TInput extends StandardJSONSchemaV1<infer TInferred, unknown> ? TInferred : TInput extends JSONSchema ? unknown : unknown : unknown;
|
|
49
|
+
/**
|
|
50
|
+
* Extract the output type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)
|
|
51
|
+
*/
|
|
52
|
+
export type InferToolOutput<T> = T extends {
|
|
53
|
+
outputSchema?: infer TOutput;
|
|
54
|
+
} ? TOutput extends StandardJSONSchemaV1<infer TInferred, unknown> ? TInferred : TOutput extends JSONSchema ? unknown : unknown : unknown;
|
|
55
|
+
/**
|
|
56
|
+
* Tool definition configuration
|
|
57
|
+
*/
|
|
58
|
+
export interface ToolDefinitionConfig<TInput extends SchemaInput = SchemaInput, TOutput extends SchemaInput = SchemaInput, TName extends string = string> {
|
|
59
|
+
name: TName;
|
|
60
|
+
description: string;
|
|
61
|
+
inputSchema?: TInput;
|
|
62
|
+
outputSchema?: TOutput;
|
|
63
|
+
needsApproval?: boolean;
|
|
64
|
+
lazy?: boolean;
|
|
65
|
+
metadata?: Record<string, unknown>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Tool definition builder that allows creating server or client tools from a shared definition
|
|
69
|
+
*/
|
|
70
|
+
export interface ToolDefinition<TInput extends SchemaInput = SchemaInput, TOutput extends SchemaInput = SchemaInput, TName extends string = string> extends ToolDefinitionInstance<TInput, TOutput, TName> {
|
|
71
|
+
/**
|
|
72
|
+
* Create a server-side tool with execute function
|
|
73
|
+
*/
|
|
74
|
+
server: <TContext = unknown>(execute: ToolExecuteFunction<TInput, TOutput, TContext>) => ServerTool<TInput, TOutput, TName, TContext>;
|
|
75
|
+
/**
|
|
76
|
+
* Create a client-side tool with optional execute function
|
|
77
|
+
*/
|
|
78
|
+
client: <TContext = unknown>(execute?: ToolExecuteFunction<TInput, TOutput, TContext>) => ClientTool<TInput, TOutput, TName, TContext>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create an isomorphic tool definition that can be used directly or instantiated for server/client
|
|
82
|
+
*
|
|
83
|
+
* The definition contains all tool metadata (name, description, schemas) and can be:
|
|
84
|
+
* 1. Used directly in chat() on the server (as a tool definition without execute)
|
|
85
|
+
* 2. Instantiated as a server tool with .server()
|
|
86
|
+
* 3. Instantiated as a client tool with .client()
|
|
87
|
+
*
|
|
88
|
+
* Supports any Standard JSON Schema compliant library (Zod v4+, ArkType, Valibot, etc.)
|
|
89
|
+
* or plain JSON Schema objects.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* import { toolDefinition } from '@tanstack/ai';
|
|
94
|
+
* import { z } from 'zod';
|
|
95
|
+
*
|
|
96
|
+
* // Using Zod (natively supports Standard JSON Schema)
|
|
97
|
+
* const addToCartTool = toolDefinition({
|
|
98
|
+
* name: 'addToCart',
|
|
99
|
+
* description: 'Add a guitar to the shopping cart (requires approval)',
|
|
100
|
+
* needsApproval: true,
|
|
101
|
+
* inputSchema: z.object({
|
|
102
|
+
* guitarId: z.string(),
|
|
103
|
+
* quantity: z.number(),
|
|
104
|
+
* }),
|
|
105
|
+
* outputSchema: z.object({
|
|
106
|
+
* success: z.boolean(),
|
|
107
|
+
* cartId: z.string(),
|
|
108
|
+
* totalItems: z.number(),
|
|
109
|
+
* }),
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* // Use directly in chat (server-side, no execute function)
|
|
113
|
+
* chat({
|
|
114
|
+
* tools: [addToCartTool],
|
|
115
|
+
* // ...
|
|
116
|
+
* });
|
|
117
|
+
*
|
|
118
|
+
* // Or create server-side implementation
|
|
119
|
+
* const addToCartServer = addToCartTool.server(async (args) => {
|
|
120
|
+
* // args is typed as { guitarId: string; quantity: number }
|
|
121
|
+
* return {
|
|
122
|
+
* success: true,
|
|
123
|
+
* cartId: 'CART_' + Date.now(),
|
|
124
|
+
* totalItems: args.quantity,
|
|
125
|
+
* };
|
|
126
|
+
* });
|
|
127
|
+
*
|
|
128
|
+
* // Or create client-side implementation
|
|
129
|
+
* const addToCartClient = addToCartTool.client(async (args) => {
|
|
130
|
+
* // Client-specific logic (e.g., localStorage)
|
|
131
|
+
* return { success: true, cartId: 'local', totalItems: 1 };
|
|
132
|
+
* });
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export declare function toolDefinition<TInput extends SchemaInput = SchemaInput, TOutput extends SchemaInput = SchemaInput, TName extends string = string>(config: ToolDefinitionConfig<TInput, TOutput, TName>): ToolDefinition<TInput, TOutput, TName>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function toolDefinition(config) {
|
|
2
|
+
const definition = {
|
|
3
|
+
__toolSide: "definition",
|
|
4
|
+
...config,
|
|
5
|
+
server(execute) {
|
|
6
|
+
return {
|
|
7
|
+
__toolSide: "server",
|
|
8
|
+
...config,
|
|
9
|
+
execute
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
client(execute) {
|
|
13
|
+
return {
|
|
14
|
+
__toolSide: "client",
|
|
15
|
+
...config,
|
|
16
|
+
...execute !== void 0 && { execute }
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return definition;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
toolDefinition
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=tool-definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-definition.js","sources":["../../../../../src/activities/chat/tools/tool-definition.ts"],"sourcesContent":["import type { StandardJSONSchemaV1 } from '@standard-schema/spec'\nimport type {\n JSONSchema,\n SchemaInput,\n Tool,\n ToolExecuteFunction,\n} from '../../../types'\n\n/**\n * Marker type for server-side tools\n */\nexport interface ServerTool<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'server'\n}\n\n/**\n * Marker type for client-side tools\n */\nexport interface ClientTool<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n> {\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?: boolean\n lazy?: boolean\n metadata?: Record<string, unknown>\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>\n}\n\n/**\n * Tool definition that can be used directly or instantiated for server/client\n */\nexport interface ToolDefinitionInstance<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n TContext = unknown,\n> extends Tool<TInput, TOutput, TName, TContext> {\n __toolSide: 'definition'\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>, 'execute'> & {\n execute?: ((args: any, context?: any) => any) | undefined\n })\n | (Omit<ToolDefinitionInstance<any, any, string, any>, 'execute'> & {\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 StandardJSONSchemaV1<infer TInferred, unknown>\n ? TInferred\n : TInput extends JSONSchema\n ? unknown\n : unknown\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<infer TInferred, unknown>\n ? TInferred\n : TOutput extends JSONSchema\n ? unknown\n : unknown\n : unknown\n\n/**\n * Tool definition configuration\n */\nexport interface ToolDefinitionConfig<\n TInput extends SchemaInput = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n> {\n name: TName\n description: string\n inputSchema?: TInput\n outputSchema?: TOutput\n needsApproval?: boolean\n lazy?: boolean\n metadata?: Record<string, unknown>\n}\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 = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n> extends ToolDefinitionInstance<TInput, TOutput, TName> {\n /**\n * Create a server-side tool with execute function\n */\n server: <TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ServerTool<TInput, TOutput, TName, TContext>\n\n /**\n * Create a client-side tool with optional execute function\n */\n client: <TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ) => ClientTool<TInput, TOutput, TName, TContext>\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 = SchemaInput,\n TOutput extends SchemaInput = SchemaInput,\n TName extends string = string,\n>(\n config: ToolDefinitionConfig<TInput, TOutput, TName>,\n): ToolDefinition<TInput, TOutput, TName> {\n const definition: ToolDefinition<TInput, TOutput, TName> = {\n __toolSide: 'definition',\n ...config,\n server<TContext = unknown>(\n execute: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ServerTool<TInput, TOutput, TName, TContext> {\n return {\n __toolSide: 'server',\n ...config,\n execute,\n }\n },\n\n client<TContext = unknown>(\n execute?: ToolExecuteFunction<TInput, TOutput, TContext>,\n ): ClientTool<TInput, TOutput, TName, TContext> {\n return {\n __toolSide: 'client',\n ...config,\n ...(execute !== undefined && { execute }),\n }\n },\n }\n\n return definition\n}\n"],"names":[],"mappings":"AA8LO,SAAS,eAKd,QACwC;AACxC,QAAM,aAAqD;AAAA,IACzD,YAAY;AAAA,IACZ,GAAG;AAAA,IACH,OACE,SAC8C;AAC9C,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,GAAG;AAAA,QACH;AAAA,MAAA;AAAA,IAEJ;AAAA,IAEA,OACE,SAC8C;AAC9C,aAAO;AAAA,QACL,YAAY;AAAA,QACZ,GAAG;AAAA,QACH,GAAI,YAAY,UAAa,EAAE,QAAA;AAAA,MAAQ;AAAA,IAE3C;AAAA,EAAA;AAGF,SAAO;AACT;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare function toRunErrorPayload(error: unknown, fallbackMessage?: string): {
|
|
2
|
+
message: string;
|
|
3
|
+
code: string | undefined;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Extract the provider's *structured error body* from a thrown value, to attach
|
|
7
|
+
* as the AG-UI `rawEvent` on a RUN_ERROR event. This is the recoverable upstream
|
|
8
|
+
* detail (provider name, the upstream model's error JSON, rate-limit/overload
|
|
9
|
+
* codes, etc.) that `toRunErrorPayload`'s `{ message, code }` deliberately drops.
|
|
10
|
+
*
|
|
11
|
+
* Security boundary: only known provider-response-body fields are forwarded —
|
|
12
|
+
* never the raw SDK exception object, which can carry request metadata such as
|
|
13
|
+
* auth headers or request ids. The recognized sources, in priority order:
|
|
14
|
+
*
|
|
15
|
+
* - `error.rawEvent` — a provider body an adapter attached explicitly (e.g. the
|
|
16
|
+
* OpenRouter mid-stream `chunk.error`).
|
|
17
|
+
* - `error.error` (object) — the parsed provider response body exposed by SDK
|
|
18
|
+
* `APIError` instances (OpenAI/Anthropic `{ type, message, code, param }`,
|
|
19
|
+
* OpenRouter typed errors whose `.error` carries `.metadata`). This is
|
|
20
|
+
* provider-shaped data, distinct from `.headers` / `.request_id`.
|
|
21
|
+
* - `error.metadata` — OpenRouter's `provider_name` + raw upstream body, when
|
|
22
|
+
* surfaced directly on the thrown error.
|
|
23
|
+
*
|
|
24
|
+
* Returns `undefined` when no structured provider body is present, so callers
|
|
25
|
+
* omit the field entirely rather than setting it to `null`:
|
|
26
|
+
*
|
|
27
|
+
* const rawEvent = toRunErrorRawEvent(error)
|
|
28
|
+
* yield { type: EventType.RUN_ERROR, ..., ...(rawEvent !== undefined && { rawEvent }) }
|
|
29
|
+
*/
|
|
30
|
+
export declare function toRunErrorRawEvent(error: unknown): unknown;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const ABORT_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
2
|
+
"AbortError",
|
|
3
|
+
"APIUserAbortError",
|
|
4
|
+
"RequestAbortedError"
|
|
5
|
+
]);
|
|
6
|
+
function normalizeCode(codeField) {
|
|
7
|
+
if (typeof codeField === "string") return codeField;
|
|
8
|
+
if (typeof codeField === "number" && Number.isFinite(codeField)) {
|
|
9
|
+
return String(codeField);
|
|
10
|
+
}
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
function toRunErrorPayload(error, fallbackMessage = "Unknown error occurred") {
|
|
14
|
+
if (error && typeof error === "object") {
|
|
15
|
+
const name = error.name;
|
|
16
|
+
if (typeof name === "string" && ABORT_ERROR_NAMES.has(name)) {
|
|
17
|
+
return { message: "Request aborted", code: "aborted" };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (error instanceof Error) {
|
|
21
|
+
const codeField = error.code;
|
|
22
|
+
return {
|
|
23
|
+
message: error.message || fallbackMessage,
|
|
24
|
+
code: normalizeCode(codeField)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (typeof error === "object" && error !== null) {
|
|
28
|
+
const messageField = error.message;
|
|
29
|
+
const codeField = error.code;
|
|
30
|
+
return {
|
|
31
|
+
message: typeof messageField === "string" && messageField.length > 0 ? messageField : fallbackMessage,
|
|
32
|
+
code: normalizeCode(codeField)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (typeof error === "string" && error.length > 0) {
|
|
36
|
+
return { message: error, code: void 0 };
|
|
37
|
+
}
|
|
38
|
+
return { message: fallbackMessage, code: void 0 };
|
|
39
|
+
}
|
|
40
|
+
function toRunErrorRawEvent(error) {
|
|
41
|
+
if (!error || typeof error !== "object") return void 0;
|
|
42
|
+
const e = error;
|
|
43
|
+
if (e.rawEvent !== void 0 && e.rawEvent !== null) return e.rawEvent;
|
|
44
|
+
if (e.error !== void 0 && e.error !== null && typeof e.error === "object") {
|
|
45
|
+
return e.error;
|
|
46
|
+
}
|
|
47
|
+
if (e.metadata !== void 0 && e.metadata !== null) return e.metadata;
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
toRunErrorPayload,
|
|
52
|
+
toRunErrorRawEvent
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=error-payload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-payload.js","sources":["../../../src/activities/error-payload.ts"],"sourcesContent":["/**\n * Shared error-narrowing helper for activities that convert thrown values\n * into structured `RUN_ERROR` events.\n *\n * Accepts Error instances, objects with string-ish `message`/`code`, or bare\n * strings; always returns a shape safe to serialize. Never leaks the full\n * error object (which may carry request/response state from an SDK).\n *\n * Abort-shaped errors (DOM `AbortError`, OpenAI `APIUserAbortError`,\n * OpenRouter `RequestAbortedError`) are normalized to a stable\n * `{ message: 'Request aborted', code: 'aborted' }` shape so callers can\n * discriminate user-initiated cancellation from other failures without\n * matching on provider-specific message strings.\n */\nconst ABORT_ERROR_NAMES = new Set([\n 'AbortError',\n 'APIUserAbortError',\n 'RequestAbortedError',\n])\n\n// HTTP status codes carried as numbers (e.g. `error.status = 429`) are a\n// common variant on SDK error classes; coerce so the resulting `code` field\n// is stable as a string for downstream consumers.\nfunction normalizeCode(codeField: unknown): string | undefined {\n if (typeof codeField === 'string') return codeField\n if (typeof codeField === 'number' && Number.isFinite(codeField)) {\n return String(codeField)\n }\n return undefined\n}\n\nexport function toRunErrorPayload(\n error: unknown,\n fallbackMessage = 'Unknown error occurred',\n): { message: string; code: string | undefined } {\n if (error && typeof error === 'object') {\n const name = (error as { name?: unknown }).name\n if (typeof name === 'string' && ABORT_ERROR_NAMES.has(name)) {\n return { message: 'Request aborted', code: 'aborted' }\n }\n }\n if (error instanceof Error) {\n const codeField = (error as Error & { code?: unknown }).code\n return {\n message: error.message || fallbackMessage,\n code: normalizeCode(codeField),\n }\n }\n if (typeof error === 'object' && error !== null) {\n const messageField = (error as { message?: unknown }).message\n const codeField = (error as { code?: unknown }).code\n return {\n message:\n typeof messageField === 'string' && messageField.length > 0\n ? messageField\n : fallbackMessage,\n code: normalizeCode(codeField),\n }\n }\n if (typeof error === 'string' && error.length > 0) {\n return { message: error, code: undefined }\n }\n return { message: fallbackMessage, code: undefined }\n}\n\n/**\n * Extract the provider's *structured error body* from a thrown value, to attach\n * as the AG-UI `rawEvent` on a RUN_ERROR event. This is the recoverable upstream\n * detail (provider name, the upstream model's error JSON, rate-limit/overload\n * codes, etc.) that `toRunErrorPayload`'s `{ message, code }` deliberately drops.\n *\n * Security boundary: only known provider-response-body fields are forwarded —\n * never the raw SDK exception object, which can carry request metadata such as\n * auth headers or request ids. The recognized sources, in priority order:\n *\n * - `error.rawEvent` — a provider body an adapter attached explicitly (e.g. the\n * OpenRouter mid-stream `chunk.error`).\n * - `error.error` (object) — the parsed provider response body exposed by SDK\n * `APIError` instances (OpenAI/Anthropic `{ type, message, code, param }`,\n * OpenRouter typed errors whose `.error` carries `.metadata`). This is\n * provider-shaped data, distinct from `.headers` / `.request_id`.\n * - `error.metadata` — OpenRouter's `provider_name` + raw upstream body, when\n * surfaced directly on the thrown error.\n *\n * Returns `undefined` when no structured provider body is present, so callers\n * omit the field entirely rather than setting it to `null`:\n *\n * const rawEvent = toRunErrorRawEvent(error)\n * yield { type: EventType.RUN_ERROR, ..., ...(rawEvent !== undefined && { rawEvent }) }\n */\nexport function toRunErrorRawEvent(error: unknown): unknown {\n if (!error || typeof error !== 'object') return undefined\n const e = error as {\n rawEvent?: unknown\n error?: unknown\n metadata?: unknown\n }\n if (e.rawEvent !== undefined && e.rawEvent !== null) return e.rawEvent\n if (\n e.error !== undefined &&\n e.error !== null &&\n typeof e.error === 'object'\n ) {\n return e.error\n }\n if (e.metadata !== undefined && e.metadata !== null) return e.metadata\n return undefined\n}\n"],"names":[],"mappings":"AAcA,MAAM,wCAAwB,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKD,SAAS,cAAc,WAAwC;AAC7D,MAAI,OAAO,cAAc,SAAU,QAAO;AAC1C,MAAI,OAAO,cAAc,YAAY,OAAO,SAAS,SAAS,GAAG;AAC/D,WAAO,OAAO,SAAS;AAAA,EACzB;AACA,SAAO;AACT;AAEO,SAAS,kBACd,OACA,kBAAkB,0BAC6B;AAC/C,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,OAAQ,MAA6B;AAC3C,QAAI,OAAO,SAAS,YAAY,kBAAkB,IAAI,IAAI,GAAG;AAC3D,aAAO,EAAE,SAAS,mBAAmB,MAAM,UAAA;AAAA,IAC7C;AAAA,EACF;AACA,MAAI,iBAAiB,OAAO;AAC1B,UAAM,YAAa,MAAqC;AACxD,WAAO;AAAA,MACL,SAAS,MAAM,WAAW;AAAA,MAC1B,MAAM,cAAc,SAAS;AAAA,IAAA;AAAA,EAEjC;AACA,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,UAAM,eAAgB,MAAgC;AACtD,UAAM,YAAa,MAA6B;AAChD,WAAO;AAAA,MACL,SACE,OAAO,iBAAiB,YAAY,aAAa,SAAS,IACtD,eACA;AAAA,MACN,MAAM,cAAc,SAAS;AAAA,IAAA;AAAA,EAEjC;AACA,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG;AACjD,WAAO,EAAE,SAAS,OAAO,MAAM,OAAA;AAAA,EACjC;AACA,SAAO,EAAE,SAAS,iBAAiB,MAAM,OAAA;AAC3C;AA2BO,SAAS,mBAAmB,OAAyB;AAC1D,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AAKV,MAAI,EAAE,aAAa,UAAa,EAAE,aAAa,aAAa,EAAE;AAC9D,MACE,EAAE,UAAU,UACZ,EAAE,UAAU,QACZ,OAAO,EAAE,UAAU,UACnB;AACA,WAAO,EAAE;AAAA,EACX;AACA,MAAI,EAAE,aAAa,UAAa,EAAE,aAAa,aAAa,EAAE;AAC9D,SAAO;AACT;"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { AudioGenerationOptions, AudioGenerationResult } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for audio generation adapter instances
|
|
4
|
+
*/
|
|
5
|
+
export interface AudioAdapterConfig {
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
maxRetries?: number;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Audio generation adapter interface with pre-resolved generics.
|
|
14
|
+
*
|
|
15
|
+
* An adapter is created by a provider function: `provider('model')` → `adapter`
|
|
16
|
+
* All type resolution happens at the provider call site, not in this interface.
|
|
17
|
+
*
|
|
18
|
+
* Generic parameters:
|
|
19
|
+
* - TModel: The specific model name (e.g., 'fal-ai/diffrhythm')
|
|
20
|
+
* - TProviderOptions: Provider-specific options (already resolved)
|
|
21
|
+
*/
|
|
22
|
+
export interface AudioAdapter<TModel extends string = string, TProviderOptions extends object = Record<string, unknown>> {
|
|
23
|
+
/** Discriminator for adapter kind - used to determine API shape */
|
|
24
|
+
readonly kind: 'audio';
|
|
25
|
+
/** Adapter name identifier */
|
|
26
|
+
readonly name: string;
|
|
27
|
+
/** The model this adapter is configured for */
|
|
28
|
+
readonly model: TModel;
|
|
29
|
+
/**
|
|
30
|
+
* @internal Type-only properties for inference. Not assigned at runtime.
|
|
31
|
+
*/
|
|
32
|
+
'~types': {
|
|
33
|
+
providerOptions: TProviderOptions;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Generate audio from a text prompt
|
|
37
|
+
*/
|
|
38
|
+
generateAudio: (options: AudioGenerationOptions<TProviderOptions>) => Promise<AudioGenerationResult>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* An AudioAdapter with any/unknown type parameters.
|
|
42
|
+
* Useful as a constraint in generic functions and interfaces.
|
|
43
|
+
*/
|
|
44
|
+
export type AnyAudioAdapter = AudioAdapter<any, any>;
|
|
45
|
+
/**
|
|
46
|
+
* Abstract base class for audio generation adapters.
|
|
47
|
+
* Extend this class to implement an audio adapter for a specific provider.
|
|
48
|
+
*
|
|
49
|
+
* Generic parameters match AudioAdapter - all pre-resolved by the provider function.
|
|
50
|
+
*/
|
|
51
|
+
export declare abstract class BaseAudioAdapter<TModel extends string = string, TProviderOptions extends object = Record<string, unknown>> implements AudioAdapter<TModel, TProviderOptions> {
|
|
52
|
+
readonly kind: "audio";
|
|
53
|
+
abstract readonly name: string;
|
|
54
|
+
readonly model: TModel;
|
|
55
|
+
'~types': {
|
|
56
|
+
providerOptions: TProviderOptions;
|
|
57
|
+
};
|
|
58
|
+
protected config: AudioAdapterConfig;
|
|
59
|
+
constructor(model: TModel, config?: AudioAdapterConfig);
|
|
60
|
+
abstract generateAudio(options: AudioGenerationOptions<TProviderOptions>): Promise<AudioGenerationResult>;
|
|
61
|
+
protected generateId(): string;
|
|
62
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class BaseAudioAdapter {
|
|
2
|
+
kind = "audio";
|
|
3
|
+
model;
|
|
4
|
+
config;
|
|
5
|
+
constructor(model, config = {}) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
this.model = model;
|
|
8
|
+
}
|
|
9
|
+
generateId() {
|
|
10
|
+
return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
BaseAudioAdapter
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sources":["../../../../src/activities/generateAudio/adapter.ts"],"sourcesContent":["import type { AudioGenerationOptions, AudioGenerationResult } from '../../types'\n\n/**\n * Configuration for audio generation adapter instances\n */\nexport interface AudioAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Audio generation adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'fal-ai/diffrhythm')\n * - TProviderOptions: Provider-specific options (already resolved)\n */\nexport interface AudioAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> {\n /** Discriminator for adapter kind - used to determine API shape */\n readonly kind: 'audio'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n }\n\n /**\n * Generate audio from a text prompt\n */\n generateAudio: (\n options: AudioGenerationOptions<TProviderOptions>,\n ) => Promise<AudioGenerationResult>\n}\n\n/**\n * An AudioAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyAudioAdapter = AudioAdapter<any, any>\n\n/**\n * Abstract base class for audio generation adapters.\n * Extend this class to implement an audio adapter for a specific provider.\n *\n * Generic parameters match AudioAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseAudioAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n> implements AudioAdapter<TModel, TProviderOptions> {\n readonly kind = 'audio' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n }\n\n protected config: AudioAdapterConfig\n\n constructor(model: TModel, config: AudioAdapterConfig = {}) {\n this.config = config\n this.model = model\n }\n\n abstract generateAudio(\n options: AudioGenerationOptions<TProviderOptions>,\n ): Promise<AudioGenerationResult>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"names":[],"mappings":"AA6DO,MAAe,iBAG8B;AAAA,EACzC,OAAO;AAAA,EAEP;AAAA,EAOC;AAAA,EAEV,YAAY,OAAe,SAA6B,IAAI;AAC1D,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAMU,aAAqB;AAC7B,WAAO,GAAG,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,UAAU,CAAC,CAAC;AAAA,EAC9E;AACF;"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { DebugOption } from '../../logger/types.js';
|
|
2
|
+
import { GenerationMiddleware } from '../middleware.js';
|
|
3
|
+
import { AudioAdapter } from './adapter.js';
|
|
4
|
+
import { AudioGenerationResult, StreamChunk } from '../../types.js';
|
|
5
|
+
/** The adapter kind this activity handles */
|
|
6
|
+
export declare const kind: "audio";
|
|
7
|
+
/**
|
|
8
|
+
* Extract provider options from an AudioAdapter via ~types.
|
|
9
|
+
*/
|
|
10
|
+
export type AudioProviderOptions<TAdapter> = TAdapter extends {
|
|
11
|
+
'~types': {
|
|
12
|
+
providerOptions: infer P extends object;
|
|
13
|
+
};
|
|
14
|
+
} ? P : object;
|
|
15
|
+
/**
|
|
16
|
+
* Options for the audio generation activity.
|
|
17
|
+
* The model is extracted from the adapter's model property.
|
|
18
|
+
*
|
|
19
|
+
* @template TAdapter - The audio adapter type
|
|
20
|
+
* @template TStream - Whether to stream the output
|
|
21
|
+
*/
|
|
22
|
+
export interface AudioActivityOptions<TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>, TStream extends boolean = false> {
|
|
23
|
+
/** The audio adapter to use (must be created with a model) */
|
|
24
|
+
adapter: TAdapter & {
|
|
25
|
+
kind: typeof kind;
|
|
26
|
+
};
|
|
27
|
+
/** Text description of the desired audio */
|
|
28
|
+
prompt: string;
|
|
29
|
+
/** Desired duration in seconds */
|
|
30
|
+
duration?: number;
|
|
31
|
+
/** Provider-specific options for audio generation */
|
|
32
|
+
modelOptions?: AudioProviderOptions<TAdapter>;
|
|
33
|
+
/**
|
|
34
|
+
* Whether to stream the generation result.
|
|
35
|
+
* When true, returns an AsyncIterable<StreamChunk> for streaming transport.
|
|
36
|
+
* When false or not provided, returns a Promise<AudioGenerationResult>.
|
|
37
|
+
*
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
stream?: TStream;
|
|
41
|
+
/**
|
|
42
|
+
* Enable debug logging. Pass `true` to enable all categories, `false` to
|
|
43
|
+
* silence everything including errors, or a `DebugConfig` object for granular
|
|
44
|
+
* control and/or a custom `Logger`.
|
|
45
|
+
*/
|
|
46
|
+
debug?: DebugOption;
|
|
47
|
+
/**
|
|
48
|
+
* Observe-only middleware notified on start, usage, success, and error. Pass
|
|
49
|
+
* `otelMiddleware()` to emit OpenTelemetry spans, or implement the
|
|
50
|
+
* `GenerationMiddleware` contract for a custom backend.
|
|
51
|
+
*/
|
|
52
|
+
middleware?: Array<GenerationMiddleware>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Result type for the audio generation activity.
|
|
56
|
+
* - If stream is true: AsyncIterable<StreamChunk>
|
|
57
|
+
* - Otherwise: Promise<AudioGenerationResult>
|
|
58
|
+
*/
|
|
59
|
+
export type AudioActivityResult<TStream extends boolean = false> = TStream extends true ? AsyncIterable<StreamChunk> : Promise<AudioGenerationResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Audio generation activity - generates audio from text prompts.
|
|
62
|
+
*
|
|
63
|
+
* Uses AI models to create music, sound effects, and other audio content.
|
|
64
|
+
*
|
|
65
|
+
* @example Generate music from a prompt
|
|
66
|
+
* ```ts
|
|
67
|
+
* import { generateAudio } from '@tanstack/ai'
|
|
68
|
+
* import { falAudio } from '@tanstack/ai-fal'
|
|
69
|
+
*
|
|
70
|
+
* const result = await generateAudio({
|
|
71
|
+
* adapter: falAudio('fal-ai/diffrhythm'),
|
|
72
|
+
* prompt: 'An upbeat electronic track with synths',
|
|
73
|
+
* duration: 10
|
|
74
|
+
* })
|
|
75
|
+
*
|
|
76
|
+
* console.log(result.audio.url) // URL to generated audio
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateAudio<TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>, TStream extends boolean = false>(options: AudioActivityOptions<TAdapter, TStream>): AudioActivityResult<TStream>;
|
|
80
|
+
/**
|
|
81
|
+
* Create typed options for the generateAudio() function without executing.
|
|
82
|
+
*/
|
|
83
|
+
export declare function createAudioOptions<TAdapter extends AudioAdapter<string, AudioProviderOptions<TAdapter>>, TStream extends boolean = false>(options: AudioActivityOptions<TAdapter, TStream>): AudioActivityOptions<TAdapter, TStream>;
|
|
84
|
+
export type { AudioAdapter, AudioAdapterConfig, AnyAudioAdapter, } from './adapter.js';
|
|
85
|
+
export { BaseAudioAdapter } from './adapter.js';
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { aiEventClient } from "@tanstack/ai-event-client";
|
|
2
|
+
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
3
|
+
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
4
|
+
import { createGenerationContext, runGenerationStart, runGenerationUsage, runGenerationFinish, runGenerationError } from "../middleware/run.js";
|
|
5
|
+
const kind = "audio";
|
|
6
|
+
function createId(prefix) {
|
|
7
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
8
|
+
}
|
|
9
|
+
function generateAudio(options) {
|
|
10
|
+
if (options.stream) {
|
|
11
|
+
return streamGenerationResult(
|
|
12
|
+
() => runGenerateAudio(options)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return runGenerateAudio(options);
|
|
16
|
+
}
|
|
17
|
+
async function runGenerateAudio(options) {
|
|
18
|
+
const {
|
|
19
|
+
adapter,
|
|
20
|
+
stream: _stream,
|
|
21
|
+
debug: _debug,
|
|
22
|
+
middleware,
|
|
23
|
+
...rest
|
|
24
|
+
} = options;
|
|
25
|
+
const model = adapter.model;
|
|
26
|
+
const requestId = createId("audio");
|
|
27
|
+
const startTime = Date.now();
|
|
28
|
+
const logger = resolveDebugOption(options.debug);
|
|
29
|
+
const providerName = adapter.provider ?? adapter.name ?? "unknown";
|
|
30
|
+
const mwCtx = createGenerationContext({
|
|
31
|
+
requestId,
|
|
32
|
+
activity: "audio",
|
|
33
|
+
provider: adapter.name,
|
|
34
|
+
model,
|
|
35
|
+
modelOptions: rest.modelOptions,
|
|
36
|
+
createId
|
|
37
|
+
});
|
|
38
|
+
await runGenerationStart(middleware, mwCtx);
|
|
39
|
+
aiEventClient.emit("audio:request:started", {
|
|
40
|
+
requestId,
|
|
41
|
+
provider: adapter.name,
|
|
42
|
+
model,
|
|
43
|
+
prompt: rest.prompt,
|
|
44
|
+
duration: rest.duration,
|
|
45
|
+
modelOptions: rest.modelOptions,
|
|
46
|
+
timestamp: startTime
|
|
47
|
+
});
|
|
48
|
+
logger.request(`activity=generateAudio provider=${providerName}`, {
|
|
49
|
+
provider: providerName,
|
|
50
|
+
model
|
|
51
|
+
});
|
|
52
|
+
try {
|
|
53
|
+
const result = await adapter.generateAudio({ ...rest, model, logger });
|
|
54
|
+
const elapsedMs = Date.now() - startTime;
|
|
55
|
+
aiEventClient.emit("audio:request:completed", {
|
|
56
|
+
requestId,
|
|
57
|
+
provider: adapter.name,
|
|
58
|
+
model,
|
|
59
|
+
audio: result.audio,
|
|
60
|
+
duration: elapsedMs,
|
|
61
|
+
modelOptions: rest.modelOptions,
|
|
62
|
+
timestamp: Date.now()
|
|
63
|
+
});
|
|
64
|
+
if (result.usage) {
|
|
65
|
+
aiEventClient.emit("audio:usage", {
|
|
66
|
+
requestId,
|
|
67
|
+
model,
|
|
68
|
+
usage: result.usage,
|
|
69
|
+
modelOptions: rest.modelOptions,
|
|
70
|
+
timestamp: Date.now()
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
logger.output(`activity=generateAudio provider=${providerName}`, {
|
|
74
|
+
contentType: result.audio.contentType,
|
|
75
|
+
audioDuration: result.audio.duration
|
|
76
|
+
});
|
|
77
|
+
if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage);
|
|
78
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
79
|
+
duration: elapsedMs,
|
|
80
|
+
usage: result.usage
|
|
81
|
+
});
|
|
82
|
+
return result;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const elapsedMs = Date.now() - startTime;
|
|
85
|
+
const err = error;
|
|
86
|
+
aiEventClient.emit("audio:request:error", {
|
|
87
|
+
requestId,
|
|
88
|
+
provider: adapter.name,
|
|
89
|
+
model,
|
|
90
|
+
error: { message: err.message, name: err.name },
|
|
91
|
+
duration: elapsedMs,
|
|
92
|
+
modelOptions: rest.modelOptions,
|
|
93
|
+
timestamp: Date.now()
|
|
94
|
+
});
|
|
95
|
+
await runGenerationError(middleware, mwCtx, {
|
|
96
|
+
error,
|
|
97
|
+
duration: elapsedMs
|
|
98
|
+
});
|
|
99
|
+
logger.errors("generateAudio activity failed", {
|
|
100
|
+
error,
|
|
101
|
+
source: "generateAudio"
|
|
102
|
+
});
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function createAudioOptions(options) {
|
|
107
|
+
return options;
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
createAudioOptions,
|
|
111
|
+
generateAudio,
|
|
112
|
+
kind
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=index.js.map
|