Include Luna AI Assistant design docs covering channels, configuration, core architecture, memory, scheduler, and skills. Add reference docs from OpenClaw and ZeroClaw projects, plus Mistral and OpenAI API specs.
162 lines
9.0 KiB
Markdown
162 lines
9.0 KiB
Markdown
# Memory SDK
|
|
|
|
OpenClaw's memory system lives in a standalone package (`packages/memory-host-sdk`) that exposes composable engines for storage, embeddings, query processing, and foundation utilities. The SDK defines a clear host-engine boundary: the host application consumes the SDK surface, while the SDK encapsulates all storage, indexing, and retrieval logic behind exported contracts.
|
|
|
|
***
|
|
|
|
## Package Structure
|
|
|
|
The SDK entry point (`engine.ts`) re-exports four focused engine modules:
|
|
|
|
```typescript
|
|
export * from "./engine-foundation.js";
|
|
export * from "./engine-storage.js";
|
|
export * from "./engine-embeddings.js";
|
|
export * from "./engine-qmd.js";
|
|
```
|
|
|
|
Each engine is a self-contained barrel export covering one concern. New code is directed to the focused subpaths rather than the aggregate surface.
|
|
|
|
***
|
|
|
|
## Engine Storage
|
|
|
|
The storage engine (`engine-storage.ts`) provides the persistence and retrieval primitives built on SQLite with the `sqlite-vec` vector extension.
|
|
|
|
### Key Exports
|
|
|
|
- **`MemoryChunk`** and **`MemoryFileEntry`** — the core data types. A chunk is an indexed segment of content with metadata; a file entry represents a source document on disk.
|
|
- **`buildFileEntry`** / **`buildMultimodalChunkForIndexing`** — constructors for creating index-ready records.
|
|
- **`chunkMarkdown`** — splits markdown content into semantically coherent chunks for embedding.
|
|
- **`cosineSimilarity`** — vector distance computation for retrieval ranking.
|
|
- **`parseEmbedding`** — deserializes stored embedding vectors.
|
|
- **`ensureMemoryIndexSchema`** — creates or migrates the SQLite schema (tables, FTS indexes, vector columns).
|
|
- **`loadSqliteVecExtension`** — loads the `sqlite-vec` native extension into the SQLite connection.
|
|
- **`requireNodeSqlite`** — resolves the Node.js SQLite driver.
|
|
- **`readMemoryFile`** — reads a memory file from disk with safety checks.
|
|
- **`resolveMemoryBackendConfig`** — resolves backend-specific configuration (SQLite paths, vector dimensions, etc.).
|
|
|
|
### Storage Architecture
|
|
|
|
The storage layer uses SQLite as a single-file database with the `sqlite-vec` extension providing vector column support. Memory chunks are stored alongside their embeddings in the same database, enabling hybrid queries that combine full-text search with cosine vector similarity in a single SQL statement. This mirrors the approach used by ZeroClaw's SQLite backend (see [[ZeroClaw/Memory]]).
|
|
|
|
```typescript
|
|
// Types exported for consumers
|
|
type MemoryChunk = { /* chunk content, metadata, embedding vector */ };
|
|
type MemoryFileEntry = { /* source file path, hash, modification time */ };
|
|
type MemorySearchResult = { /* ranked results with scores and source info */ };
|
|
```
|
|
|
|
***
|
|
|
|
## Engine Embeddings
|
|
|
|
The embeddings engine (`engine-embeddings.ts`) provides a pluggable embedding provider system with six built-in backends and batch processing utilities.
|
|
|
|
### Embedding Providers
|
|
|
|
| Provider | Default Model | Module |
|
|
|----------|--------------|--------|
|
|
| Local | `DEFAULT_LOCAL_MODEL` | `embeddings.js` |
|
|
| Gemini | `DEFAULT_GEMINI_EMBEDDING_MODEL` | `embeddings-gemini.js` |
|
|
| Mistral | `DEFAULT_MISTRAL_EMBEDDING_MODEL` | `embeddings-mistral.js` |
|
|
| Ollama | `DEFAULT_OLLAMA_EMBEDDING_MODEL` | `embeddings-ollama.js` |
|
|
| OpenAI | `DEFAULT_OPENAI_EMBEDDING_MODEL` | `embeddings-openai.js` |
|
|
| Voyage | `DEFAULT_VOYAGE_EMBEDDING_MODEL` | `embeddings-voyage.js` |
|
|
|
|
### Provider Interface
|
|
|
|
```typescript
|
|
// Core provider contract
|
|
type MemoryEmbeddingProvider = {
|
|
name: string;
|
|
// ... embedding computation methods
|
|
};
|
|
|
|
type MemoryEmbeddingProviderAdapter = {
|
|
// Adapts raw provider to the SDK contract
|
|
};
|
|
|
|
// Factory and registry
|
|
function getMemoryEmbeddingProvider(name: string): MemoryEmbeddingProvider;
|
|
function listMemoryEmbeddingProviders(): string[];
|
|
```
|
|
|
|
### Batch Processing
|
|
|
|
Three batch helpers handle high-throughput embedding jobs for initial indexing or re-indexing:
|
|
|
|
- **`runGeminiEmbeddingBatches`** — Gemini-specific batching with rate limit handling.
|
|
- **`runOpenAiEmbeddingBatches`** — OpenAI batch API integration (`OPENAI_BATCH_ENDPOINT`).
|
|
- **`runVoyageEmbeddingBatches`** — Voyage AI batch processing.
|
|
|
|
### Safety Utilities
|
|
|
|
- **`enforceEmbeddingMaxInputTokens`** — truncates input to provider-specific token limits.
|
|
- **`estimateStructuredEmbeddingInputBytes`** / **`estimateUtf8Bytes`** — byte estimation for payload sizing.
|
|
- **`hasNonTextEmbeddingParts`** — detects multimodal content that requires special handling.
|
|
|
|
***
|
|
|
|
## Engine Foundation
|
|
|
|
The foundation engine (`engine-foundation.ts`) re-exports core utilities from the main OpenClaw application that the memory system depends on. Rather than duplicating logic, the SDK imports these through relative paths to the monorepo `src/` directory.
|
|
|
|
### Key Capabilities
|
|
|
|
- **Agent Scope Resolution**: `resolveAgentDir`, `resolveAgentWorkspaceDir`, `resolveDefaultAgentId`, `resolveSessionAgentId` — determines which agent's memory space to operate on.
|
|
- **Memory Search Configuration**: `resolveMemorySearchConfig` with `ResolvedMemorySearchConfig` type — controls search behavior (result limits, relevance thresholds).
|
|
- **Configuration Loading**: `loadConfig`, `resolveStateDir` — reads OpenClaw configuration and state directories.
|
|
- **Session Integration**: `resolveSessionTranscriptsDirForAgent`, `onSessionTranscriptUpdate` — watches for new conversation transcripts to index into memory.
|
|
- **File Safety**: `writeFileWithinRoot` — prevents path traversal when writing memory files.
|
|
- **Secrets**: `hasConfiguredSecretInput`, `normalizeResolvedSecretInputString` — resolves API keys for embedding providers.
|
|
|
|
***
|
|
|
|
## Engine QMD (Query Processing)
|
|
|
|
The QMD engine (`engine-qmd.ts`) handles query decomposition, keyword extraction, and scope filtering before executing memory searches.
|
|
|
|
### Query Pipeline
|
|
|
|
- **`extractKeywords`** — pulls meaningful terms from a natural language query, filtering stop words via `isQueryStopWordToken`.
|
|
- **`parseQmdQueryJson`** — parses structured query results (type `QmdQueryResult`) from the QMD binary.
|
|
- **Scope Filtering**: `deriveQmdScopeChannel`, `deriveQmdScopeChatType`, `isQmdScopeAllowed` — restricts search results to the appropriate channel and conversation type.
|
|
- **Session Files**: `buildSessionEntry`, `listSessionFilesForAgent`, `sessionPathForFile` — manages the session transcript files that feed into memory indexing.
|
|
- **CLI Integration**: `checkQmdBinaryAvailability`, `resolveCliSpawnInvocation`, `runCliCommand` — interfaces with an external QMD binary for query processing.
|
|
|
|
***
|
|
|
|
## Integration Pattern
|
|
|
|
The SDK is consumed by the host application through the aggregate `engine.ts` export. The boundary is clear:
|
|
|
|
- **Host responsibility**: Decides when to index, when to search, which agent scope to use, and how to present results.
|
|
- **SDK responsibility**: Handles all storage I/O, embedding computation, vector indexing, query processing, and schema management.
|
|
|
|
The typical flow:
|
|
|
|
1. **Initialization**: Host calls `resolveMemoryBackendConfig` to set up the storage backend.
|
|
2. **Indexing**: Host uses `engine-embeddings` to generate vectors and `engine-storage` to persist chunks.
|
|
3. **Retrieval**: Host uses `engine-qmd` to process the query, then performs a similarity search via `engine-storage`.
|
|
|
|
This separation means the memory engine can be tested independently, and the host can swap backends (e.g., different SQLite configurations, different embedding providers) without changing application logic.
|
|
|
|
***
|
|
|
|
## Relevance to Luna
|
|
|
|
Luna's [[Memory]] module defines an `IMemoryStore` interface but the current file-based implementation only supports writing — there is no recall or search capability.
|
|
|
|
### Patterns to Adopt
|
|
|
|
- **Composable Engine Architecture**: Separating storage, embeddings, and query processing into distinct layers is a clean pattern for Luna. Rather than building a monolithic memory service, Luna could define `IMemoryStorage`, `IEmbeddingProvider`, and `IQueryProcessor` interfaces that compose into a full memory system.
|
|
- **SQLite + Vector Extension**: Both OpenClaw and ZeroClaw use SQLite with vector extensions for hybrid search. Luna already references SQLite packages — finishing `SqliteMemoryStore` with this architecture is the natural path.
|
|
- **Pluggable Embedding Providers**: Luna should support multiple embedding backends from the start. The factory pattern (`getMemoryEmbeddingProvider(name)`) maps to C# service registration.
|
|
- **Batch Processing**: For initial indexing or re-indexing of conversation history, batch embedding helpers prevent rate-limiting issues.
|
|
- **Query Preprocessing**: Keyword extraction and scope filtering before search improves relevance. Luna should implement query expansion as a pipeline step before hitting the vector store.
|
|
|
|
### Key Difference
|
|
|
|
OpenClaw's SDK is a package boundary within a monorepo — it re-exports from the main `src/` tree through barrel files. Luna, as a single compiled application, would implement this as a set of interfaces within a `Memory` namespace rather than a separate package. The architectural principle (composable engines with clear contracts) translates directly to C# DI registration.
|