Skip to content

Commit b21347c

Browse files
committed
fix: tighten compaction memory candidate prompt
1 parent ffb0477 commit b21347c

2 files changed

Lines changed: 44 additions & 31 deletions

File tree

src/plugin.ts

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -108,45 +108,37 @@ function buildCompactionPrompt(privateContext: string): string {
108108
"",
109109
"## Relevant Files",
110110
"",
111-
"At the end of the summary, extract durable memory entries for future sessions.",
111+
"At the end of the summary, include a Memory candidates section only if there are durable facts that will change future behavior.",
112112
"",
113-
"Memory quality bar:",
114-
"Extract only durable facts that will change future behavior: user preferences, decisions with rationale, stable constraints, or hard-to-rediscover references.",
115-
"",
116-
"Do not extract trivia: transient IDs/revisions, task progress, test/file counts, bare status updates, local UI details, or facts easily rediscovered from the repo.",
117-
"",
118-
"When unsure, skip it. Fewer high-signal memories are better than many low-value ones.",
113+
"CRITICAL MEMORY RULES:",
114+
"- Most compactions should produce ZERO memories. Empty is correct when nothing durable changed.",
115+
"- NO completion or progress statements: do not extract completed work, passing tests, commits, PR status, wave/task/phase completion, or current state.",
116+
"- NO session-internal implementation notes: do not extract what files were edited, what bug was just fixed, what command just ran, or what the assistant reviewed.",
117+
"- feedback ONLY means stable user preferences or user instructions, written in imperative/future-facing form.",
118+
"- decision ONLY means rules that apply to FUTURE work, not decisions already implemented in this session.",
119+
"- project/reference ONLY when the fact is stable across sessions and hard to rediscover from the repository.",
120+
"- If unsure, skip it.",
119121
"",
120122
"Good memory examples:",
121123
"- [feedback] User prefers architecture reviews in Traditional Chinese.",
122-
"- [decision] Use frozen workspace memory snapshots plus ephemeral hot state for cache stability.",
123-
"- [project] The plugin should piggyback memory extraction on OpenCode compaction and avoid extra LLM calls.",
124-
"- [reference] Workspace memory appears in frozen system[1]; pending memories appear in hot session state until compaction.",
124+
"- [decision] Do not add semantic merge to memory dedupe.",
125+
"- [project] This repository is an OpenCode plugin using local JSON stores.",
126+
"- [reference] Workspace memory is rendered as frozen system[1]; pending memories remain in hot state until compaction.",
125127
"",
126128
"Bad memory examples to skip:",
127-
"- 42 tests passed.",
128129
"- Wave 2 completed successfully.",
129-
"- Modified 5 files.",
130-
"- commit 4309cb8 contains the latest fix.",
131-
"- TypeError: Cannot read properties of undefined.",
132-
"- Currently running npm test.",
133-
"",
134-
"A memory should still be useful if a new agent opens this workspace next week.",
135-
"",
136-
"Only extract facts that are likely to stay true across sessions.",
137-
"Do not extract session-specific progress like exact test counts, file counts, or phase numbers.",
138-
"For progress, extract the stable goal or durable milestone, not the current number.",
139-
"For references, extract configuration values that do not usually change between sessions.",
140-
"For feedback, extract unresolved issues or user preferences that future sessions need to know.",
141-
"Use exactly this candidate format, including square brackets around the type:",
130+
"- 180 tests passed and CI is green.",
131+
"- Implemented owner-aware cleanup in plugin.ts.",
132+
"- The assistant reviewed code reviewer feedback and updated the plan.",
133+
"- Commit a762e86 contains the owner scope fix.",
142134
"",
135+
"Format when there ARE durable memories:",
143136
"Memory candidates:",
144-
"- [feedback] content",
145-
"- [project] content",
146-
"- [decision] content",
147-
"- [reference] content",
137+
"- [feedback|decision|project|reference] future-facing durable fact",
148138
"",
149-
"Do not write '- project content'; write '- [project] content'.",
139+
"Format when there are NO durable memories:",
140+
"Memory candidates:",
141+
"(none)",
150142
"",
151143
"Background context, use this to inform the summary above.",
152144
"Do not output this context verbatim:",

tests/plugin.test.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,9 @@ test("compaction hook sets output.prompt with ---free template", async () => {
297297
"Prompt should include concrete positive memory examples");
298298
assert.equal(prompt!.includes("Bad memory examples to skip:"), true,
299299
"Prompt should include concrete negative memory examples");
300-
assert.equal(prompt!.includes("42 tests passed"), true,
300+
assert.equal(prompt!.includes("180 tests passed"), true,
301301
"Prompt should explicitly reject test-count snapshots");
302-
assert.equal(prompt!.includes("commit 4309cb8"), true,
302+
assert.equal(prompt!.includes("Commit a762e86"), true,
303303
"Prompt should explicitly reject commit-hash snapshots");
304304

305305
// Should contain our context data (hot session state)
@@ -317,6 +317,27 @@ test("compaction hook sets output.prompt with ---free template", async () => {
317317
}
318318
});
319319

320+
test("compaction prompt forbids progress and session-internal memory candidates", async () => {
321+
const tmpDir = await mkdtemp(join(tmpdir(), "memory-plugin-prompt-"));
322+
try {
323+
const plugin = await MemoryV2Plugin({ directory: tmpDir, client: mockRootClient() });
324+
const output = { prompt: "", context: [] as string[] };
325+
326+
await (plugin as Record<string, Function>)["experimental.session.compacting"](
327+
{ sessionID: "prompt-session", model: {} },
328+
output,
329+
);
330+
331+
assert.match(output.prompt, /CRITICAL MEMORY RULES/);
332+
assert.match(output.prompt, /NO completion or progress statements/i);
333+
assert.match(output.prompt, /NO session-internal implementation notes/i);
334+
assert.match(output.prompt, /feedback ONLY/i);
335+
assert.match(output.prompt, /Most compactions should produce ZERO memories/i);
336+
} finally {
337+
await rm(tmpDir, { recursive: true, force: true });
338+
}
339+
});
340+
320341
test("compaction hook merges existing output.context from other plugins", async () => {
321342
const tmpDir = await mkdtemp(join(tmpdir(), "memory-plugin-test-"));
322343

0 commit comments

Comments
 (0)