UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

58 lines (57 loc) • 3.38 kB
/** * The ONE exit for an auto-mode classification that could not RULE (`unavailable`: the classifier leg failed, or its * per-level budget ran out) — shared by both classifier stations, the leg's gate and an ancestor's frozen classifier * in the policy fold, so the rule is written once. * * ONE fork, on the APPROVAL SEAT (does an ask this station hands on reach a person — a live approver, or a durable * park): with one, the ask goes on, its text saying why auto mode is asking, and a person decides; without one, the * call is refused with CC's `x1t` sentence and the classification's FORM (`unavailable`) is attested on the deny. The seat is * the only input to the fork — not the cause, not the mode. The handed-on ask carries `requiresRealApproval`: no * automatic lane may answer it in the classifier's stead — not a blanket `onAsk:"allow"`, not the sandbox admission, not a * budget resolver over its park (the park mints the non-budgetable kind). CC refuses either way; asking where a person can be * asked is a declared departure (a classifier that is slow or down must not turn an attended session into a string * of refusals). Neither arm is a block: the denial limit counts classifier RULINGS, and a person's refusal of the * handed-on ask is a person's, not the classifier's. * * The observer hears every such classification with where the call went, except while the call is being aborted — a halt, * or the run's end (the classifier did not fail; the call ended). It is observe-only: a throw never changes the arm. */ import { type AutoModeClassifierRound, type AutoModeUnavailableCause } from "./auto-mode.js"; import { type PermissionResult, type ToolCallRequest } from "./tool-policy.js"; /** Where an `unavailable` classification sent the call: `asked` = on to the approval seat, `denied` = refused. */ export type ClassifierUnavailableDisposition = "asked" | "denied"; /** What the stations' observer receives — the facts the `classifier.unavailable` notice is composed from. */ export interface ClassifierUnavailableInfo { toolName: string; toolCallId: string; cause: AutoModeUnavailableCause; disposition: ClassifierUnavailableDisposition; } export type ClassifierUnavailableObserver = (info: ClassifierUnavailableInfo) => void; /** The station's two facts for the fork: whether an ask it hands on reaches a person (`true` only — anything else is * no seat), and who hears it. */ export interface ClassifierUnavailableSeat { approvalSeat?: boolean; onUnavailable?: ClassifierUnavailableObserver; } /** The arm the fork chose: the ask to hand on, or the refusal. */ export type ClassifierUnavailableArm<A> = { kind: "asked"; ask: A; } | { kind: "denied"; deny: PermissionResult; }; export declare function classifierUnavailableArm<A extends Extract<PermissionResult, { action: "ask"; }>>(args: { ask: A; req: ToolCallRequest; cause: AutoModeUnavailableCause; /** The ladder's attribution, for the refusal's sentence (it names both rungs when the ladder moved). */ attribution?: AutoModeClassifierRound; seat: ClassifierUnavailableSeat | undefined; /** The call is being aborted (its per-call signal — a halt, or the run's end): the observer is not told (the arm is chosen * as ever). */ aborted: boolean; }): ClassifierUnavailableArm<A>;