feat: rolling conversation summary + session continuity

- 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).
This commit is contained in:
2026-08-19 10:23:56 -04:00
parent 56d6f355d1
commit 534b51b41b
7 changed files with 175 additions and 26 deletions
+33
View File
@@ -0,0 +1,33 @@
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:"));
});