UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

101 lines (100 loc) • 5.29 kB
import { type ModBusSide, type ModEventName, type ModSeat } from "./events.js"; import { type ModAdmissionRecord, type ModDollarBase, type ModOrigin, type ModSeats } from "./registration.js"; import { type ModAnswerCheck, type ModEventPayload, type ModFailureCause, type ModMatcher, type ModSkip, type ProxyProbe } from "./site-rules.js"; /** A frame on the dispatch stack: a registration's own `$` call, or one of its handlers running. */ export type ModFrame = { readonly kind: "dollar"; readonly plugin: string; } | { readonly kind: "handler"; readonly plugin: string; readonly handler: number; }; /** What a chain bottom (the core of an event) receives besides `e`. */ export interface ModBottomContext { readonly frames: readonly ModFrame[]; readonly signal: AbortSignal; readonly origin: ModOrigin; } /** A `$` method's chain bottom: the host's seat behind it. Its throw is the caller's throw. */ export type ModMethodBottom = (args: ModEventPayload, ctx: ModBottomContext) => unknown; /** * A `$` method on a bus: `run` is its chain bottom; `enter`, when the method has one, shapes the caller's (received) * arguments into the event payload the chain sees — the one place a method's argument form is normalised before any * handler reads it. Either one's throw is the caller's throw. */ export interface ModMethodSeat { readonly run: ModMethodBottom; readonly enter?: (args: ModEventPayload) => ModEventPayload; } export type ModMethodBottoms = Partial<Record<ModEventName, ModMethodSeat>>; export type ModDispatchOutcome = { readonly kind: "answered"; readonly answer: unknown; readonly answeredBy?: string; readonly skipped: readonly ModSkip[]; } | { readonly kind: "failed"; readonly registration: string; readonly cause: ModFailureCause; readonly reason: string; readonly skipped: readonly ModSkip[]; } | { readonly kind: "aborted"; }; /** What a participant filter sees of one mounted handler: its registration, that registration's seat, and whether it only observes. */ export interface ModParticipant { readonly plugin: string; readonly seat: ModSeat; readonly observe: boolean; } export interface ModDispatchOptions { /** The core of the event: what the engine (or shell) does when the chain reaches the bottom. */ readonly bottom: (e: ModEventPayload, ctx: ModBottomContext) => unknown; readonly signal?: AbortSignal; /** The frames the event is raised under (a chain bottom hands its own `ctx.frames` on). */ readonly frames?: readonly ModFrame[]; readonly origin?: ModOrigin; /** The raiser's reading of an answer; an answer it refuses is a violation of the site. */ readonly checkAnswer?: ModAnswerCheck; /** Which mounted handlers take part (absent ⇒ every handler on the event). A handler it leaves out neither runs nor observes. */ readonly participant?: (p: ModParticipant) => boolean; } /** One handler as admission hung it — what a registration's `register` mounted, never its code. */ export interface ModMountedHandler { readonly plugin: string; readonly seat: ModSeat; readonly pattern: string; readonly matcher?: ModMatcher; readonly observe: boolean; /** Whether it was hung with a `.catch`. */ readonly caught: boolean; } export interface ModBus { readonly records: readonly ModAdmissionRecord[]; /** Every mounted handler, in mount order (registrations in run order, each in the order its `register` hung them). */ mounted(): readonly ModMountedHandler[]; /** Whether any mounted handler hangs on `event` (among those `participant` admits) — no handler, no dispatch (the station skips the call). */ hasHandlers(event: ModEventName, participant?: (p: ModParticipant) => boolean): boolean; dispatch(event: ModEventName, e: ModEventPayload, options: ModDispatchOptions): Promise<ModDispatchOutcome>; } export interface ModBusInput<D extends ModDollarBase = ModDollarBase> { readonly side: ModBusSide; readonly seats: ModSeats<D>; readonly bottoms: ModMethodBottoms; /** Where handler failures go (the host's error channel). Never throws back into the bus. */ readonly report: (err: Error, classification?: "observational-hook-verdict-ignored") => void; /** The host's one rule for turning a THROWN value into text (a handler, a `.catch` or a `register` may throw * anything). The bus has no rendering of its own: every failure reason it writes names the value this way. */ readonly describeThrown: (err: unknown) => string; /** The host's Proxy probe: a Proxy a handler answers or hands on is refused before any of its traps runs (a violation * of the site). Absent ⇒ a Proxy is read like any object, its traps run by the copy. */ readonly isProxy?: ProxyProbe; readonly signal?: AbortSignal; } /** * Screen both seats, then admit registrations one by one in run order: each is put to the * `plugin.register` handlers of the registrations already admitted; a refused one is never registered * (its code never runs). Throws `config.mods_invalid` for a registration the kernel cannot take. */ export declare function admitMods<D extends ModDollarBase = ModDollarBase>(input: ModBusInput<D>): Promise<ModBus>;