mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 13:52:09 +03:00
The provider Playground (LlmChatCard) only added the providerId/ prefix to models without a slash, so vendor-namespaced ids (moonshotai/kimi-k2.6, nvidia/zyphra/...) were sent bare and rejected with 'Ambiguous model' when the same id exists under multiple providers. Extracted qualifyPlaygroundModel() which always prefixes with the provider unless already qualified. Bug 1 ('unhashable type: dict') is an upstream NVIDIA NIM server error, not OmniRoute. Tests: 4 cases for the qualifier.
This commit is contained in:
committed by
GitHub
parent
5f3b1e8cde
commit
5f7f74dc6a
@@ -22,6 +22,7 @@ _Development cycle in progress — entries are added as work merges into `releas
|
||||
|
||||
### 🔧 Bug Fixes
|
||||
|
||||
- **dashboard:** fix "Ambiguous model" error in the provider Playground for vendor-namespaced models — the Playground only prefixed models without a `/`, so ids like `moonshotai/kimi-k2.6` or `nvidia/zyphra/zamba2-7b-instruct` (NVIDIA NIM) were sent bare and rejected when the same id exists under multiple providers. The Playground now always qualifies the selected model with its `providerId/` prefix (without double-prefixing). ([#3050](https://github.com/diegosouzapw/OmniRoute/issues/3050))
|
||||
- **db:** stop accepting duplicate API keys for the same provider — `createProviderConnection` now dedups by the decrypted key value (not just by name), so re-adding the same key under a different/blank name updates the existing connection instead of inserting a second row. Whitespace-only differences also dedup. ([#3023](https://github.com/diegosouzapw/OmniRoute/issues/3023))
|
||||
- **dashboard:** "Import from /models" now works for no-auth providers (e.g. OpenCode Free) — the button used to silently no-op because no-auth providers have no connection row, so `handleImportModels` returned early and the models route 404'd. The route now serves the provider's model catalog when called with a no-auth provider id, and the dashboard falls back to the provider id when there is no connection. ([#3047](https://github.com/diegosouzapw/OmniRoute/issues/3047))
|
||||
- **providers:** forward Grok's paired `sso-rw` cookie for grok-web — both the executor and the connection validator now send `sso=…; sso-rw=…` (via the new `buildGrokCookieHeader` helper) when the pasted blob carries `sso-rw`, fixing the `403` _"Request rejected by anti-bot rules"_ that Grok returns for `sso` alone. The add-account hint now asks for the full cookie line. ([#3063](https://github.com/diegosouzapw/OmniRoute/issues/3063))
|
||||
|
||||
@@ -15,6 +15,25 @@ import { useProviderModels } from "../../providers/hooks/useProviderModels";
|
||||
|
||||
const ENDPOINT = "/api/v1/chat/completions";
|
||||
|
||||
/**
|
||||
* Qualify a provider-scoped playground model with its `providerId/` prefix so
|
||||
* OmniRoute can resolve it unambiguously. The previous heuristic only prefixed
|
||||
* models without a `/`, which skipped vendor-namespaced ids like
|
||||
* `moonshotai/kimi-k2.6` or `nvidia/zyphra/zamba2-7b-instruct` — those already
|
||||
* contain a slash, so they were sent bare and rejected with
|
||||
* "Ambiguous model ... Use provider/model prefix" when the same id exists under
|
||||
* several providers (#3050). Always prefix unless the id is already qualified
|
||||
* with this provider.
|
||||
*/
|
||||
export function qualifyPlaygroundModel(
|
||||
model: string | null | undefined,
|
||||
providerId: string | null | undefined
|
||||
): string {
|
||||
const m = (model ?? "").trim();
|
||||
if (!m || !providerId) return m;
|
||||
return m === providerId || m.startsWith(`${providerId}/`) ? m : `${providerId}/${m}`;
|
||||
}
|
||||
|
||||
interface Message {
|
||||
role: "user" | "assistant";
|
||||
content: string;
|
||||
@@ -125,13 +144,11 @@ export function LlmChatCard({
|
||||
|
||||
const firstModel = models[0]?.id ?? "";
|
||||
const effectiveModel = model || firstModel || initialModel || "";
|
||||
// Auto-prefix model with providerId when no provider/model prefix present, to avoid
|
||||
// OmniRoute "Ambiguous model" rejection when same alias is registered under multiple providers.
|
||||
const qualifiedModel = effectiveModel.includes("/")
|
||||
? effectiveModel
|
||||
: providerId
|
||||
? `${providerId}/${effectiveModel}`
|
||||
: effectiveModel;
|
||||
// Auto-prefix model with providerId to avoid OmniRoute "Ambiguous model"
|
||||
// rejection when the same id is registered under multiple providers. This
|
||||
// also covers vendor-namespaced ids (e.g. `moonshotai/kimi-k2.6`) that already
|
||||
// contain a slash but still need the provider prefix (#3050).
|
||||
const qualifiedModel = qualifyPlaygroundModel(effectiveModel, providerId);
|
||||
|
||||
// Autofocus textarea in embedded mode
|
||||
useEffect(() => {
|
||||
|
||||
31
tests/unit/playground-model-qualify.test.ts
Normal file
31
tests/unit/playground-model-qualify.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const { qualifyPlaygroundModel } = await import(
|
||||
"../../src/app/(dashboard)/dashboard/media-providers/components/LlmChatCard.tsx"
|
||||
);
|
||||
|
||||
// #3050 — vendor-namespaced model ids already contain a "/", so the old
|
||||
// `.includes("/")` heuristic skipped the provider prefix and the request was
|
||||
// rejected with "Ambiguous model 'moonshotai/kimi-k2.6'".
|
||||
test("qualifyPlaygroundModel prefixes a vendor-namespaced model with providerId (#3050)", () => {
|
||||
assert.equal(qualifyPlaygroundModel("moonshotai/kimi-k2.6", "nim"), "nim/moonshotai/kimi-k2.6");
|
||||
assert.equal(
|
||||
qualifyPlaygroundModel("nvidia/zyphra/zamba2-7b-instruct", "nim"),
|
||||
"nim/nvidia/zyphra/zamba2-7b-instruct"
|
||||
);
|
||||
});
|
||||
|
||||
test("qualifyPlaygroundModel prefixes a bare model", () => {
|
||||
assert.equal(qualifyPlaygroundModel("gpt-4o", "openai"), "openai/gpt-4o");
|
||||
});
|
||||
|
||||
test("qualifyPlaygroundModel does not double-prefix an already-qualified model", () => {
|
||||
assert.equal(qualifyPlaygroundModel("nim/moonshotai/kimi-k2.6", "nim"), "nim/moonshotai/kimi-k2.6");
|
||||
assert.equal(qualifyPlaygroundModel("nim", "nim"), "nim");
|
||||
});
|
||||
|
||||
test("qualifyPlaygroundModel returns the model unchanged without a providerId", () => {
|
||||
assert.equal(qualifyPlaygroundModel("moonshotai/kimi-k2.6", ""), "moonshotai/kimi-k2.6");
|
||||
assert.equal(qualifyPlaygroundModel("", "nim"), "");
|
||||
});
|
||||
Reference in New Issue
Block a user