Files
writing-agent/tests/context-outline.test.ts
T
chenmoranzhiandCursor bb4f934b3d 补齐缓存写量与请求轮廓记账,便于核对提示缓存是否真的命中。
给用量行挂上轮次步骤和分段字数,统计页能看出缓存断在哪。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-07 23:47:51 +08:00

115 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "vitest";
import {
annotateCacheBreaks,
firstCacheBreak,
outlineRequest,
} from "../src/llm/context-outline.js";
const sample = [
"规则开头",
"",
"## 写入规则",
"固定规则",
"",
"## 更早的对话",
"",
"【用户】",
"第一句",
"",
"【助手】",
"回过",
"",
"## 当前产物(已写入黑板)",
"",
"### 设计.氛围 〔order=0〕",
"雨",
"",
"### 设计.角色 〔order=1〕",
"甲",
"",
"## 本轮注入",
"",
"### topology @ 3",
"#### task",
"做一件事",
"",
"## 本轮",
"",
"方案进度",
"",
"最后一轮用户输入",
"再改一下",
].join("\n");
describe("outlineRequest", () => {
it("按标题、对话轮次和最后一轮输入切开,不留下正文", () => {
const segments = outlineRequest([
{ role: "system", content: sample.slice(0, sample.indexOf("## 更早的对话")) },
{ role: "user", content: sample.slice(sample.indexOf("## 更早的对话")) },
]);
expect(segments.map((item) => item.tag)).toEqual([
"规则",
"写入规则",
"更早的对话",
"更早·用户",
"更早·助手",
"当前产物",
"设计.氛围",
"设计.角色",
"本轮注入",
"topology",
"task",
"本轮",
"最后一轮用户输入",
]);
expect(JSON.stringify(segments)).not.toContain("再改一下");
expect(JSON.stringify(segments)).not.toContain("雨");
const again = outlineRequest([
{ role: "system", content: sample.slice(0, sample.indexOf("## 更早的对话")) },
{ role: "user", content: sample.slice(sample.indexOf("## 更早的对话")) },
]);
expect(again.map((item) => item.hash)).toEqual(segments.map((item) => item.hash));
});
it("工具定义放在正文之前", () => {
const segments = outlineRequest(
[{ role: "user", content: "你好" }],
[
{
type: "function",
function: { name: "insert", description: "写", parameters: {} },
},
],
);
expect(segments.map((item) => item.tag)).toEqual(["工具", "用户"]);
});
});
describe("firstCacheBreak", () => {
it("标出第一处标签或哈希不同的位置", () => {
const prev = outlineRequest([{ role: "user", content: sample.slice(sample.indexOf("## 更早的对话")) }]);
const changed = sample.replace("雨", "雪");
const next = outlineRequest([{ role: "user", content: changed.slice(changed.indexOf("## 更早的对话")) }]);
const index = firstCacheBreak(prev, next);
expect(next[index]?.tag).toBe("设计.氛围");
expect(firstCacheBreak(prev, prev)).toBe(-1);
expect(firstCacheBreak(prev, prev.slice(0, 3))).toBe(-1);
expect(firstCacheBreak(prev.slice(0, 3), prev)).toBe(3);
});
});
describe("annotateCacheBreaks", () => {
it("按同会话时间比较,窗口里第一条算冷启动", () => {
const a = outlineRequest([{ role: "user", content: "第一" }]);
const b = outlineRequest([{ role: "user", content: "第二" }]);
const marks = annotateCacheBreaks([
{ id: "2", at: "2026-10-02T02:00:00.000Z", sessionId: "s", segments: b },
{ id: "1", at: "2026-10-02T01:00:00.000Z", sessionId: "s", segments: a },
{ id: "9", at: "2026-10-02T03:00:00.000Z", sessionId: "other", segments: a },
]);
expect(marks.get("1")).toMatchObject({ cold: true, matched: 0 });
expect(marks.get("2")).toMatchObject({ cold: false, breakAt: 0, tag: "用户", matched: 0 });
expect(marks.get("9")?.cold).toBe(true);
});
});