UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

67 lines (66 loc) • 4.51 kB
/** * The hook seam's SEAT discipline and its disclosure vocabulary: which callback seats exist, what a * deployment is allowed to put in one, and how a wiring disclosure names the ones that are wired. * * Kept beside the interface rather than inside it: `hooks.ts` owns the seam's BEHAVIOUR, and this module owns * the seat as a CONFIGURATION VALUE — the same split `wiring-manifest.ts` keeps for the ask/question seats. */ import type { Hooks } from "./hooks.js"; import type { AssertAllKeysHandled } from "./ask-origin.js"; import type { SeamProvenance } from "./wiring-manifest.js"; /** * The CALLBACK SEATS of {@link Hooks} as a word list — the vocabulary a wiring disclosure names a wired seam * by (`WiringManifest.hooks[].family`), in declaration order. `preToolUseObservational` is deliberately NOT a * member (it is a DECLARATION ABOUT `preToolUse`); `timeoutMs` is not a seat either. */ export declare const HOOK_FAMILIES: readonly ["preToolUse", "postToolUse", "userPromptSubmit", "stop", "postToolUseFailure", "postToolBatch", "preCompact", "postCompact", "stopFailure", "permissionDenied"]; /** * One hook seat's name. * * @contract hooks.family_vocabulary — {@link HOOK_FAMILIES} is the only spelling of a hook seat's name on any * disclosure face, and {@link HookFamiliesCoverEverySeat} makes a new callback member of {@link Hooks} red at * `tsc` until it has a word there — a disclosure that omits a seat under-states what runs on the critical path. */ export type HookFamily = (typeof HOOK_FAMILIES)[number]; /** Every CALLBACK member of {@link Hooks} — derived from the interface, never a hand-kept second list. */ type HookCallbackSeat = { [K in keyof Hooks]-?: NonNullable<Hooks[K]> extends (...args: never[]) => unknown ? K : never; }[keyof Hooks]; /** The closed-set fence: `never` while every callback seat has a word, the MISSING SEAT'S NAME when one does * not (the constraint form names it; a conditional type says only "something changed"). */ export type HookFamiliesCoverEverySeat = AssertAllKeysHandled<Exclude<HookCallbackSeat, HookFamily>>; /** The typed refusal a hook seat holding a present NON-CALLBACK value raises at prepare. */ export declare const HOOKS_INVALID_CODE = "config.hooks_invalid"; /** * Screen the resolved hook record's seats (`spec.hooks ?? deps.hooks`). * * @contract hooks.seat_value — a hook seat is a FUNCTION or it is absent. A PRESENT non-function * (`preToolUse: null`, a string, a bare object) is a configuration error and refuses the whole prepare with * {@link HOOKS_INVALID_CODE}, naming the family and the type received. It is not folded to "unwired": the tool * gate arms on PRESENCE (`hooks?.preToolUse !== undefined`) and would invoke the non-function and fail closed * on every call, while a callability-based disclosure reported no hooks at all. The sibling seams already * refuse the same way (`resolveQuestionSeam` / `resolveElicitSeam`). `undefined` stays exactly what it was: * an unwired seat, silent. */ export declare function assertHookSeatsCallable(hooks: Hooks | undefined, provenance: SeamProvenance): void; /** * One WIRED HOOK SEAT of this leg. `family` is the seat's name; `owner` is WHICH SEAT supplied the record, the * `spec > deps` provenance the ask/question seams report. Deliberately no third owner word: core mounts NO * engine-owned hooks, and a delegated child's inherited `preToolUse` rides the gate's constraint fold. */ export interface WiringManifestHookEntry { family: HookFamily; owner: SeamProvenance; /** Only on the `preToolUse` entry, and only when the deployment DECLARED the face observational * (`Hooks.preToolUseObservational`) — it still runs on every call but is not folded into a delegated * child's inherited constraints. Absence means "not declared", never "declared false". */ observational?: true; } /** * The wiring manifest's hook read face ({@link WiringManifestHookEntry}): one entry per CALLBACK seat the * resolved record wires, in the vocabulary's declaration order. The VOCABULARY is the judge — families are * walked, never the record's own keys. `owner` is a property of the RECORD, so every entry agrees. Callability * and presence cannot diverge here: {@link assertHookSeatsCallable} has already refused the leg where they would. */ export declare function wiredHookEntries(hooks: Hooks | undefined, owner: SeamProvenance, preToolUseObservational: boolean): WiringManifestHookEntry[]; export {};