UNPKG

agents

Version:

A home for your AI agents

302 lines (300 loc) 12.6 kB
import { S as ConnectionContext, T as WSMessage, r as CapabilityWebSocketUpgradeContext, s as LifecycleCapability, x as Connection } from "../capability-runner-BUBa6Ake.js"; import { a as capnWebTransportUrl, n as CAPNWEB_TRANSPORT_QUERY, o as isCapnWebTransportUpgrade, r as CAPNWEB_TRANSPORT_VALUE, t as AgentTransport } from "../transport-protocol-ZTew5Wso.js"; import { RpcTarget } from "cloudflare:workers"; //#region src/websockets/options.d.ts /** * The part of a `State` capability the WebSockets capability uses. A * structural port, so any `State<T>` fits without a cast and the * capability never depends on the class itself. */ type SyncedState = { /** Current state, or `undefined` when nothing is stored. */ get(): unknown /** Validate and persist a change; throws when the host rejects it. */; set(nextState: never, source: Connection): void; }; /** A frame delivered on a capability-owned WebSocket connection. */ type WebSocketMessage = WSMessage; /** * Connection handlers for the WebSockets capability. Handlers run inside * the host invocation boundary with the live connection in ambient * context (`getCurrentAgent().connection`). * * @experimental The API surface may change before stabilizing. */ type WebSocketHandlers = { /** Handle a newly accepted hibernating WebSocket connection. */ onConnect?( connection: Connection, ctx: ConnectionContext ): void | Promise<void> /** Handle a message from a hibernating WebSocket connection. */; onMessage?( connection: Connection, message: WebSocketMessage ): void | Promise<void> /** Handle a closing hibernating WebSocket connection. */; onClose?( connection: Connection, code: number, reason: string, wasClean: boolean ): void | Promise<void> /** Handle a mid-connection WebSocket error. */; onError?(connection: Connection, error: unknown): void | Promise<void>; }; /** * Configuration for the WebSockets capability. * * @experimental The API surface may change before stabilizing. */ interface WebSocketsOptions { /** * Connection handlers for WebSocket clients. The capability accepts and * tracks every WebSocket upgrade either way; handlers add behavior on * connect, message, close and error. */ readonly handlers?: WebSocketHandlers; /** * An `RpcTarget` whose prototype methods are the host's complete remote * interface, reached through `useAgent().call` and `.stub`. On the * `cf-websocket` wire they are answered as JSON `rpc` frames. On the * `capnweb` wire they are native Cap'n Web methods on the session root: * an `RpcTarget` result becomes a live stub, a `ReadableStream` streams, * and calls pipeline. Methods run through the host invocation boundary * with the calling connection in scope. `Agent` answers its own * decorated methods on the JSON wire and does not set this. */ readonly callables?: RpcTarget; /** * Whether a new connection gets the connect-time protocol frames — * identity (`cf_agent_identity`), then the current state when `state` * is set — and whether protocol frames reach it at all. * * - `true` (default): every connection. * - a function: decided per connection at accept time. `false` marks * the connection no-protocol: it gets no protocol text frames, on * connect or via `broadcastState()`, but can still send and receive * ordinary messages and use callables. For binary-only clients. * - `false`: the host drives the connect sequence itself with * `sendIdentity()` and `sendState()`, and applies client state frames * with `applyStateFrame()` — `Agent` does this, since it must decide * whether a connection belongs to a facet before any frame is sent. */ readonly protocol?: | boolean | ((connection: Connection, ctx: ConnectionContext) => boolean); /** * Decide at accept time whether a connection is readonly. A readonly * connection's `cf_agent_state` frames are refused with * `cf_agent_state_error`; everything else works. Also settable later * with `setReadonly()`. */ readonly readonly?: ( connection: Connection, ctx: ConnectionContext ) => boolean; /** * A {@link SyncedState} — normally a `State` capability — to sync over * connections. The capability pushes the current value to each new * connection after identity and applies `cf_agent_state` frames a * client sends: a readonly connection is refused, and a change the * host's validator rejects is answered with `cf_agent_state_error`. * Broadcasting a change is the state owner's call — wire the `State`'s * `onChanged` to `broadcastState(source)`. Install the same instance on * the lifecycle so it owns storage and validation; without this option * state is never sent or accepted over connections. */ readonly state?: SyncedState; /** * Tags attached to each accepted connection, queryable through * `getConnections(tag)`. The connection id is always the first tag. */ readonly getConnectionTags?: ( connection: Connection, ctx: ConnectionContext ) => string[] | Promise<string[]>; } //#endregion //#region src/websockets/websockets.d.ts /** * Opt-in WebSocket support for Lifecycle Objects. * * Lifecycle itself does not model WebSockets — hosts that want them * install this capability, which owns the connection subsystem end to * end: it claims upgrades, dispatches `onConnect`/`onMessage`/`onClose` * inside the host invocation boundary, reciprocates close handshakes, * and answers `getConnections()`/`getConnection()`. * * ```ts * class Room extends DurableObject<Env> { * readonly webSockets = new WebSockets({ * handlers: { * onConnect: (connection) => connection.send("welcome"), * onMessage: (connection, message) => { ... } * }, * callables: new RoomCallables() * }); * readonly lifecycle = Lifecycle.install(this).use(this.webSockets); * } * ``` * * Connections arrive on one of two wires, chosen by the client: * * - **cf-websocket** (default): accepted with the Hibernation API. Idle * clients stay connected while the Durable Object leaves memory. * - **capnweb** (`?__agents_transport=capnweb`): protocol frames through * one pipe method on a Cap'n Web session whose root also carries the * host's callables natively. Non-hibernating — the object stays pinned * while the connection is open. * * Both wires dispatch the same handlers and appear in `getConnections()`. * On both, the capability speaks the Agent protocol a plain host needs * for `useAgent` and `AgentClient`: it sends the identity frame on * connect, and it serves `callables` — as `rpc` JSON frames on the * WebSocket wire, and natively on the Cap'n Web session root, where an * `RpcTarget` result becomes a live stub and calls pipeline. `call()` * and `stub` work against a plain Durable Object exactly as against an * `Agent`. Pass a `State` capability as `state` and the hook's * `state`/`setState` work too: the current value is pushed on connect * and client updates are validated and applied; the state owner * broadcasts changes with `broadcastState()`. Per-connection readonly * and no-protocol flags live here as well, for every host. * * @experimental The API surface may change before stabilizing. */ declare class WebSockets extends LifecycleCapability { #private; /** Claims every upgrade, so Lifecycle dispatches it after all others. */ readonly claims = "catch-all"; constructor(options?: WebSocketsOptions); /** * Claim every upgrade, never declining: a Cap'n Web transport upgrade * becomes a session, everything else a tracked hibernating connection, * whether or not handlers or callables are configured. Handlers only add * behavior on connect, message, close, and error. */ onWebSocketUpgrade({ request }: CapabilityWebSocketUpgradeContext): Promise<Response>; /** Dispatch a platform message wake for a capability-owned socket. */ onWebSocketMessage( ws: WebSocket, message: WebSocketMessage ): Promise<boolean>; /** Dispatch and reciprocate a close wake for an owned socket. */ onWebSocketClose( ws: WebSocket, code: number, reason: string, wasClean: boolean ): Promise<boolean>; /** Dispatch an error wake for an owned socket. */ onWebSocketError(ws: WebSocket, error: unknown): Promise<boolean>; /** * Close every owned connection during explicit host destruction. The * capability owns its sockets' lifetimes, so it also owns tearing * them down. */ dispose(): void; /** Open connections on either wire, optionally by tag. */ getConnections<TState = unknown>( tag?: string ): IterableIterator<Connection<TState>>; /** One connection on either wire, by id. */ getConnection<TState = unknown>(id: string): Connection<TState> | undefined; /** * Send the identity frame, unless the connection is no-protocol. The * defaults are the Durable Object's routed name and host class; a host * whose public identity differs — an `Agent` facet, whose routed name * is an internal encoding of its logical name — passes its own. */ sendIdentity( connection: Connection, identity?: { name: string; agent: string; } ): void; /** * Send the current state to one connection, unless nothing is stored * or the connection is no-protocol. Reading the state may seed the * initial value; see `#connecting`. */ sendState(connection: Connection): void; /** * Apply a parsed `cf_agent_state` frame from a client. A readonly * connection is refused; a change the host's validator rejects is * logged in full server-side and answered with a generic * `cf_agent_state_error`. Broadcasting the accepted change is the state * owner's call, through its `onChanged` hook. Callers that drive the * protocol themselves call this inside their own invocation context; * the capability's automatic path does so via `runInHostContext`. * * @returns Whether the frame was a state frame (handled either way). */ applyStateFrame(connection: Connection, frame: unknown): boolean; /** * Push the current state to every protocol-enabled connection except * the one a change came from, which already has the value it sent. * Wire a `State`'s `onChanged` to this. */ broadcastState(except?: Connection | "server"): void; /** Whether the connection may update host state over the wire. */ isReadonly(connection: Connection): boolean; /** Mark a connection readonly, or writable again. */ setReadonly(connection: Connection, readonly?: boolean): void; /** Whether protocol text frames reach the connection. */ isProtocolEnabled(connection: Connection): boolean; /** Enable or suppress protocol text frames for a connection. */ setProtocolEnabled(connection: Connection, enabled: boolean): void; } //#endregion //#region src/websockets/connection-flags.d.ts /** * Internal per-connection flags, stored inside the connection's own state * under `_cf_`-prefixed keys so they ride the hibernation attachment (or a * bridged connection's synced state) and survive a wake. The state wrapper * installed by {@link ensureConnectionWrapped} hides them from * `connection.state` and preserves them across user `setState` calls. * * Owned by the WebSockets capability; `Agent` and framework mixins reach it * through the capability or, for their own keys, through * {@link registerInternalConnectionKeys}. */ /** A readonly connection may not update host state. */ declare const CF_READONLY_KEY = "_cf_readonly"; /** * A no-protocol connection receives no protocol text frames (identity, * state sync, MCP servers) — neither on connect nor via broadcasts. */ declare const CF_NO_PROTOCOL_KEY = "_cf_no_protocol"; /** * Register additional `_cf_`-prefixed keys a host or mixin stores in * connection state, so they are hidden from `connection.state` and kept * across user `setState` calls like the capability's own flags. */ declare function registerInternalConnectionKeys(...keys: string[]): void; //#endregion export { type AgentTransport, CAPNWEB_TRANSPORT_QUERY, CAPNWEB_TRANSPORT_VALUE, CF_NO_PROTOCOL_KEY, CF_READONLY_KEY, type SyncedState, type WebSocketHandlers, type WebSocketMessage, WebSockets, type WebSocketsOptions, capnWebTransportUrl, isCapnWebTransportUpgrade, registerInternalConnectionKeys }; //# sourceMappingURL=index.d.ts.map