Repository navigation
[contexto]: Implement LocalBackend #116
Description
Problem
@ekai/contexto only ships with RemoteBackend, which calls an external api for summarization, ingestion and search. Users who want to run fully local have no option today. The ContextoBackend interface was designed to be pluggable, but there's no local implementation.
Goal
Implement a LocalBackend class that satisfies the ContextoBackend interface by running the full pipeline locally: extract, summarize, embed, cluster, persist.
Interface to implement
interface ContextoBackend {
ingest(payload: WebhookPayload | WebhookPayload[]): Promise<void>;
search(query: string, maxResults: number, filter?: Record<string, unknown>, minScore?: number): Promise<SearchResult | null>;
}Ingestion pipeline
The remote API runs this pipeline on every episode/combined event. The LocalBackend needs to replicate it:
WebhookPayload
→ Extract (strip OpenClaw metadata envelope, extract user + assistant + tool text)
→ Summarize via LLM → EpisodeSummary { summary, key_findings, status, confidence, evidence_refs }
→ Combine into content: summary + key_findings as bullets
→ Embed the combined content
→ addToMindmap() (AGNES clustering)
→ Persist via MindmapStorage
1. Extract
Strip the OpenClaw metadata envelope from user messages (Sender (untrusted metadata): ...) and extract text from ContentBlock[] arrays. Handle both string and ContentBlock[] content formats.
2. Summarize
Call an LLM to produce a structured EpisodeSummary from the raw episode (user message + assistant response + tool outputs):
interface EpisodeSummary {
summary: string; // 1-3 sentence concise summary
key_findings: string[]; // at least one entry
status: 'complete' | 'partial' | 'blocked';
confidence: number; // 0.0 to 1.0
evidence_refs: EvidenceRef[];
open_questions?: string[];
}The content stored in the mindmap is summary + "\n" + key_findings joined as bullets. The full episode is preserved in metadata.episode for context injection at retrieval time. The remote API uses openai/gpt-4o-mini via OpenRouter with temperature: 0.2 and response_format: { type: 'json_object' }. Validation should degrade gracefully (mark as partial if fields are missing, don't fail).
3. Cluster + persist and search
Call Mindmap.add() which handles addToMindmap() and storage.save. Make the storage layer pluggable
Reference
-
RemoteBackend(pattern to follow):packages/contexto/src/client.ts -
ContextoBackendinterface:packages/contexto/src/types.ts -
Mindmap class:
packages/mindmap/src/mindmap.ts
Scope
-
Episode summarizer (port LLM call + validation from api-server)
-
LocalBackendclass implementingContextoBackend -
Wire into plugin config (
backend: 'local'option inPluginConfig) -
Support pluggable storage
-
Tests for extract → summarize → embed → ingest → search round-trip
Activity
DaevMithran commentedon Apr 7, 2026
WIP: #124
feat(contexto): tighten public types + honor retrieval config (#149)