@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 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 4.6 (Thinking) |
53
- | `opus` | Claude Opus 4.6 (Thinking) |
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`, `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.
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
 
@@ -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-4-6
116
- // "opus" -> claude-opus-4-6-thinking
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-4-6", family: "other", version: null, tier: null },
120
- { full: "claude-opus-4-6-thinking", family: "other", version: null, tier: null },
121
- { full: "gpt-oss-120b-medium", family: "other", version: null, tier: null },
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-4-6"],
130
- ["opus", "claude-opus-4-6-thinking"],
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 bases
470
- * (slugs starting "gemini-") accept a separate --effort, so split the tier
471
- * suffix out of the slug: the base alone (gemini-3.6-flash) is what --model
472
- * wants, and the tier goes to --effort. Fixed-thinking families keep agy's
473
- * exact slug even when it carries a -medium suffix (gpt-oss-120b-medium):
474
- * agy rejects --effort for them, so the suffix stays part of the slug. */
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().startsWith("gemini-")) {
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" / "gpt-oss"). Checked
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
- const target = STATIC_SHORT_ALIAS.get(lower) as string;
513
- const fromCatalog = entries.find((e) => e.full.toLowerCase() === target.toLowerCase());
514
- return toResolved(fromCatalog?.full ?? target, fromCatalog?.tier ?? null);
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) return null; // unknown family -> let agy handle it
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 text
674
- .split("\n")
675
- .map(parseModelLine)
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 / gpt-oss) is merged on top so those
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.9",
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": {