Use SYBIL_AGENT_BASE_URL and SYBIL_AGENT_API_KEY with the renamed sybil-agent service. Update errors, API documentation, and test fixtures while retaining the existing room protocol and browser storage keys for compatibility. Validation: 44 server tests, 51 web tests, and both production builds.
133 lines
5.0 KiB
Markdown
133 lines
5.0 KiB
Markdown
# Sybil Server
|
|
|
|
Backend API for:
|
|
- LLM multiplexer (OpenAI Responses / Anthropic / xAI Chat Completions-compatible Grok / Gemini / Hermes Agent)
|
|
- Personal chat database (chats/messages + LLM call log)
|
|
|
|
## Stack
|
|
- Node.js + TypeScript
|
|
- Fastify (HTTP)
|
|
- Prisma + SQLite (dev)
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
npm run dev
|
|
```
|
|
|
|
Migrations are applied automatically on server startup (`prisma migrate deploy`).
|
|
|
|
Open docs: `http://localhost:8787/docs`
|
|
|
|
API contract docs for clients:
|
|
- `../docs/api/rest.md`
|
|
- `../docs/api/streaming-chat.md`
|
|
|
|
## Run Modes
|
|
|
|
- `npm run dev`: runs `src/index.ts` with `tsx` in watch mode (auto-restart on file changes). Use for local development.
|
|
- `npm run start`: runs compiled `dist/index.js` with Node.js (no watch mode). Use for production-like runs.
|
|
|
|
Both modes run startup checks (`predev` / `prestart`) and apply migrations at app boot.
|
|
|
|
## Auth
|
|
|
|
Set `ADMIN_TOKEN` and send:
|
|
|
|
`Authorization: Bearer <ADMIN_TOKEN>`
|
|
|
|
If `ADMIN_TOKEN` is not set, the server runs in open mode (dev).
|
|
|
|
## Env
|
|
- `OPENAI_API_KEY`
|
|
- `ANTHROPIC_API_KEY`
|
|
- `XAI_API_KEY`
|
|
- `GEMINI_API_KEY`
|
|
- `HERMES_AGENT_API_BASE_URL` (`http://127.0.0.1:8642/v1` by default; include the `/v1` suffix)
|
|
- `HERMES_AGENT_API_KEY` (enables the Hermes Agent provider; set to Hermes `API_SERVER_KEY`, or any non-empty value if that local server does not require auth)
|
|
- `HERMES_AGENT_MODEL` (optional fallback/override model id; defaults client-side to `hermes-agent`)
|
|
- `EXA_API_KEY`
|
|
- `BRAVE_SEARCH_API_KEY` (required when `CHAT_WEB_SEARCH_ENGINE=brave`)
|
|
- `CHAT_WEB_SEARCH_ENGINE` (`exa` by default; `brave` and `searxng` are also supported for chat tool calls only)
|
|
- `SEARXNG_BASE_URL` (required when `CHAT_WEB_SEARCH_ENGINE=searxng`; instance must allow `format=json`)
|
|
- `CHAT_MAX_TOOL_ROUNDS` (`100` by default; maximum model/tool result cycles per chat completion)
|
|
- `CHAT_CODEX_TOOL_ENABLED` (`false` by default; enables the `codex_exec` chat tool for managed-tool providers)
|
|
- `CHAT_CODEX_REMOTE_HOST` (required when Codex tool is enabled; SSH host/IP or `user@host`)
|
|
- `CHAT_CODEX_REMOTE_USER` (optional SSH user when host does not include one)
|
|
- `CHAT_CODEX_REMOTE_PORT` (`22` by default)
|
|
- `CHAT_CODEX_REMOTE_WORKDIR` (`/workspace/sybil-codex` by default; created and reused on the devbox)
|
|
- `CHAT_CODEX_SSH_KEY_PATH` (recommended: path to a read-only mounted private key)
|
|
- `CHAT_CODEX_SSH_PRIVATE_KEY_B64` (optional fallback private key delivery)
|
|
- `CHAT_CODEX_EXEC_TIMEOUT_MS` (`600000` by default)
|
|
- `CHAT_SHELL_TOOL_ENABLED` (`false` by default; enables the `shell_exec` chat tool for managed-tool providers on the same devbox)
|
|
- `CHAT_SHELL_EXEC_TIMEOUT_MS` (`120000` by default)
|
|
|
|
## API
|
|
- `GET /health`
|
|
- `GET /v1/auth/session`
|
|
- `GET /v1/chats`
|
|
- `POST /v1/chats`
|
|
- `GET /v1/chats/:chatId`
|
|
- `POST /v1/chats/:chatId/messages`
|
|
- `POST /v1/chat-completions`
|
|
- `POST /v1/chat-completions/stream` (SSE)
|
|
- `GET /v1/searches`
|
|
- `POST /v1/searches`
|
|
- `GET /v1/searches/:searchId`
|
|
- `POST /v1/searches/:searchId/run`
|
|
- `POST /v1/searches/:searchId/run/stream` (SSE)
|
|
|
|
Search runs now execute both Exa `searchAndContents` and Exa `answer`, storing:
|
|
- ranked search results (for result cards), and
|
|
- a top-level answer block + citations.
|
|
|
|
When `chatId` is provided to completion endpoints, you can send full conversation context. The server now stores only new non-assistant messages to avoid duplicate history rows.
|
|
|
|
`POST /v1/chat-completions` body example:
|
|
|
|
```json
|
|
{
|
|
"chatId": "<optional chat id>",
|
|
"provider": "openai",
|
|
"model": "gpt-4.1-mini",
|
|
"messages": [
|
|
{"role":"system","content":"You are helpful."},
|
|
{"role":"user","content":"Say hi"}
|
|
],
|
|
"temperature": 0.2,
|
|
"maxTokens": 256
|
|
}
|
|
```
|
|
|
|
## Next steps (planned)
|
|
- Better streaming protocol compatibility (OpenAI-style chunks + cancellation)
|
|
- Tool/function calling normalization
|
|
- User accounts + per-device API keys
|
|
- Postgres support + migrations for prod
|
|
- Attachments + embeddings + semantic search
|
|
|
|
## Sybil Agent
|
|
|
|
Configure the backend with:
|
|
|
|
```dotenv
|
|
SYBIL_AGENT_BASE_URL=http://sybil-agent:8788
|
|
SYBIL_AGENT_API_KEY=<the Sybil Agent service API key>
|
|
```
|
|
|
|
Use the same `SYBIL_AGENT_API_KEY` value configured on the agent service.
|
|
The base URL defaults to `http://sybil-agent:8788` and has no `/v1` suffix. In Docker,
|
|
attach Sybil's **server** container and Sybil Agent to the shared `agents` network so that
|
|
`sybil-agent` resolves privately. Supply the key through a private server environment
|
|
file; it is never a `VITE_*` variable or browser setting. Keep the existing Sybil
|
|
`ADMIN_TOKEN` authentication for clients.
|
|
|
|
The Sybil Agent tab uses `/v1/agent`, `/v1/agent/messages`, and `/v1/agent/ws` to proxy the
|
|
same persistent root conversation across devices. Sybil Agent remains the source of
|
|
truth for messages and background replies. Sybil stores only the shared,
|
|
monotonically increasing read cursor in SQLite through `/v1/agent/read-state`;
|
|
its migration is applied automatically at startup. The bundled nginx configuration
|
|
forwards WebSocket upgrades. See `docs/api/rest.md` and
|
|
`docs/api/streaming-chat.md` at the repository root for the client contracts.
|