Files
Sybil-2/web/tests/workspace-domain.test.mjs
T

66 lines
3.8 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
buildCompletionMessages, buildWorkspaceUrl, getModelOptions, getVisibleProviders,
hasNewPersistedUserMessage, loadStoredModelPreferences, normalizeStoredModelPreferences,
pickProviderModel, readSidebarSelectionFromUrl, saveModelPreferences,
} from "../src/lib/workspace-domain.ts";
const attachment = { kind: "text", id: "notes", filename: "notes.txt", mimeType: "text/plain", sizeBytes: 4, text: "plan", truncated: false };
const message = (id, role, content, metadata = null) => ({ id, role, content, metadata, createdAt: "2026-01-01T00:00:00Z", name: null });
test("both presentations submit provider history without UI tool logs and preserve attachments", () => {
const history = [
message("s", "system", "Be concise"),
message("u", "user", "Read my notes", { attachments: [attachment] }),
message("log", "tool", "Searching the web", { kind: "tool_call", toolCallId: "call-1" }),
{ ...message("tool", "tool", "Provider tool result"), name: "web_search" },
message("a", "assistant", "Here is the plan"),
];
const payload = buildCompletionMessages(history, "Continue", [attachment]);
assert.deepEqual(payload.map(entry => entry.role), ["system", "user", "tool", "assistant", "user"]);
assert.ok(!payload.some(entry => entry.id === "log"));
assert.deepEqual(payload[1].attachments, [attachment]);
assert.equal(payload[2].name, "web_search");
assert.deepEqual(payload.at(-1), { role: "user", content: "Continue", attachments: [attachment] });
assert.equal(history.length, 5);
});
test("reconciliation recognizes only a new matching persisted user turn", () => {
const old = message("old", "user", "Continue");
const next = message("next", "user", "Continue", { attachments: [attachment] });
const chat = { messages: [old, next] };
assert.equal(hasNewPersistedUserMessage(chat, new Set(["old"]), "Continue", [attachment]), true);
assert.equal(hasNewPersistedUserMessage(chat, new Set(["old", "next"]), "Continue", [attachment]), false);
assert.equal(hasNewPersistedUserMessage(chat, new Set(["old"]), "Continue", []), false);
assert.equal(hasNewPersistedUserMessage(chat, new Set(["old"]), "Different", [attachment]), false);
});
test("model policy preserves custom selections and uses advertised provider models", () => {
const catalog = { openai: { models: ["server-model"] }, "hermes-agent": { models: ["hermes"] } };
assert.deepEqual(getModelOptions(catalog, "openai"), ["server-model"]);
assert.equal(pickProviderModel(["server-model"], " custom-model "), "custom-model");
assert.equal(pickProviderModel(["server-model"], null), "server-model");
assert.ok(getVisibleProviders(catalog).includes("hermes-agent"));
assert.ok(!getVisibleProviders({}).includes("hermes-agent"));
assert.equal(normalizeStoredModelPreferences({ openai: " x ", xai: 123 }).openai, "x");
assert.equal(normalizeStoredModelPreferences({ xai: 123 }).xai, null);
});
test("selection URLs preserve interface choice and hash without stale selections", () => {
globalThis.window = { location: { pathname: "/lite", search: "?ui=lite&chat=old&search=stale", hash: "#reply" } };
try {
assert.deepEqual(readSidebarSelectionFromUrl(), { kind: "chat", id: "old" });
assert.equal(buildWorkspaceUrl({ kind: "agent", id: "root" }), "/lite?ui=lite&agent=root#reply");
assert.equal(buildWorkspaceUrl(null), "/lite?ui=lite#reply");
} finally { delete globalThis.window; }
});
test("blocked storage does not prevent reading defaults or using model controls", () => {
globalThis.window = { get localStorage() { throw new Error("Storage unavailable"); } };
try {
assert.equal(loadStoredModelPreferences().openai, null);
assert.doesNotThrow(() => saveModelPreferences(normalizeStoredModelPreferences({ openai: "x" })));
} finally { delete globalThis.window; }
});