@tanstack/openai-base 0.3.3 → 0.3.5

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.
@@ -6,9 +6,11 @@ import { extractRequestOptions } from "../utils/request-options.js";
6
6
  import { makeStructuredOutputCompatible } from "../utils/schema-converter.js";
7
7
  import { convertToolsToChatCompletionsFormat } from "./chat-completions-tool-converter.js";
8
8
  class OpenAIBaseChatCompletionsTextAdapter extends BaseTextAdapter {
9
+ kind = "text";
10
+ name;
11
+ client;
9
12
  constructor(model, name, client) {
10
13
  super({}, model);
11
- this.kind = "text";
12
14
  this.name = name;
13
15
  this.client = client;
14
16
  }
@@ -56,7 +58,10 @@ class OpenAIBaseChatCompletionsTextAdapter extends BaseTextAdapter {
56
58
  timestamp: Date.now(),
57
59
  message: errorPayload.message,
58
60
  code: errorPayload.code,
59
- error: errorPayload
61
+ error: {
62
+ message: errorPayload.message,
63
+ code: errorPayload.code
64
+ }
60
65
  };
61
66
  options.logger.errors(`${this.name}.chatStream fatal`, {
62
67
  error: errorPayload,
@@ -389,14 +394,18 @@ class OpenAIBaseChatCompletionsTextAdapter extends BaseTextAdapter {
389
394
  error,
390
395
  `${this.name}.structuredOutputStream failed`
391
396
  );
397
+ const resolvedCode = isAbort ? "aborted" : errorPayload.code;
392
398
  yield {
393
399
  type: EventType.RUN_ERROR,
394
400
  runId: aguiState.runId,
395
401
  model: lastModel || chatOptions.model,
396
402
  timestamp,
397
403
  message: errorPayload.message,
398
- code: isAbort ? "aborted" : errorPayload.code,
399
- error: { ...errorPayload, ...isAbort && { code: "aborted" } }
404
+ ...resolvedCode !== void 0 && { code: resolvedCode },
405
+ error: {
406
+ message: errorPayload.message,
407
+ ...resolvedCode !== void 0 && { code: resolvedCode }
408
+ }
400
409
  };
401
410
  chatOptions.logger.errors(`${this.name}.structuredOutputStream fatal`, {
402
411
  error: errorPayload,
@@ -572,15 +581,16 @@ class OpenAIBaseChatCompletionsTextAdapter extends BaseTextAdapter {
572
581
  if (deltaToolCalls) {
573
582
  for (const toolCallDelta of deltaToolCalls) {
574
583
  const index = toolCallDelta.index;
575
- if (!toolCallsInProgress.has(index)) {
576
- toolCallsInProgress.set(index, {
584
+ let toolCall = toolCallsInProgress.get(index);
585
+ if (!toolCall) {
586
+ toolCall = {
577
587
  id: toolCallDelta.id || "",
578
588
  name: toolCallDelta.function?.name || "",
579
589
  arguments: "",
580
590
  started: false
581
- });
591
+ };
592
+ toolCallsInProgress.set(index, toolCall);
582
593
  }
583
- const toolCall = toolCallsInProgress.get(index);
584
594
  if (toolCallDelta.id) {
585
595
  toolCall.id = toolCallDelta.id;
586
596
  }
@@ -743,11 +753,13 @@ class OpenAIBaseChatCompletionsTextAdapter extends BaseTextAdapter {
743
753
  threadId: aguiState.threadId,
744
754
  model: lastModel || options.model,
745
755
  timestamp: Date.now(),
746
- usage: lastUsage ? {
747
- promptTokens: lastUsage.prompt_tokens || 0,
748
- completionTokens: lastUsage.completion_tokens || 0,
749
- totalTokens: lastUsage.total_tokens || 0
750
- } : void 0,
756
+ ...lastUsage && {
757
+ usage: {
758
+ promptTokens: lastUsage.prompt_tokens || 0,
759
+ completionTokens: lastUsage.completion_tokens || 0,
760
+ totalTokens: lastUsage.total_tokens || 0
761
+ }
762
+ },
751
763
  finishReason
752
764
  };
753
765
  }
@@ -765,8 +777,11 @@ class OpenAIBaseChatCompletionsTextAdapter extends BaseTextAdapter {
765
777
  model: options.model,
766
778
  timestamp: Date.now(),
767
779
  message: errorPayload.message,
768
- code: errorPayload.code,
769
- error: errorPayload
780
+ ...errorPayload.code !== void 0 && { code: errorPayload.code },
781
+ error: {
782
+ message: errorPayload.message,
783
+ ...errorPayload.code !== void 0 && { code: errorPayload.code }
784
+ }
770
785
  };
771
786
  }
772
787
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chat-completions-text.js","sources":["../../../src/adapters/chat-completions-text.ts"],"sourcesContent":["import { EventType, normalizeSystemPrompts } from '@tanstack/ai'\nimport { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { generateId, transformNullsToUndefined } from '@tanstack/ai-utils'\nimport { extractRequestOptions } from '../utils/request-options'\nimport { makeStructuredOutputCompatible } from '../utils/schema-converter'\nimport { convertToolsToChatCompletionsFormat } from './chat-completions-tool-converter'\nimport type OpenAI from 'openai'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type {\n ChatCompletionChunk,\n ChatCompletionContentPart,\n ChatCompletionCreateParamsStreaming,\n ChatCompletionMessageParam,\n} from 'openai/resources/chat/completions/completions'\nimport type {\n ContentPart,\n DefaultMessageMetadataByModality,\n Modality,\n ModelMessage,\n RunFinishedEvent,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\n\n/**\n * Shared implementation of the OpenAI Chat Completions API. Holds the\n * stream-accumulator + AG-UI lifecycle logic and calls the OpenAI SDK\n * directly. Subclasses (ai-openai, ai-grok, ai-groq) construct an OpenAI\n * client with their provider-specific `baseURL` / headers and pass it in.\n */\nexport abstract class OpenAIBaseChatCompletionsTextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, unknown> = Record<string, unknown>,\n TInputModalities extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,\n TMessageMetadata extends DefaultMessageMetadataByModality =\n DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n> extends BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n TMessageMetadata,\n TToolCapabilities\n> {\n readonly kind = 'text' as const\n readonly name: string\n protected client: OpenAI\n\n constructor(model: TModel, name: string, client: OpenAI) {\n super({}, model)\n this.name = name\n this.client = client\n }\n\n async *chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n // AG-UI lifecycle tracking (mutable state object for ESLint compatibility)\n const aguiState = {\n runId: generateId(this.name),\n threadId: options.threadId ?? generateId(this.name),\n messageId: generateId(this.name),\n hasEmittedRunStarted: false,\n }\n\n try {\n // mapOptionsToRequest can throw (e.g. fail-loud guards in convertMessage\n // for empty content or unsupported parts). Keep it inside the try so\n // those failures surface as a single RUN_ERROR event, matching every\n // other failure mode here — callers iterating chatStream then only need\n // one error-handling path instead of both a try/catch around iteration\n // and a RUN_ERROR handler.\n const requestParams = this.mapOptionsToRequest(options)\n options.logger.request(\n `activity=chat provider=${this.name} model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,\n { provider: this.name, model: this.model },\n )\n const stream = await this.client.chat.completions.create(\n {\n ...requestParams,\n stream: true,\n stream_options: { include_usage: true },\n },\n extractRequestOptions(options.request),\n )\n\n yield* this.processStreamChunks(stream, options, aguiState)\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n const errorPayload = toRunErrorPayload(\n error,\n `${this.name}.chatStream failed`,\n )\n\n // Emit RUN_STARTED if not yet emitted\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: options.model,\n timestamp: Date.now(),\n parentRunId: options.parentRunId,\n }\n }\n\n // Emit AG-UI RUN_ERROR\n yield {\n type: EventType.RUN_ERROR,\n model: options.model,\n timestamp: Date.now(),\n message: errorPayload.message,\n code: errorPayload.code,\n error: errorPayload,\n }\n\n options.logger.errors(`${this.name}.chatStream fatal`, {\n error: errorPayload,\n source: `${this.name}.chatStream`,\n })\n }\n }\n\n /**\n * Generate structured output using the provider's JSON Schema response format.\n * Uses stream: false to get the complete response in one call.\n *\n * OpenAI-compatible APIs have strict requirements for structured output:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for all objects\n *\n * The outputSchema is already JSON Schema (converted in the ai layer).\n * We apply provider-specific transformations for structured output compatibility.\n */\n async structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>> {\n const { chatOptions, outputSchema } = options\n const requestParams = this.mapOptionsToRequest(chatOptions)\n\n const jsonSchema = this.makeStructuredOutputCompatible(\n outputSchema,\n outputSchema.required,\n )\n\n try {\n // Strip stream_options which is only valid for streaming calls\n const {\n stream_options: _,\n stream: __,\n ...cleanParams\n } = requestParams as any\n chatOptions.logger.request(\n `activity=structuredOutput provider=${this.name} model=${this.model} messages=${chatOptions.messages.length}`,\n { provider: this.name, model: this.model },\n )\n const response = await this.client.chat.completions.create(\n {\n ...cleanParams,\n stream: false,\n response_format: {\n type: 'json_schema',\n json_schema: {\n name: 'structured_output',\n schema: jsonSchema,\n strict: true,\n },\n },\n },\n extractRequestOptions(chatOptions.request),\n )\n\n // Extract text content from the response. Fail loud on empty content\n // rather than letting it cascade into a JSON-parse error on '' — the\n // root cause (the model returned no content for the structured request)\n // is then visible in logs.\n const rawText = response.choices[0]?.message.content\n if (typeof rawText !== 'string' || rawText.length === 0) {\n throw new Error(\n `${this.name}.structuredOutput: response contained no content`,\n )\n }\n\n // Parse the JSON response\n let parsed: unknown\n try {\n parsed = JSON.parse(rawText)\n } catch {\n throw new Error(\n `Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,\n )\n }\n\n // Transform null values to undefined to match original Zod schema expectations\n // Provider returns null for optional fields we made nullable in the schema.\n // Subclasses can override `transformStructuredOutput` to skip this — e.g.\n // OpenRouter historically passed nulls through unchanged.\n const transformed = this.transformStructuredOutput(parsed)\n\n return {\n data: transformed,\n rawText,\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n chatOptions.logger.errors(`${this.name}.structuredOutput fatal`, {\n error: toRunErrorPayload(error, `${this.name}.structuredOutput failed`),\n source: `${this.name}.structuredOutput`,\n })\n throw error\n }\n }\n\n /**\n * Stream structured output. Single Chat Completions request with\n * `response_format: json_schema` + `stream: true`. Emits the standard\n * AG-UI lifecycle (`RUN_STARTED` → `REASONING_*?` → `TEXT_MESSAGE_*`\n * carrying raw JSON deltas → terminal `CUSTOM 'structured-output.complete'`\n * → `RUN_FINISHED`). Subclasses use the same SDK-call / reasoning /\n * structured-output-transform hooks as `chatStream` / `structuredOutput` —\n * no per-subclass override should be needed.\n */\n async *structuredOutputStream(\n options: StructuredOutputOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const { chatOptions, outputSchema } = options\n const requestParams = this.mapOptionsToRequest(chatOptions)\n\n const jsonSchema = this.makeStructuredOutputCompatible(\n outputSchema,\n outputSchema.required,\n )\n\n const timestamp = Date.now()\n const aguiState = {\n runId: generateId(this.name),\n threadId: chatOptions.threadId ?? generateId(this.name),\n messageId: generateId(this.name),\n timestamp,\n hasEmittedRunStarted: false,\n }\n\n let accumulatedContent = ''\n let accumulatedReasoning = ''\n let hasEmittedTextMessageStart = false\n let reasoningMessageId: string | undefined\n let hasClosedReasoning = false\n let stepId: string | undefined\n let lastModel: string | undefined\n let lastUsage:\n | OpenAI.Chat.Completions.ChatCompletionChunk['usage']\n | undefined\n\n const closeReasoningLifecycle = function* (this: {\n name: string\n }): Generator<StreamChunk> {\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n model: lastModel || chatOptions.model,\n timestamp,\n }\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n model: lastModel || chatOptions.model,\n timestamp,\n }\n if (stepId) {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: stepId,\n stepId,\n model: lastModel || chatOptions.model,\n timestamp,\n content: accumulatedReasoning,\n }\n }\n }\n }.bind(this)\n\n try {\n // Strip stream_options + tools from the base request. Structured output\n // sends `response_format: json_schema` and doesn't carry tools — keeping\n // them in the request can confuse strict-mode validation upstream.\n const {\n stream_options: _so,\n stream: _s,\n tools: _t,\n ...cleanParams\n } = requestParams\n\n chatOptions.logger.request(\n `activity=structuredOutputStream provider=${this.name} model=${this.model} messages=${chatOptions.messages.length}`,\n { provider: this.name, model: this.model },\n )\n\n const stream = await this.client.chat.completions.create(\n {\n ...cleanParams,\n stream: true,\n stream_options: { include_usage: true },\n response_format: {\n type: 'json_schema',\n json_schema: {\n name: 'structured_output',\n schema: jsonSchema,\n strict: true,\n },\n },\n },\n extractRequestOptions(chatOptions.request),\n )\n\n for await (const chunk of stream) {\n const choiceForLog = chunk.choices[0]\n chatOptions.logger.provider(\n `provider=${this.name} finish_reason=${choiceForLog?.finish_reason ?? 'none'} hasContent=${!!choiceForLog?.delta.content} hasUsage=${!!chunk.usage}`,\n { provider: this.name, model: chunk.model },\n )\n\n if (chunk.model) lastModel = chunk.model\n\n // Usage may arrive on a chunk with empty `choices` (OpenAI's\n // include_usage terminal chunk) or piggybacked on a finish chunk\n // (`x_groq.usage` on Groq). Capture from either independent of\n // choices[0].\n const usage =\n chunk.usage ??\n (chunk as { x_groq?: { usage?: typeof chunk.usage } }).x_groq?.usage\n if (usage) lastUsage = usage\n\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chunk.model || chatOptions.model,\n timestamp,\n parentRunId: chatOptions.parentRunId,\n }\n }\n\n // Reasoning (via the extractReasoning hook — same hook as chatStream).\n const reasoning = this.extractReasoning(chunk)\n if (reasoning && reasoning.text) {\n if (!reasoningMessageId) {\n reasoningMessageId = generateId(this.name)\n stepId = generateId(this.name)\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n model: chunk.model || chatOptions.model,\n timestamp,\n }\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: 'reasoning' as const,\n model: chunk.model || chatOptions.model,\n timestamp,\n }\n yield {\n type: EventType.STEP_STARTED,\n stepName: stepId,\n stepId,\n model: chunk.model || chatOptions.model,\n timestamp,\n stepType: 'thinking',\n }\n }\n accumulatedReasoning += reasoning.text\n yield {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta: reasoning.text,\n model: chunk.model || chatOptions.model,\n timestamp,\n }\n }\n\n const choice = chunk.choices[0]\n if (!choice) continue\n\n const deltaContent = choice.delta.content\n if (deltaContent) {\n yield* closeReasoningLifecycle()\n\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield {\n type: EventType.TEXT_MESSAGE_START,\n messageId: aguiState.messageId,\n model: chunk.model || chatOptions.model,\n timestamp,\n role: 'assistant',\n }\n }\n\n accumulatedContent += deltaContent\n\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: aguiState.messageId,\n model: chunk.model || chatOptions.model,\n timestamp,\n delta: deltaContent,\n content: accumulatedContent,\n }\n }\n }\n\n // Finalisation: close any open lifecycle, parse + validate, emit\n // terminal events. This block always runs unless the loop threw — abort\n // and SDK errors land in the catch block below.\n yield* closeReasoningLifecycle()\n\n if (hasEmittedTextMessageStart) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n messageId: aguiState.messageId,\n model: lastModel || chatOptions.model,\n timestamp,\n }\n }\n\n if (accumulatedContent.length === 0) {\n yield {\n type: EventType.RUN_ERROR,\n runId: aguiState.runId,\n model: lastModel || chatOptions.model,\n timestamp,\n message: `${this.name}.structuredOutputStream: response contained no content`,\n code: 'empty-response',\n error: {\n message: `${this.name}.structuredOutputStream: response contained no content`,\n code: 'empty-response',\n },\n }\n return\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(accumulatedContent)\n } catch {\n yield {\n type: EventType.RUN_ERROR,\n runId: aguiState.runId,\n model: lastModel || chatOptions.model,\n timestamp,\n message: `Failed to parse structured output as JSON. Content: ${accumulatedContent.slice(0, 200)}${accumulatedContent.length > 200 ? '...' : ''}`,\n code: 'parse-error',\n error: {\n message: 'Failed to parse structured output as JSON',\n code: 'parse-error',\n },\n }\n return\n }\n\n const transformed = this.transformStructuredOutput(parsed)\n\n yield {\n type: EventType.CUSTOM,\n name: 'structured-output.complete',\n value: {\n object: transformed,\n raw: accumulatedContent,\n ...(accumulatedReasoning ? { reasoning: accumulatedReasoning } : {}),\n },\n model: lastModel || chatOptions.model,\n timestamp,\n }\n\n yield {\n type: EventType.RUN_FINISHED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: lastModel || chatOptions.model,\n timestamp,\n finishReason: 'stop',\n ...(lastUsage && {\n usage: {\n promptTokens: lastUsage.prompt_tokens,\n completionTokens: lastUsage.completion_tokens,\n totalTokens: lastUsage.total_tokens,\n },\n }),\n }\n } catch (error: unknown) {\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chatOptions.model,\n timestamp,\n parentRunId: chatOptions.parentRunId,\n }\n }\n\n const isAbort = this.isAbortError(error)\n const errorPayload = toRunErrorPayload(\n error,\n `${this.name}.structuredOutputStream failed`,\n )\n\n yield {\n type: EventType.RUN_ERROR,\n runId: aguiState.runId,\n model: lastModel || chatOptions.model,\n timestamp,\n message: errorPayload.message,\n code: isAbort ? 'aborted' : errorPayload.code,\n error: { ...errorPayload, ...(isAbort && { code: 'aborted' }) },\n }\n\n chatOptions.logger.errors(`${this.name}.structuredOutputStream fatal`, {\n error: errorPayload,\n source: `${this.name}.structuredOutputStream`,\n })\n }\n }\n\n /**\n * Cross-SDK abort detection for `structuredOutputStream`. Default duck-types\n * on `name === 'APIUserAbortError'` (OpenAI SDK), `code === 'ERR_CANCELED'`,\n * and standard `AbortError`s. Subclasses with proprietary error types (e.g.\n * `@openrouter/sdk`'s `RequestAbortedError`) override to extend the check.\n */\n protected isAbortError(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false\n const e = error as { name?: unknown; code?: unknown }\n return (\n e.name === 'APIUserAbortError' ||\n e.name === 'AbortError' ||\n e.code === 'ERR_CANCELED'\n )\n }\n\n /**\n * Applies provider-specific transformations for structured output compatibility.\n * Override this in subclasses to handle provider-specific quirks.\n */\n protected makeStructuredOutputCompatible(\n schema: Record<string, any>,\n originalRequired?: Array<string>,\n ): Record<string, any> {\n return makeStructuredOutputCompatible(schema, originalRequired)\n }\n\n /**\n * Extract reasoning content from a stream chunk. Default returns\n * `undefined` because the OpenAI Chat Completions chunk shape doesn't\n * carry reasoning. The chunk param is typed `unknown` so an override can\n * narrow to its own SDK chunk type without an `as` dance — the base only\n * passes through `processStreamChunks`'s structurally-iterated chunk.\n */\n protected extractReasoning(_chunk: unknown): { text: string } | undefined {\n return undefined\n }\n\n /**\n * Final shaping pass applied to parsed structured-output JSON before it is\n * returned to the caller. Default converts `null` values to `undefined` so\n * the result aligns with the original Zod schema's optional-field\n * semantics. Subclasses with different conventions (OpenRouter historically\n * preserves nulls) can override.\n */\n protected transformStructuredOutput(parsed: unknown): unknown {\n return transformNullsToUndefined(parsed)\n }\n\n /**\n * Processes streamed chunks from the Chat Completions API and yields AG-UI events.\n * Override this in subclasses to handle provider-specific stream behavior.\n */\n protected async *processStreamChunks(\n stream: AsyncIterable<ChatCompletionChunk>,\n options: TextOptions,\n aguiState: {\n runId: string\n threadId: string\n messageId: string\n hasEmittedRunStarted: boolean\n },\n ): AsyncIterable<StreamChunk> {\n let accumulatedContent = ''\n let hasEmittedTextMessageStart = false\n let lastModel: string | undefined\n // Track usage from any chunk that carries it. With\n // `stream_options: { include_usage: true }` OpenAI emits a terminal chunk\n // whose `choices` is `[]` and only the `usage` field is populated; the\n // earlier `finish_reason` chunk does NOT include token counts. We must\n // therefore defer RUN_FINISHED until the iterator is exhausted so we can\n // pick up usage from the trailing chunk regardless of arrival order.\n let lastUsage: ChatCompletionChunk['usage'] | undefined\n let pendingFinishReason:\n | ChatCompletionChunk['choices'][number]['finish_reason']\n | undefined\n\n // Track tool calls being streamed (arguments come in chunks)\n const toolCallsInProgress = new Map<\n number,\n {\n id: string\n name: string\n arguments: string\n started: boolean // Track if TOOL_CALL_START has been emitted\n }\n >()\n\n // Reasoning lifecycle (driven by extractReasoning() hook — see method\n // docs). The base wire format (OpenAI Chat Completions) has no reasoning,\n // so these stay unused for openai/grok/groq. OpenRouter etc. opt in.\n let reasoningMessageId: string | undefined\n let hasClosedReasoning = false\n // Legacy STEP_STARTED/STEP_FINISHED pair emitted alongside REASONING_*\n // for back-compat with consumers (UI, devtools) that haven't migrated\n // to the spec REASONING_* events yet.\n let stepId: string | undefined\n let accumulatedReasoning = ''\n // Track whether ANY tool call lifecycle was actually completed across the\n // entire stream. Lets us downgrade a `tool_calls` finish_reason to `stop`\n // when the upstream signalled tool calls but never produced a complete\n // start/end pair — emitting RUN_FINISHED { finishReason: 'tool_calls' }\n // with no matching TOOL_CALL_END would leave consumers waiting for tool\n // results that never arrive.\n let emittedAnyToolCallEnd = false\n\n try {\n for await (const chunk of stream) {\n const choiceForLog = chunk.choices[0]\n options.logger.provider(\n `provider=${this.name} finish_reason=${choiceForLog?.finish_reason ?? 'none'} hasContent=${!!choiceForLog?.delta.content} hasToolCalls=${!!choiceForLog?.delta.tool_calls} hasUsage=${!!chunk.usage}`,\n { provider: this.name, model: chunk.model },\n )\n\n // Capture usage from any chunk (including the terminal usage-only\n // chunk emitted when `stream_options.include_usage` is on).\n if (chunk.usage) {\n lastUsage = chunk.usage\n }\n if (chunk.model) {\n lastModel = chunk.model\n }\n\n // Emit RUN_STARTED on the first chunk of any kind so callers see a\n // run lifecycle even on streams that arrive entirely as usage-only\n // (no choices). Without this, a usage-first stream would skip\n // RUN_STARTED via `if (!choice) continue` below and the post-loop\n // synthetic block would also skip RUN_FINISHED (it gates on\n // `hasEmittedRunStarted`).\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n parentRunId: options.parentRunId,\n }\n }\n\n // Reasoning content (extractReasoning() hook). Run before reading\n // choice/delta so reasoning-only chunks (no `choices`) still drive\n // the REASONING_* lifecycle on providers that send reasoning out of\n // band. The base default returns undefined.\n const reasoning = this.extractReasoning(chunk)\n if (reasoning && reasoning.text) {\n if (!reasoningMessageId) {\n reasoningMessageId = generateId(this.name)\n stepId = generateId(this.name)\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: 'reasoning' as const,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n // Legacy STEP_STARTED (single emission, paired with the\n // STEP_FINISHED below when reasoning closes).\n yield {\n type: EventType.STEP_STARTED,\n stepName: stepId,\n stepId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n stepType: 'thinking',\n }\n }\n accumulatedReasoning += reasoning.text\n yield {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta: reasoning.text,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n }\n\n const choice = chunk.choices[0]\n\n if (!choice) continue\n\n const delta = choice.delta\n const deltaContent = delta.content\n const deltaToolCalls = delta.tool_calls\n\n // Handle content delta\n if (deltaContent) {\n // Close reasoning before text starts so consumers see a clean\n // REASONING_END before any TEXT_MESSAGE_START.\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n if (stepId) {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: stepId,\n stepId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n content: accumulatedReasoning,\n }\n }\n }\n\n // Emit TEXT_MESSAGE_START on first text content\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield {\n type: EventType.TEXT_MESSAGE_START,\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n role: 'assistant',\n }\n }\n\n accumulatedContent += deltaContent\n\n // Emit AG-UI TEXT_MESSAGE_CONTENT\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n delta: deltaContent,\n content: accumulatedContent,\n }\n }\n\n // Handle tool calls - they come in as deltas\n if (deltaToolCalls) {\n for (const toolCallDelta of deltaToolCalls) {\n const index = toolCallDelta.index\n\n // Initialize or update the tool call in progress\n if (!toolCallsInProgress.has(index)) {\n toolCallsInProgress.set(index, {\n id: toolCallDelta.id || '',\n name: toolCallDelta.function?.name || '',\n arguments: '',\n started: false,\n })\n }\n\n const toolCall = toolCallsInProgress.get(index)!\n\n // Update with any new data from the delta\n if (toolCallDelta.id) {\n toolCall.id = toolCallDelta.id\n }\n if (toolCallDelta.function?.name) {\n toolCall.name = toolCallDelta.function.name\n }\n if (toolCallDelta.function?.arguments) {\n toolCall.arguments += toolCallDelta.function.arguments\n }\n\n // Emit TOOL_CALL_START when we have id and name\n if (toolCall.id && toolCall.name && !toolCall.started) {\n toolCall.started = true\n yield {\n type: EventType.TOOL_CALL_START,\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n index,\n }\n }\n\n // Emit TOOL_CALL_ARGS for argument deltas\n if (toolCallDelta.function?.arguments && toolCall.started) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: toolCall.id,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n delta: toolCallDelta.function.arguments,\n }\n }\n }\n }\n\n // Handle finish reason. We DO emit TOOL_CALL_END and TEXT_MESSAGE_END\n // here because the corresponding _START events have already fired,\n // and tool execution downstream wants to begin as soon as possible.\n // RUN_FINISHED is deferred until the iterator is fully exhausted so\n // we can capture the trailing usage chunk that arrives AFTER this\n // chunk when stream_options.include_usage is on.\n if (choice.finish_reason) {\n if (\n choice.finish_reason === 'tool_calls' ||\n toolCallsInProgress.size > 0\n ) {\n for (const [, toolCall] of toolCallsInProgress) {\n // Skip tool calls that never emitted TOOL_CALL_START — emitting\n // a stray TOOL_CALL_END here would violate AG-UI lifecycle\n // (END without matching START) for partial deltas where the\n // upstream never sent both id and name.\n if (!toolCall.started) continue\n\n // Parse arguments for TOOL_CALL_END. Surface parse failures via\n // the logger so a model emitting malformed JSON for tool args\n // is debuggable instead of silently invoking the tool with {}.\n // Non-object JSON (e.g. a bare string or number) is also coerced\n // to {} so downstream tool execution doesn't receive a primitive\n // input, mirroring the Responses adapter's guard.\n let parsedInput: unknown = {}\n if (toolCall.arguments) {\n try {\n const parsed: unknown = JSON.parse(toolCall.arguments)\n parsedInput =\n parsed && typeof parsed === 'object' ? parsed : {}\n } catch (parseError) {\n options.logger.errors(\n `${this.name}.processStreamChunks tool-args JSON parse failed`,\n {\n error: toRunErrorPayload(\n parseError,\n `tool ${toolCall.name} (${toolCall.id}) returned malformed JSON arguments`,\n ),\n source: `${this.name}.processStreamChunks`,\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n rawArguments: toolCall.arguments,\n },\n )\n parsedInput = {}\n }\n }\n\n // Emit AG-UI TOOL_CALL_END\n yield {\n type: EventType.TOOL_CALL_END,\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n input: parsedInput,\n }\n emittedAnyToolCallEnd = true\n }\n // Clear tool-call state after emission so a subsequent\n // `finish_reason: 'stop'` chunk (or the post-loop synthetic\n // block) doesn't see lingering entries and misreport the finish.\n toolCallsInProgress.clear()\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (hasEmittedTextMessageStart) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n hasEmittedTextMessageStart = false\n }\n\n // Remember the upstream finish_reason; RUN_FINISHED is emitted at\n // end-of-stream so we pick up the trailing usage-only chunk too.\n pendingFinishReason = choice.finish_reason\n }\n }\n\n // Emit a single terminal RUN_FINISHED after the iterator is exhausted.\n // This both delivers accurate token counts (the trailing usage chunk\n // may arrive AFTER the finish_reason chunk) and gives consumers a\n // guaranteed terminal event even when the upstream cuts off mid-stream\n // (no finish_reason chunk ever arrives).\n if (aguiState.hasEmittedRunStarted) {\n // Close any started tool calls that never got finish_reason. A\n // truncated stream that emitted TOOL_CALL_START but never reached\n // finish_reason would otherwise leave consumers with an unbalanced\n // start. Skip non-started entries (no matching START to close).\n let pendingToolCount = 0\n for (const [, toolCall] of toolCallsInProgress) {\n if (!toolCall.started) continue\n let parsedInput: unknown = {}\n if (toolCall.arguments) {\n try {\n const parsed: unknown = JSON.parse(toolCall.arguments)\n parsedInput = parsed && typeof parsed === 'object' ? parsed : {}\n } catch (parseError) {\n // Mirror the finish_reason path's logger call — a truncated\n // stream emitting malformed tool-call JSON would otherwise\n // silently invoke the tool with `{}`, the exact failure the\n // finish_reason logger was added to prevent.\n options.logger.errors(\n `${this.name}.processStreamChunks tool-args JSON parse failed (drain)`,\n {\n error: toRunErrorPayload(\n parseError,\n `tool ${toolCall.name} (${toolCall.id}) returned malformed JSON arguments`,\n ),\n source: `${this.name}.processStreamChunks`,\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n rawArguments: toolCall.arguments,\n },\n )\n parsedInput = {}\n }\n }\n yield {\n type: EventType.TOOL_CALL_END,\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: lastModel || options.model,\n timestamp: Date.now(),\n input: parsedInput,\n }\n pendingToolCount += 1\n emittedAnyToolCallEnd = true\n }\n toolCallsInProgress.clear()\n\n // Make sure the text message lifecycle is closed even on early\n // termination paths where finish_reason never arrives.\n if (hasEmittedTextMessageStart) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n messageId: aguiState.messageId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n }\n }\n\n // Close any reasoning lifecycle that text never closed (no text\n // content arrived, or the stream cut off before text started).\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n }\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n }\n if (stepId) {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: stepId,\n stepId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n content: accumulatedReasoning,\n }\n }\n }\n\n // Map upstream finish_reason to AG-UI's narrower vocabulary.\n // Collapsing length / content_filter to 'stop' would hide why the\n // run terminated — surface it instead. Use `tool_calls` only when\n // a TOOL_CALL_END was actually emitted: an upstream that signalled\n // `tool_calls` but never produced a started/ended pair must NOT\n // surface `tool_calls` here, since downstream consumers wait for\n // tool results that would never arrive. OpenAI's legacy\n // `function_call` value (from the v1 function-calling API) is\n // normalized to `tool_calls` — semantically the same termination.\n const finishReason: NonNullable<RunFinishedEvent['finishReason']> =\n emittedAnyToolCallEnd\n ? 'tool_calls'\n : pendingFinishReason === 'tool_calls'\n ? 'stop'\n : pendingFinishReason === 'function_call'\n ? 'tool_calls'\n : (pendingFinishReason ?? 'stop')\n\n yield {\n type: EventType.RUN_FINISHED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n usage: lastUsage\n ? {\n promptTokens: lastUsage.prompt_tokens || 0,\n completionTokens: lastUsage.completion_tokens || 0,\n totalTokens: lastUsage.total_tokens || 0,\n }\n : undefined,\n finishReason,\n }\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n const errorPayload = toRunErrorPayload(\n error,\n `${this.name}.processStreamChunks failed`,\n )\n options.logger.errors(`${this.name}.processStreamChunks fatal`, {\n error: errorPayload,\n source: `${this.name}.processStreamChunks`,\n })\n\n // Emit AG-UI RUN_ERROR\n yield {\n type: EventType.RUN_ERROR,\n model: options.model,\n timestamp: Date.now(),\n message: errorPayload.message,\n code: errorPayload.code,\n error: errorPayload,\n }\n }\n }\n\n /**\n * Maps common TextOptions to Chat Completions API request format.\n * Override this in subclasses to add provider-specific options.\n */\n protected mapOptionsToRequest(\n options: TextOptions,\n ): ChatCompletionCreateParamsStreaming {\n const tools = options.tools\n ? convertToolsToChatCompletionsFormat(\n options.tools,\n this.makeStructuredOutputCompatible.bind(this),\n )\n : undefined\n\n // Build messages array with system prompts\n const messages: Array<ChatCompletionMessageParam> = []\n\n // Add system prompts first\n const systemPrompts = normalizeSystemPrompts(options.systemPrompts)\n if (systemPrompts.length > 0) {\n messages.push({\n role: 'system',\n content: systemPrompts.map((p) => p.content).join('\\n'),\n })\n }\n\n // Convert messages\n for (const message of options.messages) {\n messages.push(this.convertMessage(message))\n }\n\n const modelOptions = options.modelOptions\n\n // Build the request so explicit top-level options win over modelOptions\n // when set, but `undefined` top-level options do NOT clobber values the\n // caller put in modelOptions. Keeping the merge nullish-aware fixes the\n // silent regression where a `modelOptions: { temperature: 0.7 }` setting\n // was overwritten with `temperature: undefined`.\n return {\n ...modelOptions,\n model: options.model,\n messages,\n ...(options.temperature !== undefined && {\n temperature: options.temperature,\n }),\n ...(options.maxTokens !== undefined && {\n max_tokens: options.maxTokens,\n }),\n ...(options.topP !== undefined && { top_p: options.topP }),\n // Conditional spread: `tools: undefined` would clobber any\n // modelOptions.tools the caller set above.\n ...(tools &&\n tools.length > 0 && {\n tools,\n }),\n stream: true,\n }\n }\n\n /**\n * Converts a single ModelMessage to the Chat Completions API message format.\n * Override this in subclasses to handle provider-specific message formats.\n */\n protected convertMessage(message: ModelMessage): ChatCompletionMessageParam {\n // Handle tool messages\n if (message.role === 'tool') {\n return {\n role: 'tool',\n tool_call_id: message.toolCallId || '',\n content:\n typeof message.content === 'string'\n ? message.content\n : JSON.stringify(message.content),\n }\n }\n\n // Handle assistant messages\n if (message.role === 'assistant') {\n const toolCalls = message.toolCalls?.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.function.name,\n arguments:\n typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments),\n },\n }))\n const hasToolCalls = !!toolCalls && toolCalls.length > 0\n const textContent = this.extractTextContent(message.content)\n\n // Per the OpenAI Chat Completions contract, an assistant message that\n // only carries tool_calls should have `content: null` (or omit content)\n // rather than `content: ''`. Empty-string content interacts oddly with\n // tokenization on some backends; null is the documented shape.\n return {\n role: 'assistant',\n content: hasToolCalls && !textContent ? null : textContent,\n ...(hasToolCalls ? { tool_calls: toolCalls } : {}),\n }\n }\n\n // Handle user messages - support multimodal content\n const contentParts = this.normalizeContent(message.content)\n\n // If only text, use simple string format\n if (contentParts.length === 1 && contentParts[0]?.type === 'text') {\n const text = contentParts[0].content\n if (text.length === 0) {\n // Single empty text part is the same fail-loud condition as below —\n // an empty paid request mask a real intent (caller passed `null`/'',\n // or an upstream step normalised everything to an empty string).\n throw new Error(\n `User message for ${this.name} has empty text content. ` +\n `Empty user messages would produce a paid request with no input; ` +\n `provide non-empty content or omit the message.`,\n )\n }\n return {\n role: 'user',\n content: text,\n }\n }\n\n // Otherwise, use array format for multimodal. Fail fast on unsupported\n // content parts rather than silently dropping them — a message of all\n // unsupported parts would otherwise turn into an empty user prompt and\n // mask a real capability mismatch.\n const parts: Array<ChatCompletionContentPart> = []\n for (const part of contentParts) {\n const converted = this.convertContentPart(part)\n if (!converted) {\n throw new Error(\n `Unsupported content part type for ${this.name}: ${part.type}. ` +\n `Override convertContentPart() in a subclass to handle this type, ` +\n `or remove it from the message.`,\n )\n }\n parts.push(converted)\n }\n\n if (parts.length === 0) {\n // The original message had no content parts at all (e.g. content was\n // explicitly null or []). Sending an empty user message to OpenAI\n // produces a paid request with no signal — fail loud instead.\n throw new Error(\n `User message for ${this.name} has no content parts. ` +\n `Empty user messages would produce a paid request with no input; ` +\n `provide at least one text/image/audio part or omit the message.`,\n )\n }\n\n return {\n role: 'user',\n content: parts,\n }\n }\n\n /**\n * Converts a single ContentPart to the Chat Completions API content part format.\n * Override this in subclasses to handle additional content types or provider-specific metadata.\n */\n protected convertContentPart(\n part: ContentPart,\n ): ChatCompletionContentPart | null {\n if (part.type === 'text') {\n return { type: 'text', text: part.content }\n }\n\n if (part.type === 'image') {\n const imageMetadata = part.metadata as\n | { detail?: 'auto' | 'low' | 'high' }\n | undefined\n\n // For base64 data, construct a data URI using the mimeType from source.\n // Default to a generic octet-stream MIME if the source didn't provide\n // one — interpolating `undefined` into the URI (\"data:undefined;base64,\n // ...\") would produce an invalid URI the API rejects.\n const imageValue = part.source.value\n const imageMime = part.source.mimeType || 'application/octet-stream'\n const imageUrl =\n part.source.type === 'data' && !imageValue.startsWith('data:')\n ? `data:${imageMime};base64,${imageValue}`\n : imageValue\n\n return {\n type: 'image_url',\n image_url: {\n url: imageUrl,\n detail: imageMetadata?.detail || 'auto',\n },\n }\n }\n\n // Unsupported content type — subclasses can override to handle more types\n return null\n }\n\n /**\n * Normalizes message content to an array of ContentPart.\n * Handles backward compatibility with string content.\n */\n protected normalizeContent(\n content: string | null | Array<ContentPart>,\n ): Array<ContentPart> {\n if (content === null) {\n return []\n }\n if (typeof content === 'string') {\n return [{ type: 'text', content: content }]\n }\n return content\n }\n\n /**\n * Extracts text content from a content value that may be string, null, or ContentPart array.\n */\n protected extractTextContent(\n content: string | null | Array<ContentPart>,\n ): string {\n if (content === null) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n // It's an array of ContentPart\n return content\n .filter((p) => p.type === 'text')\n .map((p) => p.content)\n .join('')\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat-completions-text.js","sources":["../../../src/adapters/chat-completions-text.ts"],"sourcesContent":["import { EventType, normalizeSystemPrompts } from '@tanstack/ai'\nimport { BaseTextAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { generateId, transformNullsToUndefined } from '@tanstack/ai-utils'\nimport { extractRequestOptions } from '../utils/request-options'\nimport { makeStructuredOutputCompatible } from '../utils/schema-converter'\nimport { convertToolsToChatCompletionsFormat } from './chat-completions-tool-converter'\nimport type OpenAI from 'openai'\nimport type {\n StructuredOutputOptions,\n StructuredOutputResult,\n} from '@tanstack/ai/adapters'\nimport type {\n ChatCompletionChunk,\n ChatCompletionContentPart,\n ChatCompletionCreateParamsStreaming,\n ChatCompletionMessageParam,\n} from 'openai/resources/chat/completions/completions'\nimport type {\n ContentPart,\n DefaultMessageMetadataByModality,\n Modality,\n ModelMessage,\n RunFinishedEvent,\n StreamChunk,\n TextOptions,\n} from '@tanstack/ai'\n\n/**\n * Shared implementation of the OpenAI Chat Completions API. Holds the\n * stream-accumulator + AG-UI lifecycle logic and calls the OpenAI SDK\n * directly. Subclasses (ai-openai, ai-grok, ai-groq) construct an OpenAI\n * client with their provider-specific `baseURL` / headers and pass it in.\n */\nexport abstract class OpenAIBaseChatCompletionsTextAdapter<\n TModel extends string,\n TProviderOptions extends Record<string, unknown> = Record<string, unknown>,\n TInputModalities extends ReadonlyArray<Modality> = ReadonlyArray<Modality>,\n TMessageMetadata extends DefaultMessageMetadataByModality =\n DefaultMessageMetadataByModality,\n TToolCapabilities extends ReadonlyArray<string> = ReadonlyArray<string>,\n> extends BaseTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n TMessageMetadata,\n TToolCapabilities\n> {\n override readonly kind = 'text' as const\n readonly name: string\n protected client: OpenAI\n\n constructor(model: TModel, name: string, client: OpenAI) {\n super({}, model)\n this.name = name\n this.client = client\n }\n\n async *chatStream(\n options: TextOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n // AG-UI lifecycle tracking (mutable state object for ESLint compatibility)\n const aguiState = {\n runId: generateId(this.name),\n threadId: options.threadId ?? generateId(this.name),\n messageId: generateId(this.name),\n hasEmittedRunStarted: false,\n }\n\n try {\n // mapOptionsToRequest can throw (e.g. fail-loud guards in convertMessage\n // for empty content or unsupported parts). Keep it inside the try so\n // those failures surface as a single RUN_ERROR event, matching every\n // other failure mode here — callers iterating chatStream then only need\n // one error-handling path instead of both a try/catch around iteration\n // and a RUN_ERROR handler.\n const requestParams = this.mapOptionsToRequest(options)\n options.logger.request(\n `activity=chat provider=${this.name} model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,\n { provider: this.name, model: this.model },\n )\n const stream = await this.client.chat.completions.create(\n {\n ...requestParams,\n stream: true,\n stream_options: { include_usage: true },\n },\n extractRequestOptions(options.request),\n )\n\n yield* this.processStreamChunks(stream, options, aguiState)\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n const errorPayload = toRunErrorPayload(\n error,\n `${this.name}.chatStream failed`,\n )\n\n // Emit RUN_STARTED if not yet emitted\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: options.model,\n timestamp: Date.now(),\n parentRunId: options.parentRunId,\n }\n }\n\n // Emit AG-UI RUN_ERROR. Conditional `code` spread keeps the wire\n // shape spec-compliant under `exactOptionalPropertyTypes`: AG-UI's\n // `RunErrorEvent.code` is `string?` (absent vs explicit `undefined`\n // matter), so we omit the key when there's no code.\n yield {\n type: EventType.RUN_ERROR,\n model: options.model,\n timestamp: Date.now(),\n message: errorPayload.message,\n code: errorPayload.code,\n error: {\n message: errorPayload.message,\n code: errorPayload.code,\n },\n }\n\n options.logger.errors(`${this.name}.chatStream fatal`, {\n error: errorPayload,\n source: `${this.name}.chatStream`,\n })\n }\n }\n\n /**\n * Generate structured output using the provider's JSON Schema response format.\n * Uses stream: false to get the complete response in one call.\n *\n * OpenAI-compatible APIs have strict requirements for structured output:\n * - All properties must be in the `required` array\n * - Optional fields should have null added to their type union\n * - additionalProperties must be false for all objects\n *\n * The outputSchema is already JSON Schema (converted in the ai layer).\n * We apply provider-specific transformations for structured output compatibility.\n */\n async structuredOutput(\n options: StructuredOutputOptions<TProviderOptions>,\n ): Promise<StructuredOutputResult<unknown>> {\n const { chatOptions, outputSchema } = options\n const requestParams = this.mapOptionsToRequest(chatOptions)\n\n const jsonSchema = this.makeStructuredOutputCompatible(\n outputSchema,\n outputSchema.required,\n )\n\n try {\n // Strip stream_options which is only valid for streaming calls\n const {\n stream_options: _,\n stream: __,\n ...cleanParams\n } = requestParams as any\n chatOptions.logger.request(\n `activity=structuredOutput provider=${this.name} model=${this.model} messages=${chatOptions.messages.length}`,\n { provider: this.name, model: this.model },\n )\n const response = await this.client.chat.completions.create(\n {\n ...cleanParams,\n stream: false,\n response_format: {\n type: 'json_schema',\n json_schema: {\n name: 'structured_output',\n schema: jsonSchema,\n strict: true,\n },\n },\n },\n extractRequestOptions(chatOptions.request),\n )\n\n // Extract text content from the response. Fail loud on empty content\n // rather than letting it cascade into a JSON-parse error on '' — the\n // root cause (the model returned no content for the structured request)\n // is then visible in logs.\n const rawText = response.choices[0]?.message.content\n if (typeof rawText !== 'string' || rawText.length === 0) {\n throw new Error(\n `${this.name}.structuredOutput: response contained no content`,\n )\n }\n\n // Parse the JSON response\n let parsed: unknown\n try {\n parsed = JSON.parse(rawText)\n } catch {\n throw new Error(\n `Failed to parse structured output as JSON. Content: ${rawText.slice(0, 200)}${rawText.length > 200 ? '...' : ''}`,\n )\n }\n\n // Transform null values to undefined to match original Zod schema expectations\n // Provider returns null for optional fields we made nullable in the schema.\n // Subclasses can override `transformStructuredOutput` to skip this — e.g.\n // OpenRouter historically passed nulls through unchanged.\n const transformed = this.transformStructuredOutput(parsed)\n\n return {\n data: transformed,\n rawText,\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n chatOptions.logger.errors(`${this.name}.structuredOutput fatal`, {\n error: toRunErrorPayload(error, `${this.name}.structuredOutput failed`),\n source: `${this.name}.structuredOutput`,\n })\n throw error\n }\n }\n\n /**\n * Stream structured output. Single Chat Completions request with\n * `response_format: json_schema` + `stream: true`. Emits the standard\n * AG-UI lifecycle (`RUN_STARTED` → `REASONING_*?` → `TEXT_MESSAGE_*`\n * carrying raw JSON deltas → terminal `CUSTOM 'structured-output.complete'`\n * → `RUN_FINISHED`). Subclasses use the same SDK-call / reasoning /\n * structured-output-transform hooks as `chatStream` / `structuredOutput` —\n * no per-subclass override should be needed.\n */\n async *structuredOutputStream(\n options: StructuredOutputOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const { chatOptions, outputSchema } = options\n const requestParams = this.mapOptionsToRequest(chatOptions)\n\n const jsonSchema = this.makeStructuredOutputCompatible(\n outputSchema,\n outputSchema.required,\n )\n\n const timestamp = Date.now()\n const aguiState = {\n runId: generateId(this.name),\n threadId: chatOptions.threadId ?? generateId(this.name),\n messageId: generateId(this.name),\n timestamp,\n hasEmittedRunStarted: false,\n }\n\n let accumulatedContent = ''\n let accumulatedReasoning = ''\n let hasEmittedTextMessageStart = false\n let reasoningMessageId: string | undefined\n let hasClosedReasoning = false\n let stepId: string | undefined\n let lastModel: string | undefined\n let lastUsage:\n | OpenAI.Chat.Completions.ChatCompletionChunk['usage']\n | undefined\n\n const closeReasoningLifecycle = function* (this: {\n name: string\n }): Generator<StreamChunk> {\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n model: lastModel || chatOptions.model,\n timestamp,\n }\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n model: lastModel || chatOptions.model,\n timestamp,\n }\n if (stepId) {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: stepId,\n stepId,\n model: lastModel || chatOptions.model,\n timestamp,\n content: accumulatedReasoning,\n }\n }\n }\n }.bind(this)\n\n try {\n // Strip stream_options + tools from the base request. Structured output\n // sends `response_format: json_schema` and doesn't carry tools — keeping\n // them in the request can confuse strict-mode validation upstream.\n const {\n stream_options: _so,\n stream: _s,\n tools: _t,\n ...cleanParams\n } = requestParams\n\n chatOptions.logger.request(\n `activity=structuredOutputStream provider=${this.name} model=${this.model} messages=${chatOptions.messages.length}`,\n { provider: this.name, model: this.model },\n )\n\n const stream = await this.client.chat.completions.create(\n {\n ...cleanParams,\n stream: true,\n stream_options: { include_usage: true },\n response_format: {\n type: 'json_schema',\n json_schema: {\n name: 'structured_output',\n schema: jsonSchema,\n strict: true,\n },\n },\n },\n extractRequestOptions(chatOptions.request),\n )\n\n for await (const chunk of stream) {\n const choiceForLog = chunk.choices[0]\n chatOptions.logger.provider(\n `provider=${this.name} finish_reason=${choiceForLog?.finish_reason ?? 'none'} hasContent=${!!choiceForLog?.delta.content} hasUsage=${!!chunk.usage}`,\n { provider: this.name, model: chunk.model },\n )\n\n if (chunk.model) lastModel = chunk.model\n\n // Usage may arrive on a chunk with empty `choices` (OpenAI's\n // include_usage terminal chunk) or piggybacked on a finish chunk\n // (`x_groq.usage` on Groq). Capture from either independent of\n // choices[0].\n const usage =\n chunk.usage ??\n (chunk as { x_groq?: { usage?: typeof chunk.usage } }).x_groq?.usage\n if (usage) lastUsage = usage\n\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chunk.model || chatOptions.model,\n timestamp,\n parentRunId: chatOptions.parentRunId,\n }\n }\n\n // Reasoning (via the extractReasoning hook — same hook as chatStream).\n const reasoning = this.extractReasoning(chunk)\n if (reasoning && reasoning.text) {\n if (!reasoningMessageId) {\n reasoningMessageId = generateId(this.name)\n stepId = generateId(this.name)\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n model: chunk.model || chatOptions.model,\n timestamp,\n }\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: 'reasoning' as const,\n model: chunk.model || chatOptions.model,\n timestamp,\n }\n yield {\n type: EventType.STEP_STARTED,\n stepName: stepId,\n stepId,\n model: chunk.model || chatOptions.model,\n timestamp,\n stepType: 'thinking',\n }\n }\n accumulatedReasoning += reasoning.text\n yield {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta: reasoning.text,\n model: chunk.model || chatOptions.model,\n timestamp,\n }\n }\n\n const choice = chunk.choices[0]\n if (!choice) continue\n\n const deltaContent = choice.delta.content\n if (deltaContent) {\n yield* closeReasoningLifecycle()\n\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield {\n type: EventType.TEXT_MESSAGE_START,\n messageId: aguiState.messageId,\n model: chunk.model || chatOptions.model,\n timestamp,\n role: 'assistant',\n }\n }\n\n accumulatedContent += deltaContent\n\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: aguiState.messageId,\n model: chunk.model || chatOptions.model,\n timestamp,\n delta: deltaContent,\n content: accumulatedContent,\n }\n }\n }\n\n // Finalisation: close any open lifecycle, parse + validate, emit\n // terminal events. This block always runs unless the loop threw — abort\n // and SDK errors land in the catch block below.\n yield* closeReasoningLifecycle()\n\n if (hasEmittedTextMessageStart) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n messageId: aguiState.messageId,\n model: lastModel || chatOptions.model,\n timestamp,\n }\n }\n\n if (accumulatedContent.length === 0) {\n yield {\n type: EventType.RUN_ERROR,\n runId: aguiState.runId,\n model: lastModel || chatOptions.model,\n timestamp,\n message: `${this.name}.structuredOutputStream: response contained no content`,\n code: 'empty-response',\n error: {\n message: `${this.name}.structuredOutputStream: response contained no content`,\n code: 'empty-response',\n },\n }\n return\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(accumulatedContent)\n } catch {\n yield {\n type: EventType.RUN_ERROR,\n runId: aguiState.runId,\n model: lastModel || chatOptions.model,\n timestamp,\n message: `Failed to parse structured output as JSON. Content: ${accumulatedContent.slice(0, 200)}${accumulatedContent.length > 200 ? '...' : ''}`,\n code: 'parse-error',\n error: {\n message: 'Failed to parse structured output as JSON',\n code: 'parse-error',\n },\n }\n return\n }\n\n const transformed = this.transformStructuredOutput(parsed)\n\n yield {\n type: EventType.CUSTOM,\n name: 'structured-output.complete',\n value: {\n object: transformed,\n raw: accumulatedContent,\n ...(accumulatedReasoning ? { reasoning: accumulatedReasoning } : {}),\n },\n model: lastModel || chatOptions.model,\n timestamp,\n }\n\n yield {\n type: EventType.RUN_FINISHED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: lastModel || chatOptions.model,\n timestamp,\n finishReason: 'stop',\n ...(lastUsage && {\n usage: {\n promptTokens: lastUsage.prompt_tokens,\n completionTokens: lastUsage.completion_tokens,\n totalTokens: lastUsage.total_tokens,\n },\n }),\n }\n } catch (error: unknown) {\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chatOptions.model,\n timestamp,\n parentRunId: chatOptions.parentRunId,\n }\n }\n\n const isAbort = this.isAbortError(error)\n const errorPayload = toRunErrorPayload(\n error,\n `${this.name}.structuredOutputStream failed`,\n )\n\n // Conditional `code` spread keeps the wire shape spec-compliant under\n // `exactOptionalPropertyTypes`: AG-UI's `RunErrorEvent.code` is `string?`\n // (absent vs explicit `undefined` matter).\n const resolvedCode = isAbort ? 'aborted' : errorPayload.code\n yield {\n type: EventType.RUN_ERROR,\n runId: aguiState.runId,\n model: lastModel || chatOptions.model,\n timestamp,\n message: errorPayload.message,\n ...(resolvedCode !== undefined && { code: resolvedCode }),\n error: {\n message: errorPayload.message,\n ...(resolvedCode !== undefined && { code: resolvedCode }),\n },\n }\n\n chatOptions.logger.errors(`${this.name}.structuredOutputStream fatal`, {\n error: errorPayload,\n source: `${this.name}.structuredOutputStream`,\n })\n }\n }\n\n /**\n * Cross-SDK abort detection for `structuredOutputStream`. Default duck-types\n * on `name === 'APIUserAbortError'` (OpenAI SDK), `code === 'ERR_CANCELED'`,\n * and standard `AbortError`s. Subclasses with proprietary error types (e.g.\n * `@openrouter/sdk`'s `RequestAbortedError`) override to extend the check.\n */\n protected isAbortError(error: unknown): boolean {\n if (!error || typeof error !== 'object') return false\n const e = error as { name?: unknown; code?: unknown }\n return (\n e.name === 'APIUserAbortError' ||\n e.name === 'AbortError' ||\n e.code === 'ERR_CANCELED'\n )\n }\n\n /**\n * Applies provider-specific transformations for structured output compatibility.\n * Override this in subclasses to handle provider-specific quirks.\n */\n protected makeStructuredOutputCompatible(\n schema: Record<string, any>,\n originalRequired?: Array<string>,\n ): Record<string, any> {\n return makeStructuredOutputCompatible(schema, originalRequired)\n }\n\n /**\n * Extract reasoning content from a stream chunk. Default returns\n * `undefined` because the OpenAI Chat Completions chunk shape doesn't\n * carry reasoning. The chunk param is typed `unknown` so an override can\n * narrow to its own SDK chunk type without an `as` dance — the base only\n * passes through `processStreamChunks`'s structurally-iterated chunk.\n */\n protected extractReasoning(_chunk: unknown): { text: string } | undefined {\n return undefined\n }\n\n /**\n * Final shaping pass applied to parsed structured-output JSON before it is\n * returned to the caller. Default converts `null` values to `undefined` so\n * the result aligns with the original Zod schema's optional-field\n * semantics. Subclasses with different conventions (OpenRouter historically\n * preserves nulls) can override.\n */\n protected transformStructuredOutput(parsed: unknown): unknown {\n return transformNullsToUndefined(parsed)\n }\n\n /**\n * Processes streamed chunks from the Chat Completions API and yields AG-UI events.\n * Override this in subclasses to handle provider-specific stream behavior.\n */\n protected async *processStreamChunks(\n stream: AsyncIterable<ChatCompletionChunk>,\n options: TextOptions,\n aguiState: {\n runId: string\n threadId: string\n messageId: string\n hasEmittedRunStarted: boolean\n },\n ): AsyncIterable<StreamChunk> {\n let accumulatedContent = ''\n let hasEmittedTextMessageStart = false\n let lastModel: string | undefined\n // Track usage from any chunk that carries it. With\n // `stream_options: { include_usage: true }` OpenAI emits a terminal chunk\n // whose `choices` is `[]` and only the `usage` field is populated; the\n // earlier `finish_reason` chunk does NOT include token counts. We must\n // therefore defer RUN_FINISHED until the iterator is exhausted so we can\n // pick up usage from the trailing chunk regardless of arrival order.\n let lastUsage: ChatCompletionChunk['usage'] | undefined\n let pendingFinishReason:\n | ChatCompletionChunk['choices'][number]['finish_reason']\n | undefined\n\n // Track tool calls being streamed (arguments come in chunks)\n const toolCallsInProgress = new Map<\n number,\n {\n id: string\n name: string\n arguments: string\n started: boolean // Track if TOOL_CALL_START has been emitted\n }\n >()\n\n // Reasoning lifecycle (driven by extractReasoning() hook — see method\n // docs). The base wire format (OpenAI Chat Completions) has no reasoning,\n // so these stay unused for openai/grok/groq. OpenRouter etc. opt in.\n let reasoningMessageId: string | undefined\n let hasClosedReasoning = false\n // Legacy STEP_STARTED/STEP_FINISHED pair emitted alongside REASONING_*\n // for back-compat with consumers (UI, devtools) that haven't migrated\n // to the spec REASONING_* events yet.\n let stepId: string | undefined\n let accumulatedReasoning = ''\n // Track whether ANY tool call lifecycle was actually completed across the\n // entire stream. Lets us downgrade a `tool_calls` finish_reason to `stop`\n // when the upstream signalled tool calls but never produced a complete\n // start/end pair — emitting RUN_FINISHED { finishReason: 'tool_calls' }\n // with no matching TOOL_CALL_END would leave consumers waiting for tool\n // results that never arrive.\n let emittedAnyToolCallEnd = false\n\n try {\n for await (const chunk of stream) {\n const choiceForLog = chunk.choices[0]\n options.logger.provider(\n `provider=${this.name} finish_reason=${choiceForLog?.finish_reason ?? 'none'} hasContent=${!!choiceForLog?.delta.content} hasToolCalls=${!!choiceForLog?.delta.tool_calls} hasUsage=${!!chunk.usage}`,\n { provider: this.name, model: chunk.model },\n )\n\n // Capture usage from any chunk (including the terminal usage-only\n // chunk emitted when `stream_options.include_usage` is on).\n if (chunk.usage) {\n lastUsage = chunk.usage\n }\n if (chunk.model) {\n lastModel = chunk.model\n }\n\n // Emit RUN_STARTED on the first chunk of any kind so callers see a\n // run lifecycle even on streams that arrive entirely as usage-only\n // (no choices). Without this, a usage-first stream would skip\n // RUN_STARTED via `if (!choice) continue` below and the post-loop\n // synthetic block would also skip RUN_FINISHED (it gates on\n // `hasEmittedRunStarted`).\n if (!aguiState.hasEmittedRunStarted) {\n aguiState.hasEmittedRunStarted = true\n yield {\n type: EventType.RUN_STARTED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n parentRunId: options.parentRunId,\n }\n }\n\n // Reasoning content (extractReasoning() hook). Run before reading\n // choice/delta so reasoning-only chunks (no `choices`) still drive\n // the REASONING_* lifecycle on providers that send reasoning out of\n // band. The base default returns undefined.\n const reasoning = this.extractReasoning(chunk)\n if (reasoning && reasoning.text) {\n if (!reasoningMessageId) {\n reasoningMessageId = generateId(this.name)\n stepId = generateId(this.name)\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: 'reasoning' as const,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n // Legacy STEP_STARTED (single emission, paired with the\n // STEP_FINISHED below when reasoning closes).\n yield {\n type: EventType.STEP_STARTED,\n stepName: stepId,\n stepId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n stepType: 'thinking',\n }\n }\n accumulatedReasoning += reasoning.text\n yield {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId,\n delta: reasoning.text,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n }\n\n const choice = chunk.choices[0]\n\n if (!choice) continue\n\n const delta = choice.delta\n const deltaContent = delta.content\n const deltaToolCalls = delta.tool_calls\n\n // Handle content delta\n if (deltaContent) {\n // Close reasoning before text starts so consumers see a clean\n // REASONING_END before any TEXT_MESSAGE_START.\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n if (stepId) {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: stepId,\n stepId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n content: accumulatedReasoning,\n }\n }\n }\n\n // Emit TEXT_MESSAGE_START on first text content\n if (!hasEmittedTextMessageStart) {\n hasEmittedTextMessageStart = true\n yield {\n type: EventType.TEXT_MESSAGE_START,\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n role: 'assistant',\n }\n }\n\n accumulatedContent += deltaContent\n\n // Emit AG-UI TEXT_MESSAGE_CONTENT\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n delta: deltaContent,\n content: accumulatedContent,\n }\n }\n\n // Handle tool calls - they come in as deltas\n if (deltaToolCalls) {\n for (const toolCallDelta of deltaToolCalls) {\n const index = toolCallDelta.index\n\n // Initialize or update the tool call in progress\n let toolCall = toolCallsInProgress.get(index)\n if (!toolCall) {\n toolCall = {\n id: toolCallDelta.id || '',\n name: toolCallDelta.function?.name || '',\n arguments: '',\n started: false,\n }\n toolCallsInProgress.set(index, toolCall)\n }\n\n // Update with any new data from the delta\n if (toolCallDelta.id) {\n toolCall.id = toolCallDelta.id\n }\n if (toolCallDelta.function?.name) {\n toolCall.name = toolCallDelta.function.name\n }\n if (toolCallDelta.function?.arguments) {\n toolCall.arguments += toolCallDelta.function.arguments\n }\n\n // Emit TOOL_CALL_START when we have id and name\n if (toolCall.id && toolCall.name && !toolCall.started) {\n toolCall.started = true\n yield {\n type: EventType.TOOL_CALL_START,\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n index,\n }\n }\n\n // Emit TOOL_CALL_ARGS for argument deltas\n if (toolCallDelta.function?.arguments && toolCall.started) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: toolCall.id,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n delta: toolCallDelta.function.arguments,\n }\n }\n }\n }\n\n // Handle finish reason. We DO emit TOOL_CALL_END and TEXT_MESSAGE_END\n // here because the corresponding _START events have already fired,\n // and tool execution downstream wants to begin as soon as possible.\n // RUN_FINISHED is deferred until the iterator is fully exhausted so\n // we can capture the trailing usage chunk that arrives AFTER this\n // chunk when stream_options.include_usage is on.\n if (choice.finish_reason) {\n if (\n choice.finish_reason === 'tool_calls' ||\n toolCallsInProgress.size > 0\n ) {\n for (const [, toolCall] of toolCallsInProgress) {\n // Skip tool calls that never emitted TOOL_CALL_START — emitting\n // a stray TOOL_CALL_END here would violate AG-UI lifecycle\n // (END without matching START) for partial deltas where the\n // upstream never sent both id and name.\n if (!toolCall.started) continue\n\n // Parse arguments for TOOL_CALL_END. Surface parse failures via\n // the logger so a model emitting malformed JSON for tool args\n // is debuggable instead of silently invoking the tool with {}.\n // Non-object JSON (e.g. a bare string or number) is also coerced\n // to {} so downstream tool execution doesn't receive a primitive\n // input, mirroring the Responses adapter's guard.\n let parsedInput: unknown = {}\n if (toolCall.arguments) {\n try {\n const parsed: unknown = JSON.parse(toolCall.arguments)\n parsedInput =\n parsed && typeof parsed === 'object' ? parsed : {}\n } catch (parseError) {\n options.logger.errors(\n `${this.name}.processStreamChunks tool-args JSON parse failed`,\n {\n error: toRunErrorPayload(\n parseError,\n `tool ${toolCall.name} (${toolCall.id}) returned malformed JSON arguments`,\n ),\n source: `${this.name}.processStreamChunks`,\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n rawArguments: toolCall.arguments,\n },\n )\n parsedInput = {}\n }\n }\n\n // Emit AG-UI TOOL_CALL_END\n yield {\n type: EventType.TOOL_CALL_END,\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n input: parsedInput,\n }\n emittedAnyToolCallEnd = true\n }\n // Clear tool-call state after emission so a subsequent\n // `finish_reason: 'stop'` chunk (or the post-loop synthetic\n // block) doesn't see lingering entries and misreport the finish.\n toolCallsInProgress.clear()\n }\n\n // Emit TEXT_MESSAGE_END if we had text content\n if (hasEmittedTextMessageStart) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n messageId: aguiState.messageId,\n model: chunk.model || options.model,\n timestamp: Date.now(),\n }\n hasEmittedTextMessageStart = false\n }\n\n // Remember the upstream finish_reason; RUN_FINISHED is emitted at\n // end-of-stream so we pick up the trailing usage-only chunk too.\n pendingFinishReason = choice.finish_reason\n }\n }\n\n // Emit a single terminal RUN_FINISHED after the iterator is exhausted.\n // This both delivers accurate token counts (the trailing usage chunk\n // may arrive AFTER the finish_reason chunk) and gives consumers a\n // guaranteed terminal event even when the upstream cuts off mid-stream\n // (no finish_reason chunk ever arrives).\n if (aguiState.hasEmittedRunStarted) {\n // Close any started tool calls that never got finish_reason. A\n // truncated stream that emitted TOOL_CALL_START but never reached\n // finish_reason would otherwise leave consumers with an unbalanced\n // start. Skip non-started entries (no matching START to close).\n let pendingToolCount = 0\n for (const [, toolCall] of toolCallsInProgress) {\n if (!toolCall.started) continue\n let parsedInput: unknown = {}\n if (toolCall.arguments) {\n try {\n const parsed: unknown = JSON.parse(toolCall.arguments)\n parsedInput = parsed && typeof parsed === 'object' ? parsed : {}\n } catch (parseError) {\n // Mirror the finish_reason path's logger call — a truncated\n // stream emitting malformed tool-call JSON would otherwise\n // silently invoke the tool with `{}`, the exact failure the\n // finish_reason logger was added to prevent.\n options.logger.errors(\n `${this.name}.processStreamChunks tool-args JSON parse failed (drain)`,\n {\n error: toRunErrorPayload(\n parseError,\n `tool ${toolCall.name} (${toolCall.id}) returned malformed JSON arguments`,\n ),\n source: `${this.name}.processStreamChunks`,\n toolCallId: toolCall.id,\n toolName: toolCall.name,\n rawArguments: toolCall.arguments,\n },\n )\n parsedInput = {}\n }\n }\n yield {\n type: EventType.TOOL_CALL_END,\n toolCallId: toolCall.id,\n toolCallName: toolCall.name,\n toolName: toolCall.name,\n model: lastModel || options.model,\n timestamp: Date.now(),\n input: parsedInput,\n }\n pendingToolCount += 1\n emittedAnyToolCallEnd = true\n }\n toolCallsInProgress.clear()\n\n // Make sure the text message lifecycle is closed even on early\n // termination paths where finish_reason never arrives.\n if (hasEmittedTextMessageStart) {\n yield {\n type: EventType.TEXT_MESSAGE_END,\n messageId: aguiState.messageId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n }\n }\n\n // Close any reasoning lifecycle that text never closed (no text\n // content arrived, or the stream cut off before text started).\n if (reasoningMessageId && !hasClosedReasoning) {\n hasClosedReasoning = true\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n }\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n }\n if (stepId) {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: stepId,\n stepId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n content: accumulatedReasoning,\n }\n }\n }\n\n // Map upstream finish_reason to AG-UI's narrower vocabulary.\n // Collapsing length / content_filter to 'stop' would hide why the\n // run terminated — surface it instead. Use `tool_calls` only when\n // a TOOL_CALL_END was actually emitted: an upstream that signalled\n // `tool_calls` but never produced a started/ended pair must NOT\n // surface `tool_calls` here, since downstream consumers wait for\n // tool results that would never arrive. OpenAI's legacy\n // `function_call` value (from the v1 function-calling API) is\n // normalized to `tool_calls` — semantically the same termination.\n const finishReason: NonNullable<RunFinishedEvent['finishReason']> =\n emittedAnyToolCallEnd\n ? 'tool_calls'\n : pendingFinishReason === 'tool_calls'\n ? 'stop'\n : pendingFinishReason === 'function_call'\n ? 'tool_calls'\n : (pendingFinishReason ?? 'stop')\n\n // Conditional `usage` spread: AG-UI's `RunFinishedEvent.usage` is\n // optional with no `| undefined`; omit the key entirely when no usage\n // arrived rather than emitting `usage: undefined`.\n yield {\n type: EventType.RUN_FINISHED,\n runId: aguiState.runId,\n threadId: aguiState.threadId,\n model: lastModel || options.model,\n timestamp: Date.now(),\n ...(lastUsage && {\n usage: {\n promptTokens: lastUsage.prompt_tokens || 0,\n completionTokens: lastUsage.completion_tokens || 0,\n totalTokens: lastUsage.total_tokens || 0,\n },\n }),\n finishReason,\n }\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n const errorPayload = toRunErrorPayload(\n error,\n `${this.name}.processStreamChunks failed`,\n )\n options.logger.errors(`${this.name}.processStreamChunks fatal`, {\n error: errorPayload,\n source: `${this.name}.processStreamChunks`,\n })\n\n // Emit AG-UI RUN_ERROR with conditional `code` spread (see chatStream's\n // catch block for the rationale).\n yield {\n type: EventType.RUN_ERROR,\n model: options.model,\n timestamp: Date.now(),\n message: errorPayload.message,\n ...(errorPayload.code !== undefined && { code: errorPayload.code }),\n error: {\n message: errorPayload.message,\n ...(errorPayload.code !== undefined && { code: errorPayload.code }),\n },\n }\n }\n }\n\n /**\n * Maps common TextOptions to Chat Completions API request format.\n * Override this in subclasses to add provider-specific options.\n */\n protected mapOptionsToRequest(\n options: TextOptions,\n ): ChatCompletionCreateParamsStreaming {\n const tools = options.tools\n ? convertToolsToChatCompletionsFormat(\n options.tools,\n this.makeStructuredOutputCompatible.bind(this),\n )\n : undefined\n\n // Build messages array with system prompts\n const messages: Array<ChatCompletionMessageParam> = []\n\n // Add system prompts first\n const systemPrompts = normalizeSystemPrompts(options.systemPrompts)\n if (systemPrompts.length > 0) {\n messages.push({\n role: 'system',\n content: systemPrompts.map((p) => p.content).join('\\n'),\n })\n }\n\n // Convert messages\n for (const message of options.messages) {\n messages.push(this.convertMessage(message))\n }\n\n const modelOptions = options.modelOptions\n\n // Build the request so explicit top-level options win over modelOptions\n // when set, but `undefined` top-level options do NOT clobber values the\n // caller put in modelOptions. Keeping the merge nullish-aware fixes the\n // silent regression where a `modelOptions: { temperature: 0.7 }` setting\n // was overwritten with `temperature: undefined`.\n return {\n ...modelOptions,\n model: options.model,\n messages,\n ...(options.temperature !== undefined && {\n temperature: options.temperature,\n }),\n ...(options.maxTokens !== undefined && {\n max_tokens: options.maxTokens,\n }),\n ...(options.topP !== undefined && { top_p: options.topP }),\n // Conditional spread: `tools: undefined` would clobber any\n // modelOptions.tools the caller set above.\n ...(tools &&\n tools.length > 0 && {\n tools,\n }),\n stream: true,\n }\n }\n\n /**\n * Converts a single ModelMessage to the Chat Completions API message format.\n * Override this in subclasses to handle provider-specific message formats.\n */\n protected convertMessage(message: ModelMessage): ChatCompletionMessageParam {\n // Handle tool messages\n if (message.role === 'tool') {\n return {\n role: 'tool',\n tool_call_id: message.toolCallId || '',\n content:\n typeof message.content === 'string'\n ? message.content\n : JSON.stringify(message.content),\n }\n }\n\n // Handle assistant messages\n if (message.role === 'assistant') {\n const toolCalls = message.toolCalls?.map((tc) => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.function.name,\n arguments:\n typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments),\n },\n }))\n const hasToolCalls = !!toolCalls && toolCalls.length > 0\n const textContent = this.extractTextContent(message.content)\n\n // Per the OpenAI Chat Completions contract, an assistant message that\n // only carries tool_calls should have `content: null` (or omit content)\n // rather than `content: ''`. Empty-string content interacts oddly with\n // tokenization on some backends; null is the documented shape.\n return {\n role: 'assistant',\n content: hasToolCalls && !textContent ? null : textContent,\n ...(hasToolCalls ? { tool_calls: toolCalls } : {}),\n }\n }\n\n // Handle user messages - support multimodal content\n const contentParts = this.normalizeContent(message.content)\n\n // If only text, use simple string format\n if (contentParts.length === 1 && contentParts[0]?.type === 'text') {\n const text = contentParts[0].content\n if (text.length === 0) {\n // Single empty text part is the same fail-loud condition as below —\n // an empty paid request mask a real intent (caller passed `null`/'',\n // or an upstream step normalised everything to an empty string).\n throw new Error(\n `User message for ${this.name} has empty text content. ` +\n `Empty user messages would produce a paid request with no input; ` +\n `provide non-empty content or omit the message.`,\n )\n }\n return {\n role: 'user',\n content: text,\n }\n }\n\n // Otherwise, use array format for multimodal. Fail fast on unsupported\n // content parts rather than silently dropping them — a message of all\n // unsupported parts would otherwise turn into an empty user prompt and\n // mask a real capability mismatch.\n const parts: Array<ChatCompletionContentPart> = []\n for (const part of contentParts) {\n const converted = this.convertContentPart(part)\n if (!converted) {\n throw new Error(\n `Unsupported content part type for ${this.name}: ${part.type}. ` +\n `Override convertContentPart() in a subclass to handle this type, ` +\n `or remove it from the message.`,\n )\n }\n parts.push(converted)\n }\n\n if (parts.length === 0) {\n // The original message had no content parts at all (e.g. content was\n // explicitly null or []). Sending an empty user message to OpenAI\n // produces a paid request with no signal — fail loud instead.\n throw new Error(\n `User message for ${this.name} has no content parts. ` +\n `Empty user messages would produce a paid request with no input; ` +\n `provide at least one text/image/audio part or omit the message.`,\n )\n }\n\n return {\n role: 'user',\n content: parts,\n }\n }\n\n /**\n * Converts a single ContentPart to the Chat Completions API content part format.\n * Override this in subclasses to handle additional content types or provider-specific metadata.\n */\n protected convertContentPart(\n part: ContentPart,\n ): ChatCompletionContentPart | null {\n if (part.type === 'text') {\n return { type: 'text', text: part.content }\n }\n\n if (part.type === 'image') {\n const imageMetadata = part.metadata as\n | { detail?: 'auto' | 'low' | 'high' }\n | undefined\n\n // For base64 data, construct a data URI using the mimeType from source.\n // Default to a generic octet-stream MIME if the source didn't provide\n // one — interpolating `undefined` into the URI (\"data:undefined;base64,\n // ...\") would produce an invalid URI the API rejects.\n const imageValue = part.source.value\n const imageMime = part.source.mimeType || 'application/octet-stream'\n const imageUrl =\n part.source.type === 'data' && !imageValue.startsWith('data:')\n ? `data:${imageMime};base64,${imageValue}`\n : imageValue\n\n return {\n type: 'image_url',\n image_url: {\n url: imageUrl,\n detail: imageMetadata?.detail || 'auto',\n },\n }\n }\n\n // Unsupported content type — subclasses can override to handle more types\n return null\n }\n\n /**\n * Normalizes message content to an array of ContentPart.\n * Handles backward compatibility with string content.\n */\n protected normalizeContent(\n content: string | null | Array<ContentPart>,\n ): Array<ContentPart> {\n if (content === null) {\n return []\n }\n if (typeof content === 'string') {\n return [{ type: 'text', content: content }]\n }\n return content\n }\n\n /**\n * Extracts text content from a content value that may be string, null, or ContentPart array.\n */\n protected extractTextContent(\n content: string | null | Array<ContentPart>,\n ): string {\n if (content === null) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n // It's an array of ContentPart\n return content\n .filter((p) => p.type === 'text')\n .map((p) => p.content)\n .join('')\n }\n}\n"],"names":[],"mappings":"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"}
@@ -86,7 +86,7 @@ export declare abstract class OpenAIBaseResponsesTextAdapter<TModel extends stri
86
86
  name: string;
87
87
  started: boolean;
88
88
  ended?: boolean;
89
- pendingArguments?: string;
89
+ pendingArguments?: string | undefined;
90
90
  }>, options: TextOptions<TProviderOptions>, aguiState: {
91
91
  runId: string;
92
92
  threadId: string;
@@ -6,9 +6,11 @@ import { extractRequestOptions } from "../utils/request-options.js";
6
6
  import { makeStructuredOutputCompatible } from "../utils/schema-converter.js";
7
7
  import { convertToolsToResponsesFormat } from "./responses-tool-converter.js";
8
8
  class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
9
+ kind = "text";
10
+ name;
11
+ client;
9
12
  constructor(model, name, client) {
10
13
  super({}, model);
11
- this.kind = "text";
12
14
  this.name = name;
13
15
  this.client = client;
14
16
  }
@@ -61,7 +63,10 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
61
63
  timestamp: Date.now(),
62
64
  message: errorPayload.message,
63
65
  code: errorPayload.code,
64
- error: errorPayload
66
+ error: {
67
+ message: errorPayload.message,
68
+ code: errorPayload.code
69
+ }
65
70
  };
66
71
  options.logger.errors(`${this.name}.chatStream fatal`, {
67
72
  error: errorPayload,
@@ -293,11 +298,11 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
293
298
  const reasoningDelta = Array.isArray(raw) ? raw.join("") : typeof raw === "string" ? raw : "";
294
299
  if (!reasoningDelta) continue;
295
300
  yield* openReasoning();
296
- const messageId = reasoningMessageId;
301
+ if (!reasoningMessageId) continue;
297
302
  accumulatedReasoning += reasoningDelta;
298
303
  yield {
299
304
  type: EventType.REASONING_MESSAGE_CONTENT,
300
- messageId,
305
+ messageId: reasoningMessageId,
301
306
  delta: reasoningDelta,
302
307
  model,
303
308
  timestamp
@@ -339,14 +344,15 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
339
344
  if (chunk.type === "response.failed") {
340
345
  const response = chunk.response;
341
346
  const message = response?.error?.message || "Responses API stream failed";
347
+ const code = response?.error?.code;
342
348
  yield {
343
349
  type: EventType.RUN_ERROR,
344
350
  runId: aguiState.runId,
345
351
  model,
346
352
  timestamp,
347
353
  message,
348
- code: response?.error?.code,
349
- error: { message, code: response?.error?.code }
354
+ ...code !== void 0 && { code },
355
+ error: { message, ...code !== void 0 && { code } }
350
356
  };
351
357
  return;
352
358
  }
@@ -437,14 +443,18 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
437
443
  error,
438
444
  `${this.name}.structuredOutputStream failed`
439
445
  );
446
+ const resolvedCode = isAbort ? "aborted" : errorPayload.code;
440
447
  yield {
441
448
  type: EventType.RUN_ERROR,
442
449
  runId: aguiState.runId,
443
450
  model,
444
451
  timestamp,
445
452
  message: errorPayload.message,
446
- code: isAbort ? "aborted" : errorPayload.code,
447
- error: { ...errorPayload, ...isAbort && { code: "aborted" } }
453
+ ...resolvedCode !== void 0 && { code: resolvedCode },
454
+ error: {
455
+ message: errorPayload.message,
456
+ ...resolvedCode !== void 0 && { code: resolvedCode }
457
+ }
448
458
  };
449
459
  chatOptions.logger.errors(`${this.name}.structuredOutputStream fatal`, {
450
460
  error: errorPayload,
@@ -796,17 +806,17 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
796
806
  if (chunk.type === "response.output_item.added") {
797
807
  const item = chunk.item;
798
808
  if (item.type === "function_call" && item.id) {
799
- const existing = toolCallMetadata.get(item.id);
800
- if (!existing) {
801
- toolCallMetadata.set(item.id, {
809
+ let metadata = toolCallMetadata.get(item.id);
810
+ if (!metadata) {
811
+ metadata = {
802
812
  index: chunk.output_index,
803
813
  name: item.name || "",
804
814
  started: false
805
- });
806
- } else if (!existing.name && item.name) {
807
- existing.name = item.name;
815
+ };
816
+ toolCallMetadata.set(item.id, metadata);
817
+ } else if (!metadata.name && item.name) {
818
+ metadata.name = item.name;
808
819
  }
809
- const metadata = toolCallMetadata.get(item.id);
810
820
  if (!metadata.started && metadata.name) {
811
821
  yield {
812
822
  type: EventType.TOOL_CALL_START,
@@ -1051,15 +1061,16 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
1051
1061
  runFinishedEmitted = true;
1052
1062
  }
1053
1063
  if (chunk.type === "error") {
1064
+ const code = chunk.code ?? void 0;
1054
1065
  yield {
1055
1066
  type: EventType.RUN_ERROR,
1056
1067
  model: model || options.model,
1057
1068
  timestamp: Date.now(),
1058
1069
  message: chunk.message,
1059
- code: chunk.code ?? void 0,
1070
+ ...code !== void 0 && { code },
1060
1071
  error: {
1061
1072
  message: chunk.message,
1062
- code: chunk.code ?? void 0
1073
+ ...code !== void 0 && { code }
1063
1074
  }
1064
1075
  };
1065
1076
  runFinishedEmitted = true;
@@ -1081,7 +1092,6 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
1081
1092
  threadId: aguiState.threadId,
1082
1093
  model: model || options.model,
1083
1094
  timestamp: Date.now(),
1084
- usage: void 0,
1085
1095
  finishReason: toolCallMetadata.size > 0 ? "tool_calls" : "stop"
1086
1096
  };
1087
1097
  }
@@ -1099,8 +1109,11 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
1099
1109
  model: options.model,
1100
1110
  timestamp: Date.now(),
1101
1111
  message: errorPayload.message,
1102
- code: errorPayload.code,
1103
- error: errorPayload
1112
+ ...errorPayload.code !== void 0 && { code: errorPayload.code },
1113
+ error: {
1114
+ message: errorPayload.message,
1115
+ ...errorPayload.code !== void 0 && { code: errorPayload.code }
1116
+ }
1104
1117
  };
1105
1118
  }
1106
1119
  }
@@ -1245,6 +1258,8 @@ class OpenAIBaseResponsesTextAdapter extends BaseTextAdapter {
1245
1258
  file_data: audioFileData
1246
1259
  };
1247
1260
  }
1261
+ case "video":
1262
+ case "document":
1248
1263
  default:
1249
1264
  throw new Error(`Unsupported content part type: ${part.type}`);
1250
1265
  }