mirror of https://github.com/openclaw/openclaw.git
test: simplify model ref normalization coverage
This commit is contained in:
parent
2d32cf2839
commit
f5b006f6a1
|
|
@ -80,131 +80,121 @@ describe("model-selection", () => {
|
|||
});
|
||||
|
||||
describe("parseModelRef", () => {
|
||||
it("should parse full model refs", () => {
|
||||
expect(parseModelRef("anthropic/claude-3-5-sonnet", "openai")).toEqual({
|
||||
provider: "anthropic",
|
||||
model: "claude-3-5-sonnet",
|
||||
});
|
||||
const expectParsedModelVariants = (
|
||||
variants: string[],
|
||||
defaultProvider: string,
|
||||
expected: { provider: string; model: string },
|
||||
) => {
|
||||
for (const raw of variants) {
|
||||
expect(parseModelRef(raw, defaultProvider), raw).toEqual(expected);
|
||||
}
|
||||
};
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "parses explicit provider/model refs",
|
||||
variants: ["anthropic/claude-3-5-sonnet"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "anthropic", model: "claude-3-5-sonnet" },
|
||||
},
|
||||
{
|
||||
name: "uses the default provider when omitted",
|
||||
variants: ["claude-3-5-sonnet"],
|
||||
defaultProvider: "anthropic",
|
||||
expected: { provider: "anthropic", model: "claude-3-5-sonnet" },
|
||||
},
|
||||
{
|
||||
name: "preserves nested model ids after the provider prefix",
|
||||
variants: ["nvidia/moonshotai/kimi-k2.5"],
|
||||
defaultProvider: "anthropic",
|
||||
expected: { provider: "nvidia", model: "moonshotai/kimi-k2.5" },
|
||||
},
|
||||
{
|
||||
name: "normalizes anthropic shorthand aliases",
|
||||
variants: ["anthropic/opus-4.6", "opus-4.6", " anthropic / opus-4.6 "],
|
||||
defaultProvider: "anthropic",
|
||||
expected: { provider: "anthropic", model: "claude-opus-4-6" },
|
||||
},
|
||||
{
|
||||
name: "normalizes anthropic sonnet aliases",
|
||||
variants: ["anthropic/sonnet-4.6", "sonnet-4.6"],
|
||||
defaultProvider: "anthropic",
|
||||
expected: { provider: "anthropic", model: "claude-sonnet-4-6" },
|
||||
},
|
||||
{
|
||||
name: "normalizes deprecated google flash preview ids",
|
||||
variants: ["google/gemini-3.1-flash-preview", "gemini-3.1-flash-preview"],
|
||||
defaultProvider: "google",
|
||||
expected: { provider: "google", model: "gemini-3-flash-preview" },
|
||||
},
|
||||
{
|
||||
name: "normalizes gemini 3.1 flash-lite ids",
|
||||
variants: ["google/gemini-3.1-flash-lite", "gemini-3.1-flash-lite"],
|
||||
defaultProvider: "google",
|
||||
expected: { provider: "google", model: "gemini-3.1-flash-lite-preview" },
|
||||
},
|
||||
{
|
||||
name: "keeps OpenAI codex refs on the openai provider",
|
||||
variants: ["openai/gpt-5.3-codex", "gpt-5.3-codex"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "openai", model: "gpt-5.3-codex" },
|
||||
},
|
||||
{
|
||||
name: "preserves openrouter native model prefixes",
|
||||
variants: ["openrouter/aurora-alpha"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "openrouter", model: "openrouter/aurora-alpha" },
|
||||
},
|
||||
{
|
||||
name: "passes through openrouter upstream provider ids",
|
||||
variants: ["openrouter/anthropic/claude-sonnet-4-5"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "openrouter", model: "anthropic/claude-sonnet-4-5" },
|
||||
},
|
||||
{
|
||||
name: "normalizes Vercel Claude shorthand to anthropic-prefixed model ids",
|
||||
variants: ["vercel-ai-gateway/claude-opus-4.6"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "vercel-ai-gateway", model: "anthropic/claude-opus-4.6" },
|
||||
},
|
||||
{
|
||||
name: "normalizes Vercel Anthropic aliases without double-prefixing",
|
||||
variants: ["vercel-ai-gateway/opus-4.6"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "vercel-ai-gateway", model: "anthropic/claude-opus-4-6" },
|
||||
},
|
||||
{
|
||||
name: "keeps already-prefixed Vercel Anthropic models unchanged",
|
||||
variants: ["vercel-ai-gateway/anthropic/claude-opus-4.6"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "vercel-ai-gateway", model: "anthropic/claude-opus-4.6" },
|
||||
},
|
||||
{
|
||||
name: "passes through non-Claude Vercel model ids unchanged",
|
||||
variants: ["vercel-ai-gateway/openai/gpt-5.2"],
|
||||
defaultProvider: "openai",
|
||||
expected: { provider: "vercel-ai-gateway", model: "openai/gpt-5.2" },
|
||||
},
|
||||
{
|
||||
name: "keeps already-suffixed codex variants unchanged",
|
||||
variants: ["openai/gpt-5.3-codex-codex"],
|
||||
defaultProvider: "anthropic",
|
||||
expected: { provider: "openai", model: "gpt-5.3-codex-codex" },
|
||||
},
|
||||
])("$name", ({ variants, defaultProvider, expected }) => {
|
||||
expectParsedModelVariants(variants, defaultProvider, expected);
|
||||
});
|
||||
|
||||
it("preserves nested model ids after provider prefix", () => {
|
||||
expect(parseModelRef("nvidia/moonshotai/kimi-k2.5", "anthropic")).toEqual({
|
||||
provider: "nvidia",
|
||||
model: "moonshotai/kimi-k2.5",
|
||||
});
|
||||
it("round-trips normalized refs through modelKey", () => {
|
||||
const parsed = parseModelRef(" opus-4.6 ", "anthropic");
|
||||
expect(parsed).toEqual({ provider: "anthropic", model: "claude-opus-4-6" });
|
||||
expect(modelKey(parsed?.provider ?? "", parsed?.model ?? "")).toBe(
|
||||
"anthropic/claude-opus-4-6",
|
||||
);
|
||||
});
|
||||
|
||||
it("normalizes anthropic alias refs to canonical model ids", () => {
|
||||
expect(parseModelRef("anthropic/opus-4.6", "openai")).toEqual({
|
||||
provider: "anthropic",
|
||||
model: "claude-opus-4-6",
|
||||
});
|
||||
expect(parseModelRef("opus-4.6", "anthropic")).toEqual({
|
||||
provider: "anthropic",
|
||||
model: "claude-opus-4-6",
|
||||
});
|
||||
expect(parseModelRef("anthropic/sonnet-4.6", "openai")).toEqual({
|
||||
provider: "anthropic",
|
||||
model: "claude-sonnet-4-6",
|
||||
});
|
||||
expect(parseModelRef("sonnet-4.6", "anthropic")).toEqual({
|
||||
provider: "anthropic",
|
||||
model: "claude-sonnet-4-6",
|
||||
});
|
||||
});
|
||||
|
||||
it("should use default provider if none specified", () => {
|
||||
expect(parseModelRef("claude-3-5-sonnet", "anthropic")).toEqual({
|
||||
provider: "anthropic",
|
||||
model: "claude-3-5-sonnet",
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes deprecated google flash preview ids to the working model id", () => {
|
||||
expect(parseModelRef("google/gemini-3.1-flash-preview", "openai")).toEqual({
|
||||
provider: "google",
|
||||
model: "gemini-3-flash-preview",
|
||||
});
|
||||
expect(parseModelRef("gemini-3.1-flash-preview", "google")).toEqual({
|
||||
provider: "google",
|
||||
model: "gemini-3-flash-preview",
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes gemini 3.1 flash-lite to the preview model id", () => {
|
||||
expect(parseModelRef("google/gemini-3.1-flash-lite", "openai")).toEqual({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-lite-preview",
|
||||
});
|
||||
expect(parseModelRef("gemini-3.1-flash-lite", "google")).toEqual({
|
||||
provider: "google",
|
||||
model: "gemini-3.1-flash-lite-preview",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps openai gpt-5.3 codex refs on the openai provider", () => {
|
||||
expect(parseModelRef("openai/gpt-5.3-codex", "anthropic")).toEqual({
|
||||
provider: "openai",
|
||||
model: "gpt-5.3-codex",
|
||||
});
|
||||
expect(parseModelRef("gpt-5.3-codex", "openai")).toEqual({
|
||||
provider: "openai",
|
||||
model: "gpt-5.3-codex",
|
||||
});
|
||||
expect(parseModelRef("openai/gpt-5.3-codex-codex", "anthropic")).toEqual({
|
||||
provider: "openai",
|
||||
model: "gpt-5.3-codex-codex",
|
||||
});
|
||||
});
|
||||
|
||||
it("should return null for empty strings", () => {
|
||||
expect(parseModelRef("", "anthropic")).toBeNull();
|
||||
expect(parseModelRef(" ", "anthropic")).toBeNull();
|
||||
});
|
||||
|
||||
it("should preserve openrouter/ prefix for native models", () => {
|
||||
expect(parseModelRef("openrouter/aurora-alpha", "openai")).toEqual({
|
||||
provider: "openrouter",
|
||||
model: "openrouter/aurora-alpha",
|
||||
});
|
||||
});
|
||||
|
||||
it("should pass through openrouter external provider models as-is", () => {
|
||||
expect(parseModelRef("openrouter/anthropic/claude-sonnet-4-5", "openai")).toEqual({
|
||||
provider: "openrouter",
|
||||
model: "anthropic/claude-sonnet-4-5",
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes Vercel Claude shorthand to anthropic-prefixed model ids", () => {
|
||||
expect(parseModelRef("vercel-ai-gateway/claude-opus-4.6", "openai")).toEqual({
|
||||
provider: "vercel-ai-gateway",
|
||||
model: "anthropic/claude-opus-4.6",
|
||||
});
|
||||
expect(parseModelRef("vercel-ai-gateway/opus-4.6", "openai")).toEqual({
|
||||
provider: "vercel-ai-gateway",
|
||||
model: "anthropic/claude-opus-4-6",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps already-prefixed Vercel Anthropic models unchanged", () => {
|
||||
expect(parseModelRef("vercel-ai-gateway/anthropic/claude-opus-4.6", "openai")).toEqual({
|
||||
provider: "vercel-ai-gateway",
|
||||
model: "anthropic/claude-opus-4.6",
|
||||
});
|
||||
});
|
||||
|
||||
it("passes through non-Claude Vercel model ids unchanged", () => {
|
||||
expect(parseModelRef("vercel-ai-gateway/openai/gpt-5.2", "openai")).toEqual({
|
||||
provider: "vercel-ai-gateway",
|
||||
model: "openai/gpt-5.2",
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle invalid slash usage", () => {
|
||||
expect(parseModelRef("/", "anthropic")).toBeNull();
|
||||
expect(parseModelRef("anthropic/", "anthropic")).toBeNull();
|
||||
expect(parseModelRef("/model", "anthropic")).toBeNull();
|
||||
it.each(["", " ", "/", "anthropic/", "/model"])("returns null for invalid ref %j", (raw) => {
|
||||
expect(parseModelRef(raw, "anthropic")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue