SupportOps is a support/helpdesk system with a FastAPI agent runtime, a Next.js chat UI, and Supabase Postgres for persistence.
apps/web: Next.js product UI (chat + admin dashboard)services/agent: FastAPI agent runtime APIpackages/eval: pytest-based eval suite calling the agent APIinfra/supabase: Supabase schema and infra assets
Run the schema against your Supabase Postgres instance:
psql "$SUPABASE_DB_URL" -f infra/supabase/schema.sqlFor applying changes to an existing DB, run the latest migration in
infra/supabase/migrations (example):
psql "$SUPABASE_DB_URL" -f infra/supabase/migrations/2026-01-12_v1_vector_agent_runs.sqlcd services/agent
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
$env:SUPABASE_URL="https://your-project.supabase.co"
$env:SUPABASE_SERVICE_ROLE_KEY="your-service-role-key"
$env:AUTH_ENABLED="false"
$env:SUPABASE_JWT_SECRET="your-legacy-jwt-secret-if-using-hs256"
$env:SUPABASE_JWKS_URL="https://your-project.supabase.co/auth/v1/.well-known/jwks.json"
uvicorn app.main:app --reload --port 8000pnpm install
$env:AGENT_API_BASE_URL="http://localhost:8000"
$env:SUPABASE_URL="https://your-project.supabase.co"
$env:SUPABASE_ANON_KEY="your-anon-key"
pnpm dev:webOpen http://localhost:3000 for chat, http://localhost:3000/kb for the KB
admin screen, and http://localhost:3000/runs for recent agent runs.
Use http://localhost:3000/login to sign in when auth is enabled.
- Create a user in Supabase Auth (email + password).
- Set
AUTH_ENABLED=trueinservices/agent. - For modern Supabase projects (ECC/RS256), set
SUPABASE_JWKS_URL. - Only set
SUPABASE_JWT_SECRETif you are on legacy HS256. - Set
SUPABASE_URL+SUPABASE_ANON_KEYfor the web app.
- Send a chat message from
http://localhost:3000. - Open
http://localhost:3000/runsand verify the summary cards populate. - In agent logs, confirm
chat_responseincludeslatency_msandretrieval_source.
- The agent only returns
action=replywhen citations are present. - If no evidence is found, the agent asks for more context (
ask_clarifying). - For vector search, replies are blocked when
top_similarityis belowREPLY_MIN_SIMILARITY. - Recent conversation context is appended (last N messages) to help follow-up questions.
- Default retriever:
RETRIEVER_ENGINE=default - Optional:
RETRIEVER_ENGINE=llamaindex(requiresllama-indexinstalled) - For the optional engine, set
DEFAULT_ORG_IDso it can load KB docs.
cd packages/eval
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
$env:AGENT_API_BASE_URL="http://localhost:8000"
pytest
# or
python run_eval.pyWhen running evals, the agent logs eval_action_result to track action accuracy by category.
packages/eval/thresholds.json defines per-category thresholds (action accuracy,
and optional citation/hand-off rates). run_eval.py prints a category summary
and fails if any threshold is missed.
CI runs python packages/eval/run_eval.py and requires AGENT_API_BASE_URL as a
repo secret pointing at a reachable agent environment.
The eval runner creates/uses an org with slug eval (configurable via
EVAL_ORG_SLUG) and seeds KB data into that org to avoid cross-contamination.
python -m unittest discover services/agent/testscd infra/kb-fixtures
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
$env:AGENT_API_BASE_URL="http://localhost:8000"
python seed_kb.py --ingestSemantic evals require embeddings + vector search enabled. Opt-in with:
$env:VECTOR_EVALS="true"
python run_eval.py