commons-proxy 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +757 -0
  3. package/bin/cli.js +146 -0
  4. package/package.json +97 -0
  5. package/public/Complaint Details.pdf +0 -0
  6. package/public/Cyber Crime Portal.pdf +0 -0
  7. package/public/app.js +229 -0
  8. package/public/css/src/input.css +523 -0
  9. package/public/css/style.css +1 -0
  10. package/public/favicon.png +0 -0
  11. package/public/index.html +549 -0
  12. package/public/js/components/account-manager.js +356 -0
  13. package/public/js/components/add-account-modal.js +414 -0
  14. package/public/js/components/claude-config.js +420 -0
  15. package/public/js/components/dashboard/charts.js +605 -0
  16. package/public/js/components/dashboard/filters.js +362 -0
  17. package/public/js/components/dashboard/stats.js +110 -0
  18. package/public/js/components/dashboard.js +236 -0
  19. package/public/js/components/logs-viewer.js +100 -0
  20. package/public/js/components/models.js +36 -0
  21. package/public/js/components/server-config.js +349 -0
  22. package/public/js/config/constants.js +102 -0
  23. package/public/js/data-store.js +375 -0
  24. package/public/js/settings-store.js +58 -0
  25. package/public/js/store.js +99 -0
  26. package/public/js/translations/en.js +367 -0
  27. package/public/js/translations/id.js +412 -0
  28. package/public/js/translations/pt.js +308 -0
  29. package/public/js/translations/tr.js +358 -0
  30. package/public/js/translations/zh.js +373 -0
  31. package/public/js/utils/account-actions.js +189 -0
  32. package/public/js/utils/error-handler.js +96 -0
  33. package/public/js/utils/model-config.js +42 -0
  34. package/public/js/utils/ui-logger.js +143 -0
  35. package/public/js/utils/validators.js +77 -0
  36. package/public/js/utils.js +69 -0
  37. package/public/proxy-server-64.png +0 -0
  38. package/public/views/accounts.html +361 -0
  39. package/public/views/dashboard.html +484 -0
  40. package/public/views/logs.html +97 -0
  41. package/public/views/models.html +331 -0
  42. package/public/views/settings.html +1327 -0
  43. package/src/account-manager/credentials.js +378 -0
  44. package/src/account-manager/index.js +462 -0
  45. package/src/account-manager/onboarding.js +112 -0
  46. package/src/account-manager/rate-limits.js +369 -0
  47. package/src/account-manager/storage.js +160 -0
  48. package/src/account-manager/strategies/base-strategy.js +109 -0
  49. package/src/account-manager/strategies/hybrid-strategy.js +339 -0
  50. package/src/account-manager/strategies/index.js +79 -0
  51. package/src/account-manager/strategies/round-robin-strategy.js +76 -0
  52. package/src/account-manager/strategies/sticky-strategy.js +138 -0
  53. package/src/account-manager/strategies/trackers/health-tracker.js +162 -0
  54. package/src/account-manager/strategies/trackers/index.js +9 -0
  55. package/src/account-manager/strategies/trackers/quota-tracker.js +120 -0
  56. package/src/account-manager/strategies/trackers/token-bucket-tracker.js +155 -0
  57. package/src/auth/database.js +169 -0
  58. package/src/auth/oauth.js +548 -0
  59. package/src/auth/token-extractor.js +117 -0
  60. package/src/cli/accounts.js +648 -0
  61. package/src/cloudcode/index.js +29 -0
  62. package/src/cloudcode/message-handler.js +510 -0
  63. package/src/cloudcode/model-api.js +248 -0
  64. package/src/cloudcode/rate-limit-parser.js +235 -0
  65. package/src/cloudcode/request-builder.js +93 -0
  66. package/src/cloudcode/session-manager.js +47 -0
  67. package/src/cloudcode/sse-parser.js +121 -0
  68. package/src/cloudcode/sse-streamer.js +293 -0
  69. package/src/cloudcode/streaming-handler.js +615 -0
  70. package/src/config.js +125 -0
  71. package/src/constants.js +407 -0
  72. package/src/errors.js +242 -0
  73. package/src/fallback-config.js +29 -0
  74. package/src/format/content-converter.js +193 -0
  75. package/src/format/index.js +20 -0
  76. package/src/format/request-converter.js +255 -0
  77. package/src/format/response-converter.js +120 -0
  78. package/src/format/schema-sanitizer.js +673 -0
  79. package/src/format/signature-cache.js +88 -0
  80. package/src/format/thinking-utils.js +648 -0
  81. package/src/index.js +148 -0
  82. package/src/modules/usage-stats.js +205 -0
  83. package/src/providers/anthropic-provider.js +258 -0
  84. package/src/providers/base-provider.js +157 -0
  85. package/src/providers/cloudcode.js +94 -0
  86. package/src/providers/copilot.js +399 -0
  87. package/src/providers/github-provider.js +287 -0
  88. package/src/providers/google-provider.js +192 -0
  89. package/src/providers/index.js +211 -0
  90. package/src/providers/openai-compatible.js +265 -0
  91. package/src/providers/openai-provider.js +271 -0
  92. package/src/providers/openrouter-provider.js +325 -0
  93. package/src/providers/setup.js +83 -0
  94. package/src/server.js +870 -0
  95. package/src/utils/claude-config.js +245 -0
  96. package/src/utils/helpers.js +51 -0
  97. package/src/utils/logger.js +142 -0
  98. package/src/utils/native-module-helper.js +162 -0
  99. package/src/webui/index.js +1134 -0
