antigravity-claude-proxy 2.8.4 → 2.8.6

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/README.md CHANGED
@@ -183,9 +183,9 @@ Add this configuration:
183
183
  "ANTHROPIC_BASE_URL": "http://localhost:8080",
184
184
  "ANTHROPIC_MODEL": "claude-opus-4-6-thinking",
185
185
  "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-6-thinking",
186
- "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6-thinking",
186
+ "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-6",
187
187
  "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-sonnet-4-6",
188
- "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6-thinking",
188
+ "CLAUDE_CODE_SUBAGENT_MODEL": "claude-sonnet-4-6",
189
189
  "ENABLE_EXPERIMENTAL_MCP_CLI": "true"
190
190
  }
191
191
  }
@@ -198,11 +198,11 @@ Or to use Gemini models:
198
198
  "env": {
199
199
  "ANTHROPIC_AUTH_TOKEN": "test",
200
200
  "ANTHROPIC_BASE_URL": "http://localhost:8080",
201
- "ANTHROPIC_MODEL": "gemini-3.1-pro-high[1m]",
202
- "ANTHROPIC_DEFAULT_OPUS_MODEL": "gemini-3.1-pro-high[1m]",
203
- "ANTHROPIC_DEFAULT_SONNET_MODEL": "gemini-3-flash[1m]",
204
- "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gemini-3-flash[1m]",
205
- "CLAUDE_CODE_SUBAGENT_MODEL": "gemini-3-flash[1m]",
201
+ "ANTHROPIC_MODEL": "gemini-3.1-pro-low",
202
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "gemini-3.1-pro-low",
203
+ "ANTHROPIC_DEFAULT_SONNET_MODEL": "gemini-3.5-flash-low",
204
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gemini-3.5-flash-low",
205
+ "CLAUDE_CODE_SUBAGENT_MODEL": "gemini-3.5-flash-low",
206
206
  "ENABLE_EXPERIMENTAL_MCP_CLI": "true"
207
207
  }
208
208
  }
@@ -339,4 +339,4 @@ MIT
339
339
 
340
340
  ## Star History
341
341
 
