fix(dashboard): show API-Key-compatible providers in Antigravity CLI Tools model picker (#4503)

Rebuilt onto release/v3.8.33 (squash-base-stale). Integrated into release/v3.8.33.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-21 14:14:16 -03:00
committed by GitHub
parent 4cf73428f8
commit d83e0a4fab
3 changed files with 54 additions and 0 deletions

View File

@@ -82,6 +82,7 @@ _In development — bullets added per PR; finalized at release._
- **fix(providers): model-aware `supportsRedactedThinking` for mixed-format providers** — the redacted-thinking capability was resolved per provider rather than per model, so a mixed-format provider (some models support redacted thinking, others don't) got the wrong answer for some models; the check is now model-aware. ([#4479](https://github.com/diegosouzapw/OmniRoute/pull/4479) — thanks @TF0rd)
- **fix(usage): parse numeric-string quota reset timestamps as Unix seconds/ms** — when a provider returned the quota reset timestamp as a numeric string (e.g. `"1700000000"`), `parseResetTime` passed it straight to `new Date(str)`, which returned `Invalid Date` and dropped the reset entirely (UI showed no reset). Numeric strings are now detected and treated as Unix timestamps with the same `< 1e12` seconds-vs-ms heuristic already applied to numeric values; ISO/parseable strings are untouched. Applied symmetrically in `codexUsageQuotas.parseResetTime`. (Inspired by upstream [decolua/9router#768](https://github.com/decolua/9router/pull/768) — thanks @DEYLNN)
- **fix(usage): clearer "auth expired" message for Kiro accounts added via Google/GitHub social-auth** — a Kiro account created through the `/api/oauth/kiro/social-exchange` flow (Google or GitHub social login) uses a token format that AWS CodeWhisperer's `GetUsageLimits` quota API frequently rejects with 401/403 even when `/messages` still works. The quota card was throwing the raw upstream error blob (`Failed to fetch Kiro usage: Kiro API error (401): {…}`); social-auth accounts now get the same friendly `Kiro quota API authentication expired. Chat may still work.` message that legacy social-auth users with a stored marker already see, while Builder-ID / IDC accounts keep the existing throw-on-failure behavior so transient upstream errors don't get silently masked. (thanks @anuragg-saxenaa)
- **fix(dashboard): Antigravity CLI Tools model picker now lists API-Key-Compatible custom providers** — the API-Key-compatible / passthrough provider groups in `ModelSelectModal` are derived from the user's `modelAliases`, but `AntigravityToolCard` was the only CLI tool card that didn't fetch `/api/models/alias` or forward the `modelAliases` prop, so a custom OpenAI-compatible provider added in OmniRoute never surfaced in the Antigravity tool's model picker — routing a custom model to Antigravity from there was impossible. The card now mirrors the pattern already used by every sibling tool card (Codex, Claude, Cline, Kilo, Droid, OpenClaw, HermesAgent). (thanks @mxskeen)
### 🔒 Security

View File

@@ -27,6 +27,10 @@ export default function AntigravityToolCard({
const [modelMappings, setModelMappings] = useState({});
const [modalOpen, setModalOpen] = useState(false);
const [currentEditingAlias, setCurrentEditingAlias] = useState(null);
// Model aliases drive the API-Key-compatible / passthrough provider groups in
// ModelSelectModal — without them, custom OpenAI/Anthropic-compatible
// providers don't surface in the picker even when active.
const [modelAliases, setModelAliases] = useState({});
// (#523) Store the key *id* (not the masked string) so the backend can
// resolve the real secret from DB before writing to config files.
@@ -40,6 +44,7 @@ export default function AntigravityToolCard({
if (isExpanded && !status) {
fetchStatus();
loadSavedMappings();
fetchModelAliases();
}
}, [isExpanded, status]);
@@ -72,6 +77,16 @@ export default function AntigravityToolCard({
}
};
const fetchModelAliases = async () => {
try {
const res = await fetch("/api/models/alias");
const data = await res.json();
if (res.ok) setModelAliases(data.aliases || {});
} catch (error) {
console.log("Error fetching model aliases:", error);
}
};
// Windows uses UAC dialog, no sudo needed
const isWindows = typeof navigator !== "undefined" && navigator.userAgent?.includes("Windows");
@@ -460,6 +475,7 @@ export default function AntigravityToolCard({
onSelect={handleModelSelect}
selectedModel={currentEditingAlias ? modelMappings[currentEditingAlias] : null}
activeProviders={activeProviders}
modelAliases={modelAliases}
title={t("selectModelForAlias", { alias: currentEditingAlias || "" })}
/>
</Card>

View File

@@ -0,0 +1,37 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
// Source-level parity check (#241): AntigravityToolCard must surface
// API-Key-compatible / custom OpenAI-compatible providers in its model picker.
// Those provider groups in <ModelSelectModal> are derived from `modelAliases`
// — without the prop, custom-keyed providers are silently hidden even when
// active. The fix mirrors the pattern already used by every sibling CLI tool
// card (Codex, Claude, Cline, Kilo, Droid, OpenClaw, HermesAgent).
const __dirname = dirname(fileURLToPath(import.meta.url));
const CARD_PATH = resolve(
__dirname,
"../../../src/app/(dashboard)/dashboard/cli-code/components/AntigravityToolCard.tsx"
);
describe("AntigravityToolCard model alias wiring", () => {
const source = readFileSync(CARD_PATH, "utf8");
it("declares modelAliases state", () => {
expect(source).toMatch(/useState\(\{\}\)/);
expect(source).toMatch(/setModelAliases/);
});
it("fetches /api/models/alias when expanded", () => {
expect(source).toContain('fetch("/api/models/alias")');
expect(source).toMatch(/fetchModelAliases\s*\(\s*\)/);
});
it("passes modelAliases prop to ModelSelectModal", () => {
// Regression guard for upstream parity: the prop is what unlocks the
// API-Key-compatible / passthrough provider groups in the picker.
expect(source).toMatch(/modelAliases=\{modelAliases\}/);
});
});