Multi-replica streaming (Redis)
Swap the in-process token sink for the Redis transport so any pod can serve any run's SSE stream — the same byte-for-byte envelope, fanned across replicas over Redis pub/sub plus a replayable list.
The default token sink buffers a run's tokens in process memory — great for a single instance, but it means a run started on one pod can only be re-attached on that same pod. The Redis transport removes that constraint: any replica can serve any run's SSE stream, with the SSE envelope kept byte-identical.
Select it
import { defineConfig, tokenSinks } from '@adonis-agora/agent'
export default defineConfig({
model: () => aiSdkModel(openai('gpt-4o-mini')),
sink: tokenSinks.redis({ connection: 'main' }),
})tokenSinks.redis (aliased streamTransports.redis) fans a run's tokens across replicas over Redis pub/sub plus a replayable list, so a late or cross-instance subscriber replays the buffered chunks first and then follows live. Requires @adonisjs/redis installed and configured (config/redis.ts).
The default stays single-replica
Omit sink entirely to keep the in-process sink (tokenSinks.memory() selects it explicitly). Nothing about the SSE contract, the routes, or the client changes when you switch — only where the buffer lives. The @adonisjs/redis peer is imported only inside the redis thunk, so it stays fully optional.
Configuration
| Field | Default | Meaning |
|---|---|---|
connection | default connection | @adonisjs/redis connection name. |
keyPrefix | agent:stream | Key/channel namespace. |
ttlSeconds | 3600 | Sliding TTL on a run's replay keys, refreshed on every write. Set 0 to keep them until you clean up yourself. |
client | — | Bring-your-own RedisStreamClient adapter (over ioredis, node-redis, …). When set, @adonisjs/redis is not imported. |
ttlSeconds is the knob that keeps Redis from filling up: the framework never calls the sink's close(), so a run's replay buffer has no natural end of life. One hour is long enough that a client re-attaching after a browser restart still replays the whole run, and short enough that yesterday's transcripts aren't sitting in memory. Raise it if you re-attach on a longer horizon; set 0 only if something else prunes the keys.
Passing a client lets you drive a non-Adonis Redis driver or a test double directly — the factory uses it verbatim. Under the hood the adapter uses a dedicated duplicated connection per subscribe (a subscribed Redis connection can't run other commands).
Pair with the durable runner
The Redis sink solves stream portability across replicas; the durable runner solves run portability and crash-survival (a suspended HITL approval resumes on any pod). Together they give you a horizontally-scaled, crash-proof agent: sink: tokenSinks.redis(...) + durable: true.
For the underlying class, RedisTokenStreamSink (and the RedisStreamClient interface) are exported from the package root.
MCP client
Import an external MCP server's tools into this deployment's own ToolRegistry — HITL-gated by default, namespaced, schema-validated, and screened for a pattern that can stall the process.
Diagnostics & tracing
The eight lifecycle events and four span channels the agent publishes — their exact names and payloads, what is deliberately redacted, and how to subscribe.