← back

Discord Agent

Savya Bot

Discord bot with an AI agent that can manage roles, channels, permissions, and more via natural language commands.

Quick Start

# Backend
cd backend
uv sync --dev
uv run python server.py    # FastAPI + Discord bot on :8000

# Frontend (separate terminal)
cd frontend
npm install
npm run dev                # React SPA on :5173

Setup

Copy backend/.env and fill in:

Variable Description
DISCORD_BOT_TOKEN Bot token
DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET Discord OAuth2 app
JWT_SECRET Secret for JWT tokens
GOOGLE_AI_API Gemini API key (fallback LLM)

How It Works

  1. Invite the bot to a server and run x0auto to activate agent mode
  2. Type anything — the AI responds using Discord tools (roles, channels, members, etc.)
  3. LLM uses the user's own OpenRouter API key if connected; falls back to Gemini
  4. Manage sessions from the web UI at http://localhost:5173

OpenRouter API Key Flow

  1. User connects OpenRouter via the web UI (/links page) → key saved to api_links DB table
  2. On x0auto command: key fetched via get_user_api_key(user_id, "openrouter") and stored in the agent state
  3. When the LLM is called (agent_core/agent.py:get_llm()):
    • First checks the persisted agent state for the key
    • Falls back to get_user_api_key() from DB
    • Creates ChatOpenAI with that key (OpenRouter endpoint)
    • Falls back to Gemini if no key is available

Structure

backend/
├── server.py              # Entry point — starts FastAPI + Discord bot
├── app/
│   ├── api.py             # FastAPI routes (auth, sessions, links)
│   ├── bot.py             # Discord bot (commands, message handler)
│   ├── database.py        # SQLite via SQLAlchemy async
│   ├── agent_core/
│   │   ├── agent.py       # LangGraph agent + LLM setup
│   │   ├── models.py      # Agent state schema
│   │   ├── prompts.py     # System prompts
│   │   └── tools/         # Discord tool implementations
│   └── auth.py            # Discord OAuth2
frontend/                   # Vite + React SPA