import { ProviderStrategy } from '../provider-strategy.js'; import { extractSystemPromptFromRequestBody, MODEL_PROTOCOL_PREFIX } from '../common.js'; /** * OpenAI Responses API strategy implementation. * Migrated from Chat Completions API to Responses API. */ class ResponsesAPIStrategy extends ProviderStrategy { extractModelAndStreamInfo(req, requestBody) { const model = requestBody.model; const isStream = requestBody.stream === true; return { model, isStream }; } extractResponseText(response) { if (!response.output) { return ''; } // In Responses API, output is an array of items for (const item of response.output) { if (item.type === 'message' && item.content && item.content.length > 0) { for (const content of item.content) { if (content.type === 'output_text' && content.text) { return content.text; } } } } return ''; } extractPromptText(requestBody) { // In Responses API, input can be a string or array of items if (typeof requestBody.input === 'string') { return requestBody.input; } else if (Array.isArray(requestBody.input)) { // If input is an array of items/messages, get the last user content const userInputItems = requestBody.input.filter(item => (item.role && item.role === 'user') || (item.type && item.type === 'message' && item.role === 'user') || (item.type && item.type === 'user') ); if (userInputItems.length > 0) { const lastInput = userInputItems[userInputItems.length - 1]; if (typeof lastInput.content === 'string') { return lastInput.content; } else if (Array.isArray(lastInput.content)) { return lastInput.content.map(item => item.text || item.content || '').join('\n'); } } } return ''; } async applySystemPromptFromFile(config, requestBody) { if (!config.SYSTEM_PROMPT_FILE_PATH) { return requestBody; } const filePromptContent = config.SYSTEM_PROMPT_CONTENT; if (filePromptContent === null) { return requestBody; } // In Responses API, system instructions are typically passed in 'instructions' field // or in the input array with role: 'system' requestBody.instructions = requestBody.instructions || filePromptContent; // If using instructions field is not desired, append to input array instead if (!requestBody.instructions || config.SYSTEM_PROMPT_MODE === 'append') { if (typeof requestBody.input === 'string') { // Convert to array format to add system message requestBody.input = [ { role: 'system', content: filePromptContent }, { role: 'user', content: requestBody.input } ]; } else if (Array.isArray(requestBody.input)) { // Check if system message already exists const systemMessageIndex = requestBody.input.findIndex(m => m.role === 'system' || (m.type && m.type === 'system') ); if (systemMessageIndex !== -1) { requestBody.input[systemMessageIndex].content = filePromptContent; } else { requestBody.input.unshift({ role: 'system', content: filePromptContent }); } } else { // If input is not defined, initialize with system message requestBody.input = [{ role: 'system', content: filePromptContent }]; } } else if (requestBody.instructions) { // If system prompt mode is not append, then replace the instructions requestBody.instructions = filePromptContent; } console.log(`[System Prompt] Applied system prompt from ${config.SYSTEM_PROMPT_FILE_PATH} in '${config.SYSTEM_PROMPT_MODE}' mode for provider 'responses'.`); return requestBody; } async manageSystemPrompt(requestBody) { // For Responses API, we may extract instructions or system messages from input let incomingSystemText = ''; if (requestBody.instructions) { incomingSystemText = requestBody.instructions; } else if (Array.isArray(requestBody.input)) { const systemMessage = requestBody.input.find(item => item.role === 'system' || (item.type && item.type === 'system') ); if (systemMessage && systemMessage.content) { incomingSystemText = systemMessage.content; } } await this._updateSystemPromptFile(incomingSystemText, MODEL_PROTOCOL_PREFIX.OPENAI); } } export { ResponsesAPIStrategy };