Feat: Agent-Memory auf Mem0 (auto-lernend, semantisch) via Sidecar
Paket A des Plans. Ersetzt die flache SQLite-Fakten-DB durch Mem0 (LLM-Auto-
Extraktion + Vektor/Chroma-Suche). Architektur erzwungen durch Python-Split:
MC2-Backend laeuft auf 3.14 (kann mem0 nicht importieren), mem0+chromadb nur
auf 3.12 (~/.mem0/venv) -> Mem0-Sidecar (FastAPI, localhost:8765), MC2 spricht
ihn per HTTP. /api/memory-Form bleibt unveraendert (UI + MCP kompatibel).
- mem0_service/: Sidecar (app.py), Migration (migrate.py), deps.
- Embeddings: neue llama-swap embed-Rolle (Qwen3-Embedding-0.6B, 1024 Dim,
pooling last) ueber /v1/embeddings.
- LLM-Extraktion: lokales fast-Hirn; NoThinkLLM schaltet Qwen3-Thinking ab
(sonst bricht json_object-Extraktion ab), custom_instructions halten Deutsch.
- backend/services/memory.py: duenner HTTP-Client auf den Sidecar (semantische
Suche mit score, verbatim add, learn()). Router: /api/memory/learn.
- mcp/mcp_memory.py: neues learn-Tool (Auto-Lernen aus Gespraechs-Turns),
search jetzt semantisch.
- Frontend: Relevanz-Score + Auto/Manuell-Herkunft im Gedaechtnis-Tab.
- deploy/: mem0-service.service + deploy.sh (uv-Install, Migration, Restart).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,9 @@ import { cn } from "@/lib/utils"
|
||||
|
||||
const CATEGORIES = ["user", "instruction", "stable", "versioned", "ephemeral"]
|
||||
|
||||
// Herkunft: automatisch gelernt (Mem0-Extraktion / Agent) vs. manuell angelegt.
|
||||
const AUTO_SOURCES = new Set(["auto", "agent"])
|
||||
|
||||
const CAT_CONFIG: Record<string, { label: string; icon: any; color: string; border: string; bg: string; text: string }> = {
|
||||
user: { label: "User", icon: User, color: "text-cyan-400", border: "border-cyan-500/30", bg: "bg-cyan-500/10", text: "text-cyan-400" },
|
||||
instruction: { label: "Regel", icon: Scroll, color: "text-violet-400", border: "border-violet-500/30", bg: "bg-violet-500/10", text: "text-violet-400" },
|
||||
@@ -154,7 +157,7 @@ export function MemoryView() {
|
||||
<input
|
||||
value={q}
|
||||
onChange={(e) => setQ(e.target.value)}
|
||||
placeholder="Gedächtnis durchsuchen..."
|
||||
placeholder="Semantisch durchsuchen (nach Bedeutung, nicht nur Stichwort)..."
|
||||
className="w-full h-9 pl-9 pr-3 rounded-lg border border-border/60 bg-card/45 text-xs outline-none focus:ring-1 focus:ring-primary/50 text-foreground"
|
||||
/>
|
||||
<Search className="absolute left-3 top-2.5 h-3.5 w-3.5 text-muted-foreground" />
|
||||
@@ -228,7 +231,24 @@ export function MemoryView() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3 shrink-0">
|
||||
<span className="text-[9px] font-mono text-muted-foreground/60 bg-background/20 px-1.5 py-0.5 rounded uppercase tracking-wider">
|
||||
{typeof m.score === "number" && (
|
||||
<span
|
||||
className="text-[9px] font-mono text-primary bg-primary/10 px-1.5 py-0.5 rounded uppercase tracking-wider"
|
||||
title="Relevanz der semantischen Suche"
|
||||
>
|
||||
{Math.round(m.score * 100)}%
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className={cn(
|
||||
"flex items-center gap-1 text-[9px] font-mono px-1.5 py-0.5 rounded uppercase tracking-wider",
|
||||
AUTO_SOURCES.has(m.source)
|
||||
? "text-emerald-400 bg-emerald-500/10"
|
||||
: "text-muted-foreground/60 bg-background/20"
|
||||
)}
|
||||
title={AUTO_SOURCES.has(m.source) ? "Automatisch gelernt" : "Manuell angelegt"}
|
||||
>
|
||||
{AUTO_SOURCES.has(m.source) && <Sparkles className="h-2.5 w-2.5" />}
|
||||
{m.source}
|
||||
</span>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user