chore: sync workspace changes

This commit is contained in:
Nathan Flurry 2026-01-27 05:06:33 -08:00
parent d24f983e2c
commit bf58891edf
139 changed files with 5454 additions and 8986 deletions

View file

@ -11,6 +11,7 @@ description: "Supported agents, install methods, and streaming formats."
| Codex | OpenAI | `codex` | curl tarball from GitHub releases | `thread_id` | JSON-RPC over stdio |
| OpenCode | Multi-provider | `opencode` | curl tarball from GitHub releases | `session_id` | SSE or JSONL |
| Amp | Sourcegraph | `amp` | curl raw binary from GCS | `session_id` | JSONL via stdout |
| Mock | Built-in | — | bundled | `mock-*` | daemon-generated |
## Agent modes

15
docs/ai/llms-txt.mdx Normal file
View file

@ -0,0 +1,15 @@
---
title: "llms.txt"
description: "LLM-friendly documentation manifests."
---
Mintlify publishes `llms.txt` and `llms-full.txt` for this documentation site.
Access them at:
```
https://rivet.dev/docs/llms.txt
https://rivet.dev/docs/llms-full.txt
```
If you run a reverse proxy in front of the docs, forward `/llms.txt` and `/llms-full.txt` to Mintlify.

21
docs/ai/skill.mdx Normal file
View file

@ -0,0 +1,21 @@
---
title: "skill.md"
description: "Agent skill manifest for this documentation."
---
Mintlify hosts a `skill.md` file for this documentation site.
Access it at:
```
https://rivet.dev/docs/skill.md
```
To add it to an agent using the Skills CLI:
```
npx skills add rivet.dev/docs/skill.md
```
If you run a reverse proxy in front of the docs, make sure `/skill.md` and `/.well-known/skills/*`
are forwarded to Mintlify.

View file

@ -257,7 +257,7 @@ Defined in `sdks/typescript/src/spawn.ts`:
6. **Cleanup**: On dispose, sends SIGTERM then SIGKILL if needed; also registers process exit handlers
```typescript
const handle = await spawnSandboxDaemon({ log: "inherit" });
const handle = await spawnSandboxAgent({ log: "inherit" });
// handle.baseUrl = "http://127.0.0.1:<port>"
// handle.token = "<generated>"
// handle.dispose() to cleanup
@ -267,12 +267,12 @@ const handle = await spawnSandboxDaemon({ log: "inherit" });
Defined in `sdks/typescript/src/client.ts`:
- Direct HTTP client to a remote `sandbox-daemon` server
- Direct HTTP client to a remote `sandbox-agent` server
- Uses provided `baseUrl` and optional `token`
- No subprocess management
```typescript
const client = new SandboxDaemonClient({
const client = await SandboxAgent.connect({
baseUrl: "http://remote-server:8080",
token: "secret",
});
@ -280,26 +280,26 @@ const client = new SandboxDaemonClient({
### Auto-Detection
`SandboxDaemonClient.connect()` chooses the mode automatically:
`SandboxAgent` provides two factory methods:
```typescript
// If baseUrl provided → server mode
const client = await SandboxDaemonClient.connect({
// Connect to existing server
const client = await SandboxAgent.connect({
baseUrl: "http://remote:8080",
});
// If no baseUrl → embedded mode (spawns subprocess)
const client = await SandboxDaemonClient.connect({});
// Start embedded subprocess
const client = await SandboxAgent.start();
// Explicit control
const client = await SandboxDaemonClient.connect({
spawn: { enabled: true, port: 9000 },
// With options
const client = await SandboxAgent.start({
spawn: { port: 9000 },
});
```
The `spawn` option can be:
- `true` / `false` - Enable/disable embedded mode
- `SandboxDaemonSpawnOptions` - Fine-grained control over host, port, token, binary path, timeout, logging
- `SandboxAgentSpawnOptions` - Fine-grained control over host, port, token, binary path, timeout, logging
## Authentication

View file

@ -31,7 +31,7 @@ Every event includes:
- `event_id`, `sequence`, and `time` for ordering.
- `session_id` for the universal session.
- `native_session_id` for provider-specific debugging.
- `event_type` with one of:
- `type` with one of:
- `session.started`, `session.ended`
- `item.started`, `item.delta`, `item.completed`
- `permission.requested`, `permission.resolved`
@ -61,13 +61,13 @@ const items = new Map<string, ItemState>();
const order: string[] = [];
function applyEvent(event: UniversalEvent) {
if (event.event_type === "item.started") {
if (event.type === "item.started") {
const item = event.data.item;
items.set(item.item_id, { item, deltas: [] });
order.push(item.item_id);
}
if (event.event_type === "item.delta") {
if (event.type === "item.delta") {
const { item_id, delta } = event.data;
const state = items.get(item_id);
if (state) {
@ -75,7 +75,7 @@ function applyEvent(event: UniversalEvent) {
}
}
if (event.event_type === "item.completed") {
if (event.type === "item.completed") {
const item = event.data.item;
const state = items.get(item.item_id);
if (state) {
@ -141,23 +141,19 @@ receive the `raw` payload for each event.
Both yield the same event payloads.
## Mock mode for UI testing
## Mock agent for UI testing
Run the server with `--mock` to emit a looping, feature-complete event history for UI development:
Use the built-in `mock` agent to exercise UI behaviors without external credentials:
```bash
sandbox-agent server --mock --no-token
curl -X POST http://127.0.0.1:2468/v1/sessions/demo-session \
-H "content-type: application/json" \
-d '{"agent":"mock"}'
```
Behavior in mock mode:
- Sessions emit a fixed history that covers every event type and content part.
- The history repeats in a loop, with ~200ms between events and a ~2s pause between loops.
- `session.started` and `session.ended` are included in every loop so UIs can exercise lifecycle handling.
- `send-message` is accepted but does not change the mock stream.
If your UI stops rendering after `session.ended`, disable that behavior while testing mock mode so the
loop remains visible.
The mock agent sends a prompt telling you what commands it accepts. Send messages like `demo`,
`markdown`, or `permission` to emit specific event sequences. Any other text is echoed back as an
assistant message so you can test rendering, streaming, and approval flows on demand.
## Reference implementation

View file

@ -3,18 +3,19 @@ title: "CLI"
description: "CLI reference and server flags."
---
The `sandbox-daemon` CLI mirrors the HTTP API so you can script everything without writing client code.
The `sandbox-agent` CLI mirrors the HTTP API so you can script everything without writing client code.
## Server flags
```bash
sandbox-daemon server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
sandbox-agent server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
```
- `--token`: global token for all requests.
- `--no-token`: disable auth (local dev only).
- `--host`, `--port`: bind address.
- `--cors-allow-origin`, `--cors-allow-method`, `--cors-allow-header`, `--cors-allow-credentials`: configure CORS.
- `--no-telemetry`: disable anonymous telemetry.
## Agent commands
@ -22,7 +23,7 @@ sandbox-daemon server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
<summary><strong>agents list</strong></summary>
```bash
sandbox-daemon agents list --endpoint http://127.0.0.1:2468
sandbox-agent agents list --endpoint http://127.0.0.1:2468
```
</details>
@ -30,7 +31,7 @@ sandbox-daemon agents list --endpoint http://127.0.0.1:2468
<summary><strong>agents install</strong></summary>
```bash
sandbox-daemon agents install claude --reinstall --endpoint http://127.0.0.1:2468
sandbox-agent agents install claude --reinstall --endpoint http://127.0.0.1:2468
```
</details>
@ -38,7 +39,7 @@ sandbox-daemon agents install claude --reinstall --endpoint http://127.0.0.1:246
<summary><strong>agents modes</strong></summary>
```bash
sandbox-daemon agents modes claude --endpoint http://127.0.0.1:2468
sandbox-agent agents modes claude --endpoint http://127.0.0.1:2468
```
</details>
@ -48,7 +49,7 @@ sandbox-daemon agents modes claude --endpoint http://127.0.0.1:2468
<summary><strong>sessions create</strong></summary>
```bash
sandbox-daemon sessions create my-session \
sandbox-agent sessions create my-session \
--agent claude \
--agent-mode build \
--permission-mode default \
@ -60,7 +61,7 @@ sandbox-daemon sessions create my-session \
<summary><strong>sessions send-message</strong></summary>
```bash
sandbox-daemon sessions send-message my-session \
sandbox-agent sessions send-message my-session \
--message "Summarize the repository" \
--endpoint http://127.0.0.1:2468
```
@ -70,7 +71,7 @@ sandbox-daemon sessions send-message my-session \
<summary><strong>sessions events</strong></summary>
```bash
sandbox-daemon sessions events my-session --offset 0 --limit 50 --endpoint http://127.0.0.1:2468
sandbox-agent sessions events my-session --offset 0 --limit 50 --endpoint http://127.0.0.1:2468
```
</details>
@ -78,7 +79,7 @@ sandbox-daemon sessions events my-session --offset 0 --limit 50 --endpoint http:
<summary><strong>sessions events-sse</strong></summary>
```bash
sandbox-daemon sessions events-sse my-session --offset 0 --endpoint http://127.0.0.1:2468
sandbox-agent sessions events-sse my-session --offset 0 --endpoint http://127.0.0.1:2468
```
</details>
@ -86,7 +87,7 @@ sandbox-daemon sessions events-sse my-session --offset 0 --endpoint http://127.0
<summary><strong>sessions reply-question</strong></summary>
```bash
sandbox-daemon sessions reply-question my-session QUESTION_ID \
sandbox-agent sessions reply-question my-session QUESTION_ID \
--answers "yes" \
--endpoint http://127.0.0.1:2468
```
@ -96,7 +97,7 @@ sandbox-daemon sessions reply-question my-session QUESTION_ID \
<summary><strong>sessions reject-question</strong></summary>
```bash
sandbox-daemon sessions reject-question my-session QUESTION_ID --endpoint http://127.0.0.1:2468
sandbox-agent sessions reject-question my-session QUESTION_ID --endpoint http://127.0.0.1:2468
```
</details>
@ -104,7 +105,7 @@ sandbox-daemon sessions reject-question my-session QUESTION_ID --endpoint http:/
<summary><strong>sessions reply-permission</strong></summary>
```bash
sandbox-daemon sessions reply-permission my-session PERMISSION_ID \
sandbox-agent sessions reply-permission my-session PERMISSION_ID \
--reply once \
--endpoint http://127.0.0.1:2468
```

View file

@ -1,21 +0,0 @@
---
title: "Cloudflare Sandboxes"
description: "Deploy the daemon in Cloudflare Sandboxes."
---
## Steps
1. Create a Cloudflare Sandbox with a Linux runtime.
2. Install the agent binaries and the sandbox-agent daemon.
3. Start the daemon and expose the HTTP port.
```bash
export SANDBOX_TOKEN="..."
cargo run -p sandbox-agent -- server \
--token "$SANDBOX_TOKEN" \
--host 0.0.0.0 \
--port 2468
```
4. Connect your client to the sandbox endpoint.

View file

@ -1,82 +1,72 @@
{
"$schema": "https://mintlify.com/docs.json",
"theme": "almond",
"name": "Sandbox Agent SDK",
"colors": {
"primary": "#ff4f00",
"light": "#000000",
"dark": "#ffffff"
},
"favicon": "/favicon.svg",
"logo": {
"light": "/logo/light.svg",
"dark": "/logo/dark.svg"
},
"navigation": {
"tabs": [
{
"tab": "Guides",
"groups": [
{
"group": "Getting started",
"pages": [
"index",
"quickstart",
"architecture",
"agent-compatibility",
"universal-api"
]
},
{
"group": "Operations",
"pages": [
"frontend",
"building-chat-ui"
]
},
{
"group": "SDKs",
"pages": [
"sdks/typescript"
]
}
]
},
{
"tab": "Reference",
"groups": [
{
"group": "Interfaces",
"pages": [
"cli",
"http-api",
"typescript-sdk"
]
},
{
"group": "API",
"openapi": "openapi.json"
}
]
},
{
"tab": "Deployments",
"groups": [
{
"group": "Examples",
"pages": [
"deployments/docker",
"deployments/e2b",
"deployments/daytona",
"deployments/vercel-sandboxes",
"deployments/cloudflare-sandboxes"
]
}
]
}
]
},
"styles": [
"/theme.css"
]
"$schema": "https://mintlify.com/docs.json",
"theme": "willow",
"name": "Sandbox Agent SDK",
"appearance": {
"default": "dark",
"strict": true
},
"colors": {
"primary": "#ff4f00",
"light": "#ff4f00",
"dark": "#ff4f00"
},
"favicon": "/favicon.svg",
"logo": {
"light": "/logo/light.svg",
"dark": "/logo/dark.svg"
},
"navbar": {
"links": [
{
"label": "Discord",
"icon": "discord",
"href": "https://rivet.dev/discord"
},
{
"label": "GitHub",
"icon": "github",
"href": "https://github.com/rivet-dev/sandbox-agent"
}
]
},
"navigation": {
"pages": [
{
"group": "Getting started",
"pages": [
"index",
"quickstart",
"architecture",
"agent-compatibility",
"universal-api",
"frontend",
"building-chat-ui",
"persisting-chat-logs"
]
},
{
"group": "SDKs",
"pages": ["sdks/typescript"]
},
{
"group": "AI",
"pages": ["ai/skill", "ai/llms-txt"]
},
{
"group": "Reference",
"pages": ["cli", "telemetry", "http-api"]
},
{
"group": "Deploy",
"pages": [
"deploy/index",
"deploy/docker",
"deploy/e2b",
"deploy/daytona",
"deploy/vercel-sandboxes"
]
}
]
}
}

View file

@ -1,6 +1,6 @@
---
title: "Frontend Demo"
description: "Run the Vite + React UI for testing the daemon."
description: "Run the Vite + React UI for testing the server."
---
The demo frontend lives at `frontend/packages/inspector`.
@ -17,6 +17,6 @@ The UI expects:
- Endpoint (e.g. `http://127.0.0.1:2468`)
- Optional token
When running the daemon, the inspector is also served automatically at `http://127.0.0.1:2468/ui`.
When running the server, the inspector is also served automatically at `http://127.0.0.1:2468/ui`.
If you see CORS errors, enable CORS on the daemon with `sandbox-daemon server --cors-allow-origin` and related flags.
If you see CORS errors, enable CORS on the server with `sandbox-agent server --cors-allow-origin` and related flags.

View file

@ -18,7 +18,7 @@ Sandbox Agent SDK is a universal API and daemon for running coding agents inside
Run the daemon locally:
```bash
sandbox-daemon server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
sandbox-agent server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
```
Send a message:

View file

@ -600,9 +600,38 @@
"planMode",
"permissions",
"questions",
"toolCalls"
"toolCalls",
"toolResults",
"textMessages",
"images",
"fileAttachments",
"sessionLifecycle",
"errorEvents",
"reasoning",
"commandExecution",
"fileChanges",
"mcpTools",
"streamingDeltas"
],
"properties": {
"commandExecution": {
"type": "boolean"
},
"errorEvents": {
"type": "boolean"
},
"fileAttachments": {
"type": "boolean"
},
"fileChanges": {
"type": "boolean"
},
"images": {
"type": "boolean"
},
"mcpTools": {
"type": "boolean"
},
"permissions": {
"type": "boolean"
},
@ -612,8 +641,23 @@
"questions": {
"type": "boolean"
},
"reasoning": {
"type": "boolean"
},
"sessionLifecycle": {
"type": "boolean"
},
"streamingDeltas": {
"type": "boolean"
},
"textMessages": {
"type": "boolean"
},
"toolCalls": {
"type": "boolean"
},
"toolResults": {
"type": "boolean"
}
}
},
@ -1537,4 +1581,4 @@
"description": "Session management"
}
]
}
}

View file

@ -0,0 +1,21 @@
---
title: "Persisting Chat Logs"
description: "Persist event streams so you can resume sessions and keep durable chat history."
---
Persisting chat logs is easiest when you treat the event stream as the source of truth.
## Recommended approach
- Store the offset of the last message you have seen (the last event id).
- Update your server to stream events from the Events API using that offset.
- Write the resulting messages and events to your own database.
This lets you resume from a known offset after a disconnect and prevents duplicate writes.
## Recommended: Rivet Actors
If you want a managed way to keep long-running streams alive, consider [Rivet Actors](https://rivet.dev).
They handle continuous event streaming plus fast reads and writes of data for agents, with built-in
realtime support and observability. You can use them to stream `/events/sse` per session and persist
each event to your database as it arrives.

View file

@ -1,20 +1,20 @@
---
title: "Quickstart"
description: "Start the daemon and send your first message."
description: "Start the server and send your first message."
---
## 1. Run the daemon
## 1. Run the server
Use the installed binary, or `cargo run` in development.
```bash
sandbox-daemon server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
sandbox-agent server --token "$SANDBOX_TOKEN" --host 127.0.0.1 --port 2468
```
If you want to run without auth (local dev only):
```bash
sandbox-daemon server --no-token --host 127.0.0.1 --port 2468
sandbox-agent server --no-token --host 127.0.0.1 --port 2468
```
If you're running from source instead of the installed CLI:
@ -25,10 +25,10 @@ cargo run -p sandbox-agent -- server --token "$SANDBOX_TOKEN" --host 127.0.0.1 -
### CORS (frontend usage)
If you are calling the daemon from a browser, enable CORS explicitly:
If you are calling the server from a browser, enable CORS explicitly:
```bash
sandbox-daemon server \
sandbox-agent server \
--token "$SANDBOX_TOKEN" \
--cors-allow-origin "http://localhost:5173" \
--cors-allow-method "GET" \
@ -75,7 +75,7 @@ curl "http://127.0.0.1:2468/v1/sessions/my-session/events/sse?offset=0" \
The CLI mirrors the HTTP API:
```bash
sandbox-daemon sessions create my-session --agent claude --endpoint http://127.0.0.1:2468 --token "$SANDBOX_TOKEN"
sandbox-agent sessions create my-session --agent claude --endpoint http://127.0.0.1:2468 --token "$SANDBOX_TOKEN"
sandbox-daemon sessions send-message my-session --message "Hello" --endpoint http://127.0.0.1:2468 --token "$SANDBOX_TOKEN"
sandbox-agent sessions send-message my-session --message "Hello" --endpoint http://127.0.0.1:2468 --token "$SANDBOX_TOKEN"
```

View file

@ -3,7 +3,7 @@ title: "TypeScript SDK"
description: "Use the generated client to manage sessions and stream events."
---
The TypeScript SDK is generated from the OpenAPI spec that ships with the daemon. It provides a typed
The TypeScript SDK is generated from the OpenAPI spec that ships with the server. It provides a typed
client for sessions, events, and agent operations.
## Install
@ -15,34 +15,22 @@ npm install sandbox-agent
## Create a client
```ts
import { SandboxDaemonClient } from "sandbox-agent";
import { SandboxAgent } from "sandbox-agent";
const client = new SandboxDaemonClient({
const client = await SandboxAgent.connect({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
```
Or with the factory helper:
```ts
import { createSandboxDaemonClient } from "sandbox-agent";
const client = createSandboxDaemonClient({
baseUrl: "http://127.0.0.1:2468",
});
```
## Autospawn (Node only)
If you run locally, the SDK can launch the daemon for you.
If you run locally, the SDK can launch the server for you.
```ts
import { connectSandboxDaemonClient } from "sandbox-agent";
import { SandboxAgent } from "sandbox-agent";
const client = await connectSandboxDaemonClient({
spawn: { enabled: true },
});
const client = await SandboxAgent.start();
await client.dispose();
```
@ -55,8 +43,8 @@ Autospawn uses the local `sandbox-agent` binary. Install `@sandbox-agent/cli` (r
```ts
await client.createSession("demo-session", {
agent: "codex",
agent_mode: "default",
permission_mode: "plan",
agentMode: "default",
permissionMode: "plan",
});
await client.postMessage("demo-session", { message: "Hello" });
@ -76,11 +64,11 @@ console.log(codex?.capabilities);
const events = await client.getEvents("demo-session", {
offset: 0,
limit: 200,
include_raw: false,
includeRaw: false,
});
for (const event of events.events) {
console.log(event.event_type, event.data);
console.log(event.type, event.data);
}
```
@ -89,9 +77,9 @@ for (const event of events.events) {
```ts
for await (const event of client.streamEvents("demo-session", {
offset: 0,
include_raw: false,
includeRaw: false,
})) {
console.log(event.event_type, event.data);
console.log(event.type, event.data);
}
```
@ -100,20 +88,20 @@ The SDK parses `text/event-stream` into `UniversalEvent` objects. If you want fu
## Optional raw payloads
Set `include_raw: true` on `getEvents` or `streamEvents` to include the raw provider payload in
Set `includeRaw: true` on `getEvents` or `streamEvents` to include the raw provider payload in
`event.raw`. This is useful for debugging and conversion analysis.
## Error handling
All HTTP errors throw `SandboxDaemonError`:
All HTTP errors throw `SandboxAgentError`:
```ts
import { SandboxDaemonError } from "sandbox-agent";
import { SandboxAgentError } from "sandbox-agent";
try {
await client.postMessage("missing-session", { message: "Hi" });
} catch (error) {
if (error instanceof SandboxDaemonError) {
if (error instanceof SandboxAgentError) {
console.error(error.status, error.problem);
}
}

30
docs/telemetry.mdx Normal file
View file

@ -0,0 +1,30 @@
---
title: "Telemetry"
description: "Anonymous telemetry collected by sandbox-agent."
---
sandbox-agent sends a small, anonymous telemetry payload on startup to help us understand usage and improve reliability.
## What gets sent
- Sandbox Agent version.
- OS name, architecture, and OS family.
- Detected sandbox provider (for example: Docker, E2B, Vercel Sandboxes).
Each sandbox gets a random anonymous ID stored on disk so usage can be counted without identifying users.
## Opting out
Telemetry is enabled by default in release builds.
Disable it with:
```bash
sandbox-agent server --no-telemetry
```
Debug builds disable telemetry automatically. You can opt in with:
```bash
SANDBOX_AGENT_TELEMETRY_DEBUG=1 sandbox-agent server
```

View file

@ -1,118 +0,0 @@
---
title: "TypeScript SDK"
description: "Generated types and a thin fetch-based client."
---
The TypeScript SDK is generated from the OpenAPI spec produced by the Rust server.
## Generate types
```bash
pnpm --filter sandbox-agent generate
```
This runs:
- `cargo run -p sandbox-agent-openapi-gen -- --out docs/openapi.json` to emit OpenAPI JSON
- `openapi-typescript` to generate types
## Usage
```ts
import { SandboxDaemonClient } from "sandbox-agent";
const client = new SandboxDaemonClient({
baseUrl: "http://127.0.0.1:2468",
token: process.env.SANDBOX_TOKEN,
});
await client.createSession("my-session", { agent: "claude" });
await client.postMessage("my-session", { message: "Hello" });
const events = await client.getEvents("my-session", { offset: 0, limit: 50 });
```
## Autospawn (Node only)
```ts
import { connectSandboxDaemonClient } from "sandbox-agent";
const client = await connectSandboxDaemonClient({
spawn: { enabled: true },
});
await client.createSession("my-session", { agent: "claude" });
await client.postMessage("my-session", { message: "Hello" });
await client.dispose();
```
Autospawn uses the local `sandbox-agent` binary. Install `@sandbox-agent/cli` (recommended), or
set `SANDBOX_AGENT_BIN` to the binary path.
## Endpoint mapping
<details>
<summary><strong>client.listAgents()</strong></summary>
Maps to `GET /v1/agents`.
</details>
<details>
<summary><strong>client.installAgent(agentId, body)</strong></summary>
Maps to `POST /v1/agents/{agentId}/install`.
</details>
<details>
<summary><strong>client.getAgentModes(agentId)</strong></summary>
Maps to `GET /v1/agents/{agentId}/modes`.
</details>
<details>
<summary><strong>client.createSession(sessionId, body)</strong></summary>
Maps to `POST /v1/sessions/{sessionId}`.
</details>
<details>
<summary><strong>client.postMessage(sessionId, body)</strong></summary>
Maps to `POST /v1/sessions/{sessionId}/messages`.
</details>
<details>
<summary><strong>client.getEvents(sessionId, params)</strong></summary>
Maps to `GET /v1/sessions/{sessionId}/events`.
</details>
<details>
<summary><strong>client.getEventsSse(sessionId, params)</strong></summary>
Maps to `GET /v1/sessions/{sessionId}/events/sse` (raw SSE response).
</details>
<details>
<summary><strong>client.streamEvents(sessionId, params)</strong></summary>
Helper that parses SSE into `UniversalEvent` objects.
</details>
<details>
<summary><strong>client.replyQuestion(sessionId, questionId, body)</strong></summary>
Maps to `POST /v1/sessions/{sessionId}/questions/{questionId}/reply`.
</details>
<details>
<summary><strong>client.rejectQuestion(sessionId, questionId)</strong></summary>
Maps to `POST /v1/sessions/{sessionId}/questions/{questionId}/reject`.
</details>
<details>
<summary><strong>client.replyPermission(sessionId, permissionId, body)</strong></summary>
Maps to `POST /v1/sessions/{sessionId}/permissions/{permissionId}/reply`.
</details>