Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/compressor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ function makeSummaryBlock(summaryText: string, round?: number): MessageBlock {
return block;
}

/** 统计子串出现次数,用于断言 P2 不会把同一段摘要重复拼接。 */
function countOccurrences(text: string, needle: string): number {
return text.split(needle).length - 1;
}

// ---------------------------------------------------------------------------
// P0 衰减压缩
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -562,6 +567,33 @@ describe("compactHistory (P2)", () => {
const content = (summaryBlock.user as { content: string }).content;
// 第二次 summary 应该包含第一次 summary 的内容
expect(content).toContain("[Context Summary]");
// 但不能同时从 lastSummary 闭包和 summary block 各拼一次。
expect(countOccurrences(content, "User: q1")).toBe(1);
}
});

it("does not duplicate cached summary when raw history is compacted again", () => {
const compressor = createContextCompressor({ compactKeepRecent: 1 });

// prepareMessages 路径只压缩本次请求视图,不会把 summary 写回 history。
// 因此第二次压缩时传入的仍是完整原始 history;如果再拼 lastSummary,
// q1/q2 会既来自闭包摘要,又来自原始 oldBlocks,造成重复膨胀。
compressor.compactHistory([
makeTextBlock("q1", "a1", 1),
makeTextBlock("q2", "a2", 2),
]);

const result = compressor.compactHistory([
makeTextBlock("q1", "a1", 1),
makeTextBlock("q2", "a2", 2),
makeTextBlock("q3", "a3", 3),
]);

const summaryBlock = result.blocks[0]!;
if (summaryBlock.type === "summary") {
const content = (summaryBlock.user as { content: string }).content;
expect(countOccurrences(content, "User: q1")).toBe(1);
expect(countOccurrences(content, "User: q2")).toBe(1);
}
});

Expand Down
13 changes: 6 additions & 7 deletions src/compressor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,6 @@ export function createContextCompressor(
// 按类型遍历旧块,提取关键信息构建摘要文本
const summaryLines: string[] = [];

// 如果之前已有摘要,先加入,实现多层摘要的级联压缩
if (lastSummary) {
summaryLines.push(lastSummary);
summaryLines.push("---");
}

for (const block of oldBlocks) {
if (block.type === "text") {
const userContent = block.user ? extractText(block.user) : "";
Expand Down Expand Up @@ -386,7 +380,12 @@ export function createContextCompressor(
}
});
} else if (block.type === "summary") {
// 之前的 summary 块:保留其文本,纳入新摘要
// 之前的 summary 块:保留其文本,纳入新摘要。
// 注意:lastSummary 只作为 getState() 的状态快照,不再作为摘要输入源。
// compactHistory(blocks) 的语义是“总结本次传入的完整 block 视图”:
// - prepareMessages 路径不会写回 history,下一次传入的 blocks 仍包含原始旧消息;
// - recovery 写回路径会把旧摘要作为 summary block 放回 history。
// 如果再额外拼闭包缓存,就会把同一段旧摘要重复写入新 summary。
summaryLines.push(extractText(block.user));
}
}
Expand Down
Loading