@cortexkit/pi-antigravity-auth 1.1.0 → 2.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/dist/convert.d.ts +11 -3
- package/dist/convert.d.ts.map +1 -1
- package/dist/credential-cache.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +312 -1793
- package/dist/index.js.map +4 -4
- package/dist/stream.d.ts +10 -3
- package/dist/stream.d.ts.map +1 -1
- package/package.json +6 -8
package/dist/index.js
CHANGED
|
@@ -1,1741 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var ENV_CONSOLE_LOG = "ANTIGRAVITY_CORE_CONSOLE_LOG";
|
|
9
|
-
var _sink = null;
|
|
10
|
-
function isTruthyFlag(flag) {
|
|
11
|
-
return flag === "1" || flag?.toLowerCase() === "true";
|
|
12
|
-
}
|
|
13
|
-
function isConsoleLogEnabled() {
|
|
14
|
-
return isTruthyFlag(process.env[ENV_CONSOLE_LOG]);
|
|
15
|
-
}
|
|
16
|
-
function writeConsoleLog(level, ...args) {
|
|
17
|
-
switch (level) {
|
|
18
|
-
case "debug":
|
|
19
|
-
console.debug(...args);
|
|
20
|
-
break;
|
|
21
|
-
case "info":
|
|
22
|
-
console.info(...args);
|
|
23
|
-
break;
|
|
24
|
-
case "warn":
|
|
25
|
-
console.warn(...args);
|
|
26
|
-
break;
|
|
27
|
-
case "error":
|
|
28
|
-
console.error(...args);
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function createLogger(module) {
|
|
33
|
-
const service = `antigravity.${module}`;
|
|
34
|
-
const log3 = (level, message, extra) => {
|
|
35
|
-
if (_sink) {
|
|
36
|
-
try {
|
|
37
|
-
_sink({ service, level, message, extra });
|
|
38
|
-
} catch {
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (isConsoleLogEnabled()) {
|
|
42
|
-
const prefix = `[${service}]`;
|
|
43
|
-
const args = extra ? [prefix, message, extra] : [prefix, message];
|
|
44
|
-
writeConsoleLog(level, ...args);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
return {
|
|
48
|
-
debug: (message, extra) => log3("debug", message, extra),
|
|
49
|
-
info: (message, extra) => log3("info", message, extra),
|
|
50
|
-
warn: (message, extra) => log3("warn", message, extra),
|
|
51
|
-
error: (message, extra) => log3("error", message, extra)
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ../core/src/fingerprint.ts
|
|
56
|
-
var AGY_CLI_VERSION = "1.1.5";
|
|
57
|
-
function normalizeHarnessPlatform(platform = process.platform) {
|
|
58
|
-
return platform === "win32" ? "windows" : platform || "unknown";
|
|
59
|
-
}
|
|
60
|
-
function normalizeHarnessArch(arch = process.arch) {
|
|
61
|
-
switch (arch) {
|
|
62
|
-
case "x64":
|
|
63
|
-
return "amd64";
|
|
64
|
-
case "ia32":
|
|
65
|
-
return "386";
|
|
66
|
-
default:
|
|
67
|
-
return arch || "unknown";
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function buildAntigravityHarnessUserAgent(version = AGY_CLI_VERSION, platform = process.platform, arch = process.arch, authMethod = "consumer") {
|
|
71
|
-
const osType = normalizeHarnessPlatform(platform);
|
|
72
|
-
const normalizedArch = normalizeHarnessArch(arch);
|
|
73
|
-
return `antigravity/cli/${version} (aidev_client; os_type=${osType}; arch=${normalizedArch}; auth_method=${authMethod})`;
|
|
74
|
-
}
|
|
75
|
-
function buildAntigravityHarnessLoadCodeAssistUserAgent(version = AGY_CLI_VERSION) {
|
|
76
|
-
return buildAntigravityHarnessUserAgent(version);
|
|
77
|
-
}
|
|
78
|
-
function buildAntigravityLoadCodeAssistMetadata() {
|
|
79
|
-
return { ideType: "ANTIGRAVITY" };
|
|
80
|
-
}
|
|
81
|
-
function buildAntigravityHarnessBootstrapHeaders(accessToken) {
|
|
82
|
-
return {
|
|
83
|
-
"User-Agent": buildAntigravityHarnessLoadCodeAssistUserAgent(),
|
|
84
|
-
Authorization: `Bearer ${accessToken}`,
|
|
85
|
-
"Content-Type": "application/json",
|
|
86
|
-
"Accept-Encoding": "gzip"
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// ../core/src/constants.ts
|
|
91
|
-
var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
|
|
92
|
-
var ANTIGRAVITY_CLIENT_SECRET = "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";
|
|
93
|
-
var ANTIGRAVITY_SCOPES = [
|
|
94
|
-
"https://www.googleapis.com/auth/cloud-platform",
|
|
95
|
-
"https://www.googleapis.com/auth/userinfo.email",
|
|
96
|
-
"https://www.googleapis.com/auth/userinfo.profile",
|
|
97
|
-
"https://www.googleapis.com/auth/cclog",
|
|
98
|
-
"https://www.googleapis.com/auth/experimentsandconfigs"
|
|
99
|
-
];
|
|
100
|
-
var ANTIGRAVITY_REDIRECT_URI = "http://localhost:51121/oauth-callback";
|
|
101
|
-
var ANTIGRAVITY_ENDPOINT_DAILY = "https://daily-cloudcode-pa.googleapis.com";
|
|
102
|
-
var ANTIGRAVITY_ENDPOINT_PROD = "https://cloudcode-pa.googleapis.com";
|
|
103
|
-
var ANTIGRAVITY_ENDPOINT_FALLBACKS = [
|
|
104
|
-
ANTIGRAVITY_ENDPOINT_DAILY,
|
|
105
|
-
ANTIGRAVITY_ENDPOINT_PROD
|
|
106
|
-
];
|
|
107
|
-
var ANTIGRAVITY_LOAD_ENDPOINTS = [
|
|
108
|
-
ANTIGRAVITY_ENDPOINT_DAILY,
|
|
109
|
-
ANTIGRAVITY_ENDPOINT_PROD
|
|
110
|
-
];
|
|
111
|
-
var ANTIGRAVITY_ENDPOINT = ANTIGRAVITY_ENDPOINT_DAILY;
|
|
112
|
-
var ANTIGRAVITY_DEFAULT_PROJECT_ID = "rising-fact-p41fc";
|
|
113
|
-
var ANTIGRAVITY_VERSION_FALLBACK = "1.18.3";
|
|
114
|
-
var ANTIGRAVITY_VERSION = ANTIGRAVITY_VERSION_FALLBACK;
|
|
115
|
-
var ANTIGRAVITY_HEADERS = {
|
|
116
|
-
"User-Agent": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Antigravity/${ANTIGRAVITY_VERSION} Chrome/138.0.7204.235 Electron/37.3.1 Safari/537.36`,
|
|
117
|
-
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
|
|
118
|
-
"Client-Metadata": `{"ideType":"ANTIGRAVITY","platform":"${process.platform === "win32" ? "WINDOWS" : "MACOS"}","pluginType":"GEMINI"}`
|
|
119
|
-
};
|
|
120
|
-
var GEMINI_CLI_HEADERS = {
|
|
121
|
-
"User-Agent": "google-api-nodejs-client/9.15.1",
|
|
122
|
-
"X-Goog-Api-Client": "gl-node/22.17.0",
|
|
123
|
-
"Client-Metadata": "ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI"
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// ../core/src/auth.ts
|
|
127
|
-
var ACCESS_TOKEN_EXPIRY_BUFFER_MS = 60 * 1e3;
|
|
128
|
-
function parseRefreshParts(refresh) {
|
|
129
|
-
const [refreshToken = "", projectId = "", managedProjectId = ""] = (refresh ?? "").split("|");
|
|
130
|
-
return {
|
|
131
|
-
refreshToken,
|
|
132
|
-
projectId: projectId || void 0,
|
|
133
|
-
managedProjectId: managedProjectId || void 0
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function formatRefreshParts(parts) {
|
|
137
|
-
const projectSegment = parts.projectId ?? "";
|
|
138
|
-
const base = `${parts.refreshToken}|${projectSegment}`;
|
|
139
|
-
return parts.managedProjectId ? `${base}|${parts.managedProjectId}` : base;
|
|
140
|
-
}
|
|
141
|
-
function calculateTokenExpiry(requestTimeMs, expiresInSeconds) {
|
|
142
|
-
const seconds = typeof expiresInSeconds === "number" ? expiresInSeconds : 3600;
|
|
143
|
-
if (isNaN(seconds) || seconds <= 0) {
|
|
144
|
-
return requestTimeMs;
|
|
145
|
-
}
|
|
146
|
-
return requestTimeMs + seconds * 1e3;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// ../core/src/agy-transport.ts
|
|
150
|
-
import * as net from "node:net";
|
|
151
|
-
import * as tls from "node:tls";
|
|
152
|
-
import { Buffer as Buffer2 } from "node:buffer";
|
|
153
|
-
import { PassThrough, Readable, Transform } from "node:stream";
|
|
154
|
-
import { createGunzip } from "node:zlib";
|
|
155
|
-
var DEFAULT_HTTPS_PORT = 443;
|
|
156
|
-
var DEFAULT_PROXY_PORT = 8080;
|
|
157
|
-
var DEFAULT_AGY_RESPONSE_HEADER_TIMEOUT_MS = 18e4;
|
|
158
|
-
var DEFAULT_AGY_IDLE_TIMEOUT_MS = 18e4;
|
|
159
|
-
function headersToRecord(headers) {
|
|
160
|
-
const result = {};
|
|
161
|
-
if (!headers) return result;
|
|
162
|
-
const normalized = new Headers(headers);
|
|
163
|
-
normalized.forEach((value, key) => {
|
|
164
|
-
result[key.toLowerCase()] = value;
|
|
165
|
-
});
|
|
166
|
-
return result;
|
|
167
|
-
}
|
|
168
|
-
function getHeader(headers, name) {
|
|
169
|
-
return headers[name.toLowerCase()];
|
|
170
|
-
}
|
|
171
|
-
function bodyToBuffer(body) {
|
|
172
|
-
if (body == null) return Buffer2.alloc(0);
|
|
173
|
-
if (typeof body === "string") return Buffer2.from(body);
|
|
174
|
-
if (body instanceof Uint8Array) return Buffer2.from(body);
|
|
175
|
-
if (body instanceof ArrayBuffer) return Buffer2.from(body);
|
|
176
|
-
throw new Error("agy transport only supports string/byte request bodies");
|
|
177
|
-
}
|
|
178
|
-
function shouldUseChunkedBody(url) {
|
|
179
|
-
return url.pathname.includes(":streamGenerateContent");
|
|
180
|
-
}
|
|
181
|
-
function buildAgyCliHeaderPairs(url, init = {}) {
|
|
182
|
-
const parsedUrl = new URL(url);
|
|
183
|
-
const headers = headersToRecord(init.headers);
|
|
184
|
-
const body = bodyToBuffer(init.body);
|
|
185
|
-
const host = parsedUrl.port ? `${parsedUrl.hostname}:${parsedUrl.port}` : parsedUrl.hostname;
|
|
186
|
-
const userAgent = getHeader(headers, "User-Agent") ?? buildAntigravityHarnessUserAgent();
|
|
187
|
-
const authorization = getHeader(headers, "Authorization");
|
|
188
|
-
const contentType = getHeader(headers, "Content-Type") ?? "application/json";
|
|
189
|
-
const acceptEncoding = getHeader(headers, "Accept-Encoding") ?? "gzip";
|
|
190
|
-
const chunked = shouldUseChunkedBody(parsedUrl);
|
|
191
|
-
const pairs = [
|
|
192
|
-
["Host", host],
|
|
193
|
-
["User-Agent", userAgent]
|
|
194
|
-
];
|
|
195
|
-
if (chunked) {
|
|
196
|
-
pairs.push(["Transfer-Encoding", "chunked"]);
|
|
197
|
-
} else {
|
|
198
|
-
pairs.push(["Content-Length", String(body.byteLength)]);
|
|
199
|
-
}
|
|
200
|
-
if (authorization) {
|
|
201
|
-
pairs.push(["Authorization", authorization]);
|
|
202
|
-
}
|
|
203
|
-
pairs.push(["Content-Type", contentType]);
|
|
204
|
-
pairs.push(["Accept-Encoding", acceptEncoding]);
|
|
205
|
-
return pairs;
|
|
206
|
-
}
|
|
207
|
-
function noProxyIncludes(hostname) {
|
|
208
|
-
const raw = process.env.NO_PROXY || process.env.no_proxy || "";
|
|
209
|
-
if (!raw) return false;
|
|
210
|
-
const host = hostname.toLowerCase();
|
|
211
|
-
return raw.split(",").map((entry) => entry.trim().toLowerCase()).some((entry) => {
|
|
212
|
-
if (!entry) return false;
|
|
213
|
-
if (entry === "*") return true;
|
|
214
|
-
if (entry.startsWith(".")) return host.endsWith(entry);
|
|
215
|
-
return host === entry || host.endsWith(`.${entry}`);
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
function getHttpsProxy(url) {
|
|
219
|
-
if (url.protocol !== "https:" || noProxyIncludes(url.hostname)) return void 0;
|
|
220
|
-
const rawProxy = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.ALL_PROXY || process.env.all_proxy;
|
|
221
|
-
if (!rawProxy) return void 0;
|
|
222
|
-
try {
|
|
223
|
-
return new URL(rawProxy);
|
|
224
|
-
} catch {
|
|
225
|
-
return void 0;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
function waitForHead(socket, timeoutMs, onTimeout) {
|
|
229
|
-
return new Promise((resolve, reject) => {
|
|
230
|
-
let buffer = Buffer2.alloc(0);
|
|
231
|
-
const timeout = setTimeout(() => {
|
|
232
|
-
onTimeout();
|
|
233
|
-
cleanup(() => reject(new Error(`Antigravity request timed out waiting for response headers after ${timeoutMs}ms`)));
|
|
234
|
-
}, timeoutMs);
|
|
235
|
-
const cleanup = (finish) => {
|
|
236
|
-
socket.off("data", onData);
|
|
237
|
-
socket.off("error", onError);
|
|
238
|
-
clearTimeout(timeout);
|
|
239
|
-
finish();
|
|
240
|
-
};
|
|
241
|
-
const onError = (error) => cleanup(() => reject(error));
|
|
242
|
-
const onData = (chunk) => {
|
|
243
|
-
buffer = Buffer2.concat([buffer, chunk]);
|
|
244
|
-
const marker = buffer.indexOf("\r\n\r\n");
|
|
245
|
-
if (marker === -1) return;
|
|
246
|
-
const head = buffer.subarray(0, marker).toString("latin1");
|
|
247
|
-
const leftover = buffer.subarray(marker + 4);
|
|
248
|
-
cleanup(() => resolve({ head, leftover }));
|
|
249
|
-
};
|
|
250
|
-
socket.on("data", onData);
|
|
251
|
-
socket.once("error", onError);
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
async function connectViaProxy(proxyUrl, targetUrl, timeoutMs, onDebug) {
|
|
255
|
-
const proxySocket = net.connect({
|
|
256
|
-
host: proxyUrl.hostname,
|
|
257
|
-
port: Number(proxyUrl.port || DEFAULT_PROXY_PORT)
|
|
258
|
-
});
|
|
259
|
-
await new Promise((resolve, reject) => {
|
|
260
|
-
const timeout = setTimeout(() => {
|
|
261
|
-
onDebug?.(`agy transport proxy connect timeout after ${timeoutMs}ms`);
|
|
262
|
-
proxySocket.destroy();
|
|
263
|
-
reject(new Error(`Antigravity request timed out connecting to HTTPS proxy after ${timeoutMs}ms`));
|
|
264
|
-
}, timeoutMs);
|
|
265
|
-
const cleanup = () => clearTimeout(timeout);
|
|
266
|
-
proxySocket.once("connect", () => {
|
|
267
|
-
cleanup();
|
|
268
|
-
resolve();
|
|
269
|
-
});
|
|
270
|
-
proxySocket.once("error", (error) => {
|
|
271
|
-
cleanup();
|
|
272
|
-
reject(error);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
const targetHost = targetUrl.hostname;
|
|
276
|
-
const targetPort = Number(targetUrl.port || DEFAULT_HTTPS_PORT);
|
|
277
|
-
const auth = proxyUrl.username ? `Proxy-Authorization: Basic ${Buffer2.from(`${decodeURIComponent(proxyUrl.username)}:${decodeURIComponent(proxyUrl.password)}`).toString("base64")}\r
|
|
278
|
-
` : "";
|
|
279
|
-
proxySocket.write(
|
|
280
|
-
`CONNECT ${targetHost}:${targetPort} HTTP/1.1\r
|
|
281
|
-
Host: ${targetHost}:${targetPort}\r
|
|
282
|
-
` + auth + "\r\n"
|
|
283
|
-
);
|
|
284
|
-
const { head, leftover } = await waitForHead(proxySocket, timeoutMs, () => {
|
|
285
|
-
onDebug?.(`agy transport proxy CONNECT response timeout after ${timeoutMs}ms`);
|
|
286
|
-
proxySocket.destroy();
|
|
287
|
-
});
|
|
288
|
-
if (!/^HTTP\/1\.[01] 2\d\d\b/.test(head)) {
|
|
289
|
-
proxySocket.destroy();
|
|
290
|
-
throw new Error(`Proxy CONNECT failed: ${head.split("\r\n")[0] ?? "unknown"}`);
|
|
291
|
-
}
|
|
292
|
-
if (leftover.length > 0) {
|
|
293
|
-
proxySocket.unshift(leftover);
|
|
294
|
-
}
|
|
295
|
-
return await new Promise((resolve, reject) => {
|
|
296
|
-
const tlsSocket = tls.connect({ socket: proxySocket, servername: targetHost });
|
|
297
|
-
const timeout = setTimeout(() => {
|
|
298
|
-
onDebug?.(`agy transport proxy TLS handshake timeout after ${timeoutMs}ms`);
|
|
299
|
-
tlsSocket.destroy();
|
|
300
|
-
reject(new Error(`Antigravity request timed out during proxy TLS handshake after ${timeoutMs}ms`));
|
|
301
|
-
}, timeoutMs);
|
|
302
|
-
const cleanup = () => clearTimeout(timeout);
|
|
303
|
-
tlsSocket.once("secureConnect", () => {
|
|
304
|
-
cleanup();
|
|
305
|
-
resolve(tlsSocket);
|
|
306
|
-
});
|
|
307
|
-
tlsSocket.once("error", (error) => {
|
|
308
|
-
cleanup();
|
|
309
|
-
reject(error);
|
|
310
|
-
});
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
async function connectDirect(targetUrl, timeoutMs, onDebug) {
|
|
314
|
-
return await new Promise((resolve, reject) => {
|
|
315
|
-
const socket = tls.connect({
|
|
316
|
-
host: targetUrl.hostname,
|
|
317
|
-
port: Number(targetUrl.port || DEFAULT_HTTPS_PORT),
|
|
318
|
-
servername: targetUrl.hostname
|
|
319
|
-
});
|
|
320
|
-
const timeout = setTimeout(() => {
|
|
321
|
-
onDebug?.(`agy transport TLS connect timeout after ${timeoutMs}ms`);
|
|
322
|
-
socket.destroy();
|
|
323
|
-
reject(new Error(`Antigravity request timed out connecting after ${timeoutMs}ms`));
|
|
324
|
-
}, timeoutMs);
|
|
325
|
-
const cleanup = () => clearTimeout(timeout);
|
|
326
|
-
socket.once("secureConnect", () => {
|
|
327
|
-
cleanup();
|
|
328
|
-
resolve(socket);
|
|
329
|
-
});
|
|
330
|
-
socket.once("error", (error) => {
|
|
331
|
-
cleanup();
|
|
332
|
-
reject(error);
|
|
333
|
-
});
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
async function connectTls(targetUrl, timeoutMs, onDebug) {
|
|
337
|
-
const proxyUrl = getHttpsProxy(targetUrl);
|
|
338
|
-
return proxyUrl ? await connectViaProxy(proxyUrl, targetUrl, timeoutMs, onDebug) : await connectDirect(targetUrl, timeoutMs, onDebug);
|
|
339
|
-
}
|
|
340
|
-
function serializeRequest(url, init, body) {
|
|
341
|
-
const method = init.method ?? "POST";
|
|
342
|
-
const path = `${url.pathname}${url.search}`;
|
|
343
|
-
const headerLines = buildAgyCliHeaderPairs(url.toString(), init).map(([key, value]) => `${key}: ${value}`).join("\r\n");
|
|
344
|
-
const head = Buffer2.from(`${method} ${path} HTTP/1.1\r
|
|
345
|
-
${headerLines}\r
|
|
346
|
-
\r
|
|
347
|
-
`);
|
|
348
|
-
if (body.byteLength === 0) {
|
|
349
|
-
return head;
|
|
350
|
-
}
|
|
351
|
-
if (!shouldUseChunkedBody(url)) {
|
|
352
|
-
return Buffer2.concat([head, body]);
|
|
353
|
-
}
|
|
354
|
-
return Buffer2.concat([
|
|
355
|
-
head,
|
|
356
|
-
Buffer2.from(`${body.byteLength.toString(16)}\r
|
|
357
|
-
`),
|
|
358
|
-
body,
|
|
359
|
-
Buffer2.from("\r\n0\r\n\r\n")
|
|
360
|
-
]);
|
|
361
|
-
}
|
|
362
|
-
function parseResponseHead(head) {
|
|
363
|
-
const lines = head.split("\r\n");
|
|
364
|
-
const statusLine = lines.shift() ?? "";
|
|
365
|
-
const match = /^HTTP\/1\.[01]\s+(\d{3})\s*(.*)$/.exec(statusLine);
|
|
366
|
-
if (!match) {
|
|
367
|
-
throw new Error(`Invalid HTTP response: ${statusLine}`);
|
|
368
|
-
}
|
|
369
|
-
const headers = new Headers();
|
|
370
|
-
let chunked = false;
|
|
371
|
-
let gzip = false;
|
|
372
|
-
let contentLength;
|
|
373
|
-
for (const line of lines) {
|
|
374
|
-
const index = line.indexOf(":");
|
|
375
|
-
if (index <= 0) continue;
|
|
376
|
-
const key = line.slice(0, index);
|
|
377
|
-
const value = line.slice(index + 1).trim();
|
|
378
|
-
const lowerKey = key.toLowerCase();
|
|
379
|
-
const lowerValue = value.toLowerCase();
|
|
380
|
-
if (lowerKey === "transfer-encoding" && lowerValue.includes("chunked")) {
|
|
381
|
-
chunked = true;
|
|
382
|
-
continue;
|
|
383
|
-
}
|
|
384
|
-
if (lowerKey === "content-encoding" && lowerValue.includes("gzip")) {
|
|
385
|
-
gzip = true;
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
if (lowerKey === "content-length") {
|
|
389
|
-
const parsed = Number.parseInt(value, 10);
|
|
390
|
-
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
391
|
-
contentLength = parsed;
|
|
392
|
-
}
|
|
393
|
-
if (gzip) continue;
|
|
394
|
-
}
|
|
395
|
-
headers.append(key, value);
|
|
396
|
-
}
|
|
397
|
-
return {
|
|
398
|
-
status: Number(match[1]),
|
|
399
|
-
statusText: match[2] ?? "",
|
|
400
|
-
headers,
|
|
401
|
-
chunked,
|
|
402
|
-
gzip,
|
|
403
|
-
contentLength
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
var ContentLengthStream = class extends Transform {
|
|
407
|
-
remaining;
|
|
408
|
-
constructor(contentLength) {
|
|
409
|
-
super();
|
|
410
|
-
this.remaining = contentLength;
|
|
411
|
-
}
|
|
412
|
-
_transform(chunk, _encoding, callback) {
|
|
413
|
-
if (this.remaining <= 0) {
|
|
414
|
-
callback();
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
if (chunk.length <= this.remaining) {
|
|
418
|
-
this.remaining -= chunk.length;
|
|
419
|
-
this.push(chunk);
|
|
420
|
-
} else {
|
|
421
|
-
this.push(chunk.subarray(0, this.remaining));
|
|
422
|
-
this.remaining = 0;
|
|
423
|
-
}
|
|
424
|
-
if (this.remaining <= 0) {
|
|
425
|
-
this.push(null);
|
|
426
|
-
}
|
|
427
|
-
callback();
|
|
428
|
-
}
|
|
429
|
-
};
|
|
430
|
-
var ChunkedDecodeStream = class extends Transform {
|
|
431
|
-
buffer = Buffer2.alloc(0);
|
|
432
|
-
_transform(chunk, _encoding, callback) {
|
|
433
|
-
this.buffer = Buffer2.concat([this.buffer, chunk]);
|
|
434
|
-
try {
|
|
435
|
-
this.flushAvailableChunks();
|
|
436
|
-
callback();
|
|
437
|
-
} catch (error) {
|
|
438
|
-
callback(error instanceof Error ? error : new Error(String(error)));
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
_flush(callback) {
|
|
442
|
-
try {
|
|
443
|
-
this.flushAvailableChunks();
|
|
444
|
-
callback();
|
|
445
|
-
} catch (error) {
|
|
446
|
-
callback(error instanceof Error ? error : new Error(String(error)));
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
flushAvailableChunks() {
|
|
450
|
-
while (true) {
|
|
451
|
-
const lineEnd = this.buffer.indexOf("\r\n");
|
|
452
|
-
if (lineEnd === -1) return;
|
|
453
|
-
const sizeLine = this.buffer.subarray(0, lineEnd).toString("latin1");
|
|
454
|
-
const sizeText = sizeLine.split(";", 1)[0]?.trim() ?? "";
|
|
455
|
-
const size = Number.parseInt(sizeText, 16);
|
|
456
|
-
if (!Number.isFinite(size)) {
|
|
457
|
-
throw new Error(`Invalid chunk size: ${sizeLine}`);
|
|
458
|
-
}
|
|
459
|
-
const chunkStart = lineEnd + 2;
|
|
460
|
-
const chunkEnd = chunkStart + size;
|
|
461
|
-
const nextOffset = chunkEnd + 2;
|
|
462
|
-
if (this.buffer.length < nextOffset) return;
|
|
463
|
-
if (size === 0) {
|
|
464
|
-
this.buffer = Buffer2.alloc(0);
|
|
465
|
-
this.push(null);
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
this.push(this.buffer.subarray(chunkStart, chunkEnd));
|
|
469
|
-
this.buffer = this.buffer.subarray(nextOffset);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
function buildResponseStream(socket, leftover, head, signal, idleTimeoutMs, onDebug) {
|
|
474
|
-
const source = new PassThrough();
|
|
475
|
-
if (leftover.length > 0) {
|
|
476
|
-
source.write(leftover);
|
|
477
|
-
}
|
|
478
|
-
socket.pipe(source);
|
|
479
|
-
let responseBody = source;
|
|
480
|
-
if (head.chunked) {
|
|
481
|
-
responseBody = responseBody.pipe(new ChunkedDecodeStream());
|
|
482
|
-
} else if (typeof head.contentLength === "number") {
|
|
483
|
-
responseBody = responseBody.pipe(new ContentLengthStream(head.contentLength));
|
|
484
|
-
}
|
|
485
|
-
if (head.gzip) {
|
|
486
|
-
responseBody = responseBody.pipe(createGunzip());
|
|
487
|
-
}
|
|
488
|
-
let idleTimer;
|
|
489
|
-
const clearIdle = () => {
|
|
490
|
-
if (idleTimer) {
|
|
491
|
-
clearTimeout(idleTimer);
|
|
492
|
-
idleTimer = void 0;
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
const armIdle = () => {
|
|
496
|
-
if (!idleTimeoutMs || idleTimeoutMs <= 0) return;
|
|
497
|
-
clearIdle();
|
|
498
|
-
idleTimer = setTimeout(() => {
|
|
499
|
-
onDebug?.(`agy transport idle timeout after ${idleTimeoutMs}ms with no body data`);
|
|
500
|
-
socket.destroy(new Error(`Antigravity response stalled: no data for ${idleTimeoutMs}ms`));
|
|
501
|
-
}, idleTimeoutMs);
|
|
502
|
-
};
|
|
503
|
-
socket.on("data", armIdle);
|
|
504
|
-
armIdle();
|
|
505
|
-
const abort = () => socket.destroy(new DOMException("The operation was aborted", "AbortError"));
|
|
506
|
-
const cleanup = () => {
|
|
507
|
-
clearIdle();
|
|
508
|
-
socket.off("data", armIdle);
|
|
509
|
-
signal?.removeEventListener("abort", abort);
|
|
510
|
-
};
|
|
511
|
-
if (signal?.aborted) {
|
|
512
|
-
abort();
|
|
513
|
-
} else {
|
|
514
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
515
|
-
}
|
|
516
|
-
responseBody.once("end", () => {
|
|
517
|
-
cleanup();
|
|
518
|
-
socket.destroy();
|
|
519
|
-
});
|
|
520
|
-
responseBody.once("error", () => {
|
|
521
|
-
cleanup();
|
|
522
|
-
socket.destroy();
|
|
523
|
-
});
|
|
524
|
-
responseBody.once("close", cleanup);
|
|
525
|
-
return Readable.toWeb(responseBody);
|
|
526
|
-
}
|
|
527
|
-
async function fetchWithAgyCliTransport(url, init = {}, options = {}) {
|
|
528
|
-
const parsedUrl = new URL(url);
|
|
529
|
-
if (parsedUrl.protocol !== "https:") {
|
|
530
|
-
throw new Error(`agy transport only supports https URLs: ${url}`);
|
|
531
|
-
}
|
|
532
|
-
if (options.signal?.aborted) {
|
|
533
|
-
throw new DOMException("The operation was aborted", "AbortError");
|
|
534
|
-
}
|
|
535
|
-
const body = bodyToBuffer(init.body);
|
|
536
|
-
const requestBytes = serializeRequest(parsedUrl, init, body);
|
|
537
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_AGY_RESPONSE_HEADER_TIMEOUT_MS;
|
|
538
|
-
const idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_AGY_IDLE_TIMEOUT_MS;
|
|
539
|
-
options.onDebug?.(`agy transport connecting to ${parsedUrl.hostname} with header timeout ${timeoutMs}ms`);
|
|
540
|
-
const socket = await connectTlsWithAbort(parsedUrl, timeoutMs, options.signal, options.onDebug);
|
|
541
|
-
const abort = () => {
|
|
542
|
-
socket.destroy(new DOMException("The operation was aborted", "AbortError"));
|
|
543
|
-
};
|
|
544
|
-
try {
|
|
545
|
-
options.signal?.addEventListener("abort", abort, { once: true });
|
|
546
|
-
socket.write(requestBytes);
|
|
547
|
-
options.onDebug?.(`agy transport request dispatched (${requestBytes.byteLength} bytes)`);
|
|
548
|
-
const { head, leftover } = await waitForHead(socket, timeoutMs, () => {
|
|
549
|
-
options.onDebug?.(`agy transport response header timeout after ${timeoutMs}ms`);
|
|
550
|
-
socket.destroy();
|
|
551
|
-
});
|
|
552
|
-
const parsedHead = parseResponseHead(head);
|
|
553
|
-
options.onDebug?.(`agy transport response headers received: ${parsedHead.status} ${parsedHead.statusText}`);
|
|
554
|
-
const bodyStream = buildResponseStream(socket, leftover, parsedHead, options.signal, idleTimeoutMs, options.onDebug);
|
|
555
|
-
return new Response(bodyStream, {
|
|
556
|
-
status: parsedHead.status,
|
|
557
|
-
statusText: parsedHead.statusText,
|
|
558
|
-
headers: parsedHead.headers
|
|
559
|
-
});
|
|
560
|
-
} catch (error) {
|
|
561
|
-
socket.destroy();
|
|
562
|
-
throw error;
|
|
563
|
-
} finally {
|
|
564
|
-
options.signal?.removeEventListener("abort", abort);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
async function connectTlsWithAbort(targetUrl, timeoutMs, signal, onDebug) {
|
|
568
|
-
if (!signal) {
|
|
569
|
-
return connectTls(targetUrl, timeoutMs, onDebug);
|
|
570
|
-
}
|
|
571
|
-
const connectPromise = connectTls(targetUrl, timeoutMs, onDebug);
|
|
572
|
-
let onAbort;
|
|
573
|
-
const abortPromise = new Promise((_, reject) => {
|
|
574
|
-
onAbort = () => reject(new DOMException("The operation was aborted", "AbortError"));
|
|
575
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
576
|
-
});
|
|
577
|
-
try {
|
|
578
|
-
return await Promise.race([connectPromise, abortPromise]);
|
|
579
|
-
} catch (error) {
|
|
580
|
-
void connectPromise.then((socket) => socket.destroy()).catch(() => {
|
|
581
|
-
});
|
|
582
|
-
throw error;
|
|
583
|
-
} finally {
|
|
584
|
-
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// ../core/src/agy-request-metadata.ts
|
|
589
|
-
import { Buffer as Buffer3 } from "node:buffer";
|
|
590
|
-
import { randomUUID } from "node:crypto";
|
|
591
|
-
var FNV1A_64_OFFSET_BASIS = 0xcbf29ce484222325n;
|
|
592
|
-
var FNV1A_64_PRIME = 0x100000001b3n;
|
|
593
|
-
var DEFAULT_SESSION_STATE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
594
|
-
var DEFAULT_MAX_SESSION_STATES = 256;
|
|
595
|
-
var AGY_REQUEST_FIELD_ORDER = [
|
|
596
|
-
"contents",
|
|
597
|
-
"systemInstruction",
|
|
598
|
-
"tools",
|
|
599
|
-
"toolConfig",
|
|
600
|
-
"labels",
|
|
601
|
-
"generationConfig",
|
|
602
|
-
"sessionId"
|
|
603
|
-
];
|
|
604
|
-
var AGY_MODEL_ENUM_BY_WIRE_MODEL = {
|
|
605
|
-
"gemini-3.5-flash-extra-low": "MODEL_PLACEHOLDER_M187",
|
|
606
|
-
"gemini-3.5-flash-low": "MODEL_PLACEHOLDER_M20",
|
|
607
|
-
"gemini-3-flash-agent": "MODEL_PLACEHOLDER_M84",
|
|
608
|
-
"gemini-3.6-flash-low": "MODEL_PLACEHOLDER_M266",
|
|
609
|
-
"gemini-3.6-flash-medium": "MODEL_PLACEHOLDER_M265",
|
|
610
|
-
"gemini-3.6-flash-high": "MODEL_PLACEHOLDER_M264",
|
|
611
|
-
"gemini-3.1-pro-low": "MODEL_PLACEHOLDER_M36",
|
|
612
|
-
"gemini-pro-agent": "MODEL_PLACEHOLDER_M16",
|
|
613
|
-
"claude-sonnet-4-6": "MODEL_PLACEHOLDER_M35",
|
|
614
|
-
"claude-opus-4-6-thinking": "MODEL_PLACEHOLDER_M26",
|
|
615
|
-
"gemini-3.1-flash-image": "MODEL_PLACEHOLDER_M21",
|
|
616
|
-
"gpt-oss-120b-medium": "MODEL_OPENAI_GPT_OSS_120B_MEDIUM"
|
|
617
|
-
};
|
|
618
|
-
function fnv1a64Signed(input) {
|
|
619
|
-
let hash = FNV1A_64_OFFSET_BASIS;
|
|
620
|
-
for (const byte of Buffer3.from(input, "utf8")) {
|
|
621
|
-
hash ^= BigInt(byte);
|
|
622
|
-
hash = BigInt.asUintN(64, hash * FNV1A_64_PRIME);
|
|
623
|
-
}
|
|
624
|
-
return BigInt.asIntN(64, hash).toString();
|
|
625
|
-
}
|
|
626
|
-
function createAgyRequestSessionContext(workspaceUri, ids = {}) {
|
|
627
|
-
return {
|
|
628
|
-
conversationId: ids.conversationId ?? randomUUID(),
|
|
629
|
-
trajectoryId: ids.trajectoryId ?? randomUUID(),
|
|
630
|
-
numericSessionId: fnv1a64Signed(workspaceUri)
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
var AgyRequestSessionStore = class {
|
|
634
|
-
entries = /* @__PURE__ */ new Map();
|
|
635
|
-
workspaceUri;
|
|
636
|
-
ttlMs;
|
|
637
|
-
maxEntries;
|
|
638
|
-
now;
|
|
639
|
-
constructor(workspaceUri, options = {}) {
|
|
640
|
-
this.workspaceUri = workspaceUri;
|
|
641
|
-
this.ttlMs = options.ttlMs ?? DEFAULT_SESSION_STATE_TTL_MS;
|
|
642
|
-
this.maxEntries = options.maxEntries ?? DEFAULT_MAX_SESSION_STATES;
|
|
643
|
-
this.now = options.now ?? Date.now;
|
|
644
|
-
}
|
|
645
|
-
getOrCreate(key) {
|
|
646
|
-
const timestamp = this.now();
|
|
647
|
-
this.prune(timestamp, key);
|
|
648
|
-
const existing = this.entries.get(key);
|
|
649
|
-
if (existing) {
|
|
650
|
-
existing.lastAccessedAt = timestamp;
|
|
651
|
-
return existing.context;
|
|
652
|
-
}
|
|
653
|
-
const context = createAgyRequestSessionContext(this.workspaceUri);
|
|
654
|
-
this.entries.set(key, {
|
|
655
|
-
context,
|
|
656
|
-
lastAccessedAt: timestamp,
|
|
657
|
-
lastRequestTimestamp: 0
|
|
658
|
-
});
|
|
659
|
-
return context;
|
|
660
|
-
}
|
|
661
|
-
beginRequest(key) {
|
|
662
|
-
const session = this.getOrCreate(key);
|
|
663
|
-
const stored = this.entries.get(key);
|
|
664
|
-
const timestamp = Math.max(stored.lastAccessedAt, stored.lastRequestTimestamp + 1);
|
|
665
|
-
stored.lastRequestTimestamp = timestamp;
|
|
666
|
-
return { session, timestamp };
|
|
667
|
-
}
|
|
668
|
-
has(key) {
|
|
669
|
-
return this.entries.has(key);
|
|
670
|
-
}
|
|
671
|
-
delete(key) {
|
|
672
|
-
this.entries.delete(key);
|
|
673
|
-
}
|
|
674
|
-
get size() {
|
|
675
|
-
return this.entries.size;
|
|
676
|
-
}
|
|
677
|
-
prune(timestamp, preservedKey) {
|
|
678
|
-
const expiry = timestamp - this.ttlMs;
|
|
679
|
-
for (const [key, value] of this.entries) {
|
|
680
|
-
if (key !== preservedKey && value.lastAccessedAt < expiry) {
|
|
681
|
-
this.entries.delete(key);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
while (this.entries.size >= this.maxEntries && !this.entries.has(preservedKey)) {
|
|
685
|
-
let oldestKey = null;
|
|
686
|
-
let oldestAccess = Number.POSITIVE_INFINITY;
|
|
687
|
-
for (const [key, value] of this.entries) {
|
|
688
|
-
if (key !== preservedKey && value.lastAccessedAt < oldestAccess) {
|
|
689
|
-
oldestKey = key;
|
|
690
|
-
oldestAccess = value.lastAccessedAt;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
if (!oldestKey) {
|
|
694
|
-
break;
|
|
695
|
-
}
|
|
696
|
-
this.entries.delete(oldestKey);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
function getAgyModelEnum(model) {
|
|
701
|
-
return AGY_MODEL_ENUM_BY_WIRE_MODEL[model.toLowerCase()];
|
|
702
|
-
}
|
|
703
|
-
function orderAgyRequestPayloadInPlace(payload) {
|
|
704
|
-
const ordered = {};
|
|
705
|
-
const remaining = new Set(Object.keys(payload));
|
|
706
|
-
for (const key of AGY_REQUEST_FIELD_ORDER) {
|
|
707
|
-
if (key in payload) {
|
|
708
|
-
ordered[key] = payload[key];
|
|
709
|
-
remaining.delete(key);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
for (const key of remaining) {
|
|
713
|
-
ordered[key] = payload[key];
|
|
714
|
-
}
|
|
715
|
-
for (const key of Object.keys(payload)) {
|
|
716
|
-
delete payload[key];
|
|
717
|
-
}
|
|
718
|
-
Object.assign(payload, ordered);
|
|
719
|
-
}
|
|
720
|
-
function countAgyRequestSteps(payload) {
|
|
721
|
-
const contents = payload.contents;
|
|
722
|
-
if (!Array.isArray(contents)) {
|
|
723
|
-
return 1;
|
|
724
|
-
}
|
|
725
|
-
let partCount = 0;
|
|
726
|
-
for (const content of contents) {
|
|
727
|
-
if (!content || typeof content !== "object" || Array.isArray(content)) {
|
|
728
|
-
continue;
|
|
729
|
-
}
|
|
730
|
-
const parts = content.parts;
|
|
731
|
-
if (Array.isArray(parts)) {
|
|
732
|
-
partCount += parts.length;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
return Math.max(1, partCount);
|
|
736
|
-
}
|
|
737
|
-
function buildAgyAgentRequestMetadata(session, payload, model, timestamp = Date.now()) {
|
|
738
|
-
const lastStepIndex = countAgyRequestSteps(payload);
|
|
739
|
-
const isClaude = model.toLowerCase().startsWith("claude-");
|
|
740
|
-
const isNonGemini = isClaude || model.toLowerCase().startsWith("gpt-");
|
|
741
|
-
session.usedClaude = session.usedClaude === true || isClaude;
|
|
742
|
-
session.usedNonGeminiModel = session.usedNonGeminiModel === true || isNonGemini;
|
|
743
|
-
const modelEnum = getAgyModelEnum(model);
|
|
744
|
-
const labels = {
|
|
745
|
-
last_step_index: String(lastStepIndex),
|
|
746
|
-
...modelEnum ? { model_enum: modelEnum } : {},
|
|
747
|
-
trajectory_id: session.trajectoryId,
|
|
748
|
-
used_claude: session.usedClaude ? "true" : "false",
|
|
749
|
-
used_claude_conservative: session.usedClaude ? "true" : "false",
|
|
750
|
-
used_non_gemini_model: session.usedNonGeminiModel ? "true" : "false"
|
|
751
|
-
};
|
|
752
|
-
return {
|
|
753
|
-
requestId: `agent/${session.conversationId}/${timestamp}/${session.trajectoryId}/${lastStepIndex + 1}`,
|
|
754
|
-
sessionId: session.numericSessionId,
|
|
755
|
-
labels,
|
|
756
|
-
lastStepIndex
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// ../core/src/project.ts
|
|
761
|
-
var log = createLogger("project");
|
|
762
|
-
var PROJECT_CONTEXT_CACHE_TTL_MS = 30 * 60 * 1e3;
|
|
763
|
-
var projectContextResultCache = /* @__PURE__ */ new Map();
|
|
764
|
-
var projectContextPendingCache = /* @__PURE__ */ new Map();
|
|
765
|
-
var provisionFailedKeys = /* @__PURE__ */ new Set();
|
|
766
|
-
function buildBootstrapRequestBody(extra = {}) {
|
|
767
|
-
return {
|
|
768
|
-
...extra,
|
|
769
|
-
metadata: buildAntigravityLoadCodeAssistMetadata()
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
function getDefaultTierId(allowedTiers) {
|
|
773
|
-
if (!allowedTiers || allowedTiers.length === 0) {
|
|
774
|
-
return void 0;
|
|
775
|
-
}
|
|
776
|
-
for (const tier of allowedTiers) {
|
|
777
|
-
if (tier?.isDefault) {
|
|
778
|
-
return tier.id;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
return allowedTiers[0]?.id;
|
|
782
|
-
}
|
|
783
|
-
function wait(ms) {
|
|
784
|
-
return new Promise(function(resolve) {
|
|
785
|
-
setTimeout(resolve, ms);
|
|
786
|
-
});
|
|
787
|
-
}
|
|
788
|
-
function extractManagedProjectId(payload) {
|
|
789
|
-
if (!payload) {
|
|
790
|
-
return void 0;
|
|
791
|
-
}
|
|
792
|
-
if (typeof payload.cloudaicompanionProject === "string") {
|
|
793
|
-
return payload.cloudaicompanionProject;
|
|
794
|
-
}
|
|
795
|
-
if (payload.cloudaicompanionProject && typeof payload.cloudaicompanionProject.id === "string") {
|
|
796
|
-
return payload.cloudaicompanionProject.id;
|
|
797
|
-
}
|
|
798
|
-
return void 0;
|
|
799
|
-
}
|
|
800
|
-
function getCacheKey(auth) {
|
|
801
|
-
const refresh = auth.refresh?.trim();
|
|
802
|
-
return refresh ? refresh : void 0;
|
|
803
|
-
}
|
|
804
|
-
async function loadManagedProject(accessToken, _projectId) {
|
|
805
|
-
const requestBody = buildBootstrapRequestBody();
|
|
806
|
-
const loadHeaders = buildAntigravityHarnessBootstrapHeaders(accessToken);
|
|
807
|
-
const loadEndpoints = Array.from(
|
|
808
|
-
/* @__PURE__ */ new Set([...ANTIGRAVITY_LOAD_ENDPOINTS, ...ANTIGRAVITY_ENDPOINT_FALLBACKS])
|
|
809
|
-
);
|
|
810
|
-
for (const baseEndpoint of loadEndpoints) {
|
|
811
|
-
try {
|
|
812
|
-
const response = await fetchWithAgyCliTransport(
|
|
813
|
-
`${baseEndpoint}/v1internal:loadCodeAssist`,
|
|
814
|
-
{
|
|
815
|
-
method: "POST",
|
|
816
|
-
headers: loadHeaders,
|
|
817
|
-
body: JSON.stringify(requestBody)
|
|
818
|
-
}
|
|
819
|
-
);
|
|
820
|
-
if (!response.ok) {
|
|
821
|
-
continue;
|
|
822
|
-
}
|
|
823
|
-
return await response.json();
|
|
824
|
-
} catch (error) {
|
|
825
|
-
log.debug("Failed to load managed project", { endpoint: baseEndpoint, error: String(error) });
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
return null;
|
|
830
|
-
}
|
|
831
|
-
async function onboardManagedProject(accessToken, tierId, projectId, attempts = 10, delayMs = 5e3) {
|
|
832
|
-
const requestBody = { tierId };
|
|
833
|
-
const onboardEndpoints = Array.from(
|
|
834
|
-
/* @__PURE__ */ new Set([ANTIGRAVITY_ENDPOINT_PROD, ...ANTIGRAVITY_LOAD_ENDPOINTS, ...ANTIGRAVITY_ENDPOINT_FALLBACKS])
|
|
835
|
-
);
|
|
836
|
-
for (const baseEndpoint of onboardEndpoints) {
|
|
837
|
-
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
838
|
-
try {
|
|
839
|
-
const response = await fetchWithAgyCliTransport(
|
|
840
|
-
`${baseEndpoint}/v1internal:onboardUser`,
|
|
841
|
-
{
|
|
842
|
-
method: "POST",
|
|
843
|
-
headers: buildAntigravityHarnessBootstrapHeaders(accessToken),
|
|
844
|
-
body: JSON.stringify(requestBody)
|
|
845
|
-
}
|
|
846
|
-
);
|
|
847
|
-
if (!response.ok) {
|
|
848
|
-
log.debug("Onboard request failed", {
|
|
849
|
-
endpoint: baseEndpoint,
|
|
850
|
-
status: response.status,
|
|
851
|
-
statusText: response.statusText
|
|
852
|
-
});
|
|
853
|
-
break;
|
|
854
|
-
}
|
|
855
|
-
const payload = await response.json();
|
|
856
|
-
const managedProjectId = payload.response?.cloudaicompanionProject?.id;
|
|
857
|
-
if (payload.done && managedProjectId) {
|
|
858
|
-
return managedProjectId;
|
|
859
|
-
}
|
|
860
|
-
if (payload.done && projectId) {
|
|
861
|
-
return projectId;
|
|
862
|
-
}
|
|
863
|
-
} catch (error) {
|
|
864
|
-
log.debug("Failed to onboard managed project", { endpoint: baseEndpoint, error: String(error) });
|
|
865
|
-
break;
|
|
866
|
-
}
|
|
867
|
-
await wait(delayMs);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return void 0;
|
|
871
|
-
}
|
|
872
|
-
async function ensureProjectContext(auth) {
|
|
873
|
-
const accessToken = auth.access;
|
|
874
|
-
if (!accessToken) {
|
|
875
|
-
return { auth, effectiveProjectId: "" };
|
|
876
|
-
}
|
|
877
|
-
const cacheKey = getCacheKey(auth);
|
|
878
|
-
if (cacheKey) {
|
|
879
|
-
const cached = projectContextResultCache.get(cacheKey);
|
|
880
|
-
if (cached && Date.now() - cached.cachedAt < PROJECT_CONTEXT_CACHE_TTL_MS) {
|
|
881
|
-
return cached.result;
|
|
882
|
-
}
|
|
883
|
-
if (cached) {
|
|
884
|
-
projectContextResultCache.delete(cacheKey);
|
|
885
|
-
}
|
|
886
|
-
const pending = projectContextPendingCache.get(cacheKey);
|
|
887
|
-
if (pending) {
|
|
888
|
-
return pending;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
const resolveContext = async () => {
|
|
892
|
-
const parts = parseRefreshParts(auth.refresh);
|
|
893
|
-
if (parts.managedProjectId) {
|
|
894
|
-
return { auth, effectiveProjectId: parts.managedProjectId };
|
|
895
|
-
}
|
|
896
|
-
const fallbackProjectId = ANTIGRAVITY_DEFAULT_PROJECT_ID;
|
|
897
|
-
if (cacheKey && provisionFailedKeys.has(cacheKey)) {
|
|
898
|
-
const effectiveProjectId = parts.projectId || fallbackProjectId;
|
|
899
|
-
return { auth, effectiveProjectId };
|
|
900
|
-
}
|
|
901
|
-
const persistManagedProject = async (managedProjectId) => {
|
|
902
|
-
const updatedAuth = {
|
|
903
|
-
...auth,
|
|
904
|
-
refresh: formatRefreshParts({
|
|
905
|
-
refreshToken: parts.refreshToken,
|
|
906
|
-
projectId: parts.projectId,
|
|
907
|
-
managedProjectId
|
|
908
|
-
})
|
|
909
|
-
};
|
|
910
|
-
return { auth: updatedAuth, effectiveProjectId: managedProjectId };
|
|
911
|
-
};
|
|
912
|
-
const loadPayload = await loadManagedProject(accessToken, parts.projectId ?? fallbackProjectId);
|
|
913
|
-
const resolvedManagedProjectId = extractManagedProjectId(loadPayload);
|
|
914
|
-
if (resolvedManagedProjectId) {
|
|
915
|
-
return persistManagedProject(resolvedManagedProjectId);
|
|
916
|
-
}
|
|
917
|
-
const tierId = getDefaultTierId(loadPayload?.allowedTiers) ?? "free-tier";
|
|
918
|
-
log.debug("Auto-provisioning managed project", { tierId, projectId: parts.projectId });
|
|
919
|
-
const provisionedProjectId = await onboardManagedProject(
|
|
920
|
-
accessToken,
|
|
921
|
-
tierId,
|
|
922
|
-
parts.projectId
|
|
923
|
-
);
|
|
924
|
-
if (provisionedProjectId) {
|
|
925
|
-
log.debug("Successfully provisioned managed project", { provisionedProjectId });
|
|
926
|
-
return persistManagedProject(provisionedProjectId);
|
|
927
|
-
}
|
|
928
|
-
log.warn("Failed to provision managed project - account may not work correctly", {
|
|
929
|
-
hasProjectId: !!parts.projectId
|
|
930
|
-
});
|
|
931
|
-
if (cacheKey) {
|
|
932
|
-
provisionFailedKeys.add(cacheKey);
|
|
933
|
-
}
|
|
934
|
-
if (parts.projectId) {
|
|
935
|
-
return { auth, effectiveProjectId: parts.projectId };
|
|
936
|
-
}
|
|
937
|
-
return { auth, effectiveProjectId: fallbackProjectId };
|
|
938
|
-
};
|
|
939
|
-
if (!cacheKey) {
|
|
940
|
-
return resolveContext();
|
|
941
|
-
}
|
|
942
|
-
const promise = resolveContext().then((result) => {
|
|
943
|
-
const nextKey = getCacheKey(result.auth) ?? cacheKey;
|
|
944
|
-
projectContextPendingCache.delete(cacheKey);
|
|
945
|
-
projectContextResultCache.set(nextKey, { result, cachedAt: Date.now() });
|
|
946
|
-
if (nextKey !== cacheKey) {
|
|
947
|
-
projectContextResultCache.delete(cacheKey);
|
|
948
|
-
}
|
|
949
|
-
return result;
|
|
950
|
-
}).catch((error) => {
|
|
951
|
-
projectContextPendingCache.delete(cacheKey);
|
|
952
|
-
throw error;
|
|
953
|
-
});
|
|
954
|
-
projectContextPendingCache.set(cacheKey, promise);
|
|
955
|
-
return promise;
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
// ../core/src/model-registry.ts
|
|
959
|
-
var DEFAULT_MODALITIES = {
|
|
960
|
-
input: ["text", "image", "pdf"],
|
|
961
|
-
output: ["text"]
|
|
962
|
-
};
|
|
963
|
-
var MODEL_RELEASE_DATE = "";
|
|
964
|
-
var DEFAULT_COST = { input: 0, output: 0 };
|
|
965
|
-
var DEFAULT_OPTIONS = {};
|
|
966
|
-
function defineModel(id, model) {
|
|
967
|
-
return {
|
|
968
|
-
id,
|
|
969
|
-
release_date: MODEL_RELEASE_DATE,
|
|
970
|
-
attachment: model.modalities.input.some((modality) => modality !== "text"),
|
|
971
|
-
temperature: true,
|
|
972
|
-
tool_call: true,
|
|
973
|
-
cost: { ...DEFAULT_COST },
|
|
974
|
-
options: { ...DEFAULT_OPTIONS },
|
|
975
|
-
...model
|
|
976
|
-
};
|
|
977
|
-
}
|
|
978
|
-
var ALL_MODEL_DEFINITIONS = {
|
|
979
|
-
"antigravity-gemini-3.1-pro": defineModel("antigravity-gemini-3.1-pro", {
|
|
980
|
-
name: "Gemini 3.1 Pro (Antigravity)",
|
|
981
|
-
reasoning: true,
|
|
982
|
-
limit: { context: 1048576, output: 65535 },
|
|
983
|
-
modalities: DEFAULT_MODALITIES,
|
|
984
|
-
variants: {
|
|
985
|
-
low: { thinkingLevel: "low" },
|
|
986
|
-
high: { thinkingLevel: "high" }
|
|
987
|
-
}
|
|
988
|
-
}),
|
|
989
|
-
"antigravity-gemini-3.6-flash": defineModel("antigravity-gemini-3.6-flash", {
|
|
990
|
-
name: "Gemini 3.6 Flash (Antigravity)",
|
|
991
|
-
reasoning: true,
|
|
992
|
-
limit: { context: 1048576, output: 65536 },
|
|
993
|
-
modalities: DEFAULT_MODALITIES,
|
|
994
|
-
variants: {
|
|
995
|
-
low: { thinkingLevel: "low" },
|
|
996
|
-
high: { thinkingLevel: "high" }
|
|
997
|
-
}
|
|
998
|
-
}),
|
|
999
|
-
"antigravity-gemini-3.5-flash": defineModel("antigravity-gemini-3.5-flash", {
|
|
1000
|
-
name: "Gemini 3.5 Flash (Antigravity)",
|
|
1001
|
-
reasoning: true,
|
|
1002
|
-
limit: { context: 1048576, output: 65536 },
|
|
1003
|
-
modalities: DEFAULT_MODALITIES,
|
|
1004
|
-
variants: {
|
|
1005
|
-
low: { thinkingLevel: "low" },
|
|
1006
|
-
high: { thinkingLevel: "high" }
|
|
1007
|
-
}
|
|
1008
|
-
}),
|
|
1009
|
-
"antigravity-claude-sonnet-4-6-thinking": defineModel("antigravity-claude-sonnet-4-6-thinking", {
|
|
1010
|
-
name: "Claude Sonnet 4.6 Thinking (Antigravity)",
|
|
1011
|
-
reasoning: true,
|
|
1012
|
-
limit: { context: 25e4, output: 64e3 },
|
|
1013
|
-
modalities: DEFAULT_MODALITIES,
|
|
1014
|
-
variants: {
|
|
1015
|
-
low: { disabled: true },
|
|
1016
|
-
high: { disabled: true }
|
|
1017
|
-
}
|
|
1018
|
-
}),
|
|
1019
|
-
"antigravity-claude-opus-4-6-thinking": defineModel("antigravity-claude-opus-4-6-thinking", {
|
|
1020
|
-
name: "Claude Opus 4.6 Thinking (Antigravity)",
|
|
1021
|
-
reasoning: true,
|
|
1022
|
-
limit: { context: 25e4, output: 64e3 },
|
|
1023
|
-
modalities: DEFAULT_MODALITIES,
|
|
1024
|
-
variants: {
|
|
1025
|
-
low: { disabled: true },
|
|
1026
|
-
high: { disabled: true }
|
|
1027
|
-
}
|
|
1028
|
-
}),
|
|
1029
|
-
"antigravity-gemini-3.1-flash-image": defineModel("antigravity-gemini-3.1-flash-image", {
|
|
1030
|
-
name: "Gemini 3.1 Flash Image (Antigravity)",
|
|
1031
|
-
reasoning: false,
|
|
1032
|
-
limit: { context: 66e3, output: 33e3 },
|
|
1033
|
-
modalities: {
|
|
1034
|
-
input: ["text", "image"],
|
|
1035
|
-
output: ["text", "image"]
|
|
1036
|
-
}
|
|
1037
|
-
}),
|
|
1038
|
-
"antigravity-gpt-oss-120b-medium": defineModel("antigravity-gpt-oss-120b-medium", {
|
|
1039
|
-
name: "GPT-OSS 120B Medium (Antigravity)",
|
|
1040
|
-
reasoning: true,
|
|
1041
|
-
limit: { context: 131072, output: 32768 },
|
|
1042
|
-
modalities: DEFAULT_MODALITIES
|
|
1043
|
-
}),
|
|
1044
|
-
"gemini-2.5-flash": defineModel("gemini-2.5-flash", {
|
|
1045
|
-
name: "Gemini 2.5 Flash (Gemini CLI)",
|
|
1046
|
-
reasoning: true,
|
|
1047
|
-
limit: { context: 1048576, output: 65536 },
|
|
1048
|
-
modalities: DEFAULT_MODALITIES
|
|
1049
|
-
}),
|
|
1050
|
-
"gemini-2.5-pro": defineModel("gemini-2.5-pro", {
|
|
1051
|
-
name: "Gemini 2.5 Pro (Gemini CLI)",
|
|
1052
|
-
reasoning: true,
|
|
1053
|
-
limit: { context: 1048576, output: 65536 },
|
|
1054
|
-
modalities: DEFAULT_MODALITIES
|
|
1055
|
-
}),
|
|
1056
|
-
"gemini-3-flash-preview": defineModel("gemini-3-flash-preview", {
|
|
1057
|
-
name: "Gemini 3 Flash Preview (Gemini CLI)",
|
|
1058
|
-
reasoning: true,
|
|
1059
|
-
limit: { context: 1048576, output: 65536 },
|
|
1060
|
-
modalities: DEFAULT_MODALITIES
|
|
1061
|
-
}),
|
|
1062
|
-
"gemini-3.1-pro-preview": defineModel("gemini-3.1-pro-preview", {
|
|
1063
|
-
name: "Gemini 3.1 Pro Preview (Gemini CLI)",
|
|
1064
|
-
reasoning: true,
|
|
1065
|
-
limit: { context: 1048576, output: 65535 },
|
|
1066
|
-
modalities: DEFAULT_MODALITIES
|
|
1067
|
-
}),
|
|
1068
|
-
"gemini-3.5-flash-preview": defineModel("gemini-3.5-flash-preview", {
|
|
1069
|
-
name: "Gemini 3.5 Flash Preview (Gemini CLI)",
|
|
1070
|
-
reasoning: true,
|
|
1071
|
-
limit: { context: 1048576, output: 65536 },
|
|
1072
|
-
modalities: DEFAULT_MODALITIES
|
|
1073
|
-
}),
|
|
1074
|
-
"gemini-3.1-flash-image": defineModel("gemini-3.1-flash-image", {
|
|
1075
|
-
name: "Gemini 3.1 Flash Image (Gemini CLI)",
|
|
1076
|
-
reasoning: false,
|
|
1077
|
-
limit: { context: 66e3, output: 33e3 },
|
|
1078
|
-
modalities: {
|
|
1079
|
-
input: ["text", "image"],
|
|
1080
|
-
output: ["text", "image"]
|
|
1081
|
-
}
|
|
1082
|
-
}),
|
|
1083
|
-
"gemini-3.1-flash-image-preview": defineModel("gemini-3.1-flash-image-preview", {
|
|
1084
|
-
name: "Gemini 3.1 Flash Image Preview (Gemini CLI)",
|
|
1085
|
-
reasoning: false,
|
|
1086
|
-
limit: { context: 66e3, output: 33e3 },
|
|
1087
|
-
modalities: {
|
|
1088
|
-
input: ["text", "image"],
|
|
1089
|
-
output: ["text", "image"]
|
|
1090
|
-
}
|
|
1091
|
-
}),
|
|
1092
|
-
"gemini-3.1-pro-preview-customtools": defineModel("gemini-3.1-pro-preview-customtools", {
|
|
1093
|
-
name: "Gemini 3.1 Pro Preview Custom Tools (Gemini CLI)",
|
|
1094
|
-
reasoning: true,
|
|
1095
|
-
limit: { context: 1048576, output: 65535 },
|
|
1096
|
-
modalities: DEFAULT_MODALITIES
|
|
1097
|
-
})
|
|
1098
|
-
};
|
|
1099
|
-
var RESOLVER_ALIASES = {
|
|
1100
|
-
"gemini-3.1-pro-low": "gemini-3.1-pro",
|
|
1101
|
-
"gemini-3.1-pro-high": "gemini-3.1-pro",
|
|
1102
|
-
"gemini-3-flash-low": "gemini-3-flash",
|
|
1103
|
-
"gemini-3-flash-medium": "gemini-3-flash",
|
|
1104
|
-
"gemini-3-flash-high": "gemini-3-flash",
|
|
1105
|
-
"gemini-3.5-flash-low": "gemini-3.5-flash",
|
|
1106
|
-
"gemini-3.5-flash-medium": "gemini-3.5-flash",
|
|
1107
|
-
"gemini-3.5-flash-high": "gemini-3.5-flash",
|
|
1108
|
-
"gemini-3.6-flash-low": "gemini-3.6-flash",
|
|
1109
|
-
"gemini-3.6-flash-medium": "gemini-3.6-flash",
|
|
1110
|
-
"gemini-3.6-flash-high": "gemini-3.6-flash",
|
|
1111
|
-
"gemini-claude-opus-4-6-thinking-low": "claude-opus-4-6-thinking",
|
|
1112
|
-
"gemini-claude-opus-4-6-thinking-medium": "claude-opus-4-6-thinking",
|
|
1113
|
-
"gemini-claude-opus-4-6-thinking-high": "claude-opus-4-6-thinking",
|
|
1114
|
-
"gemini-claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6",
|
|
1115
|
-
"gemini-claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6",
|
|
1116
|
-
"gemini-claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6",
|
|
1117
|
-
"gemini-claude-sonnet-4-6": "claude-sonnet-4-6",
|
|
1118
|
-
"claude-sonnet-4-6-thinking": "claude-sonnet-4-6",
|
|
1119
|
-
"claude-sonnet-4-6-thinking-low": "claude-sonnet-4-6",
|
|
1120
|
-
"claude-sonnet-4-6-thinking-medium": "claude-sonnet-4-6",
|
|
1121
|
-
"claude-sonnet-4-6-thinking-high": "claude-sonnet-4-6",
|
|
1122
|
-
"gpt-oss-120b": "gpt-oss-120b-medium"
|
|
1123
|
-
};
|
|
1124
|
-
var GEMINI_35_FLASH_ROUTES = {
|
|
1125
|
-
antigravity: {
|
|
1126
|
-
defaultModel: "gemini-3-flash-agent",
|
|
1127
|
-
byTier: {
|
|
1128
|
-
low: "gemini-3.5-flash-extra-low",
|
|
1129
|
-
medium: "gemini-3.5-flash-low",
|
|
1130
|
-
high: "gemini-3-flash-agent"
|
|
1131
|
-
}
|
|
1132
|
-
},
|
|
1133
|
-
geminiCliFallbackModel: "gemini-3-flash-preview"
|
|
1134
|
-
};
|
|
1135
|
-
var GEMINI_36_FLASH_ROUTES = {
|
|
1136
|
-
defaultModel: "gemini-3.6-flash-medium",
|
|
1137
|
-
byTier: {
|
|
1138
|
-
low: "gemini-3.6-flash-low",
|
|
1139
|
-
medium: "gemini-3.6-flash-medium",
|
|
1140
|
-
high: "gemini-3.6-flash-high"
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
var ANTIGRAVITY_OPENCODE_MODEL_IDS = [
|
|
1144
|
-
"antigravity-gemini-3.6-flash",
|
|
1145
|
-
"antigravity-gemini-3.5-flash",
|
|
1146
|
-
"antigravity-gemini-3.1-pro",
|
|
1147
|
-
"antigravity-claude-sonnet-4-6-thinking",
|
|
1148
|
-
"antigravity-claude-opus-4-6-thinking",
|
|
1149
|
-
"antigravity-gemini-3.1-flash-image",
|
|
1150
|
-
"antigravity-gpt-oss-120b-medium"
|
|
1151
|
-
];
|
|
1152
|
-
function pickModelDefinitions(ids) {
|
|
1153
|
-
return Object.fromEntries(ids.map((id) => [id, ALL_MODEL_DEFINITIONS[id]]));
|
|
1154
|
-
}
|
|
1155
|
-
var OPENCODE_MODEL_DEFINITIONS = pickModelDefinitions(ANTIGRAVITY_OPENCODE_MODEL_IDS);
|
|
1156
|
-
function getPublicModelDefinitions() {
|
|
1157
|
-
return OPENCODE_MODEL_DEFINITIONS;
|
|
1158
|
-
}
|
|
1159
|
-
function getResolverAliasMap() {
|
|
1160
|
-
return RESOLVER_ALIASES;
|
|
1161
|
-
}
|
|
1162
|
-
function getGemini35FlashAntigravityModel(tier) {
|
|
1163
|
-
if (!tier) {
|
|
1164
|
-
return GEMINI_35_FLASH_ROUTES.antigravity.defaultModel;
|
|
1165
|
-
}
|
|
1166
|
-
return GEMINI_35_FLASH_ROUTES.antigravity.byTier[tier] ?? GEMINI_35_FLASH_ROUTES.antigravity.defaultModel;
|
|
1167
|
-
}
|
|
1168
|
-
function getGemini35FlashGeminiCliFallbackModel() {
|
|
1169
|
-
return GEMINI_35_FLASH_ROUTES.geminiCliFallbackModel;
|
|
1170
|
-
}
|
|
1171
|
-
function getGemini36FlashAntigravityModel(tier) {
|
|
1172
|
-
if (!tier) {
|
|
1173
|
-
return GEMINI_36_FLASH_ROUTES.defaultModel;
|
|
1174
|
-
}
|
|
1175
|
-
return GEMINI_36_FLASH_ROUTES.byTier[tier] ?? GEMINI_36_FLASH_ROUTES.defaultModel;
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
// ../core/src/transform/model-resolver.ts
|
|
1179
|
-
var THINKING_TIER_BUDGETS = {
|
|
1180
|
-
claude: { low: 8192, medium: 16384, high: 32768 },
|
|
1181
|
-
"gemini-2.5-pro": { low: 8192, medium: 16384, high: 32768 },
|
|
1182
|
-
"gemini-2.5-flash": { low: 6144, medium: 12288, high: 24576 },
|
|
1183
|
-
default: { low: 4096, medium: 8192, high: 16384 }
|
|
1184
|
-
};
|
|
1185
|
-
var MODEL_ALIASES = getResolverAliasMap();
|
|
1186
|
-
var TIER_REGEX = /-(minimal|low|medium|high)$/;
|
|
1187
|
-
var QUOTA_PREFIX_REGEX = /^antigravity-/i;
|
|
1188
|
-
var GEMINI_3_PRO_REGEX = /^gemini-3(?:\.\d+)?-pro/i;
|
|
1189
|
-
var GEMINI_3_FLASH_REGEX = /^gemini-3(?:\.\d+)?-flash/i;
|
|
1190
|
-
var IMAGE_GENERATION_MODELS = /image|imagen/i;
|
|
1191
|
-
function supportsThinkingTiers(model) {
|
|
1192
|
-
const lower = model.toLowerCase();
|
|
1193
|
-
return lower.includes("gemini-3") || lower.includes("gemini-2.5") || lower.includes("claude") && lower.includes("thinking");
|
|
1194
|
-
}
|
|
1195
|
-
function extractThinkingTierFromModel(model) {
|
|
1196
|
-
if (!supportsThinkingTiers(model)) {
|
|
1197
|
-
return void 0;
|
|
1198
|
-
}
|
|
1199
|
-
const tierMatch = model.match(TIER_REGEX);
|
|
1200
|
-
return tierMatch?.[1];
|
|
1201
|
-
}
|
|
1202
|
-
function getBudgetFamily(model) {
|
|
1203
|
-
if (model.includes("claude")) {
|
|
1204
|
-
return "claude";
|
|
1205
|
-
}
|
|
1206
|
-
if (model.includes("gemini-2.5-pro")) {
|
|
1207
|
-
return "gemini-2.5-pro";
|
|
1208
|
-
}
|
|
1209
|
-
if (model.includes("gemini-2.5-flash")) {
|
|
1210
|
-
return "gemini-2.5-flash";
|
|
1211
|
-
}
|
|
1212
|
-
return "default";
|
|
1213
|
-
}
|
|
1214
|
-
function isThinkingCapableModel(model) {
|
|
1215
|
-
const lower = model.toLowerCase();
|
|
1216
|
-
return lower.includes("thinking") || lower.includes("gemini-3") || lower.includes("gemini-2.5");
|
|
1217
|
-
}
|
|
1218
|
-
function isGemini3ProModel(model) {
|
|
1219
|
-
return GEMINI_3_PRO_REGEX.test(model);
|
|
1220
|
-
}
|
|
1221
|
-
function isGemini3FlashModel(model) {
|
|
1222
|
-
return GEMINI_3_FLASH_REGEX.test(model);
|
|
1223
|
-
}
|
|
1224
|
-
function isGemini35FlashModel(model) {
|
|
1225
|
-
return /^gemini-3\.5-flash/i.test(model);
|
|
1226
|
-
}
|
|
1227
|
-
function resolveGemini35FlashAntigravityModel(tier) {
|
|
1228
|
-
return getGemini35FlashAntigravityModel(tier);
|
|
1229
|
-
}
|
|
1230
|
-
function getAgyGeminiFlashThinkingBudget(tier) {
|
|
1231
|
-
switch (tier) {
|
|
1232
|
-
case "low":
|
|
1233
|
-
return 1e3;
|
|
1234
|
-
case "high":
|
|
1235
|
-
return 1e4;
|
|
1236
|
-
case "medium":
|
|
1237
|
-
default:
|
|
1238
|
-
return 4e3;
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
function getAgyGemini31ProModel(tier) {
|
|
1242
|
-
return tier === "high" ? "gemini-pro-agent" : "gemini-3.1-pro-low";
|
|
1243
|
-
}
|
|
1244
|
-
function getAgyGemini31ProThinkingBudget(tier) {
|
|
1245
|
-
return tier === "high" ? 10001 : 1001;
|
|
1246
|
-
}
|
|
1247
|
-
function resolveModelWithTier(requestedModel, options = {}) {
|
|
1248
|
-
const isAntigravity = QUOTA_PREFIX_REGEX.test(requestedModel);
|
|
1249
|
-
const modelWithoutQuota = requestedModel.replace(QUOTA_PREFIX_REGEX, "");
|
|
1250
|
-
const tier = extractThinkingTierFromModel(modelWithoutQuota);
|
|
1251
|
-
const baseName = tier ? modelWithoutQuota.replace(TIER_REGEX, "") : modelWithoutQuota;
|
|
1252
|
-
const isImageModel = IMAGE_GENERATION_MODELS.test(modelWithoutQuota);
|
|
1253
|
-
const isClaudeModel2 = modelWithoutQuota.toLowerCase().includes("claude");
|
|
1254
|
-
const preferGeminiCli = options.cli_first === true && !isAntigravity && !isImageModel && !isClaudeModel2;
|
|
1255
|
-
const quotaPreference = preferGeminiCli ? "gemini-cli" : "antigravity";
|
|
1256
|
-
const explicitQuota = isAntigravity || isImageModel;
|
|
1257
|
-
const isGemini3 = modelWithoutQuota.toLowerCase().startsWith("gemini-3");
|
|
1258
|
-
const skipAlias = isAntigravity && isGemini3;
|
|
1259
|
-
const isGemini3Pro = isGemini3ProModel(modelWithoutQuota);
|
|
1260
|
-
const isGemini3Flash = isGemini3FlashModel(modelWithoutQuota);
|
|
1261
|
-
const isGemini31Pro = /^gemini-3\.1-pro/i.test(baseName);
|
|
1262
|
-
const isGemini35Flash = /^gemini-3\.5-flash/i.test(baseName);
|
|
1263
|
-
const isGemini36Flash = /^gemini-3\.6-flash/i.test(baseName);
|
|
1264
|
-
const isGptOss120b = /^gpt-oss-120b(?:-medium)?$/i.test(baseName);
|
|
1265
|
-
if (isGemini31Pro && quotaPreference === "antigravity") {
|
|
1266
|
-
return {
|
|
1267
|
-
actualModel: getAgyGemini31ProModel(tier),
|
|
1268
|
-
thinkingBudget: getAgyGemini31ProThinkingBudget(tier),
|
|
1269
|
-
tier,
|
|
1270
|
-
isThinkingModel: true,
|
|
1271
|
-
quotaPreference,
|
|
1272
|
-
explicitQuota
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
if (isGemini35Flash && quotaPreference === "antigravity") {
|
|
1276
|
-
return {
|
|
1277
|
-
actualModel: resolveGemini35FlashAntigravityModel(tier ?? "medium"),
|
|
1278
|
-
thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
|
|
1279
|
-
tier: tier ?? "medium",
|
|
1280
|
-
isThinkingModel: true,
|
|
1281
|
-
quotaPreference,
|
|
1282
|
-
explicitQuota
|
|
1283
|
-
};
|
|
1284
|
-
}
|
|
1285
|
-
if (isGemini36Flash && quotaPreference === "antigravity") {
|
|
1286
|
-
return {
|
|
1287
|
-
actualModel: getGemini36FlashAntigravityModel(tier ?? "medium"),
|
|
1288
|
-
thinkingBudget: getAgyGeminiFlashThinkingBudget(tier),
|
|
1289
|
-
tier: tier ?? "medium",
|
|
1290
|
-
isThinkingModel: true,
|
|
1291
|
-
quotaPreference,
|
|
1292
|
-
explicitQuota
|
|
1293
|
-
};
|
|
1294
|
-
}
|
|
1295
|
-
if (isGptOss120b && quotaPreference === "antigravity") {
|
|
1296
|
-
return {
|
|
1297
|
-
actualModel: "gpt-oss-120b-medium",
|
|
1298
|
-
thinkingBudget: 8192,
|
|
1299
|
-
isThinkingModel: true,
|
|
1300
|
-
quotaPreference,
|
|
1301
|
-
explicitQuota
|
|
1302
|
-
};
|
|
1303
|
-
}
|
|
1304
|
-
let antigravityModel = modelWithoutQuota;
|
|
1305
|
-
if (skipAlias) {
|
|
1306
|
-
if ((isGemini3Pro || isGemini3Flash) && !tier && !isImageModel) {
|
|
1307
|
-
const defaultTier = isGemini3Pro ? "low" : "medium";
|
|
1308
|
-
antigravityModel = `${modelWithoutQuota}-${defaultTier}`;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
const actualModel = skipAlias ? antigravityModel : MODEL_ALIASES[modelWithoutQuota] || MODEL_ALIASES[baseName] || baseName;
|
|
1312
|
-
const resolvedModel = actualModel;
|
|
1313
|
-
const isThinking = isThinkingCapableModel(resolvedModel);
|
|
1314
|
-
if (isImageModel) {
|
|
1315
|
-
return {
|
|
1316
|
-
actualModel: resolvedModel,
|
|
1317
|
-
isThinkingModel: false,
|
|
1318
|
-
isImageModel: true,
|
|
1319
|
-
quotaPreference,
|
|
1320
|
-
explicitQuota
|
|
1321
|
-
};
|
|
1322
|
-
}
|
|
1323
|
-
const isEffectiveGemini3 = resolvedModel.toLowerCase().includes("gemini-3");
|
|
1324
|
-
const lowerModelWithoutQuota = modelWithoutQuota.toLowerCase();
|
|
1325
|
-
const isClaudeThinking = resolvedModel.toLowerCase().includes("claude") && resolvedModel.toLowerCase().includes("thinking") || lowerModelWithoutQuota.includes("claude") && lowerModelWithoutQuota.includes("thinking") || lowerModelWithoutQuota === "gemini-claude-sonnet-4-6";
|
|
1326
|
-
if (!tier) {
|
|
1327
|
-
if (isEffectiveGemini3) {
|
|
1328
|
-
return {
|
|
1329
|
-
actualModel: resolvedModel,
|
|
1330
|
-
thinkingLevel: isGemini35Flash ? "medium" : "low",
|
|
1331
|
-
isThinkingModel: true,
|
|
1332
|
-
quotaPreference,
|
|
1333
|
-
explicitQuota
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
1336
|
-
if (isClaudeThinking) {
|
|
1337
|
-
return {
|
|
1338
|
-
actualModel: resolvedModel,
|
|
1339
|
-
thinkingBudget: 1024,
|
|
1340
|
-
isThinkingModel: true,
|
|
1341
|
-
quotaPreference,
|
|
1342
|
-
explicitQuota
|
|
1343
|
-
};
|
|
1344
|
-
}
|
|
1345
|
-
return { actualModel: resolvedModel, isThinkingModel: isThinking, quotaPreference, explicitQuota };
|
|
1346
|
-
}
|
|
1347
|
-
if (isEffectiveGemini3) {
|
|
1348
|
-
return {
|
|
1349
|
-
actualModel: resolvedModel,
|
|
1350
|
-
thinkingLevel: tier,
|
|
1351
|
-
tier,
|
|
1352
|
-
isThinkingModel: true,
|
|
1353
|
-
quotaPreference,
|
|
1354
|
-
explicitQuota
|
|
1355
|
-
};
|
|
1356
|
-
}
|
|
1357
|
-
if (isClaudeThinking) {
|
|
1358
|
-
return {
|
|
1359
|
-
actualModel: resolvedModel,
|
|
1360
|
-
thinkingBudget: 1024,
|
|
1361
|
-
tier,
|
|
1362
|
-
isThinkingModel: true,
|
|
1363
|
-
quotaPreference,
|
|
1364
|
-
explicitQuota
|
|
1365
|
-
};
|
|
1366
|
-
}
|
|
1367
|
-
const budgetFamily = getBudgetFamily(resolvedModel);
|
|
1368
|
-
const budgets = THINKING_TIER_BUDGETS[budgetFamily];
|
|
1369
|
-
const thinkingBudget = budgets[tier];
|
|
1370
|
-
return {
|
|
1371
|
-
actualModel: resolvedModel,
|
|
1372
|
-
thinkingBudget,
|
|
1373
|
-
tier,
|
|
1374
|
-
isThinkingModel: isThinking,
|
|
1375
|
-
quotaPreference,
|
|
1376
|
-
explicitQuota
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
function resolveModelForHeaderStyle(requestedModel, headerStyle) {
|
|
1380
|
-
const lower = requestedModel.toLowerCase();
|
|
1381
|
-
const isGemini3 = lower.includes("gemini-3");
|
|
1382
|
-
if (!isGemini3) {
|
|
1383
|
-
return resolveModelWithTier(requestedModel);
|
|
1384
|
-
}
|
|
1385
|
-
if (headerStyle === "antigravity") {
|
|
1386
|
-
let transformedModel = requestedModel.replace(/-preview-customtools$/i, "").replace(/-preview$/i, "").replace(/^antigravity-/i, "");
|
|
1387
|
-
const isGemini3Pro = isGemini3ProModel(transformedModel);
|
|
1388
|
-
const isGemini3Flash = isGemini3FlashModel(transformedModel);
|
|
1389
|
-
const hasTierSuffix = /-(minimal|low|medium|high)$/i.test(transformedModel);
|
|
1390
|
-
const isImageModel = IMAGE_GENERATION_MODELS.test(transformedModel);
|
|
1391
|
-
const isGemini35Flash = isGemini35FlashModel(transformedModel.replace(TIER_REGEX, ""));
|
|
1392
|
-
if ((isGemini3Pro || isGemini3Flash) && !isGemini35Flash && !hasTierSuffix && !isImageModel) {
|
|
1393
|
-
const defaultTier = isGemini3Pro ? "low" : "medium";
|
|
1394
|
-
transformedModel = `${transformedModel}-${defaultTier}`;
|
|
1395
|
-
}
|
|
1396
|
-
const prefixedModel = `antigravity-${transformedModel}`;
|
|
1397
|
-
return resolveModelWithTier(prefixedModel);
|
|
1398
|
-
}
|
|
1399
|
-
if (headerStyle === "gemini-cli") {
|
|
1400
|
-
const requestedTier = extractThinkingTierFromModel(requestedModel.replace(/^antigravity-/i, ""));
|
|
1401
|
-
let transformedModel = requestedModel.replace(/^antigravity-/i, "").replace(/-(minimal|low|medium|high)$/i, "");
|
|
1402
|
-
const hasPreviewSuffix = /-preview($|-)/i.test(transformedModel);
|
|
1403
|
-
const isGemini35Flash = isGemini35FlashModel(transformedModel);
|
|
1404
|
-
if (isGemini35Flash) {
|
|
1405
|
-
transformedModel = getGemini35FlashGeminiCliFallbackModel();
|
|
1406
|
-
} else if (!hasPreviewSuffix) {
|
|
1407
|
-
transformedModel = `${transformedModel}-preview`;
|
|
1408
|
-
}
|
|
1409
|
-
const resolved = resolveModelWithTier(transformedModel, { cli_first: true });
|
|
1410
|
-
return {
|
|
1411
|
-
...resolved,
|
|
1412
|
-
thinkingLevel: requestedTier ?? resolved.thinkingLevel,
|
|
1413
|
-
tier: requestedTier ?? resolved.tier,
|
|
1414
|
-
quotaPreference: "gemini-cli"
|
|
1415
|
-
};
|
|
1416
|
-
}
|
|
1417
|
-
return resolveModelWithTier(requestedModel);
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
// ../core/src/transform/gemini.ts
|
|
1421
|
-
var UNSUPPORTED_SCHEMA_FIELDS = /* @__PURE__ */ new Set([
|
|
1422
|
-
"additionalProperties",
|
|
1423
|
-
"$schema",
|
|
1424
|
-
"$id",
|
|
1425
|
-
"$comment",
|
|
1426
|
-
"$ref",
|
|
1427
|
-
"$defs",
|
|
1428
|
-
"definitions",
|
|
1429
|
-
"const",
|
|
1430
|
-
"contentMediaType",
|
|
1431
|
-
"contentEncoding",
|
|
1432
|
-
"if",
|
|
1433
|
-
"then",
|
|
1434
|
-
"else",
|
|
1435
|
-
"not",
|
|
1436
|
-
"patternProperties",
|
|
1437
|
-
"unevaluatedProperties",
|
|
1438
|
-
"unevaluatedItems",
|
|
1439
|
-
"dependentRequired",
|
|
1440
|
-
"dependentSchemas",
|
|
1441
|
-
"propertyNames",
|
|
1442
|
-
"minContains",
|
|
1443
|
-
"maxContains"
|
|
1444
|
-
]);
|
|
1445
|
-
var NUMERIC_SCHEMA_CONSTRAINTS = /* @__PURE__ */ new Set([
|
|
1446
|
-
"minLength",
|
|
1447
|
-
"maxLength",
|
|
1448
|
-
"minItems",
|
|
1449
|
-
"maxItems",
|
|
1450
|
-
"minProperties",
|
|
1451
|
-
"maxProperties",
|
|
1452
|
-
"minimum",
|
|
1453
|
-
"maximum",
|
|
1454
|
-
"exclusiveMinimum",
|
|
1455
|
-
"exclusiveMaximum",
|
|
1456
|
-
"multipleOf"
|
|
1457
|
-
]);
|
|
1458
|
-
function toGeminiSchema(schema, options = {}) {
|
|
1459
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1460
|
-
return schema;
|
|
1461
|
-
}
|
|
1462
|
-
const inputSchema = schema;
|
|
1463
|
-
const result = {};
|
|
1464
|
-
const numericConstraintHints = [];
|
|
1465
|
-
const propertyNames = /* @__PURE__ */ new Set();
|
|
1466
|
-
if (inputSchema.properties && typeof inputSchema.properties === "object") {
|
|
1467
|
-
for (const propName of Object.keys(inputSchema.properties)) {
|
|
1468
|
-
propertyNames.add(propName);
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
for (const [key, value] of Object.entries(inputSchema)) {
|
|
1472
|
-
if (UNSUPPORTED_SCHEMA_FIELDS.has(key)) {
|
|
1473
|
-
continue;
|
|
1474
|
-
}
|
|
1475
|
-
if (key === "type" && typeof value === "string") {
|
|
1476
|
-
result[key] = value.toUpperCase();
|
|
1477
|
-
} else if (key === "properties" && typeof value === "object" && value !== null) {
|
|
1478
|
-
const props = {};
|
|
1479
|
-
for (const [propName, propSchema] of Object.entries(value)) {
|
|
1480
|
-
props[propName] = toGeminiSchema(propSchema, options);
|
|
1481
|
-
}
|
|
1482
|
-
result[key] = props;
|
|
1483
|
-
} else if (key === "items" && typeof value === "object") {
|
|
1484
|
-
result[key] = toGeminiSchema(value, options);
|
|
1485
|
-
} else if ((key === "anyOf" || key === "oneOf" || key === "allOf") && Array.isArray(value)) {
|
|
1486
|
-
result[key] = value.map((item) => toGeminiSchema(item, options));
|
|
1487
|
-
} else if (key === "enum" && Array.isArray(value)) {
|
|
1488
|
-
result[key] = value;
|
|
1489
|
-
} else if (options.moveNumericConstraintsToDescription && NUMERIC_SCHEMA_CONSTRAINTS.has(key)) {
|
|
1490
|
-
if (typeof value === "string" || typeof value === "number") {
|
|
1491
|
-
numericConstraintHints.push(`${key}: ${value}`);
|
|
1492
|
-
}
|
|
1493
|
-
} else if (key === "default" || key === "examples") {
|
|
1494
|
-
result[key] = value;
|
|
1495
|
-
} else if (key === "required" && Array.isArray(value)) {
|
|
1496
|
-
if (propertyNames.size > 0) {
|
|
1497
|
-
const validRequired = value.filter(
|
|
1498
|
-
(prop) => typeof prop === "string" && propertyNames.has(prop)
|
|
1499
|
-
);
|
|
1500
|
-
if (validRequired.length > 0) {
|
|
1501
|
-
result[key] = validRequired;
|
|
1502
|
-
}
|
|
1503
|
-
} else {
|
|
1504
|
-
result[key] = value;
|
|
1505
|
-
}
|
|
1506
|
-
} else {
|
|
1507
|
-
result[key] = value;
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
if (numericConstraintHints.length > 0) {
|
|
1511
|
-
const hint = numericConstraintHints.join(", ");
|
|
1512
|
-
result.description = typeof result.description === "string" && result.description ? `${result.description} (${hint})` : hint;
|
|
1513
|
-
}
|
|
1514
|
-
if (result.type === "ARRAY" && !result.items) {
|
|
1515
|
-
result.items = { type: "STRING" };
|
|
1516
|
-
}
|
|
1517
|
-
return result;
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
// ../../node_modules/jose/dist/node/esm/runtime/base64url.js
|
|
1521
|
-
import { Buffer as Buffer4 } from "node:buffer";
|
|
1522
|
-
|
|
1523
|
-
// ../../node_modules/jose/dist/node/esm/lib/buffer_utils.js
|
|
1524
|
-
var encoder = new TextEncoder();
|
|
1525
|
-
var decoder = new TextDecoder();
|
|
1526
|
-
var MAX_INT32 = 2 ** 32;
|
|
1527
|
-
|
|
1528
|
-
// ../../node_modules/jose/dist/node/esm/runtime/base64url.js
|
|
1529
|
-
function normalize(input) {
|
|
1530
|
-
let encoded = input;
|
|
1531
|
-
if (encoded instanceof Uint8Array) {
|
|
1532
|
-
encoded = decoder.decode(encoded);
|
|
1533
|
-
}
|
|
1534
|
-
return encoded;
|
|
1535
|
-
}
|
|
1536
|
-
var encode = (input) => Buffer4.from(input).toString("base64url");
|
|
1537
|
-
var decode = (input) => new Uint8Array(Buffer4.from(normalize(input), "base64url"));
|
|
1538
|
-
|
|
1539
|
-
// ../../node_modules/jose/dist/node/esm/util/base64url.js
|
|
1540
|
-
var base64url_exports = {};
|
|
1541
|
-
__export(base64url_exports, {
|
|
1542
|
-
decode: () => decode2,
|
|
1543
|
-
encode: () => encode2
|
|
1544
|
-
});
|
|
1545
|
-
var encode2 = encode;
|
|
1546
|
-
var decode2 = decode;
|
|
1547
|
-
|
|
1548
|
-
// ../../node_modules/@openauthjs/openauth/dist/esm/pkce.js
|
|
1549
|
-
function generateVerifier(length) {
|
|
1550
|
-
const buffer = new Uint8Array(length);
|
|
1551
|
-
crypto.getRandomValues(buffer);
|
|
1552
|
-
return base64url_exports.encode(buffer);
|
|
1553
|
-
}
|
|
1554
|
-
async function generateChallenge(verifier, method) {
|
|
1555
|
-
if (method === "plain")
|
|
1556
|
-
return verifier;
|
|
1557
|
-
const encoder2 = new TextEncoder();
|
|
1558
|
-
const data = encoder2.encode(verifier);
|
|
1559
|
-
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
1560
|
-
return base64url_exports.encode(new Uint8Array(hash));
|
|
1561
|
-
}
|
|
1562
|
-
async function generatePKCE(length = 64) {
|
|
1563
|
-
if (length < 43 || length > 128) {
|
|
1564
|
-
throw new Error("Code verifier length must be between 43 and 128 characters");
|
|
1565
|
-
}
|
|
1566
|
-
const verifier = generateVerifier(length);
|
|
1567
|
-
const challenge = await generateChallenge(verifier, "S256");
|
|
1568
|
-
return {
|
|
1569
|
-
verifier,
|
|
1570
|
-
challenge,
|
|
1571
|
-
method: "S256"
|
|
1572
|
-
};
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
// ../core/src/antigravity/oauth.ts
|
|
1576
|
-
var log2 = createLogger("oauth");
|
|
1577
|
-
async function refreshAntigravityToken(refreshToken) {
|
|
1578
|
-
const startTime = Date.now();
|
|
1579
|
-
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
1580
|
-
method: "POST",
|
|
1581
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1582
|
-
body: new URLSearchParams({
|
|
1583
|
-
grant_type: "refresh_token",
|
|
1584
|
-
refresh_token: refreshToken,
|
|
1585
|
-
client_id: ANTIGRAVITY_CLIENT_ID,
|
|
1586
|
-
client_secret: ANTIGRAVITY_CLIENT_SECRET
|
|
1587
|
-
})
|
|
1588
|
-
});
|
|
1589
|
-
if (!response.ok) {
|
|
1590
|
-
const errorText = await response.text().catch(() => "");
|
|
1591
|
-
throw new Error(
|
|
1592
|
-
`Antigravity token refresh failed (${response.status} ${response.statusText})${errorText ? ` - ${errorText}` : ""}`
|
|
1593
|
-
);
|
|
1594
|
-
}
|
|
1595
|
-
const payload = await response.json();
|
|
1596
|
-
return {
|
|
1597
|
-
access: payload.access_token,
|
|
1598
|
-
refresh: payload.refresh_token ?? refreshToken,
|
|
1599
|
-
expires: calculateTokenExpiry(startTime, payload.expires_in)
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
function encodeState(payload) {
|
|
1603
|
-
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
1604
|
-
}
|
|
1605
|
-
function decodeState(state) {
|
|
1606
|
-
const normalized = state.replace(/-/g, "+").replace(/_/g, "/");
|
|
1607
|
-
const padded = normalized.padEnd(normalized.length + (4 - normalized.length % 4) % 4, "=");
|
|
1608
|
-
const json = Buffer.from(padded, "base64").toString("utf8");
|
|
1609
|
-
const parsed = JSON.parse(json);
|
|
1610
|
-
if (typeof parsed.verifier !== "string") {
|
|
1611
|
-
throw new Error("Missing PKCE verifier in state");
|
|
1612
|
-
}
|
|
1613
|
-
return {
|
|
1614
|
-
verifier: parsed.verifier,
|
|
1615
|
-
projectId: typeof parsed.projectId === "string" ? parsed.projectId : ""
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
|
-
async function authorizeAntigravity(projectId = "") {
|
|
1619
|
-
const pkce = await generatePKCE();
|
|
1620
|
-
const url = new URL("https://accounts.google.com/o/oauth2/v2/auth");
|
|
1621
|
-
url.searchParams.set("client_id", ANTIGRAVITY_CLIENT_ID);
|
|
1622
|
-
url.searchParams.set("response_type", "code");
|
|
1623
|
-
url.searchParams.set("redirect_uri", ANTIGRAVITY_REDIRECT_URI);
|
|
1624
|
-
url.searchParams.set("scope", ANTIGRAVITY_SCOPES.join(" "));
|
|
1625
|
-
url.searchParams.set("code_challenge", pkce.challenge);
|
|
1626
|
-
url.searchParams.set("code_challenge_method", "S256");
|
|
1627
|
-
url.searchParams.set(
|
|
1628
|
-
"state",
|
|
1629
|
-
encodeState({ verifier: pkce.verifier, projectId: projectId || "" })
|
|
1630
|
-
);
|
|
1631
|
-
url.searchParams.set("access_type", "offline");
|
|
1632
|
-
url.searchParams.set("prompt", "consent");
|
|
1633
|
-
return {
|
|
1634
|
-
url: url.toString(),
|
|
1635
|
-
verifier: pkce.verifier,
|
|
1636
|
-
projectId: projectId || ""
|
|
1637
|
-
};
|
|
1638
|
-
}
|
|
1639
|
-
async function fetchProjectID(accessToken) {
|
|
1640
|
-
const errors = [];
|
|
1641
|
-
const loadHeaders = buildAntigravityHarnessBootstrapHeaders(accessToken);
|
|
1642
|
-
const loadEndpoints = Array.from(
|
|
1643
|
-
/* @__PURE__ */ new Set([...ANTIGRAVITY_LOAD_ENDPOINTS, ...ANTIGRAVITY_ENDPOINT_FALLBACKS])
|
|
1644
|
-
);
|
|
1645
|
-
for (const baseEndpoint of loadEndpoints) {
|
|
1646
|
-
try {
|
|
1647
|
-
const url = `${baseEndpoint}/v1internal:loadCodeAssist`;
|
|
1648
|
-
const response = await fetchWithAgyCliTransport(url, {
|
|
1649
|
-
method: "POST",
|
|
1650
|
-
headers: loadHeaders,
|
|
1651
|
-
body: JSON.stringify({ metadata: buildAntigravityLoadCodeAssistMetadata() })
|
|
1652
|
-
}, { timeoutMs: 1e4 });
|
|
1653
|
-
if (!response.ok) {
|
|
1654
|
-
const message = await response.text().catch(() => "");
|
|
1655
|
-
errors.push(
|
|
1656
|
-
`loadCodeAssist ${response.status} at ${baseEndpoint}${message ? `: ${message}` : ""}`
|
|
1657
|
-
);
|
|
1658
|
-
continue;
|
|
1659
|
-
}
|
|
1660
|
-
const data = await response.json();
|
|
1661
|
-
if (typeof data.cloudaicompanionProject === "string" && data.cloudaicompanionProject) {
|
|
1662
|
-
return data.cloudaicompanionProject;
|
|
1663
|
-
}
|
|
1664
|
-
if (data.cloudaicompanionProject && typeof data.cloudaicompanionProject.id === "string" && data.cloudaicompanionProject.id) {
|
|
1665
|
-
return data.cloudaicompanionProject.id;
|
|
1666
|
-
}
|
|
1667
|
-
errors.push(`loadCodeAssist missing project id at ${baseEndpoint}`);
|
|
1668
|
-
} catch (e) {
|
|
1669
|
-
errors.push(
|
|
1670
|
-
`loadCodeAssist error at ${baseEndpoint}: ${e instanceof Error ? e.message : String(e)}`
|
|
1671
|
-
);
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
if (errors.length) {
|
|
1675
|
-
log2.warn("Failed to resolve Antigravity project via loadCodeAssist", { errors: errors.join("; ") });
|
|
1676
|
-
}
|
|
1677
|
-
return "";
|
|
1678
|
-
}
|
|
1679
|
-
async function exchangeAntigravity(code, state) {
|
|
1680
|
-
try {
|
|
1681
|
-
const { verifier, projectId } = decodeState(state);
|
|
1682
|
-
const startTime = Date.now();
|
|
1683
|
-
const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
|
|
1684
|
-
method: "POST",
|
|
1685
|
-
headers: {
|
|
1686
|
-
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
1687
|
-
"Accept": "*/*",
|
|
1688
|
-
"Accept-Encoding": "gzip, deflate, br",
|
|
1689
|
-
"User-Agent": GEMINI_CLI_HEADERS["User-Agent"]
|
|
1690
|
-
},
|
|
1691
|
-
body: new URLSearchParams({
|
|
1692
|
-
client_id: ANTIGRAVITY_CLIENT_ID,
|
|
1693
|
-
client_secret: ANTIGRAVITY_CLIENT_SECRET,
|
|
1694
|
-
code,
|
|
1695
|
-
grant_type: "authorization_code",
|
|
1696
|
-
redirect_uri: ANTIGRAVITY_REDIRECT_URI,
|
|
1697
|
-
code_verifier: verifier
|
|
1698
|
-
})
|
|
1699
|
-
});
|
|
1700
|
-
if (!tokenResponse.ok) {
|
|
1701
|
-
const errorText = await tokenResponse.text();
|
|
1702
|
-
return { type: "failed", error: errorText };
|
|
1703
|
-
}
|
|
1704
|
-
const tokenPayload = await tokenResponse.json();
|
|
1705
|
-
const userInfoResponse = await fetch(
|
|
1706
|
-
"https://www.googleapis.com/oauth2/v1/userinfo?alt=json",
|
|
1707
|
-
{
|
|
1708
|
-
headers: {
|
|
1709
|
-
Authorization: `Bearer ${tokenPayload.access_token}`,
|
|
1710
|
-
"User-Agent": GEMINI_CLI_HEADERS["User-Agent"]
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
);
|
|
1714
|
-
const userInfo = userInfoResponse.ok ? await userInfoResponse.json() : {};
|
|
1715
|
-
const refreshToken = tokenPayload.refresh_token;
|
|
1716
|
-
if (!refreshToken) {
|
|
1717
|
-
return { type: "failed", error: "Missing refresh token in response" };
|
|
1718
|
-
}
|
|
1719
|
-
let effectiveProjectId = projectId;
|
|
1720
|
-
if (!effectiveProjectId) {
|
|
1721
|
-
effectiveProjectId = await fetchProjectID(tokenPayload.access_token);
|
|
1722
|
-
}
|
|
1723
|
-
const storedRefresh = `${refreshToken}|${effectiveProjectId || ""}`;
|
|
1724
|
-
return {
|
|
1725
|
-
type: "success",
|
|
1726
|
-
refresh: storedRefresh,
|
|
1727
|
-
access: tokenPayload.access_token,
|
|
1728
|
-
expires: calculateTokenExpiry(startTime, tokenPayload.expires_in),
|
|
1729
|
-
email: userInfo.email,
|
|
1730
|
-
projectId: effectiveProjectId || ""
|
|
1731
|
-
};
|
|
1732
|
-
} catch (error) {
|
|
1733
|
-
return {
|
|
1734
|
-
type: "failed",
|
|
1735
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
authorizeAntigravity,
|
|
4
|
+
exchangeAntigravity,
|
|
5
|
+
getPublicModelDefinitions,
|
|
6
|
+
refreshAntigravityToken
|
|
7
|
+
} from "@cortexkit/antigravity-auth-core";
|
|
1739
8
|
|
|
1740
9
|
// src/credential-cache.ts
|
|
1741
10
|
var packedRefreshByAccessToken = /* @__PURE__ */ new Map();
|
|
@@ -1755,12 +24,23 @@ function getPackedRefresh(accessToken) {
|
|
|
1755
24
|
}
|
|
1756
25
|
|
|
1757
26
|
// src/stream.ts
|
|
27
|
+
import {
|
|
28
|
+
AgyRequestSessionStore,
|
|
29
|
+
ANTIGRAVITY_ENDPOINT,
|
|
30
|
+
buildAgyAgentRequestMetadata,
|
|
31
|
+
buildAntigravityHarnessUserAgent,
|
|
32
|
+
ensureProjectContext,
|
|
33
|
+
fetchWithAgyCliTransport,
|
|
34
|
+
orderAgyRequestPayloadInPlace,
|
|
35
|
+
resolveModelForHeaderStyle
|
|
36
|
+
} from "@cortexkit/antigravity-auth-core";
|
|
1758
37
|
import {
|
|
1759
38
|
calculateCost,
|
|
1760
39
|
createAssistantMessageEventStream
|
|
1761
40
|
} from "@earendil-works/pi-ai";
|
|
1762
41
|
|
|
1763
42
|
// src/convert.ts
|
|
43
|
+
import { toGeminiSchema } from "@cortexkit/antigravity-auth-core";
|
|
1764
44
|
function sanitize(text) {
|
|
1765
45
|
return text.replace(/[\uD800-\uDFFF]/gu, "\uFFFD");
|
|
1766
46
|
}
|
|
@@ -1775,18 +55,30 @@ function convertUserParts(content) {
|
|
|
1775
55
|
}
|
|
1776
56
|
return parts;
|
|
1777
57
|
}
|
|
1778
|
-
function convertAssistantParts(
|
|
58
|
+
function convertAssistantParts(message, preserveSignedHistory) {
|
|
1779
59
|
const parts = [];
|
|
1780
|
-
for (const block of content) {
|
|
1781
|
-
if (block.type === "
|
|
1782
|
-
|
|
60
|
+
for (const block of message.content) {
|
|
61
|
+
if (block.type === "thinking") {
|
|
62
|
+
if (preserveSignedHistory && block.thinking) {
|
|
63
|
+
parts.push({
|
|
64
|
+
text: sanitize(block.thinking),
|
|
65
|
+
thought: true,
|
|
66
|
+
...block.thinkingSignature ? { thoughtSignature: block.thinkingSignature } : {}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
} else if (block.type === "text" && block.text.trim()) {
|
|
70
|
+
parts.push({
|
|
71
|
+
text: sanitize(block.text),
|
|
72
|
+
...preserveSignedHistory && block.textSignature ? { thoughtSignature: block.textSignature } : {}
|
|
73
|
+
});
|
|
1783
74
|
} else if (block.type === "toolCall") {
|
|
1784
75
|
parts.push({
|
|
1785
76
|
functionCall: {
|
|
1786
77
|
name: block.name,
|
|
1787
|
-
args: block.arguments ?? {}
|
|
78
|
+
args: block.arguments ?? {},
|
|
79
|
+
id: block.id
|
|
1788
80
|
},
|
|
1789
|
-
...block.thoughtSignature ? { thoughtSignature: block.thoughtSignature } : {}
|
|
81
|
+
...preserveSignedHistory && block.thoughtSignature ? { thoughtSignature: block.thoughtSignature } : {}
|
|
1790
82
|
});
|
|
1791
83
|
}
|
|
1792
84
|
}
|
|
@@ -1799,32 +91,53 @@ function toolResultResponse(message) {
|
|
|
1799
91
|
}
|
|
1800
92
|
return { output: text };
|
|
1801
93
|
}
|
|
1802
|
-
function
|
|
94
|
+
function isSameTargetModel(message, options) {
|
|
95
|
+
if (!options?.provider || !options.model) return true;
|
|
96
|
+
return message.provider === options.provider && message.model === options.model;
|
|
97
|
+
}
|
|
98
|
+
function convertMessages(messages, options) {
|
|
1803
99
|
const contents = [];
|
|
100
|
+
const callMatchesTarget = /* @__PURE__ */ new Map();
|
|
101
|
+
for (const message of messages) {
|
|
102
|
+
if (message?.role !== "assistant") continue;
|
|
103
|
+
const matchesTarget = isSameTargetModel(message, options);
|
|
104
|
+
for (const block of message.content) {
|
|
105
|
+
if (block.type === "toolCall") {
|
|
106
|
+
callMatchesTarget.set(block.id, matchesTarget);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
1804
110
|
for (const message of messages) {
|
|
1805
111
|
if (!message) continue;
|
|
1806
112
|
if (message.role === "user") {
|
|
1807
|
-
const parts = typeof message.content === "string" ? message.content.trim() ? [{ text: sanitize(message.content) }] : [] : convertUserParts(
|
|
113
|
+
const parts = typeof message.content === "string" ? message.content.trim() ? [{ text: sanitize(message.content) }] : [] : convertUserParts(
|
|
114
|
+
message.content
|
|
115
|
+
);
|
|
1808
116
|
if (parts.length) contents.push({ role: "user", parts });
|
|
1809
117
|
continue;
|
|
1810
118
|
}
|
|
1811
119
|
if (message.role === "assistant") {
|
|
1812
|
-
const parts = convertAssistantParts(
|
|
120
|
+
const parts = convertAssistantParts(
|
|
121
|
+
message,
|
|
122
|
+
isSameTargetModel(message, options)
|
|
123
|
+
);
|
|
1813
124
|
if (parts.length) contents.push({ role: "model", parts });
|
|
1814
125
|
continue;
|
|
1815
126
|
}
|
|
1816
127
|
if (message.role === "toolResult") {
|
|
128
|
+
const role = callMatchesTarget.get(message.toolCallId) === true ? "model" : "user";
|
|
1817
129
|
const part = {
|
|
1818
130
|
functionResponse: {
|
|
1819
131
|
name: message.toolName,
|
|
1820
|
-
response: toolResultResponse(message)
|
|
132
|
+
response: toolResultResponse(message),
|
|
133
|
+
id: message.toolCallId
|
|
1821
134
|
}
|
|
1822
135
|
};
|
|
1823
136
|
const last = contents[contents.length - 1];
|
|
1824
|
-
if (last && last.role ===
|
|
137
|
+
if (last && last.role === role && last.parts.every((p) => "functionResponse" in p)) {
|
|
1825
138
|
last.parts.push(part);
|
|
1826
139
|
} else {
|
|
1827
|
-
contents.push({ role
|
|
140
|
+
contents.push({ role, parts: [part] });
|
|
1828
141
|
}
|
|
1829
142
|
}
|
|
1830
143
|
}
|
|
@@ -1845,14 +158,16 @@ function convertTools(tools) {
|
|
|
1845
158
|
}
|
|
1846
159
|
];
|
|
1847
160
|
}
|
|
1848
|
-
function buildGeminiRequest(context) {
|
|
161
|
+
function buildGeminiRequest(context, options) {
|
|
1849
162
|
const request = {
|
|
1850
|
-
contents: convertMessages(context.messages)
|
|
163
|
+
contents: convertMessages(context.messages, options)
|
|
1851
164
|
};
|
|
1852
165
|
const tools = convertTools(context.tools);
|
|
1853
166
|
if (tools) request.tools = tools;
|
|
1854
167
|
if (context.systemPrompt?.trim()) {
|
|
1855
|
-
request.systemInstruction = {
|
|
168
|
+
request.systemInstruction = {
|
|
169
|
+
parts: [{ text: sanitize(context.systemPrompt) }]
|
|
170
|
+
};
|
|
1856
171
|
}
|
|
1857
172
|
return request;
|
|
1858
173
|
}
|
|
@@ -1860,7 +175,24 @@ function buildGeminiRequest(context) {
|
|
|
1860
175
|
// src/stream.ts
|
|
1861
176
|
var STREAM_ACTION = "streamGenerateContent";
|
|
1862
177
|
var FALLBACK_SESSION_KEY = "__default__";
|
|
178
|
+
var TRAILING_USAGE_TIMEOUT_MS = 1e3;
|
|
1863
179
|
var requestSessions = new AgyRequestSessionStore("");
|
|
180
|
+
async function nextWithTimeout(iterator, timeoutMs, onTimeout) {
|
|
181
|
+
let timer;
|
|
182
|
+
try {
|
|
183
|
+
return await Promise.race([
|
|
184
|
+
iterator.next(),
|
|
185
|
+
new Promise((resolve) => {
|
|
186
|
+
timer = setTimeout(() => {
|
|
187
|
+
onTimeout();
|
|
188
|
+
resolve(void 0);
|
|
189
|
+
}, timeoutMs);
|
|
190
|
+
})
|
|
191
|
+
]);
|
|
192
|
+
} finally {
|
|
193
|
+
if (timer) clearTimeout(timer);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
1864
196
|
function mapFinishReason(reason) {
|
|
1865
197
|
switch (reason) {
|
|
1866
198
|
case "STOP":
|
|
@@ -1890,6 +222,35 @@ function createOutput(model) {
|
|
|
1890
222
|
timestamp: Date.now()
|
|
1891
223
|
};
|
|
1892
224
|
}
|
|
225
|
+
function asRecord(value) {
|
|
226
|
+
return value !== null && typeof value === "object" ? value : void 0;
|
|
227
|
+
}
|
|
228
|
+
function describeEmbeddedStreamFailure(chunk) {
|
|
229
|
+
if (chunk.error !== void 0) {
|
|
230
|
+
const error = asRecord(chunk.error);
|
|
231
|
+
if (!error) {
|
|
232
|
+
const detail = typeof chunk.error === "string" ? `: ${chunk.error}` : "";
|
|
233
|
+
return `Antigravity stream error${detail}`;
|
|
234
|
+
}
|
|
235
|
+
const labels = [];
|
|
236
|
+
if (typeof error.status === "string") labels.push(error.status);
|
|
237
|
+
if (typeof error.code === "number" || typeof error.code === "string") {
|
|
238
|
+
labels.push(`code ${String(error.code)}`);
|
|
239
|
+
}
|
|
240
|
+
const details = Array.isArray(error.details) ? error.details : [];
|
|
241
|
+
const reason2 = details.map((detail) => asRecord(detail)?.reason).find((value) => typeof value === "string");
|
|
242
|
+
if (reason2 && !labels.includes(reason2)) labels.push(reason2);
|
|
243
|
+
const label = labels.length > 0 ? ` (${labels.join(", ")})` : "";
|
|
244
|
+
const message2 = typeof error.message === "string" && error.message.length > 0 ? `: ${error.message}` : "";
|
|
245
|
+
return `Antigravity stream error${label}${message2}`;
|
|
246
|
+
}
|
|
247
|
+
const promptFeedback = asRecord(chunk.promptFeedback);
|
|
248
|
+
if (!promptFeedback) return void 0;
|
|
249
|
+
const reason = typeof promptFeedback.blockReason === "string" ? promptFeedback.blockReason : void 0;
|
|
250
|
+
const message = typeof promptFeedback.blockReasonMessage === "string" ? promptFeedback.blockReasonMessage : void 0;
|
|
251
|
+
if (!reason && !message) return void 0;
|
|
252
|
+
return `Antigravity prompt blocked${reason ? ` (${reason})` : ""}${message ? `: ${message}` : ""}`;
|
|
253
|
+
}
|
|
1893
254
|
function unwrapChunk(raw) {
|
|
1894
255
|
if (raw && typeof raw === "object" && "response" in raw) {
|
|
1895
256
|
const inner = raw.response;
|
|
@@ -1899,6 +260,21 @@ function unwrapChunk(raw) {
|
|
|
1899
260
|
}
|
|
1900
261
|
return raw;
|
|
1901
262
|
}
|
|
263
|
+
function convertGeminiToolCallPart(part, state) {
|
|
264
|
+
if (part.thought && !part.text && part.thoughtSignature) {
|
|
265
|
+
state.pendingThoughtSignature = part.thoughtSignature;
|
|
266
|
+
}
|
|
267
|
+
if (!part.functionCall) return void 0;
|
|
268
|
+
const thoughtSignature = part.thoughtSignature ?? state.pendingThoughtSignature;
|
|
269
|
+
state.pendingThoughtSignature = void 0;
|
|
270
|
+
return {
|
|
271
|
+
type: "toolCall",
|
|
272
|
+
id: part.functionCall.id ?? `call_${crypto.randomUUID()}`,
|
|
273
|
+
name: part.functionCall.name ?? "",
|
|
274
|
+
arguments: part.functionCall.args ?? {},
|
|
275
|
+
...thoughtSignature ? { thoughtSignature } : {}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
1902
278
|
function updateUsage(model, output, usage) {
|
|
1903
279
|
if (!usage) return;
|
|
1904
280
|
const cacheRead = usage.cachedContentTokenCount ?? output.usage.cacheRead;
|
|
@@ -1914,7 +290,7 @@ function updateUsage(model, output, usage) {
|
|
|
1914
290
|
async function* parseGeminiSse(response) {
|
|
1915
291
|
if (!response.body) return;
|
|
1916
292
|
const reader = response.body.getReader();
|
|
1917
|
-
const
|
|
293
|
+
const decoder = new TextDecoder();
|
|
1918
294
|
let buffer = "";
|
|
1919
295
|
const parseFrame = function* (frame) {
|
|
1920
296
|
for (const line of frame.split("\n")) {
|
|
@@ -1931,7 +307,7 @@ async function* parseGeminiSse(response) {
|
|
|
1931
307
|
while (true) {
|
|
1932
308
|
const { done, value } = await reader.read();
|
|
1933
309
|
if (done) break;
|
|
1934
|
-
buffer +=
|
|
310
|
+
buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
|
|
1935
311
|
let boundary = buffer.indexOf("\n\n");
|
|
1936
312
|
while (boundary !== -1) {
|
|
1937
313
|
const frame = buffer.slice(0, boundary);
|
|
@@ -1962,7 +338,8 @@ function finalizePiAntigravityRequest(request, wireModel, scope) {
|
|
|
1962
338
|
scope.session,
|
|
1963
339
|
request,
|
|
1964
340
|
wireModel,
|
|
1965
|
-
scope.timestamp
|
|
341
|
+
scope.timestamp,
|
|
342
|
+
{ stepCountMode: "cli" }
|
|
1966
343
|
);
|
|
1967
344
|
request.labels = metadata.labels;
|
|
1968
345
|
request.sessionId = metadata.sessionId;
|
|
@@ -1980,7 +357,10 @@ function resolvePiAntigravityModel(model, reasoning) {
|
|
|
1980
357
|
return resolveModelForHeaderStyle(`${baseModel}-${tier}`, "antigravity");
|
|
1981
358
|
}
|
|
1982
359
|
async function sendAntigravityRequest(options) {
|
|
1983
|
-
const resolved = resolvePiAntigravityModel(
|
|
360
|
+
const resolved = resolvePiAntigravityModel(
|
|
361
|
+
options.model,
|
|
362
|
+
options.streamOptions?.reasoning
|
|
363
|
+
);
|
|
1984
364
|
const wireModel = resolved.actualModel;
|
|
1985
365
|
const packedRefresh = getPackedRefresh(options.accessToken) ?? "";
|
|
1986
366
|
const projectContext = await ensureProjectContext({
|
|
@@ -1989,7 +369,10 @@ async function sendAntigravityRequest(options) {
|
|
|
1989
369
|
access: options.accessToken,
|
|
1990
370
|
expires: Date.now() + 6e4
|
|
1991
371
|
});
|
|
1992
|
-
const request = buildGeminiRequest(options.context
|
|
372
|
+
const request = buildGeminiRequest(options.context, {
|
|
373
|
+
provider: options.model.provider,
|
|
374
|
+
model: options.model.id
|
|
375
|
+
});
|
|
1993
376
|
const generationConfig = {};
|
|
1994
377
|
if (resolved.thinkingLevel) {
|
|
1995
378
|
generationConfig.thinkingConfig = {
|
|
@@ -2009,10 +392,12 @@ async function sendAntigravityRequest(options) {
|
|
|
2009
392
|
if (Object.keys(generationConfig).length > 0) {
|
|
2010
393
|
request.generationConfig = generationConfig;
|
|
2011
394
|
}
|
|
2012
|
-
const requestScope = requestSessions.beginRequest(
|
|
2013
|
-
|
|
395
|
+
const requestScope = requestSessions.beginRequest(options.sessionKey);
|
|
396
|
+
const requestId = finalizePiAntigravityRequest(
|
|
397
|
+
request,
|
|
398
|
+
wireModel,
|
|
399
|
+
requestScope
|
|
2014
400
|
);
|
|
2015
|
-
const requestId = finalizePiAntigravityRequest(request, wireModel, requestScope);
|
|
2016
401
|
const envelope = {
|
|
2017
402
|
project: projectContext.effectiveProjectId,
|
|
2018
403
|
requestId,
|
|
@@ -2034,7 +419,7 @@ async function sendAntigravityRequest(options) {
|
|
|
2034
419
|
},
|
|
2035
420
|
body: JSON.stringify(envelope)
|
|
2036
421
|
},
|
|
2037
|
-
{ signal: options.streamOptions?.signal ?? null }
|
|
422
|
+
{ signal: options.signal ?? options.streamOptions?.signal ?? null }
|
|
2038
423
|
);
|
|
2039
424
|
}
|
|
2040
425
|
function streamCortexKitAntigravity(model, context, options) {
|
|
@@ -2042,49 +427,163 @@ function streamCortexKitAntigravity(model, context, options) {
|
|
|
2042
427
|
void (async () => {
|
|
2043
428
|
const output = createOutput(model);
|
|
2044
429
|
stream.push({ type: "start", partial: output });
|
|
430
|
+
let response;
|
|
431
|
+
let requestAbort;
|
|
432
|
+
let chunkIterator;
|
|
2045
433
|
try {
|
|
2046
434
|
const accessToken = options?.apiKey ?? "";
|
|
2047
|
-
if (!accessToken)
|
|
2048
|
-
|
|
435
|
+
if (!accessToken)
|
|
436
|
+
throw new Error("Missing Antigravity OAuth access token");
|
|
437
|
+
const sessionKey = getRequestSessionKey(context, options);
|
|
438
|
+
requestAbort = new AbortController();
|
|
439
|
+
const requestSignal = options?.signal ? AbortSignal.any([options.signal, requestAbort.signal]) : requestAbort.signal;
|
|
440
|
+
response = await sendAntigravityRequest({
|
|
2049
441
|
model,
|
|
2050
442
|
context,
|
|
2051
443
|
streamOptions: options,
|
|
2052
|
-
accessToken
|
|
444
|
+
accessToken,
|
|
445
|
+
sessionKey,
|
|
446
|
+
signal: requestSignal
|
|
2053
447
|
});
|
|
2054
448
|
if (!response.ok) {
|
|
2055
|
-
throw new Error(
|
|
449
|
+
throw new Error(
|
|
450
|
+
`Antigravity request failed: HTTP ${response.status} ${await response.text()}`
|
|
451
|
+
);
|
|
2056
452
|
}
|
|
2057
453
|
const content = output.content;
|
|
454
|
+
const toolCallState = {};
|
|
2058
455
|
let textIndex = -1;
|
|
2059
|
-
let
|
|
2060
|
-
|
|
456
|
+
let thinkingIndex = -1;
|
|
457
|
+
let terminalSeen = false;
|
|
458
|
+
const closeText = () => {
|
|
459
|
+
if (textIndex === -1) return;
|
|
460
|
+
const block = content[textIndex];
|
|
461
|
+
if (block?.type === "text") {
|
|
462
|
+
stream.push({
|
|
463
|
+
type: "text_end",
|
|
464
|
+
contentIndex: textIndex,
|
|
465
|
+
content: block.text,
|
|
466
|
+
partial: output
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
textIndex = -1;
|
|
470
|
+
};
|
|
471
|
+
const closeThinking = () => {
|
|
472
|
+
if (thinkingIndex === -1) return;
|
|
473
|
+
const block = content[thinkingIndex];
|
|
474
|
+
if (block?.type === "thinking") {
|
|
475
|
+
stream.push({
|
|
476
|
+
type: "thinking_end",
|
|
477
|
+
contentIndex: thinkingIndex,
|
|
478
|
+
content: block.thinking,
|
|
479
|
+
partial: output
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
thinkingIndex = -1;
|
|
483
|
+
};
|
|
484
|
+
chunkIterator = parseGeminiSse(response)[Symbol.asyncIterator]();
|
|
485
|
+
let terminalFinishReason;
|
|
486
|
+
while (true) {
|
|
487
|
+
const next = terminalSeen ? await nextWithTimeout(
|
|
488
|
+
chunkIterator,
|
|
489
|
+
TRAILING_USAGE_TIMEOUT_MS,
|
|
490
|
+
() => requestAbort?.abort()
|
|
491
|
+
) : await chunkIterator.next();
|
|
492
|
+
if (!next) break;
|
|
493
|
+
if (next.done) break;
|
|
494
|
+
const chunk = next.value;
|
|
495
|
+
const embeddedFailure = describeEmbeddedStreamFailure(chunk);
|
|
496
|
+
if (embeddedFailure) throw new Error(embeddedFailure);
|
|
2061
497
|
updateUsage(model, output, chunk.usageMetadata);
|
|
498
|
+
if (terminalSeen) {
|
|
499
|
+
if (chunk.usageMetadata) break;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
2062
502
|
const candidate = chunk.candidates?.[0];
|
|
2063
503
|
const parts = candidate?.content?.parts ?? [];
|
|
2064
504
|
for (const part of parts) {
|
|
2065
|
-
if (part.functionCall) {
|
|
2066
|
-
const
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
505
|
+
if (!part.thought && !part.functionCall && !part.text && part.thoughtSignature) {
|
|
506
|
+
const block = textIndex === -1 ? void 0 : content[textIndex];
|
|
507
|
+
if (block?.type === "text") {
|
|
508
|
+
block.textSignature = part.thoughtSignature;
|
|
509
|
+
} else {
|
|
510
|
+
toolCallState.pendingThoughtSignature = part.thoughtSignature;
|
|
511
|
+
}
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
const toolCall = convertGeminiToolCallPart(part, toolCallState);
|
|
515
|
+
if (toolCall) {
|
|
516
|
+
closeText();
|
|
517
|
+
closeThinking();
|
|
2073
518
|
content.push(toolCall);
|
|
2074
519
|
const idx = content.length - 1;
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
520
|
+
stream.push({
|
|
521
|
+
type: "toolcall_start",
|
|
522
|
+
contentIndex: idx,
|
|
523
|
+
partial: output
|
|
524
|
+
});
|
|
525
|
+
stream.push({
|
|
526
|
+
type: "toolcall_end",
|
|
527
|
+
contentIndex: idx,
|
|
528
|
+
toolCall,
|
|
529
|
+
partial: output
|
|
530
|
+
});
|
|
2078
531
|
output.stopReason = "toolUse";
|
|
2079
|
-
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
if (part.thought) {
|
|
535
|
+
if (typeof part.text !== "string" || part.text.length === 0)
|
|
536
|
+
continue;
|
|
537
|
+
closeText();
|
|
538
|
+
if (thinkingIndex === -1) {
|
|
539
|
+
content.push({
|
|
540
|
+
type: "thinking",
|
|
541
|
+
thinking: "",
|
|
542
|
+
...part.thoughtSignature ? { thinkingSignature: part.thoughtSignature } : {}
|
|
543
|
+
});
|
|
544
|
+
thinkingIndex = content.length - 1;
|
|
545
|
+
stream.push({
|
|
546
|
+
type: "thinking_start",
|
|
547
|
+
contentIndex: thinkingIndex,
|
|
548
|
+
partial: output
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
const block = content[thinkingIndex];
|
|
552
|
+
if (block?.type === "thinking") {
|
|
553
|
+
block.thinking += part.text;
|
|
554
|
+
if (part.thoughtSignature)
|
|
555
|
+
block.thinkingSignature = part.thoughtSignature;
|
|
556
|
+
stream.push({
|
|
557
|
+
type: "thinking_delta",
|
|
558
|
+
contentIndex: thinkingIndex,
|
|
559
|
+
delta: part.text,
|
|
560
|
+
partial: output
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
if (typeof part.text === "string" && part.text.length > 0) {
|
|
566
|
+
closeThinking();
|
|
2080
567
|
if (textIndex === -1) {
|
|
2081
|
-
|
|
568
|
+
const textSignature = part.thoughtSignature ?? toolCallState.pendingThoughtSignature;
|
|
569
|
+
toolCallState.pendingThoughtSignature = void 0;
|
|
570
|
+
content.push({
|
|
571
|
+
type: "text",
|
|
572
|
+
text: "",
|
|
573
|
+
...textSignature ? { textSignature } : {}
|
|
574
|
+
});
|
|
2082
575
|
textIndex = content.length - 1;
|
|
2083
|
-
stream.push({
|
|
576
|
+
stream.push({
|
|
577
|
+
type: "text_start",
|
|
578
|
+
contentIndex: textIndex,
|
|
579
|
+
partial: output
|
|
580
|
+
});
|
|
2084
581
|
}
|
|
2085
582
|
const block = content[textIndex];
|
|
2086
|
-
if (block
|
|
583
|
+
if (block?.type === "text") {
|
|
2087
584
|
block.text += part.text;
|
|
585
|
+
if (part.thoughtSignature)
|
|
586
|
+
block.textSignature = part.thoughtSignature;
|
|
2088
587
|
stream.push({
|
|
2089
588
|
type: "text_delta",
|
|
2090
589
|
contentIndex: textIndex,
|
|
@@ -2095,32 +594,52 @@ function streamCortexKitAntigravity(model, context, options) {
|
|
|
2095
594
|
}
|
|
2096
595
|
}
|
|
2097
596
|
if (candidate?.finishReason) {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
if (block && block.type === "text") {
|
|
2101
|
-
stream.push({ type: "text_end", contentIndex: textIndex, content: block.text, partial: output });
|
|
2102
|
-
}
|
|
2103
|
-
textIndex = -1;
|
|
2104
|
-
}
|
|
597
|
+
closeText();
|
|
598
|
+
closeThinking();
|
|
2105
599
|
if (output.stopReason !== "toolUse") {
|
|
2106
600
|
output.stopReason = mapFinishReason(candidate.finishReason);
|
|
2107
601
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
602
|
+
terminalSeen = true;
|
|
603
|
+
terminalFinishReason = candidate.finishReason;
|
|
604
|
+
const needsTrailingUsage = model.id.toLowerCase().includes("gpt-oss") && !chunk.usageMetadata;
|
|
605
|
+
if (!needsTrailingUsage) break;
|
|
2110
606
|
}
|
|
2111
607
|
}
|
|
2112
|
-
if (
|
|
608
|
+
if (terminalSeen) {
|
|
609
|
+
try {
|
|
610
|
+
await chunkIterator.return?.(void 0);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
if (!requestAbort.signal.aborted) throw error;
|
|
613
|
+
}
|
|
2113
614
|
await response.body?.cancel().catch(() => {
|
|
2114
615
|
});
|
|
2115
616
|
}
|
|
2116
617
|
if (options?.signal?.aborted) throw new Error("Request was aborted");
|
|
618
|
+
if (!terminalSeen) {
|
|
619
|
+
throw new Error(
|
|
620
|
+
"Antigravity stream ended without a terminal candidate response"
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
if (content.length === 0) {
|
|
624
|
+
throw new Error(
|
|
625
|
+
`Antigravity returned an empty response${terminalFinishReason ? ` (${terminalFinishReason})` : ""}`
|
|
626
|
+
);
|
|
627
|
+
}
|
|
2117
628
|
stream.push({
|
|
2118
629
|
type: "done",
|
|
2119
630
|
reason: output.stopReason,
|
|
2120
631
|
message: output
|
|
2121
632
|
});
|
|
633
|
+
if (output.stopReason === "stop" || output.stopReason === "length") {
|
|
634
|
+
requestSessions.completeExecution(sessionKey);
|
|
635
|
+
}
|
|
2122
636
|
stream.end();
|
|
2123
637
|
} catch (error) {
|
|
638
|
+
requestAbort?.abort();
|
|
639
|
+
await chunkIterator?.return?.(void 0).catch(() => {
|
|
640
|
+
});
|
|
641
|
+
await response?.body?.cancel().catch(() => {
|
|
642
|
+
});
|
|
2124
643
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
2125
644
|
output.errorMessage = error instanceof Error ? error.message : String(error);
|
|
2126
645
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|