diff --git a/backend/apps/memory/distill.py b/backend/apps/memory/distill.py index 4cb45db6..ad8c8423 100644 --- a/backend/apps/memory/distill.py +++ b/backend/apps/memory/distill.py @@ -56,15 +56,33 @@ async def distill_session_memory(session: AgentSession) -> List[str]: p_last_distilled[session.id] = p_user_message_count(session) aux_model = (await resolve_aux_model(global_settings, preferred_tier="haiku"))[0] client = get_anthropic_client_for_model(global_settings, aux_model) + # Deliberately harsh. The permissive version filled a real user's memory with task summaries + # ("works on an app with Slack OAuth, fullscreen modes, pinch-to-zoom") and topic echoes + # ("interested in AI agents") that were just the last thing they happened to ask about. Saying + # NOTHING costs nothing; a junk fact is paid for on every turn of every chat, forever. system_prompt = ( - "You extract durable facts about the USER from a conversation with their AI agent: " - "who they are, what they work on, standing preferences, constraints they stated. " - "Facts must be about the user themselves and still true next month; never task details, " - "never one-off requests, never anything the ASSISTANT said, never secrets, keys, or " - "passwords. Write each fact self-contained in third person, under 200 characters " - '(e.g. "Prefers concise answers with real measured numbers").\n\n' + "You maintain a small, permanent profile of the USER as a PERSON. It is read on every " + "turn of every future conversation, so a wrong or trivial entry is expensive and a " + "missing one costs nothing. Default to NOTHING.\n\n" + "SAVE only a fact that passes ALL FIVE:\n" + "1. It is about the person: who they are, their role, their tools and languages, how " + "they want to be worked with, a constraint or standing rule they set.\n" + "2. They stated or clearly demonstrated it about THEMSELVES. Never infer a trait from " + "the fact that they asked about a topic once.\n" + "3. It is still true in six months, whatever they happen to be working on then.\n" + "4. It changes how an assistant should behave in an UNRELATED future conversation.\n" + "5. It is not already obvious from whatever they are working on at the time.\n\n" + "NEVER save: what they are building or its features; anything about the current task, " + "bug, file, or request; a topic they asked about; anything the ASSISTANT said, did, or " + "suggested; anything time-bound; secrets, keys, tokens, or passwords.\n\n" + 'GOOD: "Prefers answers with real measured numbers over estimates" - ' + '"Works solo and ships releases himself" - "Writes TypeScript and Python".\n' + 'BAD: "Works on an app with Slack OAuth and pinch-to-zoom" (that is the project, not ' + 'the person) - "Interested in AI agents and LLM tooling" (that is just the topic they ' + 'raised) - "Wants a weekly news digest" (that is a request they made).\n\n' + "Write each fact self-contained, third person, under 200 characters.\n" f"Return at most {MAX_FACTS_PER_DISTILL} facts, one per line, no numbering, no quotes. " - "If the conversation reveals nothing durable, return the single word NOTHING." + "Most conversations should yield none: if in any doubt, return the single word NOTHING." ) # Show it what is already known. Without this the model re-derives facts it recorded weeks # ago, phrased differently every time, and the store's token-overlap guard cannot catch a