Add workspace and memory system (OpenClaw-inspired)

Implements persistent memory for agents with hybrid search:

- Database-backed workspace with PostgreSQL (not filesystem)
- Memory documents: MEMORY.md, daily logs, identity files
- Chunked content with FTS (tsvector) + vector (pgvector) indexes
- Reciprocal Rank Fusion (RRF) for hybrid search combining BM25 and semantic
- Memory tools: memory_search, memory_write, memory_read
- Proactive heartbeat system for periodic execution (30 min default)
- OpenAI embeddings provider (text-embedding-3-small)

Key patterns from OpenClaw:
- "Memory is files, not RAM" - explicit persistence required
- Two-tier memory: daily logs (raw) + curated MEMORY.md
- Session isolation via user_id/agent_id scoping

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-02-02 21:18:47 -08:00
co-authored by Claude Opus 4.5
parent 8c38566378
commit 4e238e60ac
15 changed files with 2999 additions and 0 deletions
+28
View File
@@ -36,6 +36,9 @@ pub enum Error {
#[error("Repair error: {0}")]
Repair(#[from] RepairError),
#[error("Workspace error: {0}")]
Workspace(#[from] WorkspaceError),
}
/// Configuration-related errors.
@@ -268,5 +271,30 @@ pub enum RepairError {
},
}
/// Workspace/memory errors.
#[derive(Debug, thiserror::Error)]
pub enum WorkspaceError {
#[error("Document not found: {doc_type} for user {user_id}")]
DocumentNotFound { doc_type: String, user_id: String },
#[error("Search failed: {reason}")]
SearchFailed { reason: String },
#[error("Embedding generation failed: {reason}")]
EmbeddingFailed { reason: String },
#[error("Document chunking failed: {reason}")]
ChunkingFailed { reason: String },
#[error("Invalid document type: {doc_type}")]
InvalidDocType { doc_type: String },
#[error("Workspace not initialized for user {user_id}")]
NotInitialized { user_id: String },
#[error("Heartbeat error: {reason}")]
HeartbeatError { reason: String },
}
/// Result type alias for the agent.
pub type Result<T> = std::result::Result<T, Error>;