feat: add heartbeat monitor and vector memory search (Tier 2)

Heartbeat:
- HeartbeatMonitor with 5 checks: gateway, model, channels, memory, disk
- Configurable interval, failure threshold, notification channel
- Recovery notifications when health restores
- 25 new tests

Vector Memory Search:
- EmbeddingProvider interface with OpenAI, Gemini, Ollama, LlamaCpp backends
- SQLite-backed VectorStore with cosine similarity search
- Text chunker with paragraph-aware splitting and overlap
- HybridSearch merging keyword + vector results with configurable weight
- Background indexer with dirty-namespace tracking
- Graceful fallback to keyword search when embeddings unavailable
- 51 new tests

Config: automation.heartbeat + memory.embedding schema sections
Total: 950 tests passing, all types clean
This commit is contained in:
William Valentin
2026-02-07 14:45:11 -08:00
parent b50c140d25
commit 88731a50e3
17 changed files with 2354 additions and 7 deletions
+23
View File
@@ -40,6 +40,7 @@ export interface SearchResult {
*/
export class MemoryStore {
private _config: MemoryStoreConfig;
private _dirtyNamespaces: Set<string> = new Set();
constructor(config: MemoryStoreConfig) {
this._config = config;
@@ -88,6 +89,9 @@ export class MemoryStore {
const separator = existing.length > 0 ? '\n' : '';
writeFileSync(filePath, existing + separator + content, 'utf-8');
}
// Mark namespace as needing re-indexing for vector search
this._dirtyNamespaces.add(namespace);
}
/**
@@ -147,6 +151,25 @@ export class MemoryStore {
return this._scanDir(this._config.dir);
}
/**
* Return namespaces that have been modified since last call, then clear
* the dirty set. Used by the background indexer to re-embed changed content.
*/
getDirtyNamespaces(): string[] {
const dirty = Array.from(this._dirtyNamespaces);
this._dirtyNamespaces.clear();
return dirty;
}
/**
* Mark all existing namespaces as dirty (e.g. for initial full indexing).
*/
markAllDirty(): void {
for (const ns of this.listNamespaces()) {
this._dirtyNamespaces.add(ns);
}
}
/**
* Build memory context suitable for injection into a system prompt.
*