pi-provider-antigravity 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +328 -244
- package/dist/index.js.map +2 -2
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
3
3
|
|
|
4
4
|
// src/protocol.ts
|
|
5
5
|
var DEFAULT_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
|
|
6
|
-
var DEFAULT_USER_AGENT = "antigravity/cli/1.
|
|
6
|
+
var DEFAULT_USER_AGENT = "antigravity/cli/1.2.0 (aidev_client; os_type=linux; arch=amd64; cl=978750357; auth_method=consumer)";
|
|
7
7
|
var PROVIDER_ID = "antigravity";
|
|
8
8
|
async function postAntigravity({
|
|
9
9
|
token,
|
|
@@ -187,10 +187,34 @@ function parseStoredCredentials(rawApiKey) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// src/model-catalog.ts
|
|
190
|
+
var CANONICAL_TIER_SUFFIXES = Object.freeze({
|
|
191
|
+
low: "-low",
|
|
192
|
+
medium: "-medium",
|
|
193
|
+
high: "-high"
|
|
194
|
+
});
|
|
195
|
+
var TIER_ALIASES = Object.freeze({
|
|
196
|
+
low: Object.freeze(["-extra-low"]),
|
|
197
|
+
medium: Object.freeze([]),
|
|
198
|
+
high: Object.freeze(["-thinking", "-agent"])
|
|
199
|
+
});
|
|
200
|
+
var SPECIAL_TIER_SUFFIXES = Object.freeze(["-tiered"]);
|
|
201
|
+
var ALL_TIER_SUFFIXES = Object.freeze([
|
|
202
|
+
.../* @__PURE__ */ new Set([
|
|
203
|
+
...Object.values(CANONICAL_TIER_SUFFIXES),
|
|
204
|
+
...Object.values(TIER_ALIASES).flat(),
|
|
205
|
+
...SPECIAL_TIER_SUFFIXES
|
|
206
|
+
])
|
|
207
|
+
]);
|
|
208
|
+
var TIER_SUFFIX_PATTERN = new RegExp(
|
|
209
|
+
`-(?:${ALL_TIER_SUFFIXES.map((s) => s.replace(/^-/, "")).join("|")})$`
|
|
210
|
+
);
|
|
211
|
+
function tierSpellings(tier) {
|
|
212
|
+
return [CANONICAL_TIER_SUFFIXES[tier], ...TIER_ALIASES[tier]];
|
|
213
|
+
}
|
|
190
214
|
function extractBaseModelId(runtimeId) {
|
|
191
215
|
if (runtimeId === "gemini-pro-agent") return "gemini-3.1-pro";
|
|
192
216
|
if (runtimeId.startsWith("gemini-3.1-pro-")) return "gemini-3.1-pro";
|
|
193
|
-
return runtimeId.replace(
|
|
217
|
+
return runtimeId.replace(TIER_SUFFIX_PATTERN, "");
|
|
194
218
|
}
|
|
195
219
|
function classifyModelFamily(modelId) {
|
|
196
220
|
const bare = ((modelId || "").split("/").pop() || "").toLowerCase();
|
|
@@ -206,37 +230,6 @@ function isCompatibleFamily(msgModel, targetModelId) {
|
|
|
206
230
|
if (msgFamily !== "unknown" && msgFamily === classifyModelFamily(targetModelId)) return true;
|
|
207
231
|
return extractBaseModelId(msgModel) === extractBaseModelId(targetModelId);
|
|
208
232
|
}
|
|
209
|
-
function getThinkingConfig(modelId, effort) {
|
|
210
|
-
const isOff = effort === "off" || effort === "none";
|
|
211
|
-
if (isOff) {
|
|
212
|
-
return { includeThoughts: false, thinkingBudget: 0 };
|
|
213
|
-
}
|
|
214
|
-
if (modelId.includes("flash")) {
|
|
215
|
-
if (effort === "high" || effort === "xhigh" || modelId.endsWith("-high") || modelId.endsWith("-agent")) {
|
|
216
|
-
return { includeThoughts: true, thinkingBudget: -1 };
|
|
217
|
-
}
|
|
218
|
-
if (effort === "medium" || modelId.endsWith("-medium")) {
|
|
219
|
-
return { includeThoughts: true, thinkingBudget: 4e3 };
|
|
220
|
-
}
|
|
221
|
-
if (effort === "low" || effort === "minimal" || modelId.endsWith("-low")) {
|
|
222
|
-
return { includeThoughts: true, thinkingBudget: 1e3 };
|
|
223
|
-
}
|
|
224
|
-
return { includeThoughts: true, thinkingBudget: -1 };
|
|
225
|
-
}
|
|
226
|
-
if (modelId.includes("pro")) {
|
|
227
|
-
if (effort === "low" || effort === "minimal" || modelId.endsWith("-low")) {
|
|
228
|
-
return { includeThoughts: true, thinkingBudget: 1001 };
|
|
229
|
-
}
|
|
230
|
-
return { includeThoughts: true, thinkingBudget: 10001 };
|
|
231
|
-
}
|
|
232
|
-
if (modelId.startsWith("claude-")) {
|
|
233
|
-
return { includeThoughts: true, thinkingBudget: 1024 };
|
|
234
|
-
}
|
|
235
|
-
if (modelId.startsWith("gpt-oss-")) {
|
|
236
|
-
return { includeThoughts: true, thinkingBudget: 8192 };
|
|
237
|
-
}
|
|
238
|
-
return { includeThoughts: true, thinkingBudget: -1 };
|
|
239
|
-
}
|
|
240
233
|
function buildThinkingMap(models) {
|
|
241
234
|
return Object.fromEntries(
|
|
242
235
|
models.map((m) => [
|
|
@@ -248,87 +241,110 @@ function buildThinkingMap(models) {
|
|
|
248
241
|
])
|
|
249
242
|
);
|
|
250
243
|
}
|
|
251
|
-
|
|
252
|
-
enums: {},
|
|
253
|
-
runtimeIds: [],
|
|
254
|
-
thinking: {},
|
|
255
|
-
deprecated: {},
|
|
256
|
-
version: 0
|
|
257
|
-
};
|
|
258
|
-
function getCatalogSnapshot() {
|
|
244
|
+
function snapshotFromCatalog(catalog) {
|
|
259
245
|
return {
|
|
260
|
-
enums: { ...
|
|
261
|
-
runtimeIds: [...
|
|
246
|
+
enums: { ...catalog.modelEnums },
|
|
247
|
+
runtimeIds: [...new Set(catalog.models.map((m) => m.id))],
|
|
248
|
+
thinking: buildThinkingMap(catalog.models),
|
|
249
|
+
deprecated: { ...catalog.deprecated ?? {} }
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function copySnapshot(snapshot) {
|
|
253
|
+
return {
|
|
254
|
+
enums: { ...snapshot.enums },
|
|
255
|
+
runtimeIds: [...snapshot.runtimeIds],
|
|
262
256
|
thinking: Object.fromEntries(
|
|
263
|
-
Object.entries(
|
|
257
|
+
Object.entries(snapshot.thinking).map(([id, info]) => [id, { ...info }])
|
|
264
258
|
),
|
|
265
|
-
deprecated: { ...
|
|
266
|
-
version: activeStore.version
|
|
259
|
+
deprecated: { ...snapshot.deprecated }
|
|
267
260
|
};
|
|
268
261
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
262
|
+
var EMPTY_SNAPSHOT = () => ({ enums: {}, runtimeIds: [], thinking: {}, deprecated: {} });
|
|
263
|
+
function createCatalogStore() {
|
|
264
|
+
let generation = { snapshot: EMPTY_SNAPSHOT(), version: 0 };
|
|
265
|
+
return {
|
|
266
|
+
generation: () => ({ ...generation, snapshot: copySnapshot(generation.snapshot) }),
|
|
267
|
+
record: (catalog) => {
|
|
268
|
+
generation = {
|
|
269
|
+
snapshot: snapshotFromCatalog(catalog),
|
|
270
|
+
items: catalog,
|
|
271
|
+
version: generation.version + 1
|
|
272
|
+
};
|
|
273
|
+
},
|
|
274
|
+
// Version 0 means no fetch has landed in this process, so nothing here can
|
|
275
|
+
// be fresher than the persist: an older file must never replace a recorded
|
|
276
|
+
// generation (the refresh path calls this on every start, including after
|
|
277
|
+
// a successful fetch in the same process).
|
|
278
|
+
restore: (snapshot) => {
|
|
279
|
+
if (generation.version > 0) return;
|
|
280
|
+
generation = { snapshot: copySnapshot(snapshot), version: 0 };
|
|
281
|
+
}
|
|
276
282
|
};
|
|
277
283
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
284
|
+
function toPersistedSnapshot(snapshot) {
|
|
285
|
+
return {
|
|
286
|
+
modelEnums: { ...snapshot.enums },
|
|
287
|
+
runtimeIds: [...snapshot.runtimeIds],
|
|
288
|
+
thinking: { ...snapshot.thinking },
|
|
289
|
+
deprecated: { ...snapshot.deprecated }
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function isStringRecord(value) {
|
|
293
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
287
294
|
}
|
|
288
|
-
function
|
|
289
|
-
return
|
|
295
|
+
function isThinkingRecord(value) {
|
|
296
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((entry) => !!entry && typeof entry === "object" && !Array.isArray(entry));
|
|
290
297
|
}
|
|
291
|
-
function
|
|
292
|
-
if (
|
|
298
|
+
function fromPersistedSnapshot(raw) {
|
|
299
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
300
|
+
const entry = raw;
|
|
301
|
+
const enums = isStringRecord(entry.modelEnums) ? entry.modelEnums : void 0;
|
|
302
|
+
const runtimeIds = Array.isArray(entry.runtimeIds) ? entry.runtimeIds.filter((id) => typeof id === "string") : void 0;
|
|
303
|
+
const thinking = isThinkingRecord(entry.thinking) ? entry.thinking : void 0;
|
|
304
|
+
const deprecated = isStringRecord(entry.deprecated) ? entry.deprecated : void 0;
|
|
305
|
+
if (!enums && !runtimeIds && !thinking && !deprecated) return void 0;
|
|
306
|
+
return { enums: enums ?? {}, runtimeIds: runtimeIds ?? [], thinking: thinking ?? {}, deprecated: deprecated ?? {} };
|
|
307
|
+
}
|
|
308
|
+
var TIER_FALLBACKS = Object.freeze({
|
|
309
|
+
minimal: Object.freeze(["-low", "-extra-low", ""]),
|
|
310
|
+
low: Object.freeze(["-extra-low", ""]),
|
|
311
|
+
medium: Object.freeze(["", "-high"]),
|
|
312
|
+
// Gemini 3.1 Pro lists no -medium: up to high, never down
|
|
313
|
+
high: Object.freeze(["-thinking", "-agent", ""]),
|
|
314
|
+
// Claude's high tier is -thinking
|
|
315
|
+
xhigh: Object.freeze(["-high", "-thinking", "-agent", ""]),
|
|
316
|
+
max: Object.freeze(["-high", "-thinking", "-agent", ""])
|
|
317
|
+
});
|
|
318
|
+
var DEFAULT_TIER_ORDER = Object.freeze([
|
|
319
|
+
CANONICAL_TIER_SUFFIXES.high,
|
|
320
|
+
...TIER_ALIASES.high,
|
|
321
|
+
""
|
|
322
|
+
]);
|
|
323
|
+
function tierCandidateOrder(effort) {
|
|
324
|
+
if (!effort) return DEFAULT_TIER_ORDER;
|
|
325
|
+
const canonical = effort in CANONICAL_TIER_SUFFIXES ? [CANONICAL_TIER_SUFFIXES[effort]] : [`-${effort}`];
|
|
326
|
+
const fallbacks = TIER_FALLBACKS[effort] ?? DEFAULT_TIER_ORDER;
|
|
327
|
+
return [.../* @__PURE__ */ new Set([...canonical, ...fallbacks])];
|
|
328
|
+
}
|
|
329
|
+
function resolveRuntimeModelId(modelId, effort, availableRuntimeIds) {
|
|
330
|
+
if (ALL_TIER_SUFFIXES.some((suffix) => modelId.endsWith(suffix))) {
|
|
293
331
|
return modelId;
|
|
294
332
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
candidates.push(`${modelId}-low`, `${modelId}-extra-low`, modelId);
|
|
302
|
-
} else if (isMedium) {
|
|
303
|
-
candidates.push(`${modelId}-medium`, modelId);
|
|
304
|
-
} else {
|
|
305
|
-
candidates.push(`${modelId}-high`, `${modelId}-thinking`, `${modelId}-agent`, modelId);
|
|
306
|
-
}
|
|
307
|
-
for (const cand of candidates) {
|
|
308
|
-
if (availableRuntimeIds.includes(cand)) {
|
|
309
|
-
return cand;
|
|
333
|
+
if (availableRuntimeIds.length > 0) {
|
|
334
|
+
const variants = new Set(availableRuntimeIds.filter((id) => extractBaseModelId(id) === modelId));
|
|
335
|
+
const order = tierCandidateOrder(effort);
|
|
336
|
+
for (const suffix of order) {
|
|
337
|
+
if (variants.has(`${modelId}${suffix}`)) {
|
|
338
|
+
return `${modelId}${suffix}`;
|
|
310
339
|
}
|
|
311
340
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if (isMedium) return `${modelId}-medium`;
|
|
316
|
-
return `${modelId}-high`;
|
|
317
|
-
}
|
|
318
|
-
if (modelId.includes("pro")) {
|
|
319
|
-
if (isLow) return `${modelId}-low`;
|
|
320
|
-
return `${modelId}-high`;
|
|
321
|
-
}
|
|
322
|
-
if (modelId.startsWith("claude-")) {
|
|
323
|
-
if (modelId.includes("opus")) return `${modelId}-thinking`;
|
|
324
|
-
return modelId;
|
|
325
|
-
}
|
|
326
|
-
if (modelId.startsWith("gpt-")) {
|
|
327
|
-
return `${modelId}-medium`;
|
|
341
|
+
if (variants.size === 1) {
|
|
342
|
+
return [...variants][0];
|
|
343
|
+
}
|
|
328
344
|
}
|
|
329
345
|
return modelId;
|
|
330
346
|
}
|
|
331
|
-
function resolveModelPlan(publicModelId, effort, snapshot
|
|
347
|
+
function resolveModelPlan(publicModelId, effort, snapshot) {
|
|
332
348
|
const runtimeModelId = followRenames(
|
|
333
349
|
resolveRuntimeModelId(publicModelId, effort, snapshot.runtimeIds),
|
|
334
350
|
snapshot
|
|
@@ -336,14 +352,14 @@ function resolveModelPlan(publicModelId, effort, snapshot = getCatalogSnapshot()
|
|
|
336
352
|
const modelEnum = snapshot.enums[runtimeModelId];
|
|
337
353
|
if (!modelEnum) {
|
|
338
354
|
throw new Error(
|
|
339
|
-
`Unknown model "${runtimeModelId}" (not in catalog snapshot
|
|
355
|
+
`Unknown model "${runtimeModelId}" (not in the current catalog snapshot). Run /antigravity refresh and pick a current model.`
|
|
340
356
|
);
|
|
341
357
|
}
|
|
342
358
|
const family = classifyModelFamily(runtimeModelId);
|
|
343
359
|
return {
|
|
344
360
|
runtimeModelId,
|
|
345
361
|
modelEnum,
|
|
346
|
-
thinkingConfig: resolveThinkingConfig(runtimeModelId,
|
|
362
|
+
thinkingConfig: resolveThinkingConfig(runtimeModelId, snapshot),
|
|
347
363
|
isNonGemini: family !== "gemini",
|
|
348
364
|
isClaude: family === "claude"
|
|
349
365
|
};
|
|
@@ -359,29 +375,27 @@ function followRenames(runtimeModelId, snapshot) {
|
|
|
359
375
|
}
|
|
360
376
|
return current;
|
|
361
377
|
}
|
|
362
|
-
function resolveThinkingConfig(runtimeModelId,
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
const info = snapshot.thinking?.[runtimeModelId];
|
|
367
|
-
if (info) {
|
|
368
|
-
if (typeof info.budget === "number") {
|
|
369
|
-
return { includeThoughts: true, thinkingBudget: info.budget };
|
|
370
|
-
}
|
|
371
|
-
if (!info.supportsThinking) {
|
|
372
|
-
return { includeThoughts: false, thinkingBudget: 0 };
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
return getThinkingConfig(runtimeModelId, effort);
|
|
378
|
+
function resolveThinkingConfig(runtimeModelId, snapshot) {
|
|
379
|
+
const budget = snapshot.thinking[runtimeModelId]?.budget;
|
|
380
|
+
return typeof budget === "number" ? { includeThoughts: true, thinkingBudget: budget } : { includeThoughts: false, thinkingBudget: 0 };
|
|
376
381
|
}
|
|
377
382
|
function estimateModelCost(_baseId) {
|
|
378
383
|
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
379
384
|
}
|
|
380
385
|
function synthesizeDynamicModel(baseId, items) {
|
|
381
386
|
const repItem = items.find((it) => it.id === `${baseId}-high` || it.id === baseId) || items[0];
|
|
387
|
+
const hasVariant = (suffixes) => items.some((it) => suffixes.some((suffix) => it.id.endsWith(suffix)));
|
|
388
|
+
const thinkingLevelMap = {
|
|
389
|
+
off: null,
|
|
390
|
+
minimal: null,
|
|
391
|
+
...hasVariant(tierSpellings("low")) ? {} : { low: null },
|
|
392
|
+
...hasVariant(tierSpellings("medium")) ? {} : { medium: null },
|
|
393
|
+
...hasVariant(tierSpellings("high")) || items.some((it) => it.id === baseId) ? {} : { high: null }
|
|
394
|
+
};
|
|
395
|
+
const family = classifyModelFamily(baseId);
|
|
382
396
|
const isFlash = baseId.includes("flash");
|
|
383
|
-
const isClaude =
|
|
384
|
-
const isGpt =
|
|
397
|
+
const isClaude = family === "claude";
|
|
398
|
+
const isGpt = family === "gpt";
|
|
385
399
|
const defaultContext = isFlash ? 1048576 : isClaude ? 25e4 : isGpt ? 128e3 : 1048576;
|
|
386
400
|
const defaultMaxOutput = isClaude ? 64e3 : isGpt ? 32768 : 65536;
|
|
387
401
|
return {
|
|
@@ -391,6 +405,7 @@ function synthesizeDynamicModel(baseId, items) {
|
|
|
391
405
|
api: "antigravity-api",
|
|
392
406
|
baseUrl: DEFAULT_ENDPOINT,
|
|
393
407
|
reasoning: repItem?.supportsThinking ?? true,
|
|
408
|
+
thinkingLevelMap,
|
|
394
409
|
input: repItem?.supportsImages ? ["text", "image"] : ["text"],
|
|
395
410
|
cost: estimateModelCost(baseId),
|
|
396
411
|
contextWindow: repItem?.maxTokens || defaultContext,
|
|
@@ -485,53 +500,44 @@ function formatModelsList(catalog) {
|
|
|
485
500
|
}
|
|
486
501
|
|
|
487
502
|
// src/catalog-refresh.ts
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
const
|
|
493
|
-
if ((storedEnums || storedRuntimeIds || storedThinking || storedDeprecated) && getCatalogSnapshot().version === 0) {
|
|
494
|
-
updateCatalogStore(storedEnums || {}, storedRuntimeIds || [], storedThinking || {}, storedDeprecated || {});
|
|
495
|
-
}
|
|
503
|
+
var PRIVATE_SNAPSHOT_KEY = "pi-provider-antigravity";
|
|
504
|
+
async function refreshCatalog(context, store) {
|
|
505
|
+
const persisted = fromPersistedSnapshot(context.stored?.[PRIVATE_SNAPSHOT_KEY]);
|
|
506
|
+
if (persisted) store.restore(persisted);
|
|
507
|
+
const storedModels = () => [...context.stored?.models ?? []];
|
|
496
508
|
if (!context.allowNetwork) {
|
|
497
|
-
return
|
|
509
|
+
return storedModels();
|
|
498
510
|
}
|
|
499
511
|
try {
|
|
500
|
-
const
|
|
512
|
+
const credential = context.credential;
|
|
513
|
+
const apiKey = credential?.type === "oauth" ? credential.access : void 0;
|
|
501
514
|
if (!apiKey) {
|
|
502
|
-
return
|
|
515
|
+
return storedModels();
|
|
503
516
|
}
|
|
504
517
|
const { token, projectId } = parseStoredCredentials(apiKey);
|
|
505
518
|
const catalog = await fetchAvailableModelsCatalog(token, projectId, context.signal);
|
|
506
|
-
|
|
519
|
+
store.record(catalog);
|
|
507
520
|
const dynamicModels = buildDynamicPublicModels(catalog);
|
|
508
521
|
if (context.publish) {
|
|
509
|
-
const snap = getCatalogSnapshot();
|
|
510
522
|
await context.publish({
|
|
511
523
|
persist: {
|
|
512
524
|
models: dynamicModels,
|
|
513
525
|
checkedAt: Date.now(),
|
|
514
|
-
|
|
515
|
-
modelEnums: { ...snap.enums },
|
|
516
|
-
runtimeIds: [...snap.runtimeIds],
|
|
517
|
-
thinking: { ...snap.thinking ?? {} },
|
|
518
|
-
deprecated: { ...snap.deprecated ?? {} }
|
|
519
|
-
}
|
|
526
|
+
[PRIVATE_SNAPSHOT_KEY]: toPersistedSnapshot(store.generation().snapshot)
|
|
520
527
|
}
|
|
521
528
|
});
|
|
522
529
|
}
|
|
523
530
|
return dynamicModels;
|
|
524
531
|
} catch {
|
|
525
|
-
return
|
|
532
|
+
return storedModels();
|
|
526
533
|
}
|
|
527
534
|
}
|
|
528
|
-
async function refreshCatalogGeneration(doRefresh) {
|
|
529
|
-
const
|
|
535
|
+
async function refreshCatalogGeneration(store, doRefresh) {
|
|
536
|
+
const versionBefore = store.generation().version;
|
|
530
537
|
await doRefresh();
|
|
531
|
-
const
|
|
532
|
-
if (!
|
|
533
|
-
|
|
534
|
-
return { status: "fresh", catalog };
|
|
538
|
+
const { items, version } = store.generation();
|
|
539
|
+
if (!items) return { status: "failed" };
|
|
540
|
+
return { status: version === versionBefore ? "stale" : "fresh", catalog: items };
|
|
535
541
|
}
|
|
536
542
|
function parseAvailableModels(data) {
|
|
537
543
|
const models = [];
|
|
@@ -795,6 +801,46 @@ function validPairs(raw) {
|
|
|
795
801
|
}
|
|
796
802
|
return Object.keys(pairs).length > 0 ? pairs : void 0;
|
|
797
803
|
}
|
|
804
|
+
var FOOTER_MODES = Object.freeze({
|
|
805
|
+
off: {
|
|
806
|
+
key: "off",
|
|
807
|
+
label: "Off",
|
|
808
|
+
note: "",
|
|
809
|
+
render: () => ({})
|
|
810
|
+
},
|
|
811
|
+
smart: {
|
|
812
|
+
key: "smart",
|
|
813
|
+
label: "Smart",
|
|
814
|
+
note: "Picks whichever window runs out first (5h or weekly), weighting the weekly pool by a ratio learned from your usage",
|
|
815
|
+
render: (summary, modelId, ratio = DEFAULT_WEEKLY_TO_5H_RATIO) => {
|
|
816
|
+
if (!summary) return {};
|
|
817
|
+
const plain = buildQuotaFooter(summary, modelId, ratio);
|
|
818
|
+
return { plain, colored: colorizeQuotaFooter(plain) };
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
all: {
|
|
822
|
+
key: "all",
|
|
823
|
+
label: "All",
|
|
824
|
+
note: "Lists every window of the pool backing the current model (5h or weekly)",
|
|
825
|
+
render: (summary, modelId) => {
|
|
826
|
+
if (!summary) return {};
|
|
827
|
+
const plain = buildQuotaFooterBoth(summary, modelId);
|
|
828
|
+
return { plain, colored: colorizeQuotaFooterBoth(plain) };
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
var FOOTER_MODE_OPTIONS = Object.freeze(
|
|
833
|
+
Object.keys(FOOTER_MODES)
|
|
834
|
+
);
|
|
835
|
+
var FOOTER_MODE_NOTES = Object.freeze(
|
|
836
|
+
Object.fromEntries(
|
|
837
|
+
Object.entries(FOOTER_MODES).filter(([, def]) => def.note.length > 0).map(([key, def]) => [key, def.note])
|
|
838
|
+
)
|
|
839
|
+
);
|
|
840
|
+
function normalizeFooterMode(value) {
|
|
841
|
+
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
842
|
+
return v in FOOTER_MODES ? v : void 0;
|
|
843
|
+
}
|
|
798
844
|
function isAntigravityModel(model) {
|
|
799
845
|
return model?.provider === PROVIDER_ID;
|
|
800
846
|
}
|
|
@@ -804,11 +850,8 @@ function paintQuotaStatus(coord, ctx) {
|
|
|
804
850
|
ctx.ui.setStatus(QUOTA_STATUS_KEY, void 0);
|
|
805
851
|
return;
|
|
806
852
|
}
|
|
807
|
-
const
|
|
808
|
-
ctx.ui.setStatus(
|
|
809
|
-
QUOTA_STATUS_KEY,
|
|
810
|
-
mode === "all" ? colorizeQuotaFooterBoth(plain) : colorizeQuotaFooter(plain)
|
|
811
|
-
);
|
|
853
|
+
const { colored } = coord.renderFooter(ctx.model?.id, mode);
|
|
854
|
+
ctx.ui.setStatus(QUOTA_STATUS_KEY, colored);
|
|
812
855
|
}
|
|
813
856
|
var QuotaStatusCoordinator = class {
|
|
814
857
|
summary;
|
|
@@ -830,8 +873,10 @@ var QuotaStatusCoordinator = class {
|
|
|
830
873
|
return this.store.loadMode();
|
|
831
874
|
}
|
|
832
875
|
footerFor(modelId, mode = "smart") {
|
|
833
|
-
|
|
834
|
-
|
|
876
|
+
return FOOTER_MODES[mode]?.render(this.summary, modelId, this.weeklyTo5hRatio).plain;
|
|
877
|
+
}
|
|
878
|
+
renderFooter(modelId, mode = "smart") {
|
|
879
|
+
return FOOTER_MODES[mode]?.render(this.summary, modelId, this.weeklyTo5hRatio) ?? {};
|
|
835
880
|
}
|
|
836
881
|
get isFresh() {
|
|
837
882
|
return !!this.summary && Date.now() - this.fetchedAt < QUOTA_REFRESH_INTERVAL_MS;
|
|
@@ -947,10 +992,6 @@ function saveProviderConfig(file, data) {
|
|
|
947
992
|
return false;
|
|
948
993
|
}
|
|
949
994
|
}
|
|
950
|
-
function normalizeFooterMode(value) {
|
|
951
|
-
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
952
|
-
return v === "off" || v === "smart" || v === "all" ? v : void 0;
|
|
953
|
-
}
|
|
954
995
|
function resolveFooterMode(config) {
|
|
955
996
|
return normalizeFooterMode(config?.settings?.quotaFooter) ?? "off";
|
|
956
997
|
}
|
|
@@ -989,12 +1030,9 @@ var SETTINGS_FIELDS = Object.freeze([
|
|
|
989
1030
|
key: "quotaFooter",
|
|
990
1031
|
label: "Quota footer",
|
|
991
1032
|
description: "Show remaining quota in the footer",
|
|
992
|
-
options:
|
|
1033
|
+
options: FOOTER_MODE_OPTIONS,
|
|
993
1034
|
defaultValue: "off",
|
|
994
|
-
optionNotes:
|
|
995
|
-
smart: "Picks whichever window runs out first (5h or weekly), weighting the weekly pool by a ratio learned from your usage",
|
|
996
|
-
all: "Lists every window of the pool backing the current model (5h or weekly)"
|
|
997
|
-
},
|
|
1035
|
+
optionNotes: FOOTER_MODE_NOTES,
|
|
998
1036
|
onChange: async (ctx, quotaStatus) => {
|
|
999
1037
|
if (!quotaStatus) return;
|
|
1000
1038
|
if (quotaStatus.mode() !== "off") await quotaStatus.refresh(ctx, { ignoreMode: true });
|
|
@@ -1020,10 +1058,11 @@ async function applySettingValue(field, value, file, ctx, quotaStatus) {
|
|
|
1020
1058
|
return true;
|
|
1021
1059
|
}
|
|
1022
1060
|
function previewQuotaFooterText(coord, modelId, mode) {
|
|
1023
|
-
if (!coord
|
|
1024
|
-
const
|
|
1025
|
-
if (!
|
|
1026
|
-
const colored =
|
|
1061
|
+
if (!coord) return void 0;
|
|
1062
|
+
const normalized = normalizeFooterMode(mode);
|
|
1063
|
+
if (!normalized || normalized === "off") return void 0;
|
|
1064
|
+
const { colored } = coord.renderFooter(modelId, normalized);
|
|
1065
|
+
if (!colored) return void 0;
|
|
1027
1066
|
return ANSI_FG_RESET + colored;
|
|
1028
1067
|
}
|
|
1029
1068
|
function buildSettingsItems(config, fields = SETTINGS_FIELDS) {
|
|
@@ -1152,6 +1191,7 @@ function createSseFeed() {
|
|
|
1152
1191
|
input: 0,
|
|
1153
1192
|
output: 0,
|
|
1154
1193
|
cacheRead: 0,
|
|
1194
|
+
reasoning: 0,
|
|
1155
1195
|
total: 0
|
|
1156
1196
|
};
|
|
1157
1197
|
let stopReason = "stop";
|
|
@@ -1166,18 +1206,23 @@ function createSseFeed() {
|
|
|
1166
1206
|
});
|
|
1167
1207
|
const attachLoneSignature = () => {
|
|
1168
1208
|
if (!lastThoughtSignature) return;
|
|
1209
|
+
const attached = content.some(
|
|
1210
|
+
(b) => b.type === "thinking" ? Boolean(b.thinkingSignature) : b.type === "toolCall" ? Boolean(b.thoughtSignature) : b.type === "text" ? Boolean(b.textSignature) : false
|
|
1211
|
+
);
|
|
1212
|
+
if (attached) return;
|
|
1169
1213
|
const thinking = content.find((b) => b.type === "thinking");
|
|
1170
|
-
if (thinking
|
|
1171
|
-
thinking.thinkingSignature = lastThoughtSignature;
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1214
|
+
if (thinking) {
|
|
1215
|
+
if (!thinking.thinkingSignature) thinking.thinkingSignature = lastThoughtSignature;
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
1219
|
+
const block = content[i];
|
|
1220
|
+
if (block?.type === "text" && !block.textSignature) {
|
|
1221
|
+
block.textSignature = lastThoughtSignature;
|
|
1222
|
+
return;
|
|
1179
1223
|
}
|
|
1180
1224
|
}
|
|
1225
|
+
content.push({ type: "text", text: "", textSignature: lastThoughtSignature });
|
|
1181
1226
|
};
|
|
1182
1227
|
const closeOpenBlock = (events) => {
|
|
1183
1228
|
if (openType === null) return;
|
|
@@ -1211,6 +1256,7 @@ function createSseFeed() {
|
|
|
1211
1256
|
const candidates = typeof um.candidatesTokenCount === "number" ? um.candidatesTokenCount : 0;
|
|
1212
1257
|
const thoughts = typeof um.thoughtsTokenCount === "number" ? um.thoughtsTokenCount : 0;
|
|
1213
1258
|
usage.output = candidates + thoughts;
|
|
1259
|
+
usage.reasoning = thoughts;
|
|
1214
1260
|
if (typeof um.totalTokenCount === "number") usage.total = um.totalTokenCount;
|
|
1215
1261
|
}
|
|
1216
1262
|
const candidate = response.candidates?.[0];
|
|
@@ -1226,6 +1272,8 @@ function createSseFeed() {
|
|
|
1226
1272
|
lastThoughtSignature = part.thoughtSignature;
|
|
1227
1273
|
}
|
|
1228
1274
|
if (part.thought) {
|
|
1275
|
+
const delta = part.text || "";
|
|
1276
|
+
if (delta === "" && openType !== "thinking") continue;
|
|
1229
1277
|
if (openType !== "thinking") {
|
|
1230
1278
|
closeOpenBlock(events);
|
|
1231
1279
|
content.push({ type: "thinking", thinking: "" });
|
|
@@ -1234,7 +1282,6 @@ function createSseFeed() {
|
|
|
1234
1282
|
}
|
|
1235
1283
|
const block = content[content.length - 1];
|
|
1236
1284
|
if (block?.type !== "thinking") continue;
|
|
1237
|
-
const delta = part.text || "";
|
|
1238
1285
|
block.thinking += delta;
|
|
1239
1286
|
if (part.thoughtSignature) {
|
|
1240
1287
|
block.thinkingSignature = part.thoughtSignature;
|
|
@@ -1264,6 +1311,7 @@ function createSseFeed() {
|
|
|
1264
1311
|
});
|
|
1265
1312
|
events.push({ type: "toolcall_end", contentIndex, toolCall: block });
|
|
1266
1313
|
} else if (part.text !== void 0) {
|
|
1314
|
+
if (part.text === "" && openType !== "text") continue;
|
|
1267
1315
|
if (openType !== "text") {
|
|
1268
1316
|
closeOpenBlock(events);
|
|
1269
1317
|
content.push({ type: "text", text: "" });
|
|
@@ -1411,6 +1459,7 @@ function translateTurnTrace(context, runtimeModelId) {
|
|
|
1411
1459
|
const contents = [];
|
|
1412
1460
|
const messages = context.messages || [];
|
|
1413
1461
|
const isGeminiRequest = classifyModelFamily(runtimeModelId) === "gemini";
|
|
1462
|
+
const isGptRequest = classifyModelFamily(runtimeModelId) === "gpt";
|
|
1414
1463
|
for (const msg of messages) {
|
|
1415
1464
|
if (msg.role === "user") {
|
|
1416
1465
|
const parts = [];
|
|
@@ -1464,6 +1513,7 @@ function translateTurnTrace(context, runtimeModelId) {
|
|
|
1464
1513
|
} else if (item.type === "thinking") {
|
|
1465
1514
|
const candidateSig = item.thinkingSignature;
|
|
1466
1515
|
const isForeignReasoning = !isSameProviderAndModel || typeof candidateSig === "string" && candidateSig.trim().startsWith("{");
|
|
1516
|
+
if (isGptRequest && !isForeignReasoning) continue;
|
|
1467
1517
|
if (!isForeignReasoning) {
|
|
1468
1518
|
const part = {
|
|
1469
1519
|
thought: true,
|
|
@@ -1601,7 +1651,9 @@ function buildAntigravityRequestBody(params) {
|
|
|
1601
1651
|
const sessionId = deriveSessionId(context, params.sessionId);
|
|
1602
1652
|
const trajectoryId = params.trajectoryId && typeof params.trajectoryId === "string" && params.trajectoryId.trim().length > 0 ? params.trajectoryId.trim() : resolveSessionTrajectory(sessionId);
|
|
1603
1653
|
const contents = translateTurnTrace(context, runtimeModelId);
|
|
1604
|
-
const requestIndex =
|
|
1654
|
+
const requestIndex = contents.filter(
|
|
1655
|
+
(c) => c.role === "model" && !c.parts?.some((p) => p.functionResponse)
|
|
1656
|
+
).length;
|
|
1605
1657
|
const requestId = `agent/${sessionId}/${Date.now()}/${trajectoryId}/${contents.length}`;
|
|
1606
1658
|
const modelEnum = plan.modelEnum;
|
|
1607
1659
|
const labels = {
|
|
@@ -1655,7 +1707,7 @@ function buildAntigravityRequestBody(params) {
|
|
|
1655
1707
|
}
|
|
1656
1708
|
|
|
1657
1709
|
// src/stream.ts
|
|
1658
|
-
function streamAntigravity(model, context, options) {
|
|
1710
|
+
function streamAntigravity(model, context, options, store) {
|
|
1659
1711
|
const stream = createAssistantMessageEventStream();
|
|
1660
1712
|
(async () => {
|
|
1661
1713
|
const output = {
|
|
@@ -1684,7 +1736,7 @@ function streamAntigravity(model, context, options) {
|
|
|
1684
1736
|
const { token, projectId } = parseStoredCredentials(rawApiKey);
|
|
1685
1737
|
const effort = options?.reasoning;
|
|
1686
1738
|
const trajectoryId = options && "trajectoryId" in options && typeof options.trajectoryId === "string" ? options.trajectoryId : void 0;
|
|
1687
|
-
const snapshot =
|
|
1739
|
+
const snapshot = store.generation().snapshot;
|
|
1688
1740
|
const plan = resolveModelPlan(model.id, effort, snapshot);
|
|
1689
1741
|
const requestBody = buildAntigravityRequestBody({
|
|
1690
1742
|
projectId,
|
|
@@ -1716,6 +1768,7 @@ function streamAntigravity(model, context, options) {
|
|
|
1716
1768
|
output.usage.input = fed.usage.input;
|
|
1717
1769
|
output.usage.cacheRead = fed.usage.cacheRead;
|
|
1718
1770
|
output.usage.output = fed.usage.output;
|
|
1771
|
+
output.usage.reasoning = fed.usage.reasoning;
|
|
1719
1772
|
output.usage.totalTokens = fed.usage.total;
|
|
1720
1773
|
if (model.cost) {
|
|
1721
1774
|
const c = model.cost;
|
|
@@ -1759,13 +1812,75 @@ function streamAntigravity(model, context, options) {
|
|
|
1759
1812
|
}
|
|
1760
1813
|
|
|
1761
1814
|
// src/commands.ts
|
|
1762
|
-
var
|
|
1815
|
+
var SUBCOMMANDS = Object.freeze([
|
|
1816
|
+
{
|
|
1817
|
+
name: "usage",
|
|
1818
|
+
description: "Show 5h and weekly quota pool limits",
|
|
1819
|
+
run: async ({ ctx, quotaStatus }) => runUsageSubcommand(ctx, quotaStatus)
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
name: "models",
|
|
1823
|
+
description: "List recommended models with context window and remaining quota",
|
|
1824
|
+
aliases: Object.freeze(["model"]),
|
|
1825
|
+
run: async ({ ctx, store }) => runModelsSubcommand(ctx, store)
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
name: "refresh",
|
|
1829
|
+
description: "Force refresh model catalog",
|
|
1830
|
+
run: async ({ ctx, store }) => runRefreshSubcommand(ctx, store)
|
|
1831
|
+
},
|
|
1832
|
+
{
|
|
1833
|
+
name: "settings",
|
|
1834
|
+
description: "Pick provider settings: Enter cycles values",
|
|
1835
|
+
aliases: Object.freeze(["setting"]),
|
|
1836
|
+
run: async ({ ctx, quotaStatus }) => openSettings(ctx, quotaStatus)
|
|
1837
|
+
},
|
|
1838
|
+
{
|
|
1839
|
+
name: "login",
|
|
1840
|
+
description: "Run /login antigravity",
|
|
1841
|
+
run: ({ ctx }) => runLoginSubcommand(ctx)
|
|
1842
|
+
}
|
|
1843
|
+
]);
|
|
1844
|
+
function buildUsageText(commands = SUBCOMMANDS) {
|
|
1845
|
+
const maxNameLen = Math.max(...commands.map((c) => c.name.length));
|
|
1846
|
+
const lines = commands.map((c) => {
|
|
1847
|
+
const aliasPart = c.aliases?.length ? ` (alias: ${c.aliases.join(", ")})` : "";
|
|
1848
|
+
return ` ${c.name.padEnd(maxNameLen)} ${c.description}${aliasPart}`;
|
|
1849
|
+
});
|
|
1850
|
+
return `Usage: /antigravity <command>
|
|
1851
|
+
|
|
1852
|
+
Commands:
|
|
1853
|
+
${lines.join("\n")}`;
|
|
1854
|
+
}
|
|
1855
|
+
var USAGE_TEXT = buildUsageText();
|
|
1856
|
+
function completeSubcommands(prefix, commands = SUBCOMMANDS) {
|
|
1857
|
+
const trimmed = prefix.trim();
|
|
1858
|
+
if (trimmed === "") {
|
|
1859
|
+
return commands.map((s) => ({ value: s.name, label: s.name, description: s.description }));
|
|
1860
|
+
}
|
|
1861
|
+
if (/\s/.test(trimmed)) return null;
|
|
1862
|
+
const lower = trimmed.toLowerCase();
|
|
1863
|
+
return commands.filter((s) => s.name.startsWith(lower)).map((s) => ({
|
|
1864
|
+
value: s.name,
|
|
1865
|
+
label: s.name,
|
|
1866
|
+
description: s.description
|
|
1867
|
+
}));
|
|
1868
|
+
}
|
|
1869
|
+
function parseAntigravitySubcommand(args, commands = SUBCOMMANDS) {
|
|
1870
|
+
const sub = (args || "").trim().toLowerCase();
|
|
1871
|
+
for (const cmd of commands) {
|
|
1872
|
+
if (cmd.name === sub || cmd.aliases?.includes(sub)) {
|
|
1873
|
+
return cmd.name;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
return sub;
|
|
1877
|
+
}
|
|
1763
1878
|
async function resolveToken(ctx) {
|
|
1764
1879
|
const apiKey = await ctx.modelRegistry?.getApiKeyForProvider?.(PROVIDER_ID);
|
|
1765
1880
|
if (!apiKey) return null;
|
|
1766
1881
|
return parseStoredCredentials(apiKey);
|
|
1767
1882
|
}
|
|
1768
|
-
async function runModelsSubcommand(ctx) {
|
|
1883
|
+
async function runModelsSubcommand(ctx, store) {
|
|
1769
1884
|
if (await resolveToken(ctx) === null) {
|
|
1770
1885
|
emitOutput(ctx, "Not logged in. Run /login antigravity first.", "warning");
|
|
1771
1886
|
return;
|
|
@@ -1773,6 +1888,7 @@ async function runModelsSubcommand(ctx) {
|
|
|
1773
1888
|
try {
|
|
1774
1889
|
if (ctx.hasUI) ctx.ui.notify("Fetching available models\u2026", "info");
|
|
1775
1890
|
const { status, catalog } = await refreshCatalogGeneration(
|
|
1891
|
+
store,
|
|
1776
1892
|
() => ctx.modelRegistry?.refresh?.({ force: true, providers: [PROVIDER_ID], signal: ctx.signal })
|
|
1777
1893
|
);
|
|
1778
1894
|
if (status === "failed" || !catalog) {
|
|
@@ -1788,12 +1904,6 @@ async function runModelsSubcommand(ctx) {
|
|
|
1788
1904
|
emitOutput(ctx, `Failed to fetch models: ${err.message}`, "error");
|
|
1789
1905
|
}
|
|
1790
1906
|
}
|
|
1791
|
-
function parseAntigravitySubcommand(args) {
|
|
1792
|
-
const sub = (args || "").trim().toLowerCase();
|
|
1793
|
-
if (sub === "model") return "models";
|
|
1794
|
-
if (sub === "setting") return "settings";
|
|
1795
|
-
return sub;
|
|
1796
|
-
}
|
|
1797
1907
|
async function runUsageSubcommand(ctx, quotaStatus) {
|
|
1798
1908
|
if (await resolveToken(ctx) === null) {
|
|
1799
1909
|
emitOutput(ctx, "Not logged in. Run /login antigravity first.", "warning");
|
|
@@ -1816,46 +1926,38 @@ async function runUsageSubcommand(ctx, quotaStatus) {
|
|
|
1816
1926
|
emitOutput(ctx, `Failed to fetch usage: ${err.message}`, "error");
|
|
1817
1927
|
}
|
|
1818
1928
|
}
|
|
1819
|
-
async function
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
if (sub === "settings") {
|
|
1831
|
-
await openSettings(ctx, quotaStatus);
|
|
1832
|
-
return;
|
|
1833
|
-
}
|
|
1834
|
-
if (sub === "refresh") {
|
|
1835
|
-
try {
|
|
1836
|
-
if (ctx.hasUI) ctx.ui.notify("Refreshing models\u2026", "info");
|
|
1837
|
-
const { status } = await refreshCatalogGeneration(
|
|
1838
|
-
() => ctx.modelRegistry?.refresh?.({ force: true, providers: [PROVIDER_ID], signal: ctx.signal })
|
|
1839
|
-
);
|
|
1840
|
-
if (status === "fresh") {
|
|
1841
|
-
emitOutput(ctx, "Antigravity models refreshed successfully.");
|
|
1842
|
-
} else if (status === "stale") {
|
|
1843
|
-
emitOutput(ctx, "Failed to refresh models, keeping last known list.", "warning");
|
|
1844
|
-
} else {
|
|
1845
|
-
emitOutput(ctx, "Failed to refresh models: no new generation received.", "error");
|
|
1846
|
-
}
|
|
1847
|
-
} catch (err) {
|
|
1848
|
-
emitOutput(ctx, `Failed to refresh: ${err.message}`, "error");
|
|
1849
|
-
}
|
|
1850
|
-
return;
|
|
1851
|
-
}
|
|
1852
|
-
if (sub === "login") {
|
|
1853
|
-
if (ctx.hasUI) {
|
|
1854
|
-
ctx.ui.setEditorText("/login antigravity");
|
|
1855
|
-
ctx.ui.notify("Press Enter to log in to Antigravity.", "info");
|
|
1929
|
+
async function runRefreshSubcommand(ctx, store) {
|
|
1930
|
+
try {
|
|
1931
|
+
if (ctx.hasUI) ctx.ui.notify("Refreshing models\u2026", "info");
|
|
1932
|
+
const { status } = await refreshCatalogGeneration(
|
|
1933
|
+
store,
|
|
1934
|
+
() => ctx.modelRegistry?.refresh?.({ force: true, providers: [PROVIDER_ID], signal: ctx.signal })
|
|
1935
|
+
);
|
|
1936
|
+
if (status === "fresh") {
|
|
1937
|
+
emitOutput(ctx, "Antigravity models refreshed successfully.");
|
|
1938
|
+
} else if (status === "stale") {
|
|
1939
|
+
emitOutput(ctx, "Failed to refresh models, keeping last known list.", "warning");
|
|
1856
1940
|
} else {
|
|
1857
|
-
emitOutput(ctx, "
|
|
1941
|
+
emitOutput(ctx, "Failed to refresh models: no new generation received.", "error");
|
|
1858
1942
|
}
|
|
1943
|
+
} catch (err) {
|
|
1944
|
+
emitOutput(ctx, `Failed to refresh: ${err.message}`, "error");
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
function runLoginSubcommand(ctx) {
|
|
1948
|
+
if (ctx.hasUI) {
|
|
1949
|
+
ctx.ui.setEditorText("/login antigravity");
|
|
1950
|
+
ctx.ui.notify("Press Enter to log in to Antigravity.", "info");
|
|
1951
|
+
} else {
|
|
1952
|
+
emitOutput(ctx, "Please run /login antigravity to authenticate.");
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
async function runAntigravitySubcommand(args, ctx, quotaStatus, store) {
|
|
1956
|
+
const parts = (args || "").trim().split(/\s+/).filter(Boolean);
|
|
1957
|
+
const sub = parseAntigravitySubcommand(parts[0] || "");
|
|
1958
|
+
const cmd = SUBCOMMANDS.find((c) => c.name === sub);
|
|
1959
|
+
if (cmd) {
|
|
1960
|
+
await cmd.run({ ctx, quotaStatus, store });
|
|
1859
1961
|
return;
|
|
1860
1962
|
}
|
|
1861
1963
|
emitOutput(ctx, USAGE_TEXT);
|
|
@@ -1863,15 +1965,9 @@ async function runAntigravitySubcommand(args, ctx, quotaStatus) {
|
|
|
1863
1965
|
|
|
1864
1966
|
// src/index.ts
|
|
1865
1967
|
var PROVIDER_NAME = "Antigravity";
|
|
1866
|
-
var SUBCOMMANDS = [
|
|
1867
|
-
{ name: "usage", description: "Show 5h and weekly quota pool limits" },
|
|
1868
|
-
{ name: "models", description: "List recommended models with context window and remaining quota" },
|
|
1869
|
-
{ name: "refresh", description: "Force refresh model catalog" },
|
|
1870
|
-
{ name: "settings", description: "Pick provider settings: Enter cycles values" },
|
|
1871
|
-
{ name: "login", description: "Run /login antigravity" }
|
|
1872
|
-
];
|
|
1873
1968
|
function index_default(pi) {
|
|
1874
1969
|
const quotaStatus = new QuotaStatusCoordinator(fileQuotaStatusStore());
|
|
1970
|
+
const catalog = createCatalogStore();
|
|
1875
1971
|
pi.registerProvider(PROVIDER_ID, {
|
|
1876
1972
|
name: PROVIDER_NAME,
|
|
1877
1973
|
baseUrl: DEFAULT_ENDPOINT,
|
|
@@ -1884,26 +1980,14 @@ function index_default(pi) {
|
|
|
1884
1980
|
refreshToken: refreshAntigravityToken,
|
|
1885
1981
|
getApiKey
|
|
1886
1982
|
},
|
|
1887
|
-
streamSimple: streamAntigravity,
|
|
1888
|
-
refreshModels: async (context) => refreshCatalog(context)
|
|
1983
|
+
streamSimple: (model, context, options) => streamAntigravity(model, context, options, catalog),
|
|
1984
|
+
refreshModels: async (context) => refreshCatalog(context, catalog)
|
|
1889
1985
|
});
|
|
1890
1986
|
pi.registerCommand("antigravity", {
|
|
1891
1987
|
description: "Antigravity quota, models and settings",
|
|
1892
|
-
getArgumentCompletions: (prefix) =>
|
|
1893
|
-
const trimmed = prefix.trim();
|
|
1894
|
-
if (trimmed === "") {
|
|
1895
|
-
return SUBCOMMANDS.map((s) => ({ value: s.name, label: s.name, description: s.description }));
|
|
1896
|
-
}
|
|
1897
|
-
if (/\s/.test(trimmed)) return null;
|
|
1898
|
-
const lower = trimmed.toLowerCase();
|
|
1899
|
-
return SUBCOMMANDS.filter((s) => s.name.startsWith(lower)).map((s) => ({
|
|
1900
|
-
value: s.name,
|
|
1901
|
-
label: s.name,
|
|
1902
|
-
description: s.description
|
|
1903
|
-
}));
|
|
1904
|
-
},
|
|
1988
|
+
getArgumentCompletions: (prefix) => completeSubcommands(prefix),
|
|
1905
1989
|
handler: async (args, ctx) => {
|
|
1906
|
-
await runAntigravitySubcommand(args, ctx, quotaStatus);
|
|
1990
|
+
await runAntigravitySubcommand(args, ctx, quotaStatus, catalog);
|
|
1907
1991
|
}
|
|
1908
1992
|
});
|
|
1909
1993
|
pi.on("session_start", async (_event, ctx) => {
|