highperfocused 7da55c01a0
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m3s
feature/pi-agent-gateway (#4)
Reviewed-on: MoA/agent#4
Co-authored-by: highperfocused <highperfocused@pm.me>
Co-committed-by: highperfocused <highperfocused@pm.me>
2026-03-12 21:43:33 +01:00

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/chat
  • POST /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_delta
  • assistant_thinking_delta
  • tool_start, tool_update, tool_end
  • agent_start, agent_end
  • done (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: require Authorization: Bearer <token>
  • GATEWAY_CORS_ORIGIN: e.g. * or https://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.

Description
No description provided
Readme 216 KiB
Languages
TypeScript 97.3%
Dockerfile 2.7%