diff --git a/navi/core/compressor.py b/navi/core/compressor.py index 549a0de..dcd1723 100644 --- a/navi/core/compressor.py +++ b/navi/core/compressor.py @@ -19,7 +19,8 @@ _SUMMARIZE_SYSTEM = ( "You are summarizing a conversation history to free up context space. " "The assistant will continue working using ONLY this summary — it will have no access " - "to the original messages. Be thorough and precise. Prefer specifics over generalities.\n\n" + "to the original messages. Be thorough and precise. Prefer specifics over generalities. " + "This summary is historical context, not a new user request.\n\n" "## Current goal\n" "What the user is trying to accomplish in this session. Include any stated deadlines, " "constraints, or acceptance criteria.\n\n" @@ -32,9 +33,10 @@ "(port numbers, file paths, config keys, IDs) — do not paraphrase if precision matters.\n\n" "## Outputs\n" "Every file created or modified (full paths). Every config value set. " - "Commands run and their output (include verbatim if relevant). " - "Code snippets, SQL, configs, or other artifacts produced — include verbatim if short, " - "summarize with key details if long.\n\n" + "Commands run and their outcome. Preserve exact command output only when it is short " + "and needed to prove a result or diagnose an error. " + "Do not preserve tool-call-like examples with parenthesized arguments; describe tool " + "usage in words or as key/value facts instead.\n\n" "## Errors\n" "Failures, exceptions, or unexpected results encountered. " "How each was resolved — or that it remains unresolved.\n\n" @@ -42,6 +44,8 @@ "Corrections the user made to the assistant's approach. Explicit style or behavior " "preferences stated during this session. Things the user said not to do.\n\n" "Do not include greetings, filler, transitions, or meta-commentary about the summary itself. " + "Do not use Markdown code fences or inline-code backticks unless preserving a user-authored " + "literal value is essential. " "Write in tight prose or bullet points — whatever preserves more information per token." ) @@ -120,12 +124,12 @@ # Render tool calls + their results as a compact block for tc in m.tool_calls: args_preview = json.dumps(tc.arguments)[:120] - lines.append(f"[Called tool `{tc.name}` with {args_preview}]") + lines.append(f"[Tool call: {tc.name}; arguments preview: {args_preview}]") i += 1 while i < len(messages) and messages[i].role == "tool": result = messages[i].content or "" preview = result[:300] + ("…" if len(result) > 300 else "") - lines.append(f"[Tool `{messages[i].name}` returned: {preview}]") + lines.append(f"[Tool result: {messages[i].name}; preview: {preview}]") i += 1 elif m.role == "assistant" and m.content: @@ -190,7 +194,7 @@ summary_msg = Message( role="user", - content=f"[Context Summary]\n{summary_text}", + content=f"[Context Summary - historical context only, not a new user request]\n{summary_text}", is_summary=True, created_at=datetime.now(timezone.utc), ) diff --git a/navi/memory/extractor.py b/navi/memory/extractor.py index 6351fdb..000faee 100644 --- a/navi/memory/extractor.py +++ b/navi/memory/extractor.py @@ -30,9 +30,13 @@ - Topics that were discussed or questions that were asked - Temporary states ("was tired", "was busy today") - Information about third parties that isn't about the user -- Facts you already know from earlier turns (avoid duplicates) +- Directory-specific project notes, one-off commands, file paths, task progress, or local quirks + that belong in NAVI.md instead of long-term user memory +- Duplicate facts already present in the transcript -Return a JSON array — empty [] if nothing new to extract: +Return ONLY a valid JSON array. No markdown, no prose, no comments. +Return empty [] if nothing new should be extracted. +Schema: [ {"category": "profile", "key": "name", "value": "Eugene"}, {"category": "technical", "key": "primary_os", "value": "Arch Linux"}, @@ -46,7 +50,9 @@ Summarize the facts below in 2-4 short paragraphs (max 400 words). Write from the assistant's perspective: what you know about the user. Be specific and concrete. Cover the most important identifying details first, -then preferences and ongoing context.""" +then preferences and ongoing context. +Do not add facts not present below. Do not include task progress, local directory notes, +or one-off commands; those belong in NAVI.md, not user memory.""" async def extract_and_update( @@ -108,6 +114,8 @@ if not isinstance(fact, dict): continue category = str(fact.get("category", "other")).strip().lower() + if category not in {"profile", "preferences", "technical", "projects", "other"}: + category = "other" key = str(fact.get("key", "")).strip() value = str(fact.get("value", "")).strip() if key and value: