pi-provider-antigravity 0.12.0 → 0.14.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 CHANGED
@@ -22,7 +22,7 @@ Use Google Antigravity models directly in [Pi](https://pi.dev).
22
22
 
23
23
  ## Requirements
24
24
 
25
- - Pi >= 0.80.0
25
+ - Pi >= 0.86.0 (For Pi 0.80.0 ~ 0.85.x, see [Legacy Pi Support](#legacy-pi-support))
26
26
  - A Google account with Antigravity access
27
27
 
28
28
  ## Installation
@@ -37,6 +37,20 @@ Or try it without installing:
37
37
  pi -e npm:pi-provider-antigravity
38
38
  ```
39
39
 
40
+ ### Legacy Pi Support
41
+
42
+ For Pi 0.80.0 ~ 0.85.x, install the compatible `0.13.0` release:
43
+
44
+ ```bash
45
+ pi install npm:pi-provider-antigravity@0.13.0
46
+ ```
47
+
48
+ Or try it without installing:
49
+
50
+ ```bash
51
+ pi -e npm:pi-provider-antigravity@0.13.0
52
+ ```
53
+
40
54
  ## Quick Start
41
55
 
42
56
  1. Authenticate:
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { createHash, randomBytes } from "node:crypto";
6
6
 
7
7
  // src/protocol.ts
8
8
  var DEFAULT_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
9
- var DEFAULT_USER_AGENT = "antigravity/cli/1.2.4 (aidev_client; os_type=linux; arch=amd64; cl=982146307; auth_method=consumer)";
9
+ var DEFAULT_USER_AGENT = "antigravity/cli/1.2.5 (aidev_client; os_type=linux; arch=amd64; cl=982839923; auth_method=consumer)";
10
10
  var PROVIDER_ID = "antigravity";
11
11
  var AntigravityHttpError = class extends Error {
12
12
  status;
@@ -254,7 +254,24 @@ function parseStoredCredentials(rawApiKey) {
254
254
  return { token: rawApiKey, projectId: FALLBACK_PROJECT_ID };
255
255
  }
256
256
 
257
- // src/models.ts
257
+ // src/model-identity.ts
258
+ function classifyModelFamily(modelId) {
259
+ const bare = ((modelId || "").split("/").pop() || "").toLowerCase();
260
+ if (bare.startsWith("gemini-")) return "gemini";
261
+ if (bare.startsWith("claude-")) return "claude";
262
+ if (bare.startsWith("gpt-")) return "gpt";
263
+ return "unknown";
264
+ }
265
+ function isCompatibleFamily(msgModel, targetModelId) {
266
+ if (!msgModel || !targetModelId) return true;
267
+ if (msgModel === targetModelId) return true;
268
+ const msgFamily = classifyModelFamily(msgModel);
269
+ if (msgFamily !== "unknown" && msgFamily === classifyModelFamily(targetModelId)) return true;
270
+ return false;
271
+ }
272
+
273
+ // src/model-catalog.ts
274
+ var PRIVATE_SNAPSHOT_KEY = "pi-provider-antigravity";
258
275
  var CANONICAL_TIER_SUFFIXES = Object.freeze({
259
276
  low: "-low",
260
277
  medium: "-medium",
@@ -305,23 +322,6 @@ function tierCandidateOrder(effort) {
305
322
  const fallbacks = TIER_FALLBACKS[effort] ?? DEFAULT_TIER_ORDER;
306
323
  return [.../* @__PURE__ */ new Set([...canonical, ...fallbacks])];
307
324
  }
308
- function classifyModelFamily(modelId) {
309
- const bare = ((modelId || "").split("/").pop() || "").toLowerCase();
310
- if (bare.startsWith("gemini-")) return "gemini";
311
- if (bare.startsWith("claude-")) return "claude";
312
- if (bare.startsWith("gpt-")) return "gpt";
313
- return "unknown";
314
- }
315
- function isCompatibleFamily(msgModel, targetModelId) {
316
- if (!msgModel || !targetModelId) return true;
317
- if (msgModel === targetModelId) return true;
318
- const msgFamily = classifyModelFamily(msgModel);
319
- if (msgFamily !== "unknown" && msgFamily === classifyModelFamily(targetModelId)) return true;
320
- return extractBaseModelId(msgModel) === extractBaseModelId(targetModelId);
321
- }
322
-
323
- // src/model-catalog.ts
324
- var PRIVATE_SNAPSHOT_KEY = "pi-provider-antigravity";
325
325
  function buildThinkingMap(models) {
326
326
  return Object.fromEntries(
327
327
  models.map((m) => [
@@ -696,21 +696,7 @@ import * as fs from "node:fs";
696
696
  import * as os from "node:os";
697
697
  import * as path from "node:path";
698
698
  import { SettingsList } from "@earendil-works/pi-tui";
699
- var ANSI_FG_RESET = "\x1B[39m";
700
699
  var PROVIDER_CONFIG_FILE = "pi-provider-antigravity.json";
701
- var FOOTER_MODE_NOTES = Object.freeze({
702
- smart: "Picks whichever window runs out first (5h or weekly), weighting the weekly pool by a ratio learned from your usage",
703
- all: "Lists every window of the pool backing the current model (5h or weekly)"
704
- });
705
- var FOOTER_MODE_OPTIONS = Object.freeze([
706
- "off",
707
- "smart",
708
- "all"
709
- ]);
710
- function normalizeFooterMode(value) {
711
- const v = typeof value === "string" ? value.trim().toLowerCase() : "";
712
- return FOOTER_MODE_OPTIONS.includes(v) ? v : void 0;
713
- }
714
700
  function defaultConfigFile(env = process.env) {
715
701
  const dir = (env.PI_CODING_AGENT_DIR || "").trim() || path.join(os.homedir(), ".pi", "agent");
716
702
  return path.join(dir, PROVIDER_CONFIG_FILE);
@@ -761,9 +747,6 @@ function updateProviderConfig(file, mutate) {
761
747
  return false;
762
748
  }
763
749
  }
764
- function resolveFooterMode(config) {
765
- return normalizeFooterMode(config?.settings?.quotaFooter) ?? "off";
766
- }
767
750
  function loadSubsystemState(subsystem, file = defaultConfigFile()) {
768
751
  const state = loadProviderConfig(file)?.states?.[subsystem];
769
752
  return state && typeof state === "object" && !Array.isArray(state) ? state : void 0;
@@ -776,28 +759,33 @@ function saveSubsystemState(subsystem, state, file = defaultConfigFile()) {
776
759
  config.states = states;
777
760
  });
778
761
  }
779
- function fileQuotaStatusStore(file = defaultConfigFile()) {
780
- return {
781
- loadMode: () => resolveFooterMode(loadProviderConfig(file)),
782
- loadQuotaState: () => loadSubsystemState("quota", file),
783
- saveQuotaState: (state) => saveSubsystemState("quota", state, file)
784
- };
785
- }
786
- var SETTINGS_FIELDS = Object.freeze([
787
- {
788
- key: "quotaFooter",
789
- label: "Quota footer",
790
- description: "Show remaining quota in Pi's status footer",
791
- options: FOOTER_MODE_OPTIONS,
792
- defaultValue: "off",
793
- optionNotes: FOOTER_MODE_NOTES,
794
- onChange: async (ctx, quotaStatus) => {
795
- if (!quotaStatus) return;
796
- if (quotaStatus.mode() !== "off") await quotaStatus.refresh(ctx, { ignoreMode: true });
797
- quotaStatus.paint(ctx);
762
+ var SettingsRegistry = class {
763
+ fields = [];
764
+ register(field) {
765
+ const existingIndex = this.fields.findIndex((f) => f.key === field.key);
766
+ if (existingIndex >= 0) {
767
+ this.fields[existingIndex] = field;
768
+ } else {
769
+ this.fields.push(field);
798
770
  }
799
771
  }
800
- ]);
772
+ unregister(key) {
773
+ this.fields = this.fields.filter((f) => f.key !== key);
774
+ }
775
+ getFields() {
776
+ return [...this.fields];
777
+ }
778
+ clear() {
779
+ this.fields = [];
780
+ }
781
+ };
782
+ var defaultSettingsRegistry = new SettingsRegistry();
783
+ function registerSettingField(field) {
784
+ defaultSettingsRegistry.register(field);
785
+ }
786
+ function getRegisteredSettingFields() {
787
+ return defaultSettingsRegistry.getFields();
788
+ }
801
789
  function fieldDisplayValue(config, field) {
802
790
  const raw = config?.settings?.[field.key];
803
791
  if (typeof raw === "string" && raw.trim()) return raw.trim();
@@ -810,25 +798,17 @@ function saveSettingValue(field, value, file) {
810
798
  config.settings = settings;
811
799
  });
812
800
  }
813
- async function applySettingValue(field, value, file, ctx, quotaStatus) {
801
+ async function applySettingValue(field, value, file, ctx) {
814
802
  if (!saveSettingValue(field, value, file)) {
815
803
  return false;
816
804
  }
817
- await field.onChange?.(ctx, quotaStatus);
805
+ await field.onChange?.(ctx, value);
818
806
  return true;
819
807
  }
820
808
  function writeFailedMessage(file) {
821
809
  return `Failed to write ${file}. If the file is not valid JSON, fix or delete it.`;
822
810
  }
823
- function previewQuotaFooterText(coord, modelId, mode, style) {
824
- if (!coord) return void 0;
825
- const normalized = normalizeFooterMode(mode);
826
- if (!normalized || normalized === "off") return void 0;
827
- const { colored } = coord.renderFooter(modelId, normalized, style);
828
- if (!colored) return void 0;
829
- return ANSI_FG_RESET + colored;
830
- }
831
- function buildSettingsItems(config, fields = SETTINGS_FIELDS) {
811
+ function buildSettingsItems(config, fields = getRegisteredSettingFields()) {
832
812
  return fields.map((f) => ({
833
813
  id: f.key,
834
814
  label: f.label,
@@ -851,29 +831,37 @@ async function settingsListTheme(theme) {
851
831
  };
852
832
  }
853
833
  }
854
- async function openSettings(ctx, quotaStatus) {
834
+ function resolveFields(registryOrFields) {
835
+ if (!registryOrFields) return getRegisteredSettingFields();
836
+ if ("getFields" in registryOrFields && typeof registryOrFields.getFields === "function") {
837
+ return registryOrFields.getFields();
838
+ }
839
+ return registryOrFields;
840
+ }
841
+ async function openSettings(ctx, registryOrFields) {
842
+ const fields = resolveFields(registryOrFields);
855
843
  const file = defaultConfigFile();
856
844
  if (ctx.mode === "tui" && ctx.hasUI) {
857
- await openSettingsDialog(ctx, quotaStatus, file);
845
+ await openSettingsDialog(ctx, fields, file);
858
846
  return;
859
847
  }
860
848
  const config = loadProviderConfig(file);
861
849
  if (!ctx.hasUI) {
862
- const text = SETTINGS_FIELDS.map((f) => `${f.label}: ${fieldDisplayValue(config, f)}`).join("\n") + `
850
+ const text = fields.map((f) => `${f.label}: ${fieldDisplayValue(config, f)}`).join("\n") + `
863
851
  Edit ${file} to change.`;
864
852
  if (ctx.hasUI) ctx.ui.notify(text, "info");
865
853
  else console.log(text);
866
854
  return;
867
855
  }
868
- let field = SETTINGS_FIELDS[0];
856
+ let field = fields[0];
869
857
  if (!field) return;
870
- if (SETTINGS_FIELDS.length > 1) {
871
- const labels = SETTINGS_FIELDS.map(
858
+ if (fields.length > 1) {
859
+ const labels = fields.map(
872
860
  (f) => `${f.label} (current: ${fieldDisplayValue(config, f)})`
873
861
  );
874
862
  const choice = await ctx.ui.select("Antigravity settings", labels);
875
863
  if (!choice) return;
876
- const found = SETTINGS_FIELDS[labels.indexOf(choice)];
864
+ const found = fields[labels.indexOf(choice)];
877
865
  if (!found) return;
878
866
  field = found;
879
867
  }
@@ -882,39 +870,43 @@ Edit ${file} to change.`;
882
870
  [...field.options]
883
871
  );
884
872
  if (!picked || !field.options.includes(picked)) return;
885
- if (await applySettingValue(field, picked, file, ctx, quotaStatus)) {
873
+ if (await applySettingValue(field, picked, file, ctx)) {
886
874
  ctx.ui.notify(`${field.label} set to ${picked}.`, "info");
887
875
  } else {
888
876
  ctx.ui.notify(writeFailedMessage(file), "error");
889
877
  }
890
878
  }
891
- async function openSettingsDialog(ctx, quotaStatus, file) {
892
- if (quotaStatus) await quotaStatus.ensurePreview(ctx);
879
+ async function openSettingsDialog(ctx, fields, file) {
880
+ for (const field of fields) {
881
+ if (field.prepare) await field.prepare(ctx);
882
+ }
893
883
  await ctx.ui.custom(async (tui, theme, _kb, done) => {
894
884
  const config = loadProviderConfig(file);
895
- const items = buildSettingsItems(config);
896
- const quotaField = SETTINGS_FIELDS.find((f) => f.key === "quotaFooter");
897
- const paintPreview = (mode) => {
898
- const item = items.find((i) => i.id === "quotaFooter");
885
+ const items = buildSettingsItems(config, fields);
886
+ const paintPreview = (field, value) => {
887
+ const item = items.find((i) => i.id === field.key);
899
888
  if (!item) return;
900
- const base = quotaField?.description ?? "";
901
- const sample = mode === "off" ? "hidden" : previewQuotaFooterText(quotaStatus, ctx.model?.id, mode, theme);
889
+ const base = field.description ?? "";
890
+ const sample = field.renderPreview?.(value, ctx, theme);
902
891
  const head = sample && base ? `${base}: ${sample}` : sample ?? base;
903
- const note = quotaField?.optionNotes?.[mode];
892
+ const note = field.optionNotes?.[value];
904
893
  item.description = note ? `${head}
905
894
  ${note}` : head;
906
895
  };
907
- paintPreview(resolveFooterMode(config));
896
+ for (const field of fields) {
897
+ const current = fieldDisplayValue(config, field);
898
+ paintPreview(field, current);
899
+ }
908
900
  const list = new SettingsList(
909
901
  items,
910
902
  Math.min(items.length, 10),
911
903
  await settingsListTheme(theme),
912
904
  (id, newValue) => {
913
- const field = SETTINGS_FIELDS.find((f) => f.key === id);
905
+ const field = fields.find((f) => f.key === id);
914
906
  if (!field) return;
915
907
  list.invalidate();
916
908
  tui.requestRender();
917
- void applySettingValue(field, newValue, file, ctx, quotaStatus).then((saved) => {
909
+ void applySettingValue(field, newValue, file, ctx).then((saved) => {
918
910
  if (!saved) {
919
911
  list.updateValue(field.key, fieldDisplayValue(loadProviderConfig(file), field));
920
912
  ctx.ui.notify(writeFailedMessage(file), "error");
@@ -922,7 +914,7 @@ ${note}` : head;
922
914
  tui.requestRender();
923
915
  return;
924
916
  }
925
- paintPreview(newValue);
917
+ paintPreview(field, newValue);
926
918
  list.invalidate();
927
919
  tui.requestRender();
928
920
  });
@@ -945,6 +937,22 @@ ${note}` : head;
945
937
  }
946
938
 
947
939
  // src/quota-status.ts
940
+ var FOOTER_MODE_NOTES = Object.freeze({
941
+ smart: "Picks whichever window runs out first (5h or weekly), weighting the weekly pool by a ratio learned from your usage",
942
+ all: "Lists every window of the pool backing the current model (5h or weekly)"
943
+ });
944
+ var FOOTER_MODE_OPTIONS = Object.freeze([
945
+ "off",
946
+ "smart",
947
+ "all"
948
+ ]);
949
+ function normalizeFooterMode(value) {
950
+ const v = typeof value === "string" ? value.trim().toLowerCase() : "";
951
+ return FOOTER_MODE_OPTIONS.includes(v) ? v : void 0;
952
+ }
953
+ function resolveFooterMode(config) {
954
+ return normalizeFooterMode(config?.settings?.quotaFooter) ?? "off";
955
+ }
948
956
  function renderProgressBar(fraction, width = 10) {
949
957
  const clamped = Math.max(0, Math.min(1, fraction));
950
958
  const filled = Math.round(clamped * width);
@@ -1113,7 +1121,7 @@ function formatQuotaWindowPart(bucket) {
1113
1121
  var ANSI_RED = "\x1B[31m";
1114
1122
  var ANSI_YELLOW = "\x1B[33m";
1115
1123
  var ANSI_DIM = "\x1B[90m";
1116
- var ANSI_FG_RESET2 = "\x1B[39m";
1124
+ var ANSI_FG_RESET = "\x1B[39m";
1117
1125
  var QUOTA_WARN_PCT = 30;
1118
1126
  var QUOTA_ALERT_PCT = 10;
1119
1127
  function resolveColorizer(style) {
@@ -1121,7 +1129,7 @@ function resolveColorizer(style) {
1121
1129
  if (style && typeof style.fg === "function") return (tone, text) => style.fg(tone, text);
1122
1130
  return (tone, text) => {
1123
1131
  const code = tone === "error" ? ANSI_RED : tone === "warning" ? ANSI_YELLOW : ANSI_DIM;
1124
- return `${code}${text}${ANSI_FG_RESET2}`;
1132
+ return `${code}${text}${ANSI_FG_RESET}`;
1125
1133
  };
1126
1134
  }
1127
1135
  function colorizeQuotaFooter(footer, style) {
@@ -1140,9 +1148,51 @@ function colorizeQuotaFooterBoth(footer, style) {
1140
1148
  const sep = color("dim", " \xB7 ");
1141
1149
  return footer.split(" \xB7 ").map((part) => colorizeQuotaFooter(part, style) ?? part).join(sep);
1142
1150
  }
1151
+ function previewQuotaFooterText(coord, modelId, mode, style) {
1152
+ if (!coord) return void 0;
1153
+ const normalized = normalizeFooterMode(mode);
1154
+ if (!normalized || normalized === "off") return void 0;
1155
+ const { colored } = coord.renderFooter(modelId, normalized, style);
1156
+ if (!colored) return void 0;
1157
+ return ANSI_FG_RESET + colored;
1158
+ }
1143
1159
  var QUOTA_STATUS_KEY = "pi-provider-antigravity-footer-usage";
1144
1160
  var QUOTA_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
1145
1161
  var MAX_OBSERVATION_AGE_MS = 60 * 60 * 1e3;
1162
+ function fileQuotaStatusStore(file = defaultConfigFile()) {
1163
+ return {
1164
+ loadMode: () => resolveFooterMode(loadProviderConfig(file)),
1165
+ loadQuotaState: () => loadSubsystemState("quota", file),
1166
+ saveQuotaState: (state) => saveSubsystemState("quota", state, file)
1167
+ };
1168
+ }
1169
+ function createQuotaFooterField(quotaStatus) {
1170
+ return {
1171
+ key: "quotaFooter",
1172
+ label: "Quota footer",
1173
+ description: "Show remaining quota in Pi's status footer",
1174
+ options: FOOTER_MODE_OPTIONS,
1175
+ defaultValue: "off",
1176
+ optionNotes: FOOTER_MODE_NOTES,
1177
+ renderPreview: (mode, ctx, theme) => {
1178
+ if (mode === "off") return "hidden";
1179
+ const activeTheme = theme || ctx.ui?.theme;
1180
+ return previewQuotaFooterText(quotaStatus, ctx.model?.id, mode, activeTheme);
1181
+ },
1182
+ prepare: async (ctx) => {
1183
+ await quotaStatus.ensurePreview(ctx);
1184
+ },
1185
+ onChange: async (ctx, _value) => {
1186
+ if (quotaStatus.mode() !== "off") {
1187
+ await quotaStatus.refresh(ctx, { ignoreMode: true });
1188
+ }
1189
+ quotaStatus.paint(ctx);
1190
+ }
1191
+ };
1192
+ }
1193
+ function registerQuotaSettings(quotaStatus) {
1194
+ registerSettingField(createQuotaFooterField(quotaStatus));
1195
+ }
1146
1196
  function isFiniteNumber(value) {
1147
1197
  return typeof value === "number" && Number.isFinite(value);
1148
1198
  }
@@ -1339,6 +1389,13 @@ import {
1339
1389
 
1340
1390
  // src/builder.ts
1341
1391
  import { createHash as createHash2, randomUUID } from "node:crypto";
1392
+ import {
1393
+ collapseSystemMessages,
1394
+ getCurrentSystemPrompt,
1395
+ getCurrentTools,
1396
+ normalizeContext,
1397
+ withoutInitialSystemMessage
1398
+ } from "@earendil-works/pi-ai";
1342
1399
  var BASE64_SIGNATURE_PATTERN = /^[A-Za-z0-9+/_-]+={0,2}$/;
1343
1400
  var SKIP_THOUGHT_SIGNATURE_VALIDATOR = "skip_thought_signature_validator";
1344
1401
  function isValidThoughtSignature(sig) {
@@ -1350,11 +1407,11 @@ function resolveThoughtSignature(isSameProviderAndModel, sig) {
1350
1407
  if (!isSameProviderAndModel) return void 0;
1351
1408
  return isValidThoughtSignature(sig) ? sig : void 0;
1352
1409
  }
1353
- function deriveSessionId(context, explicitSessionId) {
1410
+ function deriveSessionId(conversation, explicitSessionId) {
1354
1411
  if (explicitSessionId && typeof explicitSessionId === "string" && explicitSessionId.trim().length > 0) {
1355
1412
  return explicitSessionId.trim();
1356
1413
  }
1357
- const firstMsg = context.messages?.[0];
1414
+ const firstMsg = conversation?.[0];
1358
1415
  if (!firstMsg) {
1359
1416
  return randomUUID();
1360
1417
  }
@@ -1447,9 +1504,9 @@ function convertTools(tools) {
1447
1504
  }
1448
1505
  ];
1449
1506
  }
1450
- function translateTurnTrace(context, runtimeModelId) {
1507
+ function translateTurnTrace(conversation, runtimeModelId) {
1451
1508
  const contents = [];
1452
- const messages = context.messages || [];
1509
+ const messages = conversation || [];
1453
1510
  const isGeminiRequest = classifyModelFamily(runtimeModelId) === "gemini";
1454
1511
  const isGptRequest = classifyModelFamily(runtimeModelId) === "gpt";
1455
1512
  for (const msg of messages) {
@@ -1640,9 +1697,13 @@ function buildAntigravityRequestBody(params) {
1640
1697
  maxOutputTokens = 65536
1641
1698
  } = params;
1642
1699
  const runtimeModelId = plan.runtimeModelId;
1643
- const sessionId = deriveSessionId(context, params.sessionId);
1700
+ const transcript = collapseSystemMessages(context);
1701
+ const systemPrompt = getCurrentSystemPrompt(transcript.messages);
1702
+ const tools = convertTools(getCurrentTools(transcript.messages));
1703
+ const conversation = withoutInitialSystemMessage(transcript.messages);
1704
+ const sessionId = deriveSessionId(conversation, params.sessionId);
1644
1705
  const trajectoryId = params.trajectoryId && typeof params.trajectoryId === "string" && params.trajectoryId.trim().length > 0 ? params.trajectoryId.trim() : resolveSessionTrajectory(sessionId);
1645
- const contents = translateTurnTrace(context, runtimeModelId);
1706
+ const contents = translateTurnTrace(conversation, runtimeModelId);
1646
1707
  const requestIndex = contents.filter(
1647
1708
  (c) => c.role === "model" && !c.parts?.some((p) => p.functionResponse)
1648
1709
  ).length;
@@ -1664,13 +1725,12 @@ function buildAntigravityRequestBody(params) {
1664
1725
  const request = {
1665
1726
  contents
1666
1727
  };
1667
- if (context.systemPrompt) {
1728
+ if (systemPrompt) {
1668
1729
  request.systemInstruction = {
1669
1730
  role: "user",
1670
- parts: [{ text: context.systemPrompt }]
1731
+ parts: [{ text: systemPrompt }]
1671
1732
  };
1672
1733
  }
1673
- const tools = convertTools(context.tools);
1674
1734
  if (tools) {
1675
1735
  request.tools = tools;
1676
1736
  }
@@ -1742,6 +1802,9 @@ function processLine(rawLine, state, onEvent) {
1742
1802
  return;
1743
1803
  }
1744
1804
  const response = payload.response || payload;
1805
+ if (response.responseId && !state.responseId) {
1806
+ state.responseId = response.responseId;
1807
+ }
1745
1808
  if (response.usageMetadata) {
1746
1809
  const um = response.usageMetadata;
1747
1810
  const promptTokens = typeof um.promptTokenCount === "number" ? um.promptTokenCount : 0;
@@ -1862,6 +1925,9 @@ async function consumeAntigravityStream(streamBody, output, stream, modelCost) {
1862
1925
  total: inputCost + outputCost + cacheCost
1863
1926
  };
1864
1927
  }
1928
+ if (state.responseId) {
1929
+ output.responseId ||= state.responseId;
1930
+ }
1865
1931
  output.stopReason = state.stopReason;
1866
1932
  };
1867
1933
  const dispatchEvent = (ev) => {
@@ -1910,7 +1976,7 @@ function streamAntigravity(model, context, options, catalog) {
1910
1976
  context,
1911
1977
  sessionId: options?.sessionId,
1912
1978
  trajectoryId,
1913
- maxOutputTokens: model.maxTokens,
1979
+ maxOutputTokens: options?.maxTokens ?? model.maxTokens,
1914
1980
  toolChoice: options?.toolChoice
1915
1981
  });
1916
1982
  const streamBody = await postAntigravityStream({
@@ -2063,7 +2129,10 @@ var SUBCOMMANDS = Object.freeze([
2063
2129
  name: "settings",
2064
2130
  description: "Configure provider settings",
2065
2131
  aliases: Object.freeze(["setting"]),
2066
- run: async ({ ctx, quotaStatus }) => openSettings(ctx, quotaStatus)
2132
+ run: async ({ ctx, quotaStatus }) => {
2133
+ if (quotaStatus) registerQuotaSettings(quotaStatus);
2134
+ await openSettings(ctx);
2135
+ }
2067
2136
  },
2068
2137
  {
2069
2138
  name: "websearch",
@@ -2214,6 +2283,7 @@ async function runAntigravitySubcommand(args, ctx, quotaStatus, catalog) {
2214
2283
  var PROVIDER_NAME = "Antigravity";
2215
2284
  function index_default(pi) {
2216
2285
  const quotaStatus = new QuotaStatusCoordinator();
2286
+ registerQuotaSettings(quotaStatus);
2217
2287
  const catalog = createModelCatalog();
2218
2288
  pi.registerProvider(PROVIDER_ID, {
2219
2289
  name: PROVIDER_NAME,