import { describe, expect, it } from "vitest";import { DEFAULT_MODEL_BY_PROVIDER, type ModelCapabilities } from "@t3tools/contracts"; import { applyClaudePromptEffortPrefix, getDefaultContextWindow, getDefaultEffort, hasContextWindowOption, hasEffortLevel, isClaudeUltrathinkPrompt, normalizeClaudeModelOptionsWithCapabilities, normalizeCodexModelOptionsWithCapabilities, normalizeModelSlug, resolveApiModelId, resolveContextWindow, resolveEffort, resolveModelSlug, resolveModelSlugForProvider, resolveSelectableModel, trimOrNull,} from "./model"; const codexCaps: ModelCapabilities = { reasoningEffortLevels: [ { value: "xhigh", label: "Extra High" }, { value: "high", label: "High", isDefault: true }, ], supportsFastMode: true, supportsThinkingToggle: false, contextWindowOptions: [], promptInjectedEffortLevels: [],}; const claudeCaps: ModelCapabilities = { reasoningEffortLevels: [ { value: "medium", label: "Medium" }, { value: "high", label: "High", isDefault: true }, { value: "ultrathink", label: "Ultrathink" }, ], supportsFastMode: false, supportsThinkingToggle: false, contextWindowOptions: [ { value: "200k", label: "200k" }, { value: "1m", label: "1M", isDefault: true }, ], promptInjectedEffortLevels: ["ultrathink"],}; describe("normalizeModelSlug", () => { it("maps known aliases to canonical slugs", () => { expect(normalizeModelSlug("gpt-5-codex")).toBe("gpt-5.4"); expect(normalizeModelSlug("5.3")).toBe("gpt-5.3-codex"); expect(normalizeModelSlug("sonnet", "claudeAgent")).toBe("claude-sonnet-4-6"); }); it("returns null for empty or missing values", () => { expect(normalizeModelSlug("")).toBeNull(); expect(normalizeModelSlug(" ")).toBeNull(); expect(normalizeModelSlug(null)).toBeNull(); expect(normalizeModelSlug(undefined)).toBeNull(); });}); describe("resolveModelSlug", () => { it("returns defaults when the model is missing", () => { expect(resolveModelSlug(undefined, "codex")).toBe(DEFAULT_MODEL_BY_PROVIDER.codex); expect(resolveModelSlugForProvider("claudeAgent", undefined)).toBe( DEFAULT_MODEL_BY_PROVIDER.claudeAgent, ); }); it("preserves normalized unknown models", () => { expect(resolveModelSlug("custom/internal-model", "codex")).toBe("custom/internal-model"); });}); describe("resolveSelectableModel", () => { it("resolves exact slugs, labels, and aliases", () => { const options = [ { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex" }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, ]; expect(resolveSelectableModel("codex", "gpt-5.3-codex", options)).toBe("gpt-5.3-codex"); expect(resolveSelectableModel("codex", "gpt-5.3 codex", options)).toBe("gpt-5.3-codex"); expect(resolveSelectableModel("claudeAgent", "sonnet", options)).toBe("claude-sonnet-4-6"); });}); describe("capability helpers", () => { it("reads default efforts", () => { expect(getDefaultEffort(codexCaps)).toBe("high"); expect(getDefaultEffort(claudeCaps)).toBe("high"); }); it("checks effort support", () => { expect(hasEffortLevel(codexCaps, "xhigh")).toBe(true); expect(hasEffortLevel(codexCaps, "max")).toBe(false); });}); describe("resolveEffort", () => { it("returns the explicit value when supported and not prompt-injected", () => { expect(resolveEffort(codexCaps, "xhigh")).toBe("xhigh"); expect(resolveEffort(codexCaps, "high")).toBe("high"); expect(resolveEffort(claudeCaps, "medium")).toBe("medium"); }); it("falls back to default when value is unsupported", () => { expect(resolveEffort(codexCaps, "bogus")).toBe("high"); expect(resolveEffort(claudeCaps, "bogus")).toBe("high"); }); it("returns the default when no value is provided", () => { expect(resolveEffort(codexCaps, undefined)).toBe("high"); expect(resolveEffort(codexCaps, null)).toBe("high"); expect(resolveEffort(codexCaps, "")).toBe("high"); expect(resolveEffort(codexCaps, " ")).toBe("high"); }); it("excludes prompt-injected efforts and falls back to default", () => { expect(resolveEffort(claudeCaps, "ultrathink")).toBe("high"); }); it("returns undefined for models with no effort levels", () => { const noCaps: ModelCapabilities = { reasoningEffortLevels: [], supportsFastMode: false, supportsThinkingToggle: false, contextWindowOptions: [], promptInjectedEffortLevels: [], }; expect(resolveEffort(noCaps, undefined)).toBeUndefined(); expect(resolveEffort(noCaps, "high")).toBeUndefined(); });}); describe("misc helpers", () => { it("detects ultrathink prompts", () => { expect(isClaudeUltrathinkPrompt("Ultrathink:\nInvestigate")).toBe(true); expect(isClaudeUltrathinkPrompt("Investigate")).toBe(false); }); it("prefixes ultrathink prompts once", () => { expect(applyClaudePromptEffortPrefix("Investigate", "ultrathink")).toBe( "Ultrathink:\nInvestigate", ); expect(applyClaudePromptEffortPrefix("Ultrathink:\nInvestigate", "ultrathink")).toBe( "Ultrathink:\nInvestigate", ); }); it("trims strings to null", () => { expect(trimOrNull(" hi ")).toBe("hi"); expect(trimOrNull(" ")).toBeNull(); });}); describe("context window helpers", () => { it("reads default context window", () => { expect(getDefaultContextWindow(claudeCaps)).toBe("1m"); }); it("returns null for models without context window options", () => { expect(getDefaultContextWindow(codexCaps)).toBeNull(); }); it("checks context window support", () => { expect(hasContextWindowOption(claudeCaps, "1m")).toBe(true); expect(hasContextWindowOption(claudeCaps, "200k")).toBe(true); expect(hasContextWindowOption(claudeCaps, "bogus")).toBe(false); expect(hasContextWindowOption(codexCaps, "1m")).toBe(false); });}); describe("resolveContextWindow", () => { it("returns the explicit value when supported", () => { expect(resolveContextWindow(claudeCaps, "200k")).toBe("200k"); expect(resolveContextWindow(claudeCaps, "1m")).toBe("1m"); }); it("falls back to default when value is unsupported", () => { expect(resolveContextWindow(claudeCaps, "bogus")).toBe("1m"); }); it("returns the default when no value is provided", () => { expect(resolveContextWindow(claudeCaps, undefined)).toBe("1m"); expect(resolveContextWindow(claudeCaps, null)).toBe("1m"); expect(resolveContextWindow(claudeCaps, "")).toBe("1m"); }); it("returns undefined for models with no context window options", () => { expect(resolveContextWindow(codexCaps, undefined)).toBeUndefined(); expect(resolveContextWindow(codexCaps, "1m")).toBeUndefined(); });}); describe("resolveApiModelId", () => { it("appends [1m] suffix for 1m context window", () => { expect( resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6", options: { contextWindow: "1m" }, }), ).toBe("claude-opus-4-6[1m]"); }); it("returns the model as-is for 200k context window", () => { expect( resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6", options: { contextWindow: "200k" }, }), ).toBe("claude-opus-4-6"); }); it("returns the model as-is when no context window is set", () => { expect(resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6" })).toBe( "claude-opus-4-6", ); expect( resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6", options: {} }), ).toBe("claude-opus-4-6"); }); it("returns the model as-is for Codex selections", () => { expect(resolveApiModelId({ provider: "codex", model: "gpt-5.4" })).toBe("gpt-5.4"); });}); describe("normalize*ModelOptionsWithCapabilities", () => { it("preserves explicit false codex fast mode", () => { expect( normalizeCodexModelOptionsWithCapabilities(codexCaps, { reasoningEffort: "high", fastMode: false, }), ).toEqual({ reasoningEffort: "high", fastMode: false, }); }); it("preserves the default Claude context window explicitly", () => { expect( normalizeClaudeModelOptionsWithCapabilities( { ...claudeCaps, contextWindowOptions: [ { value: "200k", label: "200k", isDefault: true }, { value: "1m", label: "1M" }, ], }, { effort: "high", contextWindow: "200k", }, ), ).toEqual({ effort: "high", contextWindow: "200k", }); }); it("omits unsupported Claude context window options", () => { expect( normalizeClaudeModelOptionsWithCapabilities( { ...claudeCaps, reasoningEffortLevels: [], supportsThinkingToggle: true, contextWindowOptions: [], }, { thinking: true, contextWindow: "1m", }, ), ).toEqual({ thinking: true, }); });});
import { describe, expect, it } from "vitest";
import { DEFAULT_MODEL_BY_PROVIDER, type ModelCapabilities } from "@t3tools/contracts";
import {
applyClaudePromptEffortPrefix,
getDefaultContextWindow,
getDefaultEffort,
hasContextWindowOption,
hasEffortLevel,
isClaudeUltrathinkPrompt,
normalizeClaudeModelOptionsWithCapabilities,
normalizeCodexModelOptionsWithCapabilities,
normalizeModelSlug,
resolveApiModelId,
resolveContextWindow,
resolveEffort,
resolveModelSlug,
resolveModelSlugForProvider,
resolveSelectableModel,
trimOrNull,
} from "./model";
const codexCaps: ModelCapabilities = {
reasoningEffortLevels: [
{ value: "xhigh", label: "Extra High" },
{ value: "high", label: "High", isDefault: true },
],
supportsFastMode: true,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
};
const claudeCaps: ModelCapabilities = {
reasoningEffortLevels: [
{ value: "medium", label: "Medium" },
{ value: "high", label: "High", isDefault: true },
{ value: "ultrathink", label: "Ultrathink" },
],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [
{ value: "200k", label: "200k" },
{ value: "1m", label: "1M", isDefault: true },
],
promptInjectedEffortLevels: ["ultrathink"],
};
describe("normalizeModelSlug", () => {
it("maps known aliases to canonical slugs", () => {
expect(normalizeModelSlug("gpt-5-codex")).toBe("gpt-5.4");
expect(normalizeModelSlug("5.3")).toBe("gpt-5.3-codex");
expect(normalizeModelSlug("sonnet", "claudeAgent")).toBe("claude-sonnet-4-6");
});
it("returns null for empty or missing values", () => {
expect(normalizeModelSlug("")).toBeNull();
expect(normalizeModelSlug(" ")).toBeNull();
expect(normalizeModelSlug(null)).toBeNull();
expect(normalizeModelSlug(undefined)).toBeNull();
});
});
describe("resolveModelSlug", () => {
it("returns defaults when the model is missing", () => {
expect(resolveModelSlug(undefined, "codex")).toBe(DEFAULT_MODEL_BY_PROVIDER.codex);
expect(resolveModelSlugForProvider("claudeAgent", undefined)).toBe(
DEFAULT_MODEL_BY_PROVIDER.claudeAgent,
);
});
it("preserves normalized unknown models", () => {
expect(resolveModelSlug("custom/internal-model", "codex")).toBe("custom/internal-model");
});
});
describe("resolveSelectableModel", () => {
it("resolves exact slugs, labels, and aliases", () => {
const options = [
{ slug: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
{ slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
];
expect(resolveSelectableModel("codex", "gpt-5.3-codex", options)).toBe("gpt-5.3-codex");
expect(resolveSelectableModel("codex", "gpt-5.3 codex", options)).toBe("gpt-5.3-codex");
expect(resolveSelectableModel("claudeAgent", "sonnet", options)).toBe("claude-sonnet-4-6");
});
});
describe("capability helpers", () => {
it("reads default efforts", () => {
expect(getDefaultEffort(codexCaps)).toBe("high");
expect(getDefaultEffort(claudeCaps)).toBe("high");
});
it("checks effort support", () => {
expect(hasEffortLevel(codexCaps, "xhigh")).toBe(true);
expect(hasEffortLevel(codexCaps, "max")).toBe(false);
});
});
describe("resolveEffort", () => {
it("returns the explicit value when supported and not prompt-injected", () => {
expect(resolveEffort(codexCaps, "xhigh")).toBe("xhigh");
expect(resolveEffort(codexCaps, "high")).toBe("high");
expect(resolveEffort(claudeCaps, "medium")).toBe("medium");
});
it("falls back to default when value is unsupported", () => {
expect(resolveEffort(codexCaps, "bogus")).toBe("high");
expect(resolveEffort(claudeCaps, "bogus")).toBe("high");
});
it("returns the default when no value is provided", () => {
expect(resolveEffort(codexCaps, undefined)).toBe("high");
expect(resolveEffort(codexCaps, null)).toBe("high");
expect(resolveEffort(codexCaps, "")).toBe("high");
expect(resolveEffort(codexCaps, " ")).toBe("high");
});
it("excludes prompt-injected efforts and falls back to default", () => {
expect(resolveEffort(claudeCaps, "ultrathink")).toBe("high");
});
it("returns undefined for models with no effort levels", () => {
const noCaps: ModelCapabilities = {
reasoningEffortLevels: [],
supportsFastMode: false,
supportsThinkingToggle: false,
contextWindowOptions: [],
promptInjectedEffortLevels: [],
};
expect(resolveEffort(noCaps, undefined)).toBeUndefined();
expect(resolveEffort(noCaps, "high")).toBeUndefined();
});
});
describe("misc helpers", () => {
it("detects ultrathink prompts", () => {
expect(isClaudeUltrathinkPrompt("Ultrathink:\nInvestigate")).toBe(true);
expect(isClaudeUltrathinkPrompt("Investigate")).toBe(false);
});
it("prefixes ultrathink prompts once", () => {
expect(applyClaudePromptEffortPrefix("Investigate", "ultrathink")).toBe(
"Ultrathink:\nInvestigate",
);
expect(applyClaudePromptEffortPrefix("Ultrathink:\nInvestigate", "ultrathink")).toBe(
"Ultrathink:\nInvestigate",
);
});
it("trims strings to null", () => {
expect(trimOrNull(" hi ")).toBe("hi");
expect(trimOrNull(" ")).toBeNull();
});
});
describe("context window helpers", () => {
it("reads default context window", () => {
expect(getDefaultContextWindow(claudeCaps)).toBe("1m");
});
it("returns null for models without context window options", () => {
expect(getDefaultContextWindow(codexCaps)).toBeNull();
});
it("checks context window support", () => {
expect(hasContextWindowOption(claudeCaps, "1m")).toBe(true);
expect(hasContextWindowOption(claudeCaps, "200k")).toBe(true);
expect(hasContextWindowOption(claudeCaps, "bogus")).toBe(false);
expect(hasContextWindowOption(codexCaps, "1m")).toBe(false);
});
});
describe("resolveContextWindow", () => {
it("returns the explicit value when supported", () => {
expect(resolveContextWindow(claudeCaps, "200k")).toBe("200k");
expect(resolveContextWindow(claudeCaps, "1m")).toBe("1m");
});
it("falls back to default when value is unsupported", () => {
expect(resolveContextWindow(claudeCaps, "bogus")).toBe("1m");
});
it("returns the default when no value is provided", () => {
expect(resolveContextWindow(claudeCaps, undefined)).toBe("1m");
expect(resolveContextWindow(claudeCaps, null)).toBe("1m");
expect(resolveContextWindow(claudeCaps, "")).toBe("1m");
});
it("returns undefined for models with no context window options", () => {
expect(resolveContextWindow(codexCaps, undefined)).toBeUndefined();
expect(resolveContextWindow(codexCaps, "1m")).toBeUndefined();
});
});
describe("resolveApiModelId", () => {
it("appends [1m] suffix for 1m context window", () => {
expect(
resolveApiModelId({
provider: "claudeAgent",
model: "claude-opus-4-6",
options: { contextWindow: "1m" },
}),
).toBe("claude-opus-4-6[1m]");
});
it("returns the model as-is for 200k context window", () => {
expect(
resolveApiModelId({
provider: "claudeAgent",
model: "claude-opus-4-6",
options: { contextWindow: "200k" },
}),
).toBe("claude-opus-4-6");
});
it("returns the model as-is when no context window is set", () => {
expect(resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6" })).toBe(
"claude-opus-4-6",
);
expect(
resolveApiModelId({ provider: "claudeAgent", model: "claude-opus-4-6", options: {} }),
).toBe("claude-opus-4-6");
});
it("returns the model as-is for Codex selections", () => {
expect(resolveApiModelId({ provider: "codex", model: "gpt-5.4" })).toBe("gpt-5.4");
});
});
describe("normalize*ModelOptionsWithCapabilities", () => {
it("preserves explicit false codex fast mode", () => {
expect(
normalizeCodexModelOptionsWithCapabilities(codexCaps, {
reasoningEffort: "high",
fastMode: false,
}),
).toEqual({
reasoningEffort: "high",
fastMode: false,
});
});
it("preserves the default Claude context window explicitly", () => {
expect(
normalizeClaudeModelOptionsWithCapabilities(
{
...claudeCaps,
contextWindowOptions: [
{ value: "200k", label: "200k", isDefault: true },
{ value: "1m", label: "1M" },
],
},
{
effort: "high",
contextWindow: "200k",
},
),
).toEqual({
effort: "high",
contextWindow: "200k",
});
});
it("omits unsupported Claude context window options", () => {
expect(
normalizeClaudeModelOptionsWithCapabilities(
{
...claudeCaps,
reasoningEffortLevels: [],
supportsThinkingToggle: true,
contextWindowOptions: [],
},
{
thinking: true,
contextWindow: "1m",
},
),
).toEqual({
thinking: true,
});
});
});