7.3 KiB
Agent Alpha — AI Agent Instructions
Project Overview
Agent Alpha is an agentic AI backend (FastAPI + pydantic-ai) with a React + Vite + Tailwind frontend. Users chat with an AI agent powered by a llama.cpp server (OpenAI-compatible endpoint).
agent_alpha/
├── backend/ # FastAPI application
│ ├── app.py # AppBuilder factory (DI, lifespan, CORS)
│ ├── main.py # Uvicorn entry point
│ ├── core/
│ │ ├── agent.py # AgentService (lazy init, capabilities)
│ │ ├── config.py # pydantic-settings from .env
│ │ ├── database.py# SQLAlchemy async engine + Valkey client + migrations; session created_at tracking
│ │ ├── dependencies.py # FastAPI DI providers
│ │ └── models.py # SQLAlchemy ORM models (User)
│ └── routes/
│ ├── admin.py # GET /api/admin/* (admin dashboard — stats, users, sessions)
│ ├── auth.py # POST /api/auth/{login,register,logout}, GET /api/auth/me
│ ├── chat.py # POST /api/chat, GET /api/chat/{history,sessions}
│ ├── health.py # GET /api/health
│ └── users.py # CRUD /api/users
├── frontend/ # React + Vite SPA
│ ├── src/
│ │ ├── Admin.tsx # Admin dashboard (overview, users, sessions tabs)
│ │ ├── App.tsx # Auth + Chat UI + admin routing
│ │ └── api.ts # Fetch client (chat, auth, users, admin)
│ └── nginx.conf # Production SPA + API proxy
├── skills/ # pydantic-ai skill definitions
└── docker-compose.yml # Full stack orchestration (docker compose / podman compose)
Tech Stack
| Layer | Technology |
|---|---|
| Backend | Python 3.12+, FastAPI, Uvicorn |
| AI | pydantic-ai-slim, pydantic-ai-harness, pydantic-ai-shields |
| Database | PostgreSQL 16 (asyncpg + SQLAlchemy async) |
| Cache | Valkey 8 (Redis-compatible, via redis[hiredis]) |
| Frontend | React 18, TypeScript 5.6, Vite 6, Tailwind CSS 3.4 |
| Infra | Docker Compose / Podman Compose (backend, frontend/nginx, postgres, valkey) |
| Pkg Mgr | uv (Python), bun (frontend) |
Build & Run Commands
make install # uv sync — install Python deps
make run # Start backend on :8000 (reload)
make frontend-install # bun install
make frontend-dev # Start Vite on :5173
make compose-up # Start all containers (detached; auto-detects podman or docker)
make compose-rebuild # Rebuild images & restart
make compose-logs # Follow logs
make compose-down # Stop everything
Coding Conventions
Python
from __future__ import annotationsat the top of every module.- Type hints required on all function signatures, including async return types.
- Docstrings: module-level Google-style with
::usage examples. - Imports: stdlib → third-party → local, grouped with blank lines.
- Async-first: all I/O uses
async/await(FastAPI routes, DB sessions, Valkey). - Settings: use
pydantic-settings(Settingsclass inconfig.py); field names are snake_case, env vars are UPPER_SNAKE_CASE. - Error handling:
HTTPException(status_code=500, detail=str(exc))in routes;try/exceptwith graceful fallback for optional components (e.g., Logfire). - DI pattern: FastAPI
Depends()with providers independencies.py. Provider functions use module-level singletons. - Factories: use
AppBuilderclass for app construction, accept optionalSettingsfor testability.
TypeScript / React
- Functional components only (hooks, no classes).
- Interfaces at file top, exported when reused.
- Tailwind utility classes inline; no CSS modules or styled-components.
- API client isolated in
api.ts— exports for chat (sendMessage,getHistory), auth (login,register,getMe,logout), users (listUsers,createUser,getUserSessions), and admin (getAdminStats,adminListUsers,adminUpdateUser,adminListSessions,adminDeleteSession). Auth token managed vialocalStorage+Authorization: Bearerheader helpers. - Session metadata: Session creation timestamps (
chat:{session_id}:created_at) are stored in Valkey viaSETNXon the first message. TheGET /api/users/{user_id}/sessionsendpoint returnssession_id,title,created_at(ISO-8601), andmessage_count, sorted newest-first. The frontend displays relative time viaformatSessionTime()in the sessions sidebar.
Key Architecture Decisions
Dependency Injection
dependencies.py provides get_settings(), get_agent_service(), and get_db_session() as FastAPI Depends() callables. AgentService is lazily initialized (not built at import time). AppBuilder accepts optional Settings for test overrides.
Capabilities Stack
Agent capabilities are assembled in AgentService._build_capabilities() — a list that includes code execution, web search, MCP, sub-agents, cost tracking, input/tool guards, secret redaction, and stuck-loop detection.
Lifecycle
FastAPI's lifespan context manager handles startup (initialize agent, DB engine, Valkey) and shutdown (close agent, DB pool, Valkey connection). See AppBuilder._lifespan() in app.py.
Configuration
Environment variables loaded from .env via pydantic-settings (backend/core/config.py). Key vars: LLM_BASE_URL, LLM_MODEL, LLM_API_KEY, LOGFIRE_TOKEN, DATABASE_URL, VALKEY_URL.
Common Pitfalls
- Container DNS caching: nginx caches DNS at startup. Podman does not use Docker's
127.0.0.11resolver, so theresolver+ variable trick doesn't work. If the backend restarts, also restart the frontend container (podman compose restart frontendordocker compose restart frontend). - Slow LLM responses: The LLM may take minutes to respond. Nginx
proxy_read_timeoutis set to 600s. Backend timeouts should match. - Logfire is optional:
logfire.configure()is wrapped intry/except— omitLOGFIRE_TOKENto disable. - API key for local LLMs: Set
LLM_API_KEY=no-key-required(or leave empty) for llama.cpp / local endpoints; the OpenAI client requires a non-None value. - uv vs pip: Always use
uv sync/uv add, neverpip install. The lock file isuv.lock. - bun for frontend: Use
bun install/bun run devfor frontend, notnpm. - Container orchestration: Backend depends on postgres + valkey being healthy. Use
depends_onwithcondition: service_healthy. Run withdocker compose up -dorpodman compose up -d. The Makefile auto-detects the available runtime. - Schema migrations:
init_db()indatabase.pyrunsBase.metadata.create_allfollowed byALTER TABLE ... ADD COLUMN IF NOT EXISTSfor new columns. Existing tables are never rebuilt — new columns are added in-place. - bcrypt on container restart:
bcryptis a native dependency. If the container fails to start with an import error, ensurebcryptis inpyproject.tomlanduv syncwas run during the container build.
Key Conventions
db.flush()in repositories, notcommit()
More Info
docs/architecture.md- Architecture detailsdocs/patterns.md- Code patternsdocs/adding_features.md- How to add features