BridgeClient
The host’s side of Bridge.Rpcs, for an agent that works in a sandbox and is reached through a
bridge there. The adapter’s Agent.Agent requires a sandbox and starts each session with
createSession, from what the adapter says of its bridge.
A session’s own bridge is the one its options launch: its Bridge.BridgeId is a digest of them
and of the sandbox’s token, so that sessions of hosts that launch a bridge alike share one, and a
host with other options, such as another model, runs its own beside it. A session finds the
bridge’s port in Bridge.listeningFile, in the bridge’s state directory, exposes the port, and
launches the bridge when none answers there.
A session connects to its bridge while it uses it, and closes the connection when it releases the session, or once it has gone unused for a minute. Each connection launches the bridge when none answers, and starts the session there from the state the bridge last gave, so that a bridge that restarted, as after it died or exited idle, has the session again. A connection that drops is not opened again: a request it dropped is sent again over another, for up to 30 seconds, unless the bridge must not receive it twice.
A turn is two requests: StartTurn, under an id the host picks, and ReadTurn, which reads the
turn’s parts, on from the last part read after the connection drops. The turn runs in the bridge
whoever reads it, so suspendTurn only stops reading, keeping which bridge runs the turn, and
continueTurn starts the turn again there, which the bridge continues if it did not finish it,
as when it died, and reads it again from its start, after the steps the harness has. A read
whose bridge died starts the turn again the same way, in the bridge launched after it, and goes
on after the steps it had read. A turn streams what suspendTurn would return as its
turn-start part first, so that a caller that keeps it continues the turn the same way once
this host is gone without suspending it. A session resumed with other options continues the
turn in the bridge that runs it and then goes on in its own; one whose turn’s bridge is gone
runs the turn again from its prompt in its own. A session whose bridge cannot answer, as when
its sandbox is gone, releases the session with the state the bridge last gave.
Since v0.1.0
Constructors
Section titled “Constructors”createSession
Section titled “createSession”Creates a session, as Agent.createSession does, of the agent behind the bridge that options
describes, in the sandbox of the session’s workspace.
Details
It connects with the WebSocketConstructor provided, which must send headers when it opens a
connection, as Bun’s and Node’s do.
Example (An adapter’s agent whose sessions run behind its bridge)
import { Agent, BridgeClient } from "@amends-dev/harness"import type { Sandbox, Template } from "@amends-dev/sandbox"import { Crypto, Effect, Redacted, Schema } from "effect"import type { Socket } from "effect/socket"
// What the adapter brings: the template that installs the agent and its bridge program, the// bridge's token for a sandbox, and the options the bridge makes its driver with.declare const template: Template.Templatedeclare const tokenOf: (sandboxId: Sandbox.SandboxId) => Redacted.Redacted<string>declare const agentOptionsOf: (options: Agent.Options) => Schema.Json
export const make = Effect.fnUntraced(function* (options: Agent.Options) { // Sessions connect from the host, with its WebSockets and its crypto. const services = yield* Effect.context<Socket.WebSocketConstructor | Crypto.Crypto>() const bridge: BridgeClient.Options = { id: "my-agent", template, command: "bun", args: ["run", "/opt/my-agent/bridge.ts"], token: tokenOf, agentOptions: agentOptionsOf(options) } const agent: Agent.Agent = { id: bridge.id, requiresSandbox: true, template, createSession: (sessionOptions) => Effect.provide(BridgeClient.createSession(bridge, sessionOptions), services) } return agent})Signature
declare const createSession: ( options: Options, sessionOptions: Agent.CreateSessionOptions) => Effect.Effect<Agent.AgentSession, HarnessError.HarnessError, Crypto.Crypto | Socket.WebSocketConstructor>Since v0.1.0
Options
Section titled “Options”Options (interface)
Section titled “Options (interface)”What an adapter says of its bridge: how to install and launch it, and where to reach it.
Signature
export interface Options { /** Names the agent, as its `Bridge.Driver` does. The bridge must answer with it. */ readonly id: string
/** * Installs the bridge and the agent in a sandbox. A session runs it again before it launches the * bridge, for a sandbox prepared with another version of it, so it keeps what the sandbox has and * installs only what it lacks. */ readonly template: Template.Template
/** The command that runs the bridge in the sandbox, and its arguments. */ readonly command: string
readonly args?: ReadonlyArray<string>
/** * The token the bridges in the sandbox `id` take, derived from the id with a secret every host * shares, such as an HMAC of it, so that every host connects to a bridge any of them launched. */ readonly token: (id: Sandbox.SandboxId) => Redacted.Redacted<string>
/** The agent's own options, which the bridge makes its driver with when it launches. */ readonly agentOptions: Schema.Json}Since v0.1.0