Problem
The context engine holds two pieces of in-memory state in CompactionState that are tightly coupled to raw data structures:
bufferedMessages: WebhookPayload[] - episode payloads accumulated after each turn, flushed to backend on compact/dispose. Lost on process crash.
injectedItemIds: Set<string> - tracks which search result IDs have been injected into context for deduplication. Lost on crash, causing duplicate context injection after restart.
Both live as plain arrays/sets with no abstraction boundary, making it impossible to swap in a persistent backend without rewriting both engine implementations.
Proposal
Introduce a BufferStore interface that unifies both concerns behind a single abstraction, and an InMemoryBufferStore that preserves current behavior. Both DefaultContextEngine and SlidingWindowEngine migrate from direct array/set manipulation to the BufferStore API.
interface BufferStore {
// Episode buffer
push(payload: WebhookPayload, sessionId: string, sessionKey: string): void;
getAll(): BufferedEntry[];
count(): number;
clear(): void;
deleteByRowids(rowids: number[]): void;
// Dedup tracking
hasInjectedId(id: string): boolean;
addInjectedId(id: string): void;
clearInjectedIds(): void;
// Lifecycle
close(): void;
}
Scope
- New
buffer-store.ts with BufferStore interface, BufferedEntry type, and InMemoryBufferStore
- Replace
bufferedMessages + injectedItemIds in CompactionState with single buffer: BufferStore
- Migrate both engines and base class to use the buffer API
Non-goals
- SQLite persistence (future follow-up:
SqliteBufferStore implementing the same interface, following lossless-claw's node:sqlite DatabaseSync patterns)
- Config changes or new dependencies
Problem
The context engine holds two pieces of in-memory state in
CompactionStatethat are tightly coupled to raw data structures:bufferedMessages: WebhookPayload[]- episode payloads accumulated after each turn, flushed to backend on compact/dispose. Lost on process crash.injectedItemIds: Set<string>- tracks which search result IDs have been injected into context for deduplication. Lost on crash, causing duplicate context injection after restart.Both live as plain arrays/sets with no abstraction boundary, making it impossible to swap in a persistent backend without rewriting both engine implementations.
Proposal
Introduce a
BufferStoreinterface that unifies both concerns behind a single abstraction, and anInMemoryBufferStorethat preserves current behavior. BothDefaultContextEngineandSlidingWindowEnginemigrate from direct array/set manipulation to theBufferStoreAPI.Scope
buffer-store.tswithBufferStoreinterface,BufferedEntrytype, andInMemoryBufferStorebufferedMessages+injectedItemIdsinCompactionStatewith singlebuffer: BufferStoreNon-goals
SqliteBufferStoreimplementing the same interface, following lossless-claw'snode:sqliteDatabaseSyncpatterns)