pi-provider-antigravity 0.4.0 → 0.6.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/README.md +20 -6
- package/dist/index.js +113 -105
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ Remaining percentages are automatically colorized to keep depletion visible with
|
|
|
95
95
|
- **Low** (≤ 30%): Yellow
|
|
96
96
|
- **Critical** (≤ 10%): Red
|
|
97
97
|
|
|
98
|
-
In `
|
|
98
|
+
In `all` mode, each window carries its own color based on its remaining percentage.
|
|
99
99
|
|
|
100
100
|
### Display Modes
|
|
101
101
|
|
|
@@ -104,13 +104,27 @@ Switch between display modes at any time using `/antigravity settings`:
|
|
|
104
104
|
| Mode | Example | Behavior |
|
|
105
105
|
|---|---|---|
|
|
106
106
|
| `off` *(default)* | *(hidden)* | Slot stays empty; zero background quota requests |
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
107
|
+
| `smart` | `Wk 6% (2d 14h)` | Shows the window that runs out first, 5h or weekly |
|
|
108
|
+
| `all` | `5h 90% (3h 54m) · Wk 6% (2d 14h)` | Shows every window of the pool backing the current model |
|
|
109
|
+
|
|
110
|
+
### Footer placement
|
|
111
|
+
|
|
112
|
+
The extension never calls `setFooter` — it only publishes the slot text under the key `pi-provider-antigravity-footer-usage` via `setStatus`. Where that text renders is up to your footer; Pi's built-in one gives it its own line, below the default two.
|
|
113
|
+
|
|
114
|
+
To move it elsewhere (the right side of the first line, for example), ask Pi in a session and name the key:
|
|
115
|
+
|
|
116
|
+
> Move the `pi-provider-antigravity-footer-usage` slot to the right side of the first footer line, keeping the rest of the footer as it is.
|
|
117
|
+
|
|
118
|
+
Pi edits your own footer extension, creating one if you have none — based on
|
|
119
|
+
Pi's [complete custom-footer
|
|
120
|
+
example](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/examples/extensions/custom-footer.ts),
|
|
121
|
+
which Pi maintains. A custom footer replaces the built-in one, so Pi has to
|
|
122
|
+
redraw whichever lines you want to keep.
|
|
109
123
|
|
|
110
124
|
### Under the Hood
|
|
111
125
|
|
|
112
126
|
- **Model-aware pool routing**: Automatically aligns with your active model. Selecting a Gemini model displays the Gemini quota pool; switching to Claude or GPT switches to the third-party pool. When using a non-Antigravity model or no model at all, the slot cleanly disappears.
|
|
113
|
-
- **
|
|
127
|
+
- **Bottleneck detection**: In `smart` mode, the extension determines urgency using `min(r5h, rWk × R)` rather than a naive percentage comparison, accounting for total volume differences between the 5-hour and weekly pools. The volume multiplier `R` starts at 6.0 and automatically self-calibrates between 1.0 and 20.0 based on real usage deltas, persisting across restarts.
|
|
114
128
|
- **Battery- and network-friendly caching**: Idle sessions perform zero network requests. The slot repaints instantly from memory on turn completion, session launch, and model changes. Upstream quota queries are throttled to at most once every 5 minutes. Running `/antigravity usage` refreshes upstream data immediately.
|
|
115
129
|
|
|
116
130
|
## Configuration
|
|
@@ -136,7 +150,7 @@ Configuration is stored in `pi-provider-antigravity.json` alongside Pi's `settin
|
|
|
136
150
|
```json
|
|
137
151
|
{
|
|
138
152
|
"settings": {
|
|
139
|
-
"quotaFooter": "
|
|
153
|
+
"quotaFooter": "smart"
|
|
140
154
|
}
|
|
141
155
|
}
|
|
142
156
|
```
|
|
@@ -147,7 +161,7 @@ Configuration is stored in `pi-provider-antigravity.json` alongside Pi's `settin
|
|
|
147
161
|
|
|
148
162
|
| Key | Values | Default | Description |
|
|
149
163
|
|---|---|---|---|
|
|
150
|
-
| `quotaFooter` | `off`, `
|
|
164
|
+
| `quotaFooter` | `off`, `smart`, `all` | `off` | Display remaining quota in Pi's status footer. See [Quota footer](#quota-footer). |
|
|
151
165
|
|
|
152
166
|
## Disclaimer
|
|
153
167
|
|
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.1.
|
|
6
|
+
var DEFAULT_USER_AGENT = "antigravity/cli/1.1.28 (aidev_client; os_type=linux; arch=amd64; cl=978129418; auth_method=consumer)";
|
|
7
7
|
var PROVIDER_ID = "antigravity";
|
|
8
8
|
async function postAntigravity({
|
|
9
9
|
token,
|
|
@@ -275,6 +275,19 @@ function updateCatalogStore(enums, runtimeIds, thinking = {}, deprecated = {}) {
|
|
|
275
275
|
version: activeStore.version + 1
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
|
+
var lastCatalog;
|
|
279
|
+
function ingestCatalog(catalog) {
|
|
280
|
+
updateCatalogStore(
|
|
281
|
+
catalog.modelEnums,
|
|
282
|
+
catalog.models.map((m) => m.id),
|
|
283
|
+
buildThinkingMap(catalog.models),
|
|
284
|
+
catalog.deprecated || {}
|
|
285
|
+
);
|
|
286
|
+
lastCatalog = catalog;
|
|
287
|
+
}
|
|
288
|
+
function getStoredCatalog() {
|
|
289
|
+
return lastCatalog;
|
|
290
|
+
}
|
|
278
291
|
function resolveRuntimeModelId(modelId, effort, availableRuntimeIds = activeStore.runtimeIds) {
|
|
279
292
|
if (modelId.endsWith("-high") || modelId.endsWith("-medium") || modelId.endsWith("-low") || modelId.endsWith("-thinking") || modelId.endsWith("-agent") || modelId.endsWith("-extra-low") || modelId.endsWith("-tiered")) {
|
|
280
293
|
return modelId;
|
|
@@ -490,20 +503,19 @@ async function refreshCatalog(context) {
|
|
|
490
503
|
}
|
|
491
504
|
const { token, projectId } = parseStoredCredentials(apiKey);
|
|
492
505
|
const catalog = await fetchAvailableModelsCatalog(token, projectId, context.signal);
|
|
493
|
-
|
|
494
|
-
const deprecated = catalog.deprecated || {};
|
|
495
|
-
updateCatalogStore(catalog.modelEnums, catalog.models.map((m) => m.id), thinking, deprecated);
|
|
506
|
+
ingestCatalog(catalog);
|
|
496
507
|
const dynamicModels = buildDynamicPublicModels(catalog);
|
|
497
508
|
if (context.publish) {
|
|
509
|
+
const snap = getCatalogSnapshot();
|
|
498
510
|
await context.publish({
|
|
499
511
|
persist: {
|
|
500
512
|
models: dynamicModels,
|
|
501
513
|
checkedAt: Date.now(),
|
|
502
514
|
"pi-provider-antigravity": {
|
|
503
|
-
modelEnums:
|
|
504
|
-
runtimeIds:
|
|
505
|
-
thinking,
|
|
506
|
-
deprecated
|
|
515
|
+
modelEnums: { ...snap.enums },
|
|
516
|
+
runtimeIds: [...snap.runtimeIds],
|
|
517
|
+
thinking: { ...snap.thinking ?? {} },
|
|
518
|
+
deprecated: { ...snap.deprecated ?? {} }
|
|
507
519
|
}
|
|
508
520
|
}
|
|
509
521
|
});
|
|
@@ -513,6 +525,14 @@ async function refreshCatalog(context) {
|
|
|
513
525
|
return context.stored?.models || [];
|
|
514
526
|
}
|
|
515
527
|
}
|
|
528
|
+
async function refreshCatalogGeneration(doRefresh) {
|
|
529
|
+
const before = getCatalogSnapshot().version;
|
|
530
|
+
await doRefresh();
|
|
531
|
+
const catalog = getStoredCatalog();
|
|
532
|
+
if (!catalog) return { status: "failed" };
|
|
533
|
+
if (getCatalogSnapshot().version === before) return { status: "stale", catalog };
|
|
534
|
+
return { status: "fresh", catalog };
|
|
535
|
+
}
|
|
516
536
|
function parseAvailableModels(data) {
|
|
517
537
|
const models = [];
|
|
518
538
|
const modelEnums = {};
|
|
@@ -758,7 +778,7 @@ function colorizeQuotaFooterBoth(footer) {
|
|
|
758
778
|
if (!footer) return void 0;
|
|
759
779
|
return footer.split(" \xB7 ").map((part) => colorizeQuotaFooter(part) ?? part).join(" \xB7 ");
|
|
760
780
|
}
|
|
761
|
-
var QUOTA_STATUS_KEY = "
|
|
781
|
+
var QUOTA_STATUS_KEY = "pi-provider-antigravity-footer-usage";
|
|
762
782
|
var QUOTA_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
|
|
763
783
|
var MAX_OBSERVATION_AGE_MS = 60 * 60 * 1e3;
|
|
764
784
|
function isFiniteNumber(value) {
|
|
@@ -787,7 +807,7 @@ function paintQuotaStatus(coord, ctx) {
|
|
|
787
807
|
const plain = coord.footerFor(ctx.model?.id, mode);
|
|
788
808
|
ctx.ui.setStatus(
|
|
789
809
|
QUOTA_STATUS_KEY,
|
|
790
|
-
mode === "
|
|
810
|
+
mode === "all" ? colorizeQuotaFooterBoth(plain) : colorizeQuotaFooter(plain)
|
|
791
811
|
);
|
|
792
812
|
}
|
|
793
813
|
var QuotaStatusCoordinator = class {
|
|
@@ -809,9 +829,9 @@ var QuotaStatusCoordinator = class {
|
|
|
809
829
|
mode() {
|
|
810
830
|
return this.store.loadMode();
|
|
811
831
|
}
|
|
812
|
-
footerFor(modelId, mode = "
|
|
832
|
+
footerFor(modelId, mode = "smart") {
|
|
813
833
|
if (!this.summary || mode === "off") return void 0;
|
|
814
|
-
return mode === "
|
|
834
|
+
return mode === "all" ? buildQuotaFooterBoth(this.summary, modelId) : buildQuotaFooter(this.summary, modelId, this.weeklyTo5hRatio);
|
|
815
835
|
}
|
|
816
836
|
get isFresh() {
|
|
817
837
|
return !!this.summary && Date.now() - this.fetchedAt < QUOTA_REFRESH_INTERVAL_MS;
|
|
@@ -832,12 +852,13 @@ var QuotaStatusCoordinator = class {
|
|
|
832
852
|
await this.refresh(ctx);
|
|
833
853
|
paintQuotaStatus(this, ctx);
|
|
834
854
|
}
|
|
835
|
-
// One fetch for preview purposes even when the footer slot is off
|
|
836
|
-
//
|
|
855
|
+
// One fetch for preview purposes even when the footer slot is off or the
|
|
856
|
+
// current model belongs to another provider: opening quota settings is an
|
|
857
|
+
// explicit look at quota (like /antigravity usage), and the preview is the
|
|
858
|
+
// only place that quota is visible while a foreign model is selected.
|
|
837
859
|
ensurePreview(ctx) {
|
|
838
860
|
if (this.summary) return Promise.resolve(this.summary);
|
|
839
861
|
if (this.inflight) return this.inflight;
|
|
840
|
-
if (!isAntigravityModel(ctx.model)) return Promise.resolve(void 0);
|
|
841
862
|
return this.fetchOnce(ctx);
|
|
842
863
|
}
|
|
843
864
|
fetchOnce(ctx, signal) {
|
|
@@ -928,7 +949,7 @@ function saveProviderConfig(file, data) {
|
|
|
928
949
|
}
|
|
929
950
|
function normalizeFooterMode(value) {
|
|
930
951
|
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
931
|
-
return v === "off" || v === "
|
|
952
|
+
return v === "off" || v === "smart" || v === "all" ? v : void 0;
|
|
932
953
|
}
|
|
933
954
|
function resolveFooterMode(config) {
|
|
934
955
|
return normalizeFooterMode(config?.settings?.quotaFooter) ?? "off";
|
|
@@ -968,13 +989,16 @@ var SETTINGS_FIELDS = Object.freeze([
|
|
|
968
989
|
key: "quotaFooter",
|
|
969
990
|
label: "Quota footer",
|
|
970
991
|
description: "Show remaining quota in the footer",
|
|
971
|
-
options: ["off", "
|
|
992
|
+
options: ["off", "smart", "all"],
|
|
972
993
|
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
|
+
},
|
|
973
998
|
onChange: async (ctx, quotaStatus) => {
|
|
974
|
-
if (quotaStatus)
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
}
|
|
999
|
+
if (!quotaStatus) return;
|
|
1000
|
+
if (quotaStatus.mode() !== "off") await quotaStatus.refresh(ctx, { ignoreMode: true });
|
|
1001
|
+
paintQuotaStatus(quotaStatus, ctx);
|
|
978
1002
|
}
|
|
979
1003
|
}
|
|
980
1004
|
]);
|
|
@@ -997,9 +1021,10 @@ async function applySettingValue(field, value, file, ctx, quotaStatus) {
|
|
|
997
1021
|
}
|
|
998
1022
|
function previewQuotaFooterText(coord, modelId, mode) {
|
|
999
1023
|
if (!coord || mode === "off") return void 0;
|
|
1000
|
-
const plain = coord.footerFor(modelId, mode === "
|
|
1024
|
+
const plain = coord.footerFor(modelId, mode === "all" ? "all" : "smart");
|
|
1001
1025
|
if (!plain) return void 0;
|
|
1002
|
-
|
|
1026
|
+
const colored = mode === "all" ? colorizeQuotaFooterBoth(plain) : colorizeQuotaFooter(plain);
|
|
1027
|
+
return ANSI_FG_RESET + colored;
|
|
1003
1028
|
}
|
|
1004
1029
|
function buildSettingsItems(config, fields = SETTINGS_FIELDS) {
|
|
1005
1030
|
return fields.map((f) => ({
|
|
@@ -1081,7 +1106,10 @@ async function openSettingsDialog(ctx, quotaStatus, file) {
|
|
|
1081
1106
|
if (!item) return;
|
|
1082
1107
|
const base = quotaField?.description ?? "";
|
|
1083
1108
|
const sample = mode === "off" ? "hidden" : previewQuotaFooterText(quotaStatus, ctx.model?.id, mode);
|
|
1084
|
-
|
|
1109
|
+
const head = sample && base ? `${base}: ${sample}` : sample ?? base;
|
|
1110
|
+
const note = quotaField?.optionNotes?.[mode];
|
|
1111
|
+
item.description = note ? `${head}
|
|
1112
|
+
${note}` : head;
|
|
1085
1113
|
};
|
|
1086
1114
|
paintPreview(resolveFooterMode(config));
|
|
1087
1115
|
const list = new SettingsList(
|
|
@@ -1153,12 +1181,12 @@ function createSseFeed() {
|
|
|
1153
1181
|
};
|
|
1154
1182
|
const closeOpenBlock = (events) => {
|
|
1155
1183
|
if (openType === null) return;
|
|
1156
|
-
const
|
|
1157
|
-
const block = content[
|
|
1184
|
+
const contentIndex = content.length - 1;
|
|
1185
|
+
const block = content[contentIndex];
|
|
1158
1186
|
if (block?.type === "thinking") {
|
|
1159
|
-
events.push({
|
|
1187
|
+
events.push({ type: "thinking_end", contentIndex, content: block.thinking });
|
|
1160
1188
|
} else if (block?.type === "text") {
|
|
1161
|
-
events.push({
|
|
1189
|
+
events.push({ type: "text_end", contentIndex, content: block.text });
|
|
1162
1190
|
}
|
|
1163
1191
|
openType = null;
|
|
1164
1192
|
};
|
|
@@ -1201,7 +1229,7 @@ function createSseFeed() {
|
|
|
1201
1229
|
if (openType !== "thinking") {
|
|
1202
1230
|
closeOpenBlock(events);
|
|
1203
1231
|
content.push({ type: "thinking", thinking: "" });
|
|
1204
|
-
events.push({
|
|
1232
|
+
events.push({ type: "thinking_start", contentIndex: content.length - 1 });
|
|
1205
1233
|
openType = "thinking";
|
|
1206
1234
|
}
|
|
1207
1235
|
const block = content[content.length - 1];
|
|
@@ -1212,10 +1240,9 @@ function createSseFeed() {
|
|
|
1212
1240
|
block.thinkingSignature = part.thoughtSignature;
|
|
1213
1241
|
}
|
|
1214
1242
|
events.push({
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
delta
|
|
1218
|
-
...part.thoughtSignature ? { thinkingSignature: part.thoughtSignature } : {}
|
|
1243
|
+
type: "thinking_delta",
|
|
1244
|
+
contentIndex: content.length - 1,
|
|
1245
|
+
delta
|
|
1219
1246
|
});
|
|
1220
1247
|
} else if (part.functionCall) {
|
|
1221
1248
|
closeOpenBlock(events);
|
|
@@ -1228,18 +1255,25 @@ function createSseFeed() {
|
|
|
1228
1255
|
thoughtSignature: part.thoughtSignature || lastThoughtSignature
|
|
1229
1256
|
};
|
|
1230
1257
|
content.push(block);
|
|
1231
|
-
|
|
1258
|
+
const contentIndex = content.length - 1;
|
|
1259
|
+
events.push({ type: "toolcall_start", contentIndex });
|
|
1260
|
+
events.push({
|
|
1261
|
+
type: "toolcall_delta",
|
|
1262
|
+
contentIndex,
|
|
1263
|
+
delta: JSON.stringify(block.arguments)
|
|
1264
|
+
});
|
|
1265
|
+
events.push({ type: "toolcall_end", contentIndex, toolCall: block });
|
|
1232
1266
|
} else if (part.text !== void 0) {
|
|
1233
1267
|
if (openType !== "text") {
|
|
1234
1268
|
closeOpenBlock(events);
|
|
1235
1269
|
content.push({ type: "text", text: "" });
|
|
1236
|
-
events.push({
|
|
1270
|
+
events.push({ type: "text_start", contentIndex: content.length - 1 });
|
|
1237
1271
|
openType = "text";
|
|
1238
1272
|
}
|
|
1239
1273
|
const block = content[content.length - 1];
|
|
1240
1274
|
if (block?.type !== "text") continue;
|
|
1241
1275
|
block.text += part.text;
|
|
1242
|
-
events.push({
|
|
1276
|
+
events.push({ type: "text_delta", contentIndex: content.length - 1, delta: part.text });
|
|
1243
1277
|
}
|
|
1244
1278
|
}
|
|
1245
1279
|
};
|
|
@@ -1266,6 +1300,7 @@ function createSseFeed() {
|
|
|
1266
1300
|
// src/builder.ts
|
|
1267
1301
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
1268
1302
|
var BASE64_SIGNATURE_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/;
|
|
1303
|
+
var SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
|
|
1269
1304
|
function isValidThoughtSignature(sig) {
|
|
1270
1305
|
if (typeof sig !== "string" || sig.length === 0) return false;
|
|
1271
1306
|
if (sig.includes("=") && sig.length % 4 !== 0) return false;
|
|
@@ -1297,12 +1332,12 @@ function resolveSessionTrajectory(sessionId) {
|
|
|
1297
1332
|
const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1298
1333
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
1299
1334
|
}
|
|
1335
|
+
var AGY_SESSION_ID = "-3750763034362895579";
|
|
1300
1336
|
function resolveNumericSessionId(sessionId) {
|
|
1301
1337
|
if (/^-?\d+$/.test(sessionId)) {
|
|
1302
1338
|
return sessionId;
|
|
1303
1339
|
}
|
|
1304
|
-
|
|
1305
|
-
return hash.readBigInt64BE(0).toString();
|
|
1340
|
+
return AGY_SESSION_ID;
|
|
1306
1341
|
}
|
|
1307
1342
|
function normalizeToolCallId(id) {
|
|
1308
1343
|
if (!id || typeof id !== "string") return id;
|
|
@@ -1375,6 +1410,7 @@ function convertTools(tools) {
|
|
|
1375
1410
|
function translateTurnTrace(context, runtimeModelId) {
|
|
1376
1411
|
const contents = [];
|
|
1377
1412
|
const messages = context.messages || [];
|
|
1413
|
+
const isGeminiRequest = classifyModelFamily(runtimeModelId) === "gemini";
|
|
1378
1414
|
for (const msg of messages) {
|
|
1379
1415
|
if (msg.role === "user") {
|
|
1380
1416
|
const parts = [];
|
|
@@ -1468,6 +1504,8 @@ function translateTurnTrace(context, runtimeModelId) {
|
|
|
1468
1504
|
if (sig) {
|
|
1469
1505
|
part.thoughtSignature = sig;
|
|
1470
1506
|
pendingThinkingSig = void 0;
|
|
1507
|
+
} else if (isGeminiRequest && !isSameProviderAndModel) {
|
|
1508
|
+
part.thoughtSignature = SKIP_THOUGHT_SIGNATURE_VALIDATOR;
|
|
1471
1509
|
}
|
|
1472
1510
|
parts.push(part);
|
|
1473
1511
|
}
|
|
@@ -1673,11 +1711,12 @@ function streamAntigravity(model, context, options) {
|
|
|
1673
1711
|
const reader = res.body.getReader();
|
|
1674
1712
|
const decoder = new TextDecoder();
|
|
1675
1713
|
const feed = createSseFeed();
|
|
1676
|
-
const
|
|
1677
|
-
output.
|
|
1678
|
-
output.usage.
|
|
1679
|
-
output.usage.
|
|
1680
|
-
output.usage.
|
|
1714
|
+
const applyFeedOutput = (fed) => {
|
|
1715
|
+
output.content = fed.content;
|
|
1716
|
+
output.usage.input = fed.usage.input;
|
|
1717
|
+
output.usage.cacheRead = fed.usage.cacheRead;
|
|
1718
|
+
output.usage.output = fed.usage.output;
|
|
1719
|
+
output.usage.totalTokens = fed.usage.total;
|
|
1681
1720
|
if (model.cost) {
|
|
1682
1721
|
const c = model.cost;
|
|
1683
1722
|
const inputCost = output.usage.input * (c.input || 0) / 1e6;
|
|
@@ -1691,51 +1730,10 @@ function streamAntigravity(model, context, options) {
|
|
|
1691
1730
|
total: inputCost + outputCost + cacheCost
|
|
1692
1731
|
};
|
|
1693
1732
|
}
|
|
1694
|
-
};
|
|
1695
|
-
const translate = (events) => {
|
|
1696
|
-
for (const ev of events) {
|
|
1697
|
-
if (ev.kind === "text_start" || ev.kind === "thinking_start") {
|
|
1698
|
-
const isThinking = ev.kind === "thinking_start";
|
|
1699
|
-
stream.push(
|
|
1700
|
-
isThinking ? { type: "thinking_start", contentIndex: ev.index, partial: output } : { type: "text_start", contentIndex: ev.index, partial: output }
|
|
1701
|
-
);
|
|
1702
|
-
} else if (ev.kind === "text_delta" || ev.kind === "thinking_delta") {
|
|
1703
|
-
stream.push(
|
|
1704
|
-
ev.kind === "text_delta" ? { type: "text_delta", contentIndex: ev.index, delta: ev.delta, partial: output } : { type: "thinking_delta", contentIndex: ev.index, delta: ev.delta, partial: output }
|
|
1705
|
-
);
|
|
1706
|
-
} else if (ev.kind === "text_end" || ev.kind === "thinking_end") {
|
|
1707
|
-
stream.push(
|
|
1708
|
-
ev.kind === "text_end" ? { type: "text_end", contentIndex: ev.index, content: ev.content, partial: output } : { type: "thinking_end", contentIndex: ev.index, content: ev.content, partial: output }
|
|
1709
|
-
);
|
|
1710
|
-
} else if (ev.kind === "toolCall") {
|
|
1711
|
-
const toolCall = {
|
|
1712
|
-
type: "toolCall",
|
|
1713
|
-
id: ev.block.id,
|
|
1714
|
-
name: ev.block.name,
|
|
1715
|
-
arguments: ev.block.arguments || {},
|
|
1716
|
-
thoughtSignature: ev.block.thoughtSignature
|
|
1717
|
-
};
|
|
1718
|
-
stream.push({ type: "toolcall_start", contentIndex: ev.index, partial: output });
|
|
1719
|
-
stream.push({
|
|
1720
|
-
type: "toolcall_delta",
|
|
1721
|
-
contentIndex: ev.index,
|
|
1722
|
-
delta: JSON.stringify(toolCall.arguments),
|
|
1723
|
-
partial: output
|
|
1724
|
-
});
|
|
1725
|
-
stream.push({
|
|
1726
|
-
type: "toolcall_end",
|
|
1727
|
-
contentIndex: ev.index,
|
|
1728
|
-
toolCall,
|
|
1729
|
-
partial: output
|
|
1730
|
-
});
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
};
|
|
1734
|
-
const applyFeedOutput = (fed) => {
|
|
1735
|
-
output.content = fed.content;
|
|
1736
|
-
applyUsage(fed.usage);
|
|
1737
1733
|
output.stopReason = fed.stopReason;
|
|
1738
|
-
|
|
1734
|
+
for (const ev of fed.events) {
|
|
1735
|
+
stream.push({ ...ev, partial: output });
|
|
1736
|
+
}
|
|
1739
1737
|
};
|
|
1740
1738
|
while (true) {
|
|
1741
1739
|
const { done, value } = await reader.read();
|
|
@@ -1762,29 +1760,32 @@ function streamAntigravity(model, context, options) {
|
|
|
1762
1760
|
|
|
1763
1761
|
// src/commands.ts
|
|
1764
1762
|
var USAGE_TEXT = "Usage: /antigravity <command>\n\nCommands:\n usage Show 5h and weekly quota pool limits\n models List recommended models with context window and remaining quota (alias: model)\n refresh Force refresh model catalog\n settings Pick provider settings: Enter cycles values (alias: setting)\n login Run /login antigravity";
|
|
1765
|
-
var FETCH_SUBCOMMANDS = {
|
|
1766
|
-
models: {
|
|
1767
|
-
progress: "Fetching available models\u2026",
|
|
1768
|
-
errLabel: "models",
|
|
1769
|
-
run: (token, projectId, signal) => fetchAvailableModelsCatalog(token, projectId, signal).then(formatModelsList)
|
|
1770
|
-
}
|
|
1771
|
-
};
|
|
1772
1763
|
async function resolveToken(ctx) {
|
|
1773
1764
|
const apiKey = await ctx.modelRegistry?.getApiKeyForProvider?.(PROVIDER_ID);
|
|
1774
1765
|
if (!apiKey) return null;
|
|
1775
1766
|
return parseStoredCredentials(apiKey);
|
|
1776
1767
|
}
|
|
1777
|
-
async function
|
|
1778
|
-
|
|
1779
|
-
if (!creds) {
|
|
1768
|
+
async function runModelsSubcommand(ctx) {
|
|
1769
|
+
if (await resolveToken(ctx) === null) {
|
|
1780
1770
|
emitOutput(ctx, "Not logged in. Run /login antigravity first.", "warning");
|
|
1781
1771
|
return;
|
|
1782
1772
|
}
|
|
1783
1773
|
try {
|
|
1784
|
-
if (ctx.hasUI) ctx.ui.notify(
|
|
1785
|
-
|
|
1774
|
+
if (ctx.hasUI) ctx.ui.notify("Fetching available models\u2026", "info");
|
|
1775
|
+
const { status, catalog } = await refreshCatalogGeneration(
|
|
1776
|
+
() => ctx.modelRegistry?.refresh?.({ force: true, providers: [PROVIDER_ID], signal: ctx.signal })
|
|
1777
|
+
);
|
|
1778
|
+
if (status === "failed" || !catalog) {
|
|
1779
|
+
throw new Error("no new generation received");
|
|
1780
|
+
}
|
|
1781
|
+
if (status === "stale") {
|
|
1782
|
+
emitOutput(ctx, "Failed to refresh models, showing last known list.", "warning");
|
|
1783
|
+
emitOutput(ctx, formatModelsList(catalog));
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
emitOutput(ctx, formatModelsList(catalog));
|
|
1786
1787
|
} catch (err) {
|
|
1787
|
-
emitOutput(ctx, `Failed to fetch
|
|
1788
|
+
emitOutput(ctx, `Failed to fetch models: ${err.message}`, "error");
|
|
1788
1789
|
}
|
|
1789
1790
|
}
|
|
1790
1791
|
function parseAntigravitySubcommand(args) {
|
|
@@ -1822,9 +1823,8 @@ async function runAntigravitySubcommand(args, ctx, quotaStatus) {
|
|
|
1822
1823
|
await runUsageSubcommand(ctx, quotaStatus);
|
|
1823
1824
|
return;
|
|
1824
1825
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
await runWithToken(ctx, fetchCmd);
|
|
1826
|
+
if (sub === "models") {
|
|
1827
|
+
await runModelsSubcommand(ctx);
|
|
1828
1828
|
return;
|
|
1829
1829
|
}
|
|
1830
1830
|
if (sub === "settings") {
|
|
@@ -1834,8 +1834,16 @@ async function runAntigravitySubcommand(args, ctx, quotaStatus) {
|
|
|
1834
1834
|
if (sub === "refresh") {
|
|
1835
1835
|
try {
|
|
1836
1836
|
if (ctx.hasUI) ctx.ui.notify("Refreshing models\u2026", "info");
|
|
1837
|
-
|
|
1838
|
-
|
|
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
|
+
}
|
|
1839
1847
|
} catch (err) {
|
|
1840
1848
|
emitOutput(ctx, `Failed to refresh: ${err.message}`, "error");
|
|
1841
1849
|
}
|