pi-provider-antigravity 0.14.0 → 0.15.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 +3 -1
- package/dist/index.js +130 -35
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,7 +39,9 @@ pi -e npm:pi-provider-antigravity
|
|
|
39
39
|
|
|
40
40
|
### Legacy Pi Support
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
We strongly recommend upgrading to Pi >= 0.86.0 to take advantage of the latest SDK capabilities, streaming reliability improvements, and full feature parity.
|
|
43
|
+
|
|
44
|
+
However, if you are unable to upgrade your Pi installation just yet (for environment or workflow reasons), you can pin to the compatible `0.13.0` release for Pi 0.80.0 ~ 0.85.x:
|
|
43
45
|
|
|
44
46
|
```bash
|
|
45
47
|
pi install npm:pi-provider-antigravity@0.13.0
|
package/dist/index.js
CHANGED
|
@@ -28,13 +28,15 @@ function resolveToken(auth) {
|
|
|
28
28
|
async function postAntigravityRaw({
|
|
29
29
|
auth,
|
|
30
30
|
path: path2,
|
|
31
|
+
endpoint = DEFAULT_ENDPOINT,
|
|
32
|
+
headers,
|
|
31
33
|
body,
|
|
32
34
|
signal
|
|
33
35
|
}) {
|
|
34
36
|
const token = resolveToken(auth);
|
|
35
|
-
return fetch(`${
|
|
37
|
+
return fetch(`${endpoint}/${path2}`, {
|
|
36
38
|
method: "POST",
|
|
37
|
-
headers: buildAntigravityHeaders(token),
|
|
39
|
+
headers: { ...buildAntigravityHeaders(token), ...headers },
|
|
38
40
|
body: JSON.stringify(body),
|
|
39
41
|
signal
|
|
40
42
|
});
|
|
@@ -56,7 +58,7 @@ async function postAntigravityStream(params) {
|
|
|
56
58
|
if (!res.body) {
|
|
57
59
|
throw new Error(`No response stream received from Antigravity for ${params.path}.`);
|
|
58
60
|
}
|
|
59
|
-
return res.body;
|
|
61
|
+
return { response: res, stream: res.body };
|
|
60
62
|
}
|
|
61
63
|
function buildAntigravityHeaders(token, userAgent = DEFAULT_USER_AGENT) {
|
|
62
64
|
return {
|
|
@@ -122,7 +124,8 @@ async function fetchProjectId(token, signal) {
|
|
|
122
124
|
if (data.cloudaicompanionProject) {
|
|
123
125
|
return data.cloudaicompanionProject;
|
|
124
126
|
}
|
|
125
|
-
} catch {
|
|
127
|
+
} catch (err) {
|
|
128
|
+
if (signal?.aborted) throw err;
|
|
126
129
|
}
|
|
127
130
|
return FALLBACK_PROJECT_ID;
|
|
128
131
|
}
|
|
@@ -142,16 +145,37 @@ async function loginAntigravity(callbacks) {
|
|
|
142
145
|
});
|
|
143
146
|
const authUrl = `${AUTH_URL}?${authParams.toString()}`;
|
|
144
147
|
callbacks.onAuth({ url: authUrl });
|
|
148
|
+
let timer;
|
|
149
|
+
const abortPromise = new Promise((_, rej) => {
|
|
150
|
+
if (callbacks.signal?.aborted) {
|
|
151
|
+
rej(callbacks.signal.reason ?? new Error("Login cancelled"));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
callbacks.signal?.addEventListener(
|
|
155
|
+
"abort",
|
|
156
|
+
() => rej(callbacks.signal?.reason ?? new Error("Login cancelled")),
|
|
157
|
+
{ once: true }
|
|
158
|
+
);
|
|
159
|
+
});
|
|
145
160
|
const manualPromptPromise = (async () => {
|
|
146
161
|
const input = await callbacks.onPrompt({
|
|
147
162
|
message: "Paste authorization code from browser:"
|
|
148
163
|
});
|
|
149
164
|
return extractCodeFromInput(input);
|
|
150
165
|
})();
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
const timeoutPromise = new Promise((_, rej) => {
|
|
167
|
+
timer = setTimeout(
|
|
168
|
+
() => rej(new Error("Timed out waiting for authorization code (5 minutes)")),
|
|
169
|
+
OAUTH_CALLBACK_TIMEOUT_MS
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
let code;
|
|
173
|
+
try {
|
|
174
|
+
code = await Promise.race([manualPromptPromise, timeoutPromise, abortPromise]);
|
|
175
|
+
} finally {
|
|
176
|
+
if (timer) clearTimeout(timer);
|
|
177
|
+
}
|
|
178
|
+
callbacks.onProgress?.("Exchanging authorization code for tokens...");
|
|
155
179
|
const tokenParams = new URLSearchParams({
|
|
156
180
|
client_id: CLIENT_ID,
|
|
157
181
|
client_secret: CLIENT_SECRET,
|
|
@@ -163,14 +187,16 @@ async function loginAntigravity(callbacks) {
|
|
|
163
187
|
const tokenRes = await fetch(TOKEN_URL, {
|
|
164
188
|
method: "POST",
|
|
165
189
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
166
|
-
body: tokenParams.toString()
|
|
190
|
+
body: tokenParams.toString(),
|
|
191
|
+
signal: callbacks.signal
|
|
167
192
|
});
|
|
168
193
|
if (!tokenRes.ok) {
|
|
169
194
|
const errText = await tokenRes.text();
|
|
170
195
|
throw new Error(`Failed to exchange token (${tokenRes.status}): ${errText}`);
|
|
171
196
|
}
|
|
172
197
|
const tokens = await tokenRes.json();
|
|
173
|
-
|
|
198
|
+
callbacks.onProgress?.("Resolving Code Assist project ID...");
|
|
199
|
+
const projectId = await fetchProjectId(tokens.access_token, callbacks.signal);
|
|
174
200
|
return {
|
|
175
201
|
refresh: tokens.refresh_token || "",
|
|
176
202
|
access: JSON.stringify({ token: tokens.access_token, projectId }),
|
|
@@ -527,6 +553,7 @@ function synthesizeDynamicModel(baseId, items) {
|
|
|
527
553
|
const isGpt = family === "gpt";
|
|
528
554
|
const defaultContext = isFlash ? 1048576 : isClaude ? 25e4 : isGpt ? 128e3 : 1048576;
|
|
529
555
|
const defaultMaxOutput = isClaude ? 64e3 : isGpt ? 32768 : 65536;
|
|
556
|
+
const promptCache = isClaude ? { short: 300, long: 3600 } : { short: 300 };
|
|
530
557
|
return {
|
|
531
558
|
id: baseId,
|
|
532
559
|
name: formatModelDisplayName(baseId, repItem?.displayName),
|
|
@@ -537,6 +564,7 @@ function synthesizeDynamicModel(baseId, items) {
|
|
|
537
564
|
thinkingLevelMap,
|
|
538
565
|
input: repItem?.supportsImages ? ["text", "image"] : ["text"],
|
|
539
566
|
cost: estimateModelCost(baseId),
|
|
567
|
+
promptCache,
|
|
540
568
|
contextWindow: repItem?.maxTokens || defaultContext,
|
|
541
569
|
maxTokens: repItem?.maxOutputTokens || defaultMaxOutput
|
|
542
570
|
};
|
|
@@ -1384,6 +1412,7 @@ var QuotaStatusCoordinator = class {
|
|
|
1384
1412
|
|
|
1385
1413
|
// src/stream.ts
|
|
1386
1414
|
import {
|
|
1415
|
+
calculateCost,
|
|
1387
1416
|
createAssistantMessageEventStream
|
|
1388
1417
|
} from "@earendil-works/pi-ai";
|
|
1389
1418
|
|
|
@@ -1801,6 +1830,10 @@ function processLine(rawLine, state, onEvent) {
|
|
|
1801
1830
|
} catch {
|
|
1802
1831
|
return;
|
|
1803
1832
|
}
|
|
1833
|
+
const streamError = payload?.error ?? payload?.response?.error;
|
|
1834
|
+
if (streamError) {
|
|
1835
|
+
throw new Error(streamError.message ?? JSON.stringify(streamError));
|
|
1836
|
+
}
|
|
1804
1837
|
const response = payload.response || payload;
|
|
1805
1838
|
if (response.responseId && !state.responseId) {
|
|
1806
1839
|
state.responseId = response.responseId;
|
|
@@ -1821,8 +1854,14 @@ function processLine(rawLine, state, onEvent) {
|
|
|
1821
1854
|
if (!candidate) return;
|
|
1822
1855
|
if (candidate.finishReason === "MAX_TOKENS") {
|
|
1823
1856
|
state.stopReason = "length";
|
|
1824
|
-
|
|
1857
|
+
state.rawStopReason = "MAX_TOKENS";
|
|
1858
|
+
} else if (candidate.finishReason === "STOP") {
|
|
1859
|
+
if (state.stopReason === "pending") {
|
|
1860
|
+
state.stopReason = "stop";
|
|
1861
|
+
}
|
|
1862
|
+
} else if (typeof candidate.finishReason === "string") {
|
|
1825
1863
|
state.stopReason = "error";
|
|
1864
|
+
state.rawStopReason = candidate.finishReason;
|
|
1826
1865
|
}
|
|
1827
1866
|
const parts = candidate.content?.parts || [];
|
|
1828
1867
|
for (const part of parts) {
|
|
@@ -1851,7 +1890,9 @@ function processLine(rawLine, state, onEvent) {
|
|
|
1851
1890
|
});
|
|
1852
1891
|
} else if (part.functionCall) {
|
|
1853
1892
|
closeOpenBlock(state, onEvent);
|
|
1854
|
-
state.stopReason
|
|
1893
|
+
if (state.stopReason === "pending" || state.stopReason === "stop") {
|
|
1894
|
+
state.stopReason = "toolUse";
|
|
1895
|
+
}
|
|
1855
1896
|
const block = {
|
|
1856
1897
|
type: "toolCall",
|
|
1857
1898
|
id: part.functionCall.id || `call_${state.content.length}`,
|
|
@@ -1899,36 +1940,43 @@ function finishStream(state, onEvent) {
|
|
|
1899
1940
|
closeOpenBlock(state, onEvent);
|
|
1900
1941
|
attachLoneSignature(state.content, state.lastThoughtSignature);
|
|
1901
1942
|
}
|
|
1902
|
-
|
|
1943
|
+
var NON_OVERFLOW_PATTERN = /rate limit|too many requests|quota exceeded|resource_exhausted/i;
|
|
1944
|
+
var CONTEXT_OVERFLOW_PATTERN = /(?:(?:input|prompt) token count.*exceeds|prompt (?:is )?too long)/i;
|
|
1945
|
+
function normalizeOverflowError(rawMessage) {
|
|
1946
|
+
if (rawMessage.includes("context_length_exceeded")) return rawMessage;
|
|
1947
|
+
if (!NON_OVERFLOW_PATTERN.test(rawMessage) && CONTEXT_OVERFLOW_PATTERN.test(rawMessage)) {
|
|
1948
|
+
return `context_length_exceeded: ${rawMessage}`;
|
|
1949
|
+
}
|
|
1950
|
+
return rawMessage;
|
|
1951
|
+
}
|
|
1952
|
+
async function consumeAntigravityStream(streamBody, output, stream, model, signal) {
|
|
1903
1953
|
const state = {
|
|
1904
1954
|
content: output.content,
|
|
1905
1955
|
usage: { input: 0, output: 0, cacheRead: 0, reasoning: 0, total: 0 },
|
|
1906
|
-
stopReason: "
|
|
1956
|
+
stopReason: "pending",
|
|
1907
1957
|
openType: null,
|
|
1908
1958
|
buffer: ""
|
|
1909
1959
|
};
|
|
1960
|
+
let lastTotalTokens = -1;
|
|
1910
1961
|
const updateUsageAndCost = () => {
|
|
1911
1962
|
output.usage.input = state.usage.input;
|
|
1912
1963
|
output.usage.cacheRead = state.usage.cacheRead;
|
|
1913
1964
|
output.usage.output = state.usage.output;
|
|
1914
1965
|
output.usage.reasoning = state.usage.reasoning;
|
|
1915
1966
|
output.usage.totalTokens = state.usage.total;
|
|
1916
|
-
if (
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
input: inputCost,
|
|
1922
|
-
output: outputCost,
|
|
1923
|
-
cacheRead: cacheCost,
|
|
1924
|
-
cacheWrite: 0,
|
|
1925
|
-
total: inputCost + outputCost + cacheCost
|
|
1926
|
-
};
|
|
1967
|
+
if (state.usage.total !== lastTotalTokens) {
|
|
1968
|
+
lastTotalTokens = state.usage.total;
|
|
1969
|
+
if (model.cost) {
|
|
1970
|
+
calculateCost(model, output.usage);
|
|
1971
|
+
}
|
|
1927
1972
|
}
|
|
1928
1973
|
if (state.responseId) {
|
|
1929
1974
|
output.responseId ||= state.responseId;
|
|
1930
1975
|
}
|
|
1931
1976
|
output.stopReason = state.stopReason;
|
|
1977
|
+
if (state.rawStopReason) {
|
|
1978
|
+
output.rawStopReason = state.rawStopReason;
|
|
1979
|
+
}
|
|
1932
1980
|
};
|
|
1933
1981
|
const dispatchEvent = (ev) => {
|
|
1934
1982
|
updateUsageAndCost();
|
|
@@ -1936,13 +1984,20 @@ async function consumeAntigravityStream(streamBody, output, stream, modelCost) {
|
|
|
1936
1984
|
};
|
|
1937
1985
|
const reader = streamBody.getReader();
|
|
1938
1986
|
const decoder = new TextDecoder();
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1987
|
+
try {
|
|
1988
|
+
while (true) {
|
|
1989
|
+
if (signal?.aborted) {
|
|
1990
|
+
throw new Error("Request was aborted");
|
|
1991
|
+
}
|
|
1992
|
+
const { done, value } = await reader.read();
|
|
1993
|
+
if (done) break;
|
|
1994
|
+
feedChunk(decoder.decode(value, { stream: true }), state, dispatchEvent);
|
|
1995
|
+
}
|
|
1996
|
+
finishStream(state, dispatchEvent);
|
|
1997
|
+
updateUsageAndCost();
|
|
1998
|
+
} finally {
|
|
1999
|
+
reader.releaseLock();
|
|
1943
2000
|
}
|
|
1944
|
-
finishStream(state, dispatchEvent);
|
|
1945
|
-
updateUsageAndCost();
|
|
1946
2001
|
}
|
|
1947
2002
|
function streamAntigravity(model, context, options, catalog) {
|
|
1948
2003
|
const stream = createAssistantMessageEventStream();
|
|
@@ -1970,7 +2025,7 @@ function streamAntigravity(model, context, options, catalog) {
|
|
|
1970
2025
|
const effort = options?.reasoning;
|
|
1971
2026
|
const trajectoryId = options && "trajectoryId" in options && typeof options.trajectoryId === "string" ? options.trajectoryId : void 0;
|
|
1972
2027
|
const plan = catalog.resolvePlan(model.id, effort);
|
|
1973
|
-
|
|
2028
|
+
let requestBody = buildAntigravityRequestBody({
|
|
1974
2029
|
projectId,
|
|
1975
2030
|
plan,
|
|
1976
2031
|
context,
|
|
@@ -1979,13 +2034,51 @@ function streamAntigravity(model, context, options, catalog) {
|
|
|
1979
2034
|
maxOutputTokens: options?.maxTokens ?? model.maxTokens,
|
|
1980
2035
|
toolChoice: options?.toolChoice
|
|
1981
2036
|
});
|
|
1982
|
-
|
|
2037
|
+
if (options?.onPayload) {
|
|
2038
|
+
const replacement = await options.onPayload(requestBody, model);
|
|
2039
|
+
if (replacement !== void 0) {
|
|
2040
|
+
requestBody = replacement;
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
const endpoint = model.baseUrl || DEFAULT_ENDPOINT;
|
|
2044
|
+
const mergedHeaders = {};
|
|
2045
|
+
if (model.headers) {
|
|
2046
|
+
for (const [k, v] of Object.entries(model.headers)) {
|
|
2047
|
+
if (typeof v === "string") mergedHeaders[k] = v;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
if (options?.headers) {
|
|
2051
|
+
for (const [k, v] of Object.entries(options.headers)) {
|
|
2052
|
+
if (typeof v === "string") mergedHeaders[k] = v;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
const { response, stream: streamBody } = await postAntigravityStream({
|
|
1983
2056
|
auth: token,
|
|
2057
|
+
endpoint,
|
|
1984
2058
|
path: "v1internal:streamGenerateContent?alt=sse",
|
|
2059
|
+
headers: mergedHeaders,
|
|
1985
2060
|
body: requestBody,
|
|
1986
2061
|
signal: options?.signal
|
|
1987
2062
|
});
|
|
1988
|
-
|
|
2063
|
+
if (options?.onResponse) {
|
|
2064
|
+
const resHeaders = {};
|
|
2065
|
+
response.headers.forEach((val, key) => {
|
|
2066
|
+
resHeaders[key] = val;
|
|
2067
|
+
});
|
|
2068
|
+
await options.onResponse({ status: response.status, headers: resHeaders }, model);
|
|
2069
|
+
}
|
|
2070
|
+
await consumeAntigravityStream(streamBody, output, stream, model, options?.signal);
|
|
2071
|
+
if (options?.signal?.aborted) {
|
|
2072
|
+
throw new Error("Request was aborted");
|
|
2073
|
+
}
|
|
2074
|
+
if (output.stopReason === "pending") {
|
|
2075
|
+
throw new Error("Provider stream ended without a stop reason");
|
|
2076
|
+
}
|
|
2077
|
+
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
2078
|
+
throw new Error(
|
|
2079
|
+
output.rawStopReason ? `Provider stopped with: ${output.rawStopReason}` : output.errorMessage || "An unknown error occurred"
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
1989
2082
|
const doneReason = output.stopReason === "toolUse" || output.stopReason === "length" ? output.stopReason : "stop";
|
|
1990
2083
|
stream.push({
|
|
1991
2084
|
type: "done",
|
|
@@ -1995,7 +2088,8 @@ function streamAntigravity(model, context, options, catalog) {
|
|
|
1995
2088
|
stream.end();
|
|
1996
2089
|
} catch (error) {
|
|
1997
2090
|
output.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
1998
|
-
|
|
2091
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
2092
|
+
output.errorMessage = normalizeOverflowError(rawMessage);
|
|
1999
2093
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
2000
2094
|
stream.end();
|
|
2001
2095
|
}
|
|
@@ -2293,6 +2387,7 @@ function index_default(pi) {
|
|
|
2293
2387
|
// Purely dynamic provider per Pi SDK architecture
|
|
2294
2388
|
oauth: {
|
|
2295
2389
|
name: PROVIDER_NAME,
|
|
2390
|
+
isSubscription: true,
|
|
2296
2391
|
login: loginAntigravity,
|
|
2297
2392
|
refreshToken: refreshAntigravityToken,
|
|
2298
2393
|
getApiKey
|