Engram
基于 Planner–Manager–Executor 的文本 Agent;Executor 支持 YAML / Python 高度自定义;可选 Neo4j+Graphiti 记忆图谱;FastAPI + React。
Install / Use
/learn @Mink026/EngramREADME
engram
Languages: English | 简体中文
A text-only conversational agent with a Planner → Manager → Executor pipeline (LangGraph), optional Neo4j + Graphiti memory graph, and a React + Vite frontend. Secrets live in .env, not in code.
Engram (neuroscience): the physical trace of a memory in the brain—aligned with “dialogue agent + persistent memory graph.”
Screenshots
| Chat (streaming + sessions) | Memory graph (Neo4j / vis-network) |
|------------------------------|-------------------------------------|
|
|
|
Features
- Agent workflow: Planner (JSON mode structured plan) routes work to role-based executors; Manager schedules steps; executors call the LLM (streaming for replies).
- Chat UI: SSE streaming, session list, history restored from the server after refresh.
- Memory graph: Optional Graphiti episodes + Neo4j; vis-network page embeddable from the frontend.
- Persistence:
DATABASE_URLor default SQLite atbackend/data/engram.db. - Extensible roles:
executors_config.yaml+ optional Python executor classes.
Requirements
- Backend: Python 3.11+ recommended, uv
- Frontend: Node 18+ / npm
- Optional: Neo4j for the memory graph; OpenAI-compatible LLM API
Repository layout
engram/
├── docs/static/screenshots/ # UI screenshots (README)
├── backend/ # FastAPI, uv
│ ├── main.py # Entry, port 5000 by default
│ ├── config.py # Loads .env
│ ├── executors_config.yaml
│ ├── core/ # planner, manager, base_executor, state
│ ├── executors/ # registry + custom executors
│ ├── tools/ # @tool definitions → ALL_TOOLS
│ ├── tools_lib/ # TOOL_REGISTRY, get_tools_by_names
│ ├── graph/ # LangGraph workflow
│ ├── services/ # agent SSE, Graphiti, session store
│ ├── routes/ # /api/chat, /api/kg/*, sessions
│ ├── models/ # SQLAlchemy (conversations / messages)
│ └── templates/ # kg_graph.html (vis-network)
└── frontend/ # React (Vite), port 3000
└── src/pages/ # ChatPage, MemoryGraphPage
Quick start
Backend
cd engram/backend
cp .env.example .env
# Edit .env: LLM_API_KEY, LLM_BASE_URL, LLM_MODEL, etc.
uv sync
# Production-style (no auto-reload on file changes)
uv run python main.py
# Dev hot reload:
# UVICORN_RELOAD=1 uv run python main.py
# # or: uv run uvicorn main:app --reload --port 5000
- API base:
http://localhost:5000 - OpenAPI:
http://localhost:5000/docs
Frontend
cd engram/frontend
npm install
npm run dev
- App:
http://localhost:3000(Vite proxies/apitolocalhost:5000in dev)
Conversation & session HTTP API
| Method | Path | Description |
|--------|------|-------------|
| GET | /api/sessions | sessions (ids) + conversations (session_id, title, updated_at) |
| GET | /api/sessions/{session_id}/messages | Full message list for reload/hydration |
| DELETE | /api/sessions/{session_id} | Delete server-side session + messages |
If DATABASE_URL is unset, SQLite is used automatically; history still persists.
Environment variables (backend/.env)
| Variable | Description | Required |
|----------|-------------|----------|
| LLM_API_KEY | API key | Yes |
| LLM_BASE_URL | OpenAI-compatible base URL | Yes |
| LLM_MODEL | Chat model name | Yes |
| GRAPHITI_LLM_MODEL | Model for Graphiti extraction (default gpt-4o) | No |
| GRAPHITI_EMBEDDING_MODEL | Embedding model name | No |
| NEO4J_URI | e.g. bolt://localhost:7687 (empty disables graph writes) | No |
| NEO4J_USER | Default neo4j | No |
| NEO4J_PASSWORD | Password | No |
| USER_ID | Graphiti group_id (default 1) | No |
| DATABASE_URL | SQLAlchemy URL; empty → ./data/engram.db | No |
| HOST / PORT | Bind address (default 0.0.0.0:5000) | No |
| UVICORN_RELOAD | 1 / true to enable reload with python main.py | No |
Database URL examples
| Engine | DATABASE_URL | Extra dependency |
|--------|----------------|------------------|
| SQLite (default) | (omit) | — |
| PostgreSQL | postgresql+psycopg2://user:pass@host:5432/db | uv add psycopg2-binary |
| MySQL | mysql+pymysql://user:pass@host:3306/db | uv add pymysql |
Custom executors
Tool functions (agent_platform-style: code-first presets)
- Declare
@toolfunctions underbackend/tools/and register them viatools/__init__.py(_TOOL_MODULES). - In
tools_lib/__init__.py, define named sets the same way asGENERAL_TOOLS/RESEARCHER_TOOLSin agent_platform:
GENERAL_TOOLS = get_tools_by_names(["get_current_time", "calculate"])
TOOL_PRESETS = {"general": GENERAL_TOOLS, "empty": EMPTY_TOOLS, ...}
- Python executors: implement
get_tools()→return GENERAL_TOOLS(seeexecutors/example_executor.py). - YAML-only executors: set
tool_preset: general(orempty,analyst, …) instead of listing every tool name.
Optional tools: [name, ...] in YAML still overrides presets / class get_tools() when you need an explicit exception.
Use tools_lib.list_registered_tool_names() and list_tool_presets() for debugging.
A. YAML-only (no code)
Edit backend/executors_config.yaml (optional tools as above). Restart the backend. The Planner reads role_key values from the registry.
B. Python class
- Add e.g.
backend/executors/researcher.pyimplementingBaseExecutor(role_name,system_prompt,get_tools()), or rely on YAMLtoolsto inject shared tools without customget_tools. - Register in YAML:
- role_key: researcher
name: Researcher
desc: Tasks that need search or structured gathering
python_class: executors.researcher.ResearcherExecutor
Restart the backend.
HTTP API summary
POST /api/chat
SSE stream. Body:
{ "query": "Hello", "session_id": "uuid-here" }
Events include: user_message, todo_list, summary, tool_call, tool_result, answer_delta, answer, error, end.
GET /api/kg/page
HTML page for the memory graph (e.g. iframe). Uses USER_ID as default group_id when not overridden.
GET /api/kg/graph
JSON nodes/edges for the graph viewer.
Languages: English | 简体中文
Related Skills
node-connect
350.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
350.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
350.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
