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 +15 -1
- package/dist/index.js +171 -101
- package/dist/index.js.map +4 -4
- package/package.json +13 -14
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.
|
|
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/
|
|
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
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
}
|
|
786
|
-
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
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 =
|
|
856
|
+
let field = fields[0];
|
|
869
857
|
if (!field) return;
|
|
870
|
-
if (
|
|
871
|
-
const labels =
|
|
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 =
|
|
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
|
|
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,
|
|
892
|
-
|
|
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
|
|
897
|
-
|
|
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 =
|
|
901
|
-
const sample =
|
|
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 =
|
|
892
|
+
const note = field.optionNotes?.[value];
|
|
904
893
|
item.description = note ? `${head}
|
|
905
894
|
${note}` : head;
|
|
906
895
|
};
|
|
907
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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}${
|
|
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(
|
|
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 =
|
|
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(
|
|
1507
|
+
function translateTurnTrace(conversation, runtimeModelId) {
|
|
1451
1508
|
const contents = [];
|
|
1452
|
-
const 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
|
|
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(
|
|
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 (
|
|
1728
|
+
if (systemPrompt) {
|
|
1668
1729
|
request.systemInstruction = {
|
|
1669
1730
|
role: "user",
|
|
1670
|
-
parts: [{ text:
|
|
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 }) =>
|
|
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,
|