memory.*
Memory pipeline RPC methods
memory.* (and its companion dreaming.* / insights.tools) is the read / observability surface over the layered memory pipeline:
- Layer 1 —
raw_memories(raw conversation records; one row per user + assistant turn) - Layer 2 —
notes_index(compiled knowledge notes; the canonical notes-based model since the 26.6.x refactor) - Layer 3 —
notes_graph_cache(Louvain communities, similarity edges, graph-health insights)
Writes stay LLM/tool-driven; the RPC surface is intentionally read-only over Layer 1 + Layer 2, with a handful of bulk-clear endpoints that fail closed (the old "fake success on no-op" shape was deleted — see Bulk clears below).
Twelve methods are wired in register_memory_handlers (src/bin/aleph-server/commands/start/builder/handlers/memory.rs:28-268). The handler functions live in src/gateway/handlers/memory.rs; the dreaming.run_now / dreaming.list_insights / insights.tools companions are registered directly in HandlerRegistry::new().
Methods
memory.search
Search raw memories (Layer 1). Substring match against content; empty query returns recent rows in reverse-chronological order. This is the only raw-memory entry point — the previous note-search branch was removed because it duplicated graph.search and led to wrong delete_raw_memory targets in the Panel.
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | no | Substring filter; omitted = browse |
agent_id | string | no | Workspace isolation (defaults to routing::DEFAULT_AGENT_ID) |
window_title | string | no | (Reserved; not surfaced by the current model) |
limit | number | no | Defaults to 20 |
offset | number | no | Defaults to 0 (pager sizing) |
Response: { "memories": [ ...MemoryEntry... ], "total" }. Each MemoryEntry carries id, agent_id, window_title (empty), user_input (the raw content), ai_output (empty), session_id?, timestamp (created_at, epoch seconds). total is the count under the same (agent_id, query) filter — not the store-wide total, so a filter-aware pager does not show phantom pages.
memory.delete
Delete a single raw-memory row by id. Layer-1 rows have no foreign keys, so a single-row delete is safe; Layer-2 knowledge notes are unaffected.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | yes | Raw-memory id |
Response: { "ok": true } on success; INTERNAL_ERROR: No raw memory found with id '<id>' on a miss.
memory.stats
One scope for every count. scope: "global" (omitted agent_id) returns the raw + note counts only; graph counts are null because notes are per-agent and the unscoped view cannot honestly say "zero nodes".
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | no | Scope every count to one agent |
Response: { "totalMemories", "totalFacts", "validFacts", "totalGraphNodes" | null, "totalGraphEdges" | null, "scope": "agent"|"global" }. totalFacts and validFacts are equal in the current notes-based model (notes have no invalidated state).
memory.compress
Trigger a compression cycle. Requires a live CompressionService (no service ⇒ no handler).
Request: no params.
Response: { "memoriesProcessed", "factsExtracted", "factsInvalidated", "durationMs" }.
memory.listFacts
List compiled knowledge notes (Layer 2). Paginated, scoped to one agent.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | no | Defaults to routing::DEFAULT_AGENT_ID |
limit | number | no | Defaults to 50 |
offset | number | no | Defaults to 0 |
include_invalid | boolean | no | Defaults to false (no-op: notes have no invalidated state) |
Response: { "facts": [ ...FactEntry... ], "total" }. Each FactEntry carries id (path), agent_id, content (filename), fact_type (category), created_at, updated_at, category, path, tags, link_count.
memory.appList
List windows that have associated memories. The notes-based model has no per-window grouping, so this is always an empty list — kept for backward compatibility with older clients.
Request: no params.
Response: { "windows": [] }.
memory.list_corrections
List user corrections (aleph://correction/... raw rows) and their distillation status. Read-only — distillation stays LLM-driven.
The distilled flag is read from the FeedbackDistill watermark, not from is_processed. is_processed belongs to the CompressionService drain and is set within seconds of the correction landing; using it would render every row "distilled" before the dream stage actually consumed it.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | no | Defaults to routing::DEFAULT_AGENT_ID |
limit | number | no | Defaults to 50 |
include_distilled | boolean | no | Defaults to true |
Response: { "corrections": [ ...{id, content, severity, suggested_rule?, status: "distilled"|"pending", created_at}... ] }.
memory.trace
Walk a memory claim down to ground-truth evidence. Read-only; thin I/O wrapper over MemoryTraceTool::call_impl.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | no | Defaults to routing::DEFAULT_AGENT_ID |
target | string | yes | The entity / note / profile-section to walk |
kind | string | yes | One of the TraceKind variants (note / raw / profile) |
max_results | number | no | Cap the returned evidence |
Response: the full MemoryTraceTool result serialised as JSON (evidence chain by row).
memory.reembed
Start a background reembed migration (rebuild note vectors with the current embedder). Requires a live embedding provider; without one the handler returns the "missing embedding provider" error stub. Only one reembed runs at a time — a second memory.reembed returns -32001: Reembed already in progress until the first one finishes.
| Parameter | Type | Required | Description |
|---|---|---|---|
target_dim | number | no | Defaults to the current embedder's dimension |
Response: { "status": "started", "task_id": "reembed-<unix_ms>" }. Progress is published on the memory.reembed.progress topic; completion on memory.reembed.completed.
memory.reembed.cancel
Cancel a running reembed.
Response: { "status": "cancelled" } on success; -32001: No reembed task is running when no reembed is in flight.
memory.retrieve_with_trace
Run the real NoteFactRetrieval scoring pipeline and return results plus per-stage telemetry, so a debug panel can see why a fact did or did not surface.
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | yes | Search query |
limit | number | no | Max results |
agent_id | string | no | Defaults to routing::DEFAULT_AGENT_ID |
Response: ranked results + a trace array of stages, each { stage, count, elapsed_ms, scores }. Pipeline stages in order: query → candidate pool → BM25 + vector scores → RRF fusion → cutoff → ranked.
dreaming.run_now
Force-trigger a single dream cycle on the globally-registered daemon, bypassing the scheduler's window / idle / already-ran-today checks. Reserved for E2E test harnesses.
Request: no params.
Response: { "ok": true, "report": { ...DreamReport... } } on success; INTERNAL_ERROR: DreamDaemon is not initialised when memory is disabled or simulated mode (the unit-test process never has a daemon either, so this surfaces in test harnesses).
dreaming.list_insights
Read-only listing of dream insights: recent daily digests, weekly synthesis notes (category = synthesis), and dream-run audit trail with the SkillOpt evolution-gate verdict parsed from the stored JSON.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id | string | no | Defaults to routing::DEFAULT_AGENT_ID |
limit | number | no | Defaults to 30 |
Response: { "daily": [ ...{date, content, source_memory_count, created_at}... ], "synthesis": [ ...{path, title, tags, updated_at}... ], "runs": [ ...{id, pipeline_type, started_at, finished_at, duration_ms, synthesis_count, errors?, evolution?}... ] }.
insights.tools
Per-tool usage introspection over ToolInvocation raw rows. Read-only; consumed by the Panel's "tool insights" view.
Request: no params (the panel fetches its own agent_id window).
Response: ranked list of tools by activity / success rate.
Bulk clears
The two old "fakes that always returned { "deletedCount": 0 }" are gone — both now fail closed:
| Method | New behaviour |
|---|---|
memory.clear | INTERNAL_ERROR: Bulk memory clearing is not supported in the notes-based memory model. |
memory.clearFacts | INTERNAL_ERROR: Bulk note clearing is not supported; manage knowledge notes via the note_manage tool. |
memory.delete is the only legal per-row delete. Bulk deletes go through note_manage (Layer 2) or never run (Layer 1).
Built-in chat tools (companion surface)
The Panel's "Memory" tab and the LLM reach a parallel surface through builtin chat tools — they are dispatched by tools.invoke / chat.send rather than over memory.*. They are listed here for reference but the JSON-RPC surface does not call them directly.
| Tool | Purpose |
|---|---|
memory_search | Search the knowledge base for relevant facts (Layer 2) |
memory_reflect | Synthesise a coherent answer from memory instead of returning raw facts |
session_search | Search across session transcripts |
remember | Pin a fact to curated hot memory |
forget | Remove a fact from memory |
memory_status | Health + statistics for the memory system |
See Also
- Methods Reference -- All currently registered namespaces
- Memory system -- Layer 1/2/3 model
- Dreaming daemon -- The
dreaming.*scheduler