Buckets:
GHHG10/CodeServer / opencode /packages /core /src /github-copilot /responses /convert-to-openai-responses-input.ts
| import { | |
| type LanguageModelV3Prompt, | |
| type LanguageModelV3ToolCallPart, | |
| type SharedV3Warning, | |
| UnsupportedFunctionalityError, | |
| } from "@ai-sdk/provider" | |
| import { convertToBase64, parseProviderOptions } from "@ai-sdk/provider-utils" | |
| import { z } from "zod/v4" | |
| import type { OpenAIResponsesInput, OpenAIResponsesReasoning } from "./openai-responses-api-types" | |
| import { localShellInputSchema, localShellOutputSchema } from "./tool/local-shell" | |
| /** | |
| * Check if a string is a file ID based on the given prefixes | |
| * Returns false if prefixes is undefined (disables file ID detection) | |
| */ | |
| function isFileId(data: string, prefixes?: readonly string[]): boolean { | |
| if (!prefixes) return false | |
| return prefixes.some((prefix) => data.startsWith(prefix)) | |
| } | |
| export async function convertToOpenAIResponsesInput({ | |
| prompt, | |
| systemMessageMode, | |
| fileIdPrefixes, | |
| store, | |
| hasLocalShellTool = false, | |
| }: { | |
| prompt: LanguageModelV3Prompt | |
| systemMessageMode: "system" | "developer" | "remove" | |
| fileIdPrefixes?: readonly string[] | |
| store: boolean | |
| hasLocalShellTool?: boolean | |
| }): Promise<{ | |
| input: OpenAIResponsesInput | |
| warnings: Array<SharedV3Warning> | |
| }> { | |
| const input: OpenAIResponsesInput = [] | |
| const warnings: Array<SharedV3Warning> = [] | |
| const processedApprovalIds = new Set<string>() | |
| for (const { role, content } of prompt) { | |
| switch (role) { | |
| case "system": { | |
| switch (systemMessageMode) { | |
| case "system": { | |
| input.push({ role: "system", content }) | |
| break | |
| } | |
| case "developer": { | |
| input.push({ role: "developer", content }) | |
| break | |
| } | |
| case "remove": { | |
| warnings.push({ | |
| type: "other", | |
| message: "system messages are removed for this model", | |
| }) | |
| break | |
| } | |
| default: { | |
| const _exhaustiveCheck: never = systemMessageMode | |
| throw new Error(`Unsupported system message mode: ${_exhaustiveCheck}`) | |
| } | |
| } | |
| break | |
| } | |
| case "user": { | |
| input.push({ | |
| role: "user", | |
| content: content.map((part, index) => { | |
| switch (part.type) { | |
| case "text": { | |
| return { type: "input_text", text: part.text } | |
| } | |
| case "file": { | |
| if (part.mediaType.startsWith("image/")) { | |
| const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType | |
| return { | |
| type: "input_image", | |
| ...(part.data instanceof URL | |
| ? { image_url: part.data.toString() } | |
| : typeof part.data === "string" && isFileId(part.data, fileIdPrefixes) | |
| ? { file_id: part.data } | |
| : { | |
| image_url: `data:${mediaType};base64,${convertToBase64(part.data)}`, | |
| }), | |
| detail: part.providerOptions?.openai?.imageDetail, | |
| } | |
| } else if (part.mediaType === "application/pdf") { | |
| if (part.data instanceof URL) { | |
| return { | |
| type: "input_file", | |
| file_url: part.data.toString(), | |
| } | |
| } | |
| return { | |
| type: "input_file", | |
| ...(typeof part.data === "string" && isFileId(part.data, fileIdPrefixes) | |
| ? { file_id: part.data } | |
| : { | |
| filename: part.filename ?? `part-${index}.pdf`, | |
| file_data: `data:application/pdf;base64,${convertToBase64(part.data)}`, | |
| }), | |
| } | |
| } else { | |
| throw new UnsupportedFunctionalityError({ | |
| functionality: `file part media type ${part.mediaType}`, | |
| }) | |
| } | |
| } | |
| } | |
| }), | |
| }) | |
| break | |
| } | |
| case "assistant": { | |
| const reasoningMessages: Record<string, OpenAIResponsesReasoning> = {} | |
| const toolCallParts: Record<string, LanguageModelV3ToolCallPart> = {} | |
| for (const part of content) { | |
| switch (part.type) { | |
| case "text": { | |
| input.push({ | |
| role: "assistant", | |
| content: [{ type: "output_text", text: part.text }], | |
| id: (part.providerOptions?.openai?.itemId as string) ?? undefined, | |
| }) | |
| break | |
| } | |
| case "tool-call": { | |
| toolCallParts[part.toolCallId] = part | |
| if (part.providerExecuted) { | |
| break | |
| } | |
| if (hasLocalShellTool && part.toolName === "local_shell") { | |
| const parsedInput = localShellInputSchema.parse(part.input) | |
| input.push({ | |
| type: "local_shell_call", | |
| call_id: part.toolCallId, | |
| id: (part.providerOptions?.openai?.itemId as string) ?? undefined, | |
| action: { | |
| type: "exec", | |
| command: parsedInput.action.command, | |
| timeout_ms: parsedInput.action.timeoutMs, | |
| user: parsedInput.action.user, | |
| working_directory: parsedInput.action.workingDirectory, | |
| env: parsedInput.action.env, | |
| }, | |
| }) | |
| break | |
| } | |
| input.push({ | |
| type: "function_call", | |
| call_id: part.toolCallId, | |
| name: part.toolName, | |
| arguments: JSON.stringify(part.input), | |
| id: (part.providerOptions?.openai?.itemId as string) ?? undefined, | |
| }) | |
| break | |
| } | |
| // assistant tool result parts are from provider-executed tools: | |
| case "tool-result": { | |
| if (store) { | |
| // use item references to refer to tool results from built-in tools | |
| input.push({ type: "item_reference", id: part.toolCallId }) | |
| } else { | |
| warnings.push({ | |
| type: "other", | |
| message: `Results for OpenAI tool ${part.toolName} are not sent to the API when store is false`, | |
| }) | |
| } | |
| break | |
| } | |
| case "reasoning": { | |
| const providerOptions = await parseProviderOptions({ | |
| provider: "copilot", | |
| providerOptions: part.providerOptions, | |
| schema: openaiResponsesReasoningProviderOptionsSchema, | |
| }) | |
| const reasoningId = providerOptions?.itemId | |
| if (reasoningId != null) { | |
| const reasoningMessage = reasoningMessages[reasoningId] | |
| if (store) { | |
| if (reasoningMessage === undefined) { | |
| // use item references to refer to reasoning (single reference) | |
| input.push({ type: "item_reference", id: reasoningId }) | |
| // store unused reasoning message to mark id as used | |
| reasoningMessages[reasoningId] = { | |
| type: "reasoning", | |
| id: reasoningId, | |
| summary: [], | |
| } | |
| } | |
| } else { | |
| const summaryParts: Array<{ | |
| type: "summary_text" | |
| text: string | |
| }> = [] | |
| if (part.text.length > 0) { | |
| summaryParts.push({ | |
| type: "summary_text", | |
| text: part.text, | |
| }) | |
| } else if (reasoningMessage !== undefined) { | |
| warnings.push({ | |
| type: "other", | |
| message: `Cannot append empty reasoning part to existing reasoning sequence. Skipping reasoning part: ${JSON.stringify(part)}.`, | |
| }) | |
| } | |
| if (reasoningMessage === undefined) { | |
| reasoningMessages[reasoningId] = { | |
| type: "reasoning", | |
| id: reasoningId, | |
| encrypted_content: providerOptions?.reasoningEncryptedContent, | |
| summary: summaryParts, | |
| } | |
| input.push(reasoningMessages[reasoningId]) | |
| } else { | |
| reasoningMessage.summary.push(...summaryParts) | |
| } | |
| } | |
| } else { | |
| warnings.push({ | |
| type: "other", | |
| message: `Non-OpenAI reasoning parts are not supported. Skipping reasoning part: ${JSON.stringify(part)}.`, | |
| }) | |
| } | |
| break | |
| } | |
| } | |
| } | |
| break | |
| } | |
| case "tool": { | |
| for (const part of content) { | |
| if (part.type === "tool-approval-response") { | |
| if (processedApprovalIds.has(part.approvalId)) { | |
| continue | |
| } | |
| processedApprovalIds.add(part.approvalId) | |
| if (store) { | |
| input.push({ | |
| type: "item_reference", | |
| id: part.approvalId, | |
| }) | |
| } | |
| input.push({ | |
| type: "mcp_approval_response", | |
| approval_request_id: part.approvalId, | |
| approve: part.approved, | |
| }) | |
| continue | |
| } | |
| const output = part.output | |
| if (output.type === "execution-denied") { | |
| const approvalId = (output.providerOptions?.openai as { approvalId?: string } | undefined)?.approvalId | |
| if (approvalId) { | |
| continue | |
| } | |
| } | |
| if (hasLocalShellTool && part.toolName === "local_shell" && output.type === "json") { | |
| input.push({ | |
| type: "local_shell_call_output", | |
| call_id: part.toolCallId, | |
| output: localShellOutputSchema.parse(output.value).output, | |
| }) | |
| break | |
| } | |
| let contentValue: string | |
| switch (output.type) { | |
| case "text": | |
| case "error-text": | |
| contentValue = output.value | |
| break | |
| case "execution-denied": | |
| contentValue = output.reason ?? "Tool execution denied." | |
| break | |
| case "content": | |
| case "json": | |
| case "error-json": | |
| contentValue = JSON.stringify(output.value) | |
| break | |
| } | |
| input.push({ | |
| type: "function_call_output", | |
| call_id: part.toolCallId, | |
| output: contentValue, | |
| }) | |
| } | |
| break | |
| } | |
| default: { | |
| const _exhaustiveCheck: never = role | |
| throw new Error(`Unsupported role: ${_exhaustiveCheck}`) | |
| } | |
| } | |
| } | |
| return { input, warnings } | |
| } | |
| const openaiResponsesReasoningProviderOptionsSchema = z.object({ | |
| itemId: z.string().nullish(), | |
| reasoningEncryptedContent: z.string().nullish(), | |
| }) | |
| export type OpenAIResponsesReasoningProviderOptions = z.infer<typeof openaiResponsesReasoningProviderOptionsSchema> | |
Xet Storage Details
- Size:
- 11.4 kB
- Xet hash:
- 785492b440b0837394c7095e2d135430f11b406362d595a78cce62fe916bb32c
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.