diff --git a/cloud/src/handlers/chat.js b/cloud/src/handlers/chat.js index 0b4a206d..a6b8e4d5 100644 --- a/cloud/src/handlers/chat.js +++ b/cloud/src/handlers/chat.js @@ -3,7 +3,7 @@ import { handleChatCore } from "open-sse/handlers/chatCore.js"; import { errorResponse } from "open-sse/utils/error.js"; import { checkFallbackError, isAccountUnavailable, getUnavailableUntil, getEarliestRateLimitedUntil, formatRetryAfter } from "open-sse/services/accountFallback.js"; import { getComboModelsFromData, handleComboChat } from "open-sse/services/combo.js"; -import { HTTP_STATUS } from "open-sse/config/constants.js"; +import { HTTP_STATUS } from "open-sse/config/runtimeConfig.js"; import * as log from "../utils/logger.js"; import { refreshTokenByProvider } from "../services/tokenRefresh.js"; import { parseApiKey, extractBearerToken } from "../utils/apiKey.js"; diff --git a/cloud/src/handlers/embeddings.js b/cloud/src/handlers/embeddings.js index 52d86be0..41a91080 100644 --- a/cloud/src/handlers/embeddings.js +++ b/cloud/src/handlers/embeddings.js @@ -8,7 +8,7 @@ import { getUnavailableUntil, formatRetryAfter } from "open-sse/services/accountFallback.js"; -import { HTTP_STATUS } from "open-sse/config/constants.js"; +import { HTTP_STATUS } from "open-sse/config/runtimeConfig.js"; import * as log from "../utils/logger.js"; import { parseApiKey, extractBearerToken } from "../utils/apiKey.js"; import { getMachineData, saveMachineData } from "../services/storage.js"; diff --git a/open-sse/config/appConstants.js b/open-sse/config/appConstants.js new file mode 100644 index 00000000..e9609d37 --- /dev/null +++ b/open-sse/config/appConstants.js @@ -0,0 +1,133 @@ +import { platform, arch } from "os"; + +// === Gemini CLI === +export const GEMINI_CLI_VERSION = "0.31.0"; +export const GEMINI_CLI_API_CLIENT = "google-genai-sdk/1.41.0 gl-node/v22.19.0"; + +export function geminiCLIUserAgent(model = "unknown") { + const os = platform() === "win32" ? "windows" : platform(); + return `GeminiCLI/${GEMINI_CLI_VERSION}/${model || "unknown"} (${os}; ${arch()})`; +} + +// === GitHub Copilot === +export const GITHUB_COPILOT = { + VSCODE_VERSION: "1.110.0", + COPILOT_CHAT_VERSION: "0.38.0", + USER_AGENT: "GitHubCopilotChat/0.38.0", + API_VERSION: "2025-04-01", +}; + +// === Antigravity enums === +export const IDE_TYPE = { + UNSPECIFIED: 0, + JETSKI: 10, + ANTIGRAVITY: 9, + PLUGINS: 7 +}; + +export const PLATFORM = { + UNSPECIFIED: 0, + DARWIN_AMD64: 1, + DARWIN_ARM64: 2, + LINUX_AMD64: 3, + LINUX_ARM64: 4, + WINDOWS_AMD64: 5 +}; + +export const PLUGIN_TYPE = { + UNSPECIFIED: 0, + CLOUD_CODE: 1, + GEMINI: 2 +}; + +export function getPlatformEnum() { + const os = platform(); + const architecture = arch(); + if (os === "darwin") return architecture === "arm64" ? PLATFORM.DARWIN_ARM64 : PLATFORM.DARWIN_AMD64; + if (os === "linux") return architecture === "arm64" ? PLATFORM.LINUX_ARM64 : PLATFORM.LINUX_AMD64; + if (os === "win32") return PLATFORM.WINDOWS_AMD64; + return PLATFORM.UNSPECIFIED; +} + +export function getPlatformUserAgent() { + return `antigravity/1.104.0 ${platform()}/${arch()}`; +} + +export const CLIENT_METADATA = { + ideType: IDE_TYPE.ANTIGRAVITY, + platform: getPlatformEnum(), + pluginType: PLUGIN_TYPE.GEMINI +}; + +// Internal anti-loop header +export const INTERNAL_REQUEST_HEADER = { name: "x-request-source", value: "local" }; + +// Antigravity chat/stream headers +export const ANTIGRAVITY_HEADERS = { + "X-Client-Name": "antigravity", + "X-Client-Version": "1.107.0", + "x-goog-api-client": "gl-node/18.18.2 fire/0.8.6 grpc/1.10.x", + "User-Agent": "antigravity/1.107.0 darwin/arm64" +}; + +// Cloud Code Assist API +export const CLOUD_CODE_API = { + loadCodeAssist: "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist", + onboardUser: "https://cloudcode-pa.googleapis.com/v1internal:onboardUser", +}; + +export const LOAD_CODE_ASSIST_HEADERS = { + "Content-Type": "application/json", + "User-Agent": "google-api-nodejs-client/9.15.1", + "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1", + "Client-Metadata": JSON.stringify({ ideType: "IDE_UNSPECIFIED", platform: "PLATFORM_UNSPECIFIED", pluginType: "GEMINI" }), +}; + +export const LOAD_CODE_ASSIST_METADATA = { + ideType: "IDE_UNSPECIFIED", + platform: "PLATFORM_UNSPECIFIED", + pluginType: "GEMINI", +}; + +// System prompts +export const CLAUDE_SYSTEM_PROMPT = "You are a Claude agent, built on Anthropic's Claude Agent SDK."; +export const ANTIGRAVITY_DEFAULT_SYSTEM = "You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Absolute paths only****Proactiveness**"; + +// OAuth endpoints +export const OAUTH_ENDPOINTS = { + google: { + token: "https://oauth2.googleapis.com/token", + auth: "https://accounts.google.com/o/oauth2/auth" + }, + openai: { + token: "https://auth.openai.com/oauth/token", + auth: "https://auth.openai.com/oauth/authorize" + }, + anthropic: { + token: "https://api.anthropic.com/v1/oauth/token", + auth: "https://api.anthropic.com/v1/oauth/authorize" + }, + qwen: { + token: "https://chat.qwen.ai/api/v1/oauth2/token", + auth: "https://chat.qwen.ai/api/v1/oauth2/device/code" + }, + iflow: { + token: "https://iflow.cn/oauth/token", + auth: "https://iflow.cn/oauth" + }, + github: { + token: "https://github.com/login/oauth/access_token", + auth: "https://github.com/login/oauth/authorize", + deviceCode: "https://github.com/login/device/code" + } +}; + +// Generate Kimi OAuth custom headers +export function buildKimiHeaders() { + return { + "X-Msh-Platform": "9router", + "X-Msh-Version": "2.1.2", + "X-Msh-Device-Model": typeof process !== "undefined" ? `${process.platform} ${process.arch}` : "unknown", + "X-Msh-Device-Id": `kimi-${Date.now()}` + }; +} diff --git a/open-sse/config/constants.js b/open-sse/config/constants.js index 70face1d..7607376d 100644 --- a/open-sse/config/constants.js +++ b/open-sse/config/constants.js @@ -1,593 +1,4 @@ -import { platform, arch } from "os"; - -function mapStainlessOs() { - switch (platform()) { - case "darwin": return "MacOS"; - case "win32": return "Windows"; - case "linux": return "Linux"; - case "freebsd": return "FreeBSD"; - default: return `Other::${platform()}`; - } -} - -function mapStainlessArch() { - switch (arch()) { - case "x64": return "x64"; - case "arm64": return "arm64"; - case "ia32": return "x86"; - default: return `other::${arch()}`; - } -} - -// === Gemini CLI Version Constants === -export const GEMINI_CLI_VERSION = "0.31.0"; -export const GEMINI_CLI_API_CLIENT = "google-genai-sdk/1.41.0 gl-node/v22.19.0"; - -function mapGeminiCLIOs() { - switch (platform()) { - case "darwin": return "darwin"; - case "win32": return "windows"; - case "linux": return "linux"; - case "freebsd": return "freebsd"; - default: return platform(); - } -} - -function mapGeminiCLIArch() { - switch (arch()) { - case "x64": return "x64"; - case "arm64": return "arm64"; - case "ia32": return "x86"; - default: return arch(); - } -} - -/** Returns User-Agent matching native Gemini CLI format: GeminiCLI// (; ) */ -export function geminiCLIUserAgent(model = "unknown") { - return `GeminiCLI/${GEMINI_CLI_VERSION}/${model || "unknown"} (${mapGeminiCLIOs()}; ${mapGeminiCLIArch()})`; -} - -// === GitHub Copilot Version Constants === -export const GITHUB_COPILOT = { - VSCODE_VERSION: "1.110.0", - COPILOT_CHAT_VERSION: "0.38.0", - USER_AGENT: "GitHubCopilotChat/0.38.0", - API_VERSION: "2025-04-01", -}; - -// === Antigravity Binary Alignment: Numeric Enums === -// Reference: Antigravity binary analysis - google.internal.cloud.code.v1internal.ClientMetadata - -// IDE Type enum (numeric values as expected by Cloud Code API) -export const IDE_TYPE = { - UNSPECIFIED: 0, - JETSKI: 10, // Internal codename for Gemini CLI - ANTIGRAVITY: 9, - PLUGINS: 7 -}; - -// Platform enum (as specified in Antigravity binary) -export const PLATFORM = { - UNSPECIFIED: 0, - DARWIN_AMD64: 1, - DARWIN_ARM64: 2, - LINUX_AMD64: 3, - LINUX_ARM64: 4, - WINDOWS_AMD64: 5 -}; - -// Plugin type enum (as specified in Antigravity binary) -export const PLUGIN_TYPE = { - UNSPECIFIED: 0, - CLOUD_CODE: 1, - GEMINI: 2 -}; - -/** - * Get the platform enum value based on the current OS. - * @returns {number} Platform enum value - */ -export function getPlatformEnum() { - const os = platform(); - const architecture = arch(); - - if (os === "darwin") { - return architecture === "arm64" ? PLATFORM.DARWIN_ARM64 : PLATFORM.DARWIN_AMD64; - } else if (os === "linux") { - return architecture === "arm64" ? PLATFORM.LINUX_ARM64 : PLATFORM.LINUX_AMD64; - } else if (os === "win32") { - return PLATFORM.WINDOWS_AMD64; - } - return PLATFORM.UNSPECIFIED; -} - -/** - * Generate platform-specific User-Agent string. - * @returns {string} User-Agent in format "antigravity/version os/arch" - */ -export function getPlatformUserAgent() { - const os = platform(); - const architecture = arch(); - return `antigravity/1.104.0 ${os}/${architecture}`; -} - -// Centralized client metadata (used in request bodies for loadCodeAssist, onboardUser, etc.) -// Using numeric enum values as expected by the Cloud Code API -export const CLIENT_METADATA = { - ideType: IDE_TYPE.ANTIGRAVITY, // 9 - identifies as Antigravity client - platform: getPlatformEnum(), // Runtime platform detection - pluginType: PLUGIN_TYPE.GEMINI // 2 -}; - -// Internal anti-loop header to identify requests originating from this proxy -export const INTERNAL_REQUEST_HEADER = { name: "x-request-source", value: "local" }; - -// Antigravity headers (for chat/stream requests) -export const ANTIGRAVITY_HEADERS = { - "X-Client-Name": "antigravity", - "X-Client-Version": "1.107.0", - "x-goog-api-client": "gl-node/18.18.2 fire/0.8.6 grpc/1.10.x", - "User-Agent": "antigravity/1.107.0 darwin/arm64" -}; - -// Cloud Code Assist API endpoints (for Project ID discovery) -export const CLOUD_CODE_API = { - loadCodeAssist: "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist", - onboardUser: "https://cloudcode-pa.googleapis.com/v1internal:onboardUser", -}; - -// Headers for loadCodeAssist / onboardUser API calls (matches CLIProxyAPI Go source) -export const LOAD_CODE_ASSIST_HEADERS = { - "Content-Type": "application/json", - "User-Agent": "google-api-nodejs-client/9.15.1", - "X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1", - "Client-Metadata": JSON.stringify({ ideType: "IDE_UNSPECIFIED", platform: "PLATFORM_UNSPECIFIED", pluginType: "GEMINI" }), -}; - -// Metadata body for loadCodeAssist / onboardUser (string enum, matches CLIProxyAPI Go source) -export const LOAD_CODE_ASSIST_METADATA = { - ideType: "IDE_UNSPECIFIED", - platform: "PLATFORM_UNSPECIFIED", - pluginType: "GEMINI", -}; - -// Provider configurations -export const PROVIDERS = { - claude: { - baseUrl: "https://api.anthropic.com/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05", - "Anthropic-Dangerous-Direct-Browser-Access": "true", - "User-Agent": "claude-cli/2.1.63 (external, cli)", - "X-App": "cli", - "X-Stainless-Helper-Method": "stream", - "X-Stainless-Retry-Count": "0", - "X-Stainless-Runtime-Version": "v24.3.0", - "X-Stainless-Package-Version": "0.74.0", - "X-Stainless-Runtime": "node", - "X-Stainless-Lang": "js", - "X-Stainless-Arch": mapStainlessArch(), - "X-Stainless-Os": mapStainlessOs(), - "X-Stainless-Timeout": "600" - }, - // Claude OAuth configuration - clientId: "9d1c250a-e61b-44d9-88ed-5944d1962f5e", - tokenUrl: "https://api.anthropic.com/v1/oauth/token" - }, - gemini: { - baseUrl: "https://generativelanguage.googleapis.com/v1beta/models", - format: "gemini", - clientId: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com", - clientSecret: "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" - }, - "gemini-cli": { - baseUrl: "https://cloudcode-pa.googleapis.com/v1internal", - format: "gemini-cli", - clientId: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com", - clientSecret: "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" - }, - codex: { - baseUrl: "https://chatgpt.com/backend-api/codex/responses", - format: "openai-responses", // Use OpenAI Responses API format (reuse translator) - headers: { - "originator": "codex-cli", - "User-Agent": "codex-cli/1.0.18 (macOS; arm64)" - }, - // OpenAI OAuth configuration - clientId: "app_EMoamEEZ73f0CkXaXp7hrann", - clientSecret: "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", - tokenUrl: "https://auth.openai.com/oauth/token" - }, - qwen: { - baseUrl: "https://portal.qwen.ai/v1/chat/completions", - format: "openai", - headers: { - "User-Agent": "google-api-nodejs-client/9.15.1", - "X-Goog-Api-Client": "gl-node/22.17.0" - }, - // Qwen OAuth configuration - clientId: "f0304373b74a44d2b584a3fb70ca9e56", // From CLIProxyAPI - tokenUrl: "https://chat.qwen.ai/api/v1/oauth2/token", - authUrl: "https://chat.qwen.ai/api/v1/oauth2/device/code" - }, - iflow: { - baseUrl: "https://apis.iflow.cn/v1/chat/completions", - format: "openai", - headers: { - "User-Agent": "iFlow-Cli" - }, - // iFlow OAuth configuration (from CLIProxyAPI) - clientId: "10009311001", - clientSecret: "4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW", - tokenUrl: "https://iflow.cn/oauth/token", - authUrl: "https://iflow.cn/oauth" - }, - antigravity: { - baseUrls: [ - "https://daily-cloudcode-pa.googleapis.com", - "https://cloudcode-pa.googleapis.com", - ], - format: "antigravity", - headers: { - "User-Agent": getPlatformUserAgent() - }, - clientId: "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com", - clientSecret: "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" - }, - openrouter: { - baseUrl: "https://openrouter.ai/api/v1/chat/completions", - format: "openai", - headers: { - "HTTP-Referer": "https://endpoint-proxy.local", - "X-Title": "Endpoint Proxy" - } - }, - openai: { - baseUrl: "https://api.openai.com/v1/chat/completions", - format: "openai" - }, - glm: { - baseUrl: "https://api.z.ai/api/anthropic/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" - } - }, - "glm-cn": { - baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4/chat/completions", - format: "openai", - headers: {} - }, - kimi: { - baseUrl: "https://api.kimi.com/coding/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" - } - }, - minimax: { - baseUrl: "https://api.minimax.io/anthropic/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" - } - }, - "minimax-cn": { - baseUrl: "https://api.minimaxi.com/anthropic/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" - } - }, - alicode: { - baseUrl: "https://coding.dashscope.aliyuncs.com/v1/chat/completions", - format: "openai", - headers: {} - }, - "alicode-intl": { - baseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions", - format: "openai", - headers: {} - }, - github: { - baseUrl: "https://api.githubcopilot.com/chat/completions", // GitHub Copilot API endpoint for chat - responsesUrl: "https://api.githubcopilot.com/responses", - format: "openai", // GitHub Copilot uses OpenAI-compatible format - headers: { - "copilot-integration-id": "vscode-chat", - "editor-version": `vscode/${GITHUB_COPILOT.VSCODE_VERSION}`, - "editor-plugin-version": `copilot-chat/${GITHUB_COPILOT.COPILOT_CHAT_VERSION}`, - "user-agent": GITHUB_COPILOT.USER_AGENT, - "openai-intent": "conversation-panel", - "x-github-api-version": GITHUB_COPILOT.API_VERSION, - "x-vscode-user-agent-library-version": "electron-fetch", - "X-Initiator": "user", - "Accept": "application/json", - "Content-Type": "application/json" - } - }, - kiro: { - baseUrl: "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse", - format: "kiro", - headers: { - "Content-Type": "application/json", - "Accept": "application/vnd.amazon.eventstream", - "X-Amz-Target": "AmazonCodeWhispererStreamingService.GenerateAssistantResponse", - "User-Agent": "AWS-SDK-JS/3.0.0 kiro-ide/1.0.0", - "X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0" - }, - // Kiro OAuth endpoints - tokenUrl: "https://prod.us-east-1.auth.desktop.kiro.dev/refreshToken", - authUrl: "https://prod.us-east-1.auth.desktop.kiro.dev" - }, - cursor: { - baseUrl: "https://api2.cursor.sh", - chatPath: "/aiserver.v1.ChatService/StreamUnifiedChatWithTools", - format: "cursor", - headers: { - "connect-accept-encoding": "gzip", - "connect-protocol-version": "1", - "Content-Type": "application/connect+proto", - "User-Agent": "connect-es/1.6.1" - }, - clientVersion: "1.1.3" - }, - "kimi-coding": { - baseUrl: "https://api.kimi.com/coding/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" - }, - clientId: "17e5f671-d194-4dfb-9706-5516cb48c098", - tokenUrl: "https://auth.kimi.com/api/oauth/token", - refreshUrl: "https://auth.kimi.com/api/oauth/token" - }, - kilocode: { - baseUrl: "https://api.kilo.ai/api/openrouter/chat/completions", - format: "openai", - headers: {} - }, - cline: { - baseUrl: "https://api.cline.bot/api/v1/chat/completions", - format: "openai", - headers: { - "HTTP-Referer": "https://cline.bot", - "X-Title": "Cline" - }, - tokenUrl: "https://api.cline.bot/api/v1/auth/token", - refreshUrl: "https://api.cline.bot/api/v1/auth/refresh" - }, - nvidia: { - baseUrl: "https://integrate.api.nvidia.com/v1/chat/completions", - format: "openai" - }, - anthropic: { - baseUrl: "https://api.anthropic.com/v1/messages", - format: "claude", - headers: { - "Anthropic-Version": "2023-06-01", - "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" - } - }, - deepseek: { - baseUrl: "https://api.deepseek.com/chat/completions", - format: "openai" - }, - groq: { - baseUrl: "https://api.groq.com/openai/v1/chat/completions", - format: "openai" - }, - xai: { - baseUrl: "https://api.x.ai/v1/chat/completions", - format: "openai" - }, - mistral: { - baseUrl: "https://api.mistral.ai/v1/chat/completions", - format: "openai" - }, - perplexity: { - baseUrl: "https://api.perplexity.ai/chat/completions", - format: "openai" - }, - together: { - baseUrl: "https://api.together.xyz/v1/chat/completions", - format: "openai" - }, - fireworks: { - baseUrl: "https://api.fireworks.ai/inference/v1/chat/completions", - format: "openai" - }, - cerebras: { - baseUrl: "https://api.cerebras.ai/v1/chat/completions", - format: "openai" - }, - cohere: { - baseUrl: "https://api.cohere.ai/v1/chat/completions", - format: "openai" - }, - nebius: { - baseUrl: "https://api.studio.nebius.ai/v1/chat/completions", - format: "openai" - }, - siliconflow: { - baseUrl: "https://api.siliconflow.cn/v1/chat/completions", - format: "openai" - }, - hyperbolic: { - baseUrl: "https://api.hyperbolic.xyz/v1/chat/completions", - format: "openai" - }, - deepgram: { - baseUrl: "https://api.deepgram.com/v1/listen", - format: "openai" - }, - assemblyai: { - baseUrl: "https://api.assemblyai.com/v1/audio/transcriptions", - format: "openai" - }, - nanobanana: { - baseUrl: "https://api.nanobananaapi.ai/v1/chat/completions", - format: "openai" - }, - chutes: { - baseUrl: "https://llm.chutes.ai/v1/chat/completions", - format: "openai" - }, - ollama: { - baseUrl: "https://ollama.com/api/chat", - format: "ollama" - }, -}; - -// Claude system prompt -export const CLAUDE_SYSTEM_PROMPT = "You are a Claude agent, built on Anthropic's Claude Agent SDK."; - -// Antigravity default system prompt (required for API to work) -export const ANTIGRAVITY_DEFAULT_SYSTEM = "You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Absolute paths only****Proactiveness**"; - -// OAuth endpoints -export const OAUTH_ENDPOINTS = { - google: { - token: "https://oauth2.googleapis.com/token", - auth: "https://accounts.google.com/o/oauth2/auth" - }, - openai: { - token: "https://auth.openai.com/oauth/token", - auth: "https://auth.openai.com/oauth/authorize" - }, - anthropic: { - token: "https://api.anthropic.com/v1/oauth/token", - auth: "https://api.anthropic.com/v1/oauth/authorize" - }, - qwen: { - token: "https://chat.qwen.ai/api/v1/oauth2/token", // From CLIProxyAPI - auth: "https://chat.qwen.ai/api/v1/oauth2/device/code" // From CLIProxyAPI - }, - iflow: { - token: "https://iflow.cn/oauth/token", - auth: "https://iflow.cn/oauth" - }, - github: { - token: "https://github.com/login/oauth/access_token", - auth: "https://github.com/login/oauth/authorize", - deviceCode: "https://github.com/login/device/code" - } -}; - -// Cache TTLs (seconds) -export const CACHE_TTL = { - userInfo: 300, // 5 minutes - modelAlias: 3600 // 1 hour -}; - -// Memory management config -export const MEMORY_CONFIG = { - sessionTtlMs: 2 * 60 * 60 * 1000, // 2 hours per session entry - sessionCleanupIntervalMs: 30 * 60 * 1000, // cleanup every 30 minutes - dnsCacheTtlMs: 5 * 60 * 1000, // 5 minutes DNS TTL - proxyDispatchersMaxSize: 20, // max proxy agent instances -}; - -// Default max tokens -export const DEFAULT_MAX_TOKENS = 64000; - -// Minimum max tokens for tool calling (to prevent truncated arguments) -export const DEFAULT_MIN_TOKENS = 32000; - -// Retry config for 429 responses (used by BaseExecutor) -export const RETRY_CONFIG = { - maxAttempts: 2, - delayMs: 2000 -}; - -// HTTP status codes -export const HTTP_STATUS = { - BAD_REQUEST: 400, - UNAUTHORIZED: 401, - PAYMENT_REQUIRED: 402, - FORBIDDEN: 403, - NOT_FOUND: 404, - NOT_ACCEPTABLE: 406, - REQUEST_TIMEOUT: 408, - RATE_LIMITED: 429, - SERVER_ERROR: 500, - BAD_GATEWAY: 502, - SERVICE_UNAVAILABLE: 503, - GATEWAY_TIMEOUT: 504 -}; - -// OpenAI-compatible error types mapping -export const ERROR_TYPES = { - [HTTP_STATUS.BAD_REQUEST]: { type: "invalid_request_error", code: "bad_request" }, - [HTTP_STATUS.UNAUTHORIZED]: { type: "authentication_error", code: "invalid_api_key" }, - [HTTP_STATUS.FORBIDDEN]: { type: "permission_error", code: "insufficient_quota" }, - [HTTP_STATUS.NOT_FOUND]: { type: "invalid_request_error", code: "model_not_found" }, - [HTTP_STATUS.NOT_ACCEPTABLE]: { type: "invalid_request_error", code: "model_not_supported" }, - [HTTP_STATUS.RATE_LIMITED]: { type: "rate_limit_error", code: "rate_limit_exceeded" }, - [HTTP_STATUS.SERVER_ERROR]: { type: "server_error", code: "internal_server_error" }, - [HTTP_STATUS.BAD_GATEWAY]: { type: "server_error", code: "bad_gateway" }, - [HTTP_STATUS.SERVICE_UNAVAILABLE]: { type: "server_error", code: "service_unavailable" }, - [HTTP_STATUS.GATEWAY_TIMEOUT]: { type: "server_error", code: "gateway_timeout" } -}; - -// Default error messages per status code -export const DEFAULT_ERROR_MESSAGES = { - [HTTP_STATUS.BAD_REQUEST]: "Bad request", - [HTTP_STATUS.UNAUTHORIZED]: "Invalid API key provided", - [HTTP_STATUS.FORBIDDEN]: "You exceeded your current quota", - [HTTP_STATUS.NOT_FOUND]: "Model not found", - [HTTP_STATUS.NOT_ACCEPTABLE]: "Model not supported", - [HTTP_STATUS.RATE_LIMITED]: "Rate limit exceeded", - [HTTP_STATUS.SERVER_ERROR]: "Internal server error", - [HTTP_STATUS.BAD_GATEWAY]: "Bad gateway - upstream provider error", - [HTTP_STATUS.SERVICE_UNAVAILABLE]: "Service temporarily unavailable", - [HTTP_STATUS.GATEWAY_TIMEOUT]: "Gateway timeout" -}; - -// Exponential backoff config for rate limits (like CLIProxyAPI) -export const BACKOFF_CONFIG = { - base: 1000, // 1 second base - max: 2 * 60 * 1000, // 2 minutes max - maxLevel: 15 // Cap backoff level -}; - -// Error-based cooldown times (aligned with CLIProxyAPI) -export const COOLDOWN_MS = { - unauthorized: 2 * 60 * 1000, // 401 → 30 min - paymentRequired: 2 * 60 * 1000, // 402/403 → 30 min - notFound: 2 * 60 * 1000, // 404 → 2 minutes - transient: 30 * 1000, // 408/500/502/503/504 → 1 min - requestNotAllowed: 5 * 1000, // "Request not allowed" → 5 sec - // Legacy aliases for backward compatibility - rateLimit: 2 * 60 * 1000, - serviceUnavailable: 2 * 1000, - authExpired: 2 * 60 * 1000 -}; - -// Skip patterns - requests containing these texts will bypass provider -export const SKIP_PATTERNS = [ - "Please write a 5-10 word title for the following conversation:" -]; - -// Generate Kimi OAuth custom headers -export function buildKimiHeaders() { - const deviceId = `kimi-${Date.now()}`; - const platform = "9router"; - const version = "2.1.2"; - const deviceModel = typeof process !== "undefined" ? `${process.platform} ${process.arch}` : "unknown"; - - return { - "X-Msh-Platform": platform, - "X-Msh-Version": version, - "X-Msh-Device-Model": deviceModel, - "X-Msh-Device-Id": deviceId - }; -} - +// Barrel re-export — consumers can migrate to specific files over time +export * from "./providers.js"; +export * from "./appConstants.js"; +export * from "./runtimeConfig.js"; diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.js index 86bba9b0..a9cb3dfc 100644 --- a/open-sse/config/providerModels.js +++ b/open-sse/config/providerModels.js @@ -1,3 +1,5 @@ +import { PROVIDERS } from "./providers.js"; + // Provider models - Single source of truth // Key = alias (cc, cx, gc, qw, if, ag, gh for OAuth; id for API Key) // Field "provider" for special cases (e.g. AntiGravity models that call different backends) @@ -342,8 +344,8 @@ export function getModelTargetFormat(aliasOrId, modelId) { return found?.targetFormat || null; } -// Provider ID to alias mapping -export const PROVIDER_ID_TO_ALIAS = { +// OAuth providers that use short aliases (everything else: alias = id) +const OAUTH_ALIASES = { claude: "cc", codex: "cx", "gemini-cli": "gc", @@ -356,33 +358,13 @@ export const PROVIDER_ID_TO_ALIAS = { "kimi-coding": "kmc", kilocode: "kc", cline: "cl", - openai: "openai", - anthropic: "anthropic", - gemini: "gemini", - openrouter: "openrouter", - glm: "glm", - "glm-cn": "glm-cn", - kimi: "kimi", - minimax: "minimax", - "minimax-cn": "minimax-cn", - alicode: "alicode", - "alicode-intl": "alicode-intl", - deepseek: "deepseek", - groq: "groq", - xai: "xai", - mistral: "mistral", - perplexity: "perplexity", - together: "together", - fireworks: "fireworks", - cerebras: "cerebras", - cohere: "cohere", - nvidia: "nvidia", - nebius: "nebius", - siliconflow: "siliconflow", - hyperbolic: "hyperbolic", - ollama: "ollama", }; +// Derived from PROVIDERS — no need to maintain manually +export const PROVIDER_ID_TO_ALIAS = Object.fromEntries( + Object.keys(PROVIDERS).map(id => [id, OAUTH_ALIASES[id] || id]) +); + export function getModelsByProviderId(providerId) { const alias = PROVIDER_ID_TO_ALIAS[providerId] || providerId; return PROVIDER_MODELS[alias] || []; diff --git a/open-sse/config/providers.js b/open-sse/config/providers.js new file mode 100644 index 00000000..c7263fe3 --- /dev/null +++ b/open-sse/config/providers.js @@ -0,0 +1,297 @@ +import { platform, arch } from "os"; + +// === OS/Arch helpers === +function mapStainlessOs() { + switch (platform()) { + case "darwin": return "MacOS"; + case "win32": return "Windows"; + case "linux": return "Linux"; + case "freebsd": return "FreeBSD"; + default: return `Other::${platform()}`; + } +} + +function mapStainlessArch() { + switch (arch()) { + case "x64": return "x64"; + case "arm64": return "arm64"; + case "ia32": return "x86"; + default: return `other::${arch()}`; + } +} + +// Shared Claude-compatible API headers (reused across claude-format providers) +const CLAUDE_API_HEADERS = { + "Anthropic-Version": "2023-06-01", + "Anthropic-Beta": "claude-code-20250219,interleaved-thinking-2025-05-14" +}; + +// Shared baseUrls +const KIMI_CODING_BASE_URL = "https://api.kimi.com/coding/v1/messages"; + +export const PROVIDERS = { + claude: { + baseUrl: "https://api.anthropic.com/v1/messages", + format: "claude", + headers: { + "Anthropic-Version": "2023-06-01", + "Anthropic-Beta": "claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14,context-management-2025-06-27,prompt-caching-scope-2026-01-05", + "Anthropic-Dangerous-Direct-Browser-Access": "true", + "User-Agent": "claude-cli/2.1.63 (external, cli)", + "X-App": "cli", + "X-Stainless-Helper-Method": "stream", + "X-Stainless-Retry-Count": "0", + "X-Stainless-Runtime-Version": "v24.3.0", + "X-Stainless-Package-Version": "0.74.0", + "X-Stainless-Runtime": "node", + "X-Stainless-Lang": "js", + "X-Stainless-Arch": mapStainlessArch(), + "X-Stainless-Os": mapStainlessOs(), + "X-Stainless-Timeout": "600" + }, + clientId: "9d1c250a-e61b-44d9-88ed-5944d1962f5e", + tokenUrl: "https://api.anthropic.com/v1/oauth/token" + }, + gemini: { + baseUrl: "https://generativelanguage.googleapis.com/v1beta/models", + format: "gemini", + clientId: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com", + clientSecret: "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" + }, + "gemini-cli": { + baseUrl: "https://cloudcode-pa.googleapis.com/v1internal", + format: "gemini-cli", + clientId: "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com", + clientSecret: "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" + }, + codex: { + baseUrl: "https://chatgpt.com/backend-api/codex/responses", + format: "openai-responses", + headers: { + "originator": "codex-cli", + "User-Agent": "codex-cli/1.0.18 (macOS; arm64)" + }, + clientId: "app_EMoamEEZ73f0CkXaXp7hrann", + clientSecret: "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", + tokenUrl: "https://auth.openai.com/oauth/token" + }, + qwen: { + baseUrl: "https://portal.qwen.ai/v1/chat/completions", + format: "openai", + headers: { + "User-Agent": "google-api-nodejs-client/9.15.1", + "X-Goog-Api-Client": "gl-node/22.17.0" + }, + clientId: "f0304373b74a44d2b584a3fb70ca9e56", + tokenUrl: "https://chat.qwen.ai/api/v1/oauth2/token", + authUrl: "https://chat.qwen.ai/api/v1/oauth2/device/code" + }, + iflow: { + baseUrl: "https://apis.iflow.cn/v1/chat/completions", + format: "openai", + headers: { "User-Agent": "iFlow-Cli" }, + clientId: "10009311001", + clientSecret: "4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW", + tokenUrl: "https://iflow.cn/oauth/token", + authUrl: "https://iflow.cn/oauth" + }, + antigravity: { + baseUrls: [ + "https://daily-cloudcode-pa.googleapis.com", + "https://cloudcode-pa.googleapis.com", + ], + format: "antigravity", + headers: { "User-Agent": `antigravity/1.104.0 ${platform()}/${arch()}` }, + clientId: "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com", + clientSecret: "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" + }, + openrouter: { + baseUrl: "https://openrouter.ai/api/v1/chat/completions", + format: "openai", + headers: { + "HTTP-Referer": "https://endpoint-proxy.local", + "X-Title": "Endpoint Proxy" + } + }, + openai: { + baseUrl: "https://api.openai.com/v1/chat/completions", + format: "openai" + }, + glm: { + baseUrl: "https://api.z.ai/api/anthropic/v1/messages", + format: "claude", + headers: { ...CLAUDE_API_HEADERS } + }, + "glm-cn": { + baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4/chat/completions", + format: "openai", + headers: {} + }, + kimi: { + baseUrl: KIMI_CODING_BASE_URL, + format: "claude", + headers: { ...CLAUDE_API_HEADERS } + }, + minimax: { + baseUrl: "https://api.minimax.io/anthropic/v1/messages", + format: "claude", + headers: { ...CLAUDE_API_HEADERS } + }, + "minimax-cn": { + baseUrl: "https://api.minimaxi.com/anthropic/v1/messages", + format: "claude", + headers: { ...CLAUDE_API_HEADERS } + }, + alicode: { + baseUrl: "https://coding.dashscope.aliyuncs.com/v1/chat/completions", + format: "openai", + headers: {} + }, + "alicode-intl": { + baseUrl: "https://coding-intl.dashscope.aliyuncs.com/v1/chat/completions", + format: "openai", + headers: {} + }, + github: { + baseUrl: "https://api.githubcopilot.com/chat/completions", + responsesUrl: "https://api.githubcopilot.com/responses", + format: "openai", + headers: { + "copilot-integration-id": "vscode-chat", + "editor-version": "vscode/1.110.0", + "editor-plugin-version": "copilot-chat/0.38.0", + "user-agent": "GitHubCopilotChat/0.38.0", + "openai-intent": "conversation-panel", + "x-github-api-version": "2025-04-01", + "x-vscode-user-agent-library-version": "electron-fetch", + "X-Initiator": "user", + "Accept": "application/json", + "Content-Type": "application/json" + } + }, + kiro: { + baseUrl: "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse", + format: "kiro", + headers: { + "Content-Type": "application/json", + "Accept": "application/vnd.amazon.eventstream", + "X-Amz-Target": "AmazonCodeWhispererStreamingService.GenerateAssistantResponse", + "User-Agent": "AWS-SDK-JS/3.0.0 kiro-ide/1.0.0", + "X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0" + }, + tokenUrl: "https://prod.us-east-1.auth.desktop.kiro.dev/refreshToken", + authUrl: "https://prod.us-east-1.auth.desktop.kiro.dev" + }, + cursor: { + baseUrl: "https://api2.cursor.sh", + chatPath: "/aiserver.v1.ChatService/StreamUnifiedChatWithTools", + format: "cursor", + headers: { + "connect-accept-encoding": "gzip", + "connect-protocol-version": "1", + "Content-Type": "application/connect+proto", + "User-Agent": "connect-es/1.6.1" + }, + clientVersion: "1.1.3" + }, + "kimi-coding": { + baseUrl: KIMI_CODING_BASE_URL, + format: "claude", + headers: { ...CLAUDE_API_HEADERS }, + clientId: "17e5f671-d194-4dfb-9706-5516cb48c098", + tokenUrl: "https://auth.kimi.com/api/oauth/token", + refreshUrl: "https://auth.kimi.com/api/oauth/token" + }, + kilocode: { + baseUrl: "https://api.kilo.ai/api/openrouter/chat/completions", + format: "openai", + headers: {} + }, + cline: { + baseUrl: "https://api.cline.bot/api/v1/chat/completions", + format: "openai", + headers: { + "HTTP-Referer": "https://cline.bot", + "X-Title": "Cline" + }, + tokenUrl: "https://api.cline.bot/api/v1/auth/token", + refreshUrl: "https://api.cline.bot/api/v1/auth/refresh" + }, + nvidia: { + baseUrl: "https://integrate.api.nvidia.com/v1/chat/completions", + format: "openai" + }, + anthropic: { + baseUrl: "https://api.anthropic.com/v1/messages", + format: "claude", + headers: { ...CLAUDE_API_HEADERS } + }, + deepseek: { + baseUrl: "https://api.deepseek.com/chat/completions", + format: "openai" + }, + groq: { + baseUrl: "https://api.groq.com/openai/v1/chat/completions", + format: "openai" + }, + xai: { + baseUrl: "https://api.x.ai/v1/chat/completions", + format: "openai" + }, + mistral: { + baseUrl: "https://api.mistral.ai/v1/chat/completions", + format: "openai" + }, + perplexity: { + baseUrl: "https://api.perplexity.ai/chat/completions", + format: "openai" + }, + together: { + baseUrl: "https://api.together.xyz/v1/chat/completions", + format: "openai" + }, + fireworks: { + baseUrl: "https://api.fireworks.ai/inference/v1/chat/completions", + format: "openai" + }, + cerebras: { + baseUrl: "https://api.cerebras.ai/v1/chat/completions", + format: "openai" + }, + cohere: { + baseUrl: "https://api.cohere.ai/v1/chat/completions", + format: "openai" + }, + nebius: { + baseUrl: "https://api.studio.nebius.ai/v1/chat/completions", + format: "openai" + }, + siliconflow: { + baseUrl: "https://api.siliconflow.cn/v1/chat/completions", + format: "openai" + }, + hyperbolic: { + baseUrl: "https://api.hyperbolic.xyz/v1/chat/completions", + format: "openai" + }, + deepgram: { + baseUrl: "https://api.deepgram.com/v1/listen", + format: "openai" + }, + assemblyai: { + baseUrl: "https://api.assemblyai.com/v1/audio/transcriptions", + format: "openai" + }, + nanobanana: { + baseUrl: "https://api.nanobananaapi.ai/v1/chat/completions", + format: "openai" + }, + chutes: { + baseUrl: "https://llm.chutes.ai/v1/chat/completions", + format: "openai" + }, + ollama: { + baseUrl: "https://ollama.com/api/chat", + format: "ollama" + }, +}; diff --git a/open-sse/config/runtimeConfig.js b/open-sse/config/runtimeConfig.js new file mode 100644 index 00000000..19ac15ab --- /dev/null +++ b/open-sse/config/runtimeConfig.js @@ -0,0 +1,92 @@ +// HTTP status codes +export const HTTP_STATUS = { + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + PAYMENT_REQUIRED: 402, + FORBIDDEN: 403, + NOT_FOUND: 404, + NOT_ACCEPTABLE: 406, + REQUEST_TIMEOUT: 408, + RATE_LIMITED: 429, + SERVER_ERROR: 500, + BAD_GATEWAY: 502, + SERVICE_UNAVAILABLE: 503, + GATEWAY_TIMEOUT: 504 +}; + +// OpenAI-compatible error types mapping +export const ERROR_TYPES = { + [HTTP_STATUS.BAD_REQUEST]: { type: "invalid_request_error", code: "bad_request" }, + [HTTP_STATUS.UNAUTHORIZED]: { type: "authentication_error", code: "invalid_api_key" }, + [HTTP_STATUS.FORBIDDEN]: { type: "permission_error", code: "insufficient_quota" }, + [HTTP_STATUS.NOT_FOUND]: { type: "invalid_request_error", code: "model_not_found" }, + [HTTP_STATUS.NOT_ACCEPTABLE]: { type: "invalid_request_error", code: "model_not_supported" }, + [HTTP_STATUS.RATE_LIMITED]: { type: "rate_limit_error", code: "rate_limit_exceeded" }, + [HTTP_STATUS.SERVER_ERROR]: { type: "server_error", code: "internal_server_error" }, + [HTTP_STATUS.BAD_GATEWAY]: { type: "server_error", code: "bad_gateway" }, + [HTTP_STATUS.SERVICE_UNAVAILABLE]: { type: "server_error", code: "service_unavailable" }, + [HTTP_STATUS.GATEWAY_TIMEOUT]: { type: "server_error", code: "gateway_timeout" } +}; + +// Default error messages per status code +export const DEFAULT_ERROR_MESSAGES = { + [HTTP_STATUS.BAD_REQUEST]: "Bad request", + [HTTP_STATUS.UNAUTHORIZED]: "Invalid API key provided", + [HTTP_STATUS.FORBIDDEN]: "You exceeded your current quota", + [HTTP_STATUS.NOT_FOUND]: "Model not found", + [HTTP_STATUS.NOT_ACCEPTABLE]: "Model not supported", + [HTTP_STATUS.RATE_LIMITED]: "Rate limit exceeded", + [HTTP_STATUS.SERVER_ERROR]: "Internal server error", + [HTTP_STATUS.BAD_GATEWAY]: "Bad gateway - upstream provider error", + [HTTP_STATUS.SERVICE_UNAVAILABLE]: "Service temporarily unavailable", + [HTTP_STATUS.GATEWAY_TIMEOUT]: "Gateway timeout" +}; + +// Cache TTLs (seconds) +export const CACHE_TTL = { + userInfo: 300, // 5 minutes + modelAlias: 3600 // 1 hour +}; + +// Memory management config +export const MEMORY_CONFIG = { + sessionTtlMs: 2 * 60 * 60 * 1000, + sessionCleanupIntervalMs: 30 * 60 * 1000, + dnsCacheTtlMs: 5 * 60 * 1000, + proxyDispatchersMaxSize: 20, +}; + +// Default token limits +export const DEFAULT_MAX_TOKENS = 64000; +export const DEFAULT_MIN_TOKENS = 32000; + +// Retry config for 429 responses +export const RETRY_CONFIG = { + maxAttempts: 2, + delayMs: 2000 +}; + +// Exponential backoff config for rate limits +export const BACKOFF_CONFIG = { + base: 1000, + max: 2 * 60 * 1000, + maxLevel: 15 +}; + +// Error-based cooldown times +export const COOLDOWN_MS = { + unauthorized: 2 * 60 * 1000, + paymentRequired: 2 * 60 * 1000, + notFound: 2 * 60 * 1000, + transient: 30 * 1000, + requestNotAllowed: 5 * 1000, + // Legacy aliases + rateLimit: 2 * 60 * 1000, + serviceUnavailable: 2 * 1000, + authExpired: 2 * 60 * 1000 +}; + +// Requests containing these texts will bypass provider +export const SKIP_PATTERNS = [ + "Please write a 5-10 word title for the following conversation:" +]; diff --git a/open-sse/executors/antigravity.js b/open-sse/executors/antigravity.js index 30e0db8b..2b6001a8 100644 --- a/open-sse/executors/antigravity.js +++ b/open-sse/executors/antigravity.js @@ -1,6 +1,8 @@ import crypto from "crypto"; import { BaseExecutor } from "./base.js"; -import { PROVIDERS, OAUTH_ENDPOINTS, HTTP_STATUS, ANTIGRAVITY_HEADERS, INTERNAL_REQUEST_HEADER } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; +import { OAUTH_ENDPOINTS, ANTIGRAVITY_HEADERS, INTERNAL_REQUEST_HEADER } from "../config/appConstants.js"; +import { HTTP_STATUS } from "../config/runtimeConfig.js"; import { deriveSessionId } from "../utils/sessionManager.js"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; diff --git a/open-sse/executors/base.js b/open-sse/executors/base.js index 17f351de..61fb0f6e 100644 --- a/open-sse/executors/base.js +++ b/open-sse/executors/base.js @@ -1,4 +1,4 @@ -import { HTTP_STATUS, RETRY_CONFIG } from "../config/constants.js"; +import { HTTP_STATUS, RETRY_CONFIG } from "../config/runtimeConfig.js"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; /** diff --git a/open-sse/executors/codex.js b/open-sse/executors/codex.js index e49edf57..ca062ecb 100644 --- a/open-sse/executors/codex.js +++ b/open-sse/executors/codex.js @@ -1,6 +1,6 @@ import { BaseExecutor } from "./base.js"; import { CODEX_DEFAULT_INSTRUCTIONS } from "../config/codexInstructions.js"; -import { PROVIDERS } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; import { normalizeResponsesInput } from "../translator/helpers/responsesApiHelper.js"; /** diff --git a/open-sse/executors/cursor.js b/open-sse/executors/cursor.js index abe85a45..e090fc73 100644 --- a/open-sse/executors/cursor.js +++ b/open-sse/executors/cursor.js @@ -1,5 +1,6 @@ import { BaseExecutor } from "./base.js"; -import { PROVIDERS, HTTP_STATUS } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; +import { HTTP_STATUS } from "../config/runtimeConfig.js"; import { generateCursorBody, parseConnectRPCFrame, diff --git a/open-sse/executors/default.js b/open-sse/executors/default.js index 2b5ccde9..eb3e19d0 100644 --- a/open-sse/executors/default.js +++ b/open-sse/executors/default.js @@ -1,5 +1,6 @@ import { BaseExecutor } from "./base.js"; -import { PROVIDERS, OAUTH_ENDPOINTS, buildKimiHeaders } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; +import { OAUTH_ENDPOINTS, buildKimiHeaders } from "../config/appConstants.js"; import { buildClineHeaders } from "../../src/shared/utils/clineAuth.js"; export class DefaultExecutor extends BaseExecutor { diff --git a/open-sse/executors/gemini-cli.js b/open-sse/executors/gemini-cli.js index e6fe3d35..45470c87 100644 --- a/open-sse/executors/gemini-cli.js +++ b/open-sse/executors/gemini-cli.js @@ -1,5 +1,6 @@ import { BaseExecutor } from "./base.js"; -import { PROVIDERS, OAUTH_ENDPOINTS, GEMINI_CLI_API_CLIENT, geminiCLIUserAgent } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; +import { OAUTH_ENDPOINTS, GEMINI_CLI_API_CLIENT, geminiCLIUserAgent } from "../config/appConstants.js"; export class GeminiCLIExecutor extends BaseExecutor { constructor() { diff --git a/open-sse/executors/github.js b/open-sse/executors/github.js index c38dec88..7188e575 100644 --- a/open-sse/executors/github.js +++ b/open-sse/executors/github.js @@ -1,5 +1,7 @@ import { BaseExecutor } from "./base.js"; -import { PROVIDERS, OAUTH_ENDPOINTS, HTTP_STATUS, GITHUB_COPILOT } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; +import { OAUTH_ENDPOINTS, GITHUB_COPILOT } from "../config/appConstants.js"; +import { HTTP_STATUS } from "../config/runtimeConfig.js"; import { openaiToOpenAIResponsesRequest } from "../translator/request/openai-responses.js"; import { openaiResponsesToOpenAIResponse } from "../translator/response/openai-responses.js"; import { initState } from "../translator/index.js"; diff --git a/open-sse/executors/iflow.js b/open-sse/executors/iflow.js index f18753bd..701c8c9a 100644 --- a/open-sse/executors/iflow.js +++ b/open-sse/executors/iflow.js @@ -1,6 +1,6 @@ import crypto from "crypto"; import { BaseExecutor } from "./base.js"; -import { PROVIDERS } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; /** * IFlowExecutor - Executor for iFlow API with HMAC-SHA256 signature diff --git a/open-sse/executors/kiro.js b/open-sse/executors/kiro.js index 9ad2ed97..698dcdf4 100644 --- a/open-sse/executors/kiro.js +++ b/open-sse/executors/kiro.js @@ -1,5 +1,5 @@ import { BaseExecutor } from "./base.js"; -import { PROVIDERS } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; import { v4 as uuidv4 } from "uuid"; import { refreshKiroToken } from "../services/tokenRefresh.js"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; diff --git a/open-sse/handlers/chatCore.js b/open-sse/handlers/chatCore.js index 92c89c6d..43f766e9 100644 --- a/open-sse/handlers/chatCore.js +++ b/open-sse/handlers/chatCore.js @@ -7,7 +7,7 @@ import { refreshWithRetry } from "../services/tokenRefresh.js"; import { createRequestLogger } from "../utils/requestLogger.js"; import { getModelTargetFormat, PROVIDER_ID_TO_ALIAS } from "../config/providerModels.js"; import { createErrorResult, parseUpstreamError, formatProviderError } from "../utils/error.js"; -import { HTTP_STATUS } from "../config/constants.js"; +import { HTTP_STATUS } from "../config/runtimeConfig.js"; import { handleBypassRequest } from "../utils/bypassHandler.js"; import { trackPendingRequest, appendRequestLog, saveRequestDetail } from "@/lib/usageDb.js"; import { getExecutor } from "../executors/index.js"; diff --git a/open-sse/handlers/chatCore/nonStreamingHandler.js b/open-sse/handlers/chatCore/nonStreamingHandler.js index 9468dc86..62efc03d 100644 --- a/open-sse/handlers/chatCore/nonStreamingHandler.js +++ b/open-sse/handlers/chatCore/nonStreamingHandler.js @@ -3,7 +3,7 @@ import { needsTranslation } from "../../translator/index.js"; import { ollamaBodyToOpenAI } from "../../translator/response/ollama-to-openai.js"; import { addBufferToUsage, filterUsageForFormat } from "../../utils/usageTracking.js"; import { createErrorResult } from "../../utils/error.js"; -import { HTTP_STATUS } from "../../config/constants.js"; +import { HTTP_STATUS } from "../../config/runtimeConfig.js"; import { parseSSEToOpenAIResponse } from "./sseToJsonHandler.js"; import { buildRequestDetail, extractRequestConfig, extractUsageFromResponse, saveUsageStats } from "./requestDetail.js"; import { appendRequestLog, saveRequestDetail } from "@/lib/usageDb.js"; diff --git a/open-sse/handlers/chatCore/sseToJsonHandler.js b/open-sse/handlers/chatCore/sseToJsonHandler.js index 0c71be30..8df3996c 100644 --- a/open-sse/handlers/chatCore/sseToJsonHandler.js +++ b/open-sse/handlers/chatCore/sseToJsonHandler.js @@ -1,6 +1,6 @@ import { convertResponsesStreamToJson } from "../../transformer/streamToJsonConverter.js"; import { createErrorResult } from "../../utils/error.js"; -import { HTTP_STATUS } from "../../config/constants.js"; +import { HTTP_STATUS } from "../../config/runtimeConfig.js"; import { FORMATS } from "../../translator/formats.js"; import { buildRequestDetail, extractRequestConfig, saveUsageStats } from "./requestDetail.js"; import { saveRequestDetail, appendRequestLog } from "@/lib/usageDb.js"; diff --git a/open-sse/handlers/embeddingsCore.js b/open-sse/handlers/embeddingsCore.js index 35fdade7..b9eb6360 100644 --- a/open-sse/handlers/embeddingsCore.js +++ b/open-sse/handlers/embeddingsCore.js @@ -1,6 +1,6 @@ import { getModelTargetFormat, PROVIDER_ID_TO_ALIAS } from "../config/providerModels.js"; import { createErrorResult, parseUpstreamError, formatProviderError } from "../utils/error.js"; -import { HTTP_STATUS } from "../config/constants.js"; +import { HTTP_STATUS } from "../config/runtimeConfig.js"; import { getExecutor } from "../executors/index.js"; import { refreshWithRetry } from "../services/tokenRefresh.js"; diff --git a/open-sse/index.js b/open-sse/index.js index 7e6fb334..dde009c5 100644 --- a/open-sse/index.js +++ b/open-sse/index.js @@ -2,7 +2,9 @@ import "./utils/proxyFetch.js"; // Config -export { PROVIDERS, OAUTH_ENDPOINTS, CACHE_TTL, DEFAULT_MAX_TOKENS, CLAUDE_SYSTEM_PROMPT, COOLDOWN_MS, BACKOFF_CONFIG } from "./config/constants.js"; +export { PROVIDERS } from "./config/providers.js"; +export { OAUTH_ENDPOINTS, CLAUDE_SYSTEM_PROMPT } from "./config/appConstants.js"; +export { CACHE_TTL, DEFAULT_MAX_TOKENS, COOLDOWN_MS, BACKOFF_CONFIG } from "./config/runtimeConfig.js"; export { PROVIDER_MODELS, getProviderModels, diff --git a/open-sse/services/accountFallback.js b/open-sse/services/accountFallback.js index 0e1b2d1b..573a5d64 100644 --- a/open-sse/services/accountFallback.js +++ b/open-sse/services/accountFallback.js @@ -1,4 +1,4 @@ -import { COOLDOWN_MS, BACKOFF_CONFIG, HTTP_STATUS } from "../config/constants.js"; +import { COOLDOWN_MS, BACKOFF_CONFIG, HTTP_STATUS } from "../config/runtimeConfig.js"; /** * Calculate exponential backoff cooldown for rate limits (429) diff --git a/open-sse/services/projectId.js b/open-sse/services/projectId.js index 8bb8fde0..4f5ba327 100644 --- a/open-sse/services/projectId.js +++ b/open-sse/services/projectId.js @@ -8,7 +8,7 @@ * This significantly reduces the risk of being flagged by Google's anti-abuse systems. */ -import {CLOUD_CODE_API, LOAD_CODE_ASSIST_HEADERS, LOAD_CODE_ASSIST_METADATA} from "../config/constants.js"; +import { CLOUD_CODE_API, LOAD_CODE_ASSIST_HEADERS, LOAD_CODE_ASSIST_METADATA } from "../config/appConstants.js"; // ─── Cache ──────────────────────────────────────────────────────────────────── // connectionId -> { projectId: string, fetchedAt: number } diff --git a/open-sse/services/provider.js b/open-sse/services/provider.js index 93101367..1bb41d7e 100644 --- a/open-sse/services/provider.js +++ b/open-sse/services/provider.js @@ -1,4 +1,4 @@ -import { PROVIDERS } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; import { buildClineHeaders } from "../../src/shared/utils/clineAuth.js"; const OPENAI_COMPATIBLE_PREFIX = "openai-compatible-"; diff --git a/open-sse/services/tokenRefresh.js b/open-sse/services/tokenRefresh.js index 1d4f628f..7ee5b0a4 100644 --- a/open-sse/services/tokenRefresh.js +++ b/open-sse/services/tokenRefresh.js @@ -1,4 +1,5 @@ -import { PROVIDERS, OAUTH_ENDPOINTS, GITHUB_COPILOT } from "../config/constants.js"; +import { PROVIDERS } from "../config/providers.js"; +import { OAUTH_ENDPOINTS, GITHUB_COPILOT } from "../config/appConstants.js"; // Token expiry buffer (refresh if expires within 5 minutes) export const TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1000; diff --git a/open-sse/services/usage.js b/open-sse/services/usage.js index d6b7cf07..59ddf8ec 100644 --- a/open-sse/services/usage.js +++ b/open-sse/services/usage.js @@ -2,7 +2,7 @@ * Usage Fetcher - Get usage data from provider APIs */ -import { CLIENT_METADATA, getPlatformUserAgent } from "../config/constants.js"; +import { CLIENT_METADATA, getPlatformUserAgent } from "../config/appConstants.js"; // GitHub API config const GITHUB_CONFIG = { diff --git a/open-sse/translator/helpers/maxTokensHelper.js b/open-sse/translator/helpers/maxTokensHelper.js index 4627fabd..6a1c044d 100644 --- a/open-sse/translator/helpers/maxTokensHelper.js +++ b/open-sse/translator/helpers/maxTokensHelper.js @@ -1,4 +1,4 @@ -import { DEFAULT_MAX_TOKENS, DEFAULT_MIN_TOKENS } from "../../config/constants.js"; +import { DEFAULT_MAX_TOKENS, DEFAULT_MIN_TOKENS } from "../../config/runtimeConfig.js"; /** * Adjust max_tokens based on request context diff --git a/open-sse/translator/request/openai-to-claude.js b/open-sse/translator/request/openai-to-claude.js index e2e96630..13f87b19 100644 --- a/open-sse/translator/request/openai-to-claude.js +++ b/open-sse/translator/request/openai-to-claude.js @@ -1,6 +1,6 @@ import { register } from "../index.js"; import { FORMATS } from "../formats.js"; -import { CLAUDE_SYSTEM_PROMPT } from "../../config/constants.js"; +import { CLAUDE_SYSTEM_PROMPT } from "../../config/appConstants.js"; import { adjustMaxTokens } from "../helpers/maxTokensHelper.js"; // Empty prefix matches real Claude Code behavior (no tool name prefix). diff --git a/open-sse/translator/request/openai-to-gemini.js b/open-sse/translator/request/openai-to-gemini.js index 2874b394..fef3e480 100644 --- a/open-sse/translator/request/openai-to-gemini.js +++ b/open-sse/translator/request/openai-to-gemini.js @@ -1,7 +1,7 @@ import { register } from "../index.js"; import { FORMATS } from "../formats.js"; import { DEFAULT_THINKING_GEMINI_SIGNATURE } from "../../config/defaultThinkingSignature.js"; -import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../config/constants.js"; +import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../config/appConstants.js"; import { openaiToClaudeRequestForAntigravity } from "./openai-to-claude.js"; function generateUUID() { diff --git a/open-sse/utils/bypassHandler.js b/open-sse/utils/bypassHandler.js index a4e21f38..1c57dc54 100644 --- a/open-sse/utils/bypassHandler.js +++ b/open-sse/utils/bypassHandler.js @@ -1,7 +1,7 @@ import { detectFormat } from "../services/provider.js"; import { translateResponse, initState } from "../translator/index.js"; import { FORMATS } from "../translator/formats.js"; -import { SKIP_PATTERNS } from "../config/constants.js"; +import { SKIP_PATTERNS } from "../config/runtimeConfig.js"; import { formatSSE } from "./stream.js"; /** diff --git a/open-sse/utils/error.js b/open-sse/utils/error.js index 31497ddd..cf637873 100644 --- a/open-sse/utils/error.js +++ b/open-sse/utils/error.js @@ -1,4 +1,4 @@ -import { ERROR_TYPES, DEFAULT_ERROR_MESSAGES } from "../config/constants.js"; +import { ERROR_TYPES, DEFAULT_ERROR_MESSAGES } from "../config/runtimeConfig.js"; /** * Build OpenAI-compatible error response body diff --git a/open-sse/utils/proxyFetch.js b/open-sse/utils/proxyFetch.js index 5d00309a..d686fe11 100644 --- a/open-sse/utils/proxyFetch.js +++ b/open-sse/utils/proxyFetch.js @@ -1,4 +1,4 @@ -import { MEMORY_CONFIG } from "../config/constants.js"; +import { MEMORY_CONFIG } from "../config/runtimeConfig.js"; const isCloud = typeof caches !== "undefined" && typeof caches === "object"; diff --git a/open-sse/utils/sessionManager.js b/open-sse/utils/sessionManager.js index f3fb08cf..ce56291a 100644 --- a/open-sse/utils/sessionManager.js +++ b/open-sse/utils/sessionManager.js @@ -9,7 +9,7 @@ */ import crypto from "crypto"; -import { MEMORY_CONFIG } from "../config/constants.js"; +import { MEMORY_CONFIG } from "../config/runtimeConfig.js"; // Runtime storage: Key = connectionId, Value = { sessionId, lastUsed } const runtimeSessionStore = new Map(); diff --git a/src/sse/handlers/chat.js b/src/sse/handlers/chat.js index 12a9d6ce..c711f3d3 100644 --- a/src/sse/handlers/chat.js +++ b/src/sse/handlers/chat.js @@ -12,7 +12,7 @@ import { getModelInfo, getComboModels } from "../services/model.js"; import { handleChatCore } from "open-sse/handlers/chatCore.js"; import { errorResponse, unavailableResponse } from "open-sse/utils/error.js"; import { handleComboChat } from "open-sse/services/combo.js"; -import { HTTP_STATUS } from "open-sse/config/constants.js"; +import { HTTP_STATUS } from "open-sse/config/runtimeConfig.js"; import { detectFormatByEndpoint } from "open-sse/translator/formats.js"; import * as log from "../utils/logger.js"; import { updateProviderCredentials, checkAndRefreshToken } from "../services/tokenRefresh.js"; diff --git a/src/sse/handlers/embeddings.js b/src/sse/handlers/embeddings.js index a9e02d1b..0aa2463f 100644 --- a/src/sse/handlers/embeddings.js +++ b/src/sse/handlers/embeddings.js @@ -9,7 +9,7 @@ import { getSettings } from "@/lib/localDb"; import { getModelInfo } from "../services/model.js"; import { handleEmbeddingsCore } from "open-sse/handlers/embeddingsCore.js"; import { errorResponse, unavailableResponse } from "open-sse/utils/error.js"; -import { HTTP_STATUS } from "open-sse/config/constants.js"; +import { HTTP_STATUS } from "open-sse/config/runtimeConfig.js"; import * as log from "../utils/logger.js"; import { updateProviderCredentials, checkAndRefreshToken } from "../services/tokenRefresh.js";