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.

659 lines (649 loc) 23.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { VERSION: () => VERSION, createOpenResponses: () => createOpenResponses }); module.exports = __toCommonJS(index_exports); // src/version.ts var VERSION = true ? "1.0.11" : "0.0.0-test"; // src/open-responses-provider.ts var import_provider = require("@ai-sdk/provider"); var import_provider_utils6 = require("@ai-sdk/provider-utils"); // src/responses/open-responses-language-model.ts var import_provider_utils5 = require("@ai-sdk/provider-utils"); var import_v43 = require("zod/v4"); // src/responses/convert-to-open-responses-input.ts var import_provider_utils = require("@ai-sdk/provider-utils"); async function convertToOpenResponsesInput({ prompt }) { var _a, _b; const input = []; const warnings = []; const systemMessages = []; for (const { role, content } of prompt) { switch (role) { case "system": { systemMessages.push(content); break; } case "user": { const userContent = []; for (const part of content) { switch (part.type) { case "text": { userContent.push({ type: "input_text", text: part.text }); break; } case "file": { if (!part.mediaType.startsWith("image/")) { warnings.push({ type: "other", message: `unsupported file content type: ${part.mediaType}` }); break; } const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType; userContent.push({ type: "input_image", ...part.data instanceof URL ? { image_url: part.data.toString() } : { image_url: `data:${mediaType};base64,${(0, import_provider_utils.convertToBase64)(part.data)}` } }); break; } } } input.push({ type: "message", role: "user", content: userContent }); break; } case "assistant": { const assistantContent = []; const toolCalls = []; for (const part of content) { switch (part.type) { case "text": { assistantContent.push({ type: "output_text", text: part.text }); break; } case "tool-call": { const argumentsValue = typeof part.input === "string" ? part.input : JSON.stringify(part.input); toolCalls.push({ type: "function_call", call_id: part.toolCallId, name: part.toolName, arguments: argumentsValue }); break; } } } if (assistantContent.length > 0) { input.push({ type: "message", role: "assistant", content: assistantContent }); } for (const toolCall of toolCalls) { input.push(toolCall); } break; } case "tool": { for (const part of content) { if (part.type === "tool-result") { const output = part.output; let contentValue; switch (output.type) { case "text": case "error-text": contentValue = output.value; break; case "execution-denied": contentValue = (_a = output.reason) != null ? _a : "Tool execution denied."; break; case "json": case "error-json": contentValue = JSON.stringify(output.value); break; case "content": { const contentParts = []; for (const item of output.value) { switch (item.type) { case "text": { contentParts.push({ type: "input_text", text: item.text }); break; } case "image-data": { contentParts.push({ type: "input_image", image_url: `data:${item.mediaType};base64,${item.data}` }); break; } case "image-url": { contentParts.push({ type: "input_image", image_url: item.url }); break; } case "file-data": { contentParts.push({ type: "input_file", filename: (_b = item.filename) != null ? _b : "data", file_data: `data:${item.mediaType};base64,${item.data}` }); break; } default: { warnings.push({ type: "other", message: `unsupported tool content part type: ${item.type}` }); break; } } } contentValue = contentParts; break; } } input.push({ type: "function_call_output", call_id: part.toolCallId, output: contentValue }); } } break; } } } return { input, instructions: systemMessages.length > 0 ? systemMessages.join("\n") : void 0, warnings }; } // src/responses/open-responses-api.ts var import_provider_utils2 = require("@ai-sdk/provider-utils"); var import_v4 = require("zod/v4"); var import_provider_utils3 = require("@ai-sdk/provider-utils"); var openResponsesErrorSchema = (0, import_provider_utils2.lazySchema)( () => (0, import_provider_utils3.zodSchema)( import_v4.z.object({ error: import_v4.z.object({ message: import_v4.z.string(), type: import_v4.z.string(), param: import_v4.z.string(), code: import_v4.z.string() }) }) ) ); // src/responses/map-open-responses-finish-reason.ts function mapOpenResponsesFinishReason({ finishReason, hasToolCalls }) { switch (finishReason) { case void 0: case null: return hasToolCalls ? "tool-calls" : "stop"; case "max_output_tokens": return "length"; case "content_filter": return "content-filter"; default: return hasToolCalls ? "tool-calls" : "other"; } } // src/responses/open-responses-options.ts var import_provider_utils4 = require("@ai-sdk/provider-utils"); var import_v42 = require("zod/v4"); var openResponsesOptionsSchema = (0, import_provider_utils4.lazySchema)( () => (0, import_provider_utils4.zodSchema)( import_v42.z.object({ reasoningEffort: import_v42.z.enum(["none", "low", "medium", "high", "xhigh"]).nullish(), /** * Controls reasoning summary output from the model. * Valid values: 'concise', 'detailed', 'auto'. */ reasoningSummary: import_v42.z.enum(["concise", "detailed", "auto"]).nullish() }) ) ); // src/responses/open-responses-language-model.ts var OpenResponsesLanguageModel = class { constructor(modelId, config) { this.specificationVersion = "v3"; this.supportedUrls = { "image/*": [/^https?:\/\/.*$/] }; this.modelId = modelId; this.config = config; } get provider() { return this.config.provider; } async getArgs({ maxOutputTokens, temperature, stopSequences, topP, topK, presencePenalty, frequencyPenalty, seed, prompt, providerOptions, tools, toolChoice, responseFormat }) { var _a; const warnings = []; if (stopSequences != null) { warnings.push({ type: "unsupported", feature: "stopSequences" }); } if (topK != null) { warnings.push({ type: "unsupported", feature: "topK" }); } if (seed != null) { warnings.push({ type: "unsupported", feature: "seed" }); } const { input, instructions, warnings: inputWarnings } = await convertToOpenResponsesInput({ prompt }); warnings.push(...inputWarnings); const functionTools = tools == null ? void 0 : tools.filter((tool) => tool.type === "function").map((tool) => ({ type: "function", name: tool.name, description: tool.description, parameters: tool.inputSchema, ...tool.strict != null ? { strict: tool.strict } : {} })); const convertedToolChoice = toolChoice == null ? void 0 : toolChoice.type === "tool" ? { type: "function", name: toolChoice.toolName } : toolChoice.type; const textFormat = (responseFormat == null ? void 0 : responseFormat.type) === "json" ? { type: "json_schema", ...responseFormat.schema != null ? { name: (_a = responseFormat.name) != null ? _a : "response", description: responseFormat.description, schema: responseFormat.schema, strict: true } : {} } : void 0; const openResponsesOptions = await (0, import_provider_utils5.parseProviderOptions)({ provider: this.config.providerOptionsName, providerOptions, schema: openResponsesOptionsSchema }); return { body: { model: this.modelId, input, instructions, max_output_tokens: maxOutputTokens, temperature, top_p: topP, presence_penalty: presencePenalty, frequency_penalty: frequencyPenalty, reasoning: (openResponsesOptions == null ? void 0 : openResponsesOptions.reasoningEffort) != null || (openResponsesOptions == null ? void 0 : openResponsesOptions.reasoningSummary) != null ? { ...(openResponsesOptions == null ? void 0 : openResponsesOptions.reasoningEffort) != null && { effort: openResponsesOptions.reasoningEffort }, ...(openResponsesOptions == null ? void 0 : openResponsesOptions.reasoningSummary) != null && { summary: openResponsesOptions.reasoningSummary } } : void 0, tools: (functionTools == null ? void 0 : functionTools.length) ? functionTools : void 0, tool_choice: convertedToolChoice, ...textFormat != null && { text: { format: textFormat } } }, warnings }; } async doGenerate(options) { var _a, _b, _c, _d, _e, _f; const { body, warnings } = await this.getArgs(options); const { responseHeaders, value: response, rawValue: rawResponse } = await (0, import_provider_utils5.postJsonToApi)({ url: this.config.url, headers: (0, import_provider_utils5.combineHeaders)(this.config.headers(), options.headers), body, failedResponseHandler: (0, import_provider_utils5.createJsonErrorResponseHandler)({ errorSchema: openResponsesErrorSchema, errorToMessage: (error) => error.error.message }), successfulResponseHandler: (0, import_provider_utils5.createJsonResponseHandler)( // do not validate the response body, only apply types to the response body (0, import_provider_utils5.jsonSchema)(() => { throw new Error("json schema not implemented"); }) ), abortSignal: options.abortSignal, fetch: this.config.fetch }); const content = []; let hasToolCalls = false; for (const part of response.output) { switch (part.type) { // TODO AI SDK 7 adjust reasoning in the specification to better support the reasoning structure from open responses. case "reasoning": { for (const contentPart of (_a = part.content) != null ? _a : []) { content.push({ type: "reasoning", text: contentPart.text }); } break; } case "message": { for (const contentPart of part.content) { content.push({ type: "text", text: contentPart.text }); } break; } case "function_call": { hasToolCalls = true; content.push({ type: "tool-call", toolCallId: part.call_id, toolName: part.name, input: part.arguments }); break; } } } const usage = response.usage; const inputTokens = usage == null ? void 0 : usage.input_tokens; const cachedInputTokens = (_b = usage == null ? void 0 : usage.input_tokens_details) == null ? void 0 : _b.cached_tokens; const outputTokens = usage == null ? void 0 : usage.output_tokens; const reasoningTokens = (_c = usage == null ? void 0 : usage.output_tokens_details) == null ? void 0 : _c.reasoning_tokens; return { content, finishReason: { unified: mapOpenResponsesFinishReason({ finishReason: (_d = response.incomplete_details) == null ? void 0 : _d.reason, hasToolCalls }), raw: (_f = (_e = response.incomplete_details) == null ? void 0 : _e.reason) != null ? _f : void 0 }, usage: { inputTokens: { total: inputTokens, noCache: (inputTokens != null ? inputTokens : 0) - (cachedInputTokens != null ? cachedInputTokens : 0), cacheRead: cachedInputTokens, cacheWrite: void 0 }, outputTokens: { total: outputTokens, text: (outputTokens != null ? outputTokens : 0) - (reasoningTokens != null ? reasoningTokens : 0), reasoning: reasoningTokens }, raw: response.usage }, request: { body }, response: { id: response.id, timestamp: new Date(response.created_at * 1e3), modelId: response.model, headers: responseHeaders, body: rawResponse }, providerMetadata: void 0, warnings }; } async doStream(options) { const { body, warnings } = await this.getArgs(options); const { responseHeaders, value: response } = await (0, import_provider_utils5.postJsonToApi)({ url: this.config.url, headers: (0, import_provider_utils5.combineHeaders)(this.config.headers(), options.headers), body: { ...body, stream: true }, failedResponseHandler: (0, import_provider_utils5.createJsonErrorResponseHandler)({ errorSchema: openResponsesErrorSchema, errorToMessage: (error) => error.error.message }), // TODO consider validation successfulResponseHandler: (0, import_provider_utils5.createEventSourceResponseHandler)(import_v43.z.any()), abortSignal: options.abortSignal, fetch: this.config.fetch }); const usage = { inputTokens: { total: void 0, noCache: void 0, cacheRead: void 0, cacheWrite: void 0 }, outputTokens: { total: void 0, text: void 0, reasoning: void 0 } }; const updateUsage = (responseUsage) => { var _a, _b; if (!responseUsage) { return; } const inputTokens = responseUsage.input_tokens; const cachedInputTokens = (_a = responseUsage.input_tokens_details) == null ? void 0 : _a.cached_tokens; const outputTokens = responseUsage.output_tokens; const reasoningTokens = (_b = responseUsage.output_tokens_details) == null ? void 0 : _b.reasoning_tokens; usage.inputTokens = { total: inputTokens, noCache: (inputTokens != null ? inputTokens : 0) - (cachedInputTokens != null ? cachedInputTokens : 0), cacheRead: cachedInputTokens, cacheWrite: void 0 }; usage.outputTokens = { total: outputTokens, text: (outputTokens != null ? outputTokens : 0) - (reasoningTokens != null ? reasoningTokens : 0), reasoning: reasoningTokens }; usage.raw = responseUsage; }; let isActiveReasoning = false; let hasToolCalls = false; let finishReason = { unified: "other", raw: void 0 }; const toolCallsByItemId = {}; return { stream: response.pipeThrough( new TransformStream({ start(controller) { controller.enqueue({ type: "stream-start", warnings }); }, transform(parseResult, controller) { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; if (options.includeRawChunks) { controller.enqueue({ type: "raw", rawValue: parseResult.rawValue }); } if (!parseResult.success) { controller.enqueue({ type: "error", error: parseResult.error }); return; } const chunk = parseResult.value; if (chunk.type === "response.output_item.added" && chunk.item.type === "function_call") { toolCallsByItemId[chunk.item.id] = { toolName: chunk.item.name, toolCallId: chunk.item.call_id, arguments: chunk.item.arguments }; } else if (chunk.type === "response.function_call_arguments.delta") { const functionCallChunk = chunk; const toolCall = (_a = toolCallsByItemId[functionCallChunk.item_id]) != null ? _a : toolCallsByItemId[functionCallChunk.item_id] = {}; toolCall.arguments = ((_b = toolCall.arguments) != null ? _b : "") + functionCallChunk.delta; } else if (chunk.type === "response.function_call_arguments.done") { const functionCallChunk = chunk; const toolCall = (_c = toolCallsByItemId[functionCallChunk.item_id]) != null ? _c : toolCallsByItemId[functionCallChunk.item_id] = {}; toolCall.arguments = functionCallChunk.arguments; } else if (chunk.type === "response.output_item.done" && chunk.item.type === "function_call") { const toolCall = toolCallsByItemId[chunk.item.id]; const toolName = (_d = toolCall == null ? void 0 : toolCall.toolName) != null ? _d : chunk.item.name; const toolCallId = (_e = toolCall == null ? void 0 : toolCall.toolCallId) != null ? _e : chunk.item.call_id; const input = (_g = (_f = toolCall == null ? void 0 : toolCall.arguments) != null ? _f : chunk.item.arguments) != null ? _g : ""; controller.enqueue({ type: "tool-call", toolCallId, toolName, input }); hasToolCalls = true; delete toolCallsByItemId[chunk.item.id]; } else if (chunk.type === "response.output_item.added" && chunk.item.type === "reasoning") { controller.enqueue({ type: "reasoning-start", id: chunk.item.id }); isActiveReasoning = true; } else if (chunk.type === "response.reasoning_text.delta") { const reasoningChunk = chunk; controller.enqueue({ type: "reasoning-delta", id: reasoningChunk.item_id, delta: reasoningChunk.delta }); } else if (chunk.type === "response.output_item.done" && chunk.item.type === "reasoning") { controller.enqueue({ type: "reasoning-end", id: chunk.item.id }); isActiveReasoning = false; } else if (chunk.type === "response.output_item.added" && chunk.item.type === "message") { controller.enqueue({ type: "text-start", id: chunk.item.id }); } else if (chunk.type === "response.output_text.delta") { controller.enqueue({ type: "text-delta", id: chunk.item_id, delta: chunk.delta }); } else if (chunk.type === "response.output_item.done" && chunk.item.type === "message") { controller.enqueue({ type: "text-end", id: chunk.item.id }); } else if (chunk.type === "response.completed" || chunk.type === "response.incomplete") { const reason = (_h = chunk.response.incomplete_details) == null ? void 0 : _h.reason; finishReason = { unified: mapOpenResponsesFinishReason({ finishReason: reason, hasToolCalls }), raw: reason != null ? reason : void 0 }; updateUsage(chunk.response.usage); } else if (chunk.type === "response.failed") { finishReason = { unified: "error", raw: (_j = (_i = chunk.response.error) == null ? void 0 : _i.code) != null ? _j : chunk.response.status }; updateUsage(chunk.response.usage); } }, flush(controller) { if (isActiveReasoning) { controller.enqueue({ type: "reasoning-end", id: "reasoning-0" }); } controller.enqueue({ type: "finish", finishReason, usage, providerMetadata: void 0 }); } }) ), request: { body }, response: { headers: responseHeaders } }; } }; // src/open-responses-provider.ts function createOpenResponses(options) { const providerName = options.name; const getHeaders = () => (0, import_provider_utils6.withUserAgentSuffix)( { ...options.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {}, ...options.headers }, `ai-sdk/open-responses/${VERSION}` ); const createResponsesModel = (modelId) => { return new OpenResponsesLanguageModel(modelId, { provider: `${providerName}.responses`, providerOptionsName: providerName, headers: getHeaders, url: options.url, fetch: options.fetch, generateId: () => (0, import_provider_utils6.generateId)() }); }; const createLanguageModel = (modelId) => { if (new.target) { throw new Error( "The OpenAI model function cannot be called with the new keyword." ); } return createResponsesModel(modelId); }; const provider = function(modelId) { return createLanguageModel(modelId); }; provider.specificationVersion = "v3"; provider.languageModel = createLanguageModel; provider.embeddingModel = (modelId) => { throw new import_provider.NoSuchModelError({ modelId, modelType: "embeddingModel" }); }; provider.imageModel = (modelId) => { throw new import_provider.NoSuchModelError({ modelId, modelType: "imageModel" }); }; return provider; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { VERSION, createOpenResponses }); //# sourceMappingURL=index.js.map