antigravity-claude-proxy 3.0.0 → 3.0.1
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.
- package/bin/cli.js +4 -11
- package/package.json +1 -1
- package/public/app.js +7 -4
- package/public/css/src/input.css +0 -7
- package/public/css/style.css +1 -1
- package/public/js/components/claude-config.js +0 -8
- package/public/js/components/dashboard/charts.js +8 -8
- package/public/js/components/dashboard/stats.js +1 -1
- package/public/js/components/logs-viewer.js +1 -1
- package/public/js/components/models.js +2 -3
- package/public/js/components/server-config.js +1 -9
- package/public/js/data-store.js +2 -2
- package/public/js/store.js +1 -1
- package/public/js/translations/en.js +0 -2
- package/public/js/translations/id.js +0 -1
- package/public/js/translations/pt.js +0 -1
- package/public/js/translations/tr.js +0 -2
- package/public/js/translations/zh.js +0 -2
- package/public/js/utils/error-handler.js +0 -2
- package/public/js/utils/ui-logger.js +4 -3
- package/src/account-manager/index.js +0 -4
- package/src/account-manager/rate-limits.js +0 -5
- package/src/account-manager/strategies/base-strategy.js +4 -4
- package/src/account-manager/strategies/hybrid-strategy.js +3 -3
- package/src/auth/database.js +1 -0
- package/src/auth/oauth.js +43 -41
- package/src/auth/token-extractor.js +1 -1
- package/src/cli/accounts.js +2 -1
- package/src/cloudcode/model-registry.js +0 -3
- package/src/cloudcode/rate-limit-state.js +1 -7
- package/src/config.js +1 -1
- package/src/constants.js +0 -2
- package/src/format/content-converter.js +0 -4
- package/src/format/request-converter.js +1 -6
- package/src/format/response-converter.js +0 -3
- package/src/format/schema-sanitizer.js +3 -22
- package/src/format/thinking-utils.js +1 -13
- package/src/index.js +1 -6
- package/src/modules/usage-stats.js +1 -1
- package/src/server.js +1 -28
- package/src/utils/claude-config.js +2 -6
- package/src/utils/native-module-helper.js +0 -4
- package/src/utils/proxy.js +1 -10
- package/src/utils/version-detector.js +14 -5
- package/src/webui/index.js +1 -37
|
@@ -51,7 +51,7 @@ export function convertAnthropicToGoogle(anthropicRequest) {
|
|
|
51
51
|
// before any other processing, following the pattern from Antigravity-Manager.
|
|
52
52
|
const messages = cleanCacheControl(anthropicRequest.messages || []);
|
|
53
53
|
|
|
54
|
-
const { system, max_tokens, temperature, top_p, top_k, stop_sequences, tools,
|
|
54
|
+
const { system, max_tokens, temperature, top_p, top_k, stop_sequences, tools, thinking } = anthropicRequest;
|
|
55
55
|
const modelName = anthropicRequest.model || '';
|
|
56
56
|
const modelFamily = getModelFamily(modelName);
|
|
57
57
|
const isClaudeModel = modelFamily === 'claude';
|
|
@@ -63,7 +63,6 @@ export function convertAnthropicToGoogle(anthropicRequest) {
|
|
|
63
63
|
generationConfig: {}
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
-
// Handle system instruction
|
|
67
66
|
if (system) {
|
|
68
67
|
let systemParts = [];
|
|
69
68
|
if (typeof system === 'string') {
|
|
@@ -126,7 +125,6 @@ export function convertAnthropicToGoogle(anthropicRequest) {
|
|
|
126
125
|
if ((msg.role === 'assistant' || msg.role === 'model') && Array.isArray(msgContent)) {
|
|
127
126
|
// First, try to restore signatures for unsigned thinking blocks from cache
|
|
128
127
|
msgContent = restoreThinkingSignatures(msgContent);
|
|
129
|
-
// Remove trailing unsigned thinking blocks
|
|
130
128
|
msgContent = removeTrailingThinkingBlocks(msgContent);
|
|
131
129
|
// Reorder: thinking first, then text, then tool_use
|
|
132
130
|
msgContent = reorderAssistantContent(msgContent);
|
|
@@ -228,13 +226,10 @@ export function convertAnthropicToGoogle(anthropicRequest) {
|
|
|
228
226
|
// Convert tools to Google format
|
|
229
227
|
if (tools && tools.length > 0) {
|
|
230
228
|
const functionDeclarations = tools.map((tool, idx) => {
|
|
231
|
-
// Extract name from various possible locations
|
|
232
229
|
const name = tool.name || tool.function?.name || tool.custom?.name || `tool-${idx}`;
|
|
233
230
|
|
|
234
|
-
// Extract description from various possible locations
|
|
235
231
|
const description = tool.description || tool.function?.description || tool.custom?.description || '';
|
|
236
232
|
|
|
237
|
-
// Extract schema from various possible locations
|
|
238
233
|
const schema = tool.input_schema
|
|
239
234
|
|| tool.function?.input_schema
|
|
240
235
|
|| tool.function?.parameters
|
|
@@ -15,7 +15,6 @@ import { cacheSignature, cacheThinkingSignature } from './signature-cache.js';
|
|
|
15
15
|
* @returns {Object} Anthropic format response
|
|
16
16
|
*/
|
|
17
17
|
export function convertGoogleToAnthropic(googleResponse, model) {
|
|
18
|
-
// Handle the response wrapper
|
|
19
18
|
const response = googleResponse.response || googleResponse;
|
|
20
19
|
|
|
21
20
|
const candidates = response.candidates || [];
|
|
@@ -29,7 +28,6 @@ export function convertGoogleToAnthropic(googleResponse, model) {
|
|
|
29
28
|
|
|
30
29
|
for (const part of parts) {
|
|
31
30
|
if (part.text !== undefined) {
|
|
32
|
-
// Handle thinking blocks
|
|
33
31
|
if (part.thought === true) {
|
|
34
32
|
const signature = part.thoughtSignature || '';
|
|
35
33
|
|
|
@@ -72,7 +70,6 @@ export function convertGoogleToAnthropic(googleResponse, model) {
|
|
|
72
70
|
anthropicContent.push(toolUseBlock);
|
|
73
71
|
hasToolCalls = true;
|
|
74
72
|
} else if (part.inlineData) {
|
|
75
|
-
// Handle image content from Google format
|
|
76
73
|
anthropicContent.push({
|
|
77
74
|
type: 'image',
|
|
78
75
|
source: {
|
|
@@ -163,7 +163,7 @@ function mergeAllOf(schema) {
|
|
|
163
163
|
|
|
164
164
|
// Merge properties (allOf properties override parent for same keys)
|
|
165
165
|
if (Object.keys(mergedProperties).length > 0) {
|
|
166
|
-
result.properties = { ...mergedProperties, ...
|
|
166
|
+
result.properties = { ...mergedProperties, ...result.properties };
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// Merge required
|
|
@@ -289,10 +289,6 @@ function flattenAnyOfOneOf(schema) {
|
|
|
289
289
|
return result;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
-
// ============================================================================
|
|
293
|
-
// Enhanced Schema Hints (for preserving semantic information)
|
|
294
|
-
// ============================================================================
|
|
295
|
-
|
|
296
292
|
/**
|
|
297
293
|
* Add hints for enum values (if ≤10 values).
|
|
298
294
|
* This preserves enum information in the description since Gemini
|
|
@@ -611,7 +607,6 @@ export function cleanSchema(schema) {
|
|
|
611
607
|
if (!schema || typeof schema !== 'object') return schema;
|
|
612
608
|
if (Array.isArray(schema)) return schema.map(cleanSchema);
|
|
613
609
|
|
|
614
|
-
// Phase 1: Convert $refs to hints
|
|
615
610
|
let result = convertRefsToHints(schema);
|
|
616
611
|
|
|
617
612
|
// Phase 1b: Add enum hints (preserves enum info in description)
|
|
@@ -632,7 +627,6 @@ export function cleanSchema(schema) {
|
|
|
632
627
|
// Phase 2c: Flatten type arrays and update required for nullable
|
|
633
628
|
result = flattenTypeArrays(result);
|
|
634
629
|
|
|
635
|
-
// Phase 3: Remove unsupported keywords
|
|
636
630
|
const unsupported = [
|
|
637
631
|
'additionalProperties', 'default', '$schema', '$defs',
|
|
638
632
|
'definitions', '$ref', '$id', '$comment', 'title',
|
|
@@ -652,7 +646,6 @@ export function cleanSchema(schema) {
|
|
|
652
646
|
}
|
|
653
647
|
}
|
|
654
648
|
|
|
655
|
-
// Phase 4: Final cleanup - recursively clean nested schemas and validate required
|
|
656
649
|
if (result.properties && typeof result.properties === 'object') {
|
|
657
650
|
const newProps = {};
|
|
658
651
|
for (const [key, value] of Object.entries(result.properties)) {
|
|
@@ -678,21 +671,11 @@ export function cleanSchema(schema) {
|
|
|
678
671
|
}
|
|
679
672
|
}
|
|
680
673
|
|
|
681
|
-
// Phase 5: Convert type to Google's uppercase format (STRING, OBJECT, ARRAY, etc.)
|
|
682
|
-
// Only convert at current level - nested types already converted by recursive cleanSchema calls
|
|
683
674
|
if (result.type && typeof result.type === 'string') {
|
|
684
675
|
result.type = toGoogleType(result.type);
|
|
685
676
|
}
|
|
686
677
|
|
|
687
|
-
//
|
|
688
|
-
// declare a single object `items` schema. Plain JSON Schema allows this
|
|
689
|
-
// to be omitted (`{ type: 'array' }` = "array of anything"), boolean
|
|
690
|
-
// (`items: true` = "any"), or tuple-form (`items: [...]`) - none of
|
|
691
|
-
// which the Cloud Code API accepts; it rejects the first two with
|
|
692
|
-
// "items: missing field". This runs after the items/properties
|
|
693
|
-
// recursion above (and after Phase 5's type conversion), so it applies
|
|
694
|
-
// at every nesting depth - fixing issue #368 (nested array schemas like
|
|
695
|
-
// `where.items.items` losing their innermost `items`).
|
|
678
|
+
// Cloud Code rejects ARRAY schemas without a single object `items` ("items: missing field"), issue #368.
|
|
696
679
|
if (result.type === 'ARRAY') {
|
|
697
680
|
if (!result.items || typeof result.items !== 'object') {
|
|
698
681
|
// Missing entirely, or a boolean schema like `items: true`.
|
|
@@ -713,9 +696,7 @@ export function cleanSchema(schema) {
|
|
|
713
696
|
}
|
|
714
697
|
}
|
|
715
698
|
|
|
716
|
-
//
|
|
717
|
-
// These can survive on the current node after anyOf/oneOf flattening
|
|
718
|
-
// picked a non-object option while the parent still carried them.
|
|
699
|
+
// Google rejects properties/required on non-OBJECT nodes, which anyOf/oneOf flattening can leave behind.
|
|
719
700
|
if (result.type !== 'OBJECT') {
|
|
720
701
|
delete result.properties;
|
|
721
702
|
delete result.required;
|
|
@@ -7,10 +7,6 @@ import { MIN_SIGNATURE_LENGTH } from '../constants.js';
|
|
|
7
7
|
import { getCachedSignature, getCachedSignatureFamily } from './signature-cache.js';
|
|
8
8
|
import { logger } from '../utils/logger.js';
|
|
9
9
|
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// Gemini Thinking Budget Limits (Issue #289)
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
10
|
// Max thinking budget per Gemini model version
|
|
15
11
|
// Gemini 2.5 Flash: max 24,576 (API error: "supported values are integers from 1 to 24576")
|
|
16
12
|
const GEMINI_THINKING_BUDGET_LIMITS = {
|
|
@@ -57,10 +53,6 @@ export function clampGeminiThinkingBudget(modelName, budget) {
|
|
|
57
53
|
return requestedBudget;
|
|
58
54
|
}
|
|
59
55
|
|
|
60
|
-
// ============================================================================
|
|
61
|
-
// Cache Control Cleaning (Issue #189)
|
|
62
|
-
// ============================================================================
|
|
63
|
-
|
|
64
56
|
/**
|
|
65
57
|
* Remove cache_control fields from all content blocks in messages.
|
|
66
58
|
* This is a critical fix for Issue #189 where Claude Code CLI sends cache_control
|
|
@@ -94,7 +86,7 @@ export function cleanCacheControl(messages) {
|
|
|
94
86
|
if (block.cache_control === undefined) return block;
|
|
95
87
|
|
|
96
88
|
// Create a shallow copy without cache_control
|
|
97
|
-
const { cache_control, ...cleanBlock } = block;
|
|
89
|
+
const { cache_control: _cacheControl, ...cleanBlock } = block;
|
|
98
90
|
removedCount++;
|
|
99
91
|
|
|
100
92
|
return cleanBlock;
|
|
@@ -431,10 +423,6 @@ export function reorderAssistantContent(content) {
|
|
|
431
423
|
return reordered;
|
|
432
424
|
}
|
|
433
425
|
|
|
434
|
-
// ============================================================================
|
|
435
|
-
// Thinking Recovery Functions
|
|
436
|
-
// ============================================================================
|
|
437
|
-
|
|
438
426
|
/**
|
|
439
427
|
* Check if a message has any VALID (signed) thinking blocks.
|
|
440
428
|
* Only counts thinking blocks that have valid signatures, not unsigned ones
|
package/src/index.js
CHANGED
|
@@ -10,14 +10,13 @@ import app, { accountManager } from './server.js';
|
|
|
10
10
|
import { DEFAULT_PORT } from './constants.js';
|
|
11
11
|
import { logger } from './utils/logger.js';
|
|
12
12
|
import { config } from './config.js';
|
|
13
|
-
import {
|
|
13
|
+
import { STRATEGY_NAMES } from './account-manager/strategies/index.js';
|
|
14
14
|
import { getPackageVersion } from './utils/helpers.js';
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import os from 'os';
|
|
17
17
|
|
|
18
18
|
const packageVersion = getPackageVersion();
|
|
19
19
|
|
|
20
|
-
// Parse command line arguments
|
|
21
20
|
const args = process.argv.slice(2);
|
|
22
21
|
const isDebug = args.includes('--debug') || args.includes('--dev-mode') || process.env.DEBUG === 'true' || process.env.DEV_MODE === 'true';
|
|
23
22
|
const isFallbackEnabled = args.includes('--fallback') || process.env.FALLBACK === 'true';
|
|
@@ -31,13 +30,11 @@ for (let i = 0; i < args.length; i++) {
|
|
|
31
30
|
strategyOverride = args[i + 1];
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
|
-
// Validate strategy
|
|
35
33
|
if (strategyOverride && !STRATEGY_NAMES.includes(strategyOverride.toLowerCase())) {
|
|
36
34
|
logger.warn(`[Startup] Invalid strategy "${strategyOverride}". Valid options: ${STRATEGY_NAMES.join(', ')}. Using default.`);
|
|
37
35
|
strategyOverride = null;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
// Initialize logger and devMode
|
|
41
38
|
logger.setDebug(isDebug);
|
|
42
39
|
|
|
43
40
|
if (isDebug) {
|
|
@@ -65,7 +62,6 @@ const HOME_DIR = os.homedir();
|
|
|
65
62
|
const CONFIG_DIR = path.join(HOME_DIR, '.antigravity-claude-proxy');
|
|
66
63
|
|
|
67
64
|
const server = app.listen(PORT, HOST, () => {
|
|
68
|
-
// Get actual bound address
|
|
69
65
|
const address = server.address();
|
|
70
66
|
const boundHost = typeof address === 'string' ? address : address.address;
|
|
71
67
|
const boundPort = typeof address === 'string' ? null : address.port;
|
|
@@ -78,7 +74,6 @@ const server = app.listen(PORT, HOST, () => {
|
|
|
78
74
|
const align = (text) => text + ' '.repeat(Math.max(0, 60 - text.length));
|
|
79
75
|
const align4 = (text) => text + ' '.repeat(Math.max(0, 58 - text.length));
|
|
80
76
|
|
|
81
|
-
// Build Control section dynamically
|
|
82
77
|
const strategyOptions = `(${STRATEGY_NAMES.join('/')})`;
|
|
83
78
|
const strategyLine2 = ' ' + strategyOptions;
|
|
84
79
|
let controlSection = '║ Control: ║\n';
|
package/src/server.js
CHANGED
|
@@ -46,7 +46,6 @@ export const accountManager = new AccountManager();
|
|
|
46
46
|
|
|
47
47
|
// Track initialization status
|
|
48
48
|
let isInitialized = false;
|
|
49
|
-
let initError = null;
|
|
50
49
|
let initPromise = null;
|
|
51
50
|
|
|
52
51
|
/**
|
|
@@ -65,7 +64,6 @@ async function ensureInitialized() {
|
|
|
65
64
|
const status = accountManager.getStatus();
|
|
66
65
|
logger.success(`[Server] Account pool initialized: ${status.summary}`);
|
|
67
66
|
} catch (error) {
|
|
68
|
-
initError = error;
|
|
69
67
|
initPromise = null; // Allow retry on failure
|
|
70
68
|
logger.error('[Server] Failed to initialize account manager:', error.message);
|
|
71
69
|
throw error;
|
|
@@ -116,7 +114,6 @@ app.use('/v1', (req, res, next) => {
|
|
|
116
114
|
next();
|
|
117
115
|
});
|
|
118
116
|
|
|
119
|
-
// Setup usage statistics middleware
|
|
120
117
|
usageStats.setupMiddleware(app);
|
|
121
118
|
|
|
122
119
|
/**
|
|
@@ -125,11 +122,9 @@ usageStats.setupMiddleware(app);
|
|
|
125
122
|
* Using app.use instead of app.post for earlier middleware interception
|
|
126
123
|
*/
|
|
127
124
|
app.use((req, res, next) => {
|
|
128
|
-
// Handle Claude Code event logging requests silently
|
|
129
125
|
if (req.method === 'POST' && req.path === '/api/event_logging/batch') {
|
|
130
126
|
return res.status(200).json({ status: 'ok' });
|
|
131
127
|
}
|
|
132
|
-
// Handle Claude Code root POST requests silently
|
|
133
128
|
if (req.method === 'POST' && req.path === '/') {
|
|
134
129
|
return res.status(200).json({ status: 'ok' });
|
|
135
130
|
}
|
|
@@ -178,7 +173,6 @@ function parseError(error) {
|
|
|
178
173
|
} else if (error.message.includes('PERMISSION_DENIED')) {
|
|
179
174
|
errorType = 'permission_error';
|
|
180
175
|
statusCode = 403;
|
|
181
|
-
errorMessage = errorMessage;
|
|
182
176
|
}
|
|
183
177
|
|
|
184
178
|
return { errorType, statusCode, errorMessage };
|
|
@@ -188,7 +182,6 @@ function parseError(error) {
|
|
|
188
182
|
app.use((req, res, next) => {
|
|
189
183
|
const start = Date.now();
|
|
190
184
|
|
|
191
|
-
// Log response on finish
|
|
192
185
|
res.on('finish', () => {
|
|
193
186
|
const duration = Date.now() - start;
|
|
194
187
|
const status = res.statusCode;
|
|
@@ -241,14 +234,12 @@ app.get('/health', async (req, res) => {
|
|
|
241
234
|
await ensureInitialized();
|
|
242
235
|
const start = Date.now();
|
|
243
236
|
|
|
244
|
-
// Get high-level status first
|
|
245
237
|
const status = accountManager.getStatus();
|
|
246
238
|
const allAccounts = accountManager.getAllAccounts();
|
|
247
239
|
|
|
248
240
|
// Fetch quotas for each account in parallel to get detailed model info
|
|
249
241
|
const accountDetails = await Promise.allSettled(
|
|
250
242
|
allAccounts.map(async (account) => {
|
|
251
|
-
// Check model-specific rate limits
|
|
252
243
|
const activeModelLimits = Object.entries(account.modelRateLimits || {})
|
|
253
244
|
.filter(([_, limit]) => limit.isRateLimited && limit.resetTime > Date.now());
|
|
254
245
|
const isRateLimited = activeModelLimits.length > 0;
|
|
@@ -306,7 +297,6 @@ app.get('/health', async (req, res) => {
|
|
|
306
297
|
})
|
|
307
298
|
);
|
|
308
299
|
|
|
309
|
-
// Process results
|
|
310
300
|
const detailedAccounts = accountDetails.map((result, index) => {
|
|
311
301
|
if (result.status === 'fulfilled') {
|
|
312
302
|
return result.value;
|
|
@@ -357,7 +347,6 @@ app.get('/account-limits', async (req, res) => {
|
|
|
357
347
|
const format = req.query.format || 'json';
|
|
358
348
|
const includeHistory = req.query.includeHistory === 'true';
|
|
359
349
|
|
|
360
|
-
// Fetch quotas for each account in parallel
|
|
361
350
|
const results = await Promise.allSettled(
|
|
362
351
|
allAccounts.map(async (account) => {
|
|
363
352
|
// Skip invalid accounts
|
|
@@ -373,13 +362,11 @@ app.get('/account-limits', async (req, res) => {
|
|
|
373
362
|
try {
|
|
374
363
|
const token = await accountManager.getTokenForAccount(account);
|
|
375
364
|
|
|
376
|
-
// Fetch subscription tier first to get project ID
|
|
377
365
|
const subscription = await getSubscriptionTier(token);
|
|
378
366
|
|
|
379
367
|
// Then fetch quotas with project ID for accurate quota info
|
|
380
368
|
const quotas = await getModelQuotas(token, subscription.projectId);
|
|
381
369
|
|
|
382
|
-
// Update account object with fresh data
|
|
383
370
|
account.subscription = {
|
|
384
371
|
tier: subscription.tier,
|
|
385
372
|
projectId: subscription.projectId,
|
|
@@ -424,7 +411,6 @@ app.get('/account-limits', async (req, res) => {
|
|
|
424
411
|
})
|
|
425
412
|
);
|
|
426
413
|
|
|
427
|
-
// Process results
|
|
428
414
|
const accountLimits = results.map((result, index) => {
|
|
429
415
|
if (result.status === 'fulfilled') {
|
|
430
416
|
return result.value;
|
|
@@ -448,16 +434,13 @@ app.get('/account-limits', async (req, res) => {
|
|
|
448
434
|
|
|
449
435
|
const sortedModels = Array.from(allModelIds).sort();
|
|
450
436
|
|
|
451
|
-
// Return ASCII table format
|
|
452
437
|
if (format === 'table') {
|
|
453
438
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
454
439
|
|
|
455
|
-
// Build table
|
|
456
440
|
const lines = [];
|
|
457
441
|
const timestamp = new Date().toLocaleString();
|
|
458
442
|
lines.push(`Account Limits (${timestamp})`);
|
|
459
443
|
|
|
460
|
-
// Get account status info
|
|
461
444
|
const status = accountManager.getStatus();
|
|
462
445
|
lines.push(`Accounts: ${status.total} total, ${status.available} available, ${status.rateLimited} rate-limited, ${status.invalid} invalid`);
|
|
463
446
|
lines.push('');
|
|
@@ -476,7 +459,6 @@ app.get('/account-limits', async (req, res) => {
|
|
|
476
459
|
const shortEmail = acc.email.split('@')[0].slice(0, 22);
|
|
477
460
|
const lastUsed = acc.lastUsed ? new Date(acc.lastUsed).toLocaleString() : 'never';
|
|
478
461
|
|
|
479
|
-
// Get status and error from accountLimits
|
|
480
462
|
const accLimit = accountLimits.find(a => a.email === acc.email);
|
|
481
463
|
let accStatus;
|
|
482
464
|
if (acc.isInvalid) {
|
|
@@ -498,7 +480,6 @@ app.get('/account-limits', async (req, res) => {
|
|
|
498
480
|
}
|
|
499
481
|
}
|
|
500
482
|
|
|
501
|
-
// Get reset time from quota API
|
|
502
483
|
const claudeModel = sortedModels.find(m => m.includes('claude'));
|
|
503
484
|
const quota = claudeModel && accLimit?.models?.[claudeModel];
|
|
504
485
|
const resetTime = quota?.resetTime
|
|
@@ -564,13 +545,11 @@ app.get('/account-limits', async (req, res) => {
|
|
|
564
545
|
return res.send(lines.join('\n'));
|
|
565
546
|
}
|
|
566
547
|
|
|
567
|
-
// Get account metadata from AccountManager
|
|
568
548
|
const accountStatus = accountManager.getStatus();
|
|
569
549
|
const accountMetadataMap = new Map(
|
|
570
550
|
accountStatus.accounts.map(a => [a.email, a])
|
|
571
551
|
);
|
|
572
552
|
|
|
573
|
-
// Build response data
|
|
574
553
|
const responseData = {
|
|
575
554
|
timestamp: new Date().toLocaleString(),
|
|
576
555
|
totalAccounts: allAccounts.length,
|
|
@@ -705,7 +684,6 @@ app.post('/v1/messages/count_tokens', (req, res) => {
|
|
|
705
684
|
* Main messages endpoint - Anthropic Messages API compatible
|
|
706
685
|
*/
|
|
707
686
|
|
|
708
|
-
|
|
709
687
|
/**
|
|
710
688
|
* Anthropic-compatible Messages API
|
|
711
689
|
* POST /v1/messages
|
|
@@ -744,7 +722,6 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
744
722
|
|
|
745
723
|
const modelId = requestedModel;
|
|
746
724
|
|
|
747
|
-
// Validate model ID before processing
|
|
748
725
|
const { account: validationAccount } = accountManager.selectAccount();
|
|
749
726
|
if (validationAccount) {
|
|
750
727
|
const token = await accountManager.getTokenForAccount(validationAccount);
|
|
@@ -763,7 +740,6 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
763
740
|
accountManager.resetAllRateLimits();
|
|
764
741
|
}
|
|
765
742
|
|
|
766
|
-
// Validate required fields
|
|
767
743
|
if (!messages || !Array.isArray(messages)) {
|
|
768
744
|
return res.status(400).json({
|
|
769
745
|
type: 'error',
|
|
@@ -779,7 +755,6 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
779
755
|
return res.json({});
|
|
780
756
|
}
|
|
781
757
|
|
|
782
|
-
// Build the request object
|
|
783
758
|
const request = {
|
|
784
759
|
model: modelId,
|
|
785
760
|
messages,
|
|
@@ -813,7 +788,6 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
813
788
|
// to ensure we don't send a 200 OK if the upstream fails immediately (e.g. 429/503).
|
|
814
789
|
|
|
815
790
|
try {
|
|
816
|
-
// Initialize the generator
|
|
817
791
|
const generator = sendMessageStream(request, accountManager, FALLBACK_ENABLED);
|
|
818
792
|
|
|
819
793
|
// BUFFERING STRATEGY:
|
|
@@ -872,7 +846,6 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
872
846
|
}
|
|
873
847
|
|
|
874
848
|
} else {
|
|
875
|
-
// Handle non-streaming response
|
|
876
849
|
const response = await sendMessage(request, accountManager, FALLBACK_ENABLED);
|
|
877
850
|
usageStats.track(response?.model || modelId);
|
|
878
851
|
res.json(response);
|
|
@@ -892,6 +865,7 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
892
865
|
await forceRefresh();
|
|
893
866
|
errorMessage = 'Token was expired and has been refreshed. Please retry your request.';
|
|
894
867
|
} catch (refreshError) {
|
|
868
|
+
logger.warn(`[API] Token refresh failed: ${refreshError.message}`);
|
|
895
869
|
errorMessage = 'Could not refresh token. Make sure Antigravity is running.';
|
|
896
870
|
}
|
|
897
871
|
}
|
|
@@ -924,7 +898,6 @@ app.post('/v1/messages', async (req, res) => {
|
|
|
924
898
|
usageStats.setupRoutes(app);
|
|
925
899
|
|
|
926
900
|
app.use((req, res) => {
|
|
927
|
-
// Log 404s
|
|
928
901
|
if (logger.isDebugEnabled) {
|
|
929
902
|
logger.debug(`[API] 404 Not Found: ${req.method} ${req.originalUrl}`);
|
|
930
903
|
}
|
|
@@ -83,7 +83,7 @@ export async function updateClaudeConfig(updates) {
|
|
|
83
83
|
try {
|
|
84
84
|
await fs.mkdir(configDir, { recursive: true });
|
|
85
85
|
} catch (error) {
|
|
86
|
-
|
|
86
|
+
logger.debug(`[ClaudeConfig] Could not create ${configDir}: ${error.message}`);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// 4. Write back to file
|
|
@@ -112,7 +112,7 @@ export async function replaceClaudeConfig(config) {
|
|
|
112
112
|
try {
|
|
113
113
|
await fs.mkdir(configDir, { recursive: true });
|
|
114
114
|
} catch (error) {
|
|
115
|
-
|
|
115
|
+
logger.debug(`[ClaudeConfig] Could not create ${configDir}: ${error.message}`);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
// 2. Write config directly (no merge)
|
|
@@ -153,10 +153,6 @@ function isObject(item) {
|
|
|
153
153
|
return (item && typeof item === 'object' && !Array.isArray(item));
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
// ==========================================
|
|
157
|
-
// Claude CLI Presets
|
|
158
|
-
// ==========================================
|
|
159
|
-
|
|
160
156
|
/**
|
|
161
157
|
* Get the path to the presets file
|
|
162
158
|
* @returns {string} Absolute path to claude-presets.json
|
|
@@ -64,14 +64,12 @@ export function rebuildModule(packagePath) {
|
|
|
64
64
|
try {
|
|
65
65
|
logger.info(`[NativeModule] Rebuilding native module at: ${packagePath}`);
|
|
66
66
|
|
|
67
|
-
// Run npm rebuild in the package directory
|
|
68
67
|
const output = execSync('npm rebuild', {
|
|
69
68
|
cwd: packagePath,
|
|
70
69
|
stdio: 'pipe', // Capture output instead of printing
|
|
71
70
|
timeout: 120000 // 2 minute timeout
|
|
72
71
|
});
|
|
73
72
|
|
|
74
|
-
// Log rebuild output for debugging
|
|
75
73
|
const outputStr = output?.toString().trim();
|
|
76
74
|
if (outputStr) {
|
|
77
75
|
logger.debug(`[NativeModule] Rebuild output:\n${outputStr}`);
|
|
@@ -140,7 +138,6 @@ export function clearRequireCache(modulePath, cache, visited = new Set()) {
|
|
|
140
138
|
}
|
|
141
139
|
}
|
|
142
140
|
|
|
143
|
-
// Remove from parent's children array
|
|
144
141
|
if (mod.parent && mod.parent.children) {
|
|
145
142
|
const idx = mod.parent.children.indexOf(mod);
|
|
146
143
|
if (idx !== -1) {
|
|
@@ -148,7 +145,6 @@ export function clearRequireCache(modulePath, cache, visited = new Set()) {
|
|
|
148
145
|
}
|
|
149
146
|
}
|
|
150
147
|
|
|
151
|
-
// Delete from cache
|
|
152
148
|
delete cache[modulePath];
|
|
153
149
|
}
|
|
154
150
|
|
package/src/utils/proxy.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* HTTP Proxy Support
|
|
3
|
-
*
|
|
4
|
-
* Configures global fetch to use HTTP proxy from environment variables.
|
|
5
|
-
* Supports: http_proxy, HTTP_PROXY, https_proxy, HTTPS_PROXY
|
|
6
|
-
*
|
|
7
|
-
* This module should be imported at the very beginning of the application
|
|
8
|
-
* entry point (src/index.js) before any fetch calls are made.
|
|
9
|
-
*/
|
|
10
|
-
|
|
1
|
+
// Routes global fetch through http(s)_proxy env vars. Import before any fetch call (see src/index.js).
|
|
11
2
|
import { ProxyAgent, setGlobalDispatcher } from 'undici';
|
|
12
3
|
import { logger } from './logger.js';
|
|
13
4
|
|
|
@@ -27,7 +27,7 @@ import { config } from '../config.js';
|
|
|
27
27
|
|
|
28
28
|
// Fallback for User-Agent version (ideVersion in product.json), used only when
|
|
29
29
|
// no installed Antigravity version is detected
|
|
30
|
-
const FALLBACK_USER_AGENT_VERSION = process.env.FALLBACK_ANTIGRAVITY_VERSION || '2.
|
|
30
|
+
const FALLBACK_USER_AGENT_VERSION = process.env.FALLBACK_ANTIGRAVITY_VERSION || '2.32.0';
|
|
31
31
|
|
|
32
32
|
// Detected versions must be above this to be used (older installs are ignored)
|
|
33
33
|
const MIN_DETECTED_USER_AGENT_VERSION = '2.0.3';
|
|
@@ -104,7 +104,7 @@ function getProductJson() {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
} catch (e) {
|
|
107
|
-
|
|
107
|
+
logDetectionFailure(`Reading ${p}`, e);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -112,6 +112,15 @@ function getProductJson() {
|
|
|
112
112
|
return null;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Debug-log a failed detection step (lazy import to avoid circular deps).
|
|
117
|
+
*/
|
|
118
|
+
function logDetectionFailure(step, err) {
|
|
119
|
+
import('./logger.js').then(({ logger }) => {
|
|
120
|
+
logger.debug(`[VersionDetector] ${step} failed: ${err?.message ?? err}`);
|
|
121
|
+
}).catch(() => {});
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
/**
|
|
116
125
|
* Log version detection results once at startup (lazy import to avoid circular deps).
|
|
117
126
|
*/
|
|
@@ -188,7 +197,7 @@ function getUserAgentVersionConfig() {
|
|
|
188
197
|
localVersion = getVersionWindows();
|
|
189
198
|
}
|
|
190
199
|
} catch (error) {
|
|
191
|
-
|
|
200
|
+
logDetectionFailure('OS version detection', error);
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
return resolveUserAgentVersion({ localVersion });
|
|
@@ -246,7 +255,7 @@ function getVersionMacos() {
|
|
|
246
255
|
return version;
|
|
247
256
|
}
|
|
248
257
|
} catch (e) {
|
|
249
|
-
|
|
258
|
+
logDetectionFailure('plutil', e);
|
|
250
259
|
}
|
|
251
260
|
return null;
|
|
252
261
|
}
|
|
@@ -273,7 +282,7 @@ function getVersionWindows() {
|
|
|
273
282
|
}
|
|
274
283
|
}
|
|
275
284
|
} catch (e) {
|
|
276
|
-
|
|
285
|
+
logDetectionFailure('PowerShell version lookup', e);
|
|
277
286
|
}
|
|
278
287
|
return null;
|
|
279
288
|
}
|