@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
48 lines • 2.81 kB
TypeScript
import type { RedisStreamClient } from './redis-stream-client.js';
import type { SinkWriter, StreamFrame, TokenStreamSink } from './spi/token-stream-sink.js';
export interface RedisTokenStreamSinkOptions {
/** Key/channel namespace. Defaults to `agent:stream`. Keys are `${keyPrefix}:${runId}:...`. */
keyPrefix?: string;
/**
* TTL (seconds) applied to a run's `chunks`/`state` keys so they self-expire — the framework never
* calls {@link RedisTokenStreamSink.close}, so without this the replay buffer would accumulate in
* Redis forever. The TTL is a sliding window refreshed on every write, so a long run stays alive and
* a crashed run (that never `end`s) still expires. Defaults to 3600 (1h). Set `0` to disable and
* retain keys until `close()`/manual cleanup (the pre-TTL behaviour).
*/
ttlSeconds?: number;
}
/**
* A multi-replica {@link TokenStreamSink} over Redis — the shared-transport counterpart to the default
* {@link import('./in-process-sink.js').InProcessTokenStreamSink}. The replica running the model turn
* `open`s the writer and appends each token chunk to a Redis LIST (`${keyPrefix}:${runId}:chunks`) so
* ANY replica can replay the whole stream so far (the same late-subscriber/reconnect guarantee the
* in-process sink gives, but shared across pods), and PUBLISHes to a per-run channel
* (`${keyPrefix}:${runId}`) to wake live subscribers. The run's terminal state lives in a marker key
* (`${keyPrefix}:${runId}:state`), so an SSE handler on ANOTHER replica that subscribes after the run
* finished still sees the ending and closes the stream.
*
* The yielded frames are identical (frame-for-frame) to the in-process sink's, so the agent-protocol
* SSE the provider pipes is unchanged — swapping this in is transparent to clients.
*
* The host supplies a {@link RedisStreamClient} adapter over its own Redis driver; `subscribe` needs a
* connection in subscriber mode (see the client docs). Wire it with `defineConfig({ sink:
* tokenSinks.redis({...}) })`, which builds the adapter over `@adonisjs/redis` lazily.
*/
export declare class RedisTokenStreamSink implements TokenStreamSink {
private readonly client;
private readonly keyPrefix;
private readonly ttlSeconds;
constructor(client: RedisStreamClient, options?: RedisTokenStreamSinkOptions);
/** Refresh the sliding TTL on `key` (no-op when TTL is disabled or the client can't `expire`). */
private touchTtl;
private chunksKey;
private stateKey;
private channel;
open(runId: string): SinkWriter;
subscribe(runId: string): AsyncIterable<StreamFrame>;
has(runId: string): Promise<boolean>;
close(runId: string): Promise<void>;
private hasEnded;
}
//# sourceMappingURL=redis-token-stream-sink.d.ts.map