/**
* Both request shapes JanitorAI sends, and a continued conversation.
* Run with `npm test` — no test framework, just node's built-in runner.
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import { selectMessageSlots } from "../src/lib/messages.ts";
const CARD =
"<.>\na tired innkeeper.";
const GREETING = "The clink of bottles is the only greeting you get.";
const NAME = "{{user}}: Gaius";
/** What most clients send: a throwaway "." user turn before the greeting. */
const withProbe = [
{ role: "system", content: CARD },
{ role: "user", content: "." },
{ role: "assistant", content: GREETING },
{ role: "user", content: NAME },
];
/** What some clients send: no "." turn, so every index shifts by one. */
const withoutProbe = [
{ role: "system", content: CARD },
{ role: "assistant", content: GREETING },
{ role: "user", content: NAME },
];
test("both shapes resolve to the same slots", () => {
for (const [label, messages] of [
["with probe", withProbe],
["without probe", withoutProbe],
] as const) {
const slots = selectMessageSlots(messages);
assert.equal(slots.system?.content, CARD, `${label}: card`);
assert.equal(slots.greeting?.content, GREETING, `${label}: greeting`);
assert.equal(slots.lastUser?.content, NAME, `${label}: name slot`);
}
});
test("the greeting stays the first assistant turn as a chat continues", () => {
const continued = [
...withProbe,
{ role: "assistant", content: "Character updated (v2)." },
{ role: "user", content: "{{user}}: [sucker:conv=abc123]" },
];
const slots = selectMessageSlots(continued);
assert.equal(slots.greeting?.content, GREETING);
// Sucker's own reply, where a conversation token would be found.
assert.equal(slots.lastAssistant?.content, "Character updated (v2).");
assert.equal(slots.lastUser?.content, "{{user}}: [sucker:conv=abc123]");
});
test("a card with no role on the system turn still resolves", () => {
const slots = selectMessageSlots([
{ content: CARD },
{ role: "assistant", content: GREETING },
{ role: "user", content: NAME },
]);
assert.equal(slots.system?.content, CARD);
});
test("nothing throws on empty or malformed input", () => {
for (const input of [[], undefined, [{}, { role: "user" }]]) {
assert.doesNotThrow(() => selectMessageSlots(input as never));
}
assert.equal(selectMessageSlots([]).greeting, undefined);
});