@tanstack/ai 0.8.1 → 0.9.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 CHANGED
@@ -87,8 +87,8 @@ Available adapters: `openaiText`, `openaiEmbed`, `openaiSummarize`, `anthropicTe
87
87
  <td>
88
88
  <a href="https://www.coderabbit.ai/?via=tanstack&dub_id=aCcEEdAOqqutX6OS" >
89
89
  <picture>
90
- <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/coderabbit-dark-D643Zkrv.svg" height="40" />
91
- <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/coderabbit-light-CIzGLYU_.svg" height="40" />
90
+ <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/coderabbit-dark-D643Zkrv.svg" />
91
+ <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/coderabbit-light-CIzGLYU_.svg" />
92
92
  <img src="https://tanstack.com/assets/coderabbit-light-CIzGLYU_.svg" height="40" alt="CodeRabbit" />
93
93
  </picture>
94
94
  </a>
@@ -96,9 +96,9 @@ Available adapters: `openaiText`, `openaiEmbed`, `openaiSummarize`, `anthropicTe
96
96
  <td>
97
97
  <a href="https://www.cloudflare.com?utm_source=tanstack">
98
98
  <picture>
99
- <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/cloudflare-white-Co-Tyjbl.svg" height="60" />
100
- <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/cloudflare-black-6Ojsn8yh.svg" height="60" />
101
- <img src="https://tanstack.com/assets/cloudflare-black-6Ojsn8yh.svg" height="60" alt="Cloudflare" />
99
+ <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/cloudflare-white-Co-Tyjbl.svg" />
100
+ <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/cloudflare-black-6Ojsn8yh.svg" />
101
+ <img src="https://tanstack.com/assets/cloudflare-white-Co-Tyjbl.svg" height="60" alt="Cloudflare" />
102
102
  </picture>
103
103
  </a>
104
104
  </td>
@@ -1,5 +1,6 @@
1
1
  import { devtoolsMiddleware } from "@tanstack/ai-event-client";
2
2
  import { streamToText } from "../../stream-to-response.js";
3
+ import { LazyToolManager } from "./tools/lazy-tool-manager.js";
3
4
  import { ToolCallManager, MiddlewareAbortError, executeToolCalls } from "./tools/tool-calls.js";
4
5
  import { convertSchemaToJsonSchema, isStandardSchema, parseWithStandardSchema } from "./tools/schema-converter.js";
5
6
  import { maxIterations } from "./agent-loop-strategies.js";
