UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

47 lines (46 loc) • 3.83 kB
import type { AskClass } from "../ask-origin.js"; import type { HumanReviewGateRow } from "../task-result.js"; import { type OnAsk, type PermissionResult, type ResolvedAsk, type ToolCallRequest } from "../tool-policy.js"; /** One inherited ask grant: a person's clean allow at an ancestor's live approver, on ONE presented shape, to ONE question * (`classes`, the request's class set in `ASK_CLASSES` order) — it answers no stricter question. */ export interface InheritedAskGrant { approver: unknown; argsJson: string; presented: unknown; waitMs: number; settled?: object; classes: readonly AskClass[]; } /** Does a grant for `granted` cover a question the gate classified as `asked`? `ordinary` — the plain hesitation every other * class is a stricter form of — is covered by any card answered; every other class must have been on the card (the gate reads * facts the station cannot hold, and a class those add was asked of nobody). Unclassified, or a card with no class ⇒ never. */ export declare function askGrantCovers(granted: readonly AskClass[], asked: readonly AskClass[] | undefined): boolean; /** JSON.stringify throws on a cyclic value (a rewrite object carries no acyclicity guarantee) — `undefined` means "no * comparable shape", which every consumer treats as a mismatch (skip the record / reuse ⇒ re-ask, the safe direction). */ export declare function askGrantShapeOf(args: unknown): string | undefined; /** * Duplicate-frame collapse, the CONSUME half: an inherited layer already resolved THIS call as a clean allow at the * SAME approver function, on EXACTLY the byte-shape this ask now presents, for a question that covers this one — asking * again is the 2-frame UX debt, not a second authority. Guards, all mismatches re-ask (⇒ `undefined`): * · IDENTITY: the approver FUNCTION reference (never a name), compared through `askApproverIdentity`: a delegated * child's approver is the ancestor's own wrapped with provenance — a different function object, the same operator * (the wrapper grants no authority of its own); identity answers only "same consultation". * · SHAPE: byte-equality against the presented SNAPSHOT; reuse re-emits that snapshot as the executed shape via * `presentedInput` — the same binding as a main-gate approval (shown == executed, by construction). * · CLASS: the gate's stamped `classes` is covered by the set the person answered ({@link askGrantCovers}); a class * the gate's own judges add (a protected target, an out-of-root read) was not on the card. Not covered ⇒ the gate * asks its own question and the grant stays (it answers what it answered; the call-site sweep ends it). The class * set is also the AUTHORITY test (a hook's ask carries `hook`, a fallback `denial_limit_fallback`, a marked tool * `operator_forced`, a protected write `write_protection`, an out-of-root read `probe`, the operator's shell floor * `shell_floor` — a class no inherited station mints from its facts, so no station card answers it; the shell seat's classify-tier * hesitation is `ordinary`, the one question a yes on the same bytes answers) — neither the ask's `decisionReason` nor * its `mandate` word is read. * · LEDGER: the ONE real consultation (timed on the wrapper arm) is booked here — one frame happened, one is booked. * The grant lives within one gate evaluation (consumed on reuse, swept at the call site): a REOPENED checkpoint's * re-adjudication never sees a stale grant. */ export declare function consumeInheritedAskGrant(grants: Map<string, InheritedAskGrant>, onAsk: OnAsk | undefined, humanReviewRef: { count: number; totalWaitMs: number; gates: HumanReviewGateRow[]; }, decision: PermissionResult, req: ToolCallRequest): ResolvedAsk | undefined;