@tanstack/ai 0.2.2 → 0.3.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 (41) hide show
  1. package/README.md +1 -0
  2. package/dist/esm/activities/chat/index.js +206 -172
  3. package/dist/esm/activities/chat/index.js.map +1 -1
  4. package/dist/esm/activities/chat/stream/index.d.ts +1 -1
  5. package/dist/esm/activities/chat/stream/processor.d.ts +22 -43
  6. package/dist/esm/activities/chat/stream/processor.js +89 -156
  7. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  8. package/dist/esm/activities/chat/tools/tool-calls.d.ts +22 -21
  9. package/dist/esm/activities/chat/tools/tool-calls.js +40 -27
  10. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  11. package/dist/esm/activities/generateImage/index.js +41 -1
  12. package/dist/esm/activities/generateImage/index.js.map +1 -1
  13. package/dist/esm/activities/generateSpeech/index.js +33 -1
  14. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  15. package/dist/esm/activities/generateTranscription/index.js +29 -1
  16. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  17. package/dist/esm/activities/generateVideo/index.js +50 -0
  18. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  19. package/dist/esm/activities/summarize/index.js +9 -8
  20. package/dist/esm/activities/summarize/index.js.map +1 -1
  21. package/dist/esm/event-client.d.ts +378 -254
  22. package/dist/esm/event-client.js.map +1 -1
  23. package/dist/esm/index.d.ts +2 -2
  24. package/dist/esm/stream-to-response.d.ts +1 -1
  25. package/dist/esm/stream-to-response.js +5 -3
  26. package/dist/esm/stream-to-response.js.map +1 -1
  27. package/dist/esm/types.d.ts +162 -46
  28. package/package.json +1 -1
  29. package/src/activities/chat/index.ts +267 -191
  30. package/src/activities/chat/stream/index.ts +1 -5
  31. package/src/activities/chat/stream/processor.ts +128 -269
  32. package/src/activities/chat/tools/tool-calls.ts +55 -49
  33. package/src/activities/generateImage/index.ts +47 -2
  34. package/src/activities/generateSpeech/index.ts +37 -1
  35. package/src/activities/generateTranscription/index.ts +33 -1
  36. package/src/activities/generateVideo/index.ts +54 -0
  37. package/src/activities/summarize/index.ts +10 -9
  38. package/src/event-client.ts +460 -256
  39. package/src/index.ts +2 -3
  40. package/src/stream-to-response.ts +8 -6
  41. package/src/types.ts +209 -65
@@ -1,12 +1,12 @@
1
- import { DoneStreamChunk, ModelMessage, Tool, ToolCall, ToolResultStreamChunk } from '../../../types.js';
1
+ import { ModelMessage, RunFinishedEvent, Tool, ToolCall, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent } from '../../../types.js';
2
2
  /**
3
3
  * Manages tool call accumulation and execution for the chat() method's automatic tool execution loop.
4
4
  *
5
5
  * Responsibilities:
6
- * - Accumulates streaming tool call chunks (ID, name, arguments)
6
+ * - Accumulates streaming tool call events (ID, name, arguments)
7
7
  * - Validates tool calls (filters out incomplete ones)
8
8
  * - Executes tool `execute` functions with parsed arguments
9
- * - Emits `tool_result` chunks for client visibility
9
+ * - Emits `TOOL_CALL_END` events for client visibility
10
10
  * - Returns tool result messages for conversation history
11
11
  *
12
12
  * This class is used internally by the AI.chat() method to handle the automatic
@@ -18,14 +18,16 @@ import { DoneStreamChunk, ModelMessage, Tool, ToolCall, ToolResultStreamChunk }
18
18
  *
19
19
  * // During streaming, accumulate tool calls
20
20
  * for await (const chunk of stream) {
21
- * if (chunk.type === "tool_call") {
22
- * manager.addToolCallChunk(chunk);
21
+ * if (chunk.type === 'TOOL_CALL_START') {
22
+ * manager.addToolCallStartEvent(chunk);
23
+ * } else if (chunk.type === 'TOOL_CALL_ARGS') {
24
+ * manager.addToolCallArgsEvent(chunk);
23
25
  * }
24
26
  * }
25
27
  *
26
28
  * // After stream completes, execute tools
27
29
  * if (manager.hasToolCalls()) {
28
- * const toolResults = yield* manager.executeTools(doneChunk);
30
+ * const toolResults = yield* manager.executeTools(finishEvent);
29
31
  * messages = [...messages, ...toolResults];
30
32
  * manager.clear();
31
33
  * }
@@ -36,20 +38,18 @@ export declare class ToolCallManager {
36
38
  private tools;
37
39
  constructor(tools: ReadonlyArray<Tool>);
38
40
  /**
39
- * Add a tool call chunk to the accumulator
40
- * Handles streaming tool calls by accumulating arguments
41
+ * Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)
41
42
  */
42
- addToolCallChunk(chunk: {
43
- toolCall: {
44
- id: string;
45
- type: 'function';
46
- function: {
47
- name: string;
48
- arguments: string;
49
- };
50
- };
51
- index: number;
52
- }): void;
43
+ addToolCallStartEvent(event: ToolCallStartEvent): void;
44
+ /**
45
+ * Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)
46
+ */
47
+ addToolCallArgsEvent(event: ToolCallArgsEvent): void;
48
+ /**
49
+ * Complete a tool call with its final input
50
+ * Called when TOOL_CALL_END is received
51
+ */
52
+ completeToolCall(event: ToolCallEndEvent): void;
53
53
  /**
54
54
  * Check if there are any complete tool calls to execute
55
55
  */