@@ -26,9 +27,7 @@ class TextEngine {
26
27
  this.adapter = config.adapter;
27
28
  this.params = config.params;
28
29
  this.systemPrompts = config.params.systemPrompts || [];
29
- this.tools = config.params.tools || [];
30
30
  this.loopStrategy = config.params.agentLoopStrategy || maxIterations(5);
31
- this.toolCallManager = new ToolCallManager(this.tools);
32
31
  this.initialMessageCount = config.params.messages.length;
33
32
  const { approvals, clientToolResults } = this.extractClientStateFromOriginalMessages(
34
33
  config.params.messages
@@ -38,6 +37,12 @@ class TextEngine {
38
37
  this.messages = convertMessagesToModelMessages(
39
38
  config.params.messages
40
39
  );
40
+ this.lazyToolManager = new LazyToolManager(
41
+ config.params.tools || [],
42
+ this.messages
43
+ );
44
+ this.tools = this.lazyToolManager.getActiveTools();
45
+ this.toolCallManager = new ToolCallManager(this.tools);
41
46
  this.requestId = this.createId("chat");
42
47
  this.streamId = this.createId("stream");
43
48
  this.effectiveRequest = config.params.abortController ? { signal: config.params.abortController.signal } : void 0;
@@ -306,9 +311,37 @@ class TextEngine {
306
311
  return "continue";
307
312
  }
308
313
  const finishEvent = this.createSyntheticFinishedEvent();
314
+ const undiscoveredLazyResults = [];
315
+ const executablePendingCalls = pendingToolCalls.filter((tc) => {
316
+ if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {
317
+ undiscoveredLazyResults.push({
318
+ toolCallId: tc.id,
319
+ toolName: tc.function.name,
320
+ result: {
321
+ error: this.lazyToolManager.getUndiscoveredToolError(
322
+ tc.function.name
323
+ )
324
+ },
325
+ state: "output-error"
326
+ });
327
+ return false;
328
+ }
329
+ return true;
330
+ });
331
+ if (undiscoveredLazyResults.length > 0) {
332
+ for (const chunk of this.buildToolResultChunks(
333
+ undiscoveredLazyResults,
334
+ finishEvent
335
+ )) {
336
+ yield chunk;
337
+ }
338
+ }
339
+ if (executablePendingCalls.length === 0) {
340
+ return "continue";
341
+ }
309
342
  const { approvals, clientToolResults } = this.collectClientState();
310
343
  const generator = executeToolCalls(
311
- pendingToolCalls,
344
+ executablePendingCalls,
312
345
  this.tools,
313
346
  approvals,
314
347
  clientToolResults,
@@ -391,10 +424,41 @@ class TextEngine {
391
424
  return;
392
425
  }
393
426
  this.addAssistantToolCallMessage(toolCalls);
427
+ const undiscoveredLazyResults = [];
428
+ const executableToolCalls = toolCalls.filter((tc) => {
429
+ if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {
430
+ undiscoveredLazyResults.push({
431
+ toolCallId: tc.id,
432
+ toolName: tc.function.name,
433
+ result: {
434
+ error: this.lazyToolManager.getUndiscoveredToolError(
435
+ tc.function.name
436
+ )
437
+ },
438
+ state: "output-error"
439
+ });
440
+ return false;
441
+ }
442
+ return true;
443
+ });
444
+ if (undiscoveredLazyResults.length > 0) {
445
+ const finishEvt = this.finishedEvent;
446
+ for (const chunk of this.buildToolResultChunks(
447
+ undiscoveredLazyResults,
448
+ finishEvt
449
+ )) {
450
+ yield chunk;
451
+ }
452
+ }
453
+ if (executableToolCalls.length === 0) {
454
+ this.toolCallManager.clear();
455
+ this.setToolPhase("continue");
456
+ return;
457
+ }
394
458
  this.middlewareCtx.phase = "beforeTools";
395
459
  const { approvals, clientToolResults } = this.collectClientState();
396
460
  const generator = executeToolCalls(
397
- toolCalls,
461
+ executableToolCalls,
398
462
  this.tools,
399
463
  approvals,
400
464
  clientToolResults,
@@ -464,6 +528,12 @@ class TextEngine {
464
528
  for (const chunk of toolResultChunks) {
465
529
  yield chunk;
466
530
  }
531
+ if (this.lazyToolManager.hasNewlyDiscoveredTools()) {
532
+ this.tools = this.lazyToolManager.getActiveTools();
533
+ this.toolCallManager = new ToolCallManager(this.tools);
534
+ this.setToolPhase("continue");
535
+ return;
536
+ }
467
537
  this.toolCallManager.clear();
468
538
  this.setToolPhase("continue");
469
539
  }
@@ -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 { devtoolsMiddleware } from '@tanstack/ai-event-client'\nimport { streamToText } from '../../stream-to-response.js'\nimport {\n MiddlewareAbortError,\n ToolCallManager,\n executeToolCalls,\n} 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 { convertMessagesToModelMessages } from './messages'\nimport { MiddlewareRunner } from './middleware/compose'\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 CustomEvent,\n InferSchemaType,\n ModelMessage,\n RunFinishedEvent,\n SchemaInput,\n StreamChunk,\n TextMessageContentEvent,\n TextOptions,\n Tool,\n ToolCall,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n} from '../../types'\nimport type {\n ChatMiddleware,\n ChatMiddlewareConfig,\n ChatMiddlewareContext,\n ChatMiddlewarePhase,\n} from './middleware/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 * Optional middleware array for observing/transforming chat behavior.\n * Middleware hooks are called in array order. See {@link ChatMiddleware} for available hooks.\n *\n * @example\n * ```ts\n * const stream = chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [...],\n * middleware: [loggingMiddleware, redactionMiddleware],\n * })\n * ```\n */\n middleware?: Array<ChatMiddleware>\n /**\n * Opaque user-provided context value passed to middleware hooks.\n * Can be used to pass request-scoped data (e.g., user ID, request context).\n */\n context?: unknown\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 middleware?: Array<ChatMiddleware>\n context?: unknown\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 params: TParams\n private systemPrompts: Array<string>\n private tools: Array<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 eventOptions?: Record<string, unknown>\n private eventToolNames?: Array<string>\n private finishedEvent: RunFinishedEvent | null = null\n private earlyTermination = false\n private toolPhase: ToolPhaseResult = 'continue'\n private cyclePhase: CyclePhase = 'processText'\n // Client state extracted from initial messages (before conversion to ModelMessage)\n private readonly initialApprovals: Map<string, boolean>\n private readonly initialClientToolResults: Map<string, any>\n\n // Middleware support\n private readonly middlewareRunner: MiddlewareRunner\n private readonly middlewareCtx: ChatMiddlewareContext\n private readonly deferredPromises: Array<Promise<unknown>> = []\n private abortReason?: string\n private middlewareAbortController?: AbortController\n private terminalHookCalled = false\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\n // Extract client state (approvals, client tool results) from original messages BEFORE conversion\n // This preserves UIMessage parts data that would be lost during conversion to ModelMessage\n const { approvals, clientToolResults } =\n this.extractClientStateFromOriginalMessages(\n config.params.messages as Array<any>,\n )\n this.initialApprovals = approvals\n this.initialClientToolResults = clientToolResults\n\n // Convert messages to ModelMessage format (handles both UIMessage and ModelMessage input)\n // This ensures consistent internal format regardless of what the client sends\n this.messages = convertMessagesToModelMessages(\n config.params.messages as Array<any>,\n )\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 // Initialize middleware — devtools middleware is always first\n const allMiddleware = [devtoolsMiddleware(), ...(config.middleware || [])]\n this.middlewareRunner = new MiddlewareRunner(allMiddleware)\n this.middlewareAbortController = new AbortController()\n this.middlewareCtx = {\n requestId: this.requestId,\n streamId: this.streamId,\n conversationId: config.params.conversationId,\n phase: 'init' as ChatMiddlewarePhase,\n iteration: 0,\n chunkIndex: 0,\n signal: this.effectiveSignal,\n abort: (reason?: string) => {\n this.abortReason = reason\n this.middlewareAbortController?.abort(reason)\n },\n context: config.context,\n defer: (promise: Promise<unknown>) => {\n this.deferredPromises.push(promise)\n },\n // Provider / adapter info\n provider: config.adapter.name,\n model: config.params.model,\n source: 'server',\n streaming: true,\n // Config-derived (updated in beforeRun and applyMiddlewareConfig)\n systemPrompts: this.systemPrompts,\n toolNames: undefined,\n options: undefined,\n modelOptions: config.params.modelOptions,\n // Computed\n messageCount: this.initialMessageCount,\n hasTools: this.tools.length > 0,\n // Mutable per-iteration\n currentMessageId: null,\n accumulatedContent: '',\n // References\n messages: this.messages,\n createId: (prefix: string) => this.createId(prefix),\n }\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 // Run initial onConfig (phase = init)\n this.middlewareCtx.phase = 'init'\n const initialConfig = this.buildMiddlewareConfig()\n const transformedConfig = await this.middlewareRunner.runOnConfig(\n this.middlewareCtx,\n initialConfig,\n )\n this.applyMiddlewareConfig(transformedConfig)\n\n // Run onStart (devtools middleware emits text:request:started and initial messages here)\n await this.middlewareRunner.runOnStart(this.middlewareCtx)\n\n const pendingPhase = yield* this.checkForPendingToolCalls()\n if (pendingPhase === 'wait') {\n return\n }\n\n do {\n if (this.earlyTermination || this.isCancelled()) {\n return\n }\n\n await this.beginCycle()\n\n if (this.cyclePhase === 'processText') {\n // Run onConfig before each model call (phase = beforeModel)\n this.middlewareCtx.phase = 'beforeModel'\n this.middlewareCtx.iteration = this.iterationCount\n const iterConfig = this.buildMiddlewareConfig()\n const transformedConfig = await this.middlewareRunner.runOnConfig(\n this.middlewareCtx,\n iterConfig,\n )\n this.applyMiddlewareConfig(transformedConfig)\n\n yield* this.streamModelResponse()\n } else {\n yield* this.processToolCalls()\n }\n\n this.endCycle()\n } while (this.shouldContinue())\n\n // Call terminal onFinish hook (skip when waiting for client — stream is paused, not finished)\n if (!this.terminalHookCalled && this.toolPhase !== 'wait') {\n this.terminalHookCalled = true\n await this.middlewareRunner.runOnFinish(this.middlewareCtx, {\n finishReason: this.lastFinishReason,\n duration: Date.now() - this.streamStartTime,\n content: this.accumulatedContent,\n usage: this.finishedEvent?.usage,\n })\n }\n } catch (error: unknown) {\n if (!this.terminalHookCalled) {\n this.terminalHookCalled = true\n if (error instanceof MiddlewareAbortError) {\n // Middleware abort decision — call onAbort, not onError\n this.abortReason = error.message\n await this.middlewareRunner.runOnAbort(this.middlewareCtx, {\n reason: error.message,\n duration: Date.now() - this.streamStartTime,\n })\n } else {\n // Genuine error — call onError\n await this.middlewareRunner.runOnError(this.middlewareCtx, {\n error,\n duration: Date.now() - this.streamStartTime,\n })\n }\n }\n // Don't rethrow middleware abort errors — the run just stops gracefully\n if (!(error instanceof MiddlewareAbortError)) {\n throw error\n }\n } finally {\n // Check for abort terminal hook\n if (!this.terminalHookCalled && this.isCancelled()) {\n this.terminalHookCalled = true\n await this.middlewareRunner.runOnAbort(this.middlewareCtx, {\n reason: this.abortReason,\n duration: Date.now() - this.streamStartTime,\n })\n }\n\n // Await deferred promises (non-blocking side effects)\n if (this.deferredPromises.length > 0) {\n await Promise.allSettled(this.deferredPromises)\n }\n }\n }\n\n private beforeRun(): void {\n this.streamStartTime = Date.now()\n const { tools, temperature, topP, maxTokens, metadata } = this.params\n\n // Gather flattened options into an object for context\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 this.eventOptions = Object.keys(options).length > 0 ? options : undefined\n this.eventToolNames = tools?.map((t) => t.name)\n\n // Update middleware context with computed fields\n this.middlewareCtx.options = this.eventOptions\n this.middlewareCtx.toolNames = this.eventToolNames\n }\n\n private async beginCycle(): Promise<void> {\n if (this.cyclePhase === 'processText') {\n await 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 async beginIteration(): Promise<void> {\n this.currentMessageId = this.createId('msg')\n this.accumulatedContent = ''\n this.finishedEvent = null\n\n // Update mutable context fields\n this.middlewareCtx.currentMessageId = this.currentMessageId\n this.middlewareCtx.accumulatedContent = ''\n\n // Notify middleware of new iteration (devtools emits assistant message:created here)\n await this.middlewareRunner.runOnIteration(this.middlewareCtx, {\n iteration: this.iterationCount,\n messageId: this.currentMessageId,\n })\n }\n\n private async *streamModelResponse(): AsyncGenerator<StreamChunk> {\n const { temperature, topP, maxTokens, metadata, modelOptions } = this.params\n const tools = this.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 this.middlewareCtx.phase = 'modelStream'\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.isCancelled()) {\n break\n }\n\n this.totalChunkCount++\n\n // Pipe chunk through middleware (devtools middleware observes and emits events)\n const outputChunks = await this.middlewareRunner.runOnChunk(\n this.middlewareCtx,\n chunk,\n )\n for (const outputChunk of outputChunks) {\n yield outputChunk\n this.handleStreamChunk(outputChunk)\n this.middlewareCtx.chunkIndex++\n }\n\n // Handle usage via middleware\n if (chunk.type === 'RUN_FINISHED' && chunk.usage) {\n await this.middlewareRunner.runOnUsage(this.middlewareCtx, chunk.usage)\n }\n\n if (this.earlyTermination) {\n break\n }\n }\n }\n\n private handleStreamChunk(chunk: StreamChunk): void {\n switch (chunk.type) {\n // AG-UI Events\n case 'TEXT_MESSAGE_CONTENT':\n this.handleTextMessageContentEvent(chunk)\n break\n case 'TOOL_CALL_START':\n this.handleToolCallStartEvent(chunk)\n break\n case 'TOOL_CALL_ARGS':\n this.handleToolCallArgsEvent(chunk)\n break\n case 'TOOL_CALL_END':\n this.handleToolCallEndEvent(chunk)\n break\n case 'RUN_FINISHED':\n this.handleRunFinishedEvent(chunk)\n break\n case 'RUN_ERROR':\n this.handleRunErrorEvent(chunk)\n break\n case 'STEP_FINISHED':\n this.handleStepFinishedEvent(chunk)\n break\n\n default:\n // RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_END, STEP_STARTED,\n // STATE_SNAPSHOT, STATE_DELTA, CUSTOM\n // - no special handling needed in chat activity\n break\n }\n }\n\n // ===========================\n // AG-UI Event Handlers\n // ===========================\n\n private handleTextMessageContentEvent(chunk: TextMessageContentEvent): void {\n if (chunk.content) {\n this.accumulatedContent = chunk.content\n } else {\n this.accumulatedContent += chunk.delta\n }\n this.middlewareCtx.accumulatedContent = this.accumulatedContent\n }\n\n private handleToolCallStartEvent(chunk: ToolCallStartEvent): void {\n this.toolCallManager.addToolCallStartEvent(chunk)\n }\n\n private handleToolCallArgsEvent(chunk: ToolCallArgsEvent): void {\n this.toolCallManager.addToolCallArgsEvent(chunk)\n }\n\n private handleToolCallEndEvent(chunk: ToolCallEndEvent): void {\n this.toolCallManager.completeToolCall(chunk)\n }\n\n private handleRunFinishedEvent(chunk: RunFinishedEvent): void {\n this.finishedEvent = chunk\n this.lastFinishReason = chunk.finishReason\n }\n\n private handleRunErrorEvent(\n _chunk: Extract<StreamChunk, { type: 'RUN_ERROR' }>,\n ): void {\n this.earlyTermination = true\n }\n\n private handleStepFinishedEvent(\n _chunk: Extract<StreamChunk, { type: 'STEP_FINISHED' }>,\n ): void {\n // State tracking for STEP_FINISHED is handled by middleware\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 finishEvent = this.createSyntheticFinishedEvent()\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const generator = executeToolCalls(\n pendingToolCalls,\n this.tools,\n approvals,\n clientToolResults,\n (eventName, data) => this.createCustomEventChunk(eventName, data),\n {\n onBeforeToolCall: async (toolCall, tool, args) => {\n const hookCtx = {\n toolCall,\n tool,\n args,\n toolName: toolCall.function.name,\n toolCallId: toolCall.id,\n }\n return this.middlewareRunner.runOnBeforeToolCall(\n this.middlewareCtx,\n hookCtx,\n )\n },\n onAfterToolCall: async (info) => {\n await this.middlewareRunner.runOnAfterToolCall(\n this.middlewareCtx,\n info,\n )\n },\n },\n )\n\n // Consume the async generator, yielding custom events and collecting the return value\n const executionResult = yield* this.drainToolCallGenerator(generator)\n\n // Check if middleware aborted during pending tool execution\n if (this.isMiddlewareAborted()) {\n this.setToolPhase('stop')\n return 'stop'\n }\n\n // Notify middleware of tool phase completion (devtools emits aggregate events here)\n await this.middlewareRunner.runOnToolPhaseComplete(this.middlewareCtx, {\n toolCalls: pendingToolCalls,\n results: executionResult.results,\n needsApproval: executionResult.needsApproval,\n needsClientExecution: executionResult.needsClientExecution,\n })\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n if (executionResult.results.length > 0) {\n for (const chunk of this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\n )) {\n yield chunk\n }\n }\n\n for (const chunk of this.buildApprovalChunks(\n executionResult.needsApproval,\n finishEvent,\n )) {\n yield chunk\n }\n\n for (const chunk of this.buildClientToolChunks(\n executionResult.needsClientExecution,\n finishEvent,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return 'wait'\n }\n\n const toolResultChunks = this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\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 finishEvent = this.finishedEvent\n\n if (!finishEvent || toolCalls.length === 0) {\n this.setToolPhase('stop')\n return\n }\n\n this.addAssistantToolCallMessage(toolCalls)\n\n this.middlewareCtx.phase = 'beforeTools'\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const generator = executeToolCalls(\n toolCalls,\n this.tools,\n approvals,\n clientToolResults,\n (eventName, data) => this.createCustomEventChunk(eventName, data),\n {\n onBeforeToolCall: async (toolCall, tool, args) => {\n const hookCtx = {\n toolCall,\n tool,\n args,\n toolName: toolCall.function.name,\n toolCallId: toolCall.id,\n }\n return this.middlewareRunner.runOnBeforeToolCall(\n this.middlewareCtx,\n hookCtx,\n )\n },\n onAfterToolCall: async (info) => {\n await this.middlewareRunner.runOnAfterToolCall(\n this.middlewareCtx,\n info,\n )\n },\n },\n )\n\n // Consume the async generator, yielding custom events and collecting the return value\n const executionResult = yield* this.drainToolCallGenerator(generator)\n\n this.middlewareCtx.phase = 'afterTools'\n\n // Check if middleware aborted during tool execution\n if (this.isMiddlewareAborted()) {\n this.setToolPhase('stop')\n return\n }\n\n // Notify middleware of tool phase completion (devtools emits aggregate events here)\n await this.middlewareRunner.runOnToolPhaseComplete(this.middlewareCtx, {\n toolCalls,\n results: executionResult.results,\n needsApproval: executionResult.needsApproval,\n needsClientExecution: executionResult.needsClientExecution,\n })\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n if (executionResult.results.length > 0) {\n for (const chunk of this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\n )) {\n yield chunk\n }\n }\n\n for (const chunk of this.buildApprovalChunks(\n executionResult.needsApproval,\n finishEvent,\n )) {\n yield chunk\n }\n\n for (const chunk of this.buildClientToolChunks(\n executionResult.needsClientExecution,\n finishEvent,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return\n }\n\n const toolResultChunks = this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\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.finishedEvent?.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 /**\n * Extract client state (approvals and client tool results) from original messages.\n * This is called in the constructor BEFORE converting to ModelMessage format,\n * because the parts array (which contains approval state) is lost during conversion.\n */\n private extractClientStateFromOriginalMessages(\n originalMessages: Array<any>,\n ): {\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 originalMessages) {\n // Check for UIMessage format (parts array) - extract client tool results and approvals\n if (message.role === 'assistant' && message.parts) {\n for (const part of message.parts) {\n if (part.type === 'tool-call') {\n // Extract client tool results (tools without approval that have output)\n if (part.output !== undefined && !part.approval) {\n clientToolResults.set(part.id, part.output)\n }\n // Extract approval responses from UIMessage format parts\n if (\n part.approval?.id &&\n part.approval?.approved !== undefined &&\n part.state === 'approval-responded'\n ) {\n approvals.set(part.approval.id, part.approval.approved)\n }\n }\n }\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private collectClientState(): {\n approvals: Map<string, boolean>\n clientToolResults: Map<string, any>\n } {\n // Start with the initial client state extracted from original messages\n const approvals = new Map(this.initialApprovals)\n const clientToolResults = new Map(this.initialClientToolResults)\n\n // Also check current messages for any additional tool results (from server tools)\n for (const message of this.messages) {\n // Check for ModelMessage format (role: 'tool' messages contain tool results)\n // This handles results sent back from the client after executing client-side tools\n if (message.role === 'tool' && message.toolCallId) {\n // Parse content back to original output (was stringified by uiMessageToModelMessages)\n let output: unknown\n try {\n output = JSON.parse(message.content as string)\n } catch {\n output = message.content\n }\n // Skip approval response messages (they have pendingExecution marker)\n // These are NOT real client tool results — they are synthetic tool messages\n // created by uiMessageToModelMessages for approved-but-not-yet-executed tools.\n // Treating them as results would prevent the server from requesting actual\n // client-side execution after approval (see GitHub issue #225).\n if (\n output &&\n typeof output === 'object' &&\n (output as any).pendingExecution === true\n ) {\n continue\n }\n clientToolResults.set(message.toolCallId, output)\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private buildApprovalChunks(\n approvals: Array<ApprovalRequest>,\n finishEvent: RunFinishedEvent,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const approval of approvals) {\n chunks.push({\n type: 'CUSTOM',\n timestamp: Date.now(),\n model: finishEvent.model,\n name: 'approval-requested',\n value: {\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\n return chunks\n }\n\n private buildClientToolChunks(\n clientRequests: Array<ClientToolRequest>,\n finishEvent: RunFinishedEvent,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const clientTool of clientRequests) {\n chunks.push({\n type: 'CUSTOM',\n timestamp: Date.now(),\n model: finishEvent.model,\n name: 'tool-input-available',\n value: {\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n },\n })\n }\n\n return chunks\n }\n\n private buildToolResultChunks(\n results: Array<ToolResult>,\n finishEvent: RunFinishedEvent,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const result of results) {\n const content = JSON.stringify(result.result)\n\n chunks.push({\n type: 'TOOL_CALL_END',\n timestamp: Date.now(),\n model: finishEvent.model,\n toolCallId: result.toolCallId,\n toolName: result.toolName,\n result: content,\n })\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 // Build a set of completed tool IDs, but exclude tools with pendingExecution marker\n // (these are approved tools that still need to execute)\n const completedToolIds = new Set<string>()\n\n for (const message of this.messages) {\n if (message.role === 'tool' && message.toolCallId) {\n // Check if this is an approval response with pendingExecution marker\n let hasPendingExecution = false\n if (typeof message.content === 'string') {\n try {\n const parsed = JSON.parse(message.content)\n if (parsed.pendingExecution === true) {\n hasPendingExecution = true\n }\n } catch {\n // Not JSON, treat as regular tool result\n }\n }\n\n // Only mark as complete if NOT pending execution\n if (!hasPendingExecution) {\n completedToolIds.add(message.toolCallId)\n }\n }\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 createSyntheticFinishedEvent(): RunFinishedEvent {\n return {\n type: 'RUN_FINISHED',\n runId: 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 isMiddlewareAborted(): boolean {\n return !!this.middlewareAbortController?.signal.aborted\n }\n\n private isCancelled(): boolean {\n return this.isAborted() || this.isMiddlewareAborted()\n }\n\n private buildMiddlewareConfig(): ChatMiddlewareConfig {\n return {\n messages: this.messages,\n systemPrompts: [...this.systemPrompts],\n tools: [...this.tools],\n temperature: this.params.temperature,\n topP: this.params.topP,\n maxTokens: this.params.maxTokens,\n metadata: this.params.metadata,\n modelOptions: this.params.modelOptions,\n }\n }\n\n private applyMiddlewareConfig(config: ChatMiddlewareConfig): void {\n this.messages = config.messages\n this.systemPrompts = config.systemPrompts\n this.tools = config.tools\n this.params = {\n ...this.params,\n temperature: config.temperature,\n topP: config.topP,\n maxTokens: config.maxTokens,\n metadata: config.metadata,\n modelOptions: config.modelOptions,\n }\n\n // Sync context fields that depend on config\n this.middlewareCtx.messages = this.messages\n this.middlewareCtx.systemPrompts = this.systemPrompts\n this.middlewareCtx.hasTools = this.tools.length > 0\n this.middlewareCtx.toolNames = this.tools.map((t) => t.name)\n this.middlewareCtx.modelOptions = config.modelOptions\n }\n\n private setToolPhase(phase: ToolPhaseResult): void {\n this.toolPhase = phase\n }\n\n /**\n * Drain an executeToolCalls async generator, yielding any CustomEvent chunks\n * and returning the final ExecuteToolCallsResult.\n */\n private async *drainToolCallGenerator(\n generator: AsyncGenerator<\n CustomEvent,\n {\n results: Array<ToolResult>\n needsApproval: Array<ApprovalRequest>\n needsClientExecution: Array<ClientToolRequest>\n },\n void\n >,\n ): AsyncGenerator<\n StreamChunk,\n {\n results: Array<ToolResult>\n needsApproval: Array<ApprovalRequest>\n needsClientExecution: Array<ClientToolRequest>\n },\n void\n > {\n let next = await generator.next()\n while (!next.done) {\n yield next.value\n next = await generator.next()\n }\n return next.value\n }\n\n private createCustomEventChunk(\n eventName: string,\n value: Record<string, any>,\n ): CustomEvent {\n return {\n type: 'CUSTOM',\n timestamp: Date.now(),\n model: this.params.model,\n name: eventName,\n value,\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, middleware, context, ...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 middleware,\n context,\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, middleware, context, ...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 middleware,\n context,\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","transformedConfig"],"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 { devtoolsMiddleware } from '@tanstack/ai-event-client'\nimport { streamToText } from '../../stream-to-response.js'\nimport { LazyToolManager } from './tools/lazy-tool-manager'\nimport {\n MiddlewareAbortError,\n ToolCallManager,\n executeToolCalls,\n} 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 { convertMessagesToModelMessages } from './messages'\nimport { MiddlewareRunner } from './middleware/compose'\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 CustomEvent,\n InferSchemaType,\n ModelMessage,\n RunFinishedEvent,\n SchemaInput,\n StreamChunk,\n TextMessageContentEvent,\n TextOptions,\n Tool,\n ToolCall,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n} from '../../types'\nimport type {\n ChatMiddleware,\n ChatMiddlewareConfig,\n ChatMiddlewareContext,\n ChatMiddlewarePhase,\n} from './middleware/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 * Optional middleware array for observing/transforming chat behavior.\n * Middleware hooks are called in array order. See {@link ChatMiddleware} for available hooks.\n *\n * @example\n * ```ts\n * const stream = chat({\n * adapter: openaiText('gpt-4o'),\n * messages: [...],\n * middleware: [loggingMiddleware, redactionMiddleware],\n * })\n * ```\n */\n middleware?: Array<ChatMiddleware>\n /**\n * Opaque user-provided context value passed to middleware hooks.\n * Can be used to pass request-scoped data (e.g., user ID, request context).\n */\n context?: unknown\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 middleware?: Array<ChatMiddleware>\n context?: unknown\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 params: TParams\n private systemPrompts: Array<string>\n private tools: Array<Tool>\n private readonly loopStrategy: AgentLoopStrategy\n private toolCallManager: ToolCallManager\n private readonly lazyToolManager: LazyToolManager\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 eventOptions?: Record<string, unknown>\n private eventToolNames?: Array<string>\n private finishedEvent: RunFinishedEvent | null = null\n private earlyTermination = false\n private toolPhase: ToolPhaseResult = 'continue'\n private cyclePhase: CyclePhase = 'processText'\n // Client state extracted from initial messages (before conversion to ModelMessage)\n private readonly initialApprovals: Map<string, boolean>\n private readonly initialClientToolResults: Map<string, any>\n\n // Middleware support\n private readonly middlewareRunner: MiddlewareRunner\n private readonly middlewareCtx: ChatMiddlewareContext\n private readonly deferredPromises: Array<Promise<unknown>> = []\n private abortReason?: string\n private middlewareAbortController?: AbortController\n private terminalHookCalled = false\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.loopStrategy =\n config.params.agentLoopStrategy || maxIterationsStrategy(5)\n this.initialMessageCount = config.params.messages.length\n\n // Extract client state (approvals, client tool results) from original messages BEFORE conversion\n // This preserves UIMessage parts data that would be lost during conversion to ModelMessage\n const { approvals, clientToolResults } =\n this.extractClientStateFromOriginalMessages(\n config.params.messages as Array<any>,\n )\n this.initialApprovals = approvals\n this.initialClientToolResults = clientToolResults\n\n // Convert messages to ModelMessage format (handles both UIMessage and ModelMessage input)\n // This ensures consistent internal format regardless of what the client sends\n this.messages = convertMessagesToModelMessages(\n config.params.messages as Array<any>,\n )\n\n // Initialize lazy tool manager after messages are converted (needs message history for scanning)\n this.lazyToolManager = new LazyToolManager(\n config.params.tools || [],\n this.messages,\n )\n this.tools = this.lazyToolManager.getActiveTools()\n this.toolCallManager = new ToolCallManager(this.tools)\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 // Initialize middleware — devtools middleware is always first\n const allMiddleware = [devtoolsMiddleware(), ...(config.middleware || [])]\n this.middlewareRunner = new MiddlewareRunner(allMiddleware)\n this.middlewareAbortController = new AbortController()\n this.middlewareCtx = {\n requestId: this.requestId,\n streamId: this.streamId,\n conversationId: config.params.conversationId,\n phase: 'init' as ChatMiddlewarePhase,\n iteration: 0,\n chunkIndex: 0,\n signal: this.effectiveSignal,\n abort: (reason?: string) => {\n this.abortReason = reason\n this.middlewareAbortController?.abort(reason)\n },\n context: config.context,\n defer: (promise: Promise<unknown>) => {\n this.deferredPromises.push(promise)\n },\n // Provider / adapter info\n provider: config.adapter.name,\n model: config.params.model,\n source: 'server',\n streaming: true,\n // Config-derived (updated in beforeRun and applyMiddlewareConfig)\n systemPrompts: this.systemPrompts,\n toolNames: undefined,\n options: undefined,\n modelOptions: config.params.modelOptions,\n // Computed\n messageCount: this.initialMessageCount,\n hasTools: this.tools.length > 0,\n // Mutable per-iteration\n currentMessageId: null,\n accumulatedContent: '',\n // References\n messages: this.messages,\n createId: (prefix: string) => this.createId(prefix),\n }\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 // Run initial onConfig (phase = init)\n this.middlewareCtx.phase = 'init'\n const initialConfig = this.buildMiddlewareConfig()\n const transformedConfig = await this.middlewareRunner.runOnConfig(\n this.middlewareCtx,\n initialConfig,\n )\n this.applyMiddlewareConfig(transformedConfig)\n\n // Run onStart (devtools middleware emits text:request:started and initial messages here)\n await this.middlewareRunner.runOnStart(this.middlewareCtx)\n\n const pendingPhase = yield* this.checkForPendingToolCalls()\n if (pendingPhase === 'wait') {\n return\n }\n\n do {\n if (this.earlyTermination || this.isCancelled()) {\n return\n }\n\n await this.beginCycle()\n\n if (this.cyclePhase === 'processText') {\n // Run onConfig before each model call (phase = beforeModel)\n this.middlewareCtx.phase = 'beforeModel'\n this.middlewareCtx.iteration = this.iterationCount\n const iterConfig = this.buildMiddlewareConfig()\n const transformedConfig = await this.middlewareRunner.runOnConfig(\n this.middlewareCtx,\n iterConfig,\n )\n this.applyMiddlewareConfig(transformedConfig)\n\n yield* this.streamModelResponse()\n } else {\n yield* this.processToolCalls()\n }\n\n this.endCycle()\n } while (this.shouldContinue())\n\n // Call terminal onFinish hook (skip when waiting for client — stream is paused, not finished)\n if (!this.terminalHookCalled && this.toolPhase !== 'wait') {\n this.terminalHookCalled = true\n await this.middlewareRunner.runOnFinish(this.middlewareCtx, {\n finishReason: this.lastFinishReason,\n duration: Date.now() - this.streamStartTime,\n content: this.accumulatedContent,\n usage: this.finishedEvent?.usage,\n })\n }\n } catch (error: unknown) {\n if (!this.terminalHookCalled) {\n this.terminalHookCalled = true\n if (error instanceof MiddlewareAbortError) {\n // Middleware abort decision — call onAbort, not onError\n this.abortReason = error.message\n await this.middlewareRunner.runOnAbort(this.middlewareCtx, {\n reason: error.message,\n duration: Date.now() - this.streamStartTime,\n })\n } else {\n // Genuine error — call onError\n await this.middlewareRunner.runOnError(this.middlewareCtx, {\n error,\n duration: Date.now() - this.streamStartTime,\n })\n }\n }\n // Don't rethrow middleware abort errors — the run just stops gracefully\n if (!(error instanceof MiddlewareAbortError)) {\n throw error\n }\n } finally {\n // Check for abort terminal hook\n if (!this.terminalHookCalled && this.isCancelled()) {\n this.terminalHookCalled = true\n await this.middlewareRunner.runOnAbort(this.middlewareCtx, {\n reason: this.abortReason,\n duration: Date.now() - this.streamStartTime,\n })\n }\n\n // Await deferred promises (non-blocking side effects)\n if (this.deferredPromises.length > 0) {\n await Promise.allSettled(this.deferredPromises)\n }\n }\n }\n\n private beforeRun(): void {\n this.streamStartTime = Date.now()\n const { tools, temperature, topP, maxTokens, metadata } = this.params\n\n // Gather flattened options into an object for context\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 this.eventOptions = Object.keys(options).length > 0 ? options : undefined\n this.eventToolNames = tools?.map((t) => t.name)\n\n // Update middleware context with computed fields\n this.middlewareCtx.options = this.eventOptions\n this.middlewareCtx.toolNames = this.eventToolNames\n }\n\n private async beginCycle(): Promise<void> {\n if (this.cyclePhase === 'processText') {\n await 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 async beginIteration(): Promise<void> {\n this.currentMessageId = this.createId('msg')\n this.accumulatedContent = ''\n this.finishedEvent = null\n\n // Update mutable context fields\n this.middlewareCtx.currentMessageId = this.currentMessageId\n this.middlewareCtx.accumulatedContent = ''\n\n // Notify middleware of new iteration (devtools emits assistant message:created here)\n await this.middlewareRunner.runOnIteration(this.middlewareCtx, {\n iteration: this.iterationCount,\n messageId: this.currentMessageId,\n })\n }\n\n private async *streamModelResponse(): AsyncGenerator<StreamChunk> {\n const { temperature, topP, maxTokens, metadata, modelOptions } = this.params\n const tools = this.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 this.middlewareCtx.phase = 'modelStream'\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.isCancelled()) {\n break\n }\n\n this.totalChunkCount++\n\n // Pipe chunk through middleware (devtools middleware observes and emits events)\n const outputChunks = await this.middlewareRunner.runOnChunk(\n this.middlewareCtx,\n chunk,\n )\n for (const outputChunk of outputChunks) {\n yield outputChunk\n this.handleStreamChunk(outputChunk)\n this.middlewareCtx.chunkIndex++\n }\n\n // Handle usage via middleware\n if (chunk.type === 'RUN_FINISHED' && chunk.usage) {\n await this.middlewareRunner.runOnUsage(this.middlewareCtx, chunk.usage)\n }\n\n if (this.earlyTermination) {\n break\n }\n }\n }\n\n private handleStreamChunk(chunk: StreamChunk): void {\n switch (chunk.type) {\n // AG-UI Events\n case 'TEXT_MESSAGE_CONTENT':\n this.handleTextMessageContentEvent(chunk)\n break\n case 'TOOL_CALL_START':\n this.handleToolCallStartEvent(chunk)\n break\n case 'TOOL_CALL_ARGS':\n this.handleToolCallArgsEvent(chunk)\n break\n case 'TOOL_CALL_END':\n this.handleToolCallEndEvent(chunk)\n break\n case 'RUN_FINISHED':\n this.handleRunFinishedEvent(chunk)\n break\n case 'RUN_ERROR':\n this.handleRunErrorEvent(chunk)\n break\n case 'STEP_FINISHED':\n this.handleStepFinishedEvent(chunk)\n break\n\n default:\n // RUN_STARTED, TEXT_MESSAGE_START, TEXT_MESSAGE_END, STEP_STARTED,\n // STATE_SNAPSHOT, STATE_DELTA, CUSTOM\n // - no special handling needed in chat activity\n break\n }\n }\n\n // ===========================\n // AG-UI Event Handlers\n // ===========================\n\n private handleTextMessageContentEvent(chunk: TextMessageContentEvent): void {\n if (chunk.content) {\n this.accumulatedContent = chunk.content\n } else {\n this.accumulatedContent += chunk.delta\n }\n this.middlewareCtx.accumulatedContent = this.accumulatedContent\n }\n\n private handleToolCallStartEvent(chunk: ToolCallStartEvent): void {\n this.toolCallManager.addToolCallStartEvent(chunk)\n }\n\n private handleToolCallArgsEvent(chunk: ToolCallArgsEvent): void {\n this.toolCallManager.addToolCallArgsEvent(chunk)\n }\n\n private handleToolCallEndEvent(chunk: ToolCallEndEvent): void {\n this.toolCallManager.completeToolCall(chunk)\n }\n\n private handleRunFinishedEvent(chunk: RunFinishedEvent): void {\n this.finishedEvent = chunk\n this.lastFinishReason = chunk.finishReason\n }\n\n private handleRunErrorEvent(\n _chunk: Extract<StreamChunk, { type: 'RUN_ERROR' }>,\n ): void {\n this.earlyTermination = true\n }\n\n private handleStepFinishedEvent(\n _chunk: Extract<StreamChunk, { type: 'STEP_FINISHED' }>,\n ): void {\n // State tracking for STEP_FINISHED is handled by middleware\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 finishEvent = this.createSyntheticFinishedEvent()\n\n // Handle undiscovered lazy tool calls with self-correcting error messages\n const undiscoveredLazyResults: Array<ToolResult> = []\n const executablePendingCalls = pendingToolCalls.filter((tc) => {\n if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {\n undiscoveredLazyResults.push({\n toolCallId: tc.id,\n toolName: tc.function.name,\n result: {\n error: this.lazyToolManager.getUndiscoveredToolError(\n tc.function.name,\n ),\n },\n state: 'output-error',\n })\n return false\n }\n return true\n })\n\n if (undiscoveredLazyResults.length > 0) {\n for (const chunk of this.buildToolResultChunks(\n undiscoveredLazyResults,\n finishEvent,\n )) {\n yield chunk\n }\n }\n\n if (executablePendingCalls.length === 0) {\n return 'continue'\n }\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const generator = executeToolCalls(\n executablePendingCalls,\n this.tools,\n approvals,\n clientToolResults,\n (eventName, data) => this.createCustomEventChunk(eventName, data),\n {\n onBeforeToolCall: async (toolCall, tool, args) => {\n const hookCtx = {\n toolCall,\n tool,\n args,\n toolName: toolCall.function.name,\n toolCallId: toolCall.id,\n }\n return this.middlewareRunner.runOnBeforeToolCall(\n this.middlewareCtx,\n hookCtx,\n )\n },\n onAfterToolCall: async (info) => {\n await this.middlewareRunner.runOnAfterToolCall(\n this.middlewareCtx,\n info,\n )\n },\n },\n )\n\n // Consume the async generator, yielding custom events and collecting the return value\n const executionResult = yield* this.drainToolCallGenerator(generator)\n\n // Check if middleware aborted during pending tool execution\n if (this.isMiddlewareAborted()) {\n this.setToolPhase('stop')\n return 'stop'\n }\n\n // Notify middleware of tool phase completion (devtools emits aggregate events here)\n await this.middlewareRunner.runOnToolPhaseComplete(this.middlewareCtx, {\n toolCalls: pendingToolCalls,\n results: executionResult.results,\n needsApproval: executionResult.needsApproval,\n needsClientExecution: executionResult.needsClientExecution,\n })\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n if (executionResult.results.length > 0) {\n for (const chunk of this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\n )) {\n yield chunk\n }\n }\n\n for (const chunk of this.buildApprovalChunks(\n executionResult.needsApproval,\n finishEvent,\n )) {\n yield chunk\n }\n\n for (const chunk of this.buildClientToolChunks(\n executionResult.needsClientExecution,\n finishEvent,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return 'wait'\n }\n\n const toolResultChunks = this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\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 finishEvent = this.finishedEvent\n\n if (!finishEvent || toolCalls.length === 0) {\n this.setToolPhase('stop')\n return\n }\n\n this.addAssistantToolCallMessage(toolCalls)\n\n // Handle undiscovered lazy tool calls with self-correcting error messages\n const undiscoveredLazyResults: Array<ToolResult> = []\n const executableToolCalls = toolCalls.filter((tc) => {\n if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {\n undiscoveredLazyResults.push({\n toolCallId: tc.id,\n toolName: tc.function.name,\n result: {\n error: this.lazyToolManager.getUndiscoveredToolError(\n tc.function.name,\n ),\n },\n state: 'output-error',\n })\n return false\n }\n return true\n })\n\n if (undiscoveredLazyResults.length > 0) {\n const finishEvt = this.finishedEvent!\n for (const chunk of this.buildToolResultChunks(\n undiscoveredLazyResults,\n finishEvt,\n )) {\n yield chunk\n }\n }\n\n if (executableToolCalls.length === 0) {\n // All tool calls were undiscovered lazy tools — errors emitted, continue loop\n this.toolCallManager.clear()\n this.setToolPhase('continue')\n return\n }\n this.middlewareCtx.phase = 'beforeTools'\n\n const { approvals, clientToolResults } = this.collectClientState()\n\n const generator = executeToolCalls(\n executableToolCalls,\n this.tools,\n approvals,\n clientToolResults,\n (eventName, data) => this.createCustomEventChunk(eventName, data),\n {\n onBeforeToolCall: async (toolCall, tool, args) => {\n const hookCtx = {\n toolCall,\n tool,\n args,\n toolName: toolCall.function.name,\n toolCallId: toolCall.id,\n }\n return this.middlewareRunner.runOnBeforeToolCall(\n this.middlewareCtx,\n hookCtx,\n )\n },\n onAfterToolCall: async (info) => {\n await this.middlewareRunner.runOnAfterToolCall(\n this.middlewareCtx,\n info,\n )\n },\n },\n )\n\n // Consume the async generator, yielding custom events and collecting the return value\n const executionResult = yield* this.drainToolCallGenerator(generator)\n\n this.middlewareCtx.phase = 'afterTools'\n\n // Check if middleware aborted during tool execution\n if (this.isMiddlewareAborted()) {\n this.setToolPhase('stop')\n return\n }\n\n // Notify middleware of tool phase completion (devtools emits aggregate events here)\n await this.middlewareRunner.runOnToolPhaseComplete(this.middlewareCtx, {\n toolCalls,\n results: executionResult.results,\n needsApproval: executionResult.needsApproval,\n needsClientExecution: executionResult.needsClientExecution,\n })\n\n if (\n executionResult.needsApproval.length > 0 ||\n executionResult.needsClientExecution.length > 0\n ) {\n if (executionResult.results.length > 0) {\n for (const chunk of this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\n )) {\n yield chunk\n }\n }\n\n for (const chunk of this.buildApprovalChunks(\n executionResult.needsApproval,\n finishEvent,\n )) {\n yield chunk\n }\n\n for (const chunk of this.buildClientToolChunks(\n executionResult.needsClientExecution,\n finishEvent,\n )) {\n yield chunk\n }\n\n this.setToolPhase('wait')\n return\n }\n\n const toolResultChunks = this.buildToolResultChunks(\n executionResult.results,\n finishEvent,\n )\n\n for (const chunk of toolResultChunks) {\n yield chunk\n }\n\n // Refresh tools if lazy tools were discovered in this batch\n if (this.lazyToolManager.hasNewlyDiscoveredTools()) {\n this.tools = this.lazyToolManager.getActiveTools()\n this.toolCallManager = new ToolCallManager(this.tools)\n this.setToolPhase('continue')\n return\n }\n\n this.toolCallManager.clear()\n\n this.setToolPhase('continue')\n }\n\n private shouldExecuteToolPhase(): boolean {\n return (\n this.finishedEvent?.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 /**\n * Extract client state (approvals and client tool results) from original messages.\n * This is called in the constructor BEFORE converting to ModelMessage format,\n * because the parts array (which contains approval state) is lost during conversion.\n */\n private extractClientStateFromOriginalMessages(\n originalMessages: Array<any>,\n ): {\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 originalMessages) {\n // Check for UIMessage format (parts array) - extract client tool results and approvals\n if (message.role === 'assistant' && message.parts) {\n for (const part of message.parts) {\n if (part.type === 'tool-call') {\n // Extract client tool results (tools without approval that have output)\n if (part.output !== undefined && !part.approval) {\n clientToolResults.set(part.id, part.output)\n }\n // Extract approval responses from UIMessage format parts\n if (\n part.approval?.id &&\n part.approval?.approved !== undefined &&\n part.state === 'approval-responded'\n ) {\n approvals.set(part.approval.id, part.approval.approved)\n }\n }\n }\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private collectClientState(): {\n approvals: Map<string, boolean>\n clientToolResults: Map<string, any>\n } {\n // Start with the initial client state extracted from original messages\n const approvals = new Map(this.initialApprovals)\n const clientToolResults = new Map(this.initialClientToolResults)\n\n // Also check current messages for any additional tool results (from server tools)\n for (const message of this.messages) {\n // Check for ModelMessage format (role: 'tool' messages contain tool results)\n // This handles results sent back from the client after executing client-side tools\n if (message.role === 'tool' && message.toolCallId) {\n // Parse content back to original output (was stringified by uiMessageToModelMessages)\n let output: unknown\n try {\n output = JSON.parse(message.content as string)\n } catch {\n output = message.content\n }\n // Skip approval response messages (they have pendingExecution marker)\n // These are NOT real client tool results — they are synthetic tool messages\n // created by uiMessageToModelMessages for approved-but-not-yet-executed tools.\n // Treating them as results would prevent the server from requesting actual\n // client-side execution after approval (see GitHub issue #225).\n if (\n output &&\n typeof output === 'object' &&\n (output as any).pendingExecution === true\n ) {\n continue\n }\n clientToolResults.set(message.toolCallId, output)\n }\n }\n\n return { approvals, clientToolResults }\n }\n\n private buildApprovalChunks(\n approvals: Array<ApprovalRequest>,\n finishEvent: RunFinishedEvent,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const approval of approvals) {\n chunks.push({\n type: 'CUSTOM',\n timestamp: Date.now(),\n model: finishEvent.model,\n name: 'approval-requested',\n value: {\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\n return chunks\n }\n\n private buildClientToolChunks(\n clientRequests: Array<ClientToolRequest>,\n finishEvent: RunFinishedEvent,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const clientTool of clientRequests) {\n chunks.push({\n type: 'CUSTOM',\n timestamp: Date.now(),\n model: finishEvent.model,\n name: 'tool-input-available',\n value: {\n toolCallId: clientTool.toolCallId,\n toolName: clientTool.toolName,\n input: clientTool.input,\n },\n })\n }\n\n return chunks\n }\n\n private buildToolResultChunks(\n results: Array<ToolResult>,\n finishEvent: RunFinishedEvent,\n ): Array<StreamChunk> {\n const chunks: Array<StreamChunk> = []\n\n for (const result of results) {\n const content = JSON.stringify(result.result)\n\n chunks.push({\n type: 'TOOL_CALL_END',\n timestamp: Date.now(),\n model: finishEvent.model,\n toolCallId: result.toolCallId,\n toolName: result.toolName,\n result: content,\n })\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 // Build a set of completed tool IDs, but exclude tools with pendingExecution marker\n // (these are approved tools that still need to execute)\n const completedToolIds = new Set<string>()\n\n for (const message of this.messages) {\n if (message.role === 'tool' && message.toolCallId) {\n // Check if this is an approval response with pendingExecution marker\n let hasPendingExecution = false\n if (typeof message.content === 'string') {\n try {\n const parsed = JSON.parse(message.content)\n if (parsed.pendingExecution === true) {\n hasPendingExecution = true\n }\n } catch {\n // Not JSON, treat as regular tool result\n }\n }\n\n // Only mark as complete if NOT pending execution\n if (!hasPendingExecution) {\n completedToolIds.add(message.toolCallId)\n }\n }\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 createSyntheticFinishedEvent(): RunFinishedEvent {\n return {\n type: 'RUN_FINISHED',\n runId: 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 isMiddlewareAborted(): boolean {\n return !!this.middlewareAbortController?.signal.aborted\n }\n\n private isCancelled(): boolean {\n return this.isAborted() || this.isMiddlewareAborted()\n }\n\n private buildMiddlewareConfig(): ChatMiddlewareConfig {\n return {\n messages: this.messages,\n systemPrompts: [...this.systemPrompts],\n tools: [...this.tools],\n temperature: this.params.temperature,\n topP: this.params.topP,\n maxTokens: this.params.maxTokens,\n metadata: this.params.metadata,\n modelOptions: this.params.modelOptions,\n }\n }\n\n private applyMiddlewareConfig(config: ChatMiddlewareConfig): void {\n this.messages = config.messages\n this.systemPrompts = config.systemPrompts\n this.tools = config.tools\n this.params = {\n ...this.params,\n temperature: config.temperature,\n topP: config.topP,\n maxTokens: config.maxTokens,\n metadata: config.metadata,\n modelOptions: config.modelOptions,\n }\n\n // Sync context fields that depend on config\n this.middlewareCtx.messages = this.messages\n this.middlewareCtx.systemPrompts = this.systemPrompts\n this.middlewareCtx.hasTools = this.tools.length > 0\n this.middlewareCtx.toolNames = this.tools.map((t) => t.name)\n this.middlewareCtx.modelOptions = config.modelOptions\n }\n\n private setToolPhase(phase: ToolPhaseResult): void {\n this.toolPhase = phase\n }\n\n /**\n * Drain an executeToolCalls async generator, yielding any CustomEvent chunks\n * and returning the final ExecuteToolCallsResult.\n */\n private async *drainToolCallGenerator(\n generator: AsyncGenerator<\n CustomEvent,\n {\n results: Array<ToolResult>\n needsApproval: Array<ApprovalRequest>\n needsClientExecution: Array<ClientToolRequest>\n },\n void\n >,\n ): AsyncGenerator<\n StreamChunk,\n {\n results: Array<ToolResult>\n needsApproval: Array<ApprovalRequest>\n needsClientExecution: Array<ClientToolRequest>\n },\n void\n > {\n let next = await generator.next()\n while (!next.done) {\n yield next.value\n next = await generator.next()\n }\n return next.value\n }\n\n private createCustomEventChunk(\n eventName: string,\n value: Record<string, any>,\n ): CustomEvent {\n return {\n type: 'CUSTOM',\n timestamp: Date.now(),\n model: this.params.model,\n name: eventName,\n value,\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, middleware, context, ...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 middleware,\n context,\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, middleware, context, ...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 middleware,\n context,\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","transformedConfig"],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { Tool } from '../../../types.js';
2
+ /**
3
+ * Manages lazy tool discovery for the chat agent loop.
4
+ *
5
+ * Lazy tools are not sent to the LLM initially. Instead, a synthetic
6
+ * "discovery tool" is provided that lets the LLM discover lazy tools
7
+ * by name, receiving their full descriptions and schemas on demand.
8
+ */
9
+ export declare class LazyToolManager {
10
+ private readonly eagerTools;
11
+ private readonly lazyToolMap;
12
+ private readonly discoveredTools;
13
+ private hasNewDiscoveries;
14
+ private readonly discoveryTool;
15
+ constructor(tools: ReadonlyArray<Tool>, messages: ReadonlyArray<{
16
+ role: string;
17
+ content?: any;
18
+ toolCalls?: Array<{
19
+ id: string;
20
+ type: string;
21
+ function: {
22
+ name: string;
23
+ arguments: string;
24
+ };
25
+ }>;
26
+ toolCallId?: string;
27
+ }>);
28
+ /**
29
+ * Returns the set of tools that should be sent to the LLM:
30
+ * eager tools + discovered lazy tools + discovery tool (if undiscovered tools remain).
31
+ * Resets the hasNewDiscoveries flag.
32
+ */
33
+ getActiveTools(): Array<Tool>;
34
+ /**
35
+ * Returns whether new tools have been discovered since the last getActiveTools() call.
36
+ */
37
+ hasNewlyDiscoveredTools(): boolean;
38
+ /**
39
+ * Returns true if the given name is a lazy tool that has not yet been discovered.
40
+ */
41
+ isUndiscoveredLazyTool(name: string): boolean;
42
+ /**
43
+ * Returns a helpful error message for when an undiscovered lazy tool is called.
44
+ */
45
+ getUndiscoveredToolError(name: string): string;
46
+ /**
47
+ * Scans message history to find previously discovered lazy tools.
48
+ * Looks for assistant messages with discovery tool calls and their
49
+ * corresponding tool result messages.
50
+ */
51
+ private scanMessageHistory;
52
+ /**
53
+ * Creates the synthetic discovery tool that the LLM can call
54
+ * to discover lazy tools' descriptions and schemas.
55
+ */
56
+ private createDiscoveryTool;
57
+ }