@tanstack/ai 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -25
- package/dist/esm/activities/chat/index.d.ts +11 -10
- package/dist/esm/activities/chat/index.js +9 -9
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/tools/schema-converter.d.ts +116 -0
- package/dist/esm/activities/chat/tools/schema-converter.js +115 -0
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -0
- package/dist/esm/activities/chat/tools/tool-calls.js +23 -34
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +18 -14
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +5 -4
- package/dist/esm/stream-to-response.d.ts +28 -21
- package/dist/esm/stream-to-response.js +24 -17
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/types.d.ts +44 -25
- package/package.json +3 -6
- package/src/activities/chat/index.ts +36 -28
- package/src/activities/chat/tools/schema-converter.ts +332 -0
- package/src/activities/chat/tools/tool-calls.ts +47 -53
- package/src/activities/chat/tools/tool-definition.ts +33 -29
- package/src/index.ts +5 -2
- package/src/stream-to-response.ts +59 -44
- package/src/types.ts +47 -26
- package/dist/esm/activities/chat/tools/zod-converter.d.ts +0 -69
- package/dist/esm/activities/chat/tools/zod-converter.js +0 -99
- package/dist/esm/activities/chat/tools/zod-converter.js.map +0 -1
- package/src/activities/chat/tools/zod-converter.ts +0 -235
package/README.md
CHANGED
|
@@ -72,31 +72,6 @@ for await (const chunk of result) {
|
|
|
72
72
|
|
|
73
73
|
Available adapters: `openaiText`, `openaiEmbed`, `openaiSummarize`, `anthropicText`, `geminiText`, `ollamaText`, and more.
|
|
74
74
|
|
|
75
|
-
## Bonus: TanStack Start Integration
|
|
76
|
-
|
|
77
|
-
TanStack AI works with **any** framework (Next.js, Express, Remix, etc.).
|
|
78
|
-
|
|
79
|
-
**With TanStack Start**, you get a bonus: share implementations between AI tools and server functions with `createServerFnTool`:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { createServerFnTool } from '@tanstack/ai-react'
|
|
83
|
-
|
|
84
|
-
// Define once, get AI tool AND server function (TanStack Start only)
|
|
85
|
-
const getProducts = createServerFnTool({
|
|
86
|
-
name: 'getProducts',
|
|
87
|
-
inputSchema: z.object({ query: z.string() }),
|
|
88
|
-
execute: async ({ query }) => db.products.search(query),
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// Use in AI chat
|
|
92
|
-
chat({ tools: [getProducts.server] })
|
|
93
|
-
|
|
94
|
-
// Call directly from components (no API endpoint needed!)
|
|
95
|
-
const products = await getProducts.serverFn({ query: 'laptop' })
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
No duplicate logic, full type safety, automatic validation. The `serverFn` feature requires TanStack Start. See [docs](https://tanstack.com/ai) for details.
|
|
99
|
-
|
|
100
75
|
## Get Involved
|
|
101
76
|
|
|
102
77
|
- We welcome issues and pull requests!
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
1
|
import { AnyTextAdapter } from './adapter.js';
|
|
3
|
-
import { ConstrainedModelMessage, StreamChunk, TextOptions } from '../../types.js';
|
|
2
|
+
import { ConstrainedModelMessage, InferSchemaType, SchemaInput, StreamChunk, TextOptions } from '../../types.js';
|
|
4
3
|
/** The adapter kind this activity handles */
|
|
5
4
|
export declare const kind: "text";
|
|
6
5
|
/**
|
|
@@ -8,10 +7,10 @@ export declare const kind: "text";
|
|
|
8
7
|
* Types are extracted directly from the adapter (which has pre-resolved generics).
|
|
9
8
|
*
|
|
10
9
|
* @template TAdapter - The text adapter type (created by a provider function)
|
|
11
|
-
* @template TSchema - Optional
|
|
10
|
+
* @template TSchema - Optional Standard Schema for structured output
|
|
12
11
|
* @template TStream - Whether to stream the output (default: true)
|
|
13
12
|
*/
|
|
14
|
-
export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema extends
|
|
13
|
+
export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema extends SchemaInput | undefined, TStream extends boolean> {
|
|
15
14
|
/** The text adapter to use (created by a provider function like openaiText('gpt-4o')) */
|
|
16
15
|
adapter: TAdapter;
|
|
17
16
|
/** Conversation messages - content types are constrained by the adapter's input modalities and metadata */
|
|
@@ -40,11 +39,13 @@ export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema ex
|
|
|
40
39
|
/** Unique conversation identifier for tracking */
|
|
41
40
|
conversationId?: TextOptions['conversationId'];
|
|
42
41
|
/**
|
|
43
|
-
* Optional
|
|
42
|
+
* Optional Standard Schema for structured output.
|
|
44
43
|
* When provided, the activity will:
|
|
45
44
|
* 1. Run the full agentic loop (executing tools as needed)
|
|
46
45
|
* 2. Once complete, return a Promise with the parsed output matching the schema
|
|
47
46
|
*
|
|
47
|
+
* Supports any Standard Schema compliant library (Zod v4+, ArkType, Valibot, etc.)
|
|
48
|
+
*
|
|
48
49
|
* @example
|
|
49
50
|
* ```ts
|
|
50
51
|
* const result = await chat({
|
|
@@ -62,7 +63,7 @@ export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema ex
|
|
|
62
63
|
* When false, returns a Promise<string> with the collected text content.
|
|
63
64
|
*
|
|
64
65
|
* Note: If outputSchema is provided, this option is ignored and the result
|
|
65
|
-
* is always a Promise<
|
|
66
|
+
* is always a Promise<InferSchemaType<TSchema>>.
|
|
66
67
|
*
|
|
67
68
|
* @default true
|
|
68
69
|
*
|
|
@@ -91,14 +92,14 @@ export interface TextActivityOptions<TAdapter extends AnyTextAdapter, TSchema ex
|
|
|
91
92
|
* const stream = chat({ ...chatOptions, messages })
|
|
92
93
|
* ```
|
|
93
94
|
*/
|
|
94
|
-
export declare function createChatOptions<TAdapter extends AnyTextAdapter, TSchema extends
|
|
95
|
+
export declare function createChatOptions<TAdapter extends AnyTextAdapter, TSchema extends SchemaInput | undefined = undefined, TStream extends boolean = true>(options: TextActivityOptions<TAdapter, TSchema, TStream>): TextActivityOptions<TAdapter, TSchema, TStream>;
|
|
95
96
|
/**
|
|
96
97
|
* Result type for the text activity.
|
|
97
|
-
* - If outputSchema is provided: Promise<
|
|
98
|
+
* - If outputSchema is provided: Promise<InferSchemaType<TSchema>>
|
|
98
99
|
* - If stream is false: Promise<string>
|
|
99
100
|
* - Otherwise (stream is true, default): AsyncIterable<StreamChunk>
|
|
100
101
|
*/
|
|
101
|
-
export type TextActivityResult<TSchema extends
|
|
102
|
+
export type TextActivityResult<TSchema extends SchemaInput | undefined, TStream extends boolean = true> = TSchema extends SchemaInput ? Promise<InferSchemaType<TSchema>> : TStream extends false ? Promise<string> : AsyncIterable<StreamChunk>;
|
|
102
103
|
/**
|
|
103
104
|
* Text activity - handles agentic text generation, one-shot text generation, and agentic structured output.
|
|
104
105
|
*
|
|
@@ -160,6 +161,6 @@ export type TextActivityResult<TSchema extends z.ZodType | undefined, TStream ex
|
|
|
160
161
|
* // result is { summary: string, keyPoints: string[] }
|
|
161
162
|
* ```
|
|
162
163
|
*/
|
|
163
|
-
export declare function chat<TAdapter extends AnyTextAdapter, TSchema extends
|
|
164
|
+
export declare function chat<TAdapter extends AnyTextAdapter, TSchema extends SchemaInput | undefined = undefined, TStream extends boolean = true>(options: TextActivityOptions<TAdapter, TSchema, TStream>): TextActivityResult<TSchema, TStream>;
|
|
164
165
|
export type { TextAdapter, TextAdapterConfig, StructuredOutputOptions, StructuredOutputResult, } from './adapter.js';
|
|
165
166
|
export { BaseTextAdapter } from './adapter.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { aiEventClient } from "../../event-client.js";
|
|
2
2
|
import { streamToText } from "../../stream-to-response.js";
|
|
3
3
|
import { ToolCallManager, executeToolCalls } from "./tools/tool-calls.js";
|
|
4
|
-
import {
|
|
4
|
+
import { convertSchemaToJsonSchema, isStandardSchema, parseWithStandardSchema } from "./tools/schema-converter.js";
|
|
5
5
|
import { maxIterations } from "./agent-loop-strategies.js";
|
|
6
6
|
const kind = "text";
|
|
7
7
|
function createChatOptions(options) {
|
|
@@ -148,8 +148,8 @@ class TextEngine {
|
|
|
148
148
|
const tools = this.params.tools;
|
|
149
149
|
const toolsWithJsonSchemas = tools?.map((tool) => ({
|
|
150
150
|
...tool,
|
|
151
|
-
inputSchema: tool.inputSchema ?
|
|
152
|
-
outputSchema: tool.outputSchema ?
|
|
151
|
+
inputSchema: tool.inputSchema ? convertSchemaToJsonSchema(tool.inputSchema) : void 0,
|
|
152
|
+
outputSchema: tool.outputSchema ? convertSchemaToJsonSchema(tool.outputSchema) : void 0
|
|
153
153
|
}));
|
|
154
154
|
for await (const chunk of this.adapter.chatStream({
|
|
155
155
|
model: this.params.model,
|
|
@@ -603,7 +603,7 @@ async function runAgenticStructuredOutput(options) {
|
|
|
603
603
|
agentLoopStrategy: _als,
|
|
604
604
|
...structuredTextOptions
|
|
605
605
|
} = textOptions;
|
|
606
|
-
const jsonSchema =
|
|
606
|
+
const jsonSchema = convertSchemaToJsonSchema(outputSchema);
|
|
607
607
|
if (!jsonSchema) {
|
|
608
608
|
throw new Error("Failed to convert output schema to JSON Schema");
|
|
609
609
|
}
|
|
@@ -615,13 +615,13 @@ async function runAgenticStructuredOutput(options) {
|
|
|
615
615
|
},
|
|
616
616
|
outputSchema: jsonSchema
|
|
617
617
|
});
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
618
|
+
if (isStandardSchema(outputSchema)) {
|
|
619
|
+
return parseWithStandardSchema(
|
|
620
|
+
outputSchema,
|
|
621
|
+
result.data
|
|
622
622
|
);
|
|
623
623
|
}
|
|
624
|
-
return
|
|
624
|
+
return result.data;
|
|
625
625
|
}
|
|
626
626
|
export {
|
|
627
627
|
chat,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/activities/chat/index.ts"],"sourcesContent":["/**\n * Text Activity\n *\n * Handles agentic text generation, one-shot text generation, and agentic structured output.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '../../event-client.js'\nimport { streamToText } from '../../stream-to-response.js'\nimport { ToolCallManager, executeToolCalls } from './tools/tool-calls'\nimport { convertZodToJsonSchema } from './tools/zod-converter'\nimport { maxIterations as maxIterationsStrategy } from './agent-loop-strategies'\nimport type {\n ApprovalRequest,\n ClientToolRequest,\n ToolResult,\n} from './tools/tool-calls'\nimport type { z } from 'zod'\nimport type { AnyTextAdapter } from './adapter'\nimport type {\n AgentLoopStrategy,\n ConstrainedModelMessage,\n DoneStreamChunk,\n ModelMessage,\n StreamChunk,\n TextOptions,\n Tool,\n ToolCall,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'text' as const\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the text activity.\n * Types are extracted directly from the adapter (which has pre-resolved generics).\n *\n * @template TAdapter - The text adapter type (created by a provider function)\n * @template TSchema - Optional Zod schema for structured output\n * @template TStream - Whether to stream the output (default: true)\n */\nexport interface TextActivityOptions<\n TAdapter extends AnyTextAdapter,\n TSchema extends z.ZodType | undefined,\n TStream extends boolean,\n> {\n /** The text adapter to use (created by a provider function like openaiText('gpt-4o')) */\n adapter: TAdapter\n /** Conversation messages - content types are constrained by the adapter's input modalities and metadata */\n messages?: Array<\n ConstrainedModelMessage<{\n inputModalities: TAdapter['~types']['inputModalities']\n messageMetadataByModality: TAdapter['~types']['messageMetadataByModality']\n }>\n >\n /** System prompts to prepend to the conversation */\n systemPrompts?: TextOptions['systemPrompts']\n /** Tools for function calling (auto-executed when called) */\n tools?: TextOptions['tools']\n /** Controls the randomness of the output. Higher values make output more random. Range: [0.0, 2.0] */\n temperature?: TextOptions['temperature']\n /** Nucleus sampling parameter. The model considers tokens with topP probability mass. */\n topP?: TextOptions['topP']\n /** The maximum number of tokens to generate in the response. */\n maxTokens?: TextOptions['maxTokens']\n /** Additional metadata to attach to the request. */\n metadata?: TextOptions['metadata']\n /** Model-specific provider options (type comes from adapter) */\n modelOptions?: TAdapter['~types']['providerOptions']\n /** AbortController for cancellation */\n abortController?: TextOptions['abortController']\n /** Strategy for controlling the agent loop */\n agentLoopStrategy?: TextOptions['agentLoopStrategy']\n /** Unique conversation identifier for tracking */\n conversationId?: TextOptions['conversationId']\n /**\n * Optional Zod schema for structured output.\n * When provided, the activity will:\n * 1. Run the full agentic loop (executing tools as needed)\n * 2. Once complete, return a Promise with the parsed output matching the schema\n *\n * @example\n * ```ts\n * const result = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Generate a person' }],\n * outputSchema: z.object({ name: z.string(), age: z.number() })\n * })\n * // result is { name: string, age: number }\n * ```\n */\n outputSchema?: TSchema\n /**\n * Whether to stream the text result.\n * When true (default), returns an AsyncIterable<StreamChunk> for streaming output.\n * When false, returns a Promise<string> with the collected text content.\n *\n * Note: If outputSchema is provided, this option is ignored and the result\n * is always a Promise<z.infer<TSchema>>.\n *\n * @default true\n *\n * @example Non-streaming text\n * ```ts\n * const text = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Hello!' }],\n * stream: false\n * })\n * // text is a string with the full response\n * ```\n */\n stream?: TStream\n}\n\n// ===========================\n// Chat Options Helper\n// ===========================\n\n/**\n * Create typed options for the chat() function without executing.\n * This is useful for pre-defining configurations with full type inference.\n *\n * @example\n * ```ts\n * const chatOptions = createChatOptions({\n * adapter: anthropicText('claude-sonnet-4-5'),\n * })\n *\n * const stream = chat({ ...chatOptions, messages })\n * ```\n */\nexport function createChatOptions<\n TAdapter extends AnyTextAdapter,\n TSchema extends z.ZodType | undefined = undefined,\n TStream extends boolean = true,\n>(\n options: TextActivityOptions<TAdapter, TSchema, TStream>,\n): TextActivityOptions<TAdapter, TSchema, TStream> {\n return options\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the text activity.\n * - If outputSchema is provided: Promise<z.infer<TSchema>>\n * - If stream is false: Promise<string>\n * - Otherwise (stream is true, default): AsyncIterable<StreamChunk>\n */\nexport type TextActivityResult<\n TSchema extends z.ZodType | undefined,\n TStream extends boolean = true,\n> = TSchema extends z.ZodType\n ? Promise<z.infer<TSchema>>\n : TStream extends false\n ? Promise<string>\n : AsyncIterable<StreamChunk>\n\n// ===========================\n// ChatEngine Implementation\n// ===========================\n\ninterface TextEngineConfig<\n TAdapter extends AnyTextAdapter,\n TParams extends TextOptions<any, any> = TextOptions<any>,\n> {\n adapter: TAdapter\n systemPrompts?: Array<string>\n params: TParams\n}\n\ntype ToolPhaseResult = 'continue' | 'stop' | 'wait'\ntype CyclePhase = 'processText' | 'executeToolCalls'\n\nclass TextEngine<\n TAdapter extends AnyTextAdapter,\n TParams extends TextOptions<any, any> = TextOptions<any>,\n> {\n private readonly adapter: TAdapter\n private readonly params: TParams\n private readonly systemPrompts: Array<string>\n private readonly tools: ReadonlyArray<Tool>\n private readonly loopStrategy: AgentLoopStrategy\n private readonly toolCallManager: ToolCallManager\n private readonly initialMessageCount: number\n private readonly requestId: string\n private readonly streamId: string\n private readonly effectiveRequest?: Request | RequestInit\n private readonly effectiveSignal?: AbortSignal\n\n private messages: Array<ModelMessage>\n private iterationCount = 0\n private lastFinishReason: string | null = null\n private streamStartTime = 0\n private totalChunkCount = 0\n private currentMessageId: string | null = null\n private accumulatedContent = ''\n private doneChunk: DoneStreamChunk | null = null\n private shouldEmitStreamEnd = true\n private earlyTermination = false\n private toolPhase: ToolPhaseResult = 'continue'\n private cyclePhase: CyclePhase = 'processText'\n\n constructor(config: TextEngineConfig<TAdapter, TParams>) {\n this.adapter = config.adapter\n this.params = config.params\n this.systemPrompts = config.params.systemPrompts || []\n this.tools = config.params.tools || []\n this.loopStrategy =\n config.params.agentLoopStrategy || maxIterationsStrategy(5)\n this.toolCallManager = new ToolCallManager(this.tools)\n this.initialMessageCount = config.params.messages.length\n this.messages = config.params.messages\n this.requestId = this.createId('chat')\n this.streamId = this.createId('stream')\n this.effectiveRequest = config.params.abortController\n ? { signal: config.params.abortController.signal }\n : undefined\n this.effectiveSignal = config.params.abortController?.signal\n }\n\n /** Get the accumulated content after the chat loop completes */\n getAccumulatedContent(): string {\n return this.accumulatedContent\n }\n\n /** Get the final messages array after the chat loop completes */\n getMessages(): Array<ModelMessage> {\n return this.messages\n }\n\n async *run(): AsyncGenerator<StreamChunk> {\n this.beforeRun()\n\n try {\n const pendingPhase = yield* this.checkForPendingToolCalls()\n if (pendingPhase === 'wait') {\n return\n }\n\n do {\n if (this.earlyTermination || this.isAborted()) {\n return\n }\n\n this.beginCycle()\n\n if (this.cyclePhase === 'processText') {\n yield* this.streamModelResponse()\n } else {\n yield* this.processToolCalls()\n }\n\n this.endCycle()\n } while (this.shouldContinue())\n } finally {\n this.afterRun()\n }\n }\n\n private beforeRun(): void {\n this.streamStartTime = Date.now()\n const {\n model,\n tools,\n temperature,\n topP,\n maxTokens,\n metadata,\n modelOptions,\n conversationId,\n } = this.params\n\n // Gather flattened options into an object for event emission\n const options: Record<string, unknown> = {}\n if (temperature !== undefined) options.temperature = temperature\n if (topP !== undefined) options.topP = topP\n if (maxTokens !== undefined) options.maxTokens = maxTokens\n if (metadata !== undefined) options.metadata = metadata\n\n aiEventClient.emit('text:started', {\n requestId: this.requestId,\n streamId: this.streamId,\n model: model,\n provider: this.adapter.name,\n messageCount: this.initialMessageCount,\n hasTools: !!tools && tools.length > 0,\n streaming: true,\n timestamp: Date.now(),\n clientId: conversationId,\n toolNames: tools?.map((t) => t.name),\n options: Object.keys(options).length > 0 ? options : undefined,\n modelOptions: modelOptions as Record<string, unknown> | undefined,\n })\n\n aiEventClient.emit('stream:started', {\n streamId: this.streamId,\n model,\n provider: this.adapter.name,\n timestamp: Date.now(),\n })\n }\n\n private afterRun(): void {\n if (!this.shouldEmitStreamEnd) {\n return\n }\n\n const now = Date.now()\n\n // Emit text:completed with final state\n aiEventClient.emit('text:completed', {\n requestId: this.requestId,\n streamId: this.streamId,\n model: this.params.model,\n content: this.accumulatedContent,\n messageId: this.currentMessageId || undefined,\n finishReason: this.lastFinishReason || undefined,\n usage: this.doneChunk?.usage,\n timestamp: now,\n })\n\n aiEventClient.emit('stream:ended', {\n requestId: this.requestId,\n streamId: this.streamId,\n totalChunks: this.totalChunkCount,\n duration: now - this.streamStartTime,\n timestamp: now,\n })\n }\n\n private beginCycle(): void {\n if (this.cyclePhase === 'processText') {\n this.beginIteration()\n }\n }\n\n private endCycle(): void {\n if (this.cyclePhase === 'processText') {\n this.cyclePhase = 'executeToolCalls'\n return\n }\n\n this.cyclePhase = 'processText'\n this.iterationCount++\n }\n\n private beginIteration(): void {\n this.currentMessageId = this.createId('msg')\n this.accumulatedContent = ''\n this.doneChunk = null\n }\n\n private async *streamModelResponse(): AsyncGenerator<StreamChunk> {\n const { temperature, topP, maxTokens, metadata, modelOptions } = this.params\n const tools = this.params.tools\n\n // Convert tool schemas from Zod to JSON Schema before passing to adapter\n const toolsWithJsonSchemas = tools?.map((tool) => ({\n ...tool,\n inputSchema: tool.inputSchema\n ? convertZodToJsonSchema(tool.inputSchema)\n : undefined,\n outputSchema: tool.outputSchema\n ? convertZodToJsonSchema(tool.outputSchema)\n : undefined,\n }))\n\n for await (const chunk of this.adapter.chatStream({\n model: this.params.model,\n messages: this.messages,\n tools: toolsWithJsonSchemas,\n temperature,\n topP,\n maxTokens,\n metadata,\n request: this.effectiveRequest,\n modelOptions,\n systemPrompts: this.systemPrompts,\n })) {\n if (this.isAborted()) {\n break\n }\n\n this.totalChunkCount++\n\n yield chunk\n this.handleStreamChunk(chunk)\n\n if (this.earlyTermination) {\n break\n }\n }\n }\n\n private handleStreamChunk(chunk: StreamChunk): void {\n switch (chunk.type) {\n case 'content':\n this.handleContentChunk(chunk)\n break\n case 'tool_call':\n this.handleToolCallChunk(chunk)\n break\n case 'tool_result':\n this.handleToolResultChunk(chunk)\n break\n case 'done':\n this.handleDoneChunk(chunk)\n break\n case 'error':\n this.handleErrorChunk(chunk)\n break\n case 'thinking':\n this.handleThinkingChunk(chunk)\n break\n default:\n break\n }\n }\n\n private handleContentChunk(chunk: Extract<StreamChunk, { type: 'content' }>) {\n this.accumulatedContent = chunk.content\n aiEventClient.emit('stream:chunk:content', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n content: chunk.content,\n delta: chunk.delta,\n timestamp: Date.now(),\n })\n }\n\n private handleToolCallChunk(\n chunk: Extract<StreamChunk, { type: 'tool_call' }>,\n ): void {\n this.toolCallManager.addToolCallChunk(chunk)\n aiEventClient.emit('stream:chunk:tool-call', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: chunk.toolCall.id,\n toolName: chunk.toolCall.function.name,\n index: chunk.index,\n arguments: chunk.toolCall.function.arguments,\n timestamp: Date.now(),\n })\n }\n\n private handleToolResultChunk(\n chunk: Extract<StreamChunk, { type: 'tool_result' }>,\n ): void {\n aiEventClient.emit('stream:chunk:tool-result', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: chunk.toolCallId,\n result: chunk.content,\n timestamp: Date.now(),\n })\n }\n\n private handleDoneChunk(chunk: DoneStreamChunk): void {\n // Don't overwrite a tool_calls finishReason with a stop finishReason\n // This can happen when adapters send multiple done chunks\n if (\n this.doneChunk?.finishReason === 'tool_calls' &&\n chunk.finishReason === 'stop'\n ) {\n // Still emit the event and update lastFinishReason, but don't overwrite doneChunk\n this.lastFinishReason = chunk.finishReason\n aiEventClient.emit('stream:chunk:done', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n\n if (chunk.usage) {\n aiEventClient.emit('usage:tokens', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n model: this.params.model,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n }\n return\n }\n\n this.doneChunk = chunk\n this.lastFinishReason = chunk.finishReason\n aiEventClient.emit('stream:chunk:done', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n\n if (chunk.usage) {\n aiEventClient.emit('usage:tokens', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n model: this.params.model,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n }\n }\n\n private handleErrorChunk(\n chunk: Extract<StreamChunk, { type: 'error' }>,\n ): void {\n aiEventClient.emit('stream:chunk:error', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n error: chunk.error.message,\n timestamp: Date.now(),\n })\n this.earlyTermination = true\n this.shouldEmitStreamEnd = false\n }\n\n private handleThinkingChunk(\n chunk: Extract<StreamChunk, { type: 'thinking' }>,\n ): void {\n aiEventClient.emit('stream:chunk:thinking', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n content: chunk.content,\n delta: chunk.delta,\n timestamp: Date.now(),\n })\n }\n\n private async *checkForPendingToolCalls(): AsyncGenerator<\n StreamChunk,\n ToolPhaseResult,\n void\n > {\n const pendingToolCalls = this.getPendingToolCallsFromMessages()\n if (pendingToolCalls.length === 0) {\n return 'continue'\n }\n\n const doneChunk = this.createSyntheticDoneChunk()\n\n aiEventClient.emit('text:iteration', {\n requestId: this.requestId,\n streamId: this.streamId,\n iterationNumber: this.iterationCount + 1,\n messageCount: this.messages.length,\n toolCallCount: pendingToolCalls.length,\n timestamp: Date.now(),\n })\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const executionResult = await executeToolCalls(\n pendingToolCalls,\n this.tools,\n approvals,\n clientToolResults,\n )\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n for (const chunk of this.emitApprovalRequests(\n executionResult.needsApproval,\n doneChunk,\n )) {\n yield chunk\n }\n\n for (const chunk of this.emitClientToolInputs(\n executionResult.needsClientExecution,\n doneChunk,\n )) {\n yield chunk\n }\n\n this.shouldEmitStreamEnd = false\n return 'wait'\n }\n\n const toolResultChunks = this.emitToolResults(\n executionResult.results,\n doneChunk,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n return 'continue'\n }\n\n private async *processToolCalls(): AsyncGenerator<StreamChunk, void, void> {\n if (!this.shouldExecuteToolPhase()) {\n this.setToolPhase('stop')\n return\n }\n\n const toolCalls = this.toolCallManager.getToolCalls()\n const doneChunk = this.doneChunk\n\n if (!doneChunk || toolCalls.length === 0) {\n this.setToolPhase('stop')\n return\n }\n\n aiEventClient.emit('text:iteration', {\n requestId: this.requestId,\n streamId: this.streamId,\n iterationNumber: this.iterationCount + 1,\n messageCount: this.messages.length,\n toolCallCount: toolCalls.length,\n timestamp: Date.now(),\n })\n\n this.addAssistantToolCallMessage(toolCalls)\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const executionResult = await executeToolCalls(\n toolCalls,\n this.tools,\n approvals,\n clientToolResults,\n )\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n for (const chunk of this.emitApprovalRequests(\n executionResult.needsApproval,\n doneChunk,\n )) {\n yield chunk\n }\n\n for (const chunk of this.emitClientToolInputs(\n executionResult.needsClientExecution,\n doneChunk,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return\n }\n\n const toolResultChunks = this.emitToolResults(\n executionResult.results,\n doneChunk,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n this.toolCallManager.clear()\n\n this.setToolPhase('continue')\n }\n\n private shouldExecuteToolPhase(): boolean {\n return (\n this.doneChunk?.finishReason === 'tool_calls' &&\n this.tools.length > 0 &&\n this.toolCallManager.hasToolCalls()\n )\n }\n\n private addAssistantToolCallMessage(toolCalls: Array<ToolCall>): void {\n this.messages = [\n ...this.messages,\n {\n role: 'assistant',\n content: this.accumulatedContent || null,\n toolCalls,\n },\n ]\n }\n\n private collectClientState(): {\n approvals: Map<string, boolean>\n clientToolResults: Map<string, any>\n } {\n const approvals = new Map<string, boolean>()\n const clientToolResults = new Map<string, any>()\n\n for (const message of this.messages) {\n // todo remove any and fix this\n if (message.role === 'assistant' && (message as any).parts) {\n const parts = (message as any).parts\n for (const part of parts) {\n if (\n part.type === 'tool-call' &&\n part.state === 'approval-responded' &&\n part.approval\n ) {\n approvals.set(part.approval.id, part.approval.approved)\n }\n\n if (\n part.type === 'tool-call' &&\n part.output !== undefined &&\n !part.approval\n ) {\n clientToolResults.set(part.id, part.output)\n }\n }\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private emitApprovalRequests(\n approvals: Array<ApprovalRequest>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const approval of approvals) {\n aiEventClient.emit('stream:approval-requested', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: approval.toolCallId,\n toolName: approval.toolName,\n input: approval.input,\n approvalId: approval.approvalId,\n timestamp: Date.now(),\n })\n\n chunks.push({\n type: 'approval-requested',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: approval.toolCallId,\n toolName: approval.toolName,\n input: approval.input,\n approval: {\n id: approval.approvalId,\n needsApproval: true,\n },\n })\n }\n\n return chunks\n }\n\n private emitClientToolInputs(\n clientRequests: Array<ClientToolRequest>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const clientTool of clientRequests) {\n aiEventClient.emit('stream:tool-input-available', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n timestamp: Date.now(),\n })\n\n chunks.push({\n type: 'tool-input-available',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n })\n }\n\n return chunks\n }\n\n private emitToolResults(\n results: Array<ToolResult>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const result of results) {\n aiEventClient.emit('tool:call-completed', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: result.toolCallId,\n toolName: result.toolName,\n result: result.result,\n duration: result.duration ?? 0,\n timestamp: Date.now(),\n })\n\n const content = JSON.stringify(result.result)\n const chunk: Extract<StreamChunk, { type: 'tool_result' }> = {\n type: 'tool_result',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: result.toolCallId,\n content,\n }\n\n chunks.push(chunk)\n\n this.messages = [\n ...this.messages,\n {\n role: 'tool',\n content,\n toolCallId: result.toolCallId,\n },\n ]\n }\n\n return chunks\n }\n\n private getPendingToolCallsFromMessages(): Array<ToolCall> {\n const completedToolIds = new Set(\n this.messages\n .filter((message) => message.role === 'tool' && message.toolCallId)\n .map((message) => message.toolCallId!), // toolCallId exists due to filter\n )\n\n const pending: Array<ToolCall> = []\n\n for (const message of this.messages) {\n if (message.role === 'assistant' && message.toolCalls) {\n for (const toolCall of message.toolCalls) {\n if (!completedToolIds.has(toolCall.id)) {\n pending.push(toolCall)\n }\n }\n }\n }\n\n return pending\n }\n\n private createSyntheticDoneChunk(): DoneStreamChunk {\n return {\n type: 'done',\n id: this.createId('pending'),\n model: this.params.model,\n timestamp: Date.now(),\n finishReason: 'tool_calls',\n }\n }\n\n private shouldContinue(): boolean {\n if (this.cyclePhase === 'executeToolCalls') {\n return true\n }\n\n return (\n this.loopStrategy({\n iterationCount: this.iterationCount,\n messages: this.messages,\n finishReason: this.lastFinishReason,\n }) && this.toolPhase === 'continue'\n )\n }\n\n private isAborted(): boolean {\n return !!this.effectiveSignal?.aborted\n }\n\n private setToolPhase(phase: ToolPhaseResult): void {\n this.toolPhase = phase\n if (phase === 'wait') {\n this.shouldEmitStreamEnd = false\n }\n }\n\n private createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n }\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Text activity - handles agentic text generation, one-shot text generation, and agentic structured output.\n *\n * This activity supports four modes:\n * 1. **Streaming agentic text**: Stream responses with automatic tool execution\n * 2. **Streaming one-shot text**: Simple streaming request/response without tools\n * 3. **Non-streaming text**: Returns collected text as a string (stream: false)\n * 4. **Agentic structured output**: Run tools, then return structured data\n *\n * @example Full agentic text (streaming with tools)\n * ```ts\n * import { chat } from '@tanstack/ai'\n * import { openaiText } from '@tanstack/ai-openai'\n *\n * for await (const chunk of chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'What is the weather?' }],\n * tools: [weatherTool]\n * })) {\n * if (chunk.type === 'content') {\n * console.log(chunk.delta)\n * }\n * }\n * ```\n *\n * @example One-shot text (streaming without tools)\n * ```ts\n * for await (const chunk of chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Hello!' }]\n * })) {\n * console.log(chunk)\n * }\n * ```\n *\n * @example Non-streaming text (stream: false)\n * ```ts\n * const text = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Hello!' }],\n * stream: false\n * })\n * // text is a string with the full response\n * ```\n *\n * @example Agentic structured output (tools + structured response)\n * ```ts\n * import { z } from 'zod'\n *\n * const result = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Research and summarize the topic' }],\n * tools: [researchTool, analyzeTool],\n * outputSchema: z.object({\n * summary: z.string(),\n * keyPoints: z.array(z.string())\n * })\n * })\n * // result is { summary: string, keyPoints: string[] }\n * ```\n */\nexport function chat<\n TAdapter extends AnyTextAdapter,\n TSchema extends z.ZodType | undefined = undefined,\n TStream extends boolean = true,\n>(\n options: TextActivityOptions<TAdapter, TSchema, TStream>,\n): TextActivityResult<TSchema, TStream> {\n const { outputSchema, stream } = options\n\n // If outputSchema is provided, run agentic structured output\n if (outputSchema) {\n return runAgenticStructuredOutput(\n options as unknown as TextActivityOptions<\n AnyTextAdapter,\n z.ZodType,\n boolean\n >,\n ) as TextActivityResult<TSchema, TStream>\n }\n\n // If stream is explicitly false, run non-streaming text\n if (stream === false) {\n return runNonStreamingText(\n options as unknown as TextActivityOptions<\n AnyTextAdapter,\n undefined,\n false\n >,\n ) as TextActivityResult<TSchema, TStream>\n }\n\n // Otherwise, run streaming text (default)\n return runStreamingText(\n options as unknown as TextActivityOptions<AnyTextAdapter, undefined, true>,\n ) as TextActivityResult<TSchema, TStream>\n}\n\n/**\n * Run streaming text (agentic or one-shot depending on tools)\n */\nasync function* runStreamingText(\n options: TextActivityOptions<AnyTextAdapter, undefined, true>,\n): AsyncIterable<StreamChunk> {\n const { adapter, ...textOptions } = options\n const model = adapter.model\n\n const engine = new TextEngine({\n adapter,\n params: { ...textOptions, model } as TextOptions<\n Record<string, any>,\n Record<string, any>\n >,\n })\n\n for await (const chunk of engine.run()) {\n yield chunk\n }\n}\n\n/**\n * Run non-streaming text - collects all content and returns as a string.\n * Runs the full agentic loop (if tools are provided) but returns collected text.\n */\nfunction runNonStreamingText(\n options: TextActivityOptions<AnyTextAdapter, undefined, false>,\n): Promise<string> {\n // Run the streaming text and collect all text using streamToText\n const stream = runStreamingText(\n options as unknown as TextActivityOptions<AnyTextAdapter, undefined, true>,\n )\n\n return streamToText(stream)\n}\n\n/**\n * Run agentic structured output:\n * 1. Execute the full agentic loop (with tools)\n * 2. Once complete, call adapter.structuredOutput with the conversation context\n * 3. Validate and return the structured result\n */\nasync function runAgenticStructuredOutput<TSchema extends z.ZodType>(\n options: TextActivityOptions<AnyTextAdapter, TSchema, boolean>,\n): Promise<z.infer<TSchema>> {\n const { adapter, outputSchema, ...textOptions } = options\n const model = adapter.model\n\n if (!outputSchema) {\n throw new Error('outputSchema is required for structured output')\n }\n\n // Create the engine and run the agentic loop\n const engine = new TextEngine({\n adapter,\n params: { ...textOptions, model } as TextOptions<\n Record<string, any>,\n Record<string, any>\n >,\n })\n\n // Consume the stream to run the agentic loop\n for await (const _chunk of engine.run()) {\n // Just consume the stream to execute the agentic loop\n }\n\n // Get the final messages from the engine (includes tool results)\n const finalMessages = engine.getMessages()\n\n // Build text options for structured output, excluding tools since\n // the agentic loop is complete and we only need the final response\n const {\n tools: _tools,\n agentLoopStrategy: _als,\n ...structuredTextOptions\n } = textOptions\n\n // Convert the Zod schema to JSON Schema before passing to the adapter\n const jsonSchema = convertZodToJsonSchema(outputSchema)\n if (!jsonSchema) {\n throw new Error('Failed to convert output schema to JSON Schema')\n }\n\n // Call the adapter's structured output method with the conversation context\n // The adapter receives JSON Schema and can apply vendor-specific patches\n const result = await adapter.structuredOutput({\n chatOptions: {\n ...structuredTextOptions,\n model,\n messages: finalMessages,\n },\n outputSchema: jsonSchema,\n })\n\n // Validate the result against the Zod schema\n const validationResult = outputSchema.safeParse(result.data)\n if (!validationResult.success) {\n throw new Error(\n `Structured output validation failed: ${validationResult.error.message}`,\n )\n }\n\n return validationResult.data\n}\n\n// Re-export adapter types\nexport type {\n TextAdapter,\n TextAdapterConfig,\n StructuredOutputOptions,\n StructuredOutputResult,\n} from './adapter'\nexport { BaseTextAdapter } from './adapter'\n"],"names":["maxIterationsStrategy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/activities/chat/index.ts"],"sourcesContent":["/**\n * Text Activity\n *\n * Handles agentic text generation, one-shot text generation, and agentic structured output.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '../../event-client.js'\nimport { streamToText } from '../../stream-to-response.js'\nimport { ToolCallManager, executeToolCalls } from './tools/tool-calls'\nimport {\n convertSchemaToJsonSchema,\n isStandardSchema,\n parseWithStandardSchema,\n} from './tools/schema-converter'\nimport { maxIterations as maxIterationsStrategy } from './agent-loop-strategies'\nimport type {\n ApprovalRequest,\n ClientToolRequest,\n ToolResult,\n} from './tools/tool-calls'\nimport type { AnyTextAdapter } from './adapter'\nimport type {\n AgentLoopStrategy,\n ConstrainedModelMessage,\n DoneStreamChunk,\n InferSchemaType,\n ModelMessage,\n SchemaInput,\n StreamChunk,\n TextOptions,\n Tool,\n ToolCall,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'text' as const\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the text activity.\n * Types are extracted directly from the adapter (which has pre-resolved generics).\n *\n * @template TAdapter - The text adapter type (created by a provider function)\n * @template TSchema - Optional Standard Schema for structured output\n * @template TStream - Whether to stream the output (default: true)\n */\nexport interface TextActivityOptions<\n TAdapter extends AnyTextAdapter,\n TSchema extends SchemaInput | undefined,\n TStream extends boolean,\n> {\n /** The text adapter to use (created by a provider function like openaiText('gpt-4o')) */\n adapter: TAdapter\n /** Conversation messages - content types are constrained by the adapter's input modalities and metadata */\n messages?: Array<\n ConstrainedModelMessage<{\n inputModalities: TAdapter['~types']['inputModalities']\n messageMetadataByModality: TAdapter['~types']['messageMetadataByModality']\n }>\n >\n /** System prompts to prepend to the conversation */\n systemPrompts?: TextOptions['systemPrompts']\n /** Tools for function calling (auto-executed when called) */\n tools?: TextOptions['tools']\n /** Controls the randomness of the output. Higher values make output more random. Range: [0.0, 2.0] */\n temperature?: TextOptions['temperature']\n /** Nucleus sampling parameter. The model considers tokens with topP probability mass. */\n topP?: TextOptions['topP']\n /** The maximum number of tokens to generate in the response. */\n maxTokens?: TextOptions['maxTokens']\n /** Additional metadata to attach to the request. */\n metadata?: TextOptions['metadata']\n /** Model-specific provider options (type comes from adapter) */\n modelOptions?: TAdapter['~types']['providerOptions']\n /** AbortController for cancellation */\n abortController?: TextOptions['abortController']\n /** Strategy for controlling the agent loop */\n agentLoopStrategy?: TextOptions['agentLoopStrategy']\n /** Unique conversation identifier for tracking */\n conversationId?: TextOptions['conversationId']\n /**\n * Optional Standard Schema for structured output.\n * When provided, the activity will:\n * 1. Run the full agentic loop (executing tools as needed)\n * 2. Once complete, return a Promise with the parsed output matching the schema\n *\n * Supports any Standard Schema compliant library (Zod v4+, ArkType, Valibot, etc.)\n *\n * @example\n * ```ts\n * const result = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Generate a person' }],\n * outputSchema: z.object({ name: z.string(), age: z.number() })\n * })\n * // result is { name: string, age: number }\n * ```\n */\n outputSchema?: TSchema\n /**\n * Whether to stream the text result.\n * When true (default), returns an AsyncIterable<StreamChunk> for streaming output.\n * When false, returns a Promise<string> with the collected text content.\n *\n * Note: If outputSchema is provided, this option is ignored and the result\n * is always a Promise<InferSchemaType<TSchema>>.\n *\n * @default true\n *\n * @example Non-streaming text\n * ```ts\n * const text = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Hello!' }],\n * stream: false\n * })\n * // text is a string with the full response\n * ```\n */\n stream?: TStream\n}\n\n// ===========================\n// Chat Options Helper\n// ===========================\n\n/**\n * Create typed options for the chat() function without executing.\n * This is useful for pre-defining configurations with full type inference.\n *\n * @example\n * ```ts\n * const chatOptions = createChatOptions({\n * adapter: anthropicText('claude-sonnet-4-5'),\n * })\n *\n * const stream = chat({ ...chatOptions, messages })\n * ```\n */\nexport function createChatOptions<\n TAdapter extends AnyTextAdapter,\n TSchema extends SchemaInput | undefined = undefined,\n TStream extends boolean = true,\n>(\n options: TextActivityOptions<TAdapter, TSchema, TStream>,\n): TextActivityOptions<TAdapter, TSchema, TStream> {\n return options\n}\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the text activity.\n * - If outputSchema is provided: Promise<InferSchemaType<TSchema>>\n * - If stream is false: Promise<string>\n * - Otherwise (stream is true, default): AsyncIterable<StreamChunk>\n */\nexport type TextActivityResult<\n TSchema extends SchemaInput | undefined,\n TStream extends boolean = true,\n> = TSchema extends SchemaInput\n ? Promise<InferSchemaType<TSchema>>\n : TStream extends false\n ? Promise<string>\n : AsyncIterable<StreamChunk>\n\n// ===========================\n// ChatEngine Implementation\n// ===========================\n\ninterface TextEngineConfig<\n TAdapter extends AnyTextAdapter,\n TParams extends TextOptions<any, any> = TextOptions<any>,\n> {\n adapter: TAdapter\n systemPrompts?: Array<string>\n params: TParams\n}\n\ntype ToolPhaseResult = 'continue' | 'stop' | 'wait'\ntype CyclePhase = 'processText' | 'executeToolCalls'\n\nclass TextEngine<\n TAdapter extends AnyTextAdapter,\n TParams extends TextOptions<any, any> = TextOptions<any>,\n> {\n private readonly adapter: TAdapter\n private readonly params: TParams\n private readonly systemPrompts: Array<string>\n private readonly tools: ReadonlyArray<Tool>\n private readonly loopStrategy: AgentLoopStrategy\n private readonly toolCallManager: ToolCallManager\n private readonly initialMessageCount: number\n private readonly requestId: string\n private readonly streamId: string\n private readonly effectiveRequest?: Request | RequestInit\n private readonly effectiveSignal?: AbortSignal\n\n private messages: Array<ModelMessage>\n private iterationCount = 0\n private lastFinishReason: string | null = null\n private streamStartTime = 0\n private totalChunkCount = 0\n private currentMessageId: string | null = null\n private accumulatedContent = ''\n private doneChunk: DoneStreamChunk | null = null\n private shouldEmitStreamEnd = true\n private earlyTermination = false\n private toolPhase: ToolPhaseResult = 'continue'\n private cyclePhase: CyclePhase = 'processText'\n\n constructor(config: TextEngineConfig<TAdapter, TParams>) {\n this.adapter = config.adapter\n this.params = config.params\n this.systemPrompts = config.params.systemPrompts || []\n this.tools = config.params.tools || []\n this.loopStrategy =\n config.params.agentLoopStrategy || maxIterationsStrategy(5)\n this.toolCallManager = new ToolCallManager(this.tools)\n this.initialMessageCount = config.params.messages.length\n this.messages = config.params.messages\n this.requestId = this.createId('chat')\n this.streamId = this.createId('stream')\n this.effectiveRequest = config.params.abortController\n ? { signal: config.params.abortController.signal }\n : undefined\n this.effectiveSignal = config.params.abortController?.signal\n }\n\n /** Get the accumulated content after the chat loop completes */\n getAccumulatedContent(): string {\n return this.accumulatedContent\n }\n\n /** Get the final messages array after the chat loop completes */\n getMessages(): Array<ModelMessage> {\n return this.messages\n }\n\n async *run(): AsyncGenerator<StreamChunk> {\n this.beforeRun()\n\n try {\n const pendingPhase = yield* this.checkForPendingToolCalls()\n if (pendingPhase === 'wait') {\n return\n }\n\n do {\n if (this.earlyTermination || this.isAborted()) {\n return\n }\n\n this.beginCycle()\n\n if (this.cyclePhase === 'processText') {\n yield* this.streamModelResponse()\n } else {\n yield* this.processToolCalls()\n }\n\n this.endCycle()\n } while (this.shouldContinue())\n } finally {\n this.afterRun()\n }\n }\n\n private beforeRun(): void {\n this.streamStartTime = Date.now()\n const {\n model,\n tools,\n temperature,\n topP,\n maxTokens,\n metadata,\n modelOptions,\n conversationId,\n } = this.params\n\n // Gather flattened options into an object for event emission\n const options: Record<string, unknown> = {}\n if (temperature !== undefined) options.temperature = temperature\n if (topP !== undefined) options.topP = topP\n if (maxTokens !== undefined) options.maxTokens = maxTokens\n if (metadata !== undefined) options.metadata = metadata\n\n aiEventClient.emit('text:started', {\n requestId: this.requestId,\n streamId: this.streamId,\n model: model,\n provider: this.adapter.name,\n messageCount: this.initialMessageCount,\n hasTools: !!tools && tools.length > 0,\n streaming: true,\n timestamp: Date.now(),\n clientId: conversationId,\n toolNames: tools?.map((t) => t.name),\n options: Object.keys(options).length > 0 ? options : undefined,\n modelOptions: modelOptions as Record<string, unknown> | undefined,\n })\n\n aiEventClient.emit('stream:started', {\n streamId: this.streamId,\n model,\n provider: this.adapter.name,\n timestamp: Date.now(),\n })\n }\n\n private afterRun(): void {\n if (!this.shouldEmitStreamEnd) {\n return\n }\n\n const now = Date.now()\n\n // Emit text:completed with final state\n aiEventClient.emit('text:completed', {\n requestId: this.requestId,\n streamId: this.streamId,\n model: this.params.model,\n content: this.accumulatedContent,\n messageId: this.currentMessageId || undefined,\n finishReason: this.lastFinishReason || undefined,\n usage: this.doneChunk?.usage,\n timestamp: now,\n })\n\n aiEventClient.emit('stream:ended', {\n requestId: this.requestId,\n streamId: this.streamId,\n totalChunks: this.totalChunkCount,\n duration: now - this.streamStartTime,\n timestamp: now,\n })\n }\n\n private beginCycle(): void {\n if (this.cyclePhase === 'processText') {\n this.beginIteration()\n }\n }\n\n private endCycle(): void {\n if (this.cyclePhase === 'processText') {\n this.cyclePhase = 'executeToolCalls'\n return\n }\n\n this.cyclePhase = 'processText'\n this.iterationCount++\n }\n\n private beginIteration(): void {\n this.currentMessageId = this.createId('msg')\n this.accumulatedContent = ''\n this.doneChunk = null\n }\n\n private async *streamModelResponse(): AsyncGenerator<StreamChunk> {\n const { temperature, topP, maxTokens, metadata, modelOptions } = this.params\n const tools = this.params.tools\n\n // Convert tool schemas to JSON Schema before passing to adapter\n const toolsWithJsonSchemas = tools?.map((tool) => ({\n ...tool,\n inputSchema: tool.inputSchema\n ? convertSchemaToJsonSchema(tool.inputSchema)\n : undefined,\n outputSchema: tool.outputSchema\n ? convertSchemaToJsonSchema(tool.outputSchema)\n : undefined,\n }))\n\n for await (const chunk of this.adapter.chatStream({\n model: this.params.model,\n messages: this.messages,\n tools: toolsWithJsonSchemas,\n temperature,\n topP,\n maxTokens,\n metadata,\n request: this.effectiveRequest,\n modelOptions,\n systemPrompts: this.systemPrompts,\n })) {\n if (this.isAborted()) {\n break\n }\n\n this.totalChunkCount++\n\n yield chunk\n this.handleStreamChunk(chunk)\n\n if (this.earlyTermination) {\n break\n }\n }\n }\n\n private handleStreamChunk(chunk: StreamChunk): void {\n switch (chunk.type) {\n case 'content':\n this.handleContentChunk(chunk)\n break\n case 'tool_call':\n this.handleToolCallChunk(chunk)\n break\n case 'tool_result':\n this.handleToolResultChunk(chunk)\n break\n case 'done':\n this.handleDoneChunk(chunk)\n break\n case 'error':\n this.handleErrorChunk(chunk)\n break\n case 'thinking':\n this.handleThinkingChunk(chunk)\n break\n default:\n break\n }\n }\n\n private handleContentChunk(chunk: Extract<StreamChunk, { type: 'content' }>) {\n this.accumulatedContent = chunk.content\n aiEventClient.emit('stream:chunk:content', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n content: chunk.content,\n delta: chunk.delta,\n timestamp: Date.now(),\n })\n }\n\n private handleToolCallChunk(\n chunk: Extract<StreamChunk, { type: 'tool_call' }>,\n ): void {\n this.toolCallManager.addToolCallChunk(chunk)\n aiEventClient.emit('stream:chunk:tool-call', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: chunk.toolCall.id,\n toolName: chunk.toolCall.function.name,\n index: chunk.index,\n arguments: chunk.toolCall.function.arguments,\n timestamp: Date.now(),\n })\n }\n\n private handleToolResultChunk(\n chunk: Extract<StreamChunk, { type: 'tool_result' }>,\n ): void {\n aiEventClient.emit('stream:chunk:tool-result', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: chunk.toolCallId,\n result: chunk.content,\n timestamp: Date.now(),\n })\n }\n\n private handleDoneChunk(chunk: DoneStreamChunk): void {\n // Don't overwrite a tool_calls finishReason with a stop finishReason\n // This can happen when adapters send multiple done chunks\n if (\n this.doneChunk?.finishReason === 'tool_calls' &&\n chunk.finishReason === 'stop'\n ) {\n // Still emit the event and update lastFinishReason, but don't overwrite doneChunk\n this.lastFinishReason = chunk.finishReason\n aiEventClient.emit('stream:chunk:done', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n\n if (chunk.usage) {\n aiEventClient.emit('usage:tokens', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n model: this.params.model,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n }\n return\n }\n\n this.doneChunk = chunk\n this.lastFinishReason = chunk.finishReason\n aiEventClient.emit('stream:chunk:done', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n finishReason: chunk.finishReason,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n\n if (chunk.usage) {\n aiEventClient.emit('usage:tokens', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n model: this.params.model,\n usage: chunk.usage,\n timestamp: Date.now(),\n })\n }\n }\n\n private handleErrorChunk(\n chunk: Extract<StreamChunk, { type: 'error' }>,\n ): void {\n aiEventClient.emit('stream:chunk:error', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n error: chunk.error.message,\n timestamp: Date.now(),\n })\n this.earlyTermination = true\n this.shouldEmitStreamEnd = false\n }\n\n private handleThinkingChunk(\n chunk: Extract<StreamChunk, { type: 'thinking' }>,\n ): void {\n aiEventClient.emit('stream:chunk:thinking', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n content: chunk.content,\n delta: chunk.delta,\n timestamp: Date.now(),\n })\n }\n\n private async *checkForPendingToolCalls(): AsyncGenerator<\n StreamChunk,\n ToolPhaseResult,\n void\n > {\n const pendingToolCalls = this.getPendingToolCallsFromMessages()\n if (pendingToolCalls.length === 0) {\n return 'continue'\n }\n\n const doneChunk = this.createSyntheticDoneChunk()\n\n aiEventClient.emit('text:iteration', {\n requestId: this.requestId,\n streamId: this.streamId,\n iterationNumber: this.iterationCount + 1,\n messageCount: this.messages.length,\n toolCallCount: pendingToolCalls.length,\n timestamp: Date.now(),\n })\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const executionResult = await executeToolCalls(\n pendingToolCalls,\n this.tools,\n approvals,\n clientToolResults,\n )\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n for (const chunk of this.emitApprovalRequests(\n executionResult.needsApproval,\n doneChunk,\n )) {\n yield chunk\n }\n\n for (const chunk of this.emitClientToolInputs(\n executionResult.needsClientExecution,\n doneChunk,\n )) {\n yield chunk\n }\n\n this.shouldEmitStreamEnd = false\n return 'wait'\n }\n\n const toolResultChunks = this.emitToolResults(\n executionResult.results,\n doneChunk,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n return 'continue'\n }\n\n private async *processToolCalls(): AsyncGenerator<StreamChunk, void, void> {\n if (!this.shouldExecuteToolPhase()) {\n this.setToolPhase('stop')\n return\n }\n\n const toolCalls = this.toolCallManager.getToolCalls()\n const doneChunk = this.doneChunk\n\n if (!doneChunk || toolCalls.length === 0) {\n this.setToolPhase('stop')\n return\n }\n\n aiEventClient.emit('text:iteration', {\n requestId: this.requestId,\n streamId: this.streamId,\n iterationNumber: this.iterationCount + 1,\n messageCount: this.messages.length,\n toolCallCount: toolCalls.length,\n timestamp: Date.now(),\n })\n\n this.addAssistantToolCallMessage(toolCalls)\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const executionResult = await executeToolCalls(\n toolCalls,\n this.tools,\n approvals,\n clientToolResults,\n )\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n for (const chunk of this.emitApprovalRequests(\n executionResult.needsApproval,\n doneChunk,\n )) {\n yield chunk\n }\n\n for (const chunk of this.emitClientToolInputs(\n executionResult.needsClientExecution,\n doneChunk,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return\n }\n\n const toolResultChunks = this.emitToolResults(\n executionResult.results,\n doneChunk,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n this.toolCallManager.clear()\n\n this.setToolPhase('continue')\n }\n\n private shouldExecuteToolPhase(): boolean {\n return (\n this.doneChunk?.finishReason === 'tool_calls' &&\n this.tools.length > 0 &&\n this.toolCallManager.hasToolCalls()\n )\n }\n\n private addAssistantToolCallMessage(toolCalls: Array<ToolCall>): void {\n this.messages = [\n ...this.messages,\n {\n role: 'assistant',\n content: this.accumulatedContent || null,\n toolCalls,\n },\n ]\n }\n\n private collectClientState(): {\n approvals: Map<string, boolean>\n clientToolResults: Map<string, any>\n } {\n const approvals = new Map<string, boolean>()\n const clientToolResults = new Map<string, any>()\n\n for (const message of this.messages) {\n // todo remove any and fix this\n if (message.role === 'assistant' && (message as any).parts) {\n const parts = (message as any).parts\n for (const part of parts) {\n if (\n part.type === 'tool-call' &&\n part.state === 'approval-responded' &&\n part.approval\n ) {\n approvals.set(part.approval.id, part.approval.approved)\n }\n\n if (\n part.type === 'tool-call' &&\n part.output !== undefined &&\n !part.approval\n ) {\n clientToolResults.set(part.id, part.output)\n }\n }\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private emitApprovalRequests(\n approvals: Array<ApprovalRequest>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const approval of approvals) {\n aiEventClient.emit('stream:approval-requested', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: approval.toolCallId,\n toolName: approval.toolName,\n input: approval.input,\n approvalId: approval.approvalId,\n timestamp: Date.now(),\n })\n\n chunks.push({\n type: 'approval-requested',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: approval.toolCallId,\n toolName: approval.toolName,\n input: approval.input,\n approval: {\n id: approval.approvalId,\n needsApproval: true,\n },\n })\n }\n\n return chunks\n }\n\n private emitClientToolInputs(\n clientRequests: Array<ClientToolRequest>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const clientTool of clientRequests) {\n aiEventClient.emit('stream:tool-input-available', {\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n timestamp: Date.now(),\n })\n\n chunks.push({\n type: 'tool-input-available',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n })\n }\n\n return chunks\n }\n\n private emitToolResults(\n results: Array<ToolResult>,\n doneChunk: DoneStreamChunk,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const result of results) {\n aiEventClient.emit('tool:call-completed', {\n requestId: this.requestId,\n streamId: this.streamId,\n messageId: this.currentMessageId || undefined,\n toolCallId: result.toolCallId,\n toolName: result.toolName,\n result: result.result,\n duration: result.duration ?? 0,\n timestamp: Date.now(),\n })\n\n const content = JSON.stringify(result.result)\n const chunk: Extract<StreamChunk, { type: 'tool_result' }> = {\n type: 'tool_result',\n id: doneChunk.id,\n model: doneChunk.model,\n timestamp: Date.now(),\n toolCallId: result.toolCallId,\n content,\n }\n\n chunks.push(chunk)\n\n this.messages = [\n ...this.messages,\n {\n role: 'tool',\n content,\n toolCallId: result.toolCallId,\n },\n ]\n }\n\n return chunks\n }\n\n private getPendingToolCallsFromMessages(): Array<ToolCall> {\n const completedToolIds = new Set(\n this.messages\n .filter((message) => message.role === 'tool' && message.toolCallId)\n .map((message) => message.toolCallId!), // toolCallId exists due to filter\n )\n\n const pending: Array<ToolCall> = []\n\n for (const message of this.messages) {\n if (message.role === 'assistant' && message.toolCalls) {\n for (const toolCall of message.toolCalls) {\n if (!completedToolIds.has(toolCall.id)) {\n pending.push(toolCall)\n }\n }\n }\n }\n\n return pending\n }\n\n private createSyntheticDoneChunk(): DoneStreamChunk {\n return {\n type: 'done',\n id: this.createId('pending'),\n model: this.params.model,\n timestamp: Date.now(),\n finishReason: 'tool_calls',\n }\n }\n\n private shouldContinue(): boolean {\n if (this.cyclePhase === 'executeToolCalls') {\n return true\n }\n\n return (\n this.loopStrategy({\n iterationCount: this.iterationCount,\n messages: this.messages,\n finishReason: this.lastFinishReason,\n }) && this.toolPhase === 'continue'\n )\n }\n\n private isAborted(): boolean {\n return !!this.effectiveSignal?.aborted\n }\n\n private setToolPhase(phase: ToolPhaseResult): void {\n this.toolPhase = phase\n if (phase === 'wait') {\n this.shouldEmitStreamEnd = false\n }\n }\n\n private createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n }\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Text activity - handles agentic text generation, one-shot text generation, and agentic structured output.\n *\n * This activity supports four modes:\n * 1. **Streaming agentic text**: Stream responses with automatic tool execution\n * 2. **Streaming one-shot text**: Simple streaming request/response without tools\n * 3. **Non-streaming text**: Returns collected text as a string (stream: false)\n * 4. **Agentic structured output**: Run tools, then return structured data\n *\n * @example Full agentic text (streaming with tools)\n * ```ts\n * import { chat } from '@tanstack/ai'\n * import { openaiText } from '@tanstack/ai-openai'\n *\n * for await (const chunk of chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'What is the weather?' }],\n * tools: [weatherTool]\n * })) {\n * if (chunk.type === 'content') {\n * console.log(chunk.delta)\n * }\n * }\n * ```\n *\n * @example One-shot text (streaming without tools)\n * ```ts\n * for await (const chunk of chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Hello!' }]\n * })) {\n * console.log(chunk)\n * }\n * ```\n *\n * @example Non-streaming text (stream: false)\n * ```ts\n * const text = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Hello!' }],\n * stream: false\n * })\n * // text is a string with the full response\n * ```\n *\n * @example Agentic structured output (tools + structured response)\n * ```ts\n * import { z } from 'zod'\n *\n * const result = await chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [{ role: 'user', content: 'Research and summarize the topic' }],\n * tools: [researchTool, analyzeTool],\n * outputSchema: z.object({\n * summary: z.string(),\n * keyPoints: z.array(z.string())\n * })\n * })\n * // result is { summary: string, keyPoints: string[] }\n * ```\n */\nexport function chat<\n TAdapter extends AnyTextAdapter,\n TSchema extends SchemaInput | undefined = undefined,\n TStream extends boolean = true,\n>(\n options: TextActivityOptions<TAdapter, TSchema, TStream>,\n): TextActivityResult<TSchema, TStream> {\n const { outputSchema, stream } = options\n\n // If outputSchema is provided, run agentic structured output\n if (outputSchema) {\n return runAgenticStructuredOutput(\n options as unknown as TextActivityOptions<\n AnyTextAdapter,\n SchemaInput,\n boolean\n >,\n ) as TextActivityResult<TSchema, TStream>\n }\n\n // If stream is explicitly false, run non-streaming text\n if (stream === false) {\n return runNonStreamingText(\n options as unknown as TextActivityOptions<\n AnyTextAdapter,\n undefined,\n false\n >,\n ) as TextActivityResult<TSchema, TStream>\n }\n\n // Otherwise, run streaming text (default)\n return runStreamingText(\n options as unknown as TextActivityOptions<AnyTextAdapter, undefined, true>,\n ) as TextActivityResult<TSchema, TStream>\n}\n\n/**\n * Run streaming text (agentic or one-shot depending on tools)\n */\nasync function* runStreamingText(\n options: TextActivityOptions<AnyTextAdapter, undefined, true>,\n): AsyncIterable<StreamChunk> {\n const { adapter, ...textOptions } = options\n const model = adapter.model\n\n const engine = new TextEngine({\n adapter,\n params: { ...textOptions, model } as TextOptions<\n Record<string, any>,\n Record<string, any>\n >,\n })\n\n for await (const chunk of engine.run()) {\n yield chunk\n }\n}\n\n/**\n * Run non-streaming text - collects all content and returns as a string.\n * Runs the full agentic loop (if tools are provided) but returns collected text.\n */\nfunction runNonStreamingText(\n options: TextActivityOptions<AnyTextAdapter, undefined, false>,\n): Promise<string> {\n // Run the streaming text and collect all text using streamToText\n const stream = runStreamingText(\n options as unknown as TextActivityOptions<AnyTextAdapter, undefined, true>,\n )\n\n return streamToText(stream)\n}\n\n/**\n * Run agentic structured output:\n * 1. Execute the full agentic loop (with tools)\n * 2. Once complete, call adapter.structuredOutput with the conversation context\n * 3. Validate and return the structured result\n */\nasync function runAgenticStructuredOutput<TSchema extends SchemaInput>(\n options: TextActivityOptions<AnyTextAdapter, TSchema, boolean>,\n): Promise<InferSchemaType<TSchema>> {\n const { adapter, outputSchema, ...textOptions } = options\n const model = adapter.model\n\n if (!outputSchema) {\n throw new Error('outputSchema is required for structured output')\n }\n\n // Create the engine and run the agentic loop\n const engine = new TextEngine({\n adapter,\n params: { ...textOptions, model } as TextOptions<\n Record<string, unknown>,\n Record<string, unknown>\n >,\n })\n\n // Consume the stream to run the agentic loop\n for await (const _chunk of engine.run()) {\n // Just consume the stream to execute the agentic loop\n }\n\n // Get the final messages from the engine (includes tool results)\n const finalMessages = engine.getMessages()\n\n // Build text options for structured output, excluding tools since\n // the agentic loop is complete and we only need the final response\n const {\n tools: _tools,\n agentLoopStrategy: _als,\n ...structuredTextOptions\n } = textOptions\n\n // Convert the schema to JSON Schema before passing to the adapter\n const jsonSchema = convertSchemaToJsonSchema(outputSchema)\n if (!jsonSchema) {\n throw new Error('Failed to convert output schema to JSON Schema')\n }\n\n // Call the adapter's structured output method with the conversation context\n // The adapter receives JSON Schema and can apply vendor-specific patches\n const result = await adapter.structuredOutput({\n chatOptions: {\n ...structuredTextOptions,\n model,\n messages: finalMessages,\n },\n outputSchema: jsonSchema,\n })\n\n // Validate the result against the schema if it's a Standard Schema\n if (isStandardSchema(outputSchema)) {\n return parseWithStandardSchema<InferSchemaType<TSchema>>(\n outputSchema,\n result.data,\n )\n }\n\n // For plain JSON Schema, return the data as-is\n return result.data as InferSchemaType<TSchema>\n}\n\n// Re-export adapter types\nexport type {\n TextAdapter,\n TextAdapterConfig,\n StructuredOutputOptions,\n StructuredOutputResult,\n} from './adapter'\nexport { BaseTextAdapter } from './adapter'\n"],"names":["maxIterationsStrategy"],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
import { JSONSchema, SchemaInput } from '../../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Check if a value is a Standard JSON Schema compliant schema.
|
|
5
|
+
* Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)
|
|
6
|
+
* implement the '~standard' property with jsonSchema converter methods.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isStandardJSONSchema(schema: unknown): schema is StandardJSONSchemaV1;
|
|
9
|
+
/**
|
|
10
|
+
* Check if a value is a Standard Schema compliant schema (for validation).
|
|
11
|
+
* Standard Schema compliant libraries implement the '~standard' property with a validate function.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isStandardSchema(schema: unknown): schema is StandardSchemaV1;
|
|
14
|
+
/**
|
|
15
|
+
* Options for schema conversion
|
|
16
|
+
*/
|
|
17
|
+
export interface ConvertSchemaOptions {
|
|
18
|
+
/**
|
|
19
|
+
* When true, transforms the schema to be compatible with OpenAI's structured output requirements:
|
|
20
|
+
* - All properties are added to the `required` array
|
|
21
|
+
* - Optional fields get null added to their type union
|
|
22
|
+
* - additionalProperties is set to false for all objects
|
|
23
|
+
*
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
forStructuredOutput?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format
|
|
30
|
+
* compatible with LLM providers.
|
|
31
|
+
*
|
|
32
|
+
* Supports any schema library that implements the Standard JSON Schema spec (v1):
|
|
33
|
+
* - Zod v4+ (natively supports StandardJSONSchemaV1)
|
|
34
|
+
* - ArkType (natively supports StandardJSONSchemaV1)
|
|
35
|
+
* - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)
|
|
36
|
+
*
|
|
37
|
+
* If the input is already a plain JSONSchema object, it is returned as-is.
|
|
38
|
+
*
|
|
39
|
+
* @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert
|
|
40
|
+
* @param options - Conversion options
|
|
41
|
+
* @returns JSON Schema object that can be sent to LLM providers
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // Using Zod v4+ (natively supports Standard JSON Schema)
|
|
46
|
+
* import * as z from 'zod';
|
|
47
|
+
*
|
|
48
|
+
* const zodSchema = z.object({
|
|
49
|
+
* location: z.string().describe('City name'),
|
|
50
|
+
* unit: z.enum(['celsius', 'fahrenheit']).optional()
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* const jsonSchema = convertSchemaToJsonSchema(zodSchema);
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Using ArkType (natively supports Standard JSON Schema)
|
|
57
|
+
* import { type } from 'arktype';
|
|
58
|
+
*
|
|
59
|
+
* const arkSchema = type({
|
|
60
|
+
* location: 'string',
|
|
61
|
+
* unit: "'celsius' | 'fahrenheit'"
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* const jsonSchema = convertSchemaToJsonSchema(arkSchema);
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Using Valibot (via toStandardJsonSchema)
|
|
68
|
+
* import * as v from 'valibot';
|
|
69
|
+
* import { toStandardJsonSchema } from '@valibot/to-json-schema';
|
|
70
|
+
*
|
|
71
|
+
* const valibotSchema = toStandardJsonSchema(v.object({
|
|
72
|
+
* location: v.string(),
|
|
73
|
+
* unit: v.optional(v.picklist(['celsius', 'fahrenheit']))
|
|
74
|
+
* }));
|
|
75
|
+
*
|
|
76
|
+
* const jsonSchema = convertSchemaToJsonSchema(valibotSchema);
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Using JSONSchema directly (passes through unchanged)
|
|
80
|
+
* const rawSchema = {
|
|
81
|
+
* type: 'object',
|
|
82
|
+
* properties: { location: { type: 'string' } },
|
|
83
|
+
* required: ['location']
|
|
84
|
+
* };
|
|
85
|
+
* const result = convertSchemaToJsonSchema(rawSchema);
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function convertSchemaToJsonSchema(schema: SchemaInput | undefined, options?: ConvertSchemaOptions): JSONSchema | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* Validates data against a Standard Schema compliant schema.
|
|
91
|
+
*
|
|
92
|
+
* @param schema - Standard Schema compliant schema
|
|
93
|
+
* @param data - Data to validate
|
|
94
|
+
* @returns Validation result with success status, data or issues
|
|
95
|
+
*/
|
|
96
|
+
export declare function validateWithStandardSchema<T>(schema: unknown, data: unknown): Promise<{
|
|
97
|
+
success: true;
|
|
98
|
+
data: T;
|
|
99
|
+
} | {
|
|
100
|
+
success: false;
|
|
101
|
+
issues: Array<{
|
|
102
|
+
message: string;
|
|
103
|
+
path?: Array<string>;
|
|
104
|
+
}>;
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Synchronously validates data against a Standard Schema compliant schema.
|
|
108
|
+
* Note: Some Standard Schema implementations may only support async validation.
|
|
109
|
+
* In those cases, this function will throw.
|
|
110
|
+
*
|
|
111
|
+
* @param schema - Standard Schema compliant schema
|
|
112
|
+
* @param data - Data to validate
|
|
113
|
+
* @returns Parsed/validated data
|
|
114
|
+
* @throws Error if validation fails or if the schema only supports async validation
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseWithStandardSchema<T>(schema: unknown, data: unknown): T;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
function isStandardJSONSchema(schema) {
|
|
2
|
+
return typeof schema === "object" && schema !== null && "~standard" in schema && typeof schema["~standard"] === "object" && schema["~standard"].version === 1 && typeof schema["~standard"].jsonSchema === "object" && typeof schema["~standard"].jsonSchema.input === "function";
|
|
3
|
+
}
|
|
4
|
+
function isStandardSchema(schema) {
|
|
5
|
+
return typeof schema === "object" && schema !== null && "~standard" in schema && typeof schema["~standard"] === "object" && schema !== null && schema["~standard"] !== null && "version" in schema["~standard"] && schema["~standard"].version === 1 && "validate" in schema["~standard"] && typeof schema["~standard"].validate === "function";
|
|
6
|
+
}
|
|
7
|
+
function makeStructuredOutputCompatible(schema, originalRequired = []) {
|
|
8
|
+
const result = { ...schema };
|
|
9
|
+
if (result.type === "object" && result.properties) {
|
|
10
|
+
const properties = { ...result.properties };
|
|
11
|
+
const allPropertyNames = Object.keys(properties);
|
|
12
|
+
for (const propName of allPropertyNames) {
|
|
13
|
+
const prop = properties[propName];
|
|
14
|
+
const wasOptional = !originalRequired.includes(propName);
|
|
15
|
+
if (prop.type === "object" && prop.properties) {
|
|
16
|
+
properties[propName] = makeStructuredOutputCompatible(
|
|
17
|
+
prop,
|
|
18
|
+
prop.required || []
|
|
19
|
+
);
|
|
20
|
+
} else if (prop.type === "array" && prop.items) {
|
|
21
|
+
properties[propName] = {
|
|
22
|
+
...prop,
|
|
23
|
+
items: makeStructuredOutputCompatible(
|
|
24
|
+
prop.items,
|
|
25
|
+
prop.items.required || []
|
|
26
|
+
)
|
|
27
|
+
};
|
|
28
|
+
} else if (wasOptional) {
|
|
29
|
+
if (prop.type && !Array.isArray(prop.type)) {
|
|
30
|
+
properties[propName] = {
|
|
31
|
+
...prop,
|
|
32
|
+
type: [prop.type, "null"]
|
|
33
|
+
};
|
|
34
|
+
} else if (Array.isArray(prop.type) && !prop.type.includes("null")) {
|
|
35
|
+
properties[propName] = {
|
|
36
|
+
...prop,
|
|
37
|
+
type: [...prop.type, "null"]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
result.properties = properties;
|
|
43
|
+
result.required = allPropertyNames;
|
|
44
|
+
result.additionalProperties = false;
|
|
45
|
+
}
|
|
46
|
+
if (result.type === "array" && result.items) {
|
|
47
|
+
result.items = makeStructuredOutputCompatible(
|
|
48
|
+
result.items,
|
|
49
|
+
result.items.required || []
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function convertSchemaToJsonSchema(schema, options = {}) {
|
|
55
|
+
if (!schema) return void 0;
|
|
56
|
+
const { forStructuredOutput = false } = options;
|
|
57
|
+
if (isStandardJSONSchema(schema)) {
|
|
58
|
+
const jsonSchema = schema["~standard"].jsonSchema.input({
|
|
59
|
+
target: "draft-07"
|
|
60
|
+
});
|
|
61
|
+
let result = jsonSchema;
|
|
62
|
+
if (typeof result === "object" && "$schema" in result) {
|
|
63
|
+
const { $schema, ...rest } = result;
|
|
64
|
+
result = rest;
|
|
65
|
+
}
|
|
66
|
+
if (typeof result === "object") {
|
|
67
|
+
if ("properties" in result && !result.type) {
|
|
68
|
+
result.type = "object";
|
|
69
|
+
}
|
|
70
|
+
if (result.type === "object" && !("properties" in result)) {
|
|
71
|
+
result.properties = {};
|
|
72
|
+
}
|
|
73
|
+
if (result.type === "object" && !("required" in result)) {
|
|
74
|
+
result.required = [];
|
|
75
|
+
}
|
|
76
|
+
if (forStructuredOutput) {
|
|
77
|
+
result = makeStructuredOutputCompatible(
|
|
78
|
+
result,
|
|
79
|
+
result.required || []
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
if (forStructuredOutput && typeof schema === "object") {
|
|
86
|
+
return makeStructuredOutputCompatible(
|
|
87
|
+
schema,
|
|
88
|
+
schema.required || []
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return schema;
|
|
92
|
+
}
|
|
93
|
+
function parseWithStandardSchema(schema, data) {
|
|
94
|
+
if (!isStandardSchema(schema)) {
|
|
95
|
+
return data;
|
|
96
|
+
}
|
|
97
|
+
const result = schema["~standard"].validate(data);
|
|
98
|
+
if (result instanceof Promise) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
"Schema validation returned a Promise. Use validateWithStandardSchema for async validation."
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (!result.issues) {
|
|
104
|
+
return result.value;
|
|
105
|
+
}
|
|
106
|
+
const errorMessages = result.issues.map((issue) => issue.message || "Validation failed").join(", ");
|
|
107
|
+
throw new Error(`Validation failed: ${errorMessages}`);
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
convertSchemaToJsonSchema,
|
|
111
|
+
isStandardJSONSchema,
|
|
112
|
+
isStandardSchema,
|
|
113
|
+
parseWithStandardSchema
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=schema-converter.js.map
|