UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

53 lines (52 loc) • 3.79 kB
/** * The deferral CENSUS: what a leg discloses about which of its tools ship as name-only placeholders, and the * seat that carries it to the stream. Split out of the disclosure mount because it is a different concern — * the mount decides the request FACE, this decides what is SAID about it. */ import type { ToolSearchPolicy, ResolvedToolSearch } from "../tool-search-setting.js"; /** * The HOST-facing census of this leg's deferral: which tool names ship as name-only placeholders, which the model has activated, and the policy that decided it. * @contract tool_disclosure.snapshot — the `tool_disclosure` frame is minted ONLY here ({@link ToolDisclosureSeat.publish}), exists ONLY on a leg that defers * at least one tool, and carries the WHOLE census each time (a consumer replaces its copy; the "what just happened" delta is this snapshot's `activated` minus * the previous one's). `deferred` is frozen at prepare (a name never leaves it, it only appears in `activated`); both lists are sorted, so two snapshots * compare by value. A leg that defers nothing emits no frame at all — absence is "nothing was deferred", never "the disclosure is off". */ export interface ToolDisclosureSnapshot { /** Which arm of `RunnerDeps.toolSearch` decided rule ② on this leg. */ policy: ToolSearchPolicy; /** Present iff `policy === "auto"`: the percent of the window the candidate set had to reach. */ thresholdPercent?: number; /** Every deferred name on this leg, sorted. Non-empty (the frame does not exist otherwise). */ deferred: readonly string[]; /** The deferred names ACTIVE on this leg right now, sorted — the engine's state, not a record of commits. Empty on the leg-start census only when nothing * seeded it; a RESUMED leg carries whatever the engine reseeded (transcript replay, compaction snapshot, checkpoint) before anything executed. */ activated: readonly string[]; } /** * The run-time seat the frame rides: prepare publishes the leg-start census, every activation that changes it publishes the next, and the run's event wiring * subscribes once. Snapshots published before the sink is installed are buffered (bounded) and flushed in order, so the leg-start census can be minted at * prepare and still arrive after the manifest frame it belongs beside. Deliberately the same shape as `ToolRosterDeltaSeat` — the two are one problem. */ export declare class ToolDisclosureSeat { #private; /** Publish a census. A snapshot equal to the last published one is DROPPED: `rematerialize` also runs on an MCP refresh, and a frame that says nothing * changed reads as an activation that did not happen. */ publish(snapshot: ToolDisclosureSnapshot): void; /** Install the stream sink; anything published before is flushed in order. */ subscribe(sink: (snapshot: ToolDisclosureSnapshot) => void): void; /** The leg ended: drop the sink so a late publish never reaches a closed stream (it buffers, unread). */ unsubscribe(): void; } /** * Mint a leg's census producer: the frozen deferred list, the policy it was classified under, and a seat. * One place holds both halves, so a census can never name a policy the classification did not run under. * * `deferred` is frozen because every census shares the one array — a host that mutated the list it was handed * would be editing every later frame of the leg. `activated` is filtered to the DEFERRED names: the live * activation set is seeded from the transcript and a resume checkpoint, both of which can name an undeferred * tool. */ export declare function createDeferralCensus(deferred: ReadonlySet<string>, policy: ResolvedToolSearch): { seat: ToolDisclosureSeat; publish: (active: ReadonlySet<string>) => void; };