/** * Marker accounting. * * This is the logic that decides which queued images actually reach the model, * so it gets a test even though it is small: a wrong count either silently * sends an image the user deleted from their draft, or drops one they kept. * * Mirrors the reduction in index.ts. Kept as a pure function here so the rule * can be tested without booting a pi session. */ import assert from "node:assert/strict"; import { test } from "node:test"; const MARKER = "[wl-image]"; interface Queued { id: string; } /** Returns the images to send and the queue that survives to the next message. */ function resolveAttachments( text: string, pending: Queued[], ): { attached: Queued[]; remaining: Queued[]; text: string } { const markers = text.split(MARKER).length - 1; if (markers === 0) return { attached: [], remaining: pending, text }; const queue = [...pending]; const attached = queue.splice(0, markers); return { attached, remaining: queue, text: text.replaceAll(MARKER, "").replace(/\s+/g, " ").trim(), }; } test("one marker sends the one queued image", () => { const result = resolveAttachments(`look at this ${MARKER}`, [{ id: "a" }]); assert.deepEqual(result.attached, [{ id: "a" }]); assert.deepEqual(result.remaining, []); assert.equal(result.text, "look at this"); }); test("deleting the marker cancels the attachment", () => { // The user removed the marker from the draft, so the image must not be sent. const result = resolveAttachments("look at this", [{ id: "a" }]); assert.deepEqual(result.attached, []); }); test("deleting one of two markers sends only one image", () => { const result = resolveAttachments(`compare ${MARKER}`, [{ id: "a" }, { id: "b" }]); assert.deepEqual(result.attached, [{ id: "a" }]); // The unsent image stays queued rather than being silently thrown away. assert.deepEqual(result.remaining, [{ id: "b" }]); }); test("more markers than images does not invent attachments", () => { const result = resolveAttachments(`${MARKER} ${MARKER} ${MARKER}`, [{ id: "a" }]); assert.deepEqual(result.attached, [{ id: "a" }]); assert.deepEqual(result.remaining, []); }); test("markers are stripped and whitespace collapsed", () => { const result = resolveAttachments(`${MARKER} what is this? ${MARKER}`, [ { id: "a" }, { id: "b" }, ]); assert.equal(result.text, "what is this?"); assert.equal(result.attached.length, 2); }); test("a marker-only message leaves empty text for the caller to fill", () => { const result = resolveAttachments(MARKER, [{ id: "a" }]); assert.equal(result.text, ""); assert.equal(result.attached.length, 1); }); test("no markers leaves the queue and text untouched", () => { const pending = [{ id: "a" }]; const result = resolveAttachments("unrelated question", pending); assert.deepEqual(result.remaining, pending); assert.equal(result.text, "unrelated question"); });