improve reasoning toggle tests and refactor model capability checks
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
// Conservative allowlist for models supporting the boolean think API.
|
// Conservative allowlist for models supporting the boolean think API.
|
||||||
// Unknown models remain usable for normal chat.
|
// Unknown models remain usable for normal chat.
|
||||||
export function supportsReasoning(model) {
|
const reasoningFamilies = new Set(["qwen3", "deepseek-r1", "deepseek-v3.1"]);
|
||||||
const id = String(typeof model === "string" ? model : model?.model || model?.name || "").toLowerCase().split("/").at(-1);
|
|
||||||
return /^(qwen3|deepseek-r1|deepseek-v3\.1)(:|$)/.test(id);
|
export function getModelFamily(model) {
|
||||||
|
const id = typeof model === "string" ? model : model?.model || model?.name || model?.id || "";
|
||||||
|
return String(id).trim().toLowerCase().split("/").at(-1).split(":")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function supportsReasoning(model) {
|
||||||
|
return reasoningFamilies.has(getModelFamily(model));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {supportsReasoning} from "./modelCapabilities.js";
|
import {supportsReasoning} from "./modelCapabilities.js?v=20260921-reasoning-capability";
|
||||||
|
|
||||||
export function createReasoningToggle(button) {
|
export function createReasoningToggle(button) {
|
||||||
let reasoningEnabled = false;
|
let reasoningEnabled = false;
|
||||||
|
|||||||
+1
-1
@@ -358,7 +358,7 @@
|
|||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js" defer></script>
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js" defer></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js" defer></script>
|
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.6/dist/purify.min.js" defer></script>
|
||||||
<script type="module" src="/script.js?v=20260909-account-controls"></script>
|
<script type="module" src="/script.js?v=20260921-reasoning-capability"></script>
|
||||||
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
<script type="module" src="/app/workspaceNavigation.js?v=20260909-account-controls"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import {del, get, post, put, stream} from "./app/api.js?v=20260909-account-controls";
|
import {del, get, post, put, stream} from "./app/api.js?v=20260909-account-controls";
|
||||||
import {appendSources, createWebSearchToggle} from "./app/webSearch.js";
|
import {appendSources, createWebSearchToggle} from "./app/webSearch.js";
|
||||||
import {createReasoningToggle, finishReasoning, updateReasoning} from "./app/reasoning.js";
|
import {createReasoningToggle, finishReasoning, updateReasoning} from "./app/reasoning.js?v=20260921-reasoning-capability";
|
||||||
import {closeChatDrawer, openChatDrawer} from "./app/chatDrawer.js?v=20260909-account-controls";
|
import {closeChatDrawer, openChatDrawer} from "./app/chatDrawer.js?v=20260909-account-controls";
|
||||||
import {onboardingPrompts, requestedChatId} from "./app/constants.js?v=20260909-account-controls";
|
import {onboardingPrompts, requestedChatId} from "./app/constants.js?v=20260909-account-controls";
|
||||||
import {getModelProfile} from "./app/modelProfiles.js?v=20260909-account-controls";
|
import {getModelProfile} from "./app/modelProfiles.js?v=20260909-account-controls";
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {createApp} from "../src/app.js";
|
|||||||
import {createModelService} from "../src/services/modelService.js";
|
import {createModelService} from "../src/services/modelService.js";
|
||||||
import {stream} from "../public/app/api.js";
|
import {stream} from "../public/app/api.js";
|
||||||
import {createReasoningToggle, finishReasoning, updateReasoning} from "../public/app/reasoning.js";
|
import {createReasoningToggle, finishReasoning, updateReasoning} from "../public/app/reasoning.js";
|
||||||
|
import {getModelFamily, supportsReasoning} from "../public/app/modelCapabilities.js";
|
||||||
|
|
||||||
test("thinking streams separately and survives reload, retry, branch and import", async (t) => {
|
test("thinking streams separately and survives reload, retry, branch and import", async (t) => {
|
||||||
const requests = [];
|
const requests = [];
|
||||||
@@ -169,17 +170,20 @@ test("reasoning toggle defaults off, resets, and rejects unsupported models", ()
|
|||||||
const button = {setAttribute() {}, addEventListener(_event, callback) { this.click = callback; }};
|
const button = {setAttribute() {}, addEventListener(_event, callback) { this.click = callback; }};
|
||||||
const toggle = createReasoningToggle(button);
|
const toggle = createReasoningToggle(button);
|
||||||
toggle.setModel("qwen3:14b");
|
toggle.setModel("qwen3:14b");
|
||||||
|
assert.equal(button.disabled, false);
|
||||||
assert.equal(toggle.enabled, false);
|
assert.equal(toggle.enabled, false);
|
||||||
assert.equal(button.title, "Enable reasoning");
|
assert.equal(button.title, "Enable reasoning");
|
||||||
button.click();
|
button.click();
|
||||||
assert.equal(toggle.enabled, true);
|
assert.equal(toggle.enabled, true);
|
||||||
assert.equal(button.title, "Reasoning enabled");
|
assert.equal(button.title, "Reasoning enabled");
|
||||||
|
assert.equal(button.disabled, false);
|
||||||
toggle.setBusy(true);
|
toggle.setBusy(true);
|
||||||
button.click();
|
button.click();
|
||||||
assert.equal(toggle.enabled, true);
|
assert.equal(toggle.enabled, true);
|
||||||
toggle.reset();
|
toggle.reset();
|
||||||
assert.equal(toggle.enabled, false);
|
assert.equal(toggle.enabled, false);
|
||||||
toggle.setBusy(false);
|
toggle.setBusy(false);
|
||||||
|
assert.equal(button.disabled, false);
|
||||||
button.click();
|
button.click();
|
||||||
toggle.setModel("mistral:latest");
|
toggle.setModel("mistral:latest");
|
||||||
assert.equal(toggle.enabled, false);
|
assert.equal(toggle.enabled, false);
|
||||||
@@ -188,3 +192,40 @@ test("reasoning toggle defaults off, resets, and rejects unsupported models", ()
|
|||||||
button.click();
|
button.click();
|
||||||
assert.equal(toggle.enabled, false);
|
assert.equal(toggle.enabled, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("tagged Qwen3 models enable the control without activating reasoning", () => {
|
||||||
|
for (const model of [
|
||||||
|
"qwen3:14b", "qwen3:8b", "qwen3:30b", "qwen3:latest",
|
||||||
|
" QWEN3:14b ", "library/qwen3:14b",
|
||||||
|
{model: "qwen3:14b"}, {name: "qwen3:8b"}, {id: "qwen3:latest"}
|
||||||
|
]) {
|
||||||
|
assert.equal(getModelFamily(model), "qwen3");
|
||||||
|
assert.equal(supportsReasoning(model), true);
|
||||||
|
const attributes = {};
|
||||||
|
const button = {
|
||||||
|
disabled: true,
|
||||||
|
setAttribute(key, value) { attributes[key] = value; },
|
||||||
|
addEventListener(_event, callback) { this.click = callback; }
|
||||||
|
};
|
||||||
|
const toggle = createReasoningToggle(button);
|
||||||
|
toggle.setModel(""); // Model list has not loaded yet.
|
||||||
|
assert.equal(button.disabled, true);
|
||||||
|
toggle.setModel(model);
|
||||||
|
assert.equal(button.disabled, false);
|
||||||
|
assert.equal(toggle.enabled, false);
|
||||||
|
assert.equal(attributes["aria-pressed"], "false");
|
||||||
|
assert.equal(button.title, "Enable reasoning");
|
||||||
|
button.click();
|
||||||
|
assert.equal(toggle.enabled, true);
|
||||||
|
assert.equal(attributes["aria-pressed"], "true");
|
||||||
|
toggle.setModel(model); // A UI refresh must preserve the choice.
|
||||||
|
assert.equal(toggle.enabled, true);
|
||||||
|
toggle.reset();
|
||||||
|
assert.equal(toggle.enabled, false);
|
||||||
|
assert.equal(button.disabled, false);
|
||||||
|
assert.equal(button.title, "Enable reasoning");
|
||||||
|
}
|
||||||
|
for (const model of ["mistral:latest", "qwen2.5:14b", "qwen3-coder:30b", "qwen30:14b", "", null]) {
|
||||||
|
assert.equal(supportsReasoning(model), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user