@estebanforge/pi-ask-antigravity 1.0.1 → 1.1.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 +31 -1
- package/extensions/index.ts +114 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,11 +51,40 @@ Verbose `agy models` strings (`Gemini 3.5 Flash (Medium)`) are hostile to natura
|
|
|
51
51
|
| `pro low` | latest Pro, Low |
|
|
52
52
|
| `3.5 flash` | pinned version, default tier |
|
|
53
53
|
| `3.1 pro` | pinned Pro version (→ High) |
|
|
54
|
+
| `sonnet` | Claude Sonnet 4.6 (Thinking) |
|
|
55
|
+
| `opus` | Claude Opus 4.6 (Thinking) |
|
|
56
|
+
| `gpt-oss` | GPT-OSS 120B (Medium) |
|
|
54
57
|
| `Gemini 3.5 Flash (Medium)` | exact passthrough |
|
|
55
58
|
|
|
56
59
|
- **Latest** = highest version number available for the family.
|
|
57
60
|
- **Default tier**: Flash → Medium, Pro → High. Overridable per-config (below).
|
|
58
61
|
- When a tier is unavailable for a family, the nearest is chosen with ties broken toward the higher tier (so "latest and greatest" wins).
|
|
62
|
+
- The non-Gemini aliases (`sonnet`, `opus`, `gpt-oss`) are a static overlay merged with the live `agy models` catalog. Live entries always win on case-insensitive full-string equality, so an updated `agy` listing takes precedence over the hardcoded fallback.
|
|
63
|
+
|
|
64
|
+
## Execution modes (`mode`)
|
|
65
|
+
|
|
66
|
+
| Mode | Flag | Use when |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `plan` | `--mode plan` | agy reviews and plans without writing. Use for cross-review and read-only tasks. |
|
|
69
|
+
| `accept-edits` (default) | `--mode accept-edits` | agy applies edits directly inside the workspace. |
|
|
70
|
+
|
|
71
|
+
For agy's orthogonal `--sandbox` shell-containment flag, set `AGY_EXTRA_ARGS=--sandbox` in your environment. The extension does not expose it as a `mode` value because `--sandbox` controls command containment, not edit persistence.
|
|
72
|
+
|
|
73
|
+
Recommended pairings:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
# Gemini produces, Claude reviews
|
|
77
|
+
AskAntigravity prompt="Implement the approved refactor" mode=accept-edits
|
|
78
|
+
AskAntigravity prompt="Review the resulting diff" model=opus mode=plan digest=true
|
|
79
|
+
|
|
80
|
+
# Claude produces, Gemini reviews
|
|
81
|
+
AskAntigravity prompt="Fix the parser root cause" model=opus mode=accept-edits
|
|
82
|
+
AskAntigravity prompt="Review the resulting diff" model=pro mode=plan digest=true
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Compact output (`digest`)
|
|
86
|
+
|
|
87
|
+
Set `digest: true` to prefix the prompt with `(Use compact digests, not full file contents.)` so `agy` returns summaries instead of full file payloads. Defaults on for `plan`, off for `accept-edits`. Use `true` for any read-only call (review, exploration, planning) where full file contents are noise.
|
|
59
88
|
|
|
60
89
|
## Configuration
|
|
61
90
|
|
|
@@ -84,8 +113,9 @@ Interactive picker for the default model and default thinking. If the project co
|
|
|
84
113
|
| `prompt` | yes | Self-contained task. agy cannot see the Pi conversation. |
|
|
85
114
|
| `cwd` | no | Workspace agy runs in. Defaults to the project root. |
|
|
86
115
|
| `model` | no | Alias or exact id. Omit for the configured default. |
|
|
116
|
+
| `mode` | no | `plan` (review-only) or `accept-edits` (agy applies edits, default). |
|
|
117
|
+
| `digest` | no | Prefix the prompt with `(Use compact digests, not full file contents.)`. Defaults on for `plan`, off for `accept-edits`. |
|
|
87
118
|
| `conversationId` | no | Omit for a one-shot (agy starts fresh). Pass the id from a prior call's result (`details.conversationId`) to resume that agy conversation with full context. See [Two modes](#two-modes-one-shot-vs-continued-conversation). |
|
|
88
|
-
| `skipPermissions` | no | Pass `--dangerously-skip-permissions`. Needed for mutating tasks. |
|
|
89
119
|
| `timeoutMinutes` | no | Hard cap on the run. Default 10. |
|
|
90
120
|
|
|
91
121
|
## Environment
|
package/extensions/index.ts
CHANGED
|
@@ -66,16 +66,70 @@ const FAMILY_DEFAULT_TIER: Record<Family, ThinkingTier> = {
|
|
|
66
66
|
|
|
67
67
|
const TIER_RANK: Record<ThinkingTier, number> = { low: 0, medium: 1, high: 2 };
|
|
68
68
|
|
|
69
|
+
// Mode = which agy tool-loop policy to apply. Distinct from the alias layer.
|
|
70
|
+
// "plan" → --mode plan (no edits; review-only)
|
|
71
|
+
// "accept-edits" → --mode accept-edits (agy applies edits)
|
|
72
|
+
//
|
|
73
|
+
// Note: agy's --sandbox flag is an orthogonal shell-containment setting
|
|
74
|
+
// (not an "edit preview" mode), so it is not exposed here. Users who need
|
|
75
|
+
// it can pass it via the AGY_EXTRA_ARGS env var.
|
|
76
|
+
type Mode = "plan" | "accept-edits";
|
|
77
|
+
|
|
78
|
+
// Static alias overlay for non-Gemini models agy may or may not surface in
|
|
79
|
+
// `agy models` depending on plan. When the live catalog contains an entry
|
|
80
|
+
// whose full string equals the overlay target, the live entry wins. When it
|
|
81
|
+
// does not (older agy, missing model, plan gate), the overlay entry resolves
|
|
82
|
+
// the alias so the user can still type "sonnet" and get a working answer.
|
|
83
|
+
// "sonnet" -> Claude Sonnet 4.6 (Thinking)
|
|
84
|
+
// "opus" -> Claude Opus 4.6 (Thinking)
|
|
85
|
+
// "gpt-oss" -> GPT-OSS 120B (Medium)
|
|
86
|
+
const STATIC_ALIAS_OVERLAY: ReadonlyArray<ModelEntry> = [
|
|
87
|
+
{ full: "Claude Sonnet 4.6 (Thinking)", family: "other", version: null, tier: null },
|
|
88
|
+
{ full: "Claude Opus 4.6 (Thinking)", family: "other", version: null, tier: null },
|
|
89
|
+
{ full: "GPT-OSS 120B (Medium)", family: "other", version: null, tier: null },
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// Short alias → overlay full string. Used by resolveModel to recognize
|
|
93
|
+
// friendly short names ("sonnet") that the family-parser (flash/pro) does
|
|
94
|
+
// not match. The overlay entries are also merged into the live catalog for
|
|
95
|
+
// exact-string passthrough, so this map only needs to cover the short names.
|
|
96
|
+
const STATIC_SHORT_ALIAS: ReadonlyMap<string, string> = new Map([
|
|
97
|
+
["sonnet", "Claude Sonnet 4.6 (Thinking)"],
|
|
98
|
+
["opus", "Claude Opus 4.6 (Thinking)"],
|
|
99
|
+
["gpt-oss", "GPT-OSS 120B (Medium)"],
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
/** Merge the live catalog with the static alias overlay. Live entries win on
|
|
103
|
+
* case-insensitive full-string equality so an updated `agy models` listing
|
|
104
|
+
* always takes precedence over the hardcoded fallback. */
|
|
105
|
+
function mergeCatalog(live: ModelEntry[]): ModelEntry[] {
|
|
106
|
+
const seen = new Set(live.map((e) => e.full.toLowerCase()));
|
|
107
|
+
const merged = [...live];
|
|
108
|
+
for (const entry of STATIC_ALIAS_OVERLAY) {
|
|
109
|
+
if (!seen.has(entry.full.toLowerCase())) merged.push(entry);
|
|
110
|
+
}
|
|
111
|
+
return merged;
|
|
112
|
+
}
|
|
113
|
+
|
|
69
114
|
// agy conversation ids are UUID DB-stems (e.g. "9e6fdc2f-f9f9-4096-95fc-7852528b50cc").
|
|
70
115
|
// Reject anything that isn't, so a leading-dash value can't misbind on agy's
|
|
71
|
-
// arg parser as the token after --conversation.
|
|
72
|
-
|
|
116
|
+
// arg parser as the token after --conversation. First char must be
|
|
117
|
+
// alphanumeric (rejects leading-dash flag injection); hyphens allowed in the
|
|
118
|
+
// body because real UUIDs contain them.
|
|
119
|
+
const CONV_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]{0,127}$/;
|
|
73
120
|
|
|
74
121
|
const AGY_DESCRIPTION = `Delegate a self-contained sub-task to Google Antigravity. agy is the CLI for Gemini, so this tool is reached under three equivalent names the user may use interchangeably: **gemini**, **antigravity**, and **agy**. When the user says "ask gemini", "ask antigravity", "ask agy", or otherwise refers to any of these, call THIS tool. agy runs its OWN tool loop: it can read, write, edit, and execute inside the workspace, then returns its final answer. Use for a second opinion from a different model family, Gemini-specific reasoning, or isolated sub-tasks you do not need to drive step-by-step. Provide a complete, self-contained task description; agy will not see this conversation.
|
|
75
122
|
|
|
76
123
|
TWO MODES (you choose):
|
|
77
124
|
- **One-shot (isolated)**: omit conversationId. agy starts fresh with no memory of prior calls. Use for independent questions.
|
|
78
|
-
- **Continued conversation**: pass the conversationId returned in the PREVIOUS call's details (details.conversationId). agy resumes that conversation with full context intact — use for follow-ups, multi-turn refinement, or when the user says "ask agy to follow up / continue / now do X based on what you just did". Thread the id from each result into the next call
|
|
125
|
+
- **Continued conversation**: pass the conversationId returned in the PREVIOUS call's details (details.conversationId). agy resumes that conversation with full context intact — use for follow-ups, multi-turn refinement, or when the user says "ask agy to follow up / continue / now do X based on what you just did". Thread the id from each result into the next call.
|
|
126
|
+
|
|
127
|
+
EXECUTION MODES (param: mode):
|
|
128
|
+
- **plan**: agy reviews and plans without writing. Use for cross-review and read-only tasks.
|
|
129
|
+
- **accept-edits** (default): agy applies edits directly inside the workspace.
|
|
130
|
+
- For agy's orthogonal \`--sandbox\` shell-containment flag, set the \`AGY_EXTRA_ARGS=--sandbox\` env var.
|
|
131
|
+
|
|
132
|
+
COMPACT OUTPUT (param: digest): when true, the prompt is prefixed to request compact digests instead of full file contents. Defaults on for plan, off for accept-edits. Use true whenever you do not need full file payloads (review, exploration, planning).`;
|
|
79
133
|
|
|
80
134
|
// --- Types -----------------------------------------------------------------
|
|
81
135
|
|
|
@@ -225,6 +279,22 @@ function resolveModel(
|
|
|
225
279
|
const exact = entries.find((e) => e.full.toLowerCase() === lower);
|
|
226
280
|
if (exact) return exact.full;
|
|
227
281
|
|
|
282
|
+
// 1b. Static short alias ("sonnet" / "opus" / "gpt-oss"). Checked
|
|
283
|
+
// before the family parser because none of these names contain
|
|
284
|
+
// "flash" or "pro" and would otherwise return null below. The
|
|
285
|
+
// resolved full string is then re-validated against the catalog
|
|
286
|
+
// in step 1's second pass on the next call, so renaming the
|
|
287
|
+
// overlay entry in code still wins on exact-string match.
|
|
288
|
+
// The case-insensitive lookup matches mergeCatalog's dedup logic
|
|
289
|
+
// so the "live entries win" guarantee holds even when agy lists
|
|
290
|
+
// the model under different casing than the overlay.
|
|
291
|
+
if (STATIC_SHORT_ALIAS.has(lower)) {
|
|
292
|
+
const target = STATIC_SHORT_ALIAS.get(lower) as string;
|
|
293
|
+
const targetLower = target.toLowerCase();
|
|
294
|
+
const fromCatalog = entries.find((e) => e.full.toLowerCase() === targetLower);
|
|
295
|
+
return fromCatalog ? fromCatalog.full : target;
|
|
296
|
+
}
|
|
297
|
+
|
|
228
298
|
// 2. Parse the alias.
|
|
229
299
|
let family: Family | null = lower.includes("flash")
|
|
230
300
|
? "flash"
|
|
@@ -385,6 +455,8 @@ function newConversationId(dir: string, before: Set<string>): string | null {
|
|
|
385
455
|
interface AgyDetails {
|
|
386
456
|
model: string | null;
|
|
387
457
|
resolvedModel: string | null;
|
|
458
|
+
mode: Mode;
|
|
459
|
+
digest: boolean;
|
|
388
460
|
conversationId: string | null;
|
|
389
461
|
exitCode: number;
|
|
390
462
|
aborted: boolean;
|
|
@@ -397,8 +469,10 @@ export default async function (pi: ExtensionAPI) {
|
|
|
397
469
|
const binary = resolveAgy();
|
|
398
470
|
// Discovered once at load; frozen for the session. Run /reload after an
|
|
399
471
|
// `agy update` to refresh. Failure is non-fatal: resolveModel falls back
|
|
400
|
-
// to passthrough so exact slugs typed by the user still work.
|
|
401
|
-
|
|
472
|
+
// to passthrough so exact slugs typed by the user still work. The static
|
|
473
|
+
// alias overlay (sonnet / opus / gpt-oss) is merged on top so those
|
|
474
|
+
// aliases resolve even when agy doesn't surface them in the live catalog.
|
|
475
|
+
const discovered = mergeCatalog(await discoverModels(binary).catch(() => []));
|
|
402
476
|
|
|
403
477
|
// --- /agy: view / change default model + thinking ---------------------
|
|
404
478
|
|
|
@@ -539,10 +613,23 @@ export default async function (pi: ExtensionAPI) {
|
|
|
539
613
|
}),
|
|
540
614
|
),
|
|
541
615
|
model: modelParam,
|
|
542
|
-
|
|
616
|
+
mode: Type.Optional(
|
|
617
|
+
Type.Union(
|
|
618
|
+
[
|
|
619
|
+
Type.Literal("plan"),
|
|
620
|
+
Type.Literal("accept-edits"),
|
|
621
|
+
],
|
|
622
|
+
{
|
|
623
|
+
description:
|
|
624
|
+
"agy execution mode. 'plan' = review-only, no edits (--mode plan). 'accept-edits' = agy applies edits directly (--mode accept-edits, default). For agy's orthogonal --sandbox shell-containment flag, set the AGY_EXTRA_ARGS env var.",
|
|
625
|
+
default: "accept-edits",
|
|
626
|
+
},
|
|
627
|
+
),
|
|
628
|
+
),
|
|
629
|
+
digest: Type.Optional(
|
|
543
630
|
Type.Boolean({
|
|
544
631
|
description:
|
|
545
|
-
"
|
|
632
|
+
"Request compact digests instead of full file contents. When true, the prompt is prefixed with '(Use compact digests, not full file contents.)'. Defaults on for plan, off for accept-edits.",
|
|
546
633
|
}),
|
|
547
634
|
),
|
|
548
635
|
conversationId: Type.Optional(
|
|
@@ -573,6 +660,8 @@ export default async function (pi: ExtensionAPI) {
|
|
|
573
660
|
details: {
|
|
574
661
|
model: null,
|
|
575
662
|
resolvedModel: null,
|
|
663
|
+
mode: "accept-edits",
|
|
664
|
+
digest: false,
|
|
576
665
|
conversationId: null,
|
|
577
666
|
exitCode: 0,
|
|
578
667
|
aborted: false,
|
|
@@ -636,18 +725,32 @@ export default async function (pi: ExtensionAPI) {
|
|
|
636
725
|
typeof rawConvId === "string" && rawConvId.length > 0 && CONV_ID_RE.test(rawConvId);
|
|
637
726
|
const snapshot = isContinuation ? null : snapshotConversations(CONVERSATIONS_DIR);
|
|
638
727
|
|
|
728
|
+
const mode: Mode = (params.mode as Mode | undefined) ?? "accept-edits";
|
|
729
|
+
// digest default: on for plan (review-only contexts where full file
|
|
730
|
+
// contents are noise), off for accept-edits (agy applies edits and
|
|
731
|
+
// may need richer context for diffs).
|
|
732
|
+
const useDigest: boolean =
|
|
733
|
+
typeof params.digest === "boolean"
|
|
734
|
+
? params.digest
|
|
735
|
+
: mode === "plan";
|
|
736
|
+
const finalPrompt: string = useDigest
|
|
737
|
+
? `(Use compact digests, not full file contents.)\n${params.prompt}`
|
|
738
|
+
: params.prompt;
|
|
739
|
+
|
|
639
740
|
const args: string[] = ["--add-dir", cwd];
|
|
640
741
|
const extra = extraArgs();
|
|
641
742
|
if (extra.length) args.push(...extra);
|
|
642
743
|
if (resolved) args.push("--model", resolved);
|
|
643
|
-
|
|
744
|
+
args.push("--mode", mode);
|
|
644
745
|
if (isContinuation) args.push("--conversation", rawConvId as string);
|
|
645
746
|
args.push("--print-timeout", `${timeoutMin}m`);
|
|
646
|
-
args.push("-p",
|
|
747
|
+
args.push("-p", finalPrompt);
|
|
647
748
|
|
|
648
749
|
const details: AgyDetails = {
|
|
649
750
|
model: requestedModel,
|
|
650
751
|
resolvedModel: resolved,
|
|
752
|
+
mode,
|
|
753
|
+
digest: useDigest,
|
|
651
754
|
conversationId: isContinuation ? (rawConvId as string) : null,
|
|
652
755
|
exitCode: 0,
|
|
653
756
|
aborted: false,
|
|
@@ -866,6 +969,8 @@ function emptyDetails(model: string | null, resolvedModel: string | null): AgyDe
|
|
|
866
969
|
return {
|
|
867
970
|
model,
|
|
868
971
|
resolvedModel,
|
|
972
|
+
mode: "accept-edits",
|
|
973
|
+
digest: false,
|
|
869
974
|
conversationId: null,
|
|
870
975
|
exitCode: 0,
|
|
871
976
|
aborted: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estebanforge/pi-ask-antigravity",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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",
|