Current stack:
agent.pyruns an always-on memory agent with aiohttp HTTP API on :8888dashboard.pyis a Streamlit client that talks to the API via requests- Dependencies:
aiohttp,streamlit,openai-agents,python-dotenv,requests
Goal:
- Replace aiohttp with FastAPI for the HTTP layer
- Rebuild dashboard as a React SPA served by FastAPI static files (no separate frontend server)
- Improve UX compared to Streamlit
- Keep existing agent logic, memory DB schema, file watcher, and consolidation loops unchanged
- Provide drop-in API compatibility for existing clients (endpoints
/status,/memories,/ingest,/query,/consolidate,/delete,/clear) - Add FastAPI docs via Swagger/OpenAPI at
/docs - Serve React dashboard at
/from FastAPI static files - Single
python main.pyentrypoint starts agent tasks + FastAPI server - Improve dashboard UX: modern React UI, real-time updates, file upload drag-drop, memory cards with tags, query history, dark mode
always-on-memory-agent/
├─ app/
│ ├─ __init__.py
│ ├─ db.py # SQLite helpers (from agent.py)
│ ├─ agents.py # MemoryAgent, build_agents (from agent.py)
│ ├─ services/
│ │ ├─ watcher.py # watch_folder
│ │ └─ consolidator.py # consolidation_loop
│ ├─ api/
│ │ ├─ routes.py # FastAPI routers for /api/*
│ │ └─ deps.py # agent singleton
│ └─ main.py # FastAPI app, static mount, startup tasks
├─ frontend/ # React + Vite source
│ ├─ package.json
│ ├─ vite.config.ts
│ └─ src/
│ ├─ App.tsx
│ ├─ pages/Ingest.tsx
│ ├─ pages/Query.tsx
│ ├─ pages/Memories.tsx
│ └─ components/
├─ static/ # built React assets (generated)
├─ agent.py # legacy, to be deprecated
├─ dashboard.py # legacy, to be deprecated
├─ requirements.txt
├─ frontend/package.json
└─ SPEC.md
Runtime:
- FastAPI app mounts React build under
/with SPA fallback - API under
/api/*mirrors current aiohttp routes - Background asyncio tasks: file watcher and consolidation loop started on app startup via
startup_event - Same SQLite DB
memory.db, same env vars
Backend:
- Python 3.11+
- FastAPI + Uvicorn
- pydantic v2 for request/response models
openai-agents,openai,python-dotenv,sqlite3,aiofilesoptional
Frontend:
- React 18 + TypeScript
- Vite for dev/build
- TailwindCSS for styling
- React Query for data fetching
- Lucide icons
- Dropzone for file upload
No separate Node server in production; FastAPI serves static build.
Keep compatible JSON contracts. Add OpenAPI schemas.
Base path /api
| Method | Path | Description |
|---|---|---|
| GET | /api/status | Memory stats |
| GET | /api/memories | List memories, optional ?limit=50 |
| POST | /api/ingest | {text, source?} |
| GET | /api/query?q=... | Query memory |
| POST | /api/consolidate | Trigger consolidation |
| POST | /api/delete | {memory_id} |
| POST | /api/clear | Full reset |
Legacy paths /query, /ingest, etc. will be kept as alias routes for compatibility.
Request/Response models defined in app/api/schemas.py.
-
Extract core functions from
agent.pyinto modules:db.py:get_db,store_memory,read_all_memories,read_unconsolidated_memories,store_consolidation,read_consolidation_history,get_memory_stats,delete_memory,clear_all_memoriesagents.py:configure_openai_provider,build_agents,MemoryAgentclassservices/watcher.py:watch_folderservices/consolidator.py:consolidation_loop
-
Create FastAPI app
app/main.py:- Mount static files from
static/at/ - SPA fallback: any GET not matching API serves
index.html - Startup event: create
MemoryAgentsingleton, launch watcher and consolidator as asyncio Tasks
- Mount static files from
-
API routes
app/api/routes.py:- Mirror existing aiohttp handlers
- Async endpoints call
MemoryAgentmethods - Use Pydantic models for validation
-
Replace
aiohttpimport with FastAPI, updaterequirements.txt- Remove
aiohttp,streamlit,requests - Add
fastapi,uvicorn[standard],python-multipart
- Remove
-
Entry point
main.pyat repo root runs Uvicorn on--portdefault 8888
Features:
- Sidebar with agent status, memory stats
- Ingest tab:
- Text area + Process button
- Sample quick-insert buttons
- Drag-drop file upload to
./inboxvia API? Files uploaded via POST/api/uploadwhich writes to inbox and returns immediate feedback. Watcher will process asynchronously. - Manual consolidation trigger
- Query tab:
- Input with history
- Results with citations and response time
- Memories tab:
- Grid/list of memory cards with summary, entities, topics, importance badge, created_at, source
- Delete button per card
- Filter by topic/entity/importance
- Danger zone: Clear all with confirmation
UI improvements over Streamlit:
- Dark theme default, responsive layout
- Real-time stats polling every 5s
- Toast notifications
- Keyboard shortcuts
Build process:
npm run devfor Vite dev server proxying API to http://localhost:8888npm run buildoutputs tostatic/
Keep existing .env vars:
AZURE_OPENAI_ENDPOINT,AZURE_OPENAI_API_KEY,OPENAI_API_VERSION,MODEL,MEMORY_DB
CLI args via FastAPI startup or env:
WATCH_DIRdefault./inboxPORTdefault 8888CONSOLIDATE_EVERYdefault 30 minutes
- Backend dev:
python -m uvicorn app.main:app --reload --port 8888 - Frontend dev:
npm run devinfrontend/ - Build frontend:
npm run build-> copy tostatic/ - Production:
python main.pyruns Uvicorn with pre-built static
- API compatibility tests: run sample curls from README against
/api/* - Ensure watcher still ingests files dropped in inbox
- Ensure consolidation still runs
- Verify React routes load and API calls succeed
- Multimodal file ingest currently handled by
MemoryAgent.ingest_filewhich expects bytes. Upload endpoint must write file to inbox so watcher processes it, avoiding re-implementing multimodal handling. - Keep SQLite concurrent access safe: use check_same_thread=False and serialize writes.
- No breaking changes: legacy routes kept as aliases.
app/package with FastAPI appfrontend/React SPA sourcestatic/built frontendmain.pyentrypoint- Updated
requirements.txtandREADME.mdwith new commands - Migration guide for existing users
Status: Spec drafted for review before implementation.