mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-21 10:22:18 +00:00
The web dashboard only showed a read-only "Reasoning" capability badge with no way to set the effort level — unlike the desktop app, which has an effort radio in its composer model menu. This adds a picker so the two surfaces reach parity. - ReasoningPicker: a Select rendered in the chat sidebar, gated on the effective model's supports_reasoning capability (from /api/model/info). Reads/writes agent.reasoning_effort via the existing config REST endpoints (read-modify-write, the dashboard's single-key save pattern), so the value lands in the config the agent boots a fresh chat from. Options mirror the desktop: Off/Minimal/Low/Medium/High/Max. - ChatSidebar: capture supports_reasoning from the model-info fetch and render the picker; on change, show the same 'apply on /new or reload' notice the model switch uses. - reasoning-effort.ts: DOM-free helpers (normalizeEffort + options) so the node-env vitest harness can cover the resolution logic, plus tests.
48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
EFFORT_OPTIONS,
|
|
VALID_EFFORTS,
|
|
normalizeEffort,
|
|
} from "./reasoning-effort";
|
|
|
|
describe("normalizeEffort", () => {
|
|
it("treats empty/unset as the Hermes default (medium)", () => {
|
|
expect(normalizeEffort("")).toBe("medium");
|
|
expect(normalizeEffort(null)).toBe("medium");
|
|
expect(normalizeEffort(undefined)).toBe("medium");
|
|
expect(normalizeEffort(" ")).toBe("medium");
|
|
});
|
|
|
|
it("passes through every valid effort level", () => {
|
|
for (const level of ["none", "minimal", "low", "medium", "high", "xhigh"]) {
|
|
expect(normalizeEffort(level)).toBe(level);
|
|
}
|
|
});
|
|
|
|
it("is case- and whitespace-insensitive", () => {
|
|
expect(normalizeEffort("HIGH")).toBe("high");
|
|
expect(normalizeEffort(" XHigh ")).toBe("xhigh");
|
|
});
|
|
|
|
it("falls back to medium for unknown values", () => {
|
|
expect(normalizeEffort("turbo")).toBe("medium");
|
|
expect(normalizeEffort("max")).toBe("medium"); // 'max' is a label, not a value
|
|
expect(normalizeEffort(42)).toBe("medium");
|
|
});
|
|
});
|
|
|
|
describe("EFFORT_OPTIONS", () => {
|
|
it("every option value is in VALID_EFFORTS (no orphan labels)", () => {
|
|
for (const opt of EFFORT_OPTIONS) {
|
|
expect(VALID_EFFORTS.has(opt.value)).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("covers the real reasoning levels plus thinking-off", () => {
|
|
// Invariant against hermes_constants.VALID_REASONING_EFFORTS + 'none'.
|
|
const values = new Set(EFFORT_OPTIONS.map((o) => o.value));
|
|
for (const level of ["none", "minimal", "low", "medium", "high", "xhigh"]) {
|
|
expect(values.has(level)).toBe(true);
|
|
}
|
|
});
|
|
});
|