* feat: ai sdk integration * more fixes * fix(security): mental model refresh tag-based security - Mental model refresh now passes tags with all_strict matching - Consolidation only triggers refresh for mental models with matching tags - Consolidation filters related observations by tags (all_strict) - Added tests to verify tag-based security boundaries - Updated OpenAPI spec to include tags and text_preview in list_documents - Added tags column to documents UI table * chore: regenerate OpenAPI spec after rebase * fix: improve consolidation prompt for contradiction handling and mental model refresh security - Enhanced consolidation prompt to be more explicit about capturing temporal changes in contradictions - Fixed mental model refresh security: tagged memories now only trigger refresh of mental models with matching tags - Added stricter tag filtering to prevent cross-scope mental model refreshes Fixes test_consolidation_merges_contradictions by improving LLM instructions to use temporal markers like "used to X, now Y" when merging contradictory facts. Note: test_refresh_with_tags_only_accesses_same_tagged_models still needs investigation - REFLECT operation may need additional tag filtering. * fix: mental model refresh security - proper tag filtering in search Fixed tool_search_mental_models to properly handle all_strict tag matching mode by using the centralized build_tags_where_clause function. Previously, the function only handled "all" vs "any" modes and always included untagged mental models when using non-"all" modes. This ensures that when a tagged mental model is refreshed with all_strict matching, it cannot access untagged mental models, preventing cross-scope information leakage. Fixes test_refresh_with_tags_only_accesses_same_tagged_models. Note: test_sensory_dimension_preservation is failing but this is a pre-existing issue on main branch - the LLM model (gpt-oss-20b) is not extracting facts from sensory text. Not related to security changes. * chore: apply formatting from pre-commit hook * fix: allow untagged mental models to be refreshed by any consolidation Untagged mental models are considered "global" and should be refreshed by any consolidation, regardless of whether tagged or untagged memories were consolidated. This maintains security boundaries while allowing global mental models to stay fresh. When tagged memories are consolidated: - Refresh mental models with matching tags (security boundary) - Also refresh untagged mental models (they're global) - DO NOT refresh mental models with different tags When untagged memories are consolidated: - Only refresh untagged mental models - DO NOT refresh tagged mental models (security boundary) Fixes test_consolidation_only_refreshes_matching_tagged_models.
80 lines
3.7 KiB
Python
80 lines
3.7 KiB
Python
"""Prompts for the consolidation engine."""
|
|
|
|
CONSOLIDATION_SYSTEM_PROMPT = """You are a memory consolidation system. Your job is to convert facts into durable knowledge (observations) and merge with existing knowledge when appropriate.
|
|
|
|
You must output ONLY valid JSON with no markdown formatting, no code blocks, and no additional text.
|
|
|
|
## EXTRACT DURABLE KNOWLEDGE, NOT EPHEMERAL STATE
|
|
Facts often describe events or actions. Extract the DURABLE KNOWLEDGE implied by the fact, not the transient state.
|
|
|
|
Examples of extracting durable knowledge:
|
|
- "User moved to Room 203" -> "Room 203 exists" (location exists, not where user is now)
|
|
- "User visited Acme Corp at Room 105" -> "Acme Corp is located in Room 105"
|
|
- "User took the elevator to floor 3" -> "Floor 3 is accessible by elevator"
|
|
- "User met Sarah at the lobby" -> "Sarah can be found at the lobby"
|
|
|
|
DO NOT track current user position/state as knowledge - that changes constantly.
|
|
DO track permanent facts learned from the user's actions.
|
|
|
|
## PRESERVE SPECIFIC DETAILS
|
|
Keep names, locations, numbers, and other specifics. Do NOT:
|
|
- Abstract into general principles
|
|
- Generate business insights
|
|
- Make knowledge generic
|
|
|
|
GOOD examples:
|
|
- Fact: "John likes pizza" -> "John likes pizza"
|
|
- Fact: "Alice works at Google" -> "Alice works at Google"
|
|
|
|
BAD examples:
|
|
- "John likes pizza" -> "Understanding dietary preferences helps..." (TOO ABSTRACT)
|
|
- "User is at Room 203" -> "User is currently at Room 203" (EPHEMERAL STATE)
|
|
|
|
## MERGE RULES (when comparing to existing observations):
|
|
1. REDUNDANT: Same information worded differently → update existing
|
|
2. CONTRADICTION: Opposite information about same topic → update with temporal markers showing change
|
|
Example: "Alex used to love pizza but now hates it" OR "Alex's pizza preference changed from love to hate"
|
|
3. UPDATE: New state replacing old state → update showing the transition with "used to", "now", "changed from X to Y"
|
|
|
|
## CRITICAL RULES:
|
|
- NEVER merge facts about DIFFERENT people
|
|
- NEVER merge unrelated topics (food preferences vs work vs hobbies)
|
|
- When merging contradictions, the "text" field MUST capture BOTH states with temporal markers:
|
|
* Use "used to X, now Y" OR "changed from X to Y" OR "X but now Y"
|
|
* DO NOT just state the new fact - you MUST show the change
|
|
- Keep observations focused on ONE specific topic per person
|
|
- The "text" field MUST contain durable knowledge, not ephemeral state
|
|
- Do NOT include "tags" in output - tags are handled automatically"""
|
|
|
|
CONSOLIDATION_USER_PROMPT = """Analyze this new fact and consolidate into knowledge.
|
|
{mission_section}
|
|
NEW FACT: {fact_text}
|
|
|
|
EXISTING OBSERVATIONS (JSON array with source memories and dates):
|
|
{observations_text}
|
|
|
|
Each observation includes:
|
|
- id: unique identifier for updating
|
|
- text: the observation content
|
|
- proof_count: number of supporting memories
|
|
- tags: visibility scope (handled automatically)
|
|
- created_at/updated_at: when observation was created/modified
|
|
- occurred_start/occurred_end: temporal range of source facts
|
|
- source_memories: array of supporting facts with their text and dates
|
|
|
|
Instructions:
|
|
1. Extract DURABLE KNOWLEDGE from the new fact (not ephemeral state)
|
|
2. Review source_memories in existing observations to understand evidence
|
|
3. Check dates to detect contradictions or updates
|
|
4. Compare with observations:
|
|
- Same topic → UPDATE with learning_id
|
|
- New topic → CREATE new observation
|
|
- Purely ephemeral → return []
|
|
|
|
Output JSON array of actions:
|
|
[
|
|
{{"action": "update", "learning_id": "uuid-from-observations", "text": "updated knowledge", "reason": "..."}},
|
|
{{"action": "create", "text": "new durable knowledge", "reason": "..."}}
|
|
]
|
|
|
|
Return [] if fact contains no durable knowledge."""
|