@rivus/agent-kit/acp
connectAgent, probeAgent, agentEnv, SessionBindingStore and its Layers — with effect and a platform that spawns
Functions
agentEnv()
function agentEnv(profile: Pick<AcpProfile, "env">, source: Readonly<Record<string, string | undefined>>): Record<string, string>;The variables of source that the profile lists, for a caller that builds the agent's environment from its own.
A pattern matches when the name has the text before and after its one *.
Parameters
profile
Pick<AcpProfile, "env">
source
Readonly<Record<string, string | undefined>>
Returns
Record<string, string>
connectAgent()
function connectAgent(agent: string, options: ConnectAgentOptions): Effect<AcpConnection>;Starts agent's ACP program with exactly options.env and completes the ACP handshake. The connection belongs to
the caller's Scope: closing that Scope closes every session and stops the process. Throws an AgentKitError (as a
defect) for an agent without a profile or an option out of range.
Parameters
agent
string
options
Returns
Effect<AcpConnection>
FileSessionBindingStoreLive()
function FileSessionBindingStoreLive(path: string): Layer<SessionBindingStore, never, PlatformService>;Bindings in one JSON file at path, whose directory must exist. Every operation reads the file again and every
change replaces it atomically, so bindings survive restarts. Writes from this Layer are serialized; writers in
other processes are not locked out, and the last one to replace the file wins. A file that does not parse, or that
a newer version wrote, is refused and left as it is.
Parameters
path
string
Returns
Layer<SessionBindingStore, never, PlatformService>
probeAgent()
function probeAgent(agent: string, options: ConnectAgentOptions): Effect<AgentProbe>;Connects, opens one session in options.cwd and closes both. Opening a session is where agents report a missing
login: the auth methods an agent lists are offered by logged-in agents too.
Parameters
agent
string
options
Returns
Effect<AgentProbe>
Classes
SessionBindingStore
The SessionBinding store port. It is optional: without it, sessions work and only sessionKey fails with
SessionBindingStoreFailure (unavailable). MemorySessionBindingStoreLive and FileSessionBindingStoreLive
provide it.
Extends
SessionBindingStoreBase
Constructors
Constructor
new SessionBindingStore(_: never): SessionBindingStore;Parameters
_
never
Returns
Inherited from
SessionBindingStoreBase.constructor
Interfaces
AcpConnection
A running ACP agent process after the handshake. It belongs to the Scope connectAgent ran in.
Properties
agent
readonly agent: string;agentInfo?
readonly agentInfo?: AgentInfo;authMethods
readonly authMethods: readonly AuthMethodInfo[];How the agent says one can log in; offered by agents that are logged in too, so it is not a login state.
ended
readonly ended: Effect<ConnectionClosed>;Succeeds, with why, once the connection has ended.
features
readonly features: AgentFeatures;Methods
close()
close(): Effect<void>;Closes every session and stops the process: SIGTERM, then SIGKILL after the platform's grace period.
Returns
Effect<void>
loadSession()
loadSession(target: LoadSessionTarget, options?: SessionOptions): Effect<AcpSessionHandle, LoadSessionError>;Opens an existing session with session/load, or session/resume when the agent supports only that. The agent's
replay of the session's history is not streamed. A session already open on this connection is returned as is.
Parameters
target
LoadSessionTarget
options?
SessionOptions
Returns
Effect<AcpSessionHandle, LoadSessionError>
newSession()
newSession(options?: NewSessionOptions): Effect<AcpSessionHandle, NewSessionError>;session/new; fails with AuthRequired when the agent needs a login first.
Parameters
options?
NewSessionOptions
Returns
Effect<AcpSessionHandle, NewSessionError>
AcpProfile
How one agent is launched over ACP and how it expects _meta fields.
Properties
agent
readonly agent: string;args
readonly args: readonly string[];command
readonly command: string;The agent's ACP program, found on the PATH of the environment the caller passes.
env
readonly env: readonly string[];The environment variables the agent reads, as exact names or patterns with one * (ANTHROPIC_*). agentEnv
copies the matching ones from an environment the caller chooses; the kit never reads the process environment.
specificationVersion
readonly specificationVersion: "acp-v1";systemPrompt
readonly systemPrompt: SystemPromptPlacement;warnings
readonly warnings: readonly string[];Facts about this agent that are not verified against its source or documentation.
AcpSessionHandle
A live session on a connection. Every operation is refused once the session is closed.
Properties
sessionId
readonly sessionId: string;sessionKey?
readonly sessionKey?: string;snapshot
readonly snapshot: Effect<AcpSessionSnapshot>;The session's state when the Effect runs.
Methods
cancel()
cancel(): Effect<void, SessionClosed | CancelUnsettled>;Sends session/cancel and waits for the turn to end, at most cancelTimeoutMs; the turn's stream then ends with
a finish whose reason is usually cancelled. When the turn does not end in time, its binding is removed and
this fails with CancelUnsettled; the whole connection with its process ends too, unless unsettledCancel is
"session", which closes only this session. With no turn running it does nothing.
Returns
Effect<void, SessionClosed | CancelUnsettled>
close()
close(): Effect<void>;Cancels a running turn, then closes the session, with session/close when the agent supports it. Once started it
runs to the end, also when the caller is interrupted, such as a permission callback that closes its own session.
Returns
Effect<void>
detach()
detach(): Effect<void, SessionClosed | CancelUnsettled>;Cancels a running turn, then forgets the session on this connection without telling the agent: no session/close
goes out, the agent keeps the session and runs it, and a later loadSession for its id sends session/load
again — with the MCP servers of that call. A host that rotates per-session MCP credentials after a cancel thus
reloads without closing the agent's session first, which some agents do not allow after session/close. The
handle ends with this call. A cancel that does not settle within cancelTimeoutMs fails with CancelUnsettled
and the session stays on the connection as it was.
Returns
Effect<void, SessionClosed | CancelUnsettled>
prompt()
prompt(blocks: readonly PromptBlock[]): Stream<TranscriptStreamPart, PromptError>;Runs one turn and streams its parts: deltas and completed events. It opens with the updates that arrived while no
turn ran, so a background call's result reaches its parts. A second prompt while a turn runs fails with
TurnInProgress. Interrupting the stream, or leaving it before it ends, cancels the turn as cancel does.
Parameters
blocks
readonly PromptBlock[]
Returns
Stream<TranscriptStreamPart, PromptError>
ConnectAgentOptions
Properties
cancelTimeoutMs?
readonly cancelTimeoutMs?: number;How long a cancel may take, from sending session/cancel to the end of the turn; 5 s by default.
clientInfo?
readonly clientInfo?: object;name
readonly name: string;version
readonly version: string;cwd
readonly cwd: string;The agent's working directory, and the directory of sessions that name none.
env
readonly env: Env;The agent's complete environment; nothing is inherited. agentEnv picks what a profile lists from another one.
fileSystem?
readonly fileSystem?: object;Offers the agent client file reads or writes, limited to each session's directory after links are resolved. Off by default: agents read and write files themselves.
read?
readonly read?: boolean;write?
readonly write?: boolean;handshakeTimeoutMs?
readonly handshakeTimeoutMs?: number;How long the agent may take to start and answer initialize; 30 s by default.
killGraceMs?
readonly killGraceMs?: number;How long the agent may take to exit after the abort that stops it sends SIGTERM, before SIGKILL; 2 s by default. A host that terminates on its own schedule sets a shorter one so its escalation does not wait out the platform's.
mcpServers?
readonly mcpServers?: readonly McpServerConfig[];MCP servers of every session that names none.
onPermission?
readonly onPermission?: PermissionCallback;Answers permission requests; without it, or without an answer, every request is denied.
onStderr?
readonly onStderr?: (text: string) => void | Promise<void>;Receives the agent's stderr as decoded text arrives, in order, so a host can log a running agent. It may return a promise; neither it nor the reading awaits it, and one that throws or rejects does not affect the connection.
Parameters
text
string
Returns
void | Promise<void>
providers?
readonly providers?: readonly Provider[];requestTimeoutMs?
readonly requestTimeoutMs?: number;How long session/new, session/load and session/resume may take; 30 s by default.
unsettledCancel?
readonly unsettledCancel?: "connection" | "session";What a cancel that does not settle within cancelTimeoutMs invalidates: the whole connection with its process
("connection", the default), or only the session that cancelled ("session"), which closes it — with
session/close when the agent supports it — removes its bindings, and keeps the other sessions running.
PermissionRequest
The agent asking the caller to allow an action during a turn. toolCall holds what the agent said about the call:
callId always, and title, kind and rawInput when it sent them.
Properties
options
readonly options: readonly PermissionOption[];sessionId
readonly sessionId: string;sessionKey?
readonly sessionKey?: string;toolCall
readonly toolCall: object;callId
readonly callId: string;kind?
readonly kind?: string;rawInput?
readonly rawInput?: unknown;title?
readonly title?: string;Type Aliases
ConnectError
type ConnectError = AgentUnavailable | HandshakeFailed;McpServerConfig
type McpServerConfig =
| {
args: readonly string[];
command: string;
env: readonly NameValue[];
name: string;
type?: "stdio";
}
| {
headers: readonly NameValue[];
name: string;
type: "http" | "sse";
url: string;
};An MCP server the agent connects to for one session, in ACP's shapes: a command the agent starts (stdio, the
default when type is absent), or a URL over streamable HTTP or SSE. Which transports an agent supports besides
stdio is in AcpConnection.capabilities (mcpHttp, mcpSse). The caller decides who implements the server.
NewSessionError
type NewSessionError =
| ConnectionClosed
| AuthRequired
| AcpRequestFailed
| AcpTimeout
| SessionBindingStoreFailure;PermissionCallback
type PermissionCallback = (request: PermissionRequest) => Effect.Effect<PermissionDecision | undefined>;Answers a permission request with one of its options, or with undefined to deny it. The callback runs while the
turn waits; it is interrupted when the turn is cancelled, and a failure or a defect counts as a denial.
Parameters
request
Returns
Effect.Effect<PermissionDecision | undefined>
PermissionDecision
type PermissionDecision =
| {
optionId: string;
}
| {
outcome: "cancelled";
};The caller's answer: one of the request's options by id, or cancelled, which the agent receives as the cancelled
outcome — for a policy whose answer to an unanswered request is cancelled rather than a denial. An id the request
did not offer counts as no answer, and no answer is a denial.
PromptBlock
type PromptBlock =
| {
text: string;
type: "text";
}
| {
data: string;
mimeType: string;
type: "image";
uri?: string;
}
| {
description?: string;
mimeType?: string;
name: string;
size?: number;
title?: string;
type: "resource_link";
uri: string;
}
| {
resource: | {
mimeType?: string;
text: string;
uri: string;
}
| {
blob: string;
mimeType?: string;
uri: string;
};
type: "resource";
};One block of a prompt, in ACP's content block shapes. Which kinds an agent accepts besides text and resource links
is in AcpConnection.capabilities (image, embeddedContext).
PromptError
type PromptError =
| TurnInProgress
| SessionClosed
| CancelUnsettled
| ConnectionClosed
| AuthRequired
| AcpRequestFailed;How a turn's stream can fail.
TranscriptStreamPart
type TranscriptStreamPart =
| {
id: string;
type: "text-start";
}
| {
delta: string;
id: string;
type: "text-delta";
}
| {
id: string;
type: "text-end";
}
| {
id: string;
type: "reasoning-start";
}
| {
delta: string;
id: string;
type: "reasoning-delta";
}
| {
id: string;
type: "reasoning-end";
}
| {
title?: string;
toolCallId: string;
toolName: string;
type: "tool-input-start";
}
| {
input: unknown;
title?: string;
toolCallId: string;
toolName: string;
type: "tool-input-available";
}
| {
output?: unknown;
toolCallId: string;
type: "tool-output-available";
}
| {
errorText: string;
output?: unknown;
toolCallId: string;
type: "tool-output-error";
}
| {
output: unknown;
toolCallId: string;
type: "tool-output-partial";
}
| UpdatePart
| {
finishReason: string;
id: string;
type: "finish";
usage?: Usage;
}
| {
event: LiveTranscriptEvent;
type: "event";
};One part of a live turn's stream. The deltas are named after AI SDK's UI message stream parts: text and reasoning
arrive as *-start, *-delta, *-end with a shared id; a tool call as tool-input-start, then
tool-input-available whenever its input is known or changes, then tool-output-partial while a running call
reports the output it has produced so far, then tool-output-available once it has completed
or tool-output-error once it has failed, with errorText for display and the output the agent gave, if any.
update is an update that becomes one event as it is, such as a plan or a mode change. finish ends the turn.
event carries a completed event; folding a session's parts in order gives its event parts, so the live session
keeps one folder across its turns. Each turn's deltas stay self-contained — an update for an open call the turn
has not yet mentioned repeats the call's start and input first, and the turn's finish re-sends the open calls no
earlier finish has closed — so folding one turn alone repeats the tool_call of a call that outlived it, with the
input it had when it was emitted. An update for a call whose result is out emits nothing: its input and output are
gone by design.
Union Members
Type Literal
{
id: string;
type: "text-start";
}Type Literal
{
delta: string;
id: string;
type: "text-delta";
}Type Literal
{
id: string;
type: "text-end";
}Type Literal
{
id: string;
type: "reasoning-start";
}Type Literal
{
delta: string;
id: string;
type: "reasoning-delta";
}Type Literal
{
id: string;
type: "reasoning-end";
}Type Literal
{
title?: string;
toolCallId: string;
toolName: string;
type: "tool-input-start";
}title?
readonly title?: string;The agent's display title when the call starts, while it differs from toolName.
toolCallId
readonly toolCallId: string;toolName
readonly toolName: string;type
readonly type: "tool-input-start";Type Literal
{
input: unknown;
title?: string;
toolCallId: string;
toolName: string;
type: "tool-input-available";
}input
readonly input: unknown;title?
readonly title?: string;The agent's display title while it differs from toolName, such as Read `/u/me/x.md`; this is the
call's current title, so leaving it out clears an earlier one.
toolCallId
readonly toolCallId: string;toolName
readonly toolName: string;type
readonly type: "tool-input-available";Type Literal
{
output?: unknown;
toolCallId: string;
type: "tool-output-available";
}Type Literal
{
errorText: string;
output?: unknown;
toolCallId: string;
type: "tool-output-error";
}Type Literal
{
output: unknown;
toolCallId: string;
type: "tool-output-partial";
}UpdatePart
Type Literal
{
finishReason: string;
id: string;
type: "finish";
usage?: Usage;
}Type Literal
{
event: LiveTranscriptEvent;
type: "event";
}Variables
MemorySessionBindingStoreLive
const MemorySessionBindingStoreLive: Layer.Layer<SessionBindingStore>;Bindings in this process's memory, for tests and hosts that never load a session after a restart.