import { assert, describe, it } from "@effect/vitest";import { ProviderInstanceId } from "@t3tools/contracts"; import { hasValidClaudeManifestAdapters } from "./ClaudeModelManifest.ts";import type { ModelManifestData } from "./ModelManifest.ts";import { formatClaudeVersionUpgradeMessage, normalizeClaudeCatalogEffort, resolveClaudeCatalogApiModelId, resolveClaudeCatalogEffort, resolveClaudeModelCatalog, resolveClaudeModelsForVersion, resolveClaudeModelSlug, scopeClaudeModelCatalog,} from "./ClaudeModelCatalog.ts"; /** * Test policy: adding or changing a real Claude model in model-manifest.json * must not add or update tests here. These synthetic fixtures cover resolver * behavior once. Add a test only when Claude adapter semantics change, such * as introducing a new compatibility rule or dispatch mapping type. */ const manifest = (): ModelManifestData => ({ version: 1, currentModels: {}, providers: { claudeAgent: { profiles: { synthetic: { capabilities: { optionDescriptors: [ { id: "effort", label: "Reasoning", type: "select", options: [{ id: "extreme", label: "Extreme", isDefault: true }], }, { id: "contextWindow", label: "Context Window", type: "select", options: [{ id: "large", label: "Large", isDefault: true }], }, ], }, adapter: { claudeCode: { effortMap: { extreme: "high" }, modelSuffixes: { contextWindow: { large: "[large]" } }, }, }, }, }, models: [ { slug: "claude-synthetic-next", name: "Claude Synthetic Next", aliases: ["synthetic"], status: "current", profile: "synthetic", adapter: { claudeCode: { minVersion: "3.2.0" } }, }, ], }, },}); describe("Claude model catalog", () => { it("filters models at runtime-version boundaries and derives the upgrade message", () => { const catalog = resolveClaudeModelCatalog(manifest()); assert.deepStrictEqual(resolveClaudeModelsForVersion(catalog, "3.1.9"), []); assert.deepStrictEqual( resolveClaudeModelsForVersion(catalog, "3.2.0").map((model) => model.slug), ["claude-synthetic-next"], ); assert.strictEqual( formatClaudeVersionUpgradeMessage(catalog, "3.1.9"), "Claude Code v3.1.9 is too old for Claude Synthetic Next. Upgrade to v3.2.0 or newer to access it.", ); }); it("resolves aliases and declarative adapter mappings", () => { const base = manifest(); const input: ModelManifestData = { ...base, providers: { ...base.providers, claudeAgent: { ...base.providers!.claudeAgent!, models: [ { slug: "claude-synthetic-collision", name: "Claude Synthetic Collision", aliases: ["claude-synthetic-next"], status: "current", }, ...base.providers!.claudeAgent!.models, ], }, }, }; const catalog = resolveClaudeModelCatalog(input); assert.strictEqual(resolveClaudeModelSlug(catalog, "synthetic"), "claude-synthetic-next"); assert.strictEqual( resolveClaudeModelSlug(catalog, "claude-synthetic-next"), "claude-synthetic-next", ); assert.strictEqual(normalizeClaudeCatalogEffort(catalog, "extreme", "synthetic"), "high"); assert.strictEqual( resolveClaudeCatalogApiModelId(catalog, { instanceId: ProviderInstanceId.make("claudeAgent"), model: "synthetic", }), "claude-synthetic-next[large]", ); }); it("rejects malformed adapter mappings", () => { const base = manifest(); const malformed: ModelManifestData = { ...base, providers: { ...base.providers, claudeAgent: { ...base.providers!.claudeAgent!, profiles: { ...base.providers!.claudeAgent!.profiles, synthetic: { ...base.providers!.claudeAgent!.profiles.synthetic!, adapter: { claudeCode: { effortMap: { extreme: 123 } } }, }, }, }, }, }; assert.isFalse(hasValidClaudeManifestAdapters(malformed)); }); it("appends custom models with their own descriptors and keeps bare slugs opaque", () => { const catalog = scopeClaudeModelCatalog(resolveClaudeModelCatalog(manifest()), [ "synthetic", { slug: "claude-custom-tuned", name: "Tuned", capabilities: { optionDescriptors: [ { id: "effort", label: "Reasoning", type: "select", options: [ { id: "gentle", label: "Gentle", isDefault: true }, { id: "brutal", label: "Brutal" }, ], }, ], }, }, ]); // The bare custom slug shadows the built-in alias, so it no longer resolves to it. assert.strictEqual(resolveClaudeModelSlug(catalog, "synthetic"), "synthetic"); assert.strictEqual(resolveClaudeCatalogEffort(catalog, "synthetic", "extreme"), undefined); // The entry with descriptors resolves user-defined effort ids and passes // them through untouched (no effortMap, no model suffix). assert.strictEqual( resolveClaudeCatalogEffort(catalog, "claude-custom-tuned", "brutal"), "brutal", ); assert.strictEqual( resolveClaudeCatalogEffort(catalog, "claude-custom-tuned", "bogus"), "gentle", ); assert.strictEqual( normalizeClaudeCatalogEffort(catalog, "brutal", "claude-custom-tuned"), "brutal", ); assert.strictEqual( resolveClaudeCatalogApiModelId(catalog, { instanceId: ProviderInstanceId.make("claudeAgent"), model: "claude-custom-tuned", options: [{ id: "effort", value: "brutal" }], }), "claude-custom-tuned", ); assert.deepStrictEqual( resolveClaudeModelsForVersion(catalog, "3.2.0").map((model) => model.slug), ["claude-synthetic-next", "claude-custom-tuned"], ); });});
import { assert, describe, it } from "@effect/vitest";
import { ProviderInstanceId } from "@t3tools/contracts";
import { hasValidClaudeManifestAdapters } from "./ClaudeModelManifest.ts";
import type { ModelManifestData } from "./ModelManifest.ts";
import {
formatClaudeVersionUpgradeMessage,
normalizeClaudeCatalogEffort,
resolveClaudeCatalogApiModelId,
resolveClaudeCatalogEffort,
resolveClaudeModelCatalog,
resolveClaudeModelsForVersion,
resolveClaudeModelSlug,
scopeClaudeModelCatalog,
} from "./ClaudeModelCatalog.ts";
/**
* Test policy: adding or changing a real Claude model in model-manifest.json
* must not add or update tests here. These synthetic fixtures cover resolver
* behavior once. Add a test only when Claude adapter semantics change, such
* as introducing a new compatibility rule or dispatch mapping type.
*/
const manifest = (): ModelManifestData => ({
version: 1,
currentModels: {},
providers: {
claudeAgent: {
profiles: {
synthetic: {
capabilities: {
optionDescriptors: [
{
id: "effort",
label: "Reasoning",
type: "select",
options: [{ id: "extreme", label: "Extreme", isDefault: true }],
},
{
id: "contextWindow",
label: "Context Window",
type: "select",
options: [{ id: "large", label: "Large", isDefault: true }],
},
],
},
adapter: {
claudeCode: {
effortMap: { extreme: "high" },
modelSuffixes: { contextWindow: { large: "[large]" } },
},
},
},
},
models: [
{
slug: "claude-synthetic-next",
name: "Claude Synthetic Next",
aliases: ["synthetic"],
status: "current",
profile: "synthetic",
adapter: { claudeCode: { minVersion: "3.2.0" } },
},
],
},
},
});
describe("Claude model catalog", () => {
it("filters models at runtime-version boundaries and derives the upgrade message", () => {
const catalog = resolveClaudeModelCatalog(manifest());
assert.deepStrictEqual(resolveClaudeModelsForVersion(catalog, "3.1.9"), []);
assert.deepStrictEqual(
resolveClaudeModelsForVersion(catalog, "3.2.0").map((model) => model.slug),
["claude-synthetic-next"],
);
assert.strictEqual(
formatClaudeVersionUpgradeMessage(catalog, "3.1.9"),
"Claude Code v3.1.9 is too old for Claude Synthetic Next. Upgrade to v3.2.0 or newer to access it.",
);
});
it("resolves aliases and declarative adapter mappings", () => {
const base = manifest();
const input: ModelManifestData = {
...base,
providers: {
...base.providers,
claudeAgent: {
...base.providers!.claudeAgent!,
models: [
{
slug: "claude-synthetic-collision",
name: "Claude Synthetic Collision",
aliases: ["claude-synthetic-next"],
status: "current",
},
...base.providers!.claudeAgent!.models,
],
},
},
};
const catalog = resolveClaudeModelCatalog(input);
assert.strictEqual(resolveClaudeModelSlug(catalog, "synthetic"), "claude-synthetic-next");
assert.strictEqual(
resolveClaudeModelSlug(catalog, "claude-synthetic-next"),
"claude-synthetic-next",
);
assert.strictEqual(normalizeClaudeCatalogEffort(catalog, "extreme", "synthetic"), "high");
assert.strictEqual(
resolveClaudeCatalogApiModelId(catalog, {
instanceId: ProviderInstanceId.make("claudeAgent"),
model: "synthetic",
}),
"claude-synthetic-next[large]",
);
});
it("rejects malformed adapter mappings", () => {
const base = manifest();
const malformed: ModelManifestData = {
...base,
providers: {
...base.providers,
claudeAgent: {
...base.providers!.claudeAgent!,
profiles: {
...base.providers!.claudeAgent!.profiles,
synthetic: {
...base.providers!.claudeAgent!.profiles.synthetic!,
adapter: { claudeCode: { effortMap: { extreme: 123 } } },
},
},
},
},
};
assert.isFalse(hasValidClaudeManifestAdapters(malformed));
});
it("appends custom models with their own descriptors and keeps bare slugs opaque", () => {
const catalog = scopeClaudeModelCatalog(resolveClaudeModelCatalog(manifest()), [
"synthetic",
{
slug: "claude-custom-tuned",
name: "Tuned",
capabilities: {
optionDescriptors: [
{
id: "effort",
label: "Reasoning",
type: "select",
options: [
{ id: "gentle", label: "Gentle", isDefault: true },
{ id: "brutal", label: "Brutal" },
],
},
],
},
},
]);
// The bare custom slug shadows the built-in alias, so it no longer resolves to it.
assert.strictEqual(resolveClaudeModelSlug(catalog, "synthetic"), "synthetic");
assert.strictEqual(resolveClaudeCatalogEffort(catalog, "synthetic", "extreme"), undefined);
// The entry with descriptors resolves user-defined effort ids and passes
// them through untouched (no effortMap, no model suffix).
assert.strictEqual(
resolveClaudeCatalogEffort(catalog, "claude-custom-tuned", "brutal"),
"brutal",
);
assert.strictEqual(
resolveClaudeCatalogEffort(catalog, "claude-custom-tuned", "bogus"),
"gentle",
);
assert.strictEqual(
normalizeClaudeCatalogEffort(catalog, "brutal", "claude-custom-tuned"),
"brutal",
);
assert.strictEqual(
resolveClaudeCatalogApiModelId(catalog, {
instanceId: ProviderInstanceId.make("claudeAgent"),
model: "claude-custom-tuned",
options: [{ id: "effort", value: "brutal" }],
}),
"claude-custom-tuned",
);
assert.deepStrictEqual(
resolveClaudeModelsForVersion(catalog, "3.2.0").map((model) => model.slug),
["claude-synthetic-next", "claude-custom-tuned"],
);
});
});