Module: Rubino::Memory::SqliteExtractionPrompt
- Defined in:
- lib/rubino/memory/sqlite_extraction_prompt.rb
Overview
The single aux-LLM extraction prompt for the Sqlite backend. Collapses Zep’s six-step ingestion (entity/fact/temporal extraction + invalidation) into ONE structured call: given the latest turn and the currently-live facts, the model returns durable atomic facts to ‘add` and contradicted facts to `supersede`. The doctrine (“durable declarative facts, not imperatives, not stale artifacts”) is lifted from the reference MEMORY_GUIDANCE.
Constant Summary collapse
- KINDS =
%w[user_profile preference project fact env].freeze
- SYSTEM =
<<~PROMPT You maintain a long-term memory of durable facts about the user and their project. You will see the latest conversation turn and the facts already in memory. Extract only DURABLE facts worth remembering across sessions: - user identity, preferences, and recurring corrections (highest value — they reduce future steering) - stable project/environment conventions and tool quirks Write each as ONE atomic declarative fact in the third person, present tense. GOOD: "User prefers concise answers without preamble." GOOD: "Project uses pytest with the xdist plugin." BAD (imperative): "Always answer concisely." BAD (procedure): "Run tests with pytest -n 4." BAD (stale artifact): "Fixed bug #4821." "Opened PR 90." "Phase 2 done." If a fact will be stale within a week (PR/issue/commit numbers, task progress, TODO state), DO NOT save it. Procedures and how-to workflows are NOT memory — skip them. SUPERSEDE: if a new fact CONTRADICTS an existing one (same subject, changed value), emit it under "supersede" with the id of the fact it replaces. Prefer the newer information. Tag each fact with 1-4 lowercase entity keywords (people, tools, projects) for retrieval. EDGES (optional, light): if the turn states a clear RELATIONSHIP between two of the entities you tagged, emit it under "edges" as {"src","relation","dst"} with a short lowercase relation (e.g. uses, deploys_to, written_in, runs_on, depends_on). Keep it to the few obvious relations the turn actually asserts — do not invent links. These let a later query like "what does X use for Y" reach the connected fact. Omit when unsure. Return STRICT JSON, no prose: { "add": [ {"text": "...", "kind": "preference|user_profile|project|fact|env", "entities": ["..."], "valid_from": "<ISO8601 or null>"} ], "supersede": [ {"id": "<existing fact id>", "by_text": "...", "kind": "...", "entities": ["..."]} ], "edges": [ {"src": "...", "relation": "...", "dst": "..."} ] } If nothing is worth saving, return {"add": [], "supersede": [], "edges": []}. PROMPT
Class Method Summary collapse
-
.user_message(now:, live_facts:, turn:) ⇒ Object
Builds the USER message: reference timestamp, the live fact set (already char-capped by the caller), and the latest turn rendered as a transcript.
Class Method Details
.user_message(now:, live_facts:, turn:) ⇒ Object
Builds the USER message: reference timestamp, the live fact set (already char-capped by the caller), and the latest turn rendered as a transcript.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rubino/memory/sqlite_extraction_prompt.rb', line 52 def (now:, live_facts:, turn:) live = if live_facts.empty? "(none)" else live_facts.map { |f| "#{f[:id]} | #{f[:kind]} | #{f[:text]}" }.join("\n") end <<~MSG Reference timestamp: #{now} Existing live facts: #{live} Latest turn: #{turn} MSG end |