@estebanforge/pi-ask-antigravity 1.2.9 → 1.2.10
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/CHANGELOG.md +7 -0
- package/README.md +3 -4
- package/extensions/index.ts +80 -26
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.2.10] - 2026-10-06
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **Breaking: model aliases track agy's Claude 5.5 tiered catalog.** `sonnet`/`opus` now resolve to `claude-sonnet-5-5`/`claude-opus-5-5` with the tier riding `--effort` (nearest-tier pick against the requested thinking level), replacing the retired fixed `claude-sonnet-4-6`/`claude-opus-4-6-thinking` slugs Google removed from Antigravity. The static overlay carries the full low/medium/high spread so the aliases still resolve when the live catalog omits Claude, and the bare base id (`claude-sonnet-5-5`) resolves to the nearest tier variant because a bare base is rejected upstream. Exact tiered ids (`claude-sonnet-5-5-low`) split to base + effort exactly like Gemini's.
|
|
10
|
+
- **The `gpt-oss` alias and its overlay entry are removed** ahead of upstream's announced removal of that family: nobody used the fixed-thinking slug and it loses to the cheaper tiered options. The alias now resolves to nothing (the raw string passes to agy and fails there) instead of the tool offering a dying model.
|
|
11
|
+
|
|
5
12
|
## [1.2.9] - 2026-09-28
|
|
6
13
|
|
|
7
14
|
### Fixed
|
package/README.md
CHANGED
|
@@ -49,15 +49,14 @@ Verbose `agy models` strings (`Gemini 3.5 Flash (Medium)`) are hostile to natura
|
|
|
49
49
|
| `pro low` | latest Pro, Low |
|
|
50
50
|
| `3.5 flash` | pinned version, default tier |
|
|
51
51
|
| `3.1 pro` | pinned Pro version (→ High) |
|
|
52
|
-
| `sonnet` | Claude Sonnet
|
|
53
|
-
| `opus` | Claude Opus
|
|
54
|
-
| `gpt-oss` | GPT-OSS 120B (Medium) |
|
|
52
|
+
| `sonnet` | Claude Sonnet 5.5, default tier (Medium) |
|
|
53
|
+
| `opus` | Claude Opus 5.5, default tier (Medium) |
|
|
55
54
|
| `Gemini 3.5 Flash (Medium)` | exact passthrough |
|
|
56
55
|
|
|
57
56
|
- **Latest** = highest version number available for the family.
|
|
58
57
|
- **Default tier**: Flash → Medium, Pro → High. Overridable per-config (below).
|
|
59
58
|
- When a tier is unavailable for a family, the nearest is chosen with ties broken toward the higher tier (so "latest and greatest" wins).
|
|
60
|
-
- The non-Gemini aliases (`sonnet`, `opus
|
|
59
|
+
- The non-Gemini aliases (`sonnet`, `opus`) are a static overlay (the full low/medium/high tier spread) 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. A bare base id (`claude-sonnet-5-5`) resolves to the nearest tier variant; the retired `gpt-oss` family resolves to nothing.
|
|
61
60
|
|
|
62
61
|
## Execution modes (`mode`)
|
|
63
62
|
|
package/extensions/index.ts
CHANGED
|
@@ -112,13 +112,15 @@ type Mode = "plan" | "accept-edits";
|
|
|
112
112
|
// whose full string equals the overlay target, the live entry wins. When it
|
|
113
113
|
// does not (older agy, missing model, plan gate), the overlay entry resolves
|
|
114
114
|
// the alias so the user can still type "sonnet" and get a working answer.
|
|
115
|
-
// "sonnet" -> claude-sonnet-
|
|
116
|
-
// "opus" -> claude-opus-
|
|
117
|
-
// "gpt-oss" -> gpt-oss-120b-medium
|
|
115
|
+
// "sonnet" -> claude-sonnet-5-5 (tiered low/medium/high like Gemini)
|
|
116
|
+
// "opus" -> claude-opus-5-5 (tiered low/medium/high like Gemini)
|
|
118
117
|
const STATIC_ALIAS_OVERLAY: ReadonlyArray<ModelEntry> = [
|
|
119
|
-
{ full: "claude-sonnet-
|
|
120
|
-
{ full: "claude-
|
|
121
|
-
{ full: "
|
|
118
|
+
{ full: "claude-sonnet-5-5-low", family: "other", version: null, tier: "low" },
|
|
119
|
+
{ full: "claude-sonnet-5-5-medium", family: "other", version: null, tier: "medium" },
|
|
120
|
+
{ full: "claude-sonnet-5-5-high", family: "other", version: null, tier: "high" },
|
|
121
|
+
{ full: "claude-opus-5-5-low", family: "other", version: null, tier: "low" },
|
|
122
|
+
{ full: "claude-opus-5-5-medium", family: "other", version: null, tier: "medium" },
|
|
123
|
+
{ full: "claude-opus-5-5-high", family: "other", version: null, tier: "high" },
|
|
122
124
|
];
|
|
123
125
|
|
|
124
126
|
// Short alias → overlay full string. Used by resolveModel to recognize
|
|
@@ -126,11 +128,21 @@ const STATIC_ALIAS_OVERLAY: ReadonlyArray<ModelEntry> = [
|
|
|
126
128
|
// not match. The overlay entries are also merged into the live catalog for
|
|
127
129
|
// exact-string passthrough, so this map only needs to cover the short names.
|
|
128
130
|
const STATIC_SHORT_ALIAS: ReadonlyMap<string, string> = new Map([
|
|
129
|
-
["sonnet", "claude-sonnet-
|
|
130
|
-
["opus", "claude-opus-
|
|
131
|
-
["gpt-oss", "gpt-oss-120b-medium"],
|
|
131
|
+
["sonnet", "claude-sonnet-5-5"],
|
|
132
|
+
["opus", "claude-opus-5-5"],
|
|
132
133
|
]);
|
|
133
134
|
|
|
135
|
+
/** Families dropped outright even while `agy models` still lists them: the
|
|
136
|
+
* fixed-thinking single slug loses to the cheaper effort-tiered options and
|
|
137
|
+
* its removal upstream is already announced, so we stop offering it now. */
|
|
138
|
+
const HIDDEN_FAMILY_RE = /^gpt-oss-/;
|
|
139
|
+
|
|
140
|
+
/** Drop families we refuse to offer. Exported pure so tests exercise the
|
|
141
|
+
* same filter the live parse runs; discoverModels applies it per load. */
|
|
142
|
+
export function filterHiddenModels(entries: ModelEntry[]): ModelEntry[] {
|
|
143
|
+
return entries.filter((e) => !HIDDEN_FAMILY_RE.test(e.full));
|
|
144
|
+
}
|
|
145
|
+
|
|
134
146
|
/** Merge the live catalog with the static alias overlay. Live entries win on
|
|
135
147
|
* case-insensitive full-string equality so an updated `agy models` listing
|
|
136
148
|
* always takes precedence over the hardcoded fallback. */
|
|
@@ -466,19 +478,47 @@ function nearestTier(available: ThinkingTier[], preferred: ThinkingTier): Thinki
|
|
|
466
478
|
return sorted[0] ?? preferred;
|
|
467
479
|
}
|
|
468
480
|
|
|
469
|
-
/** Build the argv-facing resolution from a picked catalog entry. Gemini
|
|
470
|
-
* (slugs starting "gemini-") accept a separate
|
|
471
|
-
* suffix out of the slug: the base alone
|
|
472
|
-
* wants, and the tier goes to --effort
|
|
473
|
-
*
|
|
474
|
-
* agy
|
|
481
|
+
/** Build the argv-facing resolution from a picked catalog entry. Gemini and
|
|
482
|
+
* Claude bases (slugs starting "gemini-"/"claude-") accept a separate
|
|
483
|
+
* --effort, so split the tier suffix out of the slug: the base alone
|
|
484
|
+
* (claude-sonnet-5-5) is what --model wants, and the tier goes to --effort
|
|
485
|
+
* (agy rejects a bare base: "requires --effort"). Only unverified families
|
|
486
|
+
* keep agy's exact slug whole, so an unknown suffix can never trigger an
|
|
487
|
+
* unsupported --effort. */
|
|
475
488
|
function toResolved(full: string, tier: ThinkingTier | null): ResolvedModel {
|
|
476
|
-
if (tier && full.toLowerCase()
|
|
489
|
+
if (tier && /^(gemini|claude)-/.test(full.toLowerCase())) {
|
|
477
490
|
return { model: full.replace(/-(low|medium|high)$/, ""), effort: tier };
|
|
478
491
|
}
|
|
479
492
|
return { model: full };
|
|
480
493
|
}
|
|
481
494
|
|
|
495
|
+
/** Resolve a tiered base id - a short-alias target ("claude-sonnet-5-5") or a
|
|
496
|
+
* bare base slug the provider itself advertises - to the catalog variant
|
|
497
|
+
* nearest the requested tier. A bare base alone is invalid upstream
|
|
498
|
+
* ("requires --effort"), so the pick always rides the split in toResolved;
|
|
499
|
+
* with no variants in the catalog, the overlay/exact entry or the raw base
|
|
500
|
+
* passes through unchanged. */
|
|
501
|
+
function resolveTieredBase(
|
|
502
|
+
base: string,
|
|
503
|
+
entries: ModelEntry[],
|
|
504
|
+
defaultThinking: ThinkingTier,
|
|
505
|
+
preferredTier: ThinkingTier | undefined,
|
|
506
|
+
): ResolvedModel {
|
|
507
|
+
const needle = base.toLowerCase();
|
|
508
|
+
const variants = entries.filter((e) => e.full.toLowerCase().startsWith(`${needle}-`));
|
|
509
|
+
if (variants.length > 0) {
|
|
510
|
+
const tiers = variants.map((e) => e.tier).filter((t): t is ThinkingTier => t !== null);
|
|
511
|
+
const preferred =
|
|
512
|
+
preferredTier ??
|
|
513
|
+
(tiers.includes(defaultThinking) ? defaultThinking : FAMILY_DEFAULT_TIER.other);
|
|
514
|
+
const chosen = nearestTier(tiers, preferred);
|
|
515
|
+
const picked = variants.find((e) => e.tier === chosen) ?? variants[0];
|
|
516
|
+
return toResolved(picked.full, picked.tier);
|
|
517
|
+
}
|
|
518
|
+
const fromCatalog = entries.find((e) => e.full.toLowerCase() === needle);
|
|
519
|
+
return toResolved(fromCatalog?.full ?? base, fromCatalog?.tier ?? null);
|
|
520
|
+
}
|
|
521
|
+
|
|
482
522
|
/**
|
|
483
523
|
* Resolve a friendly alias / partial name to an argv-facing {model, effort?}.
|
|
484
524
|
* Returns null only when the family is unrecognized; the caller then passes
|
|
@@ -499,7 +539,7 @@ export function resolveModel(
|
|
|
499
539
|
const exact = entries.find((e) => e.full.toLowerCase() === lower);
|
|
500
540
|
if (exact) return toResolved(exact.full, exact.tier);
|
|
501
541
|
|
|
502
|
-
// 1b. Static short alias ("sonnet" / "opus"
|
|
542
|
+
// 1b. Static short alias ("sonnet" / "opus"). Checked
|
|
503
543
|
// before the family parser because none of these names contain
|
|
504
544
|
// "flash" or "pro" and would otherwise return null below. The
|
|
505
545
|
// resolved full string is then re-validated against the catalog
|
|
@@ -509,9 +549,12 @@ export function resolveModel(
|
|
|
509
549
|
// so the "live entries win" guarantee holds even when agy lists
|
|
510
550
|
// the model under different casing than the overlay.
|
|
511
551
|
if (STATIC_SHORT_ALIAS.has(lower)) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
552
|
+
return resolveTieredBase(
|
|
553
|
+
STATIC_SHORT_ALIAS.get(lower) as string,
|
|
554
|
+
entries,
|
|
555
|
+
defaultThinking,
|
|
556
|
+
preferredTier,
|
|
557
|
+
);
|
|
515
558
|
}
|
|
516
559
|
|
|
517
560
|
// 2. Parse the alias.
|
|
@@ -529,7 +572,19 @@ export function resolveModel(
|
|
|
529
572
|
if (!family && (/gemini/.test(lower) || lower === "" || lower === "default")) {
|
|
530
573
|
family = "flash";
|
|
531
574
|
}
|
|
532
|
-
if (!family)
|
|
575
|
+
if (!family) {
|
|
576
|
+
// A bare base slug the provider itself advertises ("claude-sonnet-5-5",
|
|
577
|
+
// the id behind the antigravity/ entry in pi's picker) is invalid
|
|
578
|
+
// upstream without an effort: resolve it to the nearest tier variant
|
|
579
|
+
// exactly like the short aliases.
|
|
580
|
+
if (
|
|
581
|
+
entries.some((e) => e.full.toLowerCase().startsWith(`${lower}-`)) ||
|
|
582
|
+
entries.some((e) => e.full.toLowerCase() === lower)
|
|
583
|
+
) {
|
|
584
|
+
return resolveTieredBase(lower, entries, defaultThinking, preferredTier);
|
|
585
|
+
}
|
|
586
|
+
return null; // unknown family -> let agy handle it
|
|
587
|
+
}
|
|
533
588
|
|
|
534
589
|
// 3. Filter by family.
|
|
535
590
|
let candidates = entries.filter((e) => e.family === family);
|
|
@@ -670,10 +725,9 @@ async function discoverModels(binary: string): Promise<ModelEntry[]> {
|
|
|
670
725
|
finish("");
|
|
671
726
|
}, DISCOVERY_TIMEOUT_MS);
|
|
672
727
|
});
|
|
673
|
-
return
|
|
674
|
-
.split("\n")
|
|
675
|
-
|
|
676
|
-
.filter((e): e is ModelEntry => e !== null);
|
|
728
|
+
return filterHiddenModels(
|
|
729
|
+
text.split("\n").map(parseModelLine).filter((e): e is ModelEntry => e !== null),
|
|
730
|
+
);
|
|
677
731
|
} catch {
|
|
678
732
|
return [];
|
|
679
733
|
}
|
|
@@ -933,7 +987,7 @@ export default async function (pi: ExtensionAPI) {
|
|
|
933
987
|
// Discovered once at load; frozen for the session. Run /reload after an
|
|
934
988
|
// `agy update` to refresh. Failure is non-fatal: resolveModel falls back
|
|
935
989
|
// to passthrough so exact slugs typed by the user still work. The static
|
|
936
|
-
// alias overlay (sonnet / opus
|
|
990
|
+
// alias overlay (sonnet / opus) is merged on top so those
|
|
937
991
|
// aliases resolve even when agy doesn't surface them in the live catalog.
|
|
938
992
|
const discovered = mergeCatalog(await discoverModels(binary).catch(() => []));
|
|
939
993
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estebanforge/pi-ask-antigravity",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.10",
|
|
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
]
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@earendil-works/pi-coding-agent": "
|
|
42
|
+
"@earendil-works/pi-coding-agent": "^1.0.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
45
45
|
"@earendil-works/pi-coding-agent": {
|