This project is a FastAPI endpoint running lang-graph in the backend:
ChatOllamaas the LLMStateGraphwith a conditional edgeinterrupt(...)for sensitive tool approvalSqliteSaveras the checkpointer for persistent memorymain.pyas the FastAPI entrypointapp.pyfor the routemodel.pyfor the request/response models
You run the API and send queries to /chat. If you keep using the same thread_id, the graph keeps the conversation memory in SQLite.
docker compose up -d --buildThe SQLite checkpoint file is stored in ./data/checkpoints.db on the host, so memory survives container restarts.
Send a query:
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{
"thread_id": "user-session-001",
"query": "Remember that I work at Acme Corp."
}'Resume an interrupt:
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{
"thread_id": "user-session-001",
"approved": true
}'- Reuse the same
thread_idto keep memory. - A different
thread_idstarts a new conversation. /chathandles both new questions and interrupt resumes.- The graph still uses conditional routing: answer directly, pause for approval, or go through tools.
- The LangChain/LangGraph logic stays in
agent/state.py,agent/graph.py,agent/nodes.py, andagent/tools.py.
