UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

123 lines (122 loc) • 7.3 kB
import type { NormalizedMemorySpec } from "./memory.js"; /** Where a requested org scope came from — the trust axis of the dual-origin model above. */ export type MemoryScopeOrigin = "deployment" | "request"; /** One org scope submitted for admission, with its origin. */ export interface MemoryScopeRequest { scope: string; origin: MemoryScopeOrigin; } /** * The resolver's verdict — exactly two states. `ok: true` carries the FROZEN admitted projection: * `scopes` must be a subset of the requested org scopes (an unrequested grant is a resolver fault ⇒ * refused), and `writeScope` is the explicit org write grant (`null` = org write face stays * read-only). `ok: false` refuses the whole prepare. */ export type MemoryAdmissionVerdict = { ok: true; scopes: readonly string[]; writeScope: string | null; } | { ok: false; reason: string; }; /** * The trusted deployment resolver ({@link import("./types.js").RunnerDeps.memoryScopeAdmission}). * Receives ONLY the org-parsed scopes (non-org scopes are not its business), each tagged with its * origin, plus the run's principal. Both async and sync forms are accepted. */ export type MemoryScopeAdmission = (input: { principal: string | undefined; requested: ReadonlyArray<MemoryScopeRequest>; requestedWriteScope: MemoryScopeRequest | null; }) => MemoryAdmissionVerdict | Promise<MemoryAdmissionVerdict>; /** Inputs to {@link admitMemoryScopes} — assembled by the prepare path (prepare-memory.ts). */ export interface MemoryAdmissionInput { memorySpec: NormalizedMemorySpec; principal: string | undefined; admission: MemoryScopeAdmission | undefined; /** The deployment's self-certified org scopes (`RunnerDeps.deploymentMemoryScopes`). */ deploymentScopes: ReadonlySet<string>; /** Compliance capability `org_memory_mount` denied for this principal (the veto covers the * REQUEST-origin plane — deployment-origin scopes are the operator's own declaration). */ orgMemoryDenied: boolean; /** True when the denial above came from a compliance-resolver fault (transient code family). */ complianceDegraded: boolean; /** The parent chain's frozen admitted org set; `undefined` on a top-level task. A delegated child * with an absent/older-shape chain gets the fail-closed empty set from the caller. */ parentAdmittedOrgScopes: readonly string[] | undefined; /** The SESSION freeze (resume legs): this session's own verdict at suspend. `undefined` = no * prior adjudication. Constrains the FINAL admitted projection regardless of origin — a * request-origin scope outside it refuses the prepare; a deployment-origin scope outside it is * dropped and disclosed; a write grant absent from it collapses to read-only. */ priorOwnVerdict: OwnOrgAdmissionVerdict | undefined; /** The monotonic governance-provenance bit (falsification-style round 5): true when this leg's TREE is * org-governed — the deployment surface is configured here, or ANY ancestor/prior leg recorded * the bit (`InheritedGate.orgAdmissionGoverned`, persisted on checkpoints). Counts as governance * evidence even when every admitted set en route is EMPTY: a governed parent's org-less child, * resumed on a surface-less worker, must still refuse org-shaped non-v2 scopes. Trees that never * had a governance surface never mint the bit and keep the opaque posture. */ governedProvenance: boolean; } /** The admission outcome the prepare path applies to the memory spec before materialization. */ export interface MemoryAdmissionOutcome { /** The spec's read layering with any resolver-dropped DEPLOYMENT-origin org scopes removed. */ scopes: string[]; /** The effective write face (org write not explicitly granted ⇒ narrowed to `null`). */ writeScope: string | null; /** The frozen verdict for the child chain: every org scope this task actually mounts. */ admittedOrgScopes: string[]; /** Deployment-origin org scopes narrowed away (by a present resolver, or by the session freeze) — * disclosed, never silent. */ droppedDeploymentScopes: string[]; /** True when an org writeScope was narrowed to read-only (disclosed by the caller). */ writeScopeNarrowed: boolean; /** The session's own frozen verdict to PERSIST at suspend — present iff this leg ADJUDICATED an * org plane (the spec requested org scopes), including the adjudicated-empty case. `undefined` * for an org-less task (nothing to freeze). */ ownVerdict: OwnOrgAdmissionVerdict | undefined; } /** * Fold the delegation-chain FREEZE a prepare leg runs under (adversarial-review adoption, * 2026-08-05). For a DELEGATED leg an undefined chain verdict reads fail-closed as the EMPTY set * (an older-shape chain must never read as "unconstrained"); a top-level leg simply has no chain * constraint. The SESSION freeze (the leg's own suspend-time verdict) is a separate input to * {@link admitMemoryScopes} (`priorOwnVerdict`) — it must constrain the FINAL admitted projection * regardless of origin (deployment-origin scopes circumvent the chain freeze, not the session freeze), * so it cannot ride this chain-side fold. */ export declare function foldAdmissionFreeze(input: { delegated: boolean; inherited: readonly string[] | undefined; }): readonly string[] | undefined; /** * The session's OWN frozen org verdict: what THIS session actually mounted (and what write grant it * held) at its last suspend. Persisted on the checkpoint (ownAdmittedOrgScopes / * ownAdmittedOrgWriteScope) — including an ADJUDICATED-EMPTY `scopes: []` (a session whose whole org * request was narrowed away must not read as "org-less" on resume). `writeScope: null` = the org * write face was read-only. */ export interface OwnOrgAdmissionVerdict { scopes: readonly string[]; writeScope: string | null; } /** * #22 — read a durable background-agent row's recorded org verdict (module header, cross-process * arm). TOTAL by construction: it answers a verdict for every row, so no caller ever has an * "unknown" to fold. An absent field is the ZERO verdict (`{scopes: [], writeScope: null}`), never * `undefined` — `undefined` is this module's spelling of "no prior adjudication constrains this * leg", and handing that to a leg whose original verdict cannot be proven is precisely the * widening the record exists to prevent. Structural parameter (not the record type) so the record * schema keeps its single owner and this module stays free of a store import. */ export declare function readDurableOrgAdmission(row: { admittedOrgScopes?: readonly string[]; admittedOrgWriteScope?: string | null; }): OwnOrgAdmissionVerdict; /** * Adjudicate the org scopes of a task's normalized memory spec. Returns the outcome to apply, or * throws a coded refusal (`memory.admission_required` — transient control-plane absence/fault; * `memory.admission_denied` — terminal policy refusal; `config.compliance_denied`/`_required` — the * compliance veto). A spec with no org scopes passes through untouched (zero cost, zero change). */ export declare function admitMemoryScopes(input: MemoryAdmissionInput): Promise<MemoryAdmissionOutcome>;