/** * Additive capability/version negotiation for the agentic wire protocol. * * The frame codec is append-only (families/codes MUST NOT be renumbered), but an * OLD peer that never learned a newly-appended family (e.g. `claim`/`release`, * codes 8/9) rejects it as an `unknown-family` decode error. Negotiation exists * so a NEW peer never *sends* a family the far end can't decode: each side * advertises the families + named features it supports, and both derive the * SHARED subset. A new supervisor against an old hub, and an old supervisor * against a new hub, both degrade to the intersection — never a protocol error. * * Negotiation is intentionally forgiving of the remote advertisement: unknown * family names / feature strings / a missing or malformed field are dropped, not * rejected, so a peer from a FUTURE protocol revision (advertising families this * build has never heard of) still negotiates cleanly down to the shared subset. */ import { type MessageFamily } from "./families.ts"; /** * The wire-protocol revision. Bumped only for a change that is not expressible * as a purely additive family/feature (which negotiation already handles). Two * peers negotiate down to `min(local, remote)`. */ export declare const PROTOCOL_VERSION = 1; /** * Named, negotiable capabilities layered on top of the raw family set. A family * code answers "can you decode this frame?"; a feature answers "do you implement * this behaviour?". `claim-release` gates the ownership frames; `multi-instance` * gates multiplexing N workers over one connection. */ export declare const PROTOCOL_FEATURES: readonly ["claim-release", "multi-instance"]; export type ProtocolFeature = (typeof PROTOCOL_FEATURES)[number]; /** What a peer tells the other side it supports, exchanged at the handshake. */ export interface ProtocolAdvertisement { readonly version: number; readonly families: readonly MessageFamily[]; readonly features: readonly ProtocolFeature[]; } /** This build's own advertisement — every family and feature it implements. */ export declare const LOCAL_ADVERTISEMENT: ProtocolAdvertisement; /** The shared protocol two peers agreed on: the intersection of their supports. */ export interface NegotiatedProtocol { /** The lower of the two advertised versions. */ readonly version: number; /** Families BOTH peers can decode — the only ones safe to send. */ readonly families: ReadonlySet; /** Features BOTH peers implement. */ readonly features: ReadonlySet; /** Whether it is safe to send `family` to the far end. */ supportsFamily(family: MessageFamily): boolean; /** Whether both peers implement `feature`. */ supportsFeature(feature: ProtocolFeature): boolean; } /** * Parse a peer's (untrusted, possibly future/garbage) advertisement into a known * one, keeping only the families/features this build recognises. A missing or * malformed `version` degrades to 0 (older-than-anything), which negotiates the * result down to this build's own version. This never throws — an unparseable * advertisement simply yields an empty support set. */ export declare function parseAdvertisement(value: unknown): ProtocolAdvertisement; /** * Negotiate the shared protocol from two advertisements. `remote` may be a raw, * untrusted value straight off the wire — it is run through * {@link parseAdvertisement} first, so unknown families/features and malformed * shapes are dropped rather than raising. The result is the intersection: the * only families safe to send and the features both sides implement. */ export declare function negotiate(local: ProtocolAdvertisement, remote: ProtocolAdvertisement | unknown): NegotiatedProtocol;