import { afterEach, describe, expect, it } from "vitest"; import { DEFAULT_CAPABILITIES, getCapabilitiesForModel, setUserCapsSource, } from "../../open-sse/providers/capabilities.js"; import { applyThinking } from "../../open-sse/translator/concerns/thinkingUnified.js"; import { looksLikeVisionModel } from "../../open-sse/providers/visionPatterns.js"; // Dashboard capability toggles are the user's own assertion about a model the // heuristics cannot know. They are final: false must beat a name heuristic, // true must beat the safe floor, and applying them must never leak a mutation // back into DEFAULT_CAPABILITIES. afterEach(() => setUserCapsSource(null)); function assertSource(caps) { setUserCapsSource(() => caps); } describe("user-asserted model capabilities", () => { it("turns a heuristic-detected vision model back off", () => { const model = "qwen3-vl-plus"; expect(looksLikeVisionModel(model)).toBe(true); expect(getCapabilitiesForModel("custom-node", model).vision).toBe(true); assertSource({ vision: false }); expect(getCapabilitiesForModel("custom-node", model).vision).toBe(false); }); it("turns reasoning on for a model the tables consider text-only", () => { const model = "my-private-chatml-9"; expect(getCapabilitiesForModel("custom-node", model).reasoning).toBe(false); assertSource({ reasoning: true }); expect(getCapabilitiesForModel("custom-node", model).reasoning).toBe(true); }); it("ignores keys outside the capability set and non-objects", () => { const before = getCapabilitiesForModel("custom-node", "gpt-5.1"); assertSource({ vision: true, nonsense: true }); const after = getCapabilitiesForModel("custom-node", "gpt-5.1"); expect(after.vision).toBe(true); expect("nonsense" in after).toBe(false); for (const junk of [null, undefined, "nope", 42]) { assertSource(junk); expect(getCapabilitiesForModel("custom-node", "gpt-5.1")).toEqual(before); } }); it("only applies asserted keys, leaving the rest resolved normally", () => { assertSource({ vision: false }); const caps = getCapabilitiesForModel("custom-node", "my-private-chatml-9"); expect(caps.vision).toBe(false); expect(caps.tools).toBe(true); expect(caps.contextWindow).toBe(DEFAULT_CAPABILITIES.contextWindow); }); it("never mutates DEFAULT_CAPABILITIES", () => { const floor = { ...DEFAULT_CAPABILITIES }; assertSource({ vision: true, reasoning: true, tools: false, contextWindow: 1234 }); getCapabilitiesForModel("custom-node", "anything"); expect(DEFAULT_CAPABILITIES).toEqual(floor); }); it("keeps heuristics when no source is installed", () => { assertSource({ vision: false }); expect(getCapabilitiesForModel("custom-node", "qwen3-vl-plus").vision).toBe(false); setUserCapsSource(null); expect(getCapabilitiesForModel("custom-node", "qwen3-vl-plus").vision).toBe(true); }); }); describe("thinking follows the assertion", () => { it("strips thinking fields when reasoning is asserted off", () => { assertSource({ reasoning: false }); const body = { reasoning_effort: "high", messages: [{ role: "user", content: "hi" }] }; applyThinking("openai", "my-private-chatml-9", body, "custom-node"); expect(body.reasoning_effort).toBeUndefined(); expect(body.reasoning).toBeUndefined(); expect(body.thinking).toBeUndefined(); }); it("emits thinking fields when reasoning is asserted on", () => { assertSource({ reasoning: true, thinkingFormat: "openai" }); const body = { reasoning_effort: "high", messages: [{ role: "user", content: "hi" }] }; applyThinking("openai", "my-private-chatml-9", body, "custom-node"); expect(body.reasoning_effort).toBe("high"); }); });