feat(grid-agent): isolate conversation memory (#122)
This commit is contained in:
55
docs/grid-agent-conversation.md
Normal file
55
docs/grid-agent-conversation.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Grid-agent conversation memory
|
||||
|
||||
`ConversationStore` owns bounded conversational context independently of the
|
||||
grid connection generation. Its key is the immutable avatar UUID plus exactly
|
||||
one channel kind: public chat or direct IM. Group and conference conversations
|
||||
are deliberately not representable. Public sessions expire at exactly 30
|
||||
minutes of monotonic inactivity and direct IM sessions at exactly 24 hours. A
|
||||
subsequent turn creates a cryptographically random new session ID and receives
|
||||
none of the expired transcript.
|
||||
|
||||
The mutex-protected store assigns one sequence order to concurrent turns. It
|
||||
stores wall-clock timestamps, normalized avatar/agent/tool roles, visible agent
|
||||
responses, bounded tool summaries, and externally meaningful action results.
|
||||
Avatar input and untrusted tool data remain untrusted when compacted. There is
|
||||
no system-message, model-scratchpad, hidden-reasoning, credential, capability
|
||||
URL, or binary-asset input variant. Text is bounded and sensitive URL/token
|
||||
forms are redacted before allocation in the store.
|
||||
|
||||
Configured limits lower hard ceilings for active sessions, turns, per-session
|
||||
bytes, aggregate bytes, tool-result count and size, summary bytes, and total
|
||||
snapshot storage. Old records compact deterministically into a smaller factual
|
||||
summary followed by recent context. Session and aggregate pressure evict the
|
||||
least-recently-active key with UUID/channel tie-breaking. Expiry, compaction,
|
||||
eviction, quarantine, and operator deletion publish stable reason codes through
|
||||
a bounded event queue.
|
||||
|
||||
`list_metadata` returns session ID, UUID, channel, timestamps, turn count, and
|
||||
byte count but never content. Operators can delete or expire an exact key.
|
||||
`context` is the separate LLM-facing projection and can read only that key;
|
||||
untrusted summaries are emitted as explicitly marked user-role data.
|
||||
|
||||
Persistence is local and opt-in through `conversation.persistence_enabled`.
|
||||
`ConversationStore::from_config` uses `storage_path/conversations`; callers
|
||||
flush at their durability boundary. A flush writes and syncs a new immutable,
|
||||
versioned generation before an atomic rename, then retains only generations
|
||||
whose aggregate bytes fit the configured storage ceiling. Linux and other Unix
|
||||
targets force directory mode 0700 and file mode 0600. Rust standard library
|
||||
does not expose a portable Windows ACL editor, so Windows emits the explicit
|
||||
`PermissionsNotVerified` event and operators must restrict the directory ACL to
|
||||
the service identity.
|
||||
|
||||
Restart recovery validates schema, UUIDs, IDs, unique sequences, timestamps,
|
||||
roles, bounds, and redaction before any record can become LLM context. A
|
||||
truncated, corrupt, oversized, or unsupported generation is quarantined and an
|
||||
older valid generation is tried. If the wall clock moved backwards, recovered
|
||||
age is zero; forward elapsed time is applied to the channel TTL. Neither case
|
||||
can grant policy authority or prevent startup.
|
||||
|
||||
Focused gates:
|
||||
|
||||
```sh
|
||||
cargo test --locked -p metacrate-grid-agent --lib conversation_tests
|
||||
cargo test --locked -p metacrate-grid-agent --test conversation_memory
|
||||
cargo clippy --locked -p metacrate-grid-agent --all-targets -- -D warnings
|
||||
```
|
||||
Reference in New Issue
Block a user