feat(ai): in-RAM semantic recall (RAG) for conversation context
Give the agent recall of things said beyond the verbatim window, without breaking the RAM-only philosophy — nothing is persisted to disk. - MemoryIndex: a capped, in-memory pool of embedded messages with pure-Python cosine search (no numpy). Retains far more than the rolling transcript so old lines can be surfaced on demand; oldest evicted past the cap to bound RAM. - OllamaEmbedder: local embeddings via nomic-embed-text, on by default and independent of the chat provider (reuses the Ollama host when chat is Ollama). - Bridge: captured room messages (live + backfilled) are embedded on a background worker so a slow embedder can't stall frame draining. On a /ai question the agent retrieves top-k relevant lines, drops weak (<min_score) and windowed-duplicate hits, and prepends them as a clearly-fenced "recalled context" preamble — kept at user role, never elevated to system, so untrusted room text informs without instructing. Falls back to recency-only if the embedder is unreachable. - CLI: --no-rag, --embed-model, --embed-host, --rag-top-k. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,29 @@ class OllamaProvider:
|
||||
return [m.get("name", "") for m in r.json().get("models", [])]
|
||||
|
||||
|
||||
class OllamaEmbedder:
|
||||
"""Local text embeddings via Ollama (default ``nomic-embed-text``), used for
|
||||
the agent's in-RAM semantic recall. Local + free, so it stays on by default
|
||||
regardless of which provider answers chat. No key, nothing persisted."""
|
||||
|
||||
name = "ollama-embed"
|
||||
|
||||
def __init__(self, model: str = "nomic-embed-text", host: str | None = None,
|
||||
timeout: int = 60):
|
||||
self.model = model
|
||||
self.host = (host or os.environ.get("OLLAMA_HOST", "http://localhost:11434")).rstrip("/")
|
||||
self.timeout = timeout
|
||||
|
||||
def embed(self, text: str) -> list[float]:
|
||||
r = requests.post(
|
||||
f"{self.host}/api/embeddings",
|
||||
json={"model": self.model, "prompt": text},
|
||||
timeout=self.timeout,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json().get("embedding") or []
|
||||
|
||||
|
||||
class AnthropicProvider:
|
||||
"""Anthropic Messages API. Cloud — opt-in. Needs ANTHROPIC_API_KEY."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user