@@ -129,14 +129,81 @@ Return ONLY a JSON object, no prose and no code fences, in exactly this shape:
129129{"memory":[{"id":"<int|new>","text":"<the resulting fact>","event":"ADD|UPDATE|DELETE|NONE"}]}
130130If nothing should change, return {"memory":[]}.`
131131
132+ // consolidationPromptV2 is a more conservative consolidation prompt. v1 lifted
133+ // the multi-hop and temporal bench categories (it reconciles changed facts in
134+ // place) but regressed single-hop by -0.10 Judge / -0.15 F1: the model would
135+ // UPDATE or DELETE facts that were already correct, or merge two distinct facts
136+ // into one less-specific statement, losing the precise token a single-hop
137+ // answer needed (bench/RESULTS.md "next levers" #1).
138+ //
139+ // v2 keeps v1's UPDATE-on-genuine-change behavior — the driver of the multi-hop
140+ // and temporal gains — but biases hard toward preserving correct facts and
141+ // forbids merging or generalizing. It must retain the opening "maintain a
142+ // person's long-term memory" phrase: the offline bench and unit-test fakes route
143+ // the consolidation call by that substring (TestConsolidationPromptsKeepRoutingPhrase).
144+ const consolidationPromptV2 = `You maintain a person's long-term memory.
145+
146+ You are given the CURRENT MEMORIES (each with a numeric id) and a set of NEW
147+ FACTS just extracted from a conversation. Decide how the new facts change the
148+ stored memory, and output one operation per change.
149+
150+ Your default stance is to PRESERVE what is already stored. Most new facts are
151+ either brand-new information (ADD) or restatements of something already known
152+ (NONE). UPDATE and DELETE are the rare, deliberate operations — use them only
153+ when a new fact unmistakably changes or contradicts one specific existing
154+ memory. When in doubt, ADD or do nothing; never overwrite or remove a correct
155+ memory on a guess.
156+
157+ EVENTS (choose exactly one per operation):
158+ - ADD: the new fact is genuinely new information not covered by any current
159+ memory. Use id "new" and put the new fact in "text". When a new fact is merely
160+ adjacent to an existing one (same topic, different detail), ADD it as its own
161+ fact rather than folding it into the existing memory.
162+ - UPDATE: the SAME attribute of the SAME entity took a new value — a move, a new
163+ job title, a changed preference, an explicitly corrected detail. Reference the
164+ existing memory's id and write the full corrected fact in "text". An UPDATE
165+ must keep every proper noun, quantity and date the original had except the one
166+ value that genuinely changed, and must stay at least as specific as the memory
167+ it replaces. Prefer UPDATE over deleting and re-adding when the same underlying
168+ fact changed.
169+ - DELETE: an existing memory is explicitly contradicted or made obsolete by the
170+ new facts and must be removed. Reference its id.
171+ - NONE: an existing memory is unaffected, or a new fact merely restates
172+ something already known. This makes no change, and is the right choice
173+ whenever you are unsure.
174+
175+ RULES
176+ - Only emit operations that change something. A current memory the new facts do
177+ not touch should simply be left alone (you may omit it, or mark it NONE).
178+ - Never invent ids. UPDATE, DELETE and NONE must reference an id that appears in
179+ CURRENT MEMORIES exactly. ADD must use the literal id "new".
180+ - Never merge two distinct memories into one, and never make a memory vaguer or
181+ drop a specific detail it already had. Two facts that merely share a topic are
182+ different memories — keep them separate.
183+ - Do not rewrite a memory that is still accurate. If it is correct, leave it
184+ (NONE) and ADD any genuinely new detail as a separate fact.
185+ - DELETE only on real contradiction or obsolescence — never just because two
186+ facts are about a similar topic.
187+ - Each resulting fact must stay self-contained and specific: resolve pronouns to
188+ names, keep proper nouns, quantities and dates — the same standard as
189+ extraction.
190+
191+ OUTPUT
192+ Return ONLY a JSON object, no prose and no code fences, in exactly this shape:
193+ {"memory":[{"id":"<int|new>","text":"<the resulting fact>","event":"ADD|UPDATE|DELETE|NONE"}]}
194+ If nothing should change, return {"memory":[]}.`
195+
132196// DefaultConsolidationVersion is the consolidation prompt version used unless
133- // WithConsolidationVersion overrides it.
197+ // WithConsolidationVersion overrides it. Held at v1 until a bench re-run shows
198+ // v2 recovers single-hop without giving back the multi-hop/temporal gains; the
199+ // flip to v2 is the decision that "gates consolidation-as-default".
134200const DefaultConsolidationVersion = "v1"
135201
136202// consolidationPrompts maps a version name to its consolidation system prompt.
137203// Separate from promptVersions on purpose (see consolidationPromptV1).
138204var consolidationPrompts = map [string ]string {
139205 "v1" : consolidationPromptV1 ,
206+ "v2" : consolidationPromptV2 ,
140207}
141208
142209// ConsolidationPromptVersions returns the registered consolidation prompt
0 commit comments