import { getSystemPrompt, getModelReasoning, getUserAgent } from '../../configs/config.js' export function transformToAnthropic(openaiRequest) { const anthropicRequest = { model: openaiRequest.model, messages: [] }; // 仅在客户端明确提供时添加 stream 参数 if (openaiRequest.stream !== undefined) { anthropicRequest.stream = openaiRequest.stream; } // 处理 max_tokens if (openaiRequest.max_tokens) { anthropicRequest.max_tokens = openaiRequest.max_tokens; } else if (openaiRequest.max_completion_tokens) { anthropicRequest.max_tokens = openaiRequest.max_completion_tokens; } else { anthropicRequest.max_tokens = 64000; } // 提取系统消息并转换其他消息 let systemContent = []; if (openaiRequest.messages && Array.isArray(openaiRequest.messages)) { for (const msg of openaiRequest.messages) { // 单独处理系统消息 if (msg.role === 'system') { if (typeof msg.content === 'string') { systemContent.push({ type: 'text', text: msg.content?.replace("You are Claude Code, Anthropic's official CLI for Claude.", 'you are bot.').replace("You are Claude Code, Anthropic's official CLI for Claude, running within the Claude Agent SDK.", "you are bot.") }); } else if (Array.isArray(msg.content)) { for (const part of msg.content) { if (part.type === 'text') { systemContent.push({ type: 'text', text: part.text?.replace("You are Claude Code, Anthropic's official CLI for Claude.", 'you are bot.').replace("You are Claude Code, Anthropic's official CLI for Claude, running within the Claude Agent SDK.", "you are bot.") }); } else { systemContent.push(part); } } } continue; // 跳过将系统消息添加到消息数组 } const anthropicMsg = { role: msg.role, content: [] }; if (typeof msg.content === 'string') { anthropicMsg.content.push({ type: 'text', text: msg.content }); } else if (Array.isArray(msg.content)) { for (const part of msg.content) { if (part.type === 'text') { anthropicMsg.content.push({ type: 'text', text: part.text }); } else if (part.type === 'image_url') { anthropicMsg.content.push({ type: 'image', source: part.image_url }); } else { anthropicMsg.content.push(part); } } } anthropicRequest.messages.push(anthropicMsg); } } // 添加系统参数,并在前面加上系统提示 const systemPrompt = getSystemPrompt(); if (systemPrompt || systemContent.length > 0) { anthropicRequest.system = []; // 如果存在系统提示,则将其作为第一个元素添加 if (systemPrompt) { anthropicRequest.system.push({ type: 'text', text: systemPrompt }); } // 添加用户提供的系统内容 anthropicRequest.system.push(...systemContent); } // 如果存在工具,则进行转换 if (openaiRequest.tools && Array.isArray(openaiRequest.tools)) { anthropicRequest.tools = openaiRequest.tools.map(tool => { if (tool.type === 'function') { return { name: tool.function.name, description: tool.function.description, input_schema: tool.function.parameters || {} }; } return tool; }); } // 根据模型配置处理 thinking 字段 const reasoningLevel = getModelReasoning(openaiRequest.model); if (reasoningLevel === 'auto') { // 自动模式:完全保留原始请求的 thinking 字段 if (openaiRequest.thinking !== undefined) { anthropicRequest.thinking = openaiRequest.thinking; } // 如果原始请求没有 thinking 字段,则不添加 } else if (reasoningLevel && ['low', 'medium', 'high'].includes(reasoningLevel)) { // 特定级别:使用模型配置覆盖 const budgetTokens = { 'low': 4096, 'medium': 12288, 'high': 24576 }; anthropicRequest.thinking = { type: 'enabled', budget_tokens: budgetTokens[reasoningLevel] }; } else { // 关闭或无效:显式删除 thinking 字段 // 这确保删除原始请求中的任何 thinking 字段 delete anthropicRequest.thinking; } // 传递其他兼容参数 if (openaiRequest.temperature !== undefined) { anthropicRequest.temperature = openaiRequest.temperature; } if (openaiRequest.top_p !== undefined) { anthropicRequest.top_p = openaiRequest.top_p; } if (openaiRequest.stop !== undefined) { anthropicRequest.stop_sequences = Array.isArray(openaiRequest.stop) ? openaiRequest.stop : [openaiRequest.stop]; } return anthropicRequest; } export function getAnthropicHeaders(authHeader, clientHeaders = {}, isStreaming = true, modelId = null) { // 如果未提供则生成唯一 ID const sessionId = clientHeaders['x-session-id'] || generateUUID(); const messageId = clientHeaders['x-assistant-message-id'] || generateUUID(); const headers = { 'accept': 'application/json', 'content-type': 'application/json', 'anthropic-version': clientHeaders['anthropic-version'] || '2023-06-01', 'authorization': authHeader || '', 'x-api-key': 'placeholder', 'x-api-provider': 'anthropic', 'x-factory-client': 'cli', 'x-session-id': sessionId, 'x-assistant-message-id': messageId, 'user-agent': getUserAgent(), 'x-stainless-timeout': '600', 'connection': 'keep-alive' } // 根据推理配置处理 anthropic-beta 头 const reasoningLevel = modelId ? getModelReasoning(modelId) : null; let betaValues = []; // 从客户端头添加现有的 beta 值 if (clientHeaders['anthropic-beta']) { const existingBeta = clientHeaders['anthropic-beta']; betaValues = existingBeta.split(',').map(v => v.trim()); } // 根据推理配置处理 thinking beta const thinkingBeta = 'interleaved-thinking-2025-05-14'; if (reasoningLevel === 'auto') { // 自动模式:不修改 anthropic-beta 头,保留原始值 // betaValues 保持客户端头的不变 } else if (reasoningLevel && ['low', 'medium', 'high'].includes(reasoningLevel)) { // 如果尚未存在,则添加 thinking beta if (!betaValues.includes(thinkingBeta)) { betaValues.push(thinkingBeta); } } else { // 如果推理关闭或无效,则删除 thinking beta betaValues = betaValues.filter(v => v !== thinkingBeta); } // 如果有任何值,则设置 anthropic-beta 头 if (betaValues.length > 0) { headers['anthropic-beta'] = betaValues.join(', '); } // 使用默认值传递 Stainless SDK 头 const stainlessDefaults = { 'x-stainless-arch': 'x64', 'x-stainless-lang': 'js', 'x-stainless-os': 'MacOS', 'x-stainless-runtime': 'node', 'x-stainless-retry-count': '0', 'x-stainless-package-version': '0.57.0', 'x-stainless-runtime-version': 'v24.3.0' }; // 根据流式传输设置 helper-method if (isStreaming) { headers['x-stainless-helper-method'] = 'stream'; } // 从客户端复制 Stainless 头或使用默认值 Object.keys(stainlessDefaults).forEach(header => { headers[header] = clientHeaders[header] || stainlessDefaults[header]; }); // 如果客户端提供,则覆盖默认超时 if (clientHeaders['x-stainless-timeout']) { headers['x-stainless-timeout'] = clientHeaders['x-stainless-timeout']; } return headers; } function generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0; const v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); }