- Backend emits session id in SSE; frontend sets activeChat so follow-ups reuse the same session (fixes fragmented history). - sessions.summary column; messages past RECENT_LIMIT (10) are folded into a persisted summary via a non-streaming model call. - buildMessages sends system(+summary) + last 10 messages, bounding context while preserving long-range memory. - Tests: aiMessages (capping + summary injection).
34 lines
1.4 KiB
JavaScript
34 lines
1.4 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { buildMessages, RECENT_LIMIT } from "../src/services/ai.js";
|
|
|
|
function msg(role, i) {
|
|
return { id: String(i), session_id: "s", role, text: `${role}-${i}`, created_at: new Date(i).toISOString() };
|
|
}
|
|
|
|
test("caps message history to the recent window", () => {
|
|
const history = Array.from({ length: RECENT_LIMIT + 5 }, (_, i) => msg(i % 2 ? "assistant" : "user", i));
|
|
const built = buildMessages(history, "Grade 10", "math", "c", "");
|
|
// system + RECENT_LIMIT messages
|
|
assert.equal(built.length, 1 + RECENT_LIMIT);
|
|
assert.equal(built[0].role, "system");
|
|
// the newest message is included
|
|
assert.equal(built[built.length - 1].content, "user-" + (RECENT_LIMIT + 4));
|
|
// the oldest message is dropped
|
|
assert.ok(!built.some((m) => m.content === "user-0"));
|
|
});
|
|
|
|
test("injects the summary into the system prompt when present", () => {
|
|
const history = [msg("user", 0), msg("assistant", 1)];
|
|
const built = buildMessages(history, "Grade 6", "english", "c5", "Student is in Grade 6 English.");
|
|
assert.equal(built[0].role, "system");
|
|
assert.ok(built[0].content.includes("Student is in Grade 6 English."));
|
|
// still includes the messages
|
|
assert.equal(built.length, 3);
|
|
});
|
|
|
|
test("does not inject an empty summary", () => {
|
|
const built = buildMessages([msg("user", 0)], "g", "s", "c", "");
|
|
assert.ok(!built[0].content.includes("Earlier in this conversation:"));
|
|
});
|