diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index 0df070a6e..ff4a24732 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Widened the Amazon Bedrock stream idle-timeout floor for reasoning models (600s, matching the GLM coding-plan floor) and for adaptive-thinking Claude — Opus 4.7+, Sonnet/Opus 5, and Fable/Mythos 5, where stalls were most frequent — to 900s, matching the tolerance direct Anthropic gets from ping keepalives. Bedrock ConverseStream sends no keepalive events, so long quiet reasoning stretches previously tripped the generic 300s watchdog with `Provider stream stalled while waiting for the next event` during plan writing and todo execution. Explicit `compat.streamIdleTimeoutMs` overrides still win (`0` disables the watchdog) ([#7892](https://github.com/can1357/oh-my-pi/pull/7892) by [@voonfoo](https://github.com/voonfoo)). +- Fixed current Devin model families, including SWE-1.7, Claude 5, Gemini 3.6 Flash, Kimi K3, Grok 4.5, and Inkling, appearing as separate wire variants instead of logical models with reasoning-effort routing. ## [17.2.10] - 2026-08-06 diff --git a/packages/catalog/src/variant-collapse.ts b/packages/catalog/src/variant-collapse.ts index e7b8e571f..b95e02097 100644 --- a/packages/catalog/src/variant-collapse.ts +++ b/packages/catalog/src/variant-collapse.ts @@ -115,7 +115,7 @@ type DevinTierRoutes = Partial { expect(sol.routing[Effort.Low]).toBe("gpt-5-6-sol-low"); expect(sol.routing.off).toBe("gpt-5-6-sol-none"); expect(sol.routing[Effort.Minimal]).toBeUndefined(); + + const solFast = family("gpt-5-6-sol-fast"); + expect(solFast.routing[Effort.Max]).toBe("gpt-5-6-sol-max-priority"); + expect(solFast.thinking.efforts).toEqual([Effort.Low, Effort.Medium, Effort.High, Effort.XHigh, Effort.Max]); }); - it("keeps families without a -max sibling on the xhigh ceiling", () => { - const solFast = family("gpt-5-6-sol-fast"); - expect(solFast.thinking.efforts).toEqual([Effort.Low, Effort.Medium, Effort.High, Effort.XHigh]); - expect(solFast.routing[Effort.Max]).toBeUndefined(); - expect(solFast.routing[Effort.XHigh]).toBe("gpt-5-6-sol-xhigh-priority"); - + it("keeps pre-5.6 families without a -max sibling on the xhigh ceiling", () => { const gpt55 = family("gpt-5-5"); expect(gpt55.thinking.efforts).toEqual([Effort.Low, Effort.Medium, Effort.High, Effort.XHigh]); expect(gpt55.routing[Effort.Minimal]).toBeUndefined(); expect(gpt55.routing[Effort.Max]).toBeUndefined(); }); + + it("routes current Devin families onto their account-visible wire variants", () => { + const fable = family("claude-fable-5"); + expect(fable.routing[Effort.Low]).toBe("claude-5-fable-low"); + expect(fable.routing[Effort.Max]).toBe("claude-5-fable-max"); + + const swe = family("swe-1-7"); + expect(swe.thinking.efforts).toEqual([Effort.Medium, Effort.Max]); + expect(swe.routing[Effort.Medium]).toBe("swe-1-7-medium"); + expect(swe.routing[Effort.Max]).toBe("swe-1-7"); + + const gemini = family("gemini-3-6-flash"); + expect(gemini.routing[Effort.Minimal]).toBe("gemini-3-6-flash-minimal"); + expect(gemini.routing[Effort.High]).toBe("gemini-3-6-flash-high"); + + const inkling = family("inkling"); + expect(inkling.routing.off).toBe("inkling-none"); + expect(inkling.routing[Effort.Max]).toBe("inkling-max"); + }); + + it("collapses entitled current variants and resolves the selected effort to the wire UID", () => { + const rawIds = [ + "claude-5-fable-low", + "claude-5-fable-medium", + "claude-5-fable-high", + "claude-5-fable-xhigh", + "claude-5-fable-max", + "swe-1-7-medium", + "swe-1-7", + ]; + const specs = rawIds.map( + (id): ModelSpec<"devin-agent"> => ({ + id, + name: id, + api: "devin-agent", + provider: "devin", + baseUrl: "https://server.codeium.com", + reasoning: true, + input: ["text"], + supportsTools: true, + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 200_000, + maxTokens: 64_000, + }), + ); + + const collapsed = collapseEffortVariants(specs, DEVIN_VARIANT_COLLAPSE_TABLE); + expect(collapsed.map(model => model.id).sort()).toEqual(["claude-fable-5", "swe-1-7"]); + + const fable = collapsed.find(model => model.id === "claude-fable-5"); + const swe = collapsed.find(model => model.id === "swe-1-7"); + if (!fable || !swe) throw new Error("Current Devin families did not collapse"); + expect(resolveWireModelId(buildModel(fable), Effort.XHigh)).toBe("claude-5-fable-xhigh"); + expect(resolveWireModelId(buildModel(swe), Effort.Medium)).toBe("swe-1-7-medium"); + expect(resolveWireModelId(buildModel(swe), Effort.Max)).toBe("swe-1-7"); + }); }); describe("variant aliases", () => {