feat: display toggles, smart session resume, fix stale transcript pane (#8)
This commit was merged in pull request #8.
This commit is contained in:
@@ -139,6 +139,45 @@ describe("buildThreadMarkdown", () => {
|
||||
expect(markdown).toContain("`web_fetch` — failed");
|
||||
});
|
||||
|
||||
it("omits tools and reasoning when the preferences are off", () => {
|
||||
const messages = [
|
||||
message({
|
||||
role: "assistant",
|
||||
text: "a",
|
||||
thinking: "let me think",
|
||||
toolCalls: [{ name: "web_search", arguments: {}, result: "ok", isError: false }],
|
||||
}),
|
||||
];
|
||||
|
||||
const hidden = buildThreadMarkdown(messages, { showToolCalls: false, showReasoning: false });
|
||||
|
||||
expect(hidden).not.toContain("Tools used");
|
||||
expect(hidden).not.toContain("web_search");
|
||||
expect(hidden).not.toContain("Reasoning");
|
||||
expect(hidden).not.toContain("let me think");
|
||||
// The answer itself must survive either way.
|
||||
expect(hidden).toContain("a");
|
||||
});
|
||||
|
||||
it("shows one section without the other", () => {
|
||||
const messages = [
|
||||
message({
|
||||
role: "assistant",
|
||||
text: "a",
|
||||
thinking: "let me think",
|
||||
toolCalls: [{ name: "web_search", arguments: {}, result: "ok", isError: false }],
|
||||
}),
|
||||
];
|
||||
|
||||
const toolsOnly = buildThreadMarkdown(messages, { showToolCalls: true, showReasoning: false });
|
||||
expect(toolsOnly).toContain("Tools used");
|
||||
expect(toolsOnly).not.toContain("Reasoning");
|
||||
|
||||
const reasoningOnly = buildThreadMarkdown(messages, { showToolCalls: false, showReasoning: true });
|
||||
expect(reasoningOnly).not.toContain("Tools used");
|
||||
expect(reasoningOnly).toContain("Reasoning");
|
||||
});
|
||||
|
||||
it("only shows a reasoning section when there is reasoning", () => {
|
||||
expect(buildThreadMarkdown([message({ role: "assistant", text: "a" })])).not.toContain("Reasoning");
|
||||
expect(buildThreadMarkdown([message({ role: "assistant", text: "a", thinking: "hmm" })])).toContain(
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { DEFAULT_HOST, DEFAULT_MODEL } from "../lib/constants";
|
||||
import { describeResumeTimeout, resolvePreferences, resolveResumeTimeout } from "../lib/preferences";
|
||||
|
||||
const MINUTE = 60_000;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
|
||||
describe("resolveResumeTimeout", () => {
|
||||
it("maps each configured window", () => {
|
||||
expect(resolveResumeTimeout("15m")).toBe(15 * MINUTE);
|
||||
expect(resolveResumeTimeout("1h")).toBe(HOUR);
|
||||
expect(resolveResumeTimeout("6h")).toBe(6 * HOUR);
|
||||
expect(resolveResumeTimeout("1d")).toBe(DAY);
|
||||
});
|
||||
|
||||
it("returns undefined for 'never', which means always reopen the last chat", () => {
|
||||
expect(resolveResumeTimeout("never")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns undefined for missing or unrecognised values rather than guessing", () => {
|
||||
expect(resolveResumeTimeout(undefined)).toBeUndefined();
|
||||
expect(resolveResumeTimeout("")).toBeUndefined();
|
||||
expect(resolveResumeTimeout("banana")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("tolerates surrounding whitespace", () => {
|
||||
expect(resolveResumeTimeout(" 15m ")).toBe(15 * MINUTE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("describeResumeTimeout", () => {
|
||||
it("names the never case rather than showing a number", () => {
|
||||
expect(describeResumeTimeout(undefined)).toContain("Never");
|
||||
});
|
||||
|
||||
it("describes minutes, hours, and days", () => {
|
||||
expect(describeResumeTimeout(15 * MINUTE)).toBe("After 15 minutes");
|
||||
expect(describeResumeTimeout(HOUR)).toBe("After 1 hour");
|
||||
expect(describeResumeTimeout(6 * HOUR)).toBe("After 6 hours");
|
||||
expect(describeResumeTimeout(DAY)).toBe("After 1 day");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolvePreferences", () => {
|
||||
it("fills in every optional value", () => {
|
||||
const resolved = resolvePreferences({});
|
||||
|
||||
expect(resolved.model).toBe(DEFAULT_MODEL);
|
||||
expect(resolved.host).toBe(DEFAULT_HOST);
|
||||
expect(resolved.webEnabled).toBe(true);
|
||||
expect(resolved.showToolCalls).toBe(true);
|
||||
expect(resolved.showReasoning).toBe(true);
|
||||
expect(resolved.think).toBeUndefined();
|
||||
expect(resolved.resumeTimeoutMs).toBe(HOUR);
|
||||
});
|
||||
|
||||
it("honours the display toggles being switched off", () => {
|
||||
const resolved = resolvePreferences({ showToolCalls: false, showReasoning: false });
|
||||
|
||||
expect(resolved.showToolCalls).toBe(false);
|
||||
expect(resolved.showReasoning).toBe(false);
|
||||
});
|
||||
|
||||
it("treats an unknown model or host as unset", () => {
|
||||
const resolved = resolvePreferences({ model: " ", ollamaHost: "" });
|
||||
|
||||
expect(resolved.model).toBe(DEFAULT_MODEL);
|
||||
expect(resolved.host).toBe(DEFAULT_HOST);
|
||||
});
|
||||
|
||||
it("keeps a local Ollama host", () => {
|
||||
expect(resolvePreferences({ ollamaHost: "http://localhost:11434" }).host).toBe(
|
||||
"http://localhost:11434",
|
||||
);
|
||||
});
|
||||
|
||||
it("treats reasoning 'off' as disabled", () => {
|
||||
expect(resolvePreferences({ thinking: "off" }).think).toBeUndefined();
|
||||
expect(resolvePreferences({ thinking: "high" }).think).toBe("high");
|
||||
});
|
||||
|
||||
it("carries the resume window through, including never", () => {
|
||||
expect(resolvePreferences({ resumeTimeout: "15m" }).resumeTimeoutMs).toBe(15 * MINUTE);
|
||||
expect(resolvePreferences({ resumeTimeout: "never" }).resumeTimeoutMs).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user