/** * OpenAI Codex API adapter for Claude Code * Provides compatibility layer between Claude's API expectations and OpenAI's Codex API */ import type { Message } from '../types/message.js' import { logError } from './log.js' /** * OpenAI message format for API requests */ interface OpenAIMessage { role: 'system' | 'user' | 'assistant' content: string | Array<{ type: 'text' | 'image_url' text?: string image_url?: { url: string } }> } /** * OpenAI API response format */ interface OpenAIResponse { id: string object: string created: number model: string choices: Array<{ index: number message: { role: string content: string } finish_reason: string }> usage: { prompt_tokens: number completion_tokens: number total_tokens: number } } /** * Convert Claude Code message format to OpenAI format */ function convertToOpenAIMessage(message: Message): OpenAIMessage { if (typeof message.content === 'string') { return { role: message.role === 'human' ? 'user' : message.role as 'system' | 'assistant', content: message.content, } } // Handle multi-modal content const content: Array = [] for (const item of message.content) { if (item.type === 'text') { content.push({ type: 'text', text: item.text, }) } else if (item.type === 'image') { // Convert Anthropic base64 image schema to OpenAI format content.push({ type: 'image_url', image_url: { url: item.source.type === 'base64' ? `data:${item.source.media_type};base64,${item.source.data}` : item.source.data } }) } } return { role: message.role === 'human' ? 'user' : message.role as 'system' | 'assistant', content, } } /** * fetchCodexResponse is disabled: sending conversation content to * api.openai.com would leak user data to a third-party service. * This function is retained as a stub to avoid breaking any call sites. */ export async function fetchCodexResponse( _messages: Message[], _model: string, _options: { apiKey?: string baseUrl?: string stream?: boolean } = {} ): Promise { throw new Error( 'OpenAI Codex API calls are disabled for privacy. External data forwarding has been removed.', ) } /** * Convert OpenAI response to Claude Code format */ export function convertFromOpenAIResponse(response: OpenAIResponse): { content: string usage: { input_tokens: number output_tokens: number } } { const choice = response.choices[0] if (!choice) { throw new Error('No choices in OpenAI response') } return { content: choice.message.content, usage: { input_tokens: response.usage.prompt_tokens, output_tokens: response.usage.completion_tokens, }, } }