summaryrefslogtreecommitdiffhomepage
path: root/packages/core/tests/compaction
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-04 21:21:20 +0900
committerAdam Malczewski <[email protected]>2026-06-04 21:21:20 +0900
commit394f1ed37ce860da6fdc385769bf29f9737105cd (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /packages/core/tests/compaction
parent81a9cdbadf8c9d940d4fe9a2a0de607dee1f5f1a (diff)
downloaddispatch-394f1ed37ce860da6fdc385769bf29f9737105cd.tar.gz
dispatch-394f1ed37ce860da6fdc385769bf29f9737105cd.zip
chore: genesis — remove all files to rebuild from scratch (arch rewrite)
Diffstat (limited to 'packages/core/tests/compaction')
-rw-r--r--packages/core/tests/compaction/compaction.test.ts194
1 files changed, 0 insertions, 194 deletions
diff --git a/packages/core/tests/compaction/compaction.test.ts b/packages/core/tests/compaction/compaction.test.ts
deleted file mode 100644
index d6edd59..0000000
--- a/packages/core/tests/compaction/compaction.test.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import { describe, expect, it } from "vitest";
-import {
- buildCompactionPrompt,
- buildCompactionRequest,
- buildSummaryTurnText,
- DEFAULT_TAIL_TURNS,
- extractPreviousSummary,
- renderTranscript,
- SUMMARY_MARKER,
- SUMMARY_TEMPLATE,
- selectHeadTail,
-} from "../../src/compaction/index.js";
-import type { ChatMessage } from "../../src/types/index.js";
-
-function user(text: string): ChatMessage {
- return { role: "user", chunks: [{ type: "text", text }] };
-}
-function assistant(text: string): ChatMessage {
- return { role: "assistant", chunks: [{ type: "text", text }] };
-}
-
-describe("selectHeadTail", () => {
- it("returns empty head when turns <= tailTurns (nothing to compact)", () => {
- const msgs = [user("u1"), assistant("a1"), user("u2"), assistant("a2")];
- const { head, tail } = selectHeadTail(msgs, 2);
- expect(head).toEqual([]);
- expect(tail).toEqual(msgs);
- });
-
- it("keeps the last N turns verbatim and summarizes the rest", () => {
- const msgs = [
- user("u1"),
- assistant("a1"),
- user("u2"),
- assistant("a2"),
- user("u3"),
- assistant("a3"),
- ];
- const { head, tail } = selectHeadTail(msgs, 2);
- expect(tail[0]).toBe(msgs[2]);
- expect(tail.at(-1)).toBe(msgs[5]);
- expect(head).toEqual([msgs[0], msgs[1]]);
- });
-
- it("a turn includes trailing assistant/tool messages up to the next user", () => {
- const msgs = [user("u1"), assistant("a1a"), assistant("a1b"), user("u2"), assistant("a2")];
- const { head, tail } = selectHeadTail(msgs, 1);
- expect(head).toEqual([msgs[0], msgs[1], msgs[2]]);
- expect(tail).toEqual([msgs[3], msgs[4]]);
- });
-
- it("tailTurns<=0 → everything is head", () => {
- const msgs = [user("u1"), assistant("a1")];
- expect(selectHeadTail(msgs, 0)).toEqual({ head: msgs, tail: [] });
- });
-
- it("defaults to DEFAULT_TAIL_TURNS", () => {
- const msgs = [user("u1"), user("u2"), user("u3")];
- const def = selectHeadTail(msgs);
- const explicit = selectHeadTail(msgs, DEFAULT_TAIL_TURNS);
- expect(def).toEqual(explicit);
- });
-});
-
-describe("buildCompactionPrompt", () => {
- it("creates a fresh-summary instruction without a previous summary", () => {
- const p = buildCompactionPrompt({});
- expect(p).toContain("Create a new anchored summary");
- expect(p).toContain(SUMMARY_TEMPLATE);
- expect(p).not.toContain("<previous-summary>");
- });
-
- it("anchors on a previous summary when provided", () => {
- const p = buildCompactionPrompt({ previousSummary: "## Goal\n- old" });
- expect(p).toContain("Update the anchored summary");
- expect(p).toContain("<previous-summary>");
- expect(p).toContain("## Goal\n- old");
- expect(p).toContain(SUMMARY_TEMPLATE);
- });
-});
-
-describe("extractPreviousSummary", () => {
- it("returns undefined when the first user message is not a seeded summary", () => {
- expect(extractPreviousSummary([user("hello"), assistant("hi")])).toBeUndefined();
- });
-
- it("extracts the body of a seeded summary turn (marker stripped)", () => {
- const seeded = user(buildSummaryTurnText("## Goal\n- build X"));
- expect(extractPreviousSummary([seeded, assistant("ok")])).toBe("## Goal\n- build X");
- });
-});
-
-describe("renderTranscript", () => {
- it("renders user/assistant text blocks", () => {
- const t = renderTranscript([user("hello"), assistant("hi there")]);
- expect(t).toContain("## User\nhello");
- expect(t).toContain("## Assistant\nhi there");
- });
-
- it("renders tool calls and caps long tool results", () => {
- const big = "x".repeat(5000);
- const msg: ChatMessage = {
- role: "assistant",
- chunks: [
- {
- type: "tool-batch",
- calls: [{ id: "c1", name: "read_file", arguments: { path: "a" }, result: big }],
- },
- ],
- };
- const t = renderTranscript([msg], 2000);
- expect(t).toContain('[tool read_file {"path":"a"}]');
- expect(t).toContain("chars truncated for summary");
- expect(t.length).toBeLessThan(5000 + 200);
- });
-
- it("skips a seeded prior-summary user turn", () => {
- const seeded = user(buildSummaryTurnText("## Goal\n- prior"));
- const t = renderTranscript([seeded, assistant("work")]);
- expect(t).not.toContain("prior");
- expect(t).toContain("## Assistant\nwork");
- });
-
- it("omits thinking/error/system chunks", () => {
- const msg: ChatMessage = {
- role: "assistant",
- chunks: [
- { type: "thinking", text: "secret reasoning" },
- { type: "text", text: "visible" },
- { type: "error", message: "boom" },
- ],
- };
- const t = renderTranscript([msg]);
- expect(t).toContain("visible");
- expect(t).not.toContain("secret reasoning");
- expect(t).not.toContain("boom");
- });
-});
-
-describe("buildCompactionRequest", () => {
- it("returns no prompt when there is nothing to compact", () => {
- const msgs = [user("u1"), assistant("a1")];
- const req = buildCompactionRequest({ messages: msgs, tailTurns: 2 });
- expect(req.prompt).toBeUndefined();
- expect(req.head).toEqual([]);
- expect(req.tail).toEqual(msgs);
- });
-
- it("builds a prompt with transcript + instruction and exposes head/tail", () => {
- const msgs = [
- user("first task"),
- assistant("did stuff"),
- user("second"),
- assistant("more"),
- user("third"),
- assistant("done"),
- ];
- const req = buildCompactionRequest({ messages: msgs, tailTurns: 2 });
- expect(req.prompt).toBeDefined();
- expect(req.prompt).toContain("first task");
- expect(req.prompt).toContain("Create a new anchored summary");
- expect(req.tail[0]).toBe(msgs[2]);
- expect(req.head[0]).toBe(msgs[0]);
- });
-
- it("anchors on a prior seeded summary", () => {
- const msgs = [
- user(buildSummaryTurnText("## Goal\n- old goal")),
- assistant("ack"),
- user("new work"),
- assistant("did new"),
- user("more work"),
- assistant("did more"),
- ];
- const req = buildCompactionRequest({ messages: msgs, tailTurns: 2 });
- expect(req.previousSummary).toBe("## Goal\n- old goal");
- expect(req.prompt).toContain("Update the anchored summary");
- // head = [seeded-summary, "ack"]; seeded summary is skipped in the
- // transcript, so "ack" represents the summarized head. "new work" lives
- // in the preserved tail (last 2 turns), not the summary body.
- expect(req.prompt).toContain("ack");
- expect(
- req.tail.some((m) => m.chunks.some((c) => c.type === "text" && c.text === "new work")),
- ).toBe(true);
- });
-});
-
-describe("buildSummaryTurnText", () => {
- it("prefixes the marker so a later compaction can anchor", () => {
- const seeded = buildSummaryTurnText("## Goal\n- x");
- expect(seeded.startsWith(SUMMARY_MARKER)).toBe(true);
- expect(extractPreviousSummary([user(seeded)])).toBe("## Goal\n- x");
- });
-});