Build, configure, and orchestrate multi-agent AI workflows with a live web UI, async messaging, and real external channel integration.
https://drive.google.com/file/d/1ZwJHIZwjUb94rIz8VyuZBnA9b9Jv7naY/view?usp=drive_link
┌─────────────────────────────────────────────────────────────────┐
│ AgentOrch Platform │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Next.js │ │ FastAPI │ │ Agent Runtime │ │
│ │ Web UI │◄──►│ REST + WS │◄──►│ (LangGraph) │ │
│ └──────────┘ └──────┬───────┘ └──────────┬───────────┘ │
│ │ │ │
│ ┌──────▼──────┐ ┌────────▼──────────┐ │
│ │ SQLite / │ │ Tool Executors │ │
│ │ Postgres │ │ web_search │ │
│ └─────────────┘ │ code_executor │ │
│ │ file_reader │ │
│ ┌─────────────────────────────┐ └───────────────────┘ │
│ │ Messaging Channels │ │
│ │ ┌──────────┐ ┌──────────┐ │ ┌───────────────────────┐ │
│ │ │ Telegram │ │ Slack │ │ │ Vector Memory │ │
│ │ │ (Bot) │ │ (OAuth) │ │ │ ChromaDB (local) │ │
│ │ └──────────┘ └──────────┘ │ └───────────────────────┘ │
│ └─────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Redis Queue (async agent-to-agent messaging) │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Why LangGraph?
- Graph-based orchestration — workflows are naturally modeled as directed graphs with nodes (agents) and edges (message flows + conditions). LangGraph provides this natively with StateGraph.
- Async-first — full async/await support means agent nodes don't block each other; critical for real-time Telegram interactions.
- Built-in persistence —
SqliteSaverandPostgresSavercheckpointers give us conversation memory and workflow state replay out of the box. - Streaming —
astream_eventslets us push real-time token updates to the frontend WebSocket. - Conditional edges —
add_conditional_edgesmaps directly to the "conditions and feedback loops" requirement without custom routing logic.
- FastAPI — async by default, WebSocket support, OpenAPI docs auto-generated, Pydantic validation.
- SQLAlchemy + SQLite (default) / PostgreSQL (production) — clean ORM, migrations via Alembic.
- Redis (optional, defaults to in-memory queue) — durable async message queue for agent-to-agent communication.
- Next.js App Router — server components for initial data, client components for live updates.
- Zustand — lightweight state management for agent/workflow state.
- WebSocket — real-time log streaming and inter-agent message display.
- ReactFlow — visual workflow builder with drag-and-drop nodes.
- Webhook mode for production, polling for local dev.
- Async handlers map directly to LangGraph agent invocations.
git clone https://github.com/Ashutosh-code-arch/agentOrch
cd agentOrch
cp .env.example .env # fill in GROQ_API_KEY and TELEGRAM_BOT_TOKEN
make setup # installs all deps, seeds DB, starts all services
make dev # start appOr manually:
# 1. Backend
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # fill in GROQ_API_KEY and TELEGRAM_BOT_TOKEN
alembic upgrade head # init DB
uvicorn main:app --reload --port 8000
# 2. Frontend (new terminal)
cd frontend
npm install
npm run dev # http://localhost:3000agentOrch/
├── backend/
│ ├── main.py # FastAPI app entry
│ ├── agents/
│ │ ├── agent_model.py # Agent DB model + CRUD
│ │ ├── agent_runtime.py # LangGraph agent execution
│ │ ├── delegation.py # Agent delegation helpers
│ │ └── tool_registry.py # Available tools registry
│ ├── workflows/
│ │ ├── workflow_engine.py # LangGraph StateGraph builder
│ │ └── __init__.py
│ ├── channels/
│ │ ├── telegram_handler.py # Telegram bot + webhook
│ │ ├── telegram_setup.py # webhook URL with Telegram
│ │ └── slack_handler.py # Slack events API
│ ├── memory/
│ │ └── vector_memory.py # ChromaDB agent memory
│ ├── api/
│ │ ├── agents_router.py # CRUD endpoints
│ │ ├── workflows_router.py # Workflow endpoints
│ │ ├── messages_router.py # Message history
│ │ └── ws_router.py # WebSocket log stream
│ ├── runtime/
│ │ └── message_bus.py # Async agent message queue
│ └── tests/
│ │ └── test_suite.py
│ ├── database.py
├── frontend/
│ ├── src/
│ │ ├── app/ # Next.js app router pages
│ │ ├── components/
│ │ │ ├── AgentCard.tsx
│ │ │ ├── AgentModal.tsx
│ │ │ ├── AgentRunModal.tsx
│ │ │ ├── NodeInspector.tsx
│ │ │ ├── Shell.tsx
│ │ │ ├── StatsRow.tsx
│ │ │ ├── WorkflowCanvas.tsx
│ │ │ └── LiveLogs.tsx
│ │ ├── stores/
│ │ │ └── orchestrator.ts # Zustand store
│ │ └── hooks/
│ │ │ └── useWebSocket.ts
│ │ ├── lib/
│ │ │ ├── WorkflowData.ts
│ │ │ └── api.ts
│ └── package.json
├── docs/
│ └── architecture.md
├── Makefile
├── docker-compose.yml
└── README.md
Each agent is configurable across 11 dimensions:
| Dimension | Options |
|---|---|
| Name & Role | Free text |
| System Prompt | Full prompt engineering |
| Model | llama, gpt-4o, local Ollama, claude-sonnet-4 |
| Tools | web_search, code_executor, file_reader, send_message, calendar, database_query |
| Channel | Telegram, Slack, WhatsApp, API-only |
| Memory | Conversation window, Vector RAG, Sliding+summary, None |
| Schedule | Always-on, cron expression, event-triggered |
| Max tokens / budget | Per-call and daily limits |
| Guardrails | Content filter, rate limit, human-in-the-loop |
| Interaction rules | Who this agent can message, routing priority |
| Skills | Custom tool plugins (importable Python modules) |
- Open
backend/workflows/workflow_engine.py. - Add a new entry to the
WORKFLOW_TEMPLATESdict. Use role-based labels/config instead of hard-coded demo agent names, so the UI can bind the template to real active agents:
"my_template": {
"name": "My Template",
"description": "What it does",
"nodes": [
{"id": "trigger", "type": "trigger", "label": "Telegram Message", "config": {"channel": "telegram"}},
{"id": "agent1", "type": "agent", "label": "Research Agent", "config": {"role": "research", "tools": ["web_search"]}},
{"id": "action", "type": "action", "label": "Send to Telegram", "config": {"action": "send_message", "channel": "telegram"}},
],
"edges": [["trigger", "agent1"], ["agent1", "action"]],
}- Add the matching front-end visual template in
frontend/src/lib/workflowData.tswith the sameid, node ids, and edges. - Restart the backend/frontend. The template appears in the Workflow Builder tabs and can be run through
POST /api/workflows/{template_id}/run.
- Create
backend/channels/your_channel.pywith the same shape astelegram_handler.pyorslack_handler.py:
class YourChannelHandler:
async def start(self): ... # setup webhook, polling, or socket mode
async def send_message(self, to, text): ...
async def _on_message(self, event): ... # publish inbound AgentMessage
async def _on_bus_message(self, msg): ... # deliver outbound channel_reply- Register in
backend/channels/__init__.py - Start it from
backend/main.pywhen the required environment variables are present. - Add the channel option to
frontend/src/components/AgentModal.tsx. - Add setup/status UI in
frontend/src/app/channels/page.tsx. - Publish inbound messages with
metadata={"channel": "<name>"}and subscribe to<name>_channelfor outbound replies.
- User opens Telegram, messages
@ariabot: "Research the latest LLM benchmarks" - Telegram webhook fires →
TelegramHandler.on_message()→ placed on message bus - Aria (Support Agent) receives message → runs LangGraph node → classifies as
research_intent - Aria publishes to message bus:
{type: "delegate", to: "max", task: "LLM benchmarks"} - Max (Research Agent) receives →
web_searchtool executes → results returned - Max publishes:
{type: "result", to: "aria", content: "..."} - Aria formats and calls
send_messagetool → delivered to Telegram user - All messages stored in SQLite, visible in UI live log and conversation history
cd backend
pytest tests/ -v# Required
GROQ_API_KEY=sk-ant-...
TELEGRAM_BOT_TOKEN=7412...:AAF4...
# Optional
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
WEBHOOK_URL=https://your-domain.com # for Telegram webhook mode
DATABASE_URL=sqlite:///agentOrch.db # or postgresql://...
REDIS_URL=redis://localhost:6379 # leave unset for in-memory queue
CHROMA_HOST=localhost # for vector memory