UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

111 lines (110 loc) • 7.76 kB
import type { RunnerDeps } from "../types.js"; import type { ExecutionEnv } from "../../internal/harness.js"; import type { PathRuleBases } from "../permission-rule-model.js"; import type { ChildPlacement, InheritedGate, RunInternals } from "./contracts.js"; import type { ToolPolicy } from "../tool-policy.js"; import { CheckpointError } from "../checkpoint-store.js"; /** * Whether this deployment can place a child agent in a tree OTHER than the caller's — the one fact behind * every request of that shape: an explicit `cwd`, a workflow agent's `isolation: "worktree"`, and the * delegation tool's per-call or per-definition `isolation: "worktree"`. * * Only an `executionEnvFactory` can: it builds one execution env per task, so a child can be rooted * wherever the request says. A static `executionEnv` is ONE shared env with ONE cwd — every child that * runs on it runs in the caller's root, whatever tree it was asked to work in. A request the deployment * cannot honor is refused before the child starts (and, for a worktree, before one is minted); each site * keeps its own code and sentence for the refusal, but none decides the condition itself. */ export declare function deploymentCanRerootChild(deps: Pick<RunnerDeps, "executionEnvFactory">): boolean; /** * Where a child the caller asked to place at `asked` actually landed (`childRoot`, the root its environment gave it) — the * ONE judgment every reader of that fact takes * (the delegation tool's worktree request, and the anchors of the rules the child inherits): * · `honored` — the environment's root is where the child was asked to be (canonical on both sides); * · `caller_tree` — it is not, and it lies inside the caller's own tree (`callerRoot`): the same filesystem, the wrong * directory — a worktree request then fails (the child would write the caller's checkout); * · `elsewhere` — neither: another filesystem namespace (a sandbox the factory minted). The child runs there, it is not * in the worktree it was offered, and it takes the caller's path rules again at its own anchors. * A path the environment cannot canonicalize is compared as spelled. Residual: two namespaces that hold the same path * string, with a factory claiming to honor it, read `honored`. */ export declare function childPlacementOf(env: Pick<ExecutionEnv, "canonicalPath">, childRoot: string, asked: string | undefined, callerRoot: string): Promise<ChildPlacement>; /** A delegated leg's placement: the place asked for is the hint (a minted worktree, an explicit cwd, the caller's own cwd) * — or, for a worktree the factory mints itself (`isolation`), that worktree on the caller's host (a remote environment's * is another namespace). A leg no delegation caller placed (no `callerRoot`) has no placement and reads nothing. */ export declare function childPlacementOnLeg(env: ExecutionEnv, internals: Pick<RunInternals, "isolation" | "parentCwd"> & { readonly callerRoot: string; }, root: string): Promise<ChildPlacement>; /** The refusal of a worktree the caller minted for a child its environment placed in the caller's own tree. */ export declare function worktreeNotHonored(cwd: string): Error & { code: "isolation.unavailable"; }; /** * The chain's top leg's anchors as THIS leg reads them (the person's global / session path rows and every `~/` row anchor * there): the chain's own (`live` as recorded, else the checkpoint's `seed` rebased — {@link recordedAnchors}), unless this * leg is a child placed `elsewhere` or no chain names one — then this leg is the top. A recorded root that is not an * absolute path anchors nothing: the rows it would anchor read `unreadable`. */ export declare function chainTopAnchors(cfg: { leg: PathRuleBases; live: InheritedGate["pathRuleAnchors"]; seed: InheritedGate["pathRuleAnchors"]; placement: ChildPlacement | undefined; rebase: (p: string) => string; }): PathRuleBases; /** The installation records a leg reads: the live chain's (as recorded), else the checkpoint's (through the workspace rebase). */ export interface ChainInstallations { readonly live: InheritedGate["pathRuleInstallations"]; readonly seed: InheritedGate["pathRuleInstallations"]; } /** Why no usable record says where a chain entry was installed: no record (a chain written before the record existed), a * record that does not cover the chain position for position, or a member that names no absolute root. */ export type ChainInstallationGap = "absent" | "misaligned" | "invalid"; /** * The chain entries a leg could not install where they were installed: each UNINSTALLED entry (a host re-supplying a * chain) whose path rules depend on the installing leg, with no usable record of that leg. Such a chain is refused — * installing those entries anywhere else (the chain's top leg, this leg) would move what they protect. Entries whose rules * do not depend on it, and installed entries, never need a record. */ export declare function chainInstallationGaps(chain: readonly ToolPolicy[], installations: ChainInstallations, rebase: (p: string) => string): Array<{ readonly position: number; readonly gap: ChainInstallationGap; }>; /** The refusal of a chain with {@link chainInstallationGaps} (`resume.parent_constraint_mismatch`, `detail.reason` naming * the first gap's form); `pending` says the checkpoint is still pending (the refusal came before the claim). */ export declare function chainInstallationRefusal(gaps: ReadonlyArray<{ readonly position: number; readonly gap: ChainInstallationGap; }>, pending: boolean): CheckpointError; /** * How a leg holds a caller policy — its own (`TaskSpec.toolPolicy` / `RunnerDeps.toolPolicy`) or one its delegation chain * hands it: a policy is installed where it ENTERS the chain, and a child holds its ancestor's installation (one object, * the same anchors) — its own caller slot included when that slot names the policy an ancestor installed. Installed again: * on a child placed `elsewhere` (another filesystem namespace — the ancestor's anchors name another namespace's files), at * this leg's anchors; a chain entry handed uninstalled (a host re-supplying a chain), where its installing leg recorded it * (`InheritedGate.pathRuleInstallations`, live or from the checkpoint). An uninstalled entry whose rules depend on that * leg and whose record is not usable refuses the leg ({@link chainInstallationRefusal}); one whose rules do not, reads * the same wherever it is installed (the chain's top leg). */ export declare function chainPolicyOnLeg(cfg: { leg: PathRuleBases; chainTop: PathRuleBases; placement: ChildPlacement | undefined; chain: readonly ToolPolicy[]; installations: ChainInstallations; rebase: (p: string) => string; }): { own: (policy: ToolPolicy | undefined) => ToolPolicy | undefined; chained: (policy: ToolPolicy, position: number) => ToolPolicy; }; /** The installation record of a chain entry (its root and home), `null` for an entry with no path rules installed. */ export declare function installationRecordOf(policy: ToolPolicy): { readonly root: string; readonly home?: string; } | null; /** What a leg hands its children about anchors (data half): the chain's top leg's anchors — the person's global / session * rows and every `~/` row anchor there — and where each entry handed down was installed, position for position (a chain * re-supplied uninstalled is installed there again; absent when no entry is an installation). */ export declare function chainAnchorRecords(chainTop: PathRuleBases, chain: readonly { readonly policy: ToolPolicy; }[]): Pick<InheritedGate, "pathRuleAnchors" | "pathRuleInstallations">;