mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 05:45:04 +03:00
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:
committed by
GitHub
parent
4cf73428f8
commit
d83e0a4fab
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
37
tests/unit/ui/AntigravityToolCard-model-aliases.test.tsx
Normal file
37
tests/unit/ui/AntigravityToolCard-model-aliases.test.tsx
Normal 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\}/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user