UNPKG

@ai-sdk/open-responses

Version:

The **[Open Responses provider](https://ai-sdk.dev/providers/ai-sdk-providers/open-responses)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for [Open Responses](https://www.openresponses.org/) compatible APIs.

1 lines 68.4 kB
{"version":3,"sources":["../src/version.ts","../src/open-responses-provider.ts","../src/responses/open-responses-language-model.ts","../src/responses/convert-to-open-responses-input.ts","../src/responses/open-responses-api.ts","../src/responses/map-open-responses-finish-reason.ts","../src/responses/open-responses-options.ts"],"sourcesContent":["// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n","import {\n LanguageModelV3,\n NoSuchModelError,\n ProviderV3,\n} from '@ai-sdk/provider';\nimport {\n FetchFunction,\n generateId,\n loadApiKey,\n withUserAgentSuffix,\n} from '@ai-sdk/provider-utils';\nimport { OpenResponsesLanguageModel } from './responses/open-responses-language-model';\nimport { VERSION } from './version';\n\nexport interface OpenResponsesProvider extends ProviderV3 {\n (modelId: string): LanguageModelV3;\n}\n\nexport interface OpenResponsesProviderSettings {\n /**\n * URL for the Open Responses API POST endpoint.\n */\n url: string;\n\n /**\n * Provider name. Used as key for provider options and metadata.\n */\n name: string;\n\n /**\n * API key for authenticating requests.\n */\n apiKey?: string;\n\n /**\n * Custom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation. You can use it as a middleware to intercept requests,\n * or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n}\n\nexport function createOpenResponses(\n options: OpenResponsesProviderSettings,\n): OpenResponsesProvider {\n const providerName = options.name;\n\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n ...(options.apiKey\n ? {\n Authorization: `Bearer ${options.apiKey}`,\n }\n : {}),\n ...options.headers,\n },\n `ai-sdk/open-responses/${VERSION}`,\n );\n\n const createResponsesModel = (modelId: string) => {\n return new OpenResponsesLanguageModel(modelId, {\n provider: `${providerName}.responses`,\n providerOptionsName: providerName,\n headers: getHeaders,\n url: options.url,\n fetch: options.fetch,\n generateId: () => generateId(),\n });\n };\n\n const createLanguageModel = (modelId: string) => {\n if (new.target) {\n throw new Error(\n 'The OpenAI model function cannot be called with the new keyword.',\n );\n }\n\n return createResponsesModel(modelId);\n };\n\n const provider = function (modelId: string) {\n return createLanguageModel(modelId);\n };\n\n provider.specificationVersion = 'v3' as const;\n provider.languageModel = createLanguageModel;\n\n provider.embeddingModel = (modelId: string) => {\n throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' });\n };\n provider.imageModel = (modelId: string) => {\n throw new NoSuchModelError({ modelId, modelType: 'imageModel' });\n };\n\n return provider as OpenResponsesProvider;\n}\n","import {\n LanguageModelV3,\n LanguageModelV3CallOptions,\n LanguageModelV3Content,\n LanguageModelV3FinishReason,\n LanguageModelV3GenerateResult,\n LanguageModelV3StreamPart,\n LanguageModelV3StreamResult,\n LanguageModelV3Usage,\n SharedV3Warning,\n} from '@ai-sdk/provider';\nimport {\n combineHeaders,\n createEventSourceResponseHandler,\n createJsonErrorResponseHandler,\n createJsonResponseHandler,\n jsonSchema,\n parseProviderOptions,\n ParseResult,\n postJsonToApi,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport { convertToOpenResponsesInput } from './convert-to-open-responses-input';\nimport {\n FunctionToolParam,\n OpenResponsesRequestBody,\n OpenResponsesResponseBody,\n OpenResponsesChunk,\n openResponsesErrorSchema,\n ToolChoiceParam,\n} from './open-responses-api';\nimport { mapOpenResponsesFinishReason } from './map-open-responses-finish-reason';\nimport { OpenResponsesConfig } from './open-responses-config';\nimport { openResponsesOptionsSchema } from './open-responses-options';\n\nexport class OpenResponsesLanguageModel implements LanguageModelV3 {\n readonly specificationVersion = 'v3';\n\n readonly modelId: string;\n\n private readonly config: OpenResponsesConfig;\n\n constructor(modelId: string, config: OpenResponsesConfig) {\n this.modelId = modelId;\n this.config = config;\n }\n\n readonly supportedUrls: Record<string, RegExp[]> = {\n 'image/*': [/^https?:\\/\\/.*$/],\n };\n\n get provider(): string {\n return this.config.provider;\n }\n\n private async getArgs({\n maxOutputTokens,\n temperature,\n stopSequences,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n seed,\n prompt,\n providerOptions,\n tools,\n toolChoice,\n responseFormat,\n }: LanguageModelV3CallOptions): Promise<{\n body: Omit<OpenResponsesRequestBody, 'stream' | 'stream_options'>;\n warnings: SharedV3Warning[];\n }> {\n const warnings: SharedV3Warning[] = [];\n\n if (stopSequences != null) {\n warnings.push({ type: 'unsupported', feature: 'stopSequences' });\n }\n\n if (topK != null) {\n warnings.push({ type: 'unsupported', feature: 'topK' });\n }\n\n if (seed != null) {\n warnings.push({ type: 'unsupported', feature: 'seed' });\n }\n\n const {\n input,\n instructions,\n warnings: inputWarnings,\n } = await convertToOpenResponsesInput({\n prompt,\n });\n\n warnings.push(...inputWarnings);\n\n // Convert function tools to the Open Responses format\n const functionTools: FunctionToolParam[] | undefined = tools\n ?.filter(tool => tool.type === 'function')\n .map(tool => ({\n type: 'function' as const,\n name: tool.name,\n description: tool.description,\n parameters: tool.inputSchema,\n ...(tool.strict != null ? { strict: tool.strict } : {}),\n }));\n\n // Convert tool choice to the Open Responses format\n const convertedToolChoice: ToolChoiceParam | undefined =\n toolChoice == null\n ? undefined\n : toolChoice.type === 'tool'\n ? { type: 'function', name: toolChoice.toolName }\n : toolChoice.type; // 'auto' | 'none' | 'required'\n\n const textFormat =\n responseFormat?.type === 'json'\n ? {\n type: 'json_schema' as const,\n ...(responseFormat.schema != null\n ? {\n name: responseFormat.name ?? 'response',\n description: responseFormat.description,\n schema: responseFormat.schema,\n strict: true,\n }\n : {}),\n }\n : undefined;\n\n const openResponsesOptions = await parseProviderOptions({\n provider: this.config.providerOptionsName,\n providerOptions,\n schema: openResponsesOptionsSchema,\n });\n\n return {\n body: {\n model: this.modelId,\n input,\n instructions,\n max_output_tokens: maxOutputTokens,\n temperature,\n top_p: topP,\n presence_penalty: presencePenalty,\n frequency_penalty: frequencyPenalty,\n reasoning:\n openResponsesOptions?.reasoningEffort != null ||\n openResponsesOptions?.reasoningSummary != null\n ? {\n ...(openResponsesOptions?.reasoningEffort != null && {\n effort: openResponsesOptions.reasoningEffort,\n }),\n ...(openResponsesOptions?.reasoningSummary != null && {\n summary: openResponsesOptions.reasoningSummary,\n }),\n }\n : undefined,\n tools: functionTools?.length ? functionTools : undefined,\n tool_choice: convertedToolChoice,\n ...(textFormat != null && { text: { format: textFormat } }),\n },\n warnings,\n };\n }\n\n async doGenerate(\n options: LanguageModelV3CallOptions,\n ): Promise<LanguageModelV3GenerateResult> {\n const { body, warnings } = await this.getArgs(options);\n\n const {\n responseHeaders,\n value: response,\n rawValue: rawResponse,\n } = await postJsonToApi({\n url: this.config.url,\n headers: combineHeaders(this.config.headers(), options.headers),\n body,\n failedResponseHandler: createJsonErrorResponseHandler({\n errorSchema: openResponsesErrorSchema,\n errorToMessage: error => error.error.message,\n }),\n successfulResponseHandler: createJsonResponseHandler(\n // do not validate the response body, only apply types to the response body\n jsonSchema<OpenResponsesResponseBody>(() => {\n throw new Error('json schema not implemented');\n }),\n ),\n abortSignal: options.abortSignal,\n fetch: this.config.fetch,\n });\n\n const content: Array<LanguageModelV3Content> = [];\n let hasToolCalls = false;\n\n for (const part of response.output!) {\n switch (part.type) {\n // TODO AI SDK 7 adjust reasoning in the specification to better support the reasoning structure from open responses.\n case 'reasoning': {\n for (const contentPart of part.content ?? []) {\n content.push({\n type: 'reasoning',\n text: contentPart.text,\n });\n }\n break;\n }\n\n case 'message': {\n for (const contentPart of part.content) {\n content.push({\n type: 'text',\n text: contentPart.text,\n });\n }\n\n break;\n }\n\n case 'function_call': {\n hasToolCalls = true;\n content.push({\n type: 'tool-call',\n toolCallId: part.call_id,\n toolName: part.name,\n input: part.arguments,\n });\n break;\n }\n }\n }\n\n const usage = response.usage;\n const inputTokens = usage?.input_tokens;\n const cachedInputTokens = usage?.input_tokens_details?.cached_tokens;\n const outputTokens = usage?.output_tokens;\n const reasoningTokens = usage?.output_tokens_details?.reasoning_tokens;\n\n return {\n content,\n finishReason: {\n unified: mapOpenResponsesFinishReason({\n finishReason: response.incomplete_details?.reason,\n hasToolCalls,\n }),\n raw: response.incomplete_details?.reason ?? undefined,\n },\n usage: {\n inputTokens: {\n total: inputTokens,\n noCache: (inputTokens ?? 0) - (cachedInputTokens ?? 0),\n cacheRead: cachedInputTokens,\n cacheWrite: undefined,\n },\n outputTokens: {\n total: outputTokens,\n text: (outputTokens ?? 0) - (reasoningTokens ?? 0),\n reasoning: reasoningTokens,\n },\n raw: response.usage,\n },\n request: { body },\n response: {\n id: response.id,\n timestamp: new Date(response.created_at! * 1000),\n modelId: response.model,\n headers: responseHeaders,\n body: rawResponse,\n },\n providerMetadata: undefined,\n warnings,\n };\n }\n\n async doStream(\n options: LanguageModelV3CallOptions,\n ): Promise<LanguageModelV3StreamResult> {\n const { body, warnings } = await this.getArgs(options);\n\n const { responseHeaders, value: response } = await postJsonToApi({\n url: this.config.url,\n headers: combineHeaders(this.config.headers(), options.headers),\n body: {\n ...body,\n stream: true,\n } satisfies OpenResponsesRequestBody,\n failedResponseHandler: createJsonErrorResponseHandler({\n errorSchema: openResponsesErrorSchema,\n errorToMessage: error => error.error.message,\n }),\n // TODO consider validation\n successfulResponseHandler: createEventSourceResponseHandler(z.any()),\n abortSignal: options.abortSignal,\n fetch: this.config.fetch,\n });\n\n const usage: LanguageModelV3Usage = {\n inputTokens: {\n total: undefined,\n noCache: undefined,\n cacheRead: undefined,\n cacheWrite: undefined,\n },\n outputTokens: {\n total: undefined,\n text: undefined,\n reasoning: undefined,\n },\n };\n\n const updateUsage = (\n responseUsage?: OpenResponsesResponseBody['usage'],\n ) => {\n if (!responseUsage) {\n return;\n }\n\n const inputTokens = responseUsage.input_tokens;\n const cachedInputTokens =\n responseUsage.input_tokens_details?.cached_tokens;\n const outputTokens = responseUsage.output_tokens;\n const reasoningTokens =\n responseUsage.output_tokens_details?.reasoning_tokens;\n\n usage.inputTokens = {\n total: inputTokens,\n noCache: (inputTokens ?? 0) - (cachedInputTokens ?? 0),\n cacheRead: cachedInputTokens,\n cacheWrite: undefined,\n };\n usage.outputTokens = {\n total: outputTokens,\n text: (outputTokens ?? 0) - (reasoningTokens ?? 0),\n reasoning: reasoningTokens,\n };\n usage.raw = responseUsage;\n };\n\n let isActiveReasoning = false;\n let hasToolCalls = false;\n let finishReason: LanguageModelV3FinishReason = {\n unified: 'other',\n raw: undefined,\n };\n const toolCallsByItemId: Record<\n string,\n { toolName?: string; toolCallId?: string; arguments?: string }\n > = {};\n\n return {\n stream: response.pipeThrough(\n new TransformStream<\n ParseResult<OpenResponsesChunk>,\n LanguageModelV3StreamPart\n >({\n start(controller) {\n controller.enqueue({ type: 'stream-start', warnings });\n },\n\n transform(parseResult, controller) {\n if (options.includeRawChunks) {\n controller.enqueue({\n type: 'raw',\n rawValue: parseResult.rawValue,\n });\n }\n\n if (!parseResult.success) {\n controller.enqueue({ type: 'error', error: parseResult.error });\n return;\n }\n\n const chunk = parseResult.value;\n\n // Tool call events (single-shot tool-call when complete)\n if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'function_call'\n ) {\n toolCallsByItemId[chunk.item.id] = {\n toolName: chunk.item.name,\n toolCallId: chunk.item.call_id,\n arguments: chunk.item.arguments,\n };\n } else if (\n (chunk as { type: string }).type ===\n 'response.function_call_arguments.delta'\n ) {\n const functionCallChunk = chunk as {\n item_id: string;\n delta: string;\n };\n const toolCall =\n toolCallsByItemId[functionCallChunk.item_id] ??\n (toolCallsByItemId[functionCallChunk.item_id] = {});\n toolCall.arguments =\n (toolCall.arguments ?? '') + functionCallChunk.delta;\n } else if (\n (chunk as { type: string }).type ===\n 'response.function_call_arguments.done'\n ) {\n const functionCallChunk = chunk as {\n item_id: string;\n arguments: string;\n };\n const toolCall =\n toolCallsByItemId[functionCallChunk.item_id] ??\n (toolCallsByItemId[functionCallChunk.item_id] = {});\n toolCall.arguments = functionCallChunk.arguments;\n } else if (\n chunk.type === 'response.output_item.done' &&\n chunk.item.type === 'function_call'\n ) {\n const toolCall = toolCallsByItemId[chunk.item.id];\n const toolName = toolCall?.toolName ?? chunk.item.name;\n const toolCallId = toolCall?.toolCallId ?? chunk.item.call_id;\n const input = toolCall?.arguments ?? chunk.item.arguments ?? '';\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId,\n toolName,\n input,\n });\n hasToolCalls = true;\n\n delete toolCallsByItemId[chunk.item.id];\n }\n\n // Reasoning events (note: response.reasoning_text.delta is an LM Studio extension, not in official spec)\n else if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'reasoning'\n ) {\n controller.enqueue({\n type: 'reasoning-start',\n id: chunk.item.id,\n });\n isActiveReasoning = true;\n } else if (\n (chunk as { type: string }).type ===\n 'response.reasoning_text.delta'\n ) {\n const reasoningChunk = chunk as {\n item_id: string;\n delta: string;\n };\n controller.enqueue({\n type: 'reasoning-delta',\n id: reasoningChunk.item_id,\n delta: reasoningChunk.delta,\n });\n } else if (\n chunk.type === 'response.output_item.done' &&\n chunk.item.type === 'reasoning'\n ) {\n controller.enqueue({ type: 'reasoning-end', id: chunk.item.id });\n isActiveReasoning = false;\n }\n\n // Text events\n else if (\n chunk.type === 'response.output_item.added' &&\n chunk.item.type === 'message'\n ) {\n controller.enqueue({ type: 'text-start', id: chunk.item.id });\n } else if (chunk.type === 'response.output_text.delta') {\n controller.enqueue({\n type: 'text-delta',\n id: chunk.item_id,\n delta: chunk.delta,\n });\n } else if (\n chunk.type === 'response.output_item.done' &&\n chunk.item.type === 'message'\n ) {\n controller.enqueue({ type: 'text-end', id: chunk.item.id });\n } else if (\n chunk.type === 'response.completed' ||\n chunk.type === 'response.incomplete'\n ) {\n const reason = chunk.response.incomplete_details?.reason;\n finishReason = {\n unified: mapOpenResponsesFinishReason({\n finishReason: reason,\n hasToolCalls,\n }),\n raw: reason ?? undefined,\n };\n updateUsage(chunk.response.usage);\n } else if (chunk.type === 'response.failed') {\n finishReason = {\n unified: 'error',\n raw: chunk.response.error?.code ?? chunk.response.status,\n };\n updateUsage(chunk.response.usage);\n }\n },\n\n flush(controller) {\n if (isActiveReasoning) {\n controller.enqueue({ type: 'reasoning-end', id: 'reasoning-0' });\n }\n\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n providerMetadata: undefined,\n });\n },\n }),\n ),\n request: { body },\n response: { headers: responseHeaders },\n };\n }\n}\n","import { LanguageModelV3Prompt, SharedV3Warning } from '@ai-sdk/provider';\nimport { convertToBase64 } from '@ai-sdk/provider-utils';\nimport {\n FunctionCallItemParam,\n FunctionCallOutputItemParam,\n InputFileContentParam,\n InputImageContentParam,\n InputTextContentParam,\n OpenResponsesRequestBody,\n OutputTextContentParam,\n RefusalContentParam,\n} from './open-responses-api';\n\nexport async function convertToOpenResponsesInput({\n prompt,\n}: {\n prompt: LanguageModelV3Prompt;\n}): Promise<{\n input: OpenResponsesRequestBody['input'];\n instructions: string | undefined;\n warnings: Array<SharedV3Warning>;\n}> {\n const input: OpenResponsesRequestBody['input'] = [];\n const warnings: Array<SharedV3Warning> = [];\n const systemMessages: string[] = [];\n\n for (const { role, content } of prompt) {\n switch (role) {\n case 'system': {\n systemMessages.push(content);\n break;\n }\n\n case 'user': {\n const userContent: Array<\n InputTextContentParam | InputImageContentParam | InputFileContentParam\n > = [];\n\n for (const part of content) {\n switch (part.type) {\n case 'text': {\n userContent.push({ type: 'input_text', text: part.text });\n break;\n }\n case 'file': {\n if (!part.mediaType.startsWith('image/')) {\n warnings.push({\n type: 'other',\n message: `unsupported file content type: ${part.mediaType}`,\n });\n break;\n }\n\n const mediaType =\n part.mediaType === 'image/*' ? 'image/jpeg' : part.mediaType;\n\n userContent.push({\n type: 'input_image',\n ...(part.data instanceof URL\n ? { image_url: part.data.toString() }\n : {\n image_url: `data:${mediaType};base64,${convertToBase64(part.data)}`,\n }),\n });\n break;\n }\n }\n }\n\n input.push({ type: 'message', role: 'user', content: userContent });\n break;\n }\n\n case 'assistant': {\n const assistantContent: Array<\n OutputTextContentParam | RefusalContentParam\n > = [];\n const toolCalls: Array<FunctionCallItemParam> = [];\n\n for (const part of content) {\n switch (part.type) {\n case 'text': {\n assistantContent.push({ type: 'output_text', text: part.text });\n break;\n }\n case 'tool-call': {\n const argumentsValue =\n typeof part.input === 'string'\n ? part.input\n : JSON.stringify(part.input);\n toolCalls.push({\n type: 'function_call',\n call_id: part.toolCallId,\n name: part.toolName,\n arguments: argumentsValue,\n });\n break;\n }\n }\n }\n\n // Push assistant message with text content if any\n if (assistantContent.length > 0) {\n input.push({\n type: 'message',\n role: 'assistant',\n content: assistantContent,\n });\n }\n\n // Push function calls as separate items\n for (const toolCall of toolCalls) {\n input.push(toolCall);\n }\n\n break;\n }\n\n case 'tool': {\n for (const part of content) {\n if (part.type === 'tool-result') {\n const output = part.output;\n let contentValue: FunctionCallOutputItemParam['output'];\n\n switch (output.type) {\n case 'text':\n case 'error-text':\n contentValue = output.value;\n break;\n case 'execution-denied':\n contentValue = output.reason ?? 'Tool execution denied.';\n break;\n case 'json':\n case 'error-json':\n contentValue = JSON.stringify(output.value);\n break;\n case 'content': {\n const contentParts: Array<\n | InputTextContentParam\n | InputImageContentParam\n | InputFileContentParam\n > = [];\n for (const item of output.value) {\n switch (item.type) {\n case 'text': {\n contentParts.push({\n type: 'input_text',\n text: item.text,\n });\n break;\n }\n case 'image-data': {\n contentParts.push({\n type: 'input_image',\n image_url: `data:${item.mediaType};base64,${item.data}`,\n });\n break;\n }\n case 'image-url': {\n contentParts.push({\n type: 'input_image',\n image_url: item.url,\n });\n break;\n }\n case 'file-data': {\n contentParts.push({\n type: 'input_file',\n filename: item.filename ?? 'data',\n file_data: `data:${item.mediaType};base64,${item.data}`,\n });\n break;\n }\n default: {\n warnings.push({\n type: 'other',\n message: `unsupported tool content part type: ${(item as { type: string }).type}`,\n });\n break;\n }\n }\n }\n contentValue = contentParts;\n break;\n }\n }\n\n input.push({\n type: 'function_call_output',\n call_id: part.toolCallId,\n output: contentValue,\n });\n }\n }\n break;\n }\n }\n }\n\n return {\n input,\n instructions:\n systemMessages.length > 0 ? systemMessages.join('\\n') : undefined,\n warnings,\n };\n}\n","import { JSONSchema7 } from '@ai-sdk/provider';\nimport { lazySchema } from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport { zodSchema } from '@ai-sdk/provider-utils';\n\nexport const openResponsesErrorSchema = lazySchema(() =>\n zodSchema(\n z.object({\n error: z.object({\n message: z.string(),\n type: z.string(),\n param: z.string(),\n code: z.string(),\n }),\n }),\n ),\n);\n\n// ============================================================================\n// Enums\n// ============================================================================\n\n/**\n * The status of a function call or message item.\n */\nexport type FunctionCallStatus = 'in_progress' | 'completed' | 'incomplete';\n\n/**\n * Image detail level for input images.\n */\nexport type ImageDetail = 'low' | 'high' | 'auto';\n\n/**\n * Reasoning effort level.\n */\nexport type ReasoningEffortEnum = 'none' | 'low' | 'medium' | 'high' | 'xhigh';\n\n/**\n * Reasoning summary level.\n */\nexport type ReasoningSummaryEnum = 'concise' | 'detailed' | 'auto';\n\n/**\n * Tool choice value enum.\n */\nexport type ToolChoiceValueEnum = 'none' | 'auto' | 'required';\n\n/**\n * Verbosity level for text output.\n */\nexport type VerbosityEnum = 'low' | 'medium' | 'high';\n\n// ============================================================================\n// Content Types\n// ============================================================================\n\n/**\n * A text input to the model.\n */\nexport type InputTextContentParam = {\n type: 'input_text';\n text: string;\n};\n\n/**\n * An image input to the model.\n */\nexport type InputImageContentParam = {\n type: 'input_image';\n image_url?: string;\n detail?: ImageDetail;\n};\n\n/**\n * A file input to the model.\n */\nexport type InputFileContentParam = {\n type: 'input_file';\n filename?: string;\n file_data?: string;\n file_url?: string;\n};\n\n/**\n * A video input to the model.\n */\nexport type InputVideoContent = {\n type: 'input_video';\n video_url: string;\n};\n\n/**\n * A text output from the model.\n */\nexport type OutputTextContentParam = {\n type: 'output_text';\n text: string;\n annotations?: UrlCitationParam[];\n};\n\n/**\n * A refusal from the model.\n */\nexport type RefusalContentParam = {\n type: 'refusal';\n refusal: string;\n};\n\n/**\n * A URL citation annotation.\n */\nexport type UrlCitationParam = {\n type: 'url_citation';\n start_index: number;\n end_index: number;\n url: string;\n title: string;\n};\n\n/**\n * Reasoning summary content.\n */\nexport type ReasoningSummaryContentParam = {\n type: 'summary_text';\n text: string;\n};\n\n// ============================================================================\n// Message Item Types\n// ============================================================================\n\n/**\n * An internal identifier for an item to reference.\n */\nexport type ItemReferenceParam = {\n type?: 'item_reference';\n id: string;\n};\n\n/**\n * A reasoning item.\n */\nexport type ReasoningItemParam = {\n id?: string;\n type: 'reasoning';\n summary: ReasoningSummaryContentParam[];\n content?: unknown;\n encrypted_content?: string;\n};\n\n/**\n * A user message item.\n */\nexport type UserMessageItemParam = {\n id?: string;\n type: 'message';\n role: 'user';\n content:\n | string\n | Array<\n InputTextContentParam | InputImageContentParam | InputFileContentParam\n >;\n status?: string;\n};\n\n/**\n * A system message item.\n */\nexport type SystemMessageItemParam = {\n id?: string;\n type: 'message';\n role: 'system';\n content: string | InputTextContentParam[];\n status?: string;\n};\n\n/**\n * A developer message item.\n */\nexport type DeveloperMessageItemParam = {\n id?: string;\n type: 'message';\n role: 'developer';\n content: string | InputTextContentParam[];\n status?: string;\n};\n\n/**\n * An assistant message item.\n */\nexport type AssistantMessageItemParam = {\n id?: string;\n type: 'message';\n role: 'assistant';\n content: string | Array<OutputTextContentParam | RefusalContentParam>;\n status?: string;\n};\n\n/**\n * A function call item.\n */\nexport type FunctionCallItemParam = {\n id?: string;\n call_id: string;\n type: 'function_call';\n name: string;\n arguments: string;\n status?: FunctionCallStatus;\n};\n\n/**\n * A function call output item.\n */\nexport type FunctionCallOutputItemParam = {\n id?: string;\n call_id: string;\n type: 'function_call_output';\n output:\n | string\n | Array<\n | InputTextContentParam\n | InputImageContentParam\n | InputFileContentParam\n | InputVideoContent\n >;\n status?: FunctionCallStatus;\n};\n\n// ============================================================================\n// Tool Types\n// ============================================================================\n\n/**\n * A function tool parameter.\n */\nexport type FunctionToolParam = {\n name: string;\n description?: string;\n parameters?: JSONSchema7;\n strict?: boolean;\n type: 'function';\n};\n\n/**\n * A specific function tool choice.\n */\nexport type SpecificFunctionParam = {\n type: 'function';\n name: string;\n};\n\n/**\n * Allowed tools parameter.\n */\nexport type AllowedToolsParam = {\n type: 'allowed_tools';\n tools: SpecificFunctionParam[];\n mode?: ToolChoiceValueEnum;\n};\n\n/**\n * Controls which tool the model should use, if any.\n */\nexport type ToolChoiceParam =\n | ToolChoiceValueEnum\n | SpecificFunctionParam\n | AllowedToolsParam;\n\n// ============================================================================\n// Configuration Types\n// ============================================================================\n\n/**\n * Set of 16 key-value pairs that can be attached to an object.\n */\nexport type MetadataParam = Record<string, string>;\n\n/**\n * Text response format (plain text).\n */\nexport type TextResponseFormat = {\n type: 'text';\n};\n\n/**\n * JSON schema response format.\n */\nexport type JsonSchemaResponseFormatParam = {\n type: 'json_schema';\n description?: string;\n name?: string;\n schema?: JSONSchema7;\n strict?: boolean;\n};\n\n/**\n * Configuration options for text output.\n */\nexport type TextParam = {\n format?: TextResponseFormat | JsonSchemaResponseFormatParam;\n verbosity?: VerbosityEnum;\n};\n\n/**\n * Options that control streamed response behavior.\n */\nexport type StreamOptionsParam = {\n include_obfuscation?: boolean;\n};\n\n/**\n * Configuration options for reasoning behavior.\n */\nexport type ReasoningParam = {\n effort?: ReasoningEffortEnum;\n summary?: ReasoningSummaryEnum;\n};\n\n// ============================================================================\n// Response-Specific Types\n// ============================================================================\n\n/**\n * The status of a message item in the response.\n */\nexport type MessageStatus = 'in_progress' | 'completed' | 'incomplete';\n\n/**\n * Truncation enum for responses.\n */\nexport type TruncationEnum = 'auto' | 'disabled';\n\n/**\n * Service tier enum.\n */\nexport type ServiceTierEnum = 'auto' | 'default' | 'flex' | 'priority';\n\n/**\n * A top log probability of a token.\n */\nexport type TopLogProb = {\n token: string;\n logprob: number;\n bytes: number[];\n};\n\n/**\n * The log probability of a token.\n */\nexport type LogProb = {\n token: string;\n logprob: number;\n bytes: number[];\n top_logprobs: TopLogProb[];\n};\n\n/**\n * A URL citation annotation in a response.\n */\nexport type UrlCitationBody = {\n type: 'url_citation';\n url: string;\n start_index: number;\n end_index: number;\n title: string;\n};\n\n/**\n * An annotation that applies to a span of output text.\n */\nexport type Annotation = UrlCitationBody;\n\n/**\n * A text input content in a response.\n */\nexport type InputTextContent = {\n type: 'input_text';\n text: string;\n};\n\n/**\n * A text output from the model in a response.\n */\nexport type OutputTextContent = {\n type: 'output_text';\n text: string;\n annotations: Annotation[];\n logprobs: LogProb[];\n};\n\n/**\n * A refusal from the model in a response.\n */\nexport type RefusalContent = {\n type: 'refusal';\n refusal: string;\n};\n\n/**\n * Reasoning text from the model.\n */\nexport type ReasoningTextContent = {\n type: 'reasoning_text';\n text: string;\n};\n\n/**\n * A summary text from the model.\n */\nexport type SummaryTextContent = {\n type: 'summary_text';\n text: string;\n};\n\n/**\n * An image input content in a response.\n */\nexport type InputImageContent = {\n type: 'input_image';\n image_url?: string;\n detail: ImageDetail;\n};\n\n/**\n * A file input content in a response.\n */\nexport type InputFileContent = {\n type: 'input_file';\n filename?: string;\n file_url?: string;\n};\n\n/**\n * A message in the response.\n */\nexport type Message = {\n type: 'message';\n id: string;\n status: MessageStatus;\n role: 'user' | 'assistant' | 'system' | 'developer';\n content: InputTextContent[];\n};\n\n/**\n * A function tool call that was generated by the model.\n */\nexport type FunctionCall = {\n type: 'function_call';\n id: string;\n call_id: string;\n name: string;\n arguments: string;\n status: FunctionCallStatus;\n};\n\n/**\n * A function tool call output that was returned.\n */\nexport type FunctionCallOutput = {\n type: 'function_call_output';\n id: string;\n call_id: string;\n output:\n | string\n | Array<InputTextContent | InputImageContent | InputFileContent>;\n status: FunctionCallStatus;\n};\n\n/**\n * A reasoning item that was generated by the model.\n */\nexport type ReasoningBody = {\n type: 'reasoning';\n id: string;\n content?: InputTextContent[];\n summary: InputTextContent[];\n encrypted_content?: string;\n};\n\n/**\n * Output item field union type.\n */\nexport type OutputItem =\n | FunctionCall\n | FunctionCallOutput\n | Message\n | ReasoningBody;\n\n/**\n * Details about why the response was incomplete.\n */\nexport type IncompleteDetails = {\n reason: string;\n};\n\n/**\n * An error that occurred while generating the response.\n */\nexport type ResponseError = {\n code: string;\n message: string;\n};\n\n/**\n * A function tool in a response.\n */\nexport type FunctionTool = {\n type: 'function';\n name: string;\n description?: string;\n parameters?: JSONSchema7;\n strict?: boolean;\n};\n\n/**\n * Function tool choice in a response.\n */\nexport type FunctionToolChoice = {\n type: 'function';\n name?: string;\n};\n\n/**\n * Allowed tool choice in a response.\n */\nexport type AllowedToolChoice = {\n type: 'allowed_tools';\n tools: FunctionToolChoice[];\n mode: ToolChoiceValueEnum;\n};\n\n/**\n * Tool choice in a response.\n */\nexport type ResponseToolChoice =\n | ToolChoiceValueEnum\n | FunctionToolChoice\n | AllowedToolChoice;\n\n/**\n * JSON object response format.\n */\nexport type JsonObjectResponseFormat = {\n type: 'json_object';\n};\n\n/**\n * JSON schema response format in a response.\n */\nexport type JsonSchemaResponseFormat = {\n type: 'json_schema';\n name: string;\n description?: string;\n schema: unknown;\n strict: boolean;\n};\n\n/**\n * Text field in a response.\n */\nexport type TextField = {\n format?:\n | TextResponseFormat\n | JsonObjectResponseFormat\n | JsonSchemaResponseFormat;\n verbosity?: VerbosityEnum;\n};\n\n/**\n * A breakdown of input token usage that was recorded.\n */\nexport type InputTokensDetails = {\n cached_tokens: number;\n};\n\n/**\n * A breakdown of output token usage that was recorded.\n */\nexport type OutputTokensDetails = {\n reasoning_tokens: number;\n};\n\n/**\n * Token usage statistics that were recorded for the response.\n */\nexport type Usage = {\n input_tokens: number;\n output_tokens: number;\n total_tokens: number;\n input_tokens_details: InputTokensDetails;\n output_tokens_details: OutputTokensDetails;\n};\n\n/**\n * Reasoning configuration and outputs that were produced for this response.\n */\nexport type Reasoning = {\n effort?: ReasoningEffortEnum;\n summary?: ReasoningSummaryEnum;\n};\n\n// ============================================================================\n// Request Body\n// ============================================================================\n\n/**\n * Body that is sent to the Open Responses API.\n */\nexport type OpenResponsesRequestBody = {\n /**\n * The model to use for this request, e.g. 'gpt-5.4'.\n */\n model: string;\n\n /**\n * Context for the model: either a string (interpreted as a user message),\n * or an array of structured message items.\n */\n input:\n | string\n | Array<\n | ItemReferenceParam\n | ReasoningItemParam\n | UserMessageItemParam\n | SystemMessageItemParam\n | DeveloperMessageItemParam\n | AssistantMessageItemParam\n | FunctionCallItemParam\n | FunctionCallOutputItemParam\n >;\n\n /**\n * The ID of the response to use as the prior turn for this request.\n */\n previous_response_id?: string;\n\n /**\n * Options specifying extra values to include in the response.\n */\n include?: Array<\n 'reasoning.encrypted_content' | 'message.output_text.logprobs'\n >;\n\n /**\n * A list of tools that the model may call while generating the response.\n */\n tools?: FunctionToolParam[];\n\n /**\n * Controls which tool the model should use, if any.\n */\n tool_choice?: ToolChoiceParam;\n\n /**\n * Structured metadata as up to 16 key-value pairs.\n */\n metadata?: MetadataParam;\n\n /**\n * Configuration options for text output.\n */\n text?: TextParam;\n\n /**\n * Sampling temperature to use, between 0 and 2.\n */\n temperature?: number;\n\n /**\n * Nucleus sampling parameter, between 0 and 1.\n */\n top_p?: number;\n\n /**\n * Penalizes new tokens based on whether they appear in the text so far.\n */\n presence_penalty?: number;\n\n /**\n * Penalizes new tokens based on their frequency in the text so far.\n */\n frequency_penalty?: number;\n\n /**\n * Whether the model may call multiple tools in parallel.\n */\n parallel_tool_calls?: boolean;\n\n /**\n * Whether to stream response events as server-sent events.\n */\n stream?: boolean;\n\n /**\n * Options that control streamed response behavior.\n */\n stream_options?: StreamOptionsParam;\n\n /**\n * Whether to run the request in the background and return immediately.\n */\n background?: boolean;\n\n /**\n * Maximum number of tokens the model may generate.\n */\n max_output_tokens?: number;\n\n /**\n * Maximum number of tool calls the model may make while generating the response.\n */\n max_tool_calls?: number;\n\n /**\n * Configuration options for reasoning behavior.\n */\n reasoning?: ReasoningParam;\n\n /**\n * A stable identifier used for safety monitoring and abuse detection.\n */\n safety_identifier?: string;\n\n /**\n * A key to use when reading/writing to the prompt cache.\n */\n prompt_cache_key?: string;\n\n /**\n * Controls how input is truncated if it exceeds the model's context window.\n * - 'auto': Let the service decide how to truncate.\n * - 'disabled': Disable truncation. Context overflow yields 400 error.\n */\n truncation?: 'auto' | 'disabled';\n\n /**\n * Additional instructions to guide the model for this request.\n */\n instructions?: string;\n\n /**\n * Whether to store the response so it can be retrieved later.\n */\n store?: boolean;\n\n /**\n * The service tier to use for this request.\n * - 'auto' | 'default' | 'flex' | 'priority'\n */\n service_tier?: 'auto' | 'default' | 'flex' | 'priority';\n\n /**\n * Number of most likely tokens to return at each position, with logprobs.\n */\n top_logprobs?: number;\n};\n\n// ============================================================================\n// Response Body\n// ============================================================================\n\n/**\n * Response body from the Open Responses API.\n */\nexport type OpenResponsesResponseBody = {\n /**\n * The unique ID of the response that was created.\n */\n id: string;\n\n /**\n * The object type, which is always 'response'.\n */\n object: 'response';\n\n /**\n * The Unix timestamp (in seconds) for when the response was created.\n */\n created_at: number;\n\n /**\n * The Unix timestamp (in seconds) for when the response was completed, if it was completed.\n */\n completed_at?: number;\n\n /**\n * The status that was set for the response.\n */\n status: string;\n\n /**\n * Details about why the response was incomplete, if applicable.\n */\n incomplete_details?: IncompleteDetails;\n\n /**\n * The model that generated this response.\n */\n model: string;\n\n /**\n * The ID of the previous response in the chain that was referenced, if any.\n */\n previous_response_id?: string;\n\n /**\n * Additional instructions that were used to guide the model for this response.\n */\n instructions?: string;\n\n /**\n * The output items that were generated by the model.\n */\n output: OutputItem[];\n\n /**\n * The error that occurred, if the response failed.\n */\n error?: ResponseError;\n\n /**\n * The tools that were available to the model during response generation.\n */\n tools?: FunctionTool[];\n\n /**\n * The tool choice configuration that was used.\n */\n tool_choice?: ResponseToolChoice;\n\n /**\n * How the input was truncated by the service when it exceeded the model context window.\n */\n truncation?: TruncationEnum;\n\n /**\n * Whether the model was allowed to call multiple tools in parallel.\n */\n parallel_tool_calls?: boolean;\n\n /**\n * Configuration options for text output that were used.\n */\n text?: TextField;\n\n /**\n * The nucleus sampling parameter that was used for this response.\n */\n top_p?: number;\n\n /**\n * The presence penalty that was used.\n */\n presence_penalty?: number;\n\n /**\n * The frequency penalty that was used.\n */\n frequency_penalty?: number;\n\n /**\n * The number of most likely tokens that were returned at each position.\n */\n top_logprobs?: number;\n\n /**\n * The sampling temperature that was used for this response.\n */\n temperature?: number;\n\n /**\n * Reasoning configuration and outputs that were produced for this response.\n */\n reasoning?: Reasoning;\n\n /**\n * Token usage statistics that were recorded for the response, if available.\n */\n usage?: Usage;\n\n /**\n * The maximum number of tokens the model was allowed to generate for this response.\n */\n max_output_tokens?: number;\n\n /**\n * The maximum number of tool calls the model was allowed to make.\n */\n max_tool_calls?: number;\n\n /**\n * Whether this response was stored so it can be retrieved later.\n */\n store?: boolean;\n\n /**\n * Whether this request was run in the background.\n */\n background?: boolean;\n\n /**\n * The service tier that was used for this response.\n */\n service_tier?: string;\n\n /**\n * Developer-defined metadata that was associated with the response.\n */\n metadata?: unknown;\n\n /**\n * A stable identifier that was used for safety monitoring and abuse detection.\n */\n safety_identifier?: string;\n\n /**\n * A key that was used to read from or write to the prompt cache.\n */\n prompt_cache_key?: string;\n};\n\n// ============================================================================\n// Streaming Chunk Types\n// ============================================================================\n\n/**\n * Content part for streaming - output text.\n */\nexport type OutputTextContentPart = {\n type: 'output_text';\n text: string;\n annotations: Annotation[];\n};\n\n/**\n * Content part for streaming - refusal.\n */\nexport type RefusalContentPart = {\n type: 'refusal';\n refusal: string;\n};\n\n/**\n * Union of content parts that can appear in streaming.\n */\nexport type ContentPart = OutputTextContentPart | RefusalContentPart;\n\n// ----------------------------------------------------------------------------\n// State Machine Events\n// ----------------------------------------------------------------------------\n\n/**\n * Emitted when a response is created.\n */\nexport type ResponseCreatedEvent = {\n type: 'response.created';\n sequence_number: number;\n response: OpenResponsesResponseBody;\n};\n\n/**\n * Emitted when a response transitions to in_progress status.\n */\nexport type ResponseInProgressEvent = {\n type: 'response.in_progress';\n sequence_number: number;\n response: OpenResponsesResponseBody;\n};\n\n/**\n * Emitted when a response completes successfully.\n */\nexport type ResponseCompletedEvent = {\n type: 'response.completed';\n sequence_number: number;\n response: OpenResponsesResponseBody;\n};\n\n/**\n * Emitted when a response fails.\n */\nexport type ResponseFailedEvent = {\n type: 'response.failed';\n sequence_number: number;\n response: OpenResponsesResponseBody;\n};\n\n/**\n * Emitted when a response is incomplete (e.g., token budget exhausted).\n */\nexport type ResponseIncompleteEvent = {\n type: 'response.incomplete';\n sequence_number: number;\n response: OpenResponsesResponseBody;\n};\n\n// ----------------------------------------------------------------------------\n// Delta Events - Output Items\n// ----------------------------------------------------------------------------\n\n/**\n * Emitted when a new output item is added to the response.\n */\nexport type ResponseOutputItemAddedEvent = {\n type: 'response.output_item.added';\n sequence_number: number;\n output_index: number;\n item: OutputItem;\n};\n\n/**\n * Emitted when an output item is completed.\n */\nexport type ResponseOutputItemDoneEvent = {\n type: 'response.output_item.done';\n sequence_number: number;\n output_index: number;\n item: OutputItem;\n};\n\n// ----------------------------------------------------------------------------\n// Delta Events - Content Parts\n// ----------------------------------------------------------------------------\n\n/**\n * Emitted when a new content part is added to an item.\n */\nexport type ResponseContentPartAddedEvent = {\n type: 'response.content_part.added';\n sequence_number: number;\n item_id: string;\n output_index: number;\n content_index: number;\n part: ContentPart;\n};\n\n/**\n * Emitted when a content part is completed.\n */\nexport type ResponseContentPartDoneEvent = {\n type: 'response.content_part.done';\n sequence_number: number;\n item_id: string;\n output_index: number;\n content_index: number;\n part: ContentPart;\n};\n\n// ----------------------------------------------------------------------------\n// Delta Events - Text Output\n// ----------------------------------------------------------------------------\n\n/**\n * Emitted when text is appended to an output.\n */\nexport type ResponseOutputTextDeltaEvent = {\n type: 'response.output_text.delta';\n sequence_number: number;\n item_id: string;\n output_index: number;\n content_index: number;\n delta: string;\n logprobs?: LogProb[];\n};\n\n/**\n * Emitted when text output is complete.\n */\nexport type ResponseOutputTextDoneEvent = {\n type: 'response.output_text.done';\n sequence