@sema-agent/core
Version:
Stateless, task-oriented AI agent core
123 lines (122 loc) • 7.3 kB
TypeScript
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>;