@estebanforge/pi-ask-antigravity 1.0.0 → 1.0.1
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/extensions/index.ts +51 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A [Pi](https://github.com/earendil-works/pi-coding-agent) extension that exposes the **`AskAntigravity`** tool: delegate a self-contained sub-task to Google Antigravity's `agy` CLI and stream its response back into the Pi session.
|
|
4
4
|
|
|
5
|
-
It is the `AskClaude`-style delegation pattern, pointed at Gemini via `agy`. The tool answers to three names the CLI is known by — **gemini**, **antigravity**, and **agy** — surfaced in its description so the model maps any of them to this single tool.
|
|
5
|
+
It is the `AskClaude`-style delegation pattern (from pi-claude-bride extension), pointed at Gemini via `agy`. The tool answers to three names the CLI is known by — **gemini**, **antigravity**, and **agy** — surfaced in its description so the model maps any of them to this single tool.
|
|
6
|
+
|
|
7
|
+
<img width="1512" height="845" alt="image" src="https://github.com/user-attachments/assets/3e1a8f19-64d2-43ab-a30f-47f39daa151d" />
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
package/extensions/index.ts
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
getSettingsListTheme,
|
|
38
38
|
type ExtensionAPI,
|
|
39
39
|
} from "@earendil-works/pi-coding-agent";
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
import { Container, SettingsList, Text, type SettingItem } from "@earendil-works/pi-tui";
|
|
42
42
|
import { Type } from "typebox";
|
|
43
43
|
|
|
@@ -252,14 +252,27 @@ function resolveModel(
|
|
|
252
252
|
const versioned = candidates.filter((e) => e.version === version);
|
|
253
253
|
if (versioned.length > 0) candidates = versioned;
|
|
254
254
|
} else {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
// Prefer Google's official `gemini-*-latest` aliases (entries with no
|
|
256
|
+
// parseable version in their name, e.g. "Gemini Flash Latest") when
|
|
257
|
+
// the user did NOT pin a specific version. The alias is the
|
|
258
|
+
// versionless pointer Google intends for "the current release" and
|
|
259
|
+
// hot-swaps on every release, while versioned entries like
|
|
260
|
+
// "Gemini 3.6 Flash (Medium)" stay available via explicit pinning
|
|
261
|
+
// (e.g. "3.6 flash medium"). Falls back to the highest versioned
|
|
262
|
+
// entry if no alias is present in the catalog.
|
|
263
|
+
const aliases = candidates.filter((e) => e.version === null);
|
|
264
|
+
if (aliases.length > 0) {
|
|
265
|
+
candidates = aliases;
|
|
266
|
+
} else {
|
|
267
|
+
const versions = candidates
|
|
268
|
+
.map((e) => e.version)
|
|
269
|
+
.filter((v): v is string => v !== null)
|
|
270
|
+
.sort(compareVersionsDesc);
|
|
271
|
+
if (versions.length > 0) {
|
|
272
|
+
const top = versions[0];
|
|
273
|
+
const latest = candidates.filter((e) => e.version === top);
|
|
274
|
+
if (latest.length > 0) candidates = latest;
|
|
275
|
+
}
|
|
263
276
|
}
|
|
264
277
|
}
|
|
265
278
|
|
|
@@ -382,8 +395,9 @@ interface AgyDetails {
|
|
|
382
395
|
|
|
383
396
|
export default async function (pi: ExtensionAPI) {
|
|
384
397
|
const binary = resolveAgy();
|
|
385
|
-
// Discovered once at load; frozen for the session
|
|
386
|
-
//
|
|
398
|
+
// Discovered once at load; frozen for the session. Run /reload after an
|
|
399
|
+
// `agy update` to refresh. Failure is non-fatal: resolveModel falls back
|
|
400
|
+
// to passthrough so exact slugs typed by the user still work.
|
|
387
401
|
const discovered = await discoverModels(binary).catch(() => []);
|
|
388
402
|
|
|
389
403
|
// --- /agy: view / change default model + thinking ---------------------
|
|
@@ -498,27 +512,17 @@ export default async function (pi: ExtensionAPI) {
|
|
|
498
512
|
|
|
499
513
|
// --- Tool registration -------------------------------------------------
|
|
500
514
|
|
|
501
|
-
// Model param: free string (friendly alias OR exact).
|
|
502
|
-
//
|
|
503
|
-
//
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
"Model alias or exact id. Friendly: 'flash' (latest Flash), 'pro' (latest Pro), 'gemini' (=flash). Add a tier: 'flash high', 'pro low'. Pin a version: '3.5 flash'. Exact: 'Gemini 3.5 Flash (Medium)'. Omit for the configured default.",
|
|
513
|
-
},
|
|
514
|
-
),
|
|
515
|
-
)
|
|
516
|
-
: Type.Optional(
|
|
517
|
-
Type.String({
|
|
518
|
-
description:
|
|
519
|
-
"Model alias or exact id. Friendly: 'flash', 'pro', 'gemini'. Add tier: 'flash high'. Omit for default.",
|
|
520
|
-
}),
|
|
521
|
-
);
|
|
515
|
+
// Model param: free string (friendly alias OR exact). Previously this
|
|
516
|
+
// was a StringEnum built from the live catalog; that made tiered/pinned
|
|
517
|
+
// aliases ("flash high", "3.5 flash") fail AJV validation before
|
|
518
|
+
// resolveModel ever saw them. Type.String() lets the resolver handle
|
|
519
|
+
// every documented form and falls back to agy for unknown slugs.
|
|
520
|
+
const modelParam = Type.Optional(
|
|
521
|
+
Type.String({
|
|
522
|
+
description:
|
|
523
|
+
"Model alias or exact id. Friendly: 'flash' (latest Flash, prefers the gemini-flash-latest alias), 'pro' (latest Pro, prefers gemini-pro-latest), 'gemini' (=flash). Add a tier: 'flash high', 'pro low'. Pin a version: '3.5 flash'. Exact: 'Gemini 3.5 Flash (Medium)'. Omit for the configured default.",
|
|
524
|
+
}),
|
|
525
|
+
);
|
|
522
526
|
|
|
523
527
|
pi.registerTool({
|
|
524
528
|
name: "AskAntigravity",
|
|
@@ -581,6 +585,21 @@ export default async function (pi: ExtensionAPI) {
|
|
|
581
585
|
|
|
582
586
|
const config = loadConfig();
|
|
583
587
|
const requestedModel = (params.model as string | undefined) ?? config.defaultModel;
|
|
588
|
+
// Defensive: reject leading-dash model values that could misbind
|
|
589
|
+
// on agy's arg parser when spliced as the `--model` value. Same
|
|
590
|
+
// threat model as CONV_ID_RE — a leading-dash value can't be a
|
|
591
|
+
// model id, so refuse it instead of letting it reach argv.
|
|
592
|
+
if (typeof params.model === "string" && params.model.trim().startsWith("-")) {
|
|
593
|
+
return {
|
|
594
|
+
content: [
|
|
595
|
+
{
|
|
596
|
+
type: "text",
|
|
597
|
+
text: `model value "${params.model}" starts with "-" — not a valid model id. Use a friendly alias (e.g. "flash", "pro", "gemini") or a known exact id (e.g. "Gemini 3.5 Flash (Medium)").`,
|
|
598
|
+
},
|
|
599
|
+
],
|
|
600
|
+
details: emptyDetails(requestedModel, null),
|
|
601
|
+
};
|
|
602
|
+
}
|
|
584
603
|
const resolved =
|
|
585
604
|
resolveModel(requestedModel, discovered, config.defaultThinking) ?? requestedModel;
|
|
586
605
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estebanforge/pi-ask-antigravity",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Pi tool that delegates a self-contained sub-task to Google Antigravity's agy CLI (the CLI for Gemini). Friendly model aliases (flash/pro/gemini), configurable default model + thinking, and the AskAntigravity delegation tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|