diff --git a/auth.js b/auth.js index 4216863..fed0395 100644 --- a/auth.js +++ b/auth.js @@ -239,26 +239,34 @@ function shouldRefresh() { export async function initializeAuth() { try { const authConfig = loadAuthConfig(); - + if (authConfig.type === 'factory_key') { // Using fixed FACTORY_API_KEY, no refresh needed logInfo('Auth system initialized with fixed API key'); } else if (authConfig.type === 'refresh') { // Using refresh token mechanism currentRefreshToken = authConfig.value; - - // Always refresh on startup to get fresh token - await refreshApiKey(); - logInfo('Auth system initialized with refresh token mechanism'); + + // Try to refresh on startup to get fresh token + try { + await refreshApiKey(); + logInfo('Auth system initialized with refresh token mechanism'); + } catch (refreshError) { + logError('Failed to refresh token on startup, falling back to client authorization', refreshError); + authSource = 'client'; + logInfo('Auth system fallback to client authorization mode'); + } } else { // Using client authorization, no setup needed logInfo('Auth system initialized for client authorization mode'); } - + logInfo('Auth system initialized successfully'); } catch (error) { logError('Failed to initialize auth system', error); - throw error; + // Don't throw error, allow server to start with client authorization + authSource = 'client'; + logInfo('Auth system fallback to client authorization mode'); } } diff --git a/config.json b/config.json index f7d3726..602c392 100644 --- a/config.json +++ b/config.json @@ -91,7 +91,7 @@ "provider": "google" } ], - "dev_mode": false, + "dev_mode": true, "user_agent": "factory-cli/0.27.1", "system_prompt": "You are Droid, an AI software engineering agent built by Factory.\n\n" } \ No newline at end of file diff --git a/routes.js b/routes.js index 5b1a33e..8f7d5ac 100644 --- a/routes.js +++ b/routes.js @@ -322,6 +322,29 @@ async function handleDirectResponses(req, res) { delete modifiedRequest.reasoning; } + // 删除 claude-cli 特有字段,避免 Factory API 返回 403 + delete modifiedRequest.context_management; + + // 过滤 Claude Code 特有的 MCP 工具 + if (modifiedRequest.tools && Array.isArray(modifiedRequest.tools)) { + modifiedRequest.tools = modifiedRequest.tools.filter(tool => { + if (!tool.name) return true; + // 过滤 Claude Code 特有工具 + const claudeCodeTools = [ + 'Skill', + 'EnterPlanMode', + 'ExitPlanMode', + 'AskUserQuestion', + 'TodoWrite' + ]; + if (claudeCodeTools.includes(tool.name)) return false; + // 过滤所有 mcp__ 开头的工具和 MCP 相关工具 + return !tool.name.startsWith('mcp__') && + !tool.name.includes('Mcp') && + !tool.name.includes('MCP'); + }); + } + logRequest('POST', endpoint.base_url, headers, modifiedRequest); // 转发修改后的请求 @@ -458,6 +481,25 @@ async function handleDirectMessages(req, res) { } } + // 将 Claude Code 格式转换为 Droid 格式 (修复 403 错误) + if (modifiedRequest.system && Array.isArray(modifiedRequest.system)) { + modifiedRequest.system = modifiedRequest.system.map((item, index) => { + // 删除 system[1] 的 cache_control (如果存在) + if (index === 1 && item.cache_control) { + const newItem = { ...item }; + delete newItem.cache_control; + + // 将 "Claude Code" 替换为 "Claude" + if (newItem.text && newItem.text.includes('Claude Code')) { + newItem.text = newItem.text.replace(/Claude Code/g, 'Claude'); + } + + return newItem; + } + return item; + }); + } + // 处理thinking字段 const reasoningLevel = getModelReasoning(modelId); if (reasoningLevel === 'auto') { @@ -480,6 +522,57 @@ async function handleDirectMessages(req, res) { delete modifiedRequest.thinking; } + // 过滤 messages 中的 Claude Code 特有标识 + if (modifiedRequest.messages && Array.isArray(modifiedRequest.messages)) { + modifiedRequest.messages = modifiedRequest.messages.map(msg => { + if (msg.content && Array.isArray(msg.content)) { + msg.content = msg.content.filter(item => { + if (item.type === 'text' && item.text) { + // 过滤包含 Claude Code 特征的内容 + const claudeCodePatterns = [ + '', + '# claudeMd', + '/Users/', + '/.claude/', + 'CLAUDE.md', + '', + '', + '', + 'CodeX MCP', + 'codex MCP' + ]; + return !claudeCodePatterns.some(pattern => item.text.includes(pattern)); + } + return true; + }); + } + return msg; + }); + } + + // 删除 claude-cli 特有字段,避免 Factory API 返回 403 + delete modifiedRequest.context_management; + + // 过滤 Claude Code 特有的 MCP 工具 + if (modifiedRequest.tools && Array.isArray(modifiedRequest.tools)) { + modifiedRequest.tools = modifiedRequest.tools.filter(tool => { + if (!tool.name) return true; + // 过滤 Claude Code 特有工具 + const claudeCodeTools = [ + 'Skill', + 'EnterPlanMode', + 'ExitPlanMode', + 'AskUserQuestion', + 'TodoWrite' + ]; + if (claudeCodeTools.includes(tool.name)) return false; + // 过滤所有 mcp__ 开头的工具和 MCP 相关工具 + return !tool.name.startsWith('mcp__') && + !tool.name.includes('Mcp') && + !tool.name.includes('MCP'); + }); + } + logRequest('POST', endpoint.base_url, headers, modifiedRequest); // 转发修改后的请求 diff --git a/transformers/request-anthropic.js b/transformers/request-anthropic.js index 108b1f4..cf970a4 100644 --- a/transformers/request-anthropic.js +++ b/transformers/request-anthropic.js @@ -178,13 +178,17 @@ export function getAnthropicHeaders(authHeader, clientHeaders = {}, isStreaming // Handle anthropic-beta header based on reasoning configuration const reasoningLevel = modelId ? getModelReasoning(modelId) : null; let betaValues = []; - + // Add existing beta values from client headers if (clientHeaders['anthropic-beta']) { const existingBeta = clientHeaders['anthropic-beta']; betaValues = existingBeta.split(',').map(v => v.trim()); } - + + // Filter out Claude Code specific beta values to avoid 403 + const claudeCodeBetas = ['claude-code-20250219', 'context-management-2025-06-27']; + betaValues = betaValues.filter(v => !claudeCodeBetas.includes(v)); + // Handle thinking beta based on reasoning configuration const thinkingBeta = 'interleaved-thinking-2025-05-14'; if (reasoningLevel === 'auto') { @@ -199,7 +203,7 @@ export function getAnthropicHeaders(authHeader, clientHeaders = {}, isStreaming // Remove thinking beta if reasoning is off/invalid betaValues = betaValues.filter(v => v !== thinkingBeta); } - + // Set anthropic-beta header if there are any values if (betaValues.length > 0) { headers['anthropic-beta'] = betaValues.join(', ');