From 2419f98ccacea42163c1870a304b55fae4bb3c75 Mon Sep 17 00:00:00 2001 From: lishixiang Date: Thu, 12 Mar 2026 01:27:07 +0800 Subject: [PATCH] feat(prompts): add facet guard and length limits to memory_merge_bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'skip' decision: reject merging memories with different facets even if they share the same category, preventing semantic dilution - Add hard character limits: abstract ≤80, overview ≤200, content ≤300 - Change merge strategy from accumulate-all to condensed snapshot: conflicts resolved by keeping newer version only - Bump template version from 1.0.0 to 2.0.0 Motivation: without facet checking, the merge prompt would combine unrelated facts (e.g. 'Python code style' + 'food preferences') into a single bloated memory just because both were categorized as 'preferences'. Without length limits, merged memories grew unbounded (some exceeding 1000+ chars), causing embedding dilution and low retrieval precision in downstream vector search. --- .../compression/memory_merge_bundle.yaml | 64 +++++++++++++++---- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/openviking/prompts/templates/compression/memory_merge_bundle.yaml b/openviking/prompts/templates/compression/memory_merge_bundle.yaml index 14bc7769..d1ab862b 100644 --- a/openviking/prompts/templates/compression/memory_merge_bundle.yaml +++ b/openviking/prompts/templates/compression/memory_merge_bundle.yaml @@ -1,8 +1,8 @@ metadata: id: "compression.memory_merge_bundle" name: "Memory Merge Bundle" - description: "Merge memory and return L0/L1/L2 in one structured response" - version: "1.0.0" + description: "Merge memory and return L0/L1/L2 in one structured response, with facet guard and length limits" + version: "2.0.0" language: "en" category: "compression" @@ -46,7 +46,7 @@ variables: default: "auto" template: | - You are merging one existing memory with one new memory update. + You are deciding whether to merge two memories of the same category, or skip (keep them separate). Category: {{ category }} Target Output Language: {{ output_language }} @@ -61,26 +61,62 @@ template: | - Overview (L1): {{ new_overview }} - Content (L2): {{ new_content }} - Requirements: - - Merge into a single coherent memory. - - Keep non-conflicting details from existing memory. - - Update conflicting details to reflect the newer fact. - - Output language must be {{ output_language }}. - - Return JSON only. + ## Step 1: Facet coherence check + + Before merging, determine whether the two memories describe the SAME specific facet/topic. + + Same facet examples (should merge): + - "Python code style: no type hints" + "Python code style: concise comments" → same facet (Python code style) + - "OpenViking project: memory extraction" + "OpenViking project: added dedup" → same facet (OpenViking project) + + Different facet examples (should skip): + - "Python code style: no type hints" + "Food preference: likes apples" → different facets + - "Server 192.168.2.75: runs agent-helper" + "OpenViking project: memory extraction" → different facets + - "Git commit style: zh-CN verbs" + "Exit code semantics: 0/1/2" → different facets + + If the two memories cover DIFFERENT facets, you MUST output decision "skip". + Do NOT merge unrelated information just because they share the same category. + + ## Step 2: Merge (only if same facet) + + If merging: + - When facts conflict, keep the NEWER version only. + - Condense to essential facts. Do NOT accumulate every historical detail. + - The merged memory should read as a clean, up-to-date snapshot — not a changelog. + + ## Hard length limits - Output JSON schema: + - `abstract`: ≤ 80 characters + - `overview`: ≤ 200 characters + - `content`: ≤ 300 characters + + If the merged result would exceed these limits, aggressively summarize. + Drop older, less important details first. Preserve specific values (names, numbers, versions) over narrative. + + ## Output + + Return JSON only. Two possible decisions: + + When merging: { "decision": "merge", - "abstract": "one-line L0 summary", - "overview": "structured markdown L1 summary", - "content": "full merged L2 content", + "abstract": "one-line L0 (≤80 chars)", + "overview": "structured L1 (≤200 chars)", + "content": "condensed L2 (≤300 chars)", "reason": "short reason" } + When skipping (different facets): + { + "decision": "skip", + "reason": "short reason why these are different facets" + } + Constraints: - `abstract` must be concise and specific. - - `overview` and `content` must be non-empty. + - `overview` and `content` must be non-empty when decision is "merge". - Do not output any text outside JSON. + - Output language must be {{ output_language }}. llm_config: temperature: 0.0