Buckets:
GHHG10/CodeServer / opencode /packages /core /src /github-copilot /responses /openai-responses-language-model.ts
| import { | |
| APICallError, | |
| type JSONValue, | |
| type LanguageModelV3, | |
| type LanguageModelV3CallOptions, | |
| type LanguageModelV3Content, | |
| type LanguageModelV3ProviderTool, | |
| type LanguageModelV3StreamPart, | |
| type SharedV3ProviderMetadata, | |
| type SharedV3Warning, | |
| } from "@ai-sdk/provider" | |
| import { | |
| combineHeaders, | |
| createEventSourceResponseHandler, | |
| createJsonResponseHandler, | |
| generateId, | |
| parseProviderOptions, | |
| type ParseResult, | |
| postJsonToApi, | |
| } from "@ai-sdk/provider-utils" | |
| import { z } from "zod/v4" | |
| import type { OpenAIConfig } from "./openai-config" | |
| import { openaiFailedResponseHandler } from "./openai-error" | |
| import { codeInterpreterInputSchema, codeInterpreterOutputSchema } from "./tool/code-interpreter" | |
| import { fileSearchOutputSchema } from "./tool/file-search" | |
| import { imageGenerationOutputSchema } from "./tool/image-generation" | |
| import { convertToOpenAIResponsesInput } from "./convert-to-openai-responses-input" | |
| import { mapOpenAIResponseFinishReason } from "./map-openai-responses-finish-reason" | |
| import type { OpenAIResponsesIncludeOptions, OpenAIResponsesIncludeValue } from "./openai-responses-api-types" | |
| import { prepareResponsesTools } from "./openai-responses-prepare-tools" | |
| import type { OpenAIResponsesModelId } from "./openai-responses-settings" | |
| import { localShellInputSchema } from "./tool/local-shell" | |
| const webSearchCallItem = z.object({ | |
| type: z.literal("web_search_call"), | |
| id: z.string(), | |
| status: z.string(), | |
| action: z | |
| .discriminatedUnion("type", [ | |
| z.object({ | |
| type: z.literal("search"), | |
| query: z.string().nullish(), | |
| }), | |
| z.object({ | |
| type: z.literal("open_page"), | |
| url: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("find"), | |
| url: z.string(), | |
| pattern: z.string(), | |
| }), | |
| ]) | |
| .nullish(), | |
| }) | |
| const fileSearchCallItem = z.object({ | |
| type: z.literal("file_search_call"), | |
| id: z.string(), | |
| queries: z.array(z.string()), | |
| results: z | |
| .array( | |
| z.object({ | |
| attributes: z.record(z.string(), z.unknown()), | |
| file_id: z.string(), | |
| filename: z.string(), | |
| score: z.number(), | |
| text: z.string(), | |
| }), | |
| ) | |
| .nullish(), | |
| }) | |
| const codeInterpreterCallItem = z.object({ | |
| type: z.literal("code_interpreter_call"), | |
| id: z.string(), | |
| code: z.string().nullable(), | |
| container_id: z.string(), | |
| outputs: z | |
| .array( | |
| z.discriminatedUnion("type", [ | |
| z.object({ type: z.literal("logs"), logs: z.string() }), | |
| z.object({ type: z.literal("image"), url: z.string() }), | |
| ]), | |
| ) | |
| .nullable(), | |
| }) | |
| const localShellCallItem = z.object({ | |
| type: z.literal("local_shell_call"), | |
| id: z.string(), | |
| call_id: z.string(), | |
| action: z.object({ | |
| type: z.literal("exec"), | |
| command: z.array(z.string()), | |
| timeout_ms: z.number().optional(), | |
| user: z.string().optional(), | |
| working_directory: z.string().optional(), | |
| env: z.record(z.string(), z.string()).optional(), | |
| }), | |
| }) | |
| const imageGenerationCallItem = z.object({ | |
| type: z.literal("image_generation_call"), | |
| id: z.string(), | |
| result: z.string(), | |
| }) | |
| /** | |
| * `top_logprobs` request body argument can be set to an integer between | |
| * 0 and 20 specifying the number of most likely tokens to return at each | |
| * token position, each with an associated log probability. | |
| * | |
| * @see https://platform.openai.com/docs/api-reference/responses/create#responses_create-top_logprobs | |
| */ | |
| const TOP_LOGPROBS_MAX = 20 | |
| const LOGPROBS_SCHEMA = z.array( | |
| z.object({ | |
| token: z.string(), | |
| logprob: z.number(), | |
| top_logprobs: z.array( | |
| z.object({ | |
| token: z.string(), | |
| logprob: z.number(), | |
| }), | |
| ), | |
| }), | |
| ) | |
| export class OpenAIResponsesLanguageModel implements LanguageModelV3 { | |
| readonly specificationVersion = "v3" | |
| readonly modelId: OpenAIResponsesModelId | |
| private readonly config: OpenAIConfig | |
| constructor(modelId: OpenAIResponsesModelId, config: OpenAIConfig) { | |
| this.modelId = modelId | |
| this.config = config | |
| } | |
| readonly supportedUrls: Record<string, RegExp[]> = { | |
| "image/*": [/^https?:\/\/.*$/], | |
| "application/pdf": [/^https?:\/\/.*$/], | |
| } | |
| get provider(): string { | |
| return this.config.provider | |
| } | |
| private async getArgs({ | |
| maxOutputTokens, | |
| temperature, | |
| stopSequences, | |
| topP, | |
| topK, | |
| presencePenalty, | |
| frequencyPenalty, | |
| seed, | |
| prompt, | |
| providerOptions, | |
| tools, | |
| toolChoice, | |
| responseFormat, | |
| }: LanguageModelV3CallOptions) { | |
| const warnings: SharedV3Warning[] = [] | |
| const modelConfig = getResponsesModelConfig(this.modelId) | |
| if (topK != null) { | |
| warnings.push({ type: "unsupported", feature: "topK" }) | |
| } | |
| if (seed != null) { | |
| warnings.push({ type: "unsupported", feature: "seed" }) | |
| } | |
| if (presencePenalty != null) { | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "presencePenalty", | |
| }) | |
| } | |
| if (frequencyPenalty != null) { | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "frequencyPenalty", | |
| }) | |
| } | |
| if (stopSequences != null) { | |
| warnings.push({ type: "unsupported", feature: "stopSequences" }) | |
| } | |
| const openaiOptions = await parseProviderOptions({ | |
| provider: "copilot", | |
| providerOptions, | |
| schema: openaiResponsesProviderOptionsSchema, | |
| }) | |
| const { input, warnings: inputWarnings } = await convertToOpenAIResponsesInput({ | |
| prompt, | |
| systemMessageMode: modelConfig.systemMessageMode, | |
| fileIdPrefixes: this.config.fileIdPrefixes, | |
| store: openaiOptions?.store ?? true, | |
| hasLocalShellTool: hasOpenAITool("openai.local_shell"), | |
| }) | |
| warnings.push(...inputWarnings) | |
| const strictJsonSchema = openaiOptions?.strictJsonSchema ?? false | |
| let include: OpenAIResponsesIncludeOptions = openaiOptions?.include | |
| function addInclude(key: OpenAIResponsesIncludeValue) { | |
| include = include != null ? [...include, key] : [key] | |
| } | |
| function hasOpenAITool(id: string) { | |
| return tools?.find((tool) => tool.type === "provider" && tool.id === id) != null | |
| } | |
| // when logprobs are requested, automatically include them: | |
| const topLogprobs = | |
| typeof openaiOptions?.logprobs === "number" | |
| ? openaiOptions?.logprobs | |
| : openaiOptions?.logprobs === true | |
| ? TOP_LOGPROBS_MAX | |
| : undefined | |
| if (topLogprobs) { | |
| addInclude("message.output_text.logprobs") | |
| } | |
| // when a web search tool is present, automatically include the sources: | |
| const webSearchToolName = ( | |
| tools?.find( | |
| (tool) => | |
| tool.type === "provider" && (tool.id === "openai.web_search" || tool.id === "openai.web_search_preview"), | |
| ) as LanguageModelV3ProviderTool | undefined | |
| )?.name | |
| if (webSearchToolName) { | |
| addInclude("web_search_call.action.sources") | |
| } | |
| // when a code interpreter tool is present, automatically include the outputs: | |
| if (hasOpenAITool("openai.code_interpreter")) { | |
| addInclude("code_interpreter_call.outputs") | |
| } | |
| const baseArgs = { | |
| model: this.modelId, | |
| input, | |
| temperature, | |
| top_p: topP, | |
| max_output_tokens: maxOutputTokens, | |
| ...((responseFormat?.type === "json" || openaiOptions?.textVerbosity) && { | |
| text: { | |
| ...(responseFormat?.type === "json" && { | |
| format: | |
| responseFormat.schema != null | |
| ? { | |
| type: "json_schema", | |
| strict: strictJsonSchema, | |
| name: responseFormat.name ?? "response", | |
| description: responseFormat.description, | |
| schema: responseFormat.schema, | |
| } | |
| : { type: "json_object" }, | |
| }), | |
| ...(openaiOptions?.textVerbosity && { | |
| verbosity: openaiOptions.textVerbosity, | |
| }), | |
| }, | |
| }), | |
| // provider options: | |
| max_tool_calls: openaiOptions?.maxToolCalls, | |
| metadata: openaiOptions?.metadata, | |
| parallel_tool_calls: openaiOptions?.parallelToolCalls, | |
| previous_response_id: openaiOptions?.previousResponseId, | |
| store: openaiOptions?.store, | |
| user: openaiOptions?.user, | |
| instructions: openaiOptions?.instructions, | |
| service_tier: openaiOptions?.serviceTier, | |
| include, | |
| prompt_cache_key: openaiOptions?.promptCacheKey, | |
| safety_identifier: openaiOptions?.safetyIdentifier, | |
| top_logprobs: topLogprobs, | |
| // model-specific settings: | |
| ...(modelConfig.isReasoningModel && | |
| (openaiOptions?.reasoningEffort != null || openaiOptions?.reasoningSummary != null) && { | |
| reasoning: { | |
| ...(openaiOptions?.reasoningEffort != null && { | |
| effort: openaiOptions.reasoningEffort, | |
| }), | |
| ...(openaiOptions?.reasoningSummary != null && { | |
| summary: openaiOptions.reasoningSummary, | |
| }), | |
| }, | |
| }), | |
| ...(modelConfig.requiredAutoTruncation && { | |
| truncation: "auto", | |
| }), | |
| } | |
| if (modelConfig.isReasoningModel) { | |
| // remove unsupported settings for reasoning models | |
| // see https://platform.openai.com/docs/guides/reasoning#limitations | |
| if (baseArgs.temperature != null) { | |
| baseArgs.temperature = undefined | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "temperature", | |
| details: "temperature is not supported for reasoning models", | |
| }) | |
| } | |
| if (baseArgs.top_p != null) { | |
| baseArgs.top_p = undefined | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "topP", | |
| details: "topP is not supported for reasoning models", | |
| }) | |
| } | |
| } else { | |
| if (openaiOptions?.reasoningEffort != null) { | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "reasoningEffort", | |
| details: "reasoningEffort is not supported for non-reasoning models", | |
| }) | |
| } | |
| if (openaiOptions?.reasoningSummary != null) { | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "reasoningSummary", | |
| details: "reasoningSummary is not supported for non-reasoning models", | |
| }) | |
| } | |
| } | |
| // Validate flex processing support | |
| if (openaiOptions?.serviceTier === "flex" && !modelConfig.supportsFlexProcessing) { | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "serviceTier", | |
| details: "flex processing is only available for o3, o4-mini, and gpt-5 models", | |
| }) | |
| // Remove from args if not supported | |
| baseArgs.service_tier = undefined | |
| } | |
| // Validate priority processing support | |
| if (openaiOptions?.serviceTier === "priority" && !modelConfig.supportsPriorityProcessing) { | |
| warnings.push({ | |
| type: "unsupported", | |
| feature: "serviceTier", | |
| details: | |
| "priority processing is only available for supported models (gpt-4, gpt-5, gpt-5-mini, o3, o4-mini) and requires Enterprise access. gpt-5-nano is not supported", | |
| }) | |
| // Remove from args if not supported | |
| baseArgs.service_tier = undefined | |
| } | |
| const { | |
| tools: openaiTools, | |
| toolChoice: openaiToolChoice, | |
| toolWarnings, | |
| } = prepareResponsesTools({ | |
| tools, | |
| toolChoice, | |
| strictJsonSchema, | |
| }) | |
| return { | |
| webSearchToolName, | |
| args: { | |
| ...baseArgs, | |
| tools: openaiTools, | |
| tool_choice: openaiToolChoice, | |
| }, | |
| warnings: [...warnings, ...toolWarnings], | |
| } | |
| } | |
| async doGenerate(options: LanguageModelV3CallOptions) { | |
| const { args: body, warnings, webSearchToolName } = await this.getArgs(options) | |
| const url = this.config.url({ | |
| path: "/responses", | |
| modelId: this.modelId, | |
| }) | |
| const { | |
| responseHeaders, | |
| value: response, | |
| rawValue: rawResponse, | |
| } = await postJsonToApi({ | |
| url, | |
| headers: combineHeaders(this.config.headers(), options.headers), | |
| body, | |
| failedResponseHandler: openaiFailedResponseHandler, | |
| successfulResponseHandler: createJsonResponseHandler( | |
| z.object({ | |
| id: z.string(), | |
| created_at: z.number(), | |
| error: z | |
| .object({ | |
| code: z.string(), | |
| message: z.string(), | |
| }) | |
| .nullish(), | |
| model: z.string(), | |
| output: z.array( | |
| z.discriminatedUnion("type", [ | |
| z.object({ | |
| type: z.literal("message"), | |
| role: z.literal("assistant"), | |
| id: z.string(), | |
| content: z.array( | |
| z.object({ | |
| type: z.literal("output_text"), | |
| text: z.string(), | |
| logprobs: LOGPROBS_SCHEMA.nullish(), | |
| annotations: z.array( | |
| z.discriminatedUnion("type", [ | |
| z.object({ | |
| type: z.literal("url_citation"), | |
| start_index: z.number(), | |
| end_index: z.number(), | |
| url: z.string(), | |
| title: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("file_citation"), | |
| file_id: z.string(), | |
| filename: z.string().nullish(), | |
| index: z.number().nullish(), | |
| start_index: z.number().nullish(), | |
| end_index: z.number().nullish(), | |
| quote: z.string().nullish(), | |
| }), | |
| z.object({ | |
| type: z.literal("container_file_citation"), | |
| }), | |
| ]), | |
| ), | |
| }), | |
| ), | |
| }), | |
| webSearchCallItem, | |
| fileSearchCallItem, | |
| codeInterpreterCallItem, | |
| imageGenerationCallItem, | |
| localShellCallItem, | |
| z.object({ | |
| type: z.literal("function_call"), | |
| call_id: z.string(), | |
| name: z.string(), | |
| arguments: z.string(), | |
| id: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("computer_call"), | |
| id: z.string(), | |
| status: z.string().optional(), | |
| }), | |
| z.object({ | |
| type: z.literal("reasoning"), | |
| id: z.string(), | |
| encrypted_content: z.string().nullish(), | |
| summary: z.array( | |
| z.object({ | |
| type: z.literal("summary_text"), | |
| text: z.string(), | |
| }), | |
| ), | |
| }), | |
| ]), | |
| ), | |
| service_tier: z.string().nullish(), | |
| incomplete_details: z.object({ reason: z.string() }).nullish(), | |
| usage: usageSchema, | |
| }), | |
| ), | |
| abortSignal: options.abortSignal, | |
| fetch: this.config.fetch, | |
| }) | |
| if (response.error) { | |
| throw new APICallError({ | |
| message: response.error.message, | |
| url, | |
| requestBodyValues: body, | |
| statusCode: 400, | |
| responseHeaders, | |
| responseBody: rawResponse as string, | |
| isRetryable: false, | |
| }) | |
| } | |
| const content: Array<LanguageModelV3Content> = [] | |
| const logprobs: Array<z.infer<typeof LOGPROBS_SCHEMA>> = [] | |
| // flag that checks if there have been client-side tool calls (not executed by openai) | |
| let hasFunctionCall = false | |
| // map response content to content array | |
| for (const part of response.output) { | |
| switch (part.type) { | |
| case "reasoning": { | |
| // when there are no summary parts, we need to add an empty reasoning part: | |
| if (part.summary.length === 0) { | |
| part.summary.push({ type: "summary_text", text: "" }) | |
| } | |
| for (const summary of part.summary) { | |
| content.push({ | |
| type: "reasoning" as const, | |
| text: summary.text, | |
| providerMetadata: { | |
| openai: { | |
| itemId: part.id, | |
| reasoningEncryptedContent: part.encrypted_content ?? null, | |
| }, | |
| }, | |
| }) | |
| } | |
| break | |
| } | |
| case "image_generation_call": { | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.id, | |
| toolName: "image_generation", | |
| input: "{}", | |
| providerExecuted: true, | |
| }) | |
| content.push({ | |
| type: "tool-result", | |
| toolCallId: part.id, | |
| toolName: "image_generation", | |
| result: { | |
| result: part.result, | |
| } satisfies z.infer<typeof imageGenerationOutputSchema>, | |
| }) | |
| break | |
| } | |
| case "local_shell_call": { | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.call_id, | |
| toolName: "local_shell", | |
| input: JSON.stringify({ action: part.action } satisfies z.infer<typeof localShellInputSchema>), | |
| providerMetadata: { | |
| openai: { | |
| itemId: part.id, | |
| }, | |
| }, | |
| }) | |
| break | |
| } | |
| case "message": { | |
| for (const contentPart of part.content) { | |
| if (options.providerOptions?.openai?.logprobs && contentPart.logprobs) { | |
| logprobs.push(contentPart.logprobs) | |
| } | |
| content.push({ | |
| type: "text", | |
| text: contentPart.text, | |
| providerMetadata: { | |
| openai: { | |
| itemId: part.id, | |
| }, | |
| }, | |
| }) | |
| for (const annotation of contentPart.annotations) { | |
| if (annotation.type === "url_citation") { | |
| content.push({ | |
| type: "source", | |
| sourceType: "url", | |
| id: this.config.generateId?.() ?? generateId(), | |
| url: annotation.url, | |
| title: annotation.title, | |
| }) | |
| } else if (annotation.type === "file_citation") { | |
| content.push({ | |
| type: "source", | |
| sourceType: "document", | |
| id: this.config.generateId?.() ?? generateId(), | |
| mediaType: "text/plain", | |
| title: annotation.quote ?? annotation.filename ?? "Document", | |
| filename: annotation.filename ?? annotation.file_id, | |
| }) | |
| } | |
| } | |
| } | |
| break | |
| } | |
| case "function_call": { | |
| hasFunctionCall = true | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.call_id, | |
| toolName: part.name, | |
| input: part.arguments, | |
| providerMetadata: { | |
| openai: { | |
| itemId: part.id, | |
| }, | |
| }, | |
| }) | |
| break | |
| } | |
| case "web_search_call": { | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.id, | |
| toolName: webSearchToolName ?? "web_search", | |
| input: JSON.stringify({ action: part.action }), | |
| providerExecuted: true, | |
| }) | |
| content.push({ | |
| type: "tool-result", | |
| toolCallId: part.id, | |
| toolName: webSearchToolName ?? "web_search", | |
| result: { status: part.status }, | |
| }) | |
| break | |
| } | |
| case "computer_call": { | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.id, | |
| toolName: "computer_use", | |
| input: "", | |
| providerExecuted: true, | |
| }) | |
| content.push({ | |
| type: "tool-result", | |
| toolCallId: part.id, | |
| toolName: "computer_use", | |
| result: { | |
| type: "computer_use_tool_result", | |
| status: part.status || "completed", | |
| }, | |
| }) | |
| break | |
| } | |
| case "file_search_call": { | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.id, | |
| toolName: "file_search", | |
| input: "{}", | |
| providerExecuted: true, | |
| }) | |
| content.push({ | |
| type: "tool-result", | |
| toolCallId: part.id, | |
| toolName: "file_search", | |
| result: { | |
| queries: part.queries, | |
| results: | |
| part.results?.map((result) => ({ | |
| attributes: result.attributes as Record<string, JSONValue>, | |
| fileId: result.file_id, | |
| filename: result.filename, | |
| score: result.score, | |
| text: result.text, | |
| })) ?? null, | |
| } satisfies z.infer<typeof fileSearchOutputSchema>, | |
| }) | |
| break | |
| } | |
| case "code_interpreter_call": { | |
| content.push({ | |
| type: "tool-call", | |
| toolCallId: part.id, | |
| toolName: "code_interpreter", | |
| input: JSON.stringify({ | |
| code: part.code, | |
| containerId: part.container_id, | |
| } satisfies z.infer<typeof codeInterpreterInputSchema>), | |
| providerExecuted: true, | |
| }) | |
| content.push({ | |
| type: "tool-result", | |
| toolCallId: part.id, | |
| toolName: "code_interpreter", | |
| result: { | |
| outputs: part.outputs, | |
| } satisfies z.infer<typeof codeInterpreterOutputSchema>, | |
| }) | |
| break | |
| } | |
| } | |
| } | |
| const providerMetadata: SharedV3ProviderMetadata = { | |
| openai: { responseId: response.id }, | |
| } | |
| if (logprobs.length > 0) { | |
| providerMetadata.openai.logprobs = logprobs | |
| } | |
| if (typeof response.service_tier === "string") { | |
| providerMetadata.openai.serviceTier = response.service_tier | |
| } | |
| return { | |
| content, | |
| finishReason: { | |
| unified: mapOpenAIResponseFinishReason({ | |
| finishReason: response.incomplete_details?.reason, | |
| hasFunctionCall, | |
| }), | |
| raw: response.incomplete_details?.reason, | |
| }, | |
| usage: { | |
| inputTokens: { | |
| total: response.usage.input_tokens, | |
| noCache: | |
| response.usage.input_tokens_details?.cached_tokens != null | |
| ? response.usage.input_tokens - response.usage.input_tokens_details.cached_tokens | |
| : undefined, | |
| cacheRead: response.usage.input_tokens_details?.cached_tokens ?? undefined, | |
| cacheWrite: undefined, | |
| }, | |
| outputTokens: { | |
| total: response.usage.output_tokens, | |
| text: undefined, | |
| reasoning: response.usage.output_tokens_details?.reasoning_tokens ?? undefined, | |
| }, | |
| raw: response.usage, | |
| }, | |
| request: { body }, | |
| response: { | |
| id: response.id, | |
| timestamp: new Date(response.created_at * 1000), | |
| modelId: response.model, | |
| headers: responseHeaders, | |
| body: rawResponse, | |
| }, | |
| providerMetadata, | |
| warnings, | |
| } | |
| } | |
| async doStream(options: LanguageModelV3CallOptions) { | |
| const { args: body, warnings, webSearchToolName } = await this.getArgs(options) | |
| const { responseHeaders, value: response } = await postJsonToApi({ | |
| url: this.config.url({ | |
| path: "/responses", | |
| modelId: this.modelId, | |
| }), | |
| headers: combineHeaders(this.config.headers(), options.headers), | |
| body: { | |
| ...body, | |
| stream: true, | |
| }, | |
| failedResponseHandler: openaiFailedResponseHandler, | |
| successfulResponseHandler: createEventSourceResponseHandler(openaiResponsesChunkSchema), | |
| abortSignal: options.abortSignal, | |
| fetch: this.config.fetch, | |
| }) | |
| // oxlint-disable-next-line no-this-alias -- needed for closure scope inside generator | |
| const self = this | |
| let finishReason: { | |
| unified: ReturnType<typeof mapOpenAIResponseFinishReason> | |
| raw: string | undefined | |
| } = { | |
| unified: "other", | |
| raw: undefined, | |
| } | |
| const usage: { | |
| inputTokens: number | undefined | |
| outputTokens: number | undefined | |
| totalTokens: number | undefined | |
| reasoningTokens: number | undefined | |
| cachedInputTokens: number | undefined | |
| } = { | |
| inputTokens: undefined, | |
| outputTokens: undefined, | |
| totalTokens: undefined, | |
| reasoningTokens: undefined, | |
| cachedInputTokens: undefined, | |
| } | |
| const logprobs: Array<z.infer<typeof LOGPROBS_SCHEMA>> = [] | |
| let responseId: string | null = null | |
| const ongoingToolCalls: Record< | |
| number, | |
| | { | |
| toolName: string | |
| toolCallId: string | |
| codeInterpreter?: { | |
| containerId: string | |
| } | |
| } | |
| | undefined | |
| > = {} | |
| // flag that checks if there have been client-side tool calls (not executed by openai) | |
| let hasFunctionCall = false | |
| // Track reasoning by output_index instead of item_id | |
| // GitHub Copilot rotates encrypted item IDs on every event | |
| const activeReasoning: Record< | |
| number, | |
| { | |
| canonicalId: string // the item.id from output_item.added | |
| encryptedContent?: string | null | |
| summaryParts: number[] | |
| } | |
| > = {} | |
| // Track current active reasoning output_index for correlating summary events | |
| let currentReasoningOutputIndex: number | null = null | |
| // Track a stable text part id for the current assistant message. | |
| // Copilot may change item_id across text deltas; normalize to one id. | |
| let currentTextId: string | null = null | |
| let serviceTier: string | undefined | |
| return { | |
| stream: response.pipeThrough( | |
| new TransformStream<ParseResult<z.infer<typeof openaiResponsesChunkSchema>>, LanguageModelV3StreamPart>({ | |
| start(controller) { | |
| controller.enqueue({ type: "stream-start", warnings }) | |
| }, | |
| transform(chunk, controller) { | |
| if (options.includeRawChunks) { | |
| controller.enqueue({ type: "raw", rawValue: chunk.rawValue }) | |
| } | |
| // handle failed chunk parsing / validation: | |
| if (!chunk.success) { | |
| finishReason = { | |
| unified: "error", | |
| raw: undefined, | |
| } | |
| controller.enqueue({ type: "error", error: chunk.error }) | |
| return | |
| } | |
| const value = chunk.value | |
| if (isResponseOutputItemAddedChunk(value)) { | |
| if (value.item.type === "function_call") { | |
| ongoingToolCalls[value.output_index] = { | |
| toolName: value.item.name, | |
| toolCallId: value.item.call_id, | |
| } | |
| controller.enqueue({ | |
| type: "tool-input-start", | |
| id: value.item.call_id, | |
| toolName: value.item.name, | |
| }) | |
| } else if (value.item.type === "web_search_call") { | |
| ongoingToolCalls[value.output_index] = { | |
| toolName: webSearchToolName ?? "web_search", | |
| toolCallId: value.item.id, | |
| } | |
| controller.enqueue({ | |
| type: "tool-input-start", | |
| id: value.item.id, | |
| toolName: webSearchToolName ?? "web_search", | |
| }) | |
| } else if (value.item.type === "computer_call") { | |
| ongoingToolCalls[value.output_index] = { | |
| toolName: "computer_use", | |
| toolCallId: value.item.id, | |
| } | |
| controller.enqueue({ | |
| type: "tool-input-start", | |
| id: value.item.id, | |
| toolName: "computer_use", | |
| }) | |
| } else if (value.item.type === "code_interpreter_call") { | |
| ongoingToolCalls[value.output_index] = { | |
| toolName: "code_interpreter", | |
| toolCallId: value.item.id, | |
| codeInterpreter: { | |
| containerId: value.item.container_id, | |
| }, | |
| } | |
| controller.enqueue({ | |
| type: "tool-input-start", | |
| id: value.item.id, | |
| toolName: "code_interpreter", | |
| }) | |
| controller.enqueue({ | |
| type: "tool-input-delta", | |
| id: value.item.id, | |
| delta: `{"containerId":"${value.item.container_id}","code":"`, | |
| }) | |
| } else if (value.item.type === "file_search_call") { | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: value.item.id, | |
| toolName: "file_search", | |
| input: "{}", | |
| providerExecuted: true, | |
| }) | |
| } else if (value.item.type === "image_generation_call") { | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: value.item.id, | |
| toolName: "image_generation", | |
| input: "{}", | |
| providerExecuted: true, | |
| }) | |
| } else if (value.item.type === "message") { | |
| // Start a stable text part for this assistant message | |
| currentTextId = value.item.id | |
| controller.enqueue({ | |
| type: "text-start", | |
| id: value.item.id, | |
| providerMetadata: { | |
| openai: { | |
| itemId: value.item.id, | |
| }, | |
| }, | |
| }) | |
| } else if (isResponseOutputItemAddedReasoningChunk(value)) { | |
| activeReasoning[value.output_index] = { | |
| canonicalId: value.item.id, | |
| encryptedContent: value.item.encrypted_content, | |
| summaryParts: [0], | |
| } | |
| currentReasoningOutputIndex = value.output_index | |
| controller.enqueue({ | |
| type: "reasoning-start", | |
| id: `${value.item.id}:0`, | |
| providerMetadata: { | |
| openai: { | |
| itemId: value.item.id, | |
| reasoningEncryptedContent: value.item.encrypted_content ?? null, | |
| }, | |
| }, | |
| }) | |
| } | |
| } else if (isResponseOutputItemDoneChunk(value)) { | |
| if (value.item.type === "function_call") { | |
| ongoingToolCalls[value.output_index] = undefined | |
| hasFunctionCall = true | |
| controller.enqueue({ | |
| type: "tool-input-end", | |
| id: value.item.call_id, | |
| }) | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: value.item.call_id, | |
| toolName: value.item.name, | |
| input: value.item.arguments, | |
| providerMetadata: { | |
| openai: { | |
| itemId: value.item.id, | |
| }, | |
| }, | |
| }) | |
| } else if (value.item.type === "web_search_call") { | |
| ongoingToolCalls[value.output_index] = undefined | |
| controller.enqueue({ | |
| type: "tool-input-end", | |
| id: value.item.id, | |
| }) | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: value.item.id, | |
| toolName: "web_search", | |
| input: JSON.stringify({ action: value.item.action }), | |
| providerExecuted: true, | |
| }) | |
| controller.enqueue({ | |
| type: "tool-result", | |
| toolCallId: value.item.id, | |
| toolName: "web_search", | |
| result: { status: value.item.status }, | |
| }) | |
| } else if (value.item.type === "computer_call") { | |
| ongoingToolCalls[value.output_index] = undefined | |
| controller.enqueue({ | |
| type: "tool-input-end", | |
| id: value.item.id, | |
| }) | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: value.item.id, | |
| toolName: "computer_use", | |
| input: "", | |
| providerExecuted: true, | |
| }) | |
| controller.enqueue({ | |
| type: "tool-result", | |
| toolCallId: value.item.id, | |
| toolName: "computer_use", | |
| result: { | |
| type: "computer_use_tool_result", | |
| status: value.item.status || "completed", | |
| }, | |
| }) | |
| } else if (value.item.type === "file_search_call") { | |
| ongoingToolCalls[value.output_index] = undefined | |
| controller.enqueue({ | |
| type: "tool-result", | |
| toolCallId: value.item.id, | |
| toolName: "file_search", | |
| result: { | |
| queries: value.item.queries, | |
| results: | |
| value.item.results?.map((result) => ({ | |
| attributes: result.attributes as Record<string, JSONValue>, | |
| fileId: result.file_id, | |
| filename: result.filename, | |
| score: result.score, | |
| text: result.text, | |
| })) ?? null, | |
| } satisfies z.infer<typeof fileSearchOutputSchema>, | |
| }) | |
| } else if (value.item.type === "code_interpreter_call") { | |
| ongoingToolCalls[value.output_index] = undefined | |
| controller.enqueue({ | |
| type: "tool-result", | |
| toolCallId: value.item.id, | |
| toolName: "code_interpreter", | |
| result: { | |
| outputs: value.item.outputs, | |
| } satisfies z.infer<typeof codeInterpreterOutputSchema>, | |
| }) | |
| } else if (value.item.type === "image_generation_call") { | |
| controller.enqueue({ | |
| type: "tool-result", | |
| toolCallId: value.item.id, | |
| toolName: "image_generation", | |
| result: { | |
| result: value.item.result, | |
| } satisfies z.infer<typeof imageGenerationOutputSchema>, | |
| }) | |
| } else if (value.item.type === "local_shell_call") { | |
| ongoingToolCalls[value.output_index] = undefined | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: value.item.call_id, | |
| toolName: "local_shell", | |
| input: JSON.stringify({ | |
| action: { | |
| type: "exec", | |
| command: value.item.action.command, | |
| timeoutMs: value.item.action.timeout_ms, | |
| user: value.item.action.user, | |
| workingDirectory: value.item.action.working_directory, | |
| env: value.item.action.env, | |
| }, | |
| } satisfies z.infer<typeof localShellInputSchema>), | |
| providerMetadata: { | |
| openai: { itemId: value.item.id }, | |
| }, | |
| }) | |
| } else if (value.item.type === "message") { | |
| if (currentTextId) { | |
| controller.enqueue({ | |
| type: "text-end", | |
| id: currentTextId, | |
| }) | |
| currentTextId = null | |
| } | |
| } else if (isResponseOutputItemDoneReasoningChunk(value)) { | |
| const activeReasoningPart = activeReasoning[value.output_index] | |
| if (activeReasoningPart) { | |
| for (const summaryIndex of activeReasoningPart.summaryParts) { | |
| controller.enqueue({ | |
| type: "reasoning-end", | |
| id: `${activeReasoningPart.canonicalId}:${summaryIndex}`, | |
| providerMetadata: { | |
| openai: { | |
| itemId: activeReasoningPart.canonicalId, | |
| reasoningEncryptedContent: value.item.encrypted_content ?? null, | |
| }, | |
| }, | |
| }) | |
| } | |
| delete activeReasoning[value.output_index] | |
| if (currentReasoningOutputIndex === value.output_index) { | |
| currentReasoningOutputIndex = null | |
| } | |
| } | |
| } | |
| } else if (isResponseFunctionCallArgumentsDeltaChunk(value)) { | |
| const toolCall = ongoingToolCalls[value.output_index] | |
| if (toolCall != null) { | |
| controller.enqueue({ | |
| type: "tool-input-delta", | |
| id: toolCall.toolCallId, | |
| delta: value.delta, | |
| }) | |
| } | |
| } else if (isResponseImageGenerationCallPartialImageChunk(value)) { | |
| controller.enqueue({ | |
| type: "tool-result", | |
| toolCallId: value.item_id, | |
| toolName: "image_generation", | |
| result: { | |
| result: value.partial_image_b64, | |
| } satisfies z.infer<typeof imageGenerationOutputSchema>, | |
| }) | |
| } else if (isResponseCodeInterpreterCallCodeDeltaChunk(value)) { | |
| const toolCall = ongoingToolCalls[value.output_index] | |
| if (toolCall != null) { | |
| controller.enqueue({ | |
| type: "tool-input-delta", | |
| id: toolCall.toolCallId, | |
| // The delta is code, which is embedding in a JSON string. | |
| // To escape it, we use JSON.stringify and slice to remove the outer quotes. | |
| delta: JSON.stringify(value.delta).slice(1, -1), | |
| }) | |
| } | |
| } else if (isResponseCodeInterpreterCallCodeDoneChunk(value)) { | |
| const toolCall = ongoingToolCalls[value.output_index] | |
| if (toolCall != null) { | |
| controller.enqueue({ | |
| type: "tool-input-delta", | |
| id: toolCall.toolCallId, | |
| delta: '"}', | |
| }) | |
| controller.enqueue({ | |
| type: "tool-input-end", | |
| id: toolCall.toolCallId, | |
| }) | |
| // immediately send the tool call after the input end: | |
| controller.enqueue({ | |
| type: "tool-call", | |
| toolCallId: toolCall.toolCallId, | |
| toolName: "code_interpreter", | |
| input: JSON.stringify({ | |
| code: value.code, | |
| containerId: toolCall.codeInterpreter!.containerId, | |
| } satisfies z.infer<typeof codeInterpreterInputSchema>), | |
| providerExecuted: true, | |
| }) | |
| } | |
| } else if (isResponseCreatedChunk(value)) { | |
| responseId = value.response.id | |
| controller.enqueue({ | |
| type: "response-metadata", | |
| id: value.response.id, | |
| timestamp: new Date(value.response.created_at * 1000), | |
| modelId: value.response.model, | |
| }) | |
| } else if (isTextDeltaChunk(value)) { | |
| // Ensure a text-start exists, and normalize deltas to a stable id | |
| if (!currentTextId) { | |
| currentTextId = value.item_id | |
| controller.enqueue({ | |
| type: "text-start", | |
| id: currentTextId, | |
| providerMetadata: { | |
| openai: { itemId: value.item_id }, | |
| }, | |
| }) | |
| } | |
| controller.enqueue({ | |
| type: "text-delta", | |
| id: currentTextId, | |
| delta: value.delta, | |
| }) | |
| if (options.providerOptions?.openai?.logprobs && value.logprobs) { | |
| logprobs.push(value.logprobs) | |
| } | |
| } else if (isResponseReasoningSummaryPartAddedChunk(value)) { | |
| const activeItem = | |
| currentReasoningOutputIndex !== null ? activeReasoning[currentReasoningOutputIndex] : null | |
| // the first reasoning start is pushed in isResponseOutputItemAddedReasoningChunk. | |
| if (activeItem && value.summary_index > 0) { | |
| activeItem.summaryParts.push(value.summary_index) | |
| controller.enqueue({ | |
| type: "reasoning-start", | |
| id: `${activeItem.canonicalId}:${value.summary_index}`, | |
| providerMetadata: { | |
| openai: { | |
| itemId: activeItem.canonicalId, | |
| reasoningEncryptedContent: activeItem.encryptedContent ?? null, | |
| }, | |
| }, | |
| }) | |
| } | |
| } else if (isResponseReasoningSummaryTextDeltaChunk(value)) { | |
| const activeItem = | |
| currentReasoningOutputIndex !== null ? activeReasoning[currentReasoningOutputIndex] : null | |
| if (activeItem) { | |
| controller.enqueue({ | |
| type: "reasoning-delta", | |
| id: `${activeItem.canonicalId}:${value.summary_index}`, | |
| delta: value.delta, | |
| providerMetadata: { | |
| openai: { | |
| itemId: activeItem.canonicalId, | |
| }, | |
| }, | |
| }) | |
| } | |
| } else if (isResponseFinishedChunk(value)) { | |
| finishReason = { | |
| unified: mapOpenAIResponseFinishReason({ | |
| finishReason: value.response.incomplete_details?.reason, | |
| hasFunctionCall, | |
| }), | |
| raw: value.response.incomplete_details?.reason ?? undefined, | |
| } | |
| usage.inputTokens = value.response.usage.input_tokens | |
| usage.outputTokens = value.response.usage.output_tokens | |
| usage.totalTokens = value.response.usage.input_tokens + value.response.usage.output_tokens | |
| usage.reasoningTokens = value.response.usage.output_tokens_details?.reasoning_tokens ?? undefined | |
| usage.cachedInputTokens = value.response.usage.input_tokens_details?.cached_tokens ?? undefined | |
| if (typeof value.response.service_tier === "string") { | |
| serviceTier = value.response.service_tier | |
| } | |
| } else if (isResponseAnnotationAddedChunk(value)) { | |
| if (value.annotation.type === "url_citation") { | |
| controller.enqueue({ | |
| type: "source", | |
| sourceType: "url", | |
| id: self.config.generateId?.() ?? generateId(), | |
| url: value.annotation.url, | |
| title: value.annotation.title, | |
| }) | |
| } else if (value.annotation.type === "file_citation") { | |
| controller.enqueue({ | |
| type: "source", | |
| sourceType: "document", | |
| id: self.config.generateId?.() ?? generateId(), | |
| mediaType: "text/plain", | |
| title: value.annotation.quote ?? value.annotation.filename ?? "Document", | |
| filename: value.annotation.filename ?? value.annotation.file_id, | |
| }) | |
| } | |
| } else if (isErrorChunk(value)) { | |
| controller.enqueue({ type: "error", error: value }) | |
| } | |
| }, | |
| flush(controller) { | |
| // Close any dangling text part | |
| if (currentTextId) { | |
| controller.enqueue({ type: "text-end", id: currentTextId }) | |
| currentTextId = null | |
| } | |
| const providerMetadata: SharedV3ProviderMetadata = { | |
| openai: { | |
| responseId, | |
| }, | |
| } | |
| if (logprobs.length > 0) { | |
| providerMetadata.openai.logprobs = logprobs | |
| } | |
| if (serviceTier !== undefined) { | |
| providerMetadata.openai.serviceTier = serviceTier | |
| } | |
| controller.enqueue({ | |
| type: "finish", | |
| finishReason, | |
| usage: { | |
| inputTokens: { | |
| total: usage.inputTokens, | |
| noCache: | |
| usage.inputTokens != null && usage.cachedInputTokens != null | |
| ? usage.inputTokens - usage.cachedInputTokens | |
| : undefined, | |
| cacheRead: usage.cachedInputTokens, | |
| cacheWrite: undefined, | |
| }, | |
| outputTokens: { | |
| total: usage.outputTokens, | |
| text: undefined, | |
| reasoning: usage.reasoningTokens, | |
| }, | |
| raw: { | |
| input_tokens: usage.inputTokens, | |
| output_tokens: usage.outputTokens, | |
| total_tokens: usage.totalTokens, | |
| }, | |
| }, | |
| providerMetadata, | |
| }) | |
| }, | |
| }), | |
| ), | |
| request: { body }, | |
| response: { headers: responseHeaders }, | |
| } | |
| } | |
| } | |
| const usageSchema = z.object({ | |
| input_tokens: z.number(), | |
| input_tokens_details: z.object({ cached_tokens: z.number().nullish() }).nullish(), | |
| output_tokens: z.number(), | |
| output_tokens_details: z.object({ reasoning_tokens: z.number().nullish() }).nullish(), | |
| }) | |
| const textDeltaChunkSchema = z.object({ | |
| type: z.literal("response.output_text.delta"), | |
| item_id: z.string(), | |
| delta: z.string(), | |
| logprobs: LOGPROBS_SCHEMA.nullish(), | |
| }) | |
| const errorChunkSchema = z.object({ | |
| type: z.literal("error"), | |
| code: z.string(), | |
| message: z.string(), | |
| param: z.string().nullish(), | |
| sequence_number: z.number(), | |
| }) | |
| const responseFinishedChunkSchema = z.object({ | |
| type: z.enum(["response.completed", "response.incomplete"]), | |
| response: z.object({ | |
| incomplete_details: z.object({ reason: z.string() }).nullish(), | |
| usage: usageSchema, | |
| service_tier: z.string().nullish(), | |
| }), | |
| }) | |
| const responseCreatedChunkSchema = z.object({ | |
| type: z.literal("response.created"), | |
| response: z.object({ | |
| id: z.string(), | |
| created_at: z.number(), | |
| model: z.string(), | |
| service_tier: z.string().nullish(), | |
| }), | |
| }) | |
| const responseOutputItemAddedSchema = z.object({ | |
| type: z.literal("response.output_item.added"), | |
| output_index: z.number(), | |
| item: z.discriminatedUnion("type", [ | |
| z.object({ | |
| type: z.literal("message"), | |
| id: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("reasoning"), | |
| id: z.string(), | |
| encrypted_content: z.string().nullish(), | |
| }), | |
| z.object({ | |
| type: z.literal("function_call"), | |
| id: z.string(), | |
| call_id: z.string(), | |
| name: z.string(), | |
| arguments: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("web_search_call"), | |
| id: z.string(), | |
| status: z.string(), | |
| action: z | |
| .object({ | |
| type: z.literal("search"), | |
| query: z.string().optional(), | |
| }) | |
| .nullish(), | |
| }), | |
| z.object({ | |
| type: z.literal("computer_call"), | |
| id: z.string(), | |
| status: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("file_search_call"), | |
| id: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("image_generation_call"), | |
| id: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("code_interpreter_call"), | |
| id: z.string(), | |
| container_id: z.string(), | |
| code: z.string().nullable(), | |
| outputs: z | |
| .array( | |
| z.discriminatedUnion("type", [ | |
| z.object({ type: z.literal("logs"), logs: z.string() }), | |
| z.object({ type: z.literal("image"), url: z.string() }), | |
| ]), | |
| ) | |
| .nullable(), | |
| status: z.string(), | |
| }), | |
| ]), | |
| }) | |
| const responseOutputItemDoneSchema = z.object({ | |
| type: z.literal("response.output_item.done"), | |
| output_index: z.number(), | |
| item: z.discriminatedUnion("type", [ | |
| z.object({ | |
| type: z.literal("message"), | |
| id: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("reasoning"), | |
| id: z.string(), | |
| encrypted_content: z.string().nullish(), | |
| }), | |
| z.object({ | |
| type: z.literal("function_call"), | |
| id: z.string(), | |
| call_id: z.string(), | |
| name: z.string(), | |
| arguments: z.string(), | |
| status: z.literal("completed"), | |
| }), | |
| codeInterpreterCallItem, | |
| imageGenerationCallItem, | |
| webSearchCallItem, | |
| fileSearchCallItem, | |
| localShellCallItem, | |
| z.object({ | |
| type: z.literal("computer_call"), | |
| id: z.string(), | |
| status: z.literal("completed"), | |
| }), | |
| ]), | |
| }) | |
| const responseFunctionCallArgumentsDeltaSchema = z.object({ | |
| type: z.literal("response.function_call_arguments.delta"), | |
| item_id: z.string(), | |
| output_index: z.number(), | |
| delta: z.string(), | |
| }) | |
| const responseImageGenerationCallPartialImageSchema = z.object({ | |
| type: z.literal("response.image_generation_call.partial_image"), | |
| item_id: z.string(), | |
| output_index: z.number(), | |
| partial_image_b64: z.string(), | |
| }) | |
| const responseCodeInterpreterCallCodeDeltaSchema = z.object({ | |
| type: z.literal("response.code_interpreter_call_code.delta"), | |
| item_id: z.string(), | |
| output_index: z.number(), | |
| delta: z.string(), | |
| }) | |
| const responseCodeInterpreterCallCodeDoneSchema = z.object({ | |
| type: z.literal("response.code_interpreter_call_code.done"), | |
| item_id: z.string(), | |
| output_index: z.number(), | |
| code: z.string(), | |
| }) | |
| const responseAnnotationAddedSchema = z.object({ | |
| type: z.literal("response.output_text.annotation.added"), | |
| annotation: z.discriminatedUnion("type", [ | |
| z.object({ | |
| type: z.literal("url_citation"), | |
| url: z.string(), | |
| title: z.string(), | |
| }), | |
| z.object({ | |
| type: z.literal("file_citation"), | |
| file_id: z.string(), | |
| filename: z.string().nullish(), | |
| index: z.number().nullish(), | |
| start_index: z.number().nullish(), | |
| end_index: z.number().nullish(), | |
| quote: z.string().nullish(), | |
| }), | |
| ]), | |
| }) | |
| const responseReasoningSummaryPartAddedSchema = z.object({ | |
| type: z.literal("response.reasoning_summary_part.added"), | |
| item_id: z.string(), | |
| summary_index: z.number(), | |
| }) | |
| const responseReasoningSummaryTextDeltaSchema = z.object({ | |
| type: z.literal("response.reasoning_summary_text.delta"), | |
| item_id: z.string(), | |
| summary_index: z.number(), | |
| delta: z.string(), | |
| }) | |
| const openaiResponsesChunkSchema = z.union([ | |
| textDeltaChunkSchema, | |
| responseFinishedChunkSchema, | |
| responseCreatedChunkSchema, | |
| responseOutputItemAddedSchema, | |
| responseOutputItemDoneSchema, | |
| responseFunctionCallArgumentsDeltaSchema, | |
| responseImageGenerationCallPartialImageSchema, | |
| responseCodeInterpreterCallCodeDeltaSchema, | |
| responseCodeInterpreterCallCodeDoneSchema, | |
| responseAnnotationAddedSchema, | |
| responseReasoningSummaryPartAddedSchema, | |
| responseReasoningSummaryTextDeltaSchema, | |
| errorChunkSchema, | |
| z.object({ type: z.string() }).loose(), // fallback for unknown chunks | |
| ]) | |
| type ExtractByType<T, K extends T extends { type: infer U } ? U : never> = T extends { type: K } ? T : never | |
| function isTextDeltaChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof textDeltaChunkSchema> { | |
| return chunk.type === "response.output_text.delta" | |
| } | |
| function isResponseOutputItemDoneChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseOutputItemDoneSchema> { | |
| return chunk.type === "response.output_item.done" | |
| } | |
| function isResponseOutputItemDoneReasoningChunk(chunk: z.infer<typeof openaiResponsesChunkSchema>): chunk is z.infer< | |
| typeof responseOutputItemDoneSchema | |
| > & { | |
| item: ExtractByType<z.infer<typeof responseOutputItemDoneSchema>["item"], "reasoning"> | |
| } { | |
| return isResponseOutputItemDoneChunk(chunk) && chunk.item.type === "reasoning" | |
| } | |
| function isResponseFinishedChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseFinishedChunkSchema> { | |
| return chunk.type === "response.completed" || chunk.type === "response.incomplete" | |
| } | |
| function isResponseCreatedChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseCreatedChunkSchema> { | |
| return chunk.type === "response.created" | |
| } | |
| function isResponseFunctionCallArgumentsDeltaChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseFunctionCallArgumentsDeltaSchema> { | |
| return chunk.type === "response.function_call_arguments.delta" | |
| } | |
| function isResponseImageGenerationCallPartialImageChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseImageGenerationCallPartialImageSchema> { | |
| return chunk.type === "response.image_generation_call.partial_image" | |
| } | |
| function isResponseCodeInterpreterCallCodeDeltaChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseCodeInterpreterCallCodeDeltaSchema> { | |
| return chunk.type === "response.code_interpreter_call_code.delta" | |
| } | |
| function isResponseCodeInterpreterCallCodeDoneChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseCodeInterpreterCallCodeDoneSchema> { | |
| return chunk.type === "response.code_interpreter_call_code.done" | |
| } | |
| function isResponseOutputItemAddedChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseOutputItemAddedSchema> { | |
| return chunk.type === "response.output_item.added" | |
| } | |
| function isResponseOutputItemAddedReasoningChunk(chunk: z.infer<typeof openaiResponsesChunkSchema>): chunk is z.infer< | |
| typeof responseOutputItemAddedSchema | |
| > & { | |
| item: ExtractByType<z.infer<typeof responseOutputItemAddedSchema>["item"], "reasoning"> | |
| } { | |
| return isResponseOutputItemAddedChunk(chunk) && chunk.item.type === "reasoning" | |
| } | |
| function isResponseAnnotationAddedChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseAnnotationAddedSchema> { | |
| return chunk.type === "response.output_text.annotation.added" | |
| } | |
| function isResponseReasoningSummaryPartAddedChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseReasoningSummaryPartAddedSchema> { | |
| return chunk.type === "response.reasoning_summary_part.added" | |
| } | |
| function isResponseReasoningSummaryTextDeltaChunk( | |
| chunk: z.infer<typeof openaiResponsesChunkSchema>, | |
| ): chunk is z.infer<typeof responseReasoningSummaryTextDeltaSchema> { | |
| return chunk.type === "response.reasoning_summary_text.delta" | |
| } | |
| function isErrorChunk(chunk: z.infer<typeof openaiResponsesChunkSchema>): chunk is z.infer<typeof errorChunkSchema> { | |
| return chunk.type === "error" | |
| } | |
| type ResponsesModelConfig = { | |
| isReasoningModel: boolean | |
| systemMessageMode: "remove" | "system" | "developer" | |
| requiredAutoTruncation: boolean | |
| supportsFlexProcessing: boolean | |
| supportsPriorityProcessing: boolean | |
| } | |
| function getResponsesModelConfig(modelId: string): ResponsesModelConfig { | |
| const supportsFlexProcessing = | |
| modelId.startsWith("o3") || | |
| modelId.startsWith("o4-mini") || | |
| (modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat")) | |
| const supportsPriorityProcessing = | |
| modelId.startsWith("gpt-4") || | |
| modelId.startsWith("gpt-5-mini") || | |
| (modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-nano") && !modelId.startsWith("gpt-5-chat")) || | |
| modelId.startsWith("o3") || | |
| modelId.startsWith("o4-mini") | |
| const defaults = { | |
| requiredAutoTruncation: false, | |
| systemMessageMode: "system" as const, | |
| supportsFlexProcessing, | |
| supportsPriorityProcessing, | |
| } | |
| // gpt-5-chat models are non-reasoning | |
| if (modelId.startsWith("gpt-5-chat")) { | |
| return { | |
| ...defaults, | |
| isReasoningModel: false, | |
| } | |
| } | |
| // o series reasoning models: | |
| if ( | |
| modelId.startsWith("o") || | |
| modelId.startsWith("gpt-5") || | |
| modelId.startsWith("codex-") || | |
| modelId.startsWith("computer-use") | |
| ) { | |
| if (modelId.startsWith("o1-mini") || modelId.startsWith("o1-preview")) { | |
| return { | |
| ...defaults, | |
| isReasoningModel: true, | |
| systemMessageMode: "remove", | |
| } | |
| } | |
| return { | |
| ...defaults, | |
| isReasoningModel: true, | |
| systemMessageMode: "developer", | |
| } | |
| } | |
| // gpt models: | |
| return { | |
| ...defaults, | |
| isReasoningModel: false, | |
| } | |
| } | |
| // TODO AI SDK 6: use optional here instead of nullish | |
| const openaiResponsesProviderOptionsSchema = z.object({ | |
| include: z | |
| .array(z.enum(["reasoning.encrypted_content", "file_search_call.results", "message.output_text.logprobs"])) | |
| .nullish(), | |
| instructions: z.string().nullish(), | |
| /** | |
| * Return the log probabilities of the tokens. | |
| * | |
| * Setting to true will return the log probabilities of the tokens that | |
| * were generated. | |
| * | |
| * Setting to a number will return the log probabilities of the top n | |
| * tokens that were generated. | |
| * | |
| * @see https://platform.openai.com/docs/api-reference/responses/create | |
| * @see https://cookbook.openai.com/examples/using_logprobs | |
| */ | |
| logprobs: z.union([z.boolean(), z.number().min(1).max(TOP_LOGPROBS_MAX)]).optional(), | |
| /** | |
| * The maximum number of total calls to built-in tools that can be processed in a response. | |
| * This maximum number applies across all built-in tool calls, not per individual tool. | |
| * Any further attempts to call a tool by the model will be ignored. | |
| */ | |
| maxToolCalls: z.number().nullish(), | |
| metadata: z.any().nullish(), | |
| parallelToolCalls: z.boolean().nullish(), | |
| previousResponseId: z.string().nullish(), | |
| promptCacheKey: z.string().nullish(), | |
| reasoningEffort: z.string().nullish(), | |
| reasoningSummary: z.string().nullish(), | |
| safetyIdentifier: z.string().nullish(), | |
| serviceTier: z.enum(["auto", "flex", "priority"]).nullish(), | |
| store: z.boolean().nullish(), | |
| strictJsonSchema: z.boolean().nullish(), | |
| textVerbosity: z.enum(["low", "medium", "high"]).nullish(), | |
| user: z.string().nullish(), | |
| }) | |
| export type OpenAIResponsesProviderOptions = z.infer<typeof openaiResponsesProviderOptionsSchema> | |
Xet Storage Details
- Size:
- 58.7 kB
- Xet hash:
- a5997b7a10ab20834caaf6da6a5985f0b6efeb3bbdf0ab307cc066c25072c821
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.