// Unit tests for the optional Internal AI (OllaBridge) settings + client + manager. // // Run with: npm run test (node --test with type-stripping and the @/ alias resolver). // These cover the contract-safety guarantees: provider "none" makes zero AI calls, settings are // browser-local and merge-safe, URLs/codes are normalized, and AI enrichment can only ever touch // display copy — never the deterministic candidate fields that drive bundle generation. import assert from "node:assert/strict"; import { afterEach, beforeEach, describe, it } from "node:test"; import { DEFAULT_AI_SETTINGS, type MatrixAISettings, type OllaBridgeSettings, } from "@/types/ai-settings"; import { getAISettings, saveAISettings, clearAISettings, mergeAISettings } from "@/lib/ai-settings-store"; import { assertRootBaseUrl, authHeader, chatUrl, fetchOllaBridgeModels, isLocalhostLike, modelsUrl, normalizePairingCode, pairWithOllaBridge, pairingUrl, sendOllaBridgeChat, stripTrailingSlash, } from "@/lib/ollabridge-client"; import { briefToIdea, enhanceProjectBrief, enrichBlueprintCandidates, explainValidationFindings, isAssistEnabled, isOllaBridgeAssistAvailable, sanitizeBrief, sanitizeEnrichment, } from "@/lib/ai-provider-manager"; import type { ProjectBriefContract } from "@/lib/workflow-types"; // --- A tiny window/localStorage shim so the store + manager run under node --test -------------- function installFakeWindow(): Map { const store = new Map(); (globalThis as Record).window = { localStorage: { getItem: (k: string) => (store.has(k) ? store.get(k)! : null), setItem: (k: string, v: string) => void store.set(k, String(v)), removeItem: (k: string) => void store.delete(k), }, dispatchEvent: () => true, addEventListener: () => {}, removeEventListener: () => {}, }; return store; } function setSettings(patch: Partial, ob: Partial = {}) { saveAISettings({ ...DEFAULT_AI_SETTINGS, ...patch, ollabridge: { ...DEFAULT_AI_SETTINGS.ollabridge, ...ob }, }); } const originalFetch = globalThis.fetch; function stubFetch(impl: (url: string, init?: RequestInit) => Promise | Response) { (globalThis as Record).fetch = (input: unknown, init?: RequestInit) => Promise.resolve(impl(String(input), init)); } function jsonResponse(body: unknown, ok = true): Response { return { ok, status: ok ? 200 : 500, json: async () => body } as unknown as Response; } beforeEach(() => installFakeWindow()); afterEach(() => { delete (globalThis as Record).window; (globalThis as Record).fetch = originalFetch; }); // --- Settings store ---------------------------------------------------------------------------- describe("ai-settings-store", () => { it("defaults to provider none / deterministic", () => { assert.equal(getAISettings().provider, "none"); assert.equal(getAISettings().mode, "deterministic"); }); it("persists to localStorage and reads back", () => { setSettings({ provider: "ollabridge", mode: "assisted" }, { model: "llama3:8b" }); const read = getAISettings(); assert.equal(read.provider, "ollabridge"); assert.equal(read.mode, "assisted"); assert.equal(read.ollabridge.model, "llama3:8b"); }); it("clearAISettings resets to defaults", () => { setSettings({ provider: "ollabridge" }); clearAISettings(); assert.equal(getAISettings().provider, "none"); }); it("falls back to defaults on malformed JSON", () => { window.localStorage.setItem("matrix-builder:ai-settings:v1", "{not json"); assert.deepEqual(getAISettings(), DEFAULT_AI_SETTINGS); }); it("merges partial/garbage objects against defaults", () => { assert.equal(mergeAISettings(null).provider, "none"); assert.equal(mergeAISettings({ provider: "bogus" }).provider, "none"); assert.equal(mergeAISettings({ ollabridge: { authMode: "weird" } }).ollabridge.authMode, "pairing"); assert.equal(mergeAISettings({ ollabridge: {} }).ollabridge.baseUrl, DEFAULT_AI_SETTINGS.ollabridge.baseUrl); }); }); // --- OllaBridge client pure helpers ------------------------------------------------------------ describe("ollabridge-client helpers", () => { it("strips trailing slashes", () => { assert.equal(stripTrailingSlash("https://app.ollabridge.com///"), "https://app.ollabridge.com"); }); it("rejects a base URL ending in /v1", () => { assert.throws(() => assertRootBaseUrl("https://app.ollabridge.com/v1")); assert.throws(() => assertRootBaseUrl("https://app.ollabridge.com/v1/")); assert.doesNotThrow(() => assertRootBaseUrl("https://app.ollabridge.com")); }); it("normalizes pairing codes (trim, upper, remove spaces and hyphens)", () => { assert.equal(normalizePairingCode(" ojqw-5764 "), "OJQW5764"); assert.equal(normalizePairingCode("oj qw 57 64"), "OJQW5764"); }); it("detects localhost-like URLs", () => { assert.equal(isLocalhostLike("http://localhost:11434"), true); assert.equal(isLocalhostLike("http://127.0.0.1"), true); assert.equal(isLocalhostLike("https://app.ollabridge.com"), false); }); it("derives the OpenAI-compatible endpoints from the root", () => { assert.equal(chatUrl("https://x.dev/"), "https://x.dev/v1/chat/completions"); assert.equal(modelsUrl("https://x.dev"), "https://x.dev/v1/models"); assert.equal(pairingUrl("https://x.dev"), "https://x.dev/pair"); }); it("builds the right Authorization header per auth mode", () => { const base = DEFAULT_AI_SETTINGS.ollabridge; assert.equal(authHeader({ ...base, authMode: "pairing", pairToken: "tok" }).Authorization, "Bearer tok"); assert.equal(authHeader({ ...base, authMode: "api_key", apiKey: "key" }).Authorization, "Bearer key"); assert.deepEqual(authHeader({ ...base, authMode: "local-trust" }), {}); // no header for local trust }); }); // --- OllaBridge network calls (stubbed fetch) -------------------------------------------------- describe("ollabridge-client network", () => { const ob: OllaBridgeSettings = { ...DEFAULT_AI_SETTINGS.ollabridge }; it("fetch models hits /v1/models and selects the default", async () => { let calledUrl = ""; stubFetch((url) => { calledUrl = url; return jsonResponse({ data: [{ id: "qwen2.5:1.5b" }, { id: "llama3:8b" }] }); }); const result = await fetchOllaBridgeModels(ob); assert.match(calledUrl, /\/v1\/models$/); assert.deepEqual(result.models, ["qwen2.5:1.5b", "llama3:8b"]); assert.equal(result.selected, "qwen2.5:1.5b"); }); it("chat hits /v1/chat/completions and returns the message content", async () => { let calledUrl = ""; stubFetch((url) => { calledUrl = url; return jsonResponse({ choices: [{ message: { content: "hi" } }] }); }); const out = await sendOllaBridgeChat(ob, [{ role: "user", content: "x" }]); assert.match(calledUrl, /\/v1\/chat\/completions$/); assert.equal(out, "hi"); }); it("pairing posts the normalized code to /pair and stores the token", async () => { let body: Record = {}; let calledUrl = ""; stubFetch((url, init) => { calledUrl = url; body = JSON.parse(String(init?.body)); return jsonResponse({ token: "T", device_id: "D" }); }); const result = await pairWithOllaBridge(ob, "oj qw-5764"); assert.match(calledUrl, /\/pair$/); assert.equal(body.code, "OJQW5764"); assert.equal(body.label, "matrix-builder"); assert.equal(result.pairToken, "T"); assert.equal(result.deviceId, "D"); }); }); // --- Enrichment guards (the contract-safety core) ---------------------------------------------- describe("sanitizeEnrichment", () => { const originals = [ { id: "minimal", tier: "Minimal", name: "A", summary: "a" }, { id: "standard", tier: "Standard", name: "B", summary: "b" }, ]; it("keeps only display* fields and drops contract fields like id/tier/stack/files", () => { const out = sanitizeEnrichment(originals, { candidates: [ { id: "minimal", displayName: "Nice A", displaySummary: "nice a", displayRationale: "because", tier: "Production", stack: ["evil"], files: 999, tasks: ["x"], allowed_files: ["/etc"] }, ], }); assert.deepEqual(out.minimal, { displayName: "Nice A", displaySummary: "nice a", displayRationale: "because" }); // None of the forbidden fields leak through. assert.equal((out.minimal as Record).tier, undefined); assert.equal((out.minimal as Record).stack, undefined); assert.equal((out.minimal as Record).files, undefined); }); it("ignores unknown / hallucinated candidate ids", () => { const out = sanitizeEnrichment(originals, { candidates: [{ id: "ghost", displayName: "X" }] }); assert.deepEqual(out, {}); }); it("returns empty for non-array / malformed AI output", () => { assert.deepEqual(sanitizeEnrichment(originals, null), {}); assert.deepEqual(sanitizeEnrichment(originals, { candidates: "nope" }), {}); }); }); // --- Manager: assist gating + fail-open -------------------------------------------------------- describe("ai-provider-manager gating", () => { const candidates = [{ id: "minimal", tier: "Minimal", name: "A", summary: "a" }]; it("assist is disabled by default (provider none)", () => { assert.equal(isAssistEnabled(), false); }); it("provider none → enrich makes no AI call and returns empty", async () => { stubFetch(() => { throw new Error("fetch must not be called when provider is none"); }); const out = await enrichBlueprintCandidates("idea", candidates); assert.deepEqual(out, {}); }); it("provider none → explain makes no AI call and returns null", async () => { stubFetch(() => { throw new Error("fetch must not be called when provider is none"); }); const out = await explainValidationFindings({ status: "approved", score: 100, findings: [] }); assert.equal(out, null); }); it("OllaBridge assist failure falls back to deterministic (empty enrichment)", async () => { setSettings({ provider: "ollabridge", mode: "assisted" }); assert.equal(isAssistEnabled(), true); stubFetch(() => jsonResponse({}, false)); // server error const out = await enrichBlueprintCandidates("idea", candidates); assert.deepEqual(out, {}); }); it("validation explanation returns helper text without mutating the findings input", async () => { setSettings({ provider: "ollabridge", mode: "assisted" }); stubFetch(() => jsonResponse({ choices: [{ message: { content: "Looks good. Ship it." } }] })); const findings = [{ label: "RMD-103", message: "forbidden file" }]; const out = await explainValidationFindings({ status: "rejected", score: 65, findings }); assert.equal(out, "Looks good. Ship it."); assert.deepEqual(findings, [{ label: "RMD-103", message: "forbidden file" }]); // unchanged }); }); // --- Batch 7 — ProjectBrief enhancement (Seam 1) ---------------------------------------------- const BASE_BRIEF: ProjectBriefContract = { schema_version: "matrix.builder.brief/v1", source_type: "document", title: "Doc QA", summary: "original summary", domain: null, goals: ["original goal"], users: [], features: ["original feature"], screens: [], integrations: [], constraints: [], risks: [], non_functional: [], source_files: ["brief.pdf"], enhanced_by: "deterministic", }; describe("Batch 7 — brief enhancement", () => { it("sanitizeBrief discards when title/summary missing", () => { assert.equal(sanitizeBrief(BASE_BRIEF, { confidence: 0.9 }).enhanced_by, "deterministic"); }); it("sanitizeBrief discards when confidence below 0.65", () => { const out = sanitizeBrief(BASE_BRIEF, { title: "X", summary: "Y", confidence: 0.4 }); assert.equal(out.enhanced_by, "deterministic"); assert.equal(out.title, "Doc QA"); }); it("sanitizeBrief applies only safe fields when valid + confident", () => { const out = sanitizeBrief(BASE_BRIEF, { title: "Better Title", summary: "Better summary", features: ["a", "b"], confidence: 0.82, source_type: "design", enhanced_by: "ollabridge", evil: "ignored", }); assert.equal(out.enhanced_by, "ollabridge"); assert.equal(out.title, "Better Title"); assert.deepEqual(out.features, ["a", "b"]); assert.equal(out.source_type, "document"); // AI cannot change the source type assert.equal((out as Record).evil, undefined); }); it("isOllaBridgeAssistAvailable is false when signed out (even with OllaBridge enabled)", () => { setSettings({ provider: "ollabridge", mode: "assisted" }); assert.equal(isOllaBridgeAssistAvailable(), false); }); it("isOllaBridgeAssistAvailable is true when signed in + OllaBridge assisted", () => { setSettings({ provider: "ollabridge", mode: "assisted" }); window.localStorage.setItem("mb_user", JSON.stringify({ email: "a@b.c" })); assert.equal(isOllaBridgeAssistAvailable(), true); }); it("enhanceProjectBrief returns the deterministic brief (no AI call) when assist unavailable", async () => { stubFetch(() => { throw new Error("fetch must not be called when assist is unavailable"); }); const out = await enhanceProjectBrief(BASE_BRIEF); // signed out by default assert.equal(out.enhanced_by, "deterministic"); }); it("briefToIdea folds title + summary + features", () => { const idea = briefToIdea({ title: "Doc QA", summary: "answers with citations", features: ["upload", "search"] }); assert.match(idea, /Doc QA/); assert.match(idea, /upload/); }); });