mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-10 02:15:02 +00:00
feat(claude): add Fable 5.2 and Mythos 5.2 to the model catalog (#9233)
Adds Claude Fable 5.2 and Mythos 5.2, available from Claude Code 2.1.321, and defaults both to medium effort to match Claude Code. Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com> Co-authored-by: gudcks <84506708+gudcks@users.noreply.github.com>
This commit is contained in:
co-authored by
Mohamed Boudra
gudcks
parent
ab64bebe14
commit
f9779a14a5
@@ -1614,6 +1614,8 @@ describe("ClaudeAgentSession features", () => {
|
||||
test.each([
|
||||
["supported model", "claude-opus-4-8", { type: "disabled" }, undefined],
|
||||
["Mythos 5.1", "claude-mythos-5-1", { type: "adaptive", display: "summarized" }, "high"],
|
||||
["Fable 5.2", "claude-fable-5-2", { type: "adaptive", display: "summarized" }, "medium"],
|
||||
["Mythos 5.2", "claude-mythos-5-2", { type: "adaptive", display: "summarized" }, "medium"],
|
||||
["Haiku 5.5", "claude-haiku-5-5", { type: "disabled" }, undefined],
|
||||
["unsupported model", "claude-fable-5", { type: "adaptive", display: "summarized" }, "high"],
|
||||
["custom model", "openrouter/anthropic/claude-opus-4-8", undefined, undefined],
|
||||
|
||||
@@ -5,7 +5,7 @@ export const CLAUDE_FAST_MODE_CONTROL: AgentOptionToggleControl = {
|
||||
type: "toggle",
|
||||
key: "fast_mode",
|
||||
label: "Fast",
|
||||
description: "Lower latency Opus responses at higher token cost",
|
||||
description: "Lower latency responses at higher token cost",
|
||||
tooltip: "Toggle fast mode",
|
||||
icon: "zap",
|
||||
};
|
||||
|
||||
@@ -58,6 +58,17 @@ export const CLAUDE_MODEL_MANIFEST = [
|
||||
supportsThinkingDisabled: true,
|
||||
supportsFastMode: true,
|
||||
},
|
||||
{
|
||||
id: "claude-mythos-5-2",
|
||||
label: "Mythos 5.2",
|
||||
requiresDiscovery: true,
|
||||
description: "Mythos 5.2 · Requires verified access",
|
||||
minimumClaudeCodeVersion: "2.1.321",
|
||||
defaultThinkingOptionId: "medium",
|
||||
contextWindowMaxTokens: 1_000_000,
|
||||
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
|
||||
supportsFastMode: true,
|
||||
},
|
||||
{
|
||||
id: "claude-mythos-5-1",
|
||||
label: "Mythos 5.1",
|
||||
@@ -66,10 +77,20 @@ export const CLAUDE_MODEL_MANIFEST = [
|
||||
contextWindowMaxTokens: 1_000_000,
|
||||
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
|
||||
},
|
||||
{
|
||||
id: "claude-fable-5-2",
|
||||
label: "Fable 5.2",
|
||||
description: "Fable 5.2 · Most powerful model",
|
||||
minimumClaudeCodeVersion: "2.1.321",
|
||||
defaultThinkingOptionId: "medium",
|
||||
contextWindowMaxTokens: 1_000_000,
|
||||
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
|
||||
supportsFastMode: true,
|
||||
},
|
||||
{
|
||||
id: "claude-fable-5-1",
|
||||
label: "Fable 5.1",
|
||||
description: "Fable 5.1 · Most powerful model",
|
||||
description: "Fable 5.1 · Previous release",
|
||||
contextWindowMaxTokens: 1_000_000,
|
||||
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
|
||||
},
|
||||
|
||||
@@ -61,17 +61,23 @@ async function createClaudeConfigDirWithRawSettings(settings: string): Promise<s
|
||||
return configDir;
|
||||
}
|
||||
|
||||
function createCatalogClient(claudeCodeVersion = "2.1.293"): ClaudeAgentClient {
|
||||
function createCatalogClient(claudeCodeVersion = "2.1.321"): ClaudeAgentClient {
|
||||
return new ClaudeAgentClient({
|
||||
logger: createTestLogger(),
|
||||
resolveVersion: async () => claudeCodeVersion,
|
||||
discoverModels: async () => [
|
||||
{
|
||||
value: "mythos",
|
||||
resolvedModel: "claude-mythos-5-1",
|
||||
resolvedModel: "claude-mythos-5-2",
|
||||
displayName: "Mythos",
|
||||
description: "",
|
||||
},
|
||||
{
|
||||
value: "claude-mythos-5-1",
|
||||
resolvedModel: "claude-mythos-5-1",
|
||||
displayName: "Mythos 5.1",
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
@@ -82,7 +88,9 @@ describe("getClaudeModels", () => {
|
||||
expect(models.map((m) => m.id)).toEqual([
|
||||
"claude-opus-5-5",
|
||||
"claude-opus-5",
|
||||
"claude-mythos-5-2",
|
||||
"claude-mythos-5-1",
|
||||
"claude-fable-5-2",
|
||||
"claude-fable-5-1",
|
||||
"claude-fable-5",
|
||||
"claude-fable-5[1m]",
|
||||
@@ -118,7 +126,9 @@ describe("getClaudeModels", () => {
|
||||
new Map([
|
||||
["claude-opus-5-5", 1_000_000],
|
||||
["claude-opus-5", 1_000_000],
|
||||
["claude-mythos-5-2", 1_000_000],
|
||||
["claude-mythos-5-1", 1_000_000],
|
||||
["claude-fable-5-2", 1_000_000],
|
||||
["claude-fable-5-1", 1_000_000],
|
||||
["claude-fable-5", 1_000_000],
|
||||
["claude-fable-5[1m]", 1_000_000],
|
||||
@@ -163,6 +173,12 @@ describe("getClaudeModels", () => {
|
||||
expect(getClaudeModels("2.1.293").find((model) => model.isDefault)?.id).toBe("claude-opus-5-5");
|
||||
});
|
||||
|
||||
it("gates Fable 5.2 on Claude Code 2.1.321 without changing the default", () => {
|
||||
expect(getClaudeModels("2.1.320").map((model) => model.id)).not.toContain("claude-fable-5-2");
|
||||
expect(getClaudeModels("2.1.321").map((model) => model.id)).toContain("claude-fable-5-2");
|
||||
expect(getClaudeModels("2.1.321").find((model) => model.isDefault)?.id).toBe("claude-opus-5-5");
|
||||
});
|
||||
|
||||
it("derives thinking options from model effort capabilities", () => {
|
||||
const models = new Map(getClaudeModels().map((model) => [model.id, model]));
|
||||
|
||||
@@ -232,6 +248,8 @@ describe("getClaudeModels", () => {
|
||||
["claude-sonnet-5-20260101", true, "high"],
|
||||
["claude-fable-5", false, "high"],
|
||||
["claude-fable-5-1", false, "high"],
|
||||
["claude-fable-5-2", false, "medium"],
|
||||
["claude-mythos-5-2", false, "medium"],
|
||||
["claude-haiku-5-5", true, "medium"],
|
||||
["claude-haiku-5-5-20261007", true, "medium"],
|
||||
["claude-haiku-4-5", false, undefined],
|
||||
@@ -284,6 +302,31 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it("offers Mythos 5.2 in place of Mythos 5.1 when Claude Code resolves mythos to 5.2", async () => {
|
||||
const configDir = await createClaudeConfigDir({});
|
||||
const client = new ClaudeAgentClient({
|
||||
logger: createTestLogger(),
|
||||
resolveVersion: async () => "2.1.321",
|
||||
runtimeSettings: { env: { CLAUDE_CONFIG_DIR: configDir } },
|
||||
discoverModels: async () => [
|
||||
{
|
||||
value: "mythos",
|
||||
resolvedModel: "claude-mythos-5-2",
|
||||
displayName: "Mythos",
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
});
|
||||
const { models } = await client.fetchCatalog({
|
||||
scope: "workspace",
|
||||
cwd: configDir,
|
||||
force: false,
|
||||
});
|
||||
expect(models.filter((model) => model.id.startsWith("claude-mythos-"))).toEqual([
|
||||
findClaudeModel("claude-mythos-5-2"),
|
||||
]);
|
||||
});
|
||||
|
||||
it("preserves the curated catalog and explicitly configured models after discovery failure", async () => {
|
||||
const configDir = await createClaudeConfigDir({ model: "claude-mythos-5-1" });
|
||||
const client = new ClaudeAgentClient({
|
||||
@@ -299,8 +342,8 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
|
||||
cwd: configDir,
|
||||
force: false,
|
||||
});
|
||||
expect(models.filter((model) => model.id !== "claude-mythos-5-1")).toEqual(
|
||||
getClaudeModels("2.1.293").filter((model) => model.id !== "claude-mythos-5-1"),
|
||||
expect(models.filter((model) => !model.id.startsWith("claude-mythos-"))).toEqual(
|
||||
getClaudeModels("2.1.293").filter((model) => !model.id.startsWith("claude-mythos-")),
|
||||
);
|
||||
expect(models.find((model) => model.id === "claude-mythos-5-1")).toEqual({
|
||||
...findClaudeModel("claude-mythos-5-1"),
|
||||
@@ -360,7 +403,7 @@ describe("ClaudeAgentClient.fetchCatalog", () => {
|
||||
});
|
||||
expect(models.map((model) => model.id)).toEqual(
|
||||
getClaudeModels("2.1.293")
|
||||
.filter((model) => model.id !== "claude-mythos-5-1")
|
||||
.filter((model) => !model.id.startsWith("claude-mythos-"))
|
||||
.map((model) => model.id),
|
||||
);
|
||||
});
|
||||
@@ -785,6 +828,44 @@ describe("Claude Fable 5.1 catalog", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Claude Fable 5.2 catalog", () => {
|
||||
it("offers one 1M model with medium default effort, always-on thinking, and fast mode", () => {
|
||||
const models = getClaudeModels().filter((model) => model.id.startsWith("claude-fable-5-2"));
|
||||
expect(models).toHaveLength(1);
|
||||
expect(models[0]).toMatchObject({
|
||||
id: "claude-fable-5-2",
|
||||
label: "Fable 5.2",
|
||||
contextWindowMaxTokens: 1_000_000,
|
||||
defaultThinkingOptionId: "medium",
|
||||
});
|
||||
expect(models[0].thinkingOptions?.map((option) => option.id)).toEqual([
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max",
|
||||
CLAUDE_ULTRACODE_THINKING_OPTION_ID,
|
||||
]);
|
||||
expect(claudeManifestModelSupportsFastMode("claude-fable-5-2")).toBe(true);
|
||||
});
|
||||
|
||||
it.each([
|
||||
"claude-fable-5-2[1m]",
|
||||
"claude-fable-5-2-20261110",
|
||||
"claude-fable-5-2-20261110[1m]",
|
||||
"Fable 5.2",
|
||||
])("resolves %s to the single catalog entry", (id) => {
|
||||
expect(findClaudeModel(id)?.id).toBe("claude-fable-5-2");
|
||||
});
|
||||
|
||||
it.each(["claude-fable-5-2", "anthropic/claude-fable-5-2", "us.anthropic.claude-fable-5-2-v1:0"])(
|
||||
"keeps runtime model %s from collapsing onto Fable 5",
|
||||
(id) => {
|
||||
expect(normalizeClaudeRuntimeModelId(id)).toBe("claude-fable-5-2");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("Claude Opus 5.5 catalog", () => {
|
||||
it("offers one Opus 5.5 entry with a 1M context window", () => {
|
||||
const opus55Models = getClaudeModels()
|
||||
@@ -920,7 +1001,7 @@ describe("claudeManifestModelSupportsFastMode", () => {
|
||||
|
||||
describe("Claude Mythos 5.1 catalog", () => {
|
||||
it("offers one 1M model with high default effort and always-on thinking", () => {
|
||||
const models = getClaudeModels().filter((model) => model.id.startsWith("claude-mythos"));
|
||||
const models = getClaudeModels().filter((model) => model.id.startsWith("claude-mythos-5-1"));
|
||||
expect(models).toHaveLength(1);
|
||||
expect(models[0]).toMatchObject({
|
||||
id: "claude-mythos-5-1",
|
||||
@@ -965,6 +1046,61 @@ describe("Claude Mythos 5.1 catalog", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe("Claude Mythos 5.2 catalog", () => {
|
||||
it("stays hidden on Claude Code older than 2.1.321 even when advertised", async () => {
|
||||
const configDir = await createClaudeConfigDir({});
|
||||
const client = new ClaudeAgentClient({
|
||||
logger: createTestLogger(),
|
||||
resolveVersion: async () => "2.1.320",
|
||||
runtimeSettings: { env: { CLAUDE_CONFIG_DIR: configDir } },
|
||||
discoverModels: async () => [
|
||||
{
|
||||
value: "mythos",
|
||||
resolvedModel: "claude-mythos-5-2",
|
||||
displayName: "Mythos",
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const { models } = await client.fetchCatalog({
|
||||
scope: "workspace",
|
||||
cwd: configDir,
|
||||
force: false,
|
||||
});
|
||||
|
||||
expect(models.some((model) => model.id === "claude-mythos-5-2")).toBe(false);
|
||||
});
|
||||
|
||||
it("offers one 1M model with medium default effort, always-on thinking, and fast mode", () => {
|
||||
const models = getClaudeModels().filter((model) => model.id.startsWith("claude-mythos-5-2"));
|
||||
expect(models).toHaveLength(1);
|
||||
expect(models[0]).toMatchObject({
|
||||
id: "claude-mythos-5-2",
|
||||
label: "Mythos 5.2",
|
||||
contextWindowMaxTokens: 1_000_000,
|
||||
defaultThinkingOptionId: "medium",
|
||||
});
|
||||
expect(models[0].thinkingOptions?.map((option) => option.id)).toEqual([
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max",
|
||||
CLAUDE_ULTRACODE_THINKING_OPTION_ID,
|
||||
]);
|
||||
expect(claudeManifestModelSupportsFastMode("claude-mythos-5-2")).toBe(true);
|
||||
});
|
||||
|
||||
it.each(["anthropic/claude-mythos-5-2", "us.anthropic.claude-mythos-5-2-v1:0"])(
|
||||
"normalizes runtime identity without granting first-party capabilities: %s",
|
||||
(id) => {
|
||||
expect(normalizeClaudeRuntimeModelId(id)).toBe("claude-mythos-5-2");
|
||||
expect(normalizeClaudeManifestModelId(id)).toBeNull();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("Claude model discovery process", () => {
|
||||
it("does not send a prompt or persist a session and closes after discovery", async () => {
|
||||
let closed = false;
|
||||
|
||||
Reference in New Issue
Block a user