342
- [![Star History Chart](https://api.star-history.com/svg?repos=badrisnarayanan/antigravity-claude-proxy&type=date&legend=top-left&cache-control=no-cache)](https://www.star-history.com/#badrisnarayanan/antigravity-claude-proxy&type=date&legend=top-left)
342
+ [![Star History Chart](https://star-history.dera.page/svg?repos=badrisnarayanan/antigravity-claude-proxy&type=date&legend=top-left&cache-control=no-cache)](https://star-history.dera.page/#badrisnarayanan/antigravity-claude-proxy&type=date&legend=top-left)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antigravity-claude-proxy",
3
- "version": "2.8.4",
3
+ "version": "2.8.6",
4
4
  "description": "Proxy server to use Antigravity's Claude models with Claude Code CLI",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -436,11 +436,11 @@ document.addEventListener('alpine:init', () => {
436
436
  _generatePlaceholderData() {
437
437
  const models = [
438
438
  'claude-opus-4-6-thinking',
439
- 'claude-sonnet-4-6-thinking',
440
439
  'claude-sonnet-4-6',
441
- 'gemini-3.1-pro-high',
442
- 'gemini-3.1-pro-low',
443
- 'gemini-3-flash'
440
+ 'gemini-3.8-flash-tiered',
441
+ 'gemini-3.6-flash-high',
442
+ 'gemini-3.6-flash-low',
443
+ 'gemini-3.5-flash-low'
444
444
  ];
445
445
 
446
446
  const tiers = ['ultra', 'pro', 'pro', 'free'];
@@ -33,6 +33,23 @@ function isSupportedModel(modelId) {
33
33
  return family === 'claude' || family === 'gemini';
34
34
  }
35
35
 
36
+ /**
37
+ * Whether a model id is an old Gemini generation (version below 3.5),
38
+ * hidden from the /v1/models listing in favor of the current line. Claude
39
+ * ids aren't versioned this way and are unaffected.
40
+ * @param {string} modelId
41
+ * @returns {boolean}
42
+ */
43
+ function isOldGemini(modelId) {
44
+ // 'gemini-pro-agent' carries no version number in its id at all - it's
45
+ // an unversioned duplicate alias of gemini-3.1-pro-high, so it's always
46
+ // old regardless of what the version regex below would say.
47
+ if (modelId === 'gemini-pro-agent') return true;
48
+
49
+ const match = modelId.match(/^gemini-(\d+(?:\.\d+)?)/);
50
+ return !!match && parseFloat(match[1]) < 3.5;
51
+ }
52
+
36
53
  /**
37
54
  * List available models in Anthropic API format
38
55
  * Fetches models dynamically from the Cloud Code API
@@ -46,8 +63,17 @@ export async function listModels(token) {
46
63
  return { object: 'list', data: [] };
47
64
  }
48
65
 
49
- const modelList = Object.entries(data.models)
50
- .filter(([modelId]) => isSupportedModel(modelId))
66
+ const supportedEntries = Object.entries(data.models).filter(([modelId]) => isSupportedModel(modelId));
67
+
68
+ // Warm the model validation cache with every supported id, unfiltered -
69
+ // isValidModel() (the actual request-time gate) must keep accepting an
70
+ // id a client already has configured even if it's hidden from the
71
+ // listing below.
72
+ modelCache.validModels = new Set(supportedEntries.map(([modelId]) => modelId));
73
+ modelCache.lastFetched = Date.now();
74
+
75
+ const modelList = supportedEntries
76
+ .filter(([modelId]) => !isOldGemini(modelId))
51
77
  .map(([modelId, modelData]) => ({
52
78
  id: modelId,
53
79
  object: 'model',
@@ -56,10 +82,6 @@ export async function listModels(token) {
56
82
  description: modelData.displayName || modelId
57
83
  }));
58
84
 
59
- // Warm the model validation cache
60
- modelCache.validModels = new Set(modelList.map(m => m.id));
61
- modelCache.lastFetched = Date.now();
62
-
63
85
  return {
64
86
  object: 'list',
65
87
  data: modelList
@@ -14,6 +14,48 @@ import {
14
14
  import { convertAnthropicToGoogle } from '../format/index.js';
15
15
  import { deriveSessionId } from './session-manager.js';
16
16
 
17
+ // cloudcode-pa returns an opaque 429 RESOURCE_EXHAUSTED (reported as "quota
18
+ // exhausted", even when quota remains) when a request's system prompt names a
19
+ // known third-party AI product — e.g. an agent whose identity line says it was
20
+ // "created by <vendor>". This is the same class of problem as the "Antigravity"
21
+ // identity handling above (issue #76), but for the *caller's* identity. We
22
+ // neutralize those strings in the caller-supplied system parts.
23
+ //
24
+ // Defaults cover agents commonly used with this proxy; extend or override with
25
+ // the ANTIGRAVITY_SCRUB_IDENTITY env var, formatted as a comma-separated list of
26
+ // "Term=>Replacement" pairs, e.g. "Nous Research=>the team,Hermes=>the assistant".
27
+ const DEFAULT_IDENTITY_SCRUB = [
28
+ ['Nous Research', 'the assistant team'],
29
+ ['Hermes Agent', 'the assistant'],
30
+ ['Hermes', 'the assistant']
31
+ ];
32
+
33
+ function parseIdentityScrubEnv(raw) {
34
+ if (!raw) return [];
35
+ return raw
36
+ .split(',')
37
+ .map((pair) => {
38
+ const idx = pair.indexOf('=>');
39
+ if (idx === -1) return null;
40
+ return [pair.slice(0, idx).trim(), pair.slice(idx + 2).trim()];
41
+ })
42
+ .filter((rule) => rule && rule[0].length > 0);
43
+ }
44
+
45
+ const IDENTITY_SCRUB_RULES = [
46
+ ...DEFAULT_IDENTITY_SCRUB,
47
+ ...parseIdentityScrubEnv(process.env.ANTIGRAVITY_SCRUB_IDENTITY)
48
+ ];
49
+
50
+ function scrubClientIdentity(text) {
51
+ if (typeof text !== 'string') return text;
52
+ let out = text;
53
+ for (const [term, replacement] of IDENTITY_SCRUB_RULES) {
54
+ out = out.split(term).join(replacement);
55
+ }
56
+ return out;
57
+ }
58
+
17
59
  /**
18
60
  * Build the wrapped request body for Cloud Code API
19
61
  *
@@ -37,11 +79,12 @@ export function buildCloudCodeRequest(anthropicRequest, projectId, accountEmail)
37
79
  { text: `Please ignore the following [ignore]${ANTIGRAVITY_SYSTEM_INSTRUCTION}[/ignore]` }
38
80
  ];
39
81
 
40
- // Append any existing system instructions from the request
82
+ // Append any existing system instructions from the request, scrubbing
83
+ // third-party AI product identities that trip cloudcode-pa's 429 (see above).
41
84
  if (googleRequest.systemInstruction && googleRequest.systemInstruction.parts) {
42
85
  for (const part of googleRequest.systemInstruction.parts) {
43
86
  if (part.text) {
44
- systemParts.push({ text: part.text });
87
+ systemParts.push({ text: scrubClientIdentity(part.text) });
45
88
  }
46
89
  }
47
90
  }
package/src/constants.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import { homedir, platform, arch } from 'os';
7
7
  import { join } from 'path';
8
8
  import { config } from './config.js';
9
- import { generateSmartUserAgent } from './utils/version-detector.js';
9
+ import { generateSmartUserAgent, getClientVersion } from './utils/version-detector.js';
10
10
 
11
11
  /**
12
12
  * Get the Antigravity database path based on the current platform.
@@ -104,7 +104,7 @@ export const ANTIGRAVITY_HEADERS = {
104
104
  'User-Agent': getPlatformUserAgent(),
105
105
  'Content-Type': 'application/json',
106
106
  'X-Client-Name': 'antigravity',
107
- 'X-Client-Version': '1.107.0', // Match product.json version
107
+ 'X-Client-Version': getClientVersion(),
108
108
  'x-goog-api-client': 'gl-node/18.18.2 fire/0.8.6 grpc/1.10.x' // Simulate Google Node.js client environment
109
109
  };
110
110
 
@@ -279,16 +279,15 @@ export const ANTIGRAVITY_SYSTEM_INSTRUCTION = `You are Antigravity, a powerful a
279
279
  export const MODEL_FALLBACK_MAP = {
280
280
  'gemini-3.1-pro-high': 'claude-opus-4-6-thinking',
281
281
  'gemini-3.1-pro-low': 'claude-sonnet-4-6',
282
- 'gemini-3-flash': 'claude-sonnet-4-6-thinking',
282
+ 'gemini-3-flash': 'claude-sonnet-4-6',
283
283
  'claude-opus-4-6-thinking': 'gemini-3.1-pro-high',
284
- 'claude-sonnet-4-6-thinking': 'gemini-3-flash',
285
284
  'claude-sonnet-4-6': 'gemini-3-flash'
286
285
  };
287
286
 
288
287
  // Default test models for each family (used by test suite)
289
288
  export const TEST_MODELS = {
290
- claude: 'claude-sonnet-4-6-thinking',
291
- gemini: 'gemini-3-flash'
289
+ claude: 'claude-sonnet-4-6',
290
+ gemini: 'gemini-3.8-flash-tiered'
292
291
  };
293
292
 
294
293
  // Default Claude CLI presets (used by WebUI settings)
@@ -300,9 +299,9 @@ export const DEFAULT_PRESETS = [
300
299
  ANTHROPIC_BASE_URL: 'http://localhost:8080',
301
300
  ANTHROPIC_MODEL: 'claude-opus-4-6-thinking',
302
301
  ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4-6-thinking',
303
- ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-6-thinking',
302
+ ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4-6',
304
303
  ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-sonnet-4-6',
305
- CLAUDE_CODE_SUBAGENT_MODEL: 'claude-sonnet-4-6-thinking',
304
+ CLAUDE_CODE_SUBAGENT_MODEL: 'claude-sonnet-4-6',
306
305
  ENABLE_EXPERIMENTAL_MCP_CLI: 'true'
307
306
  }
308
307
  },
@@ -311,11 +310,11 @@ export const DEFAULT_PRESETS = [
311
310
  config: {
312
311
  ANTHROPIC_AUTH_TOKEN: 'test',
313
312
  ANTHROPIC_BASE_URL: 'http://localhost:8080',
314
- ANTHROPIC_MODEL: 'gemini-3.1-pro-high',
315
- ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-3.1-pro-high',
316
- ANTHROPIC_DEFAULT_SONNET_MODEL: 'gemini-3.1-flash',
317
- ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-3.1-flash',
318
- CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3.1-flash',
313
+ ANTHROPIC_MODEL: 'gemini-3.1-pro-low',
314
+ ANTHROPIC_DEFAULT_OPUS_MODEL: 'gemini-3.1-pro-low',
315
+ ANTHROPIC_DEFAULT_SONNET_MODEL: 'gemini-3.5-flash-low',
316
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gemini-3.5-flash-low',
317
+ CLAUDE_CODE_SUBAGENT_MODEL: 'gemini-3.5-flash-low',
319
318
  ENABLE_EXPERIMENTAL_MCP_CLI: 'true'
320
319
  }
321
320
  }
@@ -669,5 +669,42 @@ export function cleanSchema(schema) {
669
669
  result.type = toGoogleType(result.type);
670
670
  }
671
671
 
672
+ // Phase 6: Google's protobuf-based schema requires every ARRAY type to
673
+ // declare a single object `items` schema. Plain JSON Schema allows this
674
+ // to be omitted (`{ type: 'array' }` = "array of anything"), boolean
675
+ // (`items: true` = "any"), or tuple-form (`items: [...]`) - none of
676
+ // which the Cloud Code API accepts; it rejects the first two with
677
+ // "items: missing field". This runs after the items/properties
678
+ // recursion above (and after Phase 5's type conversion), so it applies
679
+ // at every nesting depth - fixing issue #368 (nested array schemas like
680
+ // `where.items.items` losing their innermost `items`).
681
+ if (result.type === 'ARRAY') {
682
+ if (!result.items || typeof result.items !== 'object') {
683
+ // Missing entirely, or a boolean schema like `items: true`.
684
+ result.items = { type: 'STRING' };
685
+ } else if (Array.isArray(result.items)) {
686
+ // Tuple-form `items: [...]` - Google only supports one items
687
+ // schema, so collapse to the most informative entry.
688
+ let best = null;
689
+ let bestScore = -1;
690
+ for (const option of result.items) {
691
+ const score = scoreSchemaOption(option);
692
+ if (score > bestScore) {
693
+ bestScore = score;
694
+ best = option;
695
+ }
696
+ }
697
+ result.items = best || { type: 'STRING' };
698
+ }
699
+ }
700
+
701
+ // Phase 7: Google rejects `properties`/`required` on a non-OBJECT schema.
702
+ // These can survive on the current node after anyOf/oneOf flattening
703
+ // picked a non-object option while the parent still carried them.
704
+ if (result.type !== 'OBJECT') {
705
+ delete result.properties;
706
+ delete result.required;
707
+ }
708
+
672
709
  return result;
673
710
  }
@@ -1,24 +1,37 @@
1
1
  import { execSync } from 'child_process';
2
2
  import { platform, homedir } from 'os';
3
3
  import { join } from 'path';
4
- import { existsSync } from 'fs';
4
+ import { existsSync, readFileSync } from 'fs';
5
5
 
6
6
  /**
7
7
  * Intelligent Version Detection for Antigravity
8
- * Attempts to find the local installation and extract its version.
9
- * Falls back to hard-coded stable versions if detection fails.
8
+ *
9
+ * Detects versions from the local Antigravity installation's product.json.
10
+ * Two version values are tracked:
11
+ * - "version" field → X-Client-Version header (API version gate)
12
+ * - "ideVersion" field → User-Agent version string
13
+ *
14
+ * Detection priority (for each):
15
+ * 1. Environment variable override
16
+ * 2. product.json from local Antigravity app
17
+ * 3. OS-specific detection (macOS plist / Windows exe)
18
+ * 4. Hardcoded fallback
10
19
  */
11
20
 
12
- // Fallback constant (can be overridden via FALLBACK_ANTIGRAVITY_VERSION env var)
13
- const FALLBACK_ANTIGRAVITY_VERSION = process.env.FALLBACK_ANTIGRAVITY_VERSION || '1.23.2';
21
+ // Fallback for User-Agent version (ideVersion in product.json)
22
+ const FALLBACK_USER_AGENT_VERSION = process.env.FALLBACK_ANTIGRAVITY_VERSION || '2.0.3';
23
+
24
+ // Fallback for X-Client-Version (top-level "version" in product.json)
25
+ // Can be overridden via ANTIGRAVITY_CLIENT_VERSION_FALLBACK env var
26
+ const FALLBACK_CLIENT_VERSION = process.env.ANTIGRAVITY_CLIENT_VERSION_FALLBACK || '1.110.0';
14
27
 
15
- // Cache for the generated User-Agent string
16
28
  let cachedUserAgent = null;
29
+ let cachedClientVersion = null;
30
+ let cachedProductJson = undefined; // undefined = not yet attempted
31
+ let loggedVersionInfo = false;
17
32
 
18
33
  /**
19
34
  * Compares two semver-ish version strings (X.Y.Z).
20
- * @param {string} v1 - Version string 1
21
- * @param {string} v2 - Version string 2
22
35
  * @returns {boolean} True if v1 > v2
23
36
  */
24
37
  function isVersionHigher(v1, v2) {
@@ -35,15 +48,119 @@ function isVersionHigher(v1, v2) {
35
48
  }
36
49
 
37
50
  /**
38
- * Gets the version config (version, source)
51
+ * Returns platform-specific search paths for product.json.
52
+ */
53
+ function getProductJsonPaths() {
54
+ const os = platform();
55
+ const paths = [];
56
+
57
+ if (os === 'darwin') {
58
+ paths.push('/Applications/Antigravity.app/Contents/Resources/app/product.json');
59
+ paths.push(join(homedir(), 'Applications', 'Antigravity.app', 'Contents', 'Resources', 'app', 'product.json'));
60
+ } else if (os === 'win32') {
61
+ const localAppData = process.env.LOCALAPPDATA;
62
+ const programFiles = process.env.ProgramFiles || 'C:\\Program Files';
63
+ if (localAppData) {
64
+ paths.push(join(localAppData, 'Programs', 'Antigravity', 'resources', 'app', 'product.json'));
65
+ }
66
+ paths.push(join(programFiles, 'Antigravity', 'resources', 'app', 'product.json'));
67
+ } else {
68
+ paths.push('/usr/share/antigravity/resources/app/product.json');
69
+ paths.push('/opt/antigravity/resources/app/product.json');
70
+ paths.push('/opt/Antigravity/resources/app/product.json');
71
+ paths.push(join(homedir(), '.local', 'share', 'antigravity', 'resources', 'app', 'product.json'));
72
+ paths.push('/snap/antigravity/current/resources/app/product.json');
73
+ }
74
+
75
+ return paths;
76
+ }
77
+
78
+ /**
79
+ * Find and parse product.json from the local Antigravity installation.
80
+ * Caches the result after first attempt.
81
+ * @returns {Object|null} Parsed product.json or null
82
+ */
83
+ function getProductJson() {
84
+ if (cachedProductJson !== undefined) return cachedProductJson;
85
+
86
+ for (const p of getProductJsonPaths()) {
87
+ try {
88
+ if (existsSync(p)) {
89
+ const content = JSON.parse(readFileSync(p, 'utf8'));
90
+ if (content && (content.version || content.ideVersion)) {
91
+ cachedProductJson = content;
92
+ return content;
93
+ }
94
+ }
95
+ } catch (e) {
96
+ // Continue to next path
97
+ }
98
+ }
99
+
100
+ cachedProductJson = null;
101
+ return null;
102
+ }
103
+
104
+ /**
105
+ * Log version detection results once at startup (lazy import to avoid circular deps).
106
+ */
107
+ function logVersionInfo(version, source) {
108
+ if (loggedVersionInfo) return;
109
+ loggedVersionInfo = true;
110
+
111
+ import('./logger.js').then(({ logger }) => {
112
+ if (source === 'fallback') {
113
+ logger.warn(`X-Client-Version: using hardcoded fallback ${version} — product.json not found. Set ANTIGRAVITY_CLIENT_VERSION (exact version) or ANTIGRAVITY_CLIENT_VERSION_FALLBACK (fallback value) env var to override.`);
114
+ } else {
115
+ logger.debug(`X-Client-Version: ${version} (source: ${source})`);
116
+ }
117
+ }).catch(() => {});
118
+ }
119
+
120
+ /**
121
+ * Get the X-Client-Version value for API requests.
122
+ * Priority: ANTIGRAVITY_CLIENT_VERSION env var > product.json "version" > hardcoded fallback
123
+ * @returns {string} Version string (e.g. "1.110.0")
124
+ */
125
+ export function getClientVersion() {
126
+ if (cachedClientVersion) return cachedClientVersion;
127
+
128
+ if (process.env.ANTIGRAVITY_CLIENT_VERSION) {
129
+ cachedClientVersion = process.env.ANTIGRAVITY_CLIENT_VERSION;
130
+ logVersionInfo(cachedClientVersion, 'env');
131
+ return cachedClientVersion;
132
+ }
133
+
134
+ const product = getProductJson();
135
+ if (product?.version) {
136
+ cachedClientVersion = product.version;
137
+ logVersionInfo(cachedClientVersion, 'product.json');
138
+ return cachedClientVersion;
139
+ }
140
+
141
+ cachedClientVersion = FALLBACK_CLIENT_VERSION;
142
+ logVersionInfo(cachedClientVersion, 'fallback');
143
+ return cachedClientVersion;
144
+ }
145
+
146
+ /**
147
+ * Get the User-Agent version string.
148
+ * Priority: FALLBACK_ANTIGRAVITY_VERSION env var > product.json "ideVersion" > OS detection > fallback
39
149
  * @returns {{ version: string, source: string }}
40
150
  */
41
- function getVersionConfig() {
151
+ function getUserAgentVersionConfig() {
152
+ if (process.env.FALLBACK_ANTIGRAVITY_VERSION) {
153
+ return { version: process.env.FALLBACK_ANTIGRAVITY_VERSION, source: 'env' };
154
+ }
155
+
156
+ const product = getProductJson();
157
+ if (product?.ideVersion && isVersionHigher(product.ideVersion, FALLBACK_USER_AGENT_VERSION)) {
158
+ return { version: product.ideVersion, source: 'product.json' };
159
+ }
160
+
161
+ // OS-specific detection (legacy — reads app binary metadata directly)
42
162
  const os = platform();
43
163
  let detectedVersion = null;
44
- let finalVersion = FALLBACK_ANTIGRAVITY_VERSION;
45
- let source = 'fallback';
46
-
47
164
  try {
48
165
  if (os === 'darwin') {
49
166
  detectedVersion = getVersionMacos();
@@ -54,16 +171,11 @@ function getVersionConfig() {
54
171
  // Silently fail and use fallback
55
172
  }
56
173
 
57
- // Only use detected version if it's higher than the fallback version
58
- if (detectedVersion && isVersionHigher(detectedVersion, FALLBACK_ANTIGRAVITY_VERSION)) {
59
- finalVersion = detectedVersion;
60
- source = 'local';
174
+ if (detectedVersion && isVersionHigher(detectedVersion, FALLBACK_USER_AGENT_VERSION)) {
175
+ return { version: detectedVersion, source: 'local' };
61
176
  }
62
177
 
63
- return {
64
- version: finalVersion,
65
- source
66
- };
178
+ return { version: FALLBACK_USER_AGENT_VERSION, source: 'fallback' };
67
179
  }
68
180
 
69
181
  /**
@@ -74,11 +186,10 @@ function getVersionConfig() {
74
186
  export function generateSmartUserAgent() {
75
187
  if (cachedUserAgent) return cachedUserAgent;
76
188
 
77
- const { version } = getVersionConfig();
189
+ const { version } = getUserAgentVersionConfig();
78
190
  const os = platform();
79
191
  const architecture = process.arch;
80
192
 
81
- // Map Node.js platform names to binary-friendly names
82
193
  const osName = os === 'darwin' ? 'darwin' : (os === 'win32' ? 'win32' : 'linux');
83
194
 
84
195
  cachedUserAgent = `antigravity/${version} ${osName}/${architecture}`;
@@ -131,4 +242,3 @@ function getVersionWindows() {
131
242
  }
132
243
  return null;
133
244
  }
134
-