package/src/config.js ADDED
@@ -0,0 +1,125 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { logger } from './utils/logger.js';
5
+
6
+ // Default config
7
+ const DEFAULT_CONFIG = {
8
+ apiKey: '',
9
+ webuiPassword: '',
10
+ debug: false,
11
+ logLevel: 'info',
12
+ maxRetries: 5,
13
+ retryBaseMs: 1000,
14
+ retryMaxMs: 30000,
15
+ persistTokenCache: false,
16
+ defaultCooldownMs: 10000, // 10 seconds
17
+ maxWaitBeforeErrorMs: 120000, // 2 minutes
18
+ maxAccounts: 10, // Maximum number of accounts allowed
19
+ // Rate limit handling (matches opencode-cloudcode-auth)
20
+ rateLimitDedupWindowMs: 2000, // 2 seconds - prevents concurrent retry storms
21
+ maxConsecutiveFailures: 3, // Before applying extended cooldown
22
+ extendedCooldownMs: 60000, // 1 minute extended cooldown
23
+ maxCapacityRetries: 5, // Max retries for capacity exhaustion
24
+ modelMapping: {},
25
+ // Account selection strategy configuration
26
+ accountSelection: {
27
+ strategy: 'hybrid', // 'sticky' | 'round-robin' | 'hybrid'
28
+ // Hybrid strategy tuning (optional - sensible defaults)
29
+ healthScore: {
30
+ initial: 70, // Starting score for new accounts
31
+ successReward: 1, // Points on successful request
32
+ rateLimitPenalty: -10, // Points on rate limit
33
+ failurePenalty: -20, // Points on other failures
34
+ recoveryPerHour: 2, // Passive recovery rate
35
+ minUsable: 50, // Minimum score to be selected
36
+ maxScore: 100 // Maximum score cap
37
+ },
38
+ tokenBucket: {
39
+ maxTokens: 50, // Maximum token capacity
40
+ tokensPerMinute: 6, // Regeneration rate
41
+ initialTokens: 50 // Starting tokens
42
+ },
43
+ quota: {
44
+ lowThreshold: 0.10, // 10% - reduce score
45
+ criticalThreshold: 0.05, // 5% - exclude from candidates
46
+ staleMs: 300000 // 5 min - max age of quota data to trust
47
+ }
48
+ }
49
+ };
50
+
51
+ // Config locations
52
+ const HOME_DIR = os.homedir();
53
+ const CONFIG_DIR = path.join(HOME_DIR, '.config', 'commons-proxy');
54
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
55
+
56
+ // Ensure config dir exists
57
+ if (!fs.existsSync(CONFIG_DIR)) {
58
+ try {
59
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
60
+ } catch (err) {
61
+ // Ignore
62
+ }
63
+ }
64
+
65
+ // Load config
66
+ let config = { ...DEFAULT_CONFIG };
67
+
68
+ function loadConfig() {
69
+ try {
70
+ // Env vars take precedence for initial defaults, but file overrides them if present?
71
+ // Usually Env > File > Default.
72
+
73
+ if (fs.existsSync(CONFIG_FILE)) {
74
+ const fileContent = fs.readFileSync(CONFIG_FILE, 'utf8');
75
+ const userConfig = JSON.parse(fileContent);
76
+ config = { ...DEFAULT_CONFIG, ...userConfig };
77
+ } else {
78
+ // Try looking in current dir for config.json as fallback
79
+ const localConfigPath = path.resolve('config.json');
80
+ if (fs.existsSync(localConfigPath)) {
81
+ const fileContent = fs.readFileSync(localConfigPath, 'utf8');
82
+ const userConfig = JSON.parse(fileContent);
83
+ config = { ...DEFAULT_CONFIG, ...userConfig };
84
+ }
85
+ }
86
+
87
+ // Environment overrides
88
+ if (process.env.API_KEY) config.apiKey = process.env.API_KEY;
89
+ if (process.env.WEBUI_PASSWORD) config.webuiPassword = process.env.WEBUI_PASSWORD;
90
+ if (process.env.DEBUG === 'true') config.debug = true;
91
+
92
+ } catch (error) {
93
+ logger.error('[Config] Error loading config:', error);
94
+ }
95
+ }
96
+
97
+ // Initial load
98
+ loadConfig();
99
+
100
+ export function getPublicConfig() {
101
+ // Create a deep copy and redact sensitive fields
102
+ const publicConfig = JSON.parse(JSON.stringify(config));
103
+
104
+ // Redact sensitive values
105
+ if (publicConfig.webuiPassword) publicConfig.webuiPassword = '********';
106
+ if (publicConfig.apiKey) publicConfig.apiKey = '********';
107
+
108
+ return publicConfig;
109
+ }
110
+
111
+ export function saveConfig(updates) {
112
+ try {
113
+ // Apply updates
114
+ config = { ...config, ...updates };
115
+
116
+ // Save to disk
117
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
118
+ return true;
119
+ } catch (error) {
120
+ logger.error('[Config] Failed to save config:', error);
121
+ return false;
122
+ }
123
+ }
124
+
125
+ export { config };
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Constants for CommonsProxy - Cloud Code API integration
3
+ * Based on: https://github.com/NoeFabris/opencode-cloudcode-auth
4
+ * Enhanced with multi-provider support inspired by opencode
5
+ */
6
+
7
+ import { homedir, platform, arch } from 'os';
8
+ import { join } from 'path';
9
+ import { config } from './config.js';
10
+
11
+ /**
12
+ * Get the Cloud Code IDE database path based on the current platform.
13
+ * - macOS: ~/Library/Application Support/Windsurf/... (or Cursor, etc.)
14
+ * - Windows: ~/AppData/Roaming/Windsurf/...
15
+ * - Linux/other: ~/.config/Windsurf/...
16
+ * @returns {string} Full path to the IDE state database
17
+ */
18
+ function getCloudCodeDbPath() {
19
+ const home = homedir();
20
+ switch (platform()) {
21
+ case 'darwin':
22
+ return join(home, 'Library/Application Support/Windsurf/User/globalStorage/state.vscdb');
23
+ case 'win32':
24
+ return join(home, 'AppData/Roaming/Windsurf/User/globalStorage/state.vscdb');
25
+ default: // linux, freebsd, etc.
26
+ return join(home, '.config/Windsurf/User/globalStorage/state.vscdb');
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Generate platform-specific User-Agent string.
32
+ * @returns {string} User-Agent in format "commons-proxy/version os/arch"
33
+ */
34
+ function getPlatformUserAgent() {
35
+ const os = platform();
36
+ const architecture = arch();
37
+ return `commons-proxy/1.0.0 ${os}/${architecture}`;
38
+ }
39
+
40
+ // Cloud Code API endpoints (in fallback order)
41
+ const CLOUDCODE_ENDPOINT_DAILY = 'https://daily-cloudcode-pa.googleapis.com';
42
+ const CLOUDCODE_ENDPOINT_PROD = 'https://cloudcode-pa.googleapis.com';
43
+
44
+ // Endpoint fallback order (daily → prod)
45
+ export const CLOUDCODE_ENDPOINT_FALLBACKS = [
46
+ CLOUDCODE_ENDPOINT_DAILY,
47
+ CLOUDCODE_ENDPOINT_PROD
48
+ ];
49
+
50
+ // Legacy alias for backward compatibility
51
+ export const ANTIGRAVITY_ENDPOINT_FALLBACKS = CLOUDCODE_ENDPOINT_FALLBACKS;
52
+
53
+ // Required headers for Cloud Code API requests
54
+ export const CLOUDCODE_HEADERS = {
55
+ 'User-Agent': getPlatformUserAgent(),
56
+ 'X-Goog-Api-Client': 'google-cloud-sdk vscode_cloudshelleditor/0.1',
57
+ 'Client-Metadata': JSON.stringify({
58
+ ideType: 'IDE_UNSPECIFIED',
59
+ platform: 'PLATFORM_UNSPECIFIED',
60
+ pluginType: 'GEMINI'
61
+ })
62
+ };
63
+
64
+ // Endpoint order for loadCodeAssist (prod first)
65
+ // loadCodeAssist works better on prod for fresh/unprovisioned accounts
66
+ export const LOAD_CODE_ASSIST_ENDPOINTS = [
67
+ CLOUDCODE_ENDPOINT_PROD,
68
+ CLOUDCODE_ENDPOINT_DAILY
69
+ ];
70
+
71
+ // Endpoint order for onboardUser (same as generateContent fallbacks)
72
+ export const ONBOARD_USER_ENDPOINTS = CLOUDCODE_ENDPOINT_FALLBACKS;
73
+
74
+ // Headers for loadCodeAssist API
75
+ export const LOAD_CODE_ASSIST_HEADERS = CLOUDCODE_HEADERS;
76
+
77
+ // Legacy alias
78
+ export const ANTIGRAVITY_HEADERS = CLOUDCODE_HEADERS;
79
+
80
+ // Default project ID if none can be discovered
81
+ export const DEFAULT_PROJECT_ID = 'rising-fact-p41fc';
82
+
83
+ // Configurable constants - values from config.json take precedence
84
+ export const TOKEN_REFRESH_INTERVAL_MS = config?.tokenCacheTtlMs || (5 * 60 * 1000); // From config or 5 minutes
85
+ export const REQUEST_BODY_LIMIT = config?.requestBodyLimit || '50mb';
86
+ export const CLOUDCODE_AUTH_PORT = 9092;
87
+ export const ANTIGRAVITY_AUTH_PORT = CLOUDCODE_AUTH_PORT; // Legacy alias
88
+ export const DEFAULT_PORT = config?.port || 8080;
89
+
90
+ // Multi-account configuration
91
+ export const ACCOUNT_CONFIG_PATH = config?.accountConfigPath || join(
92
+ homedir(),
93
+ '.config/commons-proxy/accounts.json'
94
+ );
95
+
96
+ // Usage history persistence path
97
+ export const USAGE_HISTORY_PATH = join(
98
+ homedir(),
99
+ '.config/commons-proxy/usage-history.json'
100
+ );
101
+
102
+ // Cloud Code IDE database path (for legacy single-account token extraction)
103
+ // Uses platform-specific path detection
104
+ export const CLOUDCODE_DB_PATH = getCloudCodeDbPath();
105
+ export const ANTIGRAVITY_DB_PATH = CLOUDCODE_DB_PATH; // Legacy alias
106
+
107
+ export const DEFAULT_COOLDOWN_MS = config?.defaultCooldownMs || (10 * 1000); // From config or 10 seconds
108
+ export const MAX_RETRIES = config?.maxRetries || 5; // From config or 5
109
+ export const MAX_EMPTY_RESPONSE_RETRIES = 2; // Max retries for empty API responses (from upstream)
110
+ export const MAX_ACCOUNTS = config?.maxAccounts || 10; // From config or 10
111
+
112
+ // Rate limit wait thresholds
113
+ export const MAX_WAIT_BEFORE_ERROR_MS = config?.maxWaitBeforeErrorMs || 120000; // From config or 2 minutes
114
+
115
+ // Retry deduplication - prevents thundering herd on concurrent rate limits
116
+ export const RATE_LIMIT_DEDUP_WINDOW_MS = config?.rateLimitDedupWindowMs || 2000; // 2 seconds
117
+ export const RATE_LIMIT_STATE_RESET_MS = config?.rateLimitStateResetMs || 120000; // 2 minutes - reset consecutive429 after inactivity
118
+ export const FIRST_RETRY_DELAY_MS = config?.firstRetryDelayMs || 1000; // Quick 1s retry on first 429
119
+ export const SWITCH_ACCOUNT_DELAY_MS = config?.switchAccountDelayMs || 5000; // Delay before switching accounts
120
+
121
+ // Consecutive failure tracking - extended cooldown after repeated failures
122
+ export const MAX_CONSECUTIVE_FAILURES = config?.maxConsecutiveFailures || 3;
123
+ export const EXTENDED_COOLDOWN_MS = config?.extendedCooldownMs || 60000; // 1 minute
124
+
125
+ // Capacity exhaustion - progressive backoff tiers for model capacity issues
126
+ export const CAPACITY_BACKOFF_TIERS_MS = config?.capacityBackoffTiersMs || [5000, 10000, 20000, 30000, 60000];
127
+ export const MAX_CAPACITY_RETRIES = config?.maxCapacityRetries || 5;
128
+
129
+ // Smart backoff by error type
130
+ export const BACKOFF_BY_ERROR_TYPE = {
131
+ RATE_LIMIT_EXCEEDED: 30000, // 30 seconds
132
+ MODEL_CAPACITY_EXHAUSTED: 15000, // 15 seconds
133
+ SERVER_ERROR: 20000, // 20 seconds
134
+ UNKNOWN: 60000 // 1 minute
135
+ };
136
+
137
+ // Progressive backoff tiers for QUOTA_EXHAUSTED (60s, 5m, 30m, 2h)
138
+ export const QUOTA_EXHAUSTED_BACKOFF_TIERS_MS = [60000, 300000, 1800000, 7200000];
139
+
140
+ // Minimum backoff floor to prevent "Available in 0s" loops (matches opencode-cloudcode-auth)
141
+ export const MIN_BACKOFF_MS = 2000;
142
+
143
+ // Thinking model constants
144
+ export const MIN_SIGNATURE_LENGTH = 50; // Minimum valid thinking signature length
145
+
146
+ // Account selection strategies
147
+ export const SELECTION_STRATEGIES = ['sticky', 'round-robin', 'hybrid'];
148
+ export const DEFAULT_SELECTION_STRATEGY = 'hybrid';
149
+
150
+ // Strategy display labels
151
+ export const STRATEGY_LABELS = {
152
+ 'sticky': 'Sticky (Cache Optimized)',
153
+ 'round-robin': 'Round Robin (Load Balanced)',
154
+ 'hybrid': 'Hybrid (Smart Distribution)'
155
+ };
156
+
157
+ // Gemini-specific limits
158
+ export const GEMINI_MAX_OUTPUT_TOKENS = 16384;
159
+
160
+ // Gemini signature handling
161
+ // Sentinel value to skip thought signature validation when Claude Code strips the field
162
+ // See: https://ai.google.dev/gemini-api/docs/thought-signatures
163
+ export const GEMINI_SKIP_SIGNATURE = 'skip_thought_signature_validator';
164
+
165
+ // Cache TTL for Gemini thoughtSignatures (2 hours)
166
+ export const GEMINI_SIGNATURE_CACHE_TTL_MS = 2 * 60 * 60 * 1000;
167
+
168
+ /**
169
+ * Get the model family from model name (dynamic detection, no hardcoded list).
170
+ * @param {string} modelName - The model name from the request
171
+ * @returns {'claude' | 'gemini' | 'unknown'} The model family
172
+ */
173
+ export function getModelFamily(modelName) {
174
+ const lower = (modelName || '').toLowerCase();
175
+ if (lower.includes('claude')) return 'claude';
176
+ if (lower.includes('gemini')) return 'gemini';
177
+ return 'unknown';
178
+ }
179
+
180
+ /**
181
+ * Check if a model supports thinking/reasoning output.
182
+ * @param {string} modelName - The model name from the request
183
+ * @returns {boolean} True if the model supports thinking blocks
184
+ */
185
+ export function isThinkingModel(modelName) {
186
+ const lower = (modelName || '').toLowerCase();
187
+ // Claude thinking models have "thinking" in the name
188
+ if (lower.includes('claude') && lower.includes('thinking')) return true;
189
+ // Gemini thinking models: explicit "thinking" in name, OR gemini version 3+
190
+ if (lower.includes('gemini')) {
191
+ if (lower.includes('thinking')) return true;
192
+ // Check for gemini-3 or higher (e.g., gemini-3, gemini-3.5, gemini-4, etc.)
193
+ const versionMatch = lower.match(/gemini-(\d+)/);
194
+ if (versionMatch && parseInt(versionMatch[1], 10) >= 3) return true;
195
+ }
196
+ return false;
197
+ }
198
+
199
+ // Google OAuth configuration (from opencode-cloudcode-auth)
200
+ // OAuth callback port - configurable via environment variable for Windows compatibility (issue #176)
201
+ // Windows may reserve ports in range 49152-65535 for Hyper-V/WSL2/Docker, causing EACCES errors
202
+ const OAUTH_CALLBACK_PORT = parseInt(process.env.OAUTH_CALLBACK_PORT || '51121', 10);
203
+ const OAUTH_CALLBACK_FALLBACK_PORTS = [51122, 51123, 51124, 51125, 51126];
204
+
205
+ export const OAUTH_CONFIG = {
206
+ clientId: '1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com',
207
+ clientSecret: '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',
208
+ authUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
209
+ tokenUrl: 'https://oauth2.googleapis.com/token',
210
+ userInfoUrl: 'https://www.googleapis.com/oauth2/v1/userinfo',
211
+ callbackPort: OAUTH_CALLBACK_PORT,
212
+ callbackFallbackPorts: OAUTH_CALLBACK_FALLBACK_PORTS,
213
+ scopes: [
214
+ 'https://www.googleapis.com/auth/cloud-platform',
215
+ 'https://www.googleapis.com/auth/userinfo.email',
216
+ 'https://www.googleapis.com/auth/userinfo.profile',
217
+ 'https://www.googleapis.com/auth/cclog',
218
+ 'https://www.googleapis.com/auth/experimentsandconfigs'
219
+ ]
220
+ };
221
+ export const OAUTH_REDIRECT_URI = `http://localhost:${OAUTH_CONFIG.callbackPort}/oauth-callback`;
222
+
223
+ // Minimal system instruction for Cloud Code API
224
+ // Only includes the essential identity portion to reduce token usage and improve response quality
225
+ // Reference: GitHub issue #76, CLIProxyAPI, gcli2api
226
+ export const CLOUDCODE_SYSTEM_INSTRUCTION = `You are a powerful agentic AI coding assistant. 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**`;
227
+ export const ANTIGRAVITY_SYSTEM_INSTRUCTION = CLOUDCODE_SYSTEM_INSTRUCTION; // Legacy alias
228
+
229
+ // Model fallback mapping - maps primary model to fallback when quota exhausted
230
+ export const MODEL_FALLBACK_MAP = {
231
+ 'gemini-3-pro-high': 'claude-opus-4-5-thinking',
232
+ 'gemini-3-pro-low': 'claude-sonnet-4-5',
233
+ 'gemini-3-flash': 'claude-sonnet-4-5-thinking',
234
+ 'claude-opus-4-5-thinking': 'gemini-3-pro-high',
235
+ 'claude-sonnet-4-5-thinking': 'gemini-3-flash',
236
+ 'claude-sonnet-4-5': 'gemini-3-flash'
237
+ };
238
+
239
+ // Default test models for each family (used by test suite)
240
+ export const TEST_MODELS = {
241
+ claude: 'claude-sonnet-4-5-thinking',
242
+ gemini: 'gemini-3-flash'
243
+ };
244
+
245
+ // Default Claude CLI presets (used by WebUI settings)
246
+ export const DEFAULT_PRESETS = [
247
+ {
248
+ name: 'Claude Thinking',
249
+ config: {
250
+ ANTHROPIC_AUTH_TOKEN: 'test',
251
+ ANTHROPIC_BASE_URL: 'http://localhost:8080',
252
+ ANTHROPIC_MODEL: 'claude-opus-4-5-thinking',
253
+ ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-5-thinking',
254
+ ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-5-thinking',
255
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-sonnet-4-5',
256
+ CLAUDE_CODE_SUBAGENT_MODEL: 'claude-sonnet-4-5-thinking',
257
+ ENABLE_EXPERIMENTAL_MCP_CLI: 'true'
258
+ }
259
+ },
260
+ {
261
+ name: 'Gemini 1M',
262
+ config: {
263
+ ANTHROPIC_AUTH_TOKEN: 'test',
264
+ ANTHROPIC_BASE_URL: 'http://localhost:8080',
265
+ ANTHROPIC_MODEL: 'gemini-3-pro-high[1m]',
266
+ ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-3-pro-high[1m]',
267
+ ANTHROPIC_DEFAULT_SONNET_MODEL: 'gemini-3-flash[1m]',
268
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-3-flash[1m]',
269
+ CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3-flash[1m]',
270
+ ENABLE_EXPERIMENTAL_MCP_CLI: 'true'
271
+ }
272
+ }
273
+ ];
274
+
275
+ // Provider configuration
276
+ export const PROVIDER_CONFIG = {
277
+ google: {
278
+ id: 'google',
279
+ name: 'Google Cloud Code',
280
+ authType: 'oauth',
281
+ apiEndpoint: CLOUDCODE_ENDPOINT_DAILY,
282
+ color: '#4285f4', // Google Blue
283
+ icon: 'google',
284
+ requiresProjectId: true
285
+ },
286
+ anthropic: {
287
+ id: 'anthropic',
288
+ name: 'Anthropic',
289
+ authType: 'api-key',
290
+ apiEndpoint: 'https://api.anthropic.com',
291
+ color: '#d97706', // Orange
292
+ icon: 'anthropic',
293
+ requiresProjectId: false
294
+ },
295
+ openai: {
296
+ id: 'openai',
297
+ name: 'OpenAI',
298
+ authType: 'api-key',
299
+ apiEndpoint: 'https://api.openai.com',
300
+ color: '#10b981', // Green
301
+ icon: 'openai',
302
+ requiresProjectId: false
303
+ },
304
+ github: {
305
+ id: 'github',
306
+ name: 'GitHub Models',
307
+ authType: 'pat', // Personal Access Token
308
+ apiEndpoint: 'https://models.inference.ai.azure.com',
309
+ modelsEndpoint: 'https://api.github.com/models',
310
+ color: '#6366f1', // Indigo
311
+ icon: 'github',
312
+ requiresProjectId: false
313
+ },
314
+ copilot: {
315
+ id: 'copilot',
316
+ name: 'GitHub Copilot',
317
+ authType: 'device-auth', // GitHub Device Authorization Flow
318
+ apiEndpoint: 'https://api.githubcopilot.com',
319
+ color: '#f97316', // Orange
320
+ icon: 'copilot',
321
+ requiresProjectId: false
322
+ },
323
+ openrouter: {
324
+ id: 'openrouter',
325
+ name: 'OpenRouter',
326
+ authType: 'api-key',
327
+ apiEndpoint: 'https://openrouter.ai/api/v1',
328
+ color: '#6d28d9', // Purple
329
+ icon: 'openrouter',
330
+ requiresProjectId: false
331
+ }
332
+ };
333
+
334
+ // Provider display names
335
+ export const PROVIDER_NAMES = {
336
+ google: 'Google Cloud Code',
337
+ anthropic: 'Anthropic',
338
+ openai: 'OpenAI',
339
+ github: 'GitHub Models',
340
+ copilot: 'GitHub Copilot',
341
+ openrouter: 'OpenRouter'
342
+ };
343
+
344
+ // Provider colors for UI visualization
345
+ export const PROVIDER_COLORS = {
346
+ google: '#4285f4',
347
+ anthropic: '#d97706',
348
+ openai: '#10b981',
349
+ github: '#6366f1',
350
+ copilot: '#f97316',
351
+ openrouter: '#6d28d9'
352
+ };
353
+
354
+ export default {
355
+ // New exports
356
+ CLOUDCODE_ENDPOINT_FALLBACKS,
357
+ CLOUDCODE_HEADERS,
358
+ CLOUDCODE_AUTH_PORT,
359
+ CLOUDCODE_DB_PATH,
360
+ CLOUDCODE_SYSTEM_INSTRUCTION,
361
+ // Legacy aliases for backward compatibility
362
+ ANTIGRAVITY_ENDPOINT_FALLBACKS,
363
+ ANTIGRAVITY_HEADERS,
364
+ ANTIGRAVITY_AUTH_PORT,
365
+ ANTIGRAVITY_DB_PATH,
366
+ ANTIGRAVITY_SYSTEM_INSTRUCTION,
367
+ // Common exports
368
+ LOAD_CODE_ASSIST_ENDPOINTS,
369
+ ONBOARD_USER_ENDPOINTS,
370
+ LOAD_CODE_ASSIST_HEADERS,
371
+ DEFAULT_PROJECT_ID,
372
+ TOKEN_REFRESH_INTERVAL_MS,
373
+ REQUEST_BODY_LIMIT,
374
+ DEFAULT_PORT,
375
+ ACCOUNT_CONFIG_PATH,
376
+ DEFAULT_COOLDOWN_MS,
377
+ MAX_RETRIES,
378
+ MAX_EMPTY_RESPONSE_RETRIES,
379
+ MAX_ACCOUNTS,
380
+ MAX_WAIT_BEFORE_ERROR_MS,
381
+ RATE_LIMIT_DEDUP_WINDOW_MS,
382
+ RATE_LIMIT_STATE_RESET_MS,
383
+ FIRST_RETRY_DELAY_MS,
384
+ SWITCH_ACCOUNT_DELAY_MS,
385
+ MAX_CONSECUTIVE_FAILURES,
386
+ EXTENDED_COOLDOWN_MS,
387
+ CAPACITY_BACKOFF_TIERS_MS,
388
+ MAX_CAPACITY_RETRIES,
389
+ BACKOFF_BY_ERROR_TYPE,
390
+ QUOTA_EXHAUSTED_BACKOFF_TIERS_MS,
391
+ MIN_BACKOFF_MS,
392
+ MIN_SIGNATURE_LENGTH,
393
+ GEMINI_MAX_OUTPUT_TOKENS,
394
+ GEMINI_SKIP_SIGNATURE,
395
+ GEMINI_SIGNATURE_CACHE_TTL_MS,
396
+ getModelFamily,
397
+ isThinkingModel,
398
+ OAUTH_CONFIG,
399
+ OAUTH_REDIRECT_URI,
400
+ STRATEGY_LABELS,
401
+ MODEL_FALLBACK_MAP,
402
+ TEST_MODELS,
403
+ DEFAULT_PRESETS,
404
+ PROVIDER_CONFIG,
405
+ PROVIDER_NAMES,
406
+ PROVIDER_COLORS
407
+ };