mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 05:12:11 +03:00
fix(dashboard): resolve passthrough model aliases by providerId in ModelSelectModal (#4815)
Integrated into release/v3.8.37 — cherry-picked defining commit onto release tip; CHANGELOG re-merged; tests green.
This commit is contained in:
committed by
GitHub
parent
1608d707cc
commit
0ad8f8bfdb
@@ -3,6 +3,7 @@
|
||||
import { useState, useMemo, useEffect } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Modal from "./Modal";
|
||||
import { buildPassthroughAliasModels } from "./modelSelectModalHelpers";
|
||||
import { getModelsByProviderId, PROVIDER_ID_TO_ALIAS } from "@/shared/constants/models";
|
||||
import { getCompatibleFallbackModels } from "@/lib/providers/managedAvailableModels";
|
||||
import {
|
||||
@@ -235,14 +236,14 @@ export default function ModelSelectModal({
|
||||
const providerCustomModels = customModels[providerId] || [];
|
||||
|
||||
if (providerInfo.passthroughModels) {
|
||||
const aliasModels = Object.entries(modelAliases as Record<string, string>)
|
||||
.filter(([, fullModel]: [string, string]) => fullModel.startsWith(`${alias}/`))
|
||||
.map(([aliasName, fullModel]: [string, string]) => ({
|
||||
id: fullModel.replace(`${alias}/`, ""),
|
||||
name: aliasName,
|
||||
value: fullModel,
|
||||
source: "alias",
|
||||
}));
|
||||
// Passthrough aliases are stored prefixed by the canonical providerId
|
||||
// (e.g. "github/gpt-4"), not the public alias (e.g. "gh/"), so we must
|
||||
// filter/strip by providerId — matching the sibling custom-provider
|
||||
// branch below. (port: decolua/9router#485)
|
||||
const aliasModels = buildPassthroughAliasModels(
|
||||
modelAliases as Record<string, string>,
|
||||
providerId
|
||||
);
|
||||
|
||||
// Merge custom models for passthrough providers
|
||||
const customEntries = providerCustomModels
|
||||
|
||||
37
src/shared/components/modelSelectModalHelpers.ts
Normal file
37
src/shared/components/modelSelectModalHelpers.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
// Pure helpers extracted from ModelSelectModal so the grouping logic is
|
||||
// unit-testable (the component itself lives inside a useMemo and is not
|
||||
// directly exercisable by node:test). Keep these free of React imports.
|
||||
|
||||
export type PassthroughAliasModel = {
|
||||
id: string;
|
||||
name: string;
|
||||
value: string;
|
||||
source: "alias";
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the alias-derived model rows for a passthrough provider.
|
||||
*
|
||||
* `modelAliases` maps an alias name → the fully-qualified model string, which
|
||||
* is prefixed by the provider's *canonical id* (e.g. `github/gpt-4`), NOT by
|
||||
* its public alias (e.g. `gh`). Filtering/stripping must therefore use the
|
||||
* `providerId`, mirroring the sibling custom-provider branch. Using the alias
|
||||
* here meant aliases registered under a providerId whose alias differs (the
|
||||
* common case) never resolved.
|
||||
*
|
||||
* Inspired by upstream PR decolua/9router#485 (Anurag Saxena).
|
||||
*/
|
||||
export function buildPassthroughAliasModels(
|
||||
modelAliases: Record<string, string>,
|
||||
providerId: string
|
||||
): PassthroughAliasModel[] {
|
||||
const prefix = `${providerId}/`;
|
||||
return Object.entries(modelAliases || {})
|
||||
.filter(([, fullModel]) => typeof fullModel === "string" && fullModel.startsWith(prefix))
|
||||
.map(([aliasName, fullModel]) => ({
|
||||
id: fullModel.replace(prefix, ""),
|
||||
name: aliasName,
|
||||
value: fullModel,
|
||||
source: "alias" as const,
|
||||
}));
|
||||
}
|
||||
49
tests/unit/model-select-passthrough-alias-485.test.ts
Normal file
49
tests/unit/model-select-passthrough-alias-485.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { buildPassthroughAliasModels } from "../../src/shared/components/modelSelectModalHelpers.ts";
|
||||
|
||||
// Regression guard for port of decolua/9router#485 (Anurag Saxena).
|
||||
//
|
||||
// In ModelSelectModal, passthrough-provider model aliases are stored in
|
||||
// `modelAliases` prefixed by the provider's CANONICAL id (e.g. "github/gpt-4"),
|
||||
// while the public alias may differ (e.g. providerId "github" → alias "gh").
|
||||
// The passthrough branch previously filtered/stripped by `${alias}/`, so any
|
||||
// provider whose alias differed from its id resolved to ZERO models. The fix
|
||||
// filters by `${providerId}/`, mirroring the sibling custom-provider branch.
|
||||
|
||||
test("buildPassthroughAliasModels: resolves aliases keyed by providerId even when the public alias differs", () => {
|
||||
// providerId "github", public alias would be "gh" — aliases are stored under the id.
|
||||
const modelAliases = {
|
||||
"GPT 4o": "github/gpt-4o",
|
||||
"GPT 4o mini": "github/gpt-4o-mini",
|
||||
Sonnet: "anthropic/claude-3-5-sonnet",
|
||||
};
|
||||
|
||||
const result = buildPassthroughAliasModels(modelAliases, "github");
|
||||
|
||||
// The bug (filtering by alias "gh/") would yield [] here. The fix yields the
|
||||
// two github-prefixed entries, with the providerId prefix stripped from `id`.
|
||||
assert.deepEqual(result, [
|
||||
{ id: "gpt-4o", name: "GPT 4o", value: "github/gpt-4o", source: "alias" },
|
||||
{ id: "gpt-4o-mini", name: "GPT 4o mini", value: "github/gpt-4o-mini", source: "alias" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("buildPassthroughAliasModels: only matches the requested providerId prefix", () => {
|
||||
const modelAliases = {
|
||||
a: "openrouter/model-a",
|
||||
b: "github/model-b",
|
||||
};
|
||||
const result = buildPassthroughAliasModels(modelAliases, "openrouter");
|
||||
assert.deepEqual(result, [
|
||||
{ id: "model-a", name: "a", value: "openrouter/model-a", source: "alias" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("buildPassthroughAliasModels: tolerates empty / malformed maps", () => {
|
||||
assert.deepEqual(buildPassthroughAliasModels({}, "github"), []);
|
||||
assert.deepEqual(
|
||||
buildPassthroughAliasModels({ x: undefined as unknown as string }, "github"),
|
||||
[]
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user