跳到內容

Memory architecture

本頁內容尚未翻譯。

This page is the single end-to-end map for durable agent memory. It covers the write-side and lifecycle contracts owned by Memory Improvement Spec A. The retrieval ranking details may be expanded when Spec B lands, without changing the ownership and lifecycle boundaries documented here.

message / explicit action / import
|
v
classifier + policy gate
|
v
memory_events queue
|
v
deterministic or LLM worker ----> reject / retry audit state
|
v
user-scoped upsert (pattern v3)
|
+----> trust, decay, TTL and capacity lifecycle
|
+----> 2s write-through embedding
| `-- failure remains pending for backfill
v
semantic + keyword hybrid retrieval
|
v
permission check + prompt-budget pack
|
v
<agent-memory> injection
  1. Ingest creates memory_events for supported conversations. The lightweight classifier records why an event should proceed; it does not write a durable memory itself.
  2. The leader-elected memory worker drains deterministic events and LLM events separately. LLM extraction goes through LlmGateway, and every result is recorded on its event for retry and auditability.
  3. Accepted results upsert agent_memories. Explicit REST/action creates and confirmed imports enter the same table through their own validated paths.
  4. New runtime creates attempt an embedding through LlmGateway with a two-second bound. HTTP and action writes spawn this work so request latency is not coupled to the provider; the background worker awaits it because it is already outside the chat turn. Semantic edits use the same spawned write-through path. Failures and imports leave the row pending for the five-minute embedding backfill safety net.
  5. Retrieval combines vector and keyword candidates, filters inactive rows and unauthorized user-scoped rows, then builds a prompt-budgeted memory pack. Injected memory IDs are retained as message evidence links.

agent_memories.user_id is the principal that produced a memory. For scope = 'user_agent', every read must satisfy one of these conditions:

  • the row’s user_id matches the requesting user; or
  • user_id IS NULL, which is the explicit compatibility rule for legacy and shared snapshot rows.

The agent_id boundary still applies. System seeds retain their existing global visibility. User-scoped dedup keys use v3:{type}:{scope}:{user}:{hint}, and daily semantic dedup also requires user_id IS NOT DISTINCT FROM so maintenance cannot merge two users’ rows.

Message-memory is a separate source. In group conversations, both the user and the target agent must be members before group messages can become candidates.

The normal delete API is reversible: it sets lifecycle_status = 'deleted', archive_reason = 'user_delete', and archived_at. The restore endpoint only reactivates those rows within 30 days. User-facing lists, counts, exports, grant snapshots, and retrieval exclude inactive rows; administrative data exports also exclude deleted rows.

Other lifecycle transitions are soft as well:

  • low trust, supersede, dedup, expiry, and active-cap pressure archive rows;
  • extractor-created ephemeral memories expire after seven days, extended by a later matching upsert;
  • grant revoke/refresh marks obsolete shared snapshots deleted;
  • the hard-cap sweep is the routine physical deletion path for archived or deleted memory rows. Account erasure remains the exceptional compliance purge path.

Pinned rows are protected from normal archive selection, subject to the pinned-active cap. Capacity scoring combines trust, explicitness, recent confirmation, and staleness.

Agent-to-agent grants are explicit snapshots, not a live fan-out subscription. Grant creation copies the source agent’s active, non-system, non-shared rows; user_agent rows are limited to the caller (legacy NULL remains compatible), and every copied row has user_id = NULL. Refresh atomically retires the old snapshot and copies a new one; revoke retires it. The UI exposes a manual refresh control so this snapshot behavior is visible.

Every memory mutation crosses the retrieval cache’s Surface::Memory invalidation boundary: CRUD, worker apply, import confirmation, and grant grant/revoke/refresh. Redis failure is logged and the 30-second cache TTL is the safety net; it does not roll back a committed database write.

  • The memory/skill background job is advisory-lock leader elected.
  • Event recovery runs every minute, embedding backfill every five minutes, and dedup/expiry/capacity maintenance daily.
  • memory_events is the write audit and retry record; agent_memories is the durable serving model. Embeddings are derived indexes, never canonical data.
  • The management panels fetch when opened. Realtime pushes for worker-created memories are intentionally not implemented in this iteration; the bounded staleness is accepted and documented rather than presenting a partial live contract.

Spec B owns retrieval ranking, fallback branches, and injection-quality changes. It must preserve the user predicate in every candidate branch and the MemoryInjectionRequest struct boundary. No read-side ranking change may weaken the ownership, lifecycle, or cache contracts above.

Build a7f47a5ca54ddcf7806cd48b81ce1b9827042766