MoA Agent Gateway
This project now runs as a chat gateway in front of @mariozechner/pi-coding-agent.
It supports:
- long-lived agent conversations
- HTTP JSON API
- streaming responses via Server-Sent Events (SSE)
- a built-in browser chat UI at
/
You can also keep one-shot mode (RUN_MODE=single) for script usage.
Documentation
- Gateway internals:
docs/gateway.md - Web UI internals:
docs/web-ui.md - Channel integrations (Web UI, Slack, Matrix, custom):
docs/channels.md
Run
cp .env.example .env
# set provider/model/key in .env
docker compose up --build
Gateway default URL:
http://localhost:8787
Health check:
curl http://localhost:8787/health
One-shot mode (legacy behavior):
RUN_MODE=single PROMPT="List files" npm start
API
Create/list conversations
curl -X POST http://localhost:8787/v1/conversations \
-H 'content-type: application/json' \
-d '{"conversationId":"web:user-42:chat-a"}'
curl http://localhost:8787/v1/conversations
Chat (non-streaming)
curl -X POST http://localhost:8787/v1/chat \
-H 'content-type: application/json' \
-d '{"conversationId":"web:user-42:chat-a","message":"Summarize this repo"}'
Chat (streaming SSE)
curl -N -X POST http://localhost:8787/v1/chat/stream \
-H 'content-type: application/json' \
-d '{"conversationId":"web:user-42:chat-a","message":"List TypeScript files"}'
Adapter-friendly endpoint (Slack/Matrix/etc)
Instead of constructing conversationId in your adapter, you can call:
POST /v1/adapters/chatPOST /v1/adapters/chat/stream
Body fields:
{
"source": "slack",
"workspaceId": "T123",
"channelId": "C456",
"threadId": "1712233.991",
"userId": "U789",
"message": "Summarize the thread"
}
The gateway derives a stable conversation id:
source:workspaceId:channelId:threadId
SSE events include:
assistant_text_deltaassistant_thinking_deltatool_start,tool_update,tool_endagent_start,agent_enddone(final response payload)error
Built-in Web UI
Open:
http://localhost:8787/
The UI stores conversationId in local storage and reuses it to keep context.
Auth and CORS
Optional env vars:
GATEWAY_AUTH_TOKEN: requireAuthorization: Bearer <token>GATEWAY_CORS_ORIGIN: e.g.*orhttps://my-ui.example
Multi-client strategy (Slack / Matrix / custom UI)
The gateway is transport-agnostic. For each upstream client, map its thread identity to a stable conversationId, for example:
- Web:
web:<userId>:<chatId> - Slack:
slack:<teamId>:<channelId>:<threadTs> - Matrix:
matrix:<roomId>:<threadRootEventId>
Then post messages to /v1/chat or /v1/chat/stream with that conversationId.
This keeps one agent session per thread across transports.
For detailed setup guidance per transport, see docs/channels.md.