@@ -60,9 +60,10 @@ export declare class ToolCallManager {
60
60
  getToolCalls(): Array<ToolCall>;
61
61
  /**
62
62
  * Execute all tool calls and return tool result messages
63
- * Also yields tool_result chunks for streaming
63
+ * Yields TOOL_CALL_END events for streaming
64
+ * @param finishEvent - RUN_FINISHED event from the stream
64
65
  */
65
- executeTools(doneChunk: DoneStreamChunk): AsyncGenerator<ToolResultStreamChunk, Array<ModelMessage>, void>;
66
+ executeTools(finishEvent: RunFinishedEvent): AsyncGenerator<ToolCallEndEvent, Array<ModelMessage>, void>;
66
67
  /**
67
68
  * Clear the tool calls map for the next iteration
68
69
  */
@@ -5,29 +5,41 @@ class ToolCallManager {
5
5
  this.tools = tools;
6
6
  }
7
7
  /**
8
- * Add a tool call chunk to the accumulator
9
- * Handles streaming tool calls by accumulating arguments
8
+ * Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)
10
9
  */
11
- addToolCallChunk(chunk) {
12
- const index = chunk.index;
13
- const existing = this.toolCallsMap.get(index);
14
- if (!existing) {
15
- if (chunk.toolCall.id && chunk.toolCall.function.name) {
16
- this.toolCallsMap.set(index, {
17
- id: chunk.toolCall.id,
18
- type: "function",
19
- function: {
20
- name: chunk.toolCall.function.name,
21
- arguments: chunk.toolCall.function.arguments || ""
22
- }
23
- });
10
+ addToolCallStartEvent(event) {
11
+ const index = event.index ?? this.toolCallsMap.size;
12
+ this.toolCallsMap.set(index, {
13
+ id: event.toolCallId,
14
+ type: "function",
15
+ function: {
16
+ name: event.toolName,
17
+ arguments: ""
24
18
  }
25
- } else {
26
- if (chunk.toolCall.function.name && !existing.function.name) {
27
- existing.function.name = chunk.toolCall.function.name;
19
+ });
20
+ }
21
+ /**
22
+ * Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)
23
+ */
24
+ addToolCallArgsEvent(event) {
25
+ for (const [, toolCall] of this.toolCallsMap.entries()) {
26
+ if (toolCall.id === event.toolCallId) {
27
+ toolCall.function.arguments += event.delta;
28
+ break;
28
29
  }
29
- if (chunk.toolCall.function.arguments) {
30
- existing.function.arguments += chunk.toolCall.function.arguments;
30
+ }
31
+ }
32
+ /**
33
+ * Complete a tool call with its final input
34
+ * Called when TOOL_CALL_END is received
35
+ */
36
+ completeToolCall(event) {
37
+ for (const [, toolCall] of this.toolCallsMap.entries()) {
38
+ if (toolCall.id === event.toolCallId) {
39
+ if (event.input !== void 0) {
40
+ toolCall.function.arguments = JSON.stringify(event.input);
41
+ }
42
+ break;
31
43
  }
32
44
  }
33
45
  }
@@ -47,9 +59,10 @@ class ToolCallManager {
47
59
  }
48
60
  /**
49
61
  * Execute all tool calls and return tool result messages
50
- * Also yields tool_result chunks for streaming
62
+ * Yields TOOL_CALL_END events for streaming
63
+ * @param finishEvent - RUN_FINISHED event from the stream
51
64
  */
52
- async *executeTools(doneChunk) {
65
+ async *executeTools(finishEvent) {
53
66
  const toolCallsArray = this.getToolCalls();
54
67
  const toolResults = [];
55
68
  for (const toolCall of toolCallsArray) {
@@ -95,12 +108,12 @@ class ToolCallManager {
95
108
  toolResultContent = `Tool ${toolCall.function.name} does not have an execute function`;
96
109
  }
97
110
  yield {
98
- type: "tool_result",
99
- id: doneChunk.id,
100
- model: doneChunk.model,
101
- timestamp: Date.now(),
111
+ type: "TOOL_CALL_END",
102
112
  toolCallId: toolCall.id,
103
- content: toolResultContent
113
+ toolName: toolCall.function.name,
114
+ model: finishEvent.model,
115
+ timestamp: Date.now(),
116
+ result: toolResultContent
104
117
  };
105
118
  toolResults.push({
106
119
  role: "tool",
@@ -1 +1 @@
1
- {"version":3,"file":"tool-calls.js","sources":["../../../../../src/activities/chat/tools/tool-calls.ts"],"sourcesContent":["import { isStandardSchema, parseWithStandardSchema } from './schema-converter'\nimport type {\n DoneStreamChunk,\n ModelMessage,\n Tool,\n ToolCall,\n ToolResultStreamChunk,\n} from '../../../types'\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 chunks (ID, name, arguments)\n * - Validates tool calls (filters out incomplete ones)\n * - Executes tool `execute` functions with parsed arguments\n * - Emits `tool_result` chunks 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\") {\n * manager.addToolCallChunk(chunk);\n * }\n * }\n *\n * // After stream completes, execute tools\n * if (manager.hasToolCalls()) {\n * const toolResults = yield* manager.executeTools(doneChunk);\n * messages = [...messages, ...toolResults];\n * manager.clear();\n * }\n * ```\n */\nexport class ToolCallManager {\n private toolCallsMap = new Map<number, ToolCall>()\n private tools: ReadonlyArray<Tool>\n\n constructor(tools: ReadonlyArray<Tool>) {\n this.tools = tools\n }\n\n /**\n * Add a tool call chunk to the accumulator\n * Handles streaming tool calls by accumulating arguments\n */\n addToolCallChunk(chunk: {\n toolCall: {\n id: string\n type: 'function'\n function: {\n name: string\n arguments: string\n }\n }\n index: number\n }): void {\n const index = chunk.index\n const existing = this.toolCallsMap.get(index)\n\n if (!existing) {\n // Only create entry if we have a tool call ID and name\n if (chunk.toolCall.id && chunk.toolCall.function.name) {\n this.toolCallsMap.set(index, {\n id: chunk.toolCall.id,\n type: 'function',\n function: {\n name: chunk.toolCall.function.name,\n arguments: chunk.toolCall.function.arguments || '',\n },\n })\n }\n } else {\n // Update name if it wasn't set before\n if (chunk.toolCall.function.name && !existing.function.name) {\n existing.function.name = chunk.toolCall.function.name\n }\n // Accumulate arguments for streaming tool calls\n if (chunk.toolCall.function.arguments) {\n existing.function.arguments += chunk.toolCall.function.arguments\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 * Also yields tool_result chunks for streaming\n */\n async *executeTools(\n doneChunk: DoneStreamChunk,\n ): AsyncGenerator<ToolResultStreamChunk, Array<ModelMessage>, void> {\n const toolCallsArray = this.getToolCalls()\n const toolResults: Array<ModelMessage> = []\n\n for (const toolCall of toolCallsArray) {\n const tool = this.tools.find((t) => t.name === toolCall.function.name)\n\n let toolResultContent: string\n if (tool?.execute) {\n try {\n // Parse arguments\n let args: unknown\n try {\n args = JSON.parse(toolCall.function.arguments)\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 let result = await tool.execute(args)\n\n // Validate output against outputSchema if provided (for Standard Schema compliant schemas)\n if (\n tool.outputSchema &&\n isStandardSchema(tool.outputSchema) &&\n result !== undefined &&\n result !== null\n ) {\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 =\n typeof result === 'string' ? result : JSON.stringify(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 }\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_result chunk so callers can track tool execution\n yield {\n type: 'tool_result',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: toolCall.id,\n content: toolResultContent,\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\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 * Execute tool calls based on their configuration\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 */\nexport async function executeToolCalls(\n toolCalls: Array<ToolCall>,\n tools: ReadonlyArray<Tool>,\n approvals: Map<string, boolean> = new Map(),\n clientResults: Map<string, any> = new Map(),\n): Promise<ExecuteToolCallsResult> {\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, Tool>()\n for (const tool of tools) {\n toolMap.set(tool.name, tool)\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 // Parse arguments, throwing error if invalid JSON\n let input: unknown = {}\n const argsStr = toolCall.function.arguments.trim() || '{}'\n if (argsStr) {\n try {\n input = JSON.parse(argsStr)\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 // 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 toolCallId: toolCall.id,\n toolName,\n result: clientResults.get(toolCall.id),\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 toolCallId: toolCall.id,\n toolName,\n result: clientResults.get(toolCall.id),\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 // Execute after approval\n const startTime = Date.now()\n try {\n let result = await tool.execute(input)\n const duration = Date.now() - startTime\n\n // Validate output against outputSchema if provided (for Standard Schema compliant schemas)\n if (\n tool.outputSchema &&\n isStandardSchema(tool.outputSchema) &&\n result !== undefined &&\n result !== null\n ) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n typeof result === 'string'\n ? JSON.parse(result)\n : result || null,\n duration,\n })\n } catch (error: unknown) {\n const duration = Date.now() - startTime\n const message =\n 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 } 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 const startTime = Date.now()\n try {\n let result = await tool.execute(input)\n const duration = Date.now() - startTime\n\n // Validate output against outputSchema if provided (for Standard Schema compliant schemas)\n if (\n tool.outputSchema &&\n isStandardSchema(tool.outputSchema) &&\n result !== undefined &&\n result !== null\n ) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n typeof result === 'string' ? JSON.parse(result) : result || null,\n duration,\n })\n } catch (error: unknown) {\n const duration = Date.now() - startTime\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 }\n\n return { results, needsApproval, needsClientExecution }\n}\n"],"names":["startTime"],"mappings":"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"}
1
+ {"version":3,"file":"tool-calls.js","sources":["../../../../../src/activities/chat/tools/tool-calls.ts"],"sourcesContent":["import { isStandardSchema, parseWithStandardSchema } from './schema-converter'\nimport type {\n ModelMessage,\n RunFinishedEvent,\n Tool,\n ToolCall,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n} from '../../../types'\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 private toolCallsMap = new Map<number, ToolCall>()\n private tools: ReadonlyArray<Tool>\n\n constructor(tools: ReadonlyArray<Tool>) {\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 this.toolCallsMap.set(index, {\n id: event.toolCallId,\n type: 'function',\n function: {\n name: event.toolName,\n arguments: '',\n },\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 toolCall.function.arguments = JSON.stringify(event.input)\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 ): AsyncGenerator<ToolCallEndEvent, Array<ModelMessage>, void> {\n const toolCallsArray = this.getToolCalls()\n const toolResults: Array<ModelMessage> = []\n\n for (const toolCall of toolCallsArray) {\n const tool = this.tools.find((t) => t.name === toolCall.function.name)\n\n let toolResultContent: string\n if (tool?.execute) {\n try {\n // Parse arguments\n let args: unknown\n try {\n args = JSON.parse(toolCall.function.arguments)\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 let result = await tool.execute(args)\n\n // Validate output against outputSchema if provided (for Standard Schema compliant schemas)\n if (\n tool.outputSchema &&\n isStandardSchema(tool.outputSchema) &&\n result !== undefined &&\n result !== null\n ) {\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 =\n typeof result === 'string' ? result : JSON.stringify(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 }\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 toolName: toolCall.function.name,\n model: finishEvent.model,\n timestamp: Date.now(),\n result: toolResultContent,\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\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 * Execute tool calls based on their configuration\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 */\nexport async function executeToolCalls(\n toolCalls: Array<ToolCall>,\n tools: ReadonlyArray<Tool>,\n approvals: Map<string, boolean> = new Map(),\n clientResults: Map<string, any> = new Map(),\n): Promise<ExecuteToolCallsResult> {\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, Tool>()\n for (const tool of tools) {\n toolMap.set(tool.name, tool)\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 // Parse arguments, throwing error if invalid JSON\n let input: unknown = {}\n const argsStr = toolCall.function.arguments.trim() || '{}'\n if (argsStr) {\n try {\n input = JSON.parse(argsStr)\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 // 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 toolCallId: toolCall.id,\n toolName,\n result: clientResults.get(toolCall.id),\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 toolCallId: toolCall.id,\n toolName,\n result: clientResults.get(toolCall.id),\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 // Execute after approval\n const startTime = Date.now()\n try {\n let result = await tool.execute(input)\n const duration = Date.now() - startTime\n\n // Validate output against outputSchema if provided (for Standard Schema compliant schemas)\n if (\n tool.outputSchema &&\n isStandardSchema(tool.outputSchema) &&\n result !== undefined &&\n result !== null\n ) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n typeof result === 'string'\n ? JSON.parse(result)\n : result || null,\n duration,\n })\n } catch (error: unknown) {\n const duration = Date.now() - startTime\n const message =\n 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 } 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 const startTime = Date.now()\n try {\n let result = await tool.execute(input)\n const duration = Date.now() - startTime\n\n // Validate output against outputSchema if provided (for Standard Schema compliant schemas)\n if (\n tool.outputSchema &&\n isStandardSchema(tool.outputSchema) &&\n result !== undefined &&\n result !== null\n ) {\n result = parseWithStandardSchema(tool.outputSchema, result)\n }\n\n results.push({\n toolCallId: toolCall.id,\n toolName,\n result:\n typeof result === 'string' ? JSON.parse(result) : result || null,\n duration,\n })\n } catch (error: unknown) {\n const duration = Date.now() - startTime\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 }\n\n return { results, needsApproval, needsClientExecution }\n}\n"],"names":["startTime"],"mappings":"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"}
@@ -1,8 +1,48 @@
1
+ import { aiEventClient } from "../../event-client.js";
1
2
  const kind = "image";
3
+ function createId(prefix) {
4
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5
+ }
2
6
  async function generateImage(options) {
3
7
  const { adapter, ...rest } = options;
4
8
  const model = adapter.model;
5
- return adapter.generateImages({ ...rest, model });
9
+ const requestId = createId("image");
10
+ const startTime = Date.now();
11
+ aiEventClient.emit("image:request:started", {
12
+ requestId,
13
+ provider: adapter.name,
14
+ model,
15
+ prompt: rest.prompt,
16
+ numberOfImages: rest.numberOfImages,
17
+ size: rest.size,
18
+ modelOptions: rest.modelOptions,
19
+ timestamp: startTime
20
+ });
21
+ return adapter.generateImages({ ...rest, model }).then((result) => {
22
+ const duration = Date.now() - startTime;
23
+ aiEventClient.emit("image:request:completed", {
24
+ requestId,
25
+ provider: adapter.name,
26
+ model,
27
+ images: result.images.map((image) => ({
28
+ url: image.url,
29
+ b64Json: image.b64Json
30
+ })),
31
+ duration,
32
+ modelOptions: rest.modelOptions,
33
+ timestamp: Date.now()
34
+ });
35
+ if (result.usage) {
36
+ aiEventClient.emit("image:usage", {
37
+ requestId,
38
+ model,
39
+ usage: result.usage,
40
+ modelOptions: rest.modelOptions,
41
+ timestamp: Date.now()
42
+ });
43
+ }
44
+ return result;
45
+ });
6
46
  }
7
47
  function createImageOptions(options) {
8
48
  return options;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/activities/generateImage/index.ts"],"sourcesContent":["/**\n * Image Activity\n *\n * Generates images from text prompts.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport type { ImageAdapter } from './adapter'\nimport type { ImageGenerationResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'image' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract model-specific provider options from an ImageAdapter via ~types.\n * If the model has specific options defined in ModelProviderOptions (and not just via index signature),\n * use those; otherwise fall back to base provider options.\n */\nexport type ImageProviderOptionsForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, infer BaseOptions, infer ModelOptions, any>\n ? string extends keyof ModelOptions\n ? // ModelOptions is Record<string, unknown> or has index signature - use BaseOptions\n BaseOptions\n : // ModelOptions has explicit keys - check if TModel is one of them\n TModel extends keyof ModelOptions\n ? ModelOptions[TModel]\n : BaseOptions\n : object\n\n/**\n * Extract model-specific size options from an ImageAdapter via ~types.\n * If the model has specific sizes defined, use those; otherwise fall back to string.\n */\nexport type ImageSizeForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, infer SizeByName>\n ? string extends keyof SizeByName\n ? // SizeByName has index signature - fall back to string\n string\n : // SizeByName has explicit keys - check if TModel is one of them\n TModel extends keyof SizeByName\n ? SizeByName[TModel]\n : string\n : string\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the image activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The image adapter type\n */\nexport interface ImageActivityOptions<\n TAdapter extends ImageAdapter<string, object, any, any>,\n> {\n /** The image adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** Text description of the desired image(s) */\n prompt: string\n /** Number of images to generate (default: 1) */\n numberOfImages?: number\n /** Image size in WIDTHxHEIGHT format (e.g., \"1024x1024\") */\n size?: ImageSizeForModel<TAdapter, TAdapter['model']>\n /** Provider-specific options for image generation */\n modelOptions?: ImageProviderOptionsForModel<TAdapter, TAdapter['model']>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/** Result type for the image activity */\nexport type ImageActivityResult = Promise<ImageGenerationResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Image activity - generates images from text prompts.\n *\n * Uses AI image generation models to create images based on natural language descriptions.\n *\n * @example Generate a single image\n * ```ts\n * import { generateImage } from '@tanstack/ai'\n * import { openaiImage } from '@tanstack/ai-openai'\n *\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A serene mountain landscape at sunset'\n * })\n *\n * console.log(result.images[0].url)\n * ```\n *\n * @example Generate multiple images\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-2'),\n * prompt: 'A cute robot mascot',\n * numberOfImages: 4,\n * size: '512x512'\n * })\n *\n * result.images.forEach((image, i) => {\n * console.log(`Image ${i + 1}: ${image.url}`)\n * })\n * ```\n *\n * @example With provider-specific options\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A professional headshot photo',\n * size: '1024x1024',\n * modelOptions: {\n * quality: 'hd',\n * style: 'natural'\n * }\n * })\n * ```\n */\nexport async function generateImage<\n TAdapter extends ImageAdapter<string, object, any, any>,\n>(options: ImageActivityOptions<TAdapter>): ImageActivityResult {\n const { adapter, ...rest } = options\n const model = adapter.model\n\n return adapter.generateImages({ ...rest, model })\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateImage() function without executing.\n */\nexport function createImageOptions<\n TAdapter extends ImageAdapter<string, object, any, any>,\n>(options: ImageActivityOptions<TAdapter>): ImageActivityOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n ImageAdapter,\n ImageAdapterConfig,\n AnyImageAdapter,\n} from './adapter'\nexport { BaseImageAdapter } from './adapter'\n"],"names":[],"mappings":"AAeO,MAAM,OAAO;AAsHpB,eAAsB,cAEpB,SAA8D;AAC9D,QAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,QAAM,QAAQ,QAAQ;AAEtB,SAAO,QAAQ,eAAe,EAAE,GAAG,MAAM,OAAO;AAClD;AASO,SAAS,mBAEd,SAAyE;AACzE,SAAO;AACT;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/activities/generateImage/index.ts"],"sourcesContent":["/**\n * Image Activity\n *\n * Generates images from text prompts.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '../../event-client.js'\nimport type { ImageAdapter } from './adapter'\nimport type { ImageGenerationResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'image' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract model-specific provider options from an ImageAdapter via ~types.\n * If the model has specific options defined in ModelProviderOptions (and not just via index signature),\n * use those; otherwise fall back to base provider options.\n */\nexport type ImageProviderOptionsForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, infer BaseOptions, infer ModelOptions, any>\n ? string extends keyof ModelOptions\n ? // ModelOptions is Record<string, unknown> or has index signature - use BaseOptions\n BaseOptions\n : // ModelOptions has explicit keys - check if TModel is one of them\n TModel extends keyof ModelOptions\n ? ModelOptions[TModel]\n : BaseOptions\n : object\n\n/**\n * Extract model-specific size options from an ImageAdapter via ~types.\n * If the model has specific sizes defined, use those; otherwise fall back to string.\n */\nexport type ImageSizeForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, infer SizeByName>\n ? string extends keyof SizeByName\n ? // SizeByName has index signature - fall back to string\n string\n : // SizeByName has explicit keys - check if TModel is one of them\n TModel extends keyof SizeByName\n ? SizeByName[TModel]\n : string\n : string\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the image activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The image adapter type\n */\nexport interface ImageActivityOptions<\n TAdapter extends ImageAdapter<string, object, any, any>,\n> {\n /** The image adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** Text description of the desired image(s) */\n prompt: string\n /** Number of images to generate (default: 1) */\n numberOfImages?: number\n /** Image size in WIDTHxHEIGHT format (e.g., \"1024x1024\") */\n size?: ImageSizeForModel<TAdapter, TAdapter['model']>\n /** Provider-specific options for image generation */\n modelOptions?: ImageProviderOptionsForModel<TAdapter, TAdapter['model']>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/** Result type for the image activity */\nexport type ImageActivityResult = Promise<ImageGenerationResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Image activity - generates images from text prompts.\n *\n * Uses AI image generation models to create images based on natural language descriptions.\n *\n * @example Generate a single image\n * ```ts\n * import { generateImage } from '@tanstack/ai'\n * import { openaiImage } from '@tanstack/ai-openai'\n *\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A serene mountain landscape at sunset'\n * })\n *\n * console.log(result.images[0].url)\n * ```\n *\n * @example Generate multiple images\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-2'),\n * prompt: 'A cute robot mascot',\n * numberOfImages: 4,\n * size: '512x512'\n * })\n *\n * result.images.forEach((image, i) => {\n * console.log(`Image ${i + 1}: ${image.url}`)\n * })\n * ```\n *\n * @example With provider-specific options\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A professional headshot photo',\n * size: '1024x1024',\n * modelOptions: {\n * quality: 'hd',\n * style: 'natural'\n * }\n * })\n * ```\n */\nexport async function generateImage<\n TAdapter extends ImageAdapter<string, object, any, any>,\n>(options: ImageActivityOptions<TAdapter>): ImageActivityResult {\n const { adapter, ...rest } = options\n const model = adapter.model\n const requestId = createId('image')\n const startTime = Date.now()\n\n aiEventClient.emit('image:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: rest.prompt,\n numberOfImages: rest.numberOfImages,\n size: rest.size as string | undefined,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n return adapter.generateImages({ ...rest, model }).then((result) => {\n const duration = Date.now() - startTime\n\n aiEventClient.emit('image:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n images: result.images.map((image) => ({\n url: image.url,\n b64Json: image.b64Json,\n })),\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('image:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n }\n\n return result\n })\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateImage() function without executing.\n */\nexport function createImageOptions<\n TAdapter extends ImageAdapter<string, object, any, any>,\n>(options: ImageActivityOptions<TAdapter>): ImageActivityOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n ImageAdapter,\n ImageAdapterConfig,\n AnyImageAdapter,\n} from './adapter'\nexport { BaseImageAdapter } from './adapter'\n"],"names":[],"mappings":";AAgBO,MAAM,OAAO;AAqEpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAmDA,eAAsB,cAEpB,SAA8D;AAC9D,QAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,QAAM,QAAQ,QAAQ;AACtB,QAAM,YAAY,SAAS,OAAO;AAClC,QAAM,YAAY,KAAK,IAAA;AAEvB,gBAAc,KAAK,yBAAyB;AAAA,IAC1C;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,gBAAgB,KAAK;AAAA,IACrB,MAAM,KAAK;AAAA,IACX,cAAc,KAAK;AAAA,IACnB,WAAW;AAAA,EAAA,CACZ;AAED,SAAO,QAAQ,eAAe,EAAE,GAAG,MAAM,OAAO,EAAE,KAAK,CAAC,WAAW;AACjE,UAAM,WAAW,KAAK,IAAA,IAAQ;AAE9B,kBAAc,KAAK,2BAA2B;AAAA,MAC5C;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA,QAAQ,OAAO,OAAO,IAAI,CAAC,WAAW;AAAA,QACpC,KAAK,MAAM;AAAA,QACX,SAAS,MAAM;AAAA,MAAA,EACf;AAAA,MACF;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAED,QAAI,OAAO,OAAO;AAChB,oBAAc,KAAK,eAAe;AAAA,QAChC;AAAA,QACA;AAAA,QACA,OAAO,OAAO;AAAA,QACd,cAAc,KAAK;AAAA,QACnB,WAAW,KAAK,IAAA;AAAA,MAAI,CACrB;AAAA,IACH;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AASO,SAAS,mBAEd,SAAyE;AACzE,SAAO;AACT;"}
@@ -1,8 +1,40 @@
1
+ import { aiEventClient } from "../../event-client.js";
1
2
  const kind = "tts";
3
+ function createId(prefix) {
4
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5
+ }
2
6
  async function generateSpeech(options) {
3
7
  const { adapter, ...rest } = options;
4
8
  const model = adapter.model;
5
- return adapter.generateSpeech({ ...rest, model });
9
+ const requestId = createId("speech");
10
+ const startTime = Date.now();
11
+ aiEventClient.emit("speech:request:started", {
12
+ requestId,
13
+ provider: adapter.name,
14
+ model,
15
+ text: rest.text,
16
+ voice: rest.voice,
17
+ format: rest.format,
18
+ speed: rest.speed,
19
+ modelOptions: rest.modelOptions,
20
+ timestamp: startTime
21
+ });
22
+ return adapter.generateSpeech({ ...rest, model }).then((result) => {
23
+ const duration = Date.now() - startTime;
24
+ aiEventClient.emit("speech:request:completed", {
25
+ requestId,
26
+ provider: adapter.name,
27
+ model,
28
+ audio: result.audio,
29
+ format: result.format,
30
+ audioDuration: result.duration,
31
+ contentType: result.contentType,
32
+ duration,
33
+ modelOptions: rest.modelOptions,
34
+ timestamp: Date.now()
35
+ });
36
+ return result;
37
+ });
6
38
  }
7
39
  function createSpeechOptions(options) {
8
40
  return options;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/activities/generateSpeech/index.ts"],"sourcesContent":["/**\n * TTS Activity\n *\n * Generates speech audio from text using text-to-speech models.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport type { TTSAdapter } from './adapter'\nimport type { TTSResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'tts' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TTSAdapter via ~types.\n */\nexport type TTSProviderOptions<TAdapter> =\n TAdapter extends TTSAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the TTS activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The TTS adapter type\n */\nexport interface TTSActivityOptions<\n TAdapter extends TTSAdapter<string, object>,\n> {\n /** The TTS adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The text to convert to speech */\n text: string\n /** The voice to use for generation */\n voice?: string\n /** The output audio format */\n format?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm'\n /** The speed of the generated audio (0.25 to 4.0) */\n speed?: number\n /** Provider-specific options for TTS generation */\n modelOptions?: TTSProviderOptions<TAdapter>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/** Result type for the TTS activity */\nexport type TTSActivityResult = Promise<TTSResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * TTS activity - generates speech from text.\n *\n * Uses AI text-to-speech models to create audio from natural language text.\n *\n * @example Generate speech from text\n * ```ts\n * import { generateSpeech } from '@tanstack/ai'\n * import { openaiTTS } from '@tanstack/ai-openai'\n *\n * const result = await generateSpeech({\n * adapter: openaiTTS('tts-1-hd'),\n * text: 'Hello, welcome to TanStack AI!',\n * voice: 'nova'\n * })\n *\n * console.log(result.audio) // base64-encoded audio\n * ```\n *\n * @example With format and speed options\n * ```ts\n * const result = await generateSpeech({\n * adapter: openaiTTS('tts-1'),\n * text: 'This is slower speech.',\n * voice: 'alloy',\n * format: 'wav',\n * speed: 0.8\n * })\n * ```\n */\nexport async function generateSpeech<\n TAdapter extends TTSAdapter<string, object>,\n>(options: TTSActivityOptions<TAdapter>): TTSActivityResult {\n const { adapter, ...rest } = options\n const model = adapter.model\n\n return adapter.generateSpeech({ ...rest, model })\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateSpeech() function without executing.\n */\nexport function createSpeechOptions<\n TAdapter extends TTSAdapter<string, object>,\n>(options: TTSActivityOptions<TAdapter>): TTSActivityOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type { TTSAdapter, TTSAdapterConfig, AnyTTSAdapter } from './adapter'\nexport { BaseTTSAdapter } from './adapter'\n"],"names":[],"mappings":"AAeO,MAAM,OAAO;AAkFpB,eAAsB,eAEpB,SAA0D;AAC1D,QAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,QAAM,QAAQ,QAAQ;AAEtB,SAAO,QAAQ,eAAe,EAAE,GAAG,MAAM,OAAO;AAClD;AASO,SAAS,oBAEd,SAAqE;AACrE,SAAO;AACT;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/activities/generateSpeech/index.ts"],"sourcesContent":["/**\n * TTS Activity\n *\n * Generates speech audio from text using text-to-speech models.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '../../event-client.js'\nimport type { TTSAdapter } from './adapter'\nimport type { TTSResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'tts' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TTSAdapter via ~types.\n */\nexport type TTSProviderOptions<TAdapter> =\n TAdapter extends TTSAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the TTS activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The TTS adapter type\n */\nexport interface TTSActivityOptions<\n TAdapter extends TTSAdapter<string, object>,\n> {\n /** The TTS adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The text to convert to speech */\n text: string\n /** The voice to use for generation */\n voice?: string\n /** The output audio format */\n format?: 'mp3' | 'opus' | 'aac' | 'flac' | 'wav' | 'pcm'\n /** The speed of the generated audio (0.25 to 4.0) */\n speed?: number\n /** Provider-specific options for TTS generation */\n modelOptions?: TTSProviderOptions<TAdapter>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/** Result type for the TTS activity */\nexport type TTSActivityResult = Promise<TTSResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * TTS activity - generates speech from text.\n *\n * Uses AI text-to-speech models to create audio from natural language text.\n *\n * @example Generate speech from text\n * ```ts\n * import { generateSpeech } from '@tanstack/ai'\n * import { openaiTTS } from '@tanstack/ai-openai'\n *\n * const result = await generateSpeech({\n * adapter: openaiTTS('tts-1-hd'),\n * text: 'Hello, welcome to TanStack AI!',\n * voice: 'nova'\n * })\n *\n * console.log(result.audio) // base64-encoded audio\n * ```\n *\n * @example With format and speed options\n * ```ts\n * const result = await generateSpeech({\n * adapter: openaiTTS('tts-1'),\n * text: 'This is slower speech.',\n * voice: 'alloy',\n * format: 'wav',\n * speed: 0.8\n * })\n * ```\n */\nexport async function generateSpeech<\n TAdapter extends TTSAdapter<string, object>,\n>(options: TTSActivityOptions<TAdapter>): TTSActivityResult {\n const { adapter, ...rest } = options\n const model = adapter.model\n const requestId = createId('speech')\n const startTime = Date.now()\n\n aiEventClient.emit('speech:request:started', {\n requestId,\n provider: adapter.name,\n model,\n text: rest.text,\n voice: rest.voice,\n format: rest.format,\n speed: rest.speed,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n return adapter.generateSpeech({ ...rest, model }).then((result) => {\n const duration = Date.now() - startTime\n\n aiEventClient.emit('speech:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n audio: result.audio,\n format: result.format,\n audioDuration: result.duration,\n contentType: result.contentType,\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n return result\n })\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateSpeech() function without executing.\n */\nexport function createSpeechOptions<\n TAdapter extends TTSAdapter<string, object>,\n>(options: TTSActivityOptions<TAdapter>): TTSActivityOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type { TTSAdapter, TTSAdapterConfig, AnyTTSAdapter } from './adapter'\nexport { BaseTTSAdapter } from './adapter'\n"],"names":[],"mappings":";AAgBO,MAAM,OAAO;AAgDpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAoCA,eAAsB,eAEpB,SAA0D;AAC1D,QAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,QAAM,QAAQ,QAAQ;AACtB,QAAM,YAAY,SAAS,QAAQ;AACnC,QAAM,YAAY,KAAK,IAAA;AAEvB,gBAAc,KAAK,0BAA0B;AAAA,IAC3C;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,IACZ,cAAc,KAAK;AAAA,IACnB,WAAW;AAAA,EAAA,CACZ;AAED,SAAO,QAAQ,eAAe,EAAE,GAAG,MAAM,OAAO,EAAE,KAAK,CAAC,WAAW;AACjE,UAAM,WAAW,KAAK,IAAA,IAAQ;AAE9B,kBAAc,KAAK,4BAA4B;AAAA,MAC7C;AAAA,MACA,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,eAAe,OAAO;AAAA,MACtB,aAAa,OAAO;AAAA,MACpB;AAAA,MACA,cAAc,KAAK;AAAA,MACnB,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAED,WAAO;AAAA,EACT,CAAC;AACH;AASO,SAAS,oBAEd,SAAqE;AACrE,SAAO;AACT;"}
@@ -1,8 +1,36 @@
1
+ import { aiEventClient } from "../../event-client.js";
1
2
  const kind = "transcription";
3
+ function createId(prefix) {
4
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5
+ }
2
6
  async function generateTranscription(options) {
3
7
  const { adapter, ...rest } = options;
4
8
  const model = adapter.model;
5
- return adapter.transcribe({ ...rest, model });
9
+ const requestId = createId("transcription");
10
+ const startTime = Date.now();
11
+ aiEventClient.emit("transcription:request:started", {
12
+ requestId,
13
+ provider: adapter.name,
14
+ model,
15
+ language: rest.language,
16
+ prompt: rest.prompt,
17
+ responseFormat: rest.responseFormat,
18
+ modelOptions: rest.modelOptions,
19
+ timestamp: startTime
20
+ });
21
+ const result = await adapter.transcribe({ ...rest, model });
22
+ const duration = Date.now() - startTime;
23
+ aiEventClient.emit("transcription:request:completed", {
24
+ requestId,
25
+ provider: adapter.name,
26
+ model,
27
+ text: result.text,
28
+ language: result.language,
29
+ duration,
30
+ modelOptions: rest.modelOptions,
31
+ timestamp: Date.now()
32
+ });
33
+ return result;
6
34
  }
7
35
  function createTranscriptionOptions(options) {
8
36
  return options;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/activities/generateTranscription/index.ts"],"sourcesContent":["/**\n * Transcription Activity\n *\n * Transcribes audio to text using speech-to-text models.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport type { TranscriptionAdapter } from './adapter'\nimport type { TranscriptionResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'transcription' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TranscriptionAdapter via ~types.\n */\nexport type TranscriptionProviderOptions<TAdapter> =\n TAdapter extends TranscriptionAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the transcription activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The transcription adapter type\n */\nexport interface TranscriptionActivityOptions<\n TAdapter extends TranscriptionAdapter<string, object>,\n> {\n /** The transcription adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The audio data to transcribe - can be base64 string, File, Blob, or Buffer */\n audio: string | File | Blob | ArrayBuffer\n /** The language of the audio in ISO-639-1 format (e.g., 'en') */\n language?: string\n /** An optional prompt to guide the transcription */\n prompt?: string\n /** The format of the transcription output */\n responseFormat?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt'\n /** Provider-specific options for transcription */\n modelOptions?: TranscriptionProviderOptions<TAdapter>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/** Result type for the transcription activity */\nexport type TranscriptionActivityResult = Promise<TranscriptionResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Transcription activity - converts audio to text.\n *\n * Uses AI speech-to-text models to transcribe audio content.\n *\n * @example Transcribe an audio file\n * ```ts\n * import { generateTranscription } from '@tanstack/ai'\n * import { openaiTranscription } from '@tanstack/ai-openai'\n *\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile, // File, Blob, or base64 string\n * language: 'en'\n * })\n *\n * console.log(result.text)\n * ```\n *\n * @example With verbose output for timestamps\n * ```ts\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile,\n * responseFormat: 'verbose_json'\n * })\n *\n * result.segments?.forEach(segment => {\n * console.log(`[${segment.start}s - ${segment.end}s]: ${segment.text}`)\n * })\n * ```\n */\nexport async function generateTranscription<\n TAdapter extends TranscriptionAdapter<string, object>,\n>(\n options: TranscriptionActivityOptions<TAdapter>,\n): TranscriptionActivityResult {\n const { adapter, ...rest } = options\n const model = adapter.model\n\n return adapter.transcribe({ ...rest, model })\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateTranscription() function without executing.\n */\nexport function createTranscriptionOptions<\n TAdapter extends TranscriptionAdapter<string, object>,\n>(\n options: TranscriptionActivityOptions<TAdapter>,\n): TranscriptionActivityOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n TranscriptionAdapter,\n TranscriptionAdapterConfig,\n AnyTranscriptionAdapter,\n} from './adapter'\nexport { BaseTranscriptionAdapter } from './adapter'\n"],"names":[],"mappings":"AAeO,MAAM,OAAO;AAoFpB,eAAsB,sBAGpB,SAC6B;AAC7B,QAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,QAAM,QAAQ,QAAQ;AAEtB,SAAO,QAAQ,WAAW,EAAE,GAAG,MAAM,OAAO;AAC9C;AASO,SAAS,2BAGd,SACwC;AACxC,SAAO;AACT;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/activities/generateTranscription/index.ts"],"sourcesContent":["/**\n * Transcription Activity\n *\n * Transcribes audio to text using speech-to-text models.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '../../event-client.js'\nimport type { TranscriptionAdapter } from './adapter'\nimport type { TranscriptionResult } from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'transcription' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a TranscriptionAdapter via ~types.\n */\nexport type TranscriptionProviderOptions<TAdapter> =\n TAdapter extends TranscriptionAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the transcription activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The transcription adapter type\n */\nexport interface TranscriptionActivityOptions<\n TAdapter extends TranscriptionAdapter<string, object>,\n> {\n /** The transcription adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /** The audio data to transcribe - can be base64 string, File, Blob, or Buffer */\n audio: string | File | Blob | ArrayBuffer\n /** The language of the audio in ISO-639-1 format (e.g., 'en') */\n language?: string\n /** An optional prompt to guide the transcription */\n prompt?: string\n /** The format of the transcription output */\n responseFormat?: 'json' | 'text' | 'srt' | 'verbose_json' | 'vtt'\n /** Provider-specific options for transcription */\n modelOptions?: TranscriptionProviderOptions<TAdapter>\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/** Result type for the transcription activity */\nexport type TranscriptionActivityResult = Promise<TranscriptionResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Transcription activity - converts audio to text.\n *\n * Uses AI speech-to-text models to transcribe audio content.\n *\n * @example Transcribe an audio file\n * ```ts\n * import { generateTranscription } from '@tanstack/ai'\n * import { openaiTranscription } from '@tanstack/ai-openai'\n *\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile, // File, Blob, or base64 string\n * language: 'en'\n * })\n *\n * console.log(result.text)\n * ```\n *\n * @example With verbose output for timestamps\n * ```ts\n * const result = await generateTranscription({\n * adapter: openaiTranscription('whisper-1'),\n * audio: audioFile,\n * responseFormat: 'verbose_json'\n * })\n *\n * result.segments?.forEach(segment => {\n * console.log(`[${segment.start}s - ${segment.end}s]: ${segment.text}`)\n * })\n * ```\n */\nexport async function generateTranscription<\n TAdapter extends TranscriptionAdapter<string, object>,\n>(\n options: TranscriptionActivityOptions<TAdapter>,\n): TranscriptionActivityResult {\n const { adapter, ...rest } = options\n const model = adapter.model\n const requestId = createId('transcription')\n const startTime = Date.now()\n\n aiEventClient.emit('transcription:request:started', {\n requestId,\n provider: adapter.name,\n model,\n language: rest.language,\n prompt: rest.prompt,\n responseFormat: rest.responseFormat,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: startTime,\n })\n\n const result = await adapter.transcribe({ ...rest, model })\n const duration = Date.now() - startTime\n\n aiEventClient.emit('transcription:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n text: result.text,\n language: result.language,\n duration,\n modelOptions: rest.modelOptions as Record<string, unknown> | undefined,\n timestamp: Date.now(),\n })\n\n return result\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateTranscription() function without executing.\n */\nexport function createTranscriptionOptions<\n TAdapter extends TranscriptionAdapter<string, object>,\n>(\n options: TranscriptionActivityOptions<TAdapter>,\n): TranscriptionActivityOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n TranscriptionAdapter,\n TranscriptionAdapterConfig,\n AnyTranscriptionAdapter,\n} from './adapter'\nexport { BaseTranscriptionAdapter } from './adapter'\n"],"names":[],"mappings":";AAgBO,MAAM,OAAO;AAgDpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAsCA,eAAsB,sBAGpB,SAC6B;AAC7B,QAAM,EAAE,SAAS,GAAG,KAAA,IAAS;AAC7B,QAAM,QAAQ,QAAQ;AACtB,QAAM,YAAY,SAAS,eAAe;AAC1C,QAAM,YAAY,KAAK,IAAA;AAEvB,gBAAc,KAAK,iCAAiC;AAAA,IAClD;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,UAAU,KAAK;AAAA,IACf,QAAQ,KAAK;AAAA,IACb,gBAAgB,KAAK;AAAA,IACrB,cAAc,KAAK;AAAA,IACnB,WAAW;AAAA,EAAA,CACZ;AAED,QAAM,SAAS,MAAM,QAAQ,WAAW,EAAE,GAAG,MAAM,OAAO;AAC1D,QAAM,WAAW,KAAK,IAAA,IAAQ;AAE9B,gBAAc,KAAK,mCAAmC;AAAA,IACpD;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA,MAAM,OAAO;AAAA,IACb,UAAU,OAAO;AAAA,IACjB;AAAA,IACA,cAAc,KAAK;AAAA,IACnB,WAAW,KAAK,IAAA;AAAA,EAAI,CACrB;AAED,SAAO;AACT;AASO,SAAS,2BAGd,SACwC;AACxC,SAAO;AACT;"}
@@ -1,4 +1,8 @@
1
+ import { aiEventClient } from "../../event-client.js";
1
2
  const kind = "video";
3
+ function createId(prefix) {
4
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
5
+ }
2
6
  async function generateVideo(options) {
3
7
  const { adapter, prompt, size, duration, modelOptions } = options;
4
8
  const model = adapter.model;
@@ -12,16 +16,50 @@ async function generateVideo(options) {
12
16
  }
13
17
  async function getVideoJobStatus(options) {
14
18
  const { adapter, jobId } = options;
19
+ const requestId = createId("video-status");
20
+ const startTime = Date.now();
21
+ aiEventClient.emit("video:request:started", {
22
+ requestId,
23
+ provider: adapter.name,
24
+ model: adapter.model,
25
+ requestType: "status",
26
+ jobId,
27
+ timestamp: startTime
28
+ });
15
29
  const statusResult = await adapter.getVideoStatus(jobId);
16
30
  if (statusResult.status === "completed") {
17
31
  try {
18
32
  const urlResult = await adapter.getVideoUrl(jobId);
33
+ aiEventClient.emit("video:request:completed", {
34
+ requestId,
35
+ provider: adapter.name,
36
+ model: adapter.model,
37
+ requestType: "status",
38
+ jobId,
39
+ status: statusResult.status,
40
+ progress: statusResult.progress,
41
+ url: urlResult.url,
42
+ duration: Date.now() - startTime,
43
+ timestamp: Date.now()
44
+ });
19
45
  return {
20
46
  status: statusResult.status,
21
47
  progress: statusResult.progress,
22
48
  url: urlResult.url
23
49
  };
24
50
  } catch (error) {
51
+ aiEventClient.emit("video:request:completed", {
52
+ requestId,
53
+ provider: adapter.name,
54
+ model: adapter.model,
55
+ requestType: "status",
56
+ jobId,
57
+ status: statusResult.status,
58
+ progress: statusResult.progress,
59
+ error: error instanceof Error ? error.message : "Failed to get video URL",
60
+ duration: Date.now() - startTime,
61
+ timestamp: Date.now()
62
+ });
25
63
  return {
26
64
  status: statusResult.status,
27
65
  progress: statusResult.progress,
@@ -29,6 +67,18 @@ async function getVideoJobStatus(options) {
29
67
  };
30
68
  }
31
69
  }
70
+ aiEventClient.emit("video:request:completed", {
71
+ requestId,
72
+ provider: adapter.name,
73
+ model: adapter.model,
74
+ requestType: "status",
75
+ jobId,
76
+ status: statusResult.status,
77
+ progress: statusResult.progress,
78
+ error: statusResult.error,
79
+ duration: Date.now() - startTime,
80
+ timestamp: Date.now()
81
+ });
32
82
  return {
33
83
  status: statusResult.status,
34
84
  progress: statusResult.progress,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/activities/generateVideo/index.ts"],"sourcesContent":["/**\n * Video Activity (Experimental)\n *\n * Generates videos from text prompts using a jobs/polling architecture.\n * This is a self-contained module with implementation, types, and JSDoc.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\n\nimport type { VideoAdapter } from './adapter'\nimport type {\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'video' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a VideoAdapter via ~types.\n */\nexport type VideoProviderOptions<TAdapter> =\n TAdapter extends VideoAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Types\n// ===========================\n\n/**\n * Base options shared by all video activity operations.\n * The model is extracted from the adapter's model property.\n */\ninterface VideoActivityBaseOptions<\n TAdapter extends VideoAdapter<string, object>,\n> {\n /** The video adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n}\n\n/**\n * Options for creating a new video generation job.\n * The model is extracted from the adapter's model property.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoCreateOptions<\n TAdapter extends VideoAdapter<string, object>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - create a new job (default if not specified) */\n request?: 'create'\n /** Text description of the desired video */\n prompt: string\n /** Video size in WIDTHxHEIGHT format (e.g., \"1280x720\") */\n size?: string\n /** Video duration in seconds */\n duration?: number\n /** Provider-specific options for video generation */\n modelOptions?: VideoProviderOptions<TAdapter>\n}\n\n/**\n * Options for polling the status of a video generation job.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoStatusOptions<\n TAdapter extends VideoAdapter<string, object>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get job status */\n request: 'status'\n /** The job ID to check status for */\n jobId: string\n}\n\n/**\n * Options for getting the URL of a completed video.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoUrlOptions<\n TAdapter extends VideoAdapter<string, object>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get video URL */\n request: 'url'\n /** The job ID to get URL for */\n jobId: string\n}\n\n/**\n * Union type for all video activity options.\n * Discriminated by the `request` field.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityOptions<\n TAdapter extends VideoAdapter<string, object>,\n TRequest extends 'create' | 'status' | 'url' = 'create',\n> = TRequest extends 'status'\n ? VideoStatusOptions<TAdapter>\n : TRequest extends 'url'\n ? VideoUrlOptions<TAdapter>\n : VideoCreateOptions<TAdapter>\n\n// ===========================\n// Activity Result Types\n// ===========================\n\n/**\n * Result type for the video activity, based on request type.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityResult<\n TRequest extends 'create' | 'status' | 'url' = 'create',\n> = TRequest extends 'status'\n ? Promise<VideoStatusResult>\n : TRequest extends 'url'\n ? Promise<VideoUrlResult>\n : Promise<VideoJobResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Generate video - creates a video generation job from a text prompt.\n *\n * Uses AI video generation models to create videos based on natural language descriptions.\n * Unlike image generation, video generation is asynchronous and requires polling for completion.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Create a video generation job\n * ```ts\n * import { generateVideo } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * // Start a video generation job\n * const { jobId } = await generateVideo({\n * adapter: openaiVideo('sora-2'),\n * prompt: 'A cat chasing a dog in a sunny park'\n * })\n *\n * console.log('Job started:', jobId)\n * ```\n */\nexport async function generateVideo<\n TAdapter extends VideoAdapter<string, object>,\n>(options: VideoCreateOptions<TAdapter>): Promise<VideoJobResult> {\n const { adapter, prompt, size, duration, modelOptions } = options\n const model = adapter.model\n\n return adapter.createVideoJob({\n model,\n prompt,\n size,\n duration,\n modelOptions,\n })\n}\n\n/**\n * Get video job status - returns the current status, progress, and URL if available.\n *\n * This function combines status checking and URL retrieval. If the job is completed,\n * it will automatically fetch and include the video URL.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Check job status\n * ```ts\n * import { getVideoJobStatus } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * const result = await getVideoJobStatus({\n * adapter: openaiVideo('sora-2'),\n * jobId: 'job-123'\n * })\n *\n * console.log('Status:', result.status)\n * console.log('Progress:', result.progress)\n * if (result.url) {\n * console.log('Video URL:', result.url)\n * }\n * ```\n */\nexport async function getVideoJobStatus<\n TAdapter extends VideoAdapter<string, object>,\n>(options: {\n adapter: TAdapter & { kind: typeof kind }\n jobId: string\n}): Promise<{\n status: 'pending' | 'processing' | 'completed' | 'failed'\n progress?: number\n url?: string\n error?: string\n}> {\n const { adapter, jobId } = options\n\n // Get status first\n const statusResult = await adapter.getVideoStatus(jobId)\n\n // If completed, also get the URL\n if (statusResult.status === 'completed') {\n try {\n const urlResult = await adapter.getVideoUrl(jobId)\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n }\n } catch (error) {\n // If URL fetch fails, still return status\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n error:\n error instanceof Error ? error.message : 'Failed to get video URL',\n }\n }\n }\n\n // Return status for non-completed jobs\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateVideo() function without executing.\n */\nexport function createVideoOptions<\n TAdapter extends VideoAdapter<string, object>,\n>(options: VideoCreateOptions<TAdapter>): VideoCreateOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n VideoAdapter,\n VideoAdapterConfig,\n AnyVideoAdapter,\n} from './adapter'\nexport { BaseVideoAdapter } from './adapter'\n"],"names":[],"mappings":"AAqBO,MAAM,OAAO;AAwIpB,eAAsB,cAEpB,SAAgE;AAChE,QAAM,EAAE,SAAS,QAAQ,MAAM,UAAU,iBAAiB;AAC1D,QAAM,QAAQ,QAAQ;AAEtB,SAAO,QAAQ,eAAe;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AACH;AA2BA,eAAsB,kBAEpB,SAQC;AACD,QAAM,EAAE,SAAS,MAAA,IAAU;AAG3B,QAAM,eAAe,MAAM,QAAQ,eAAe,KAAK;AAGvD,MAAI,aAAa,WAAW,aAAa;AACvC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,YAAY,KAAK;AACjD,aAAO;AAAA,QACL,QAAQ,aAAa;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,KAAK,UAAU;AAAA,MAAA;AAAA,IAEnB,SAAS,OAAO;AAEd,aAAO;AAAA,QACL,QAAQ,aAAa;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,OACE,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAAA;AAAA,IAE/C;AAAA,EACF;AAGA,SAAO;AAAA,IACL,QAAQ,aAAa;AAAA,IACrB,UAAU,aAAa;AAAA,IACvB,OAAO,aAAa;AAAA,EAAA;AAExB;AASO,SAAS,mBAEd,SAAqE;AACrE,SAAO;AACT;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/activities/generateVideo/index.ts"],"sourcesContent":["/**\n * Video Activity (Experimental)\n *\n * Generates videos from text prompts using a jobs/polling architecture.\n * This is a self-contained module with implementation, types, and JSDoc.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\n\nimport { aiEventClient } from '../../event-client.js'\nimport type { VideoAdapter } from './adapter'\nimport type {\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'video' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract provider options from a VideoAdapter via ~types.\n */\nexport type VideoProviderOptions<TAdapter> =\n TAdapter extends VideoAdapter<any, any>\n ? TAdapter['~types']['providerOptions']\n : object\n\n// ===========================\n// Activity Options Types\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n// ===========================\n\n/**\n * Base options shared by all video activity operations.\n * The model is extracted from the adapter's model property.\n */\ninterface VideoActivityBaseOptions<\n TAdapter extends VideoAdapter<string, object>,\n> {\n /** The video adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n}\n\n/**\n * Options for creating a new video generation job.\n * The model is extracted from the adapter's model property.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoCreateOptions<\n TAdapter extends VideoAdapter<string, object>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - create a new job (default if not specified) */\n request?: 'create'\n /** Text description of the desired video */\n prompt: string\n /** Video size in WIDTHxHEIGHT format (e.g., \"1280x720\") */\n size?: string\n /** Video duration in seconds */\n duration?: number\n /** Provider-specific options for video generation */\n modelOptions?: VideoProviderOptions<TAdapter>\n}\n\n/**\n * Options for polling the status of a video generation job.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoStatusOptions<\n TAdapter extends VideoAdapter<string, object>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get job status */\n request: 'status'\n /** The job ID to check status for */\n jobId: string\n}\n\n/**\n * Options for getting the URL of a completed video.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoUrlOptions<\n TAdapter extends VideoAdapter<string, object>,\n> extends VideoActivityBaseOptions<TAdapter> {\n /** Request type - get video URL */\n request: 'url'\n /** The job ID to get URL for */\n jobId: string\n}\n\n/**\n * Union type for all video activity options.\n * Discriminated by the `request` field.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityOptions<\n TAdapter extends VideoAdapter<string, object>,\n TRequest extends 'create' | 'status' | 'url' = 'create',\n> = TRequest extends 'status'\n ? VideoStatusOptions<TAdapter>\n : TRequest extends 'url'\n ? VideoUrlOptions<TAdapter>\n : VideoCreateOptions<TAdapter>\n\n// ===========================\n// Activity Result Types\n// ===========================\n\n/**\n * Result type for the video activity, based on request type.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type VideoActivityResult<\n TRequest extends 'create' | 'status' | 'url' = 'create',\n> = TRequest extends 'status'\n ? Promise<VideoStatusResult>\n : TRequest extends 'url'\n ? Promise<VideoUrlResult>\n : Promise<VideoJobResult>\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Generate video - creates a video generation job from a text prompt.\n *\n * Uses AI video generation models to create videos based on natural language descriptions.\n * Unlike image generation, video generation is asynchronous and requires polling for completion.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Create a video generation job\n * ```ts\n * import { generateVideo } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * // Start a video generation job\n * const { jobId } = await generateVideo({\n * adapter: openaiVideo('sora-2'),\n * prompt: 'A cat chasing a dog in a sunny park'\n * })\n *\n * console.log('Job started:', jobId)\n * ```\n */\nexport async function generateVideo<\n TAdapter extends VideoAdapter<string, object>,\n>(options: VideoCreateOptions<TAdapter>): Promise<VideoJobResult> {\n const { adapter, prompt, size, duration, modelOptions } = options\n const model = adapter.model\n\n return adapter.createVideoJob({\n model,\n prompt,\n size,\n duration,\n modelOptions,\n })\n}\n\n/**\n * Get video job status - returns the current status, progress, and URL if available.\n *\n * This function combines status checking and URL retrieval. If the job is completed,\n * it will automatically fetch and include the video URL.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @example Check job status\n * ```ts\n * import { getVideoJobStatus } from '@tanstack/ai'\n * import { openaiVideo } from '@tanstack/ai-openai'\n *\n * const result = await getVideoJobStatus({\n * adapter: openaiVideo('sora-2'),\n * jobId: 'job-123'\n * })\n *\n * console.log('Status:', result.status)\n * console.log('Progress:', result.progress)\n * if (result.url) {\n * console.log('Video URL:', result.url)\n * }\n * ```\n */\nexport async function getVideoJobStatus<\n TAdapter extends VideoAdapter<string, object>,\n>(options: {\n adapter: TAdapter & { kind: typeof kind }\n jobId: string\n}): Promise<{\n status: 'pending' | 'processing' | 'completed' | 'failed'\n progress?: number\n url?: string\n error?: string\n}> {\n const { adapter, jobId } = options\n const requestId = createId('video-status')\n const startTime = Date.now()\n\n aiEventClient.emit('video:request:started', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n timestamp: startTime,\n })\n\n // Get status first\n const statusResult = await adapter.getVideoStatus(jobId)\n\n // If completed, also get the URL\n if (statusResult.status === 'completed') {\n try {\n const urlResult = await adapter.getVideoUrl(jobId)\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n url: urlResult.url,\n }\n } catch (error) {\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n error:\n error instanceof Error ? error.message : 'Failed to get video URL',\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n // If URL fetch fails, still return status\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n error:\n error instanceof Error ? error.message : 'Failed to get video URL',\n }\n }\n }\n\n aiEventClient.emit('video:request:completed', {\n requestId,\n provider: adapter.name,\n model: adapter.model,\n requestType: 'status',\n jobId,\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n })\n\n // Return status for non-completed jobs\n return {\n status: statusResult.status,\n progress: statusResult.progress,\n error: statusResult.error,\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateVideo() function without executing.\n */\nexport function createVideoOptions<\n TAdapter extends VideoAdapter<string, object>,\n>(options: VideoCreateOptions<TAdapter>): VideoCreateOptions<TAdapter> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n VideoAdapter,\n VideoAdapterConfig,\n AnyVideoAdapter,\n} from './adapter'\nexport { BaseVideoAdapter } from './adapter'\n"],"names":[],"mappings":";AAsBO,MAAM,OAAO;AAiBpB,SAAS,SAAS,QAAwB;AACxC,SAAO,GAAG,MAAM,IAAI,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAC1E;AAyHA,eAAsB,cAEpB,SAAgE;AAChE,QAAM,EAAE,SAAS,QAAQ,MAAM,UAAU,iBAAiB;AAC1D,QAAM,QAAQ,QAAQ;AAEtB,SAAO,QAAQ,eAAe;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AACH;AA2BA,eAAsB,kBAEpB,SAQC;AACD,QAAM,EAAE,SAAS,MAAA,IAAU;AAC3B,QAAM,YAAY,SAAS,cAAc;AACzC,QAAM,YAAY,KAAK,IAAA;AAEvB,gBAAc,KAAK,yBAAyB;AAAA,IAC1C;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,OAAO,QAAQ;AAAA,IACf,aAAa;AAAA,IACb;AAAA,IACA,WAAW;AAAA,EAAA,CACZ;AAGD,QAAM,eAAe,MAAM,QAAQ,eAAe,KAAK;AAGvD,MAAI,aAAa,WAAW,aAAa;AACvC,QAAI;AACF,YAAM,YAAY,MAAM,QAAQ,YAAY,KAAK;AACjD,oBAAc,KAAK,2BAA2B;AAAA,QAC5C;AAAA,QACA,UAAU,QAAQ;AAAA,QAClB,OAAO,QAAQ;AAAA,QACf,aAAa;AAAA,QACb;AAAA,QACA,QAAQ,aAAa;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,KAAK,UAAU;AAAA,QACf,UAAU,KAAK,IAAA,IAAQ;AAAA,QACvB,WAAW,KAAK,IAAA;AAAA,MAAI,CACrB;AACD,aAAO;AAAA,QACL,QAAQ,aAAa;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,KAAK,UAAU;AAAA,MAAA;AAAA,IAEnB,SAAS,OAAO;AACd,oBAAc,KAAK,2BAA2B;AAAA,QAC5C;AAAA,QACA,UAAU,QAAQ;AAAA,QAClB,OAAO,QAAQ;AAAA,QACf,aAAa;AAAA,QACb;AAAA,QACA,QAAQ,aAAa;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,OACE,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAC3C,UAAU,KAAK,IAAA,IAAQ;AAAA,QACvB,WAAW,KAAK,IAAA;AAAA,MAAI,CACrB;AAED,aAAO;AAAA,QACL,QAAQ,aAAa;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,OACE,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MAAA;AAAA,IAE/C;AAAA,EACF;AAEA,gBAAc,KAAK,2BAA2B;AAAA,IAC5C;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,OAAO,QAAQ;AAAA,IACf,aAAa;AAAA,IACb;AAAA,IACA,QAAQ,aAAa;AAAA,IACrB,UAAU,aAAa;AAAA,IACvB,OAAO,aAAa;AAAA,IACpB,UAAU,KAAK,IAAA,IAAQ;AAAA,IACvB,WAAW,KAAK,IAAA;AAAA,EAAI,CACrB;AAGD,SAAO;AAAA,IACL,QAAQ,aAAa;AAAA,IACrB,UAAU,aAAa;AAAA,IACvB,OAAO,aAAa;AAAA,EAAA;AAExB;AASO,SAAS,mBAEd,SAAqE;AACrE,SAAO;AACT;"}