UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

71 lines (70 loc) • 5.35 kB
/** * PrepareTask's Artifact phase: the `RunnerDeps.artifactHost` seat is read once; an absent seat mounts * nothing and announces nothing; a seat whose declaration fails an invariant mounts nothing and announces * `config.artifact_host_invalid` (operator audience) so a bad wiring can never read as "no hosting"; a * valid seat mounts ONE `Artifact` tool assembled from the declaration, on the same optional band the LSP * seat uses. The tool's local-file read goes through the run's fs fence (root containment, read-deny, read * face) exactly as `Read` does, then reads the bytes once from the execution env. A local stub's store * (`capabilities.storageDir`) must lie OUTSIDE every root the run may write or read — a ledger the model can * edit or read through the fs tools is not a trust boundary — judged by {@link rootAdmittingArtifactStore} at * every point a root is admitted: here over the prepare-time roots (a store that overlaps one refuses the mount, * naming both), and at an in-flight read-root grant over the granted root (the grant is refused). The phase * publishes the declared store into the run's {@link ArtifactStoreRef} for that second point. * Synchronous: the stretch has no await (the file read is a closure the tool calls later). */ import type { PermissionModeController } from "../mode-policy.js"; import type { ExecutionEnv } from "../../internal/harness.js"; import type { OnAsk } from "../tool-policy.js"; import { type ArtifactPlane } from "../artifact-host.js"; import { RosterBuilder } from "../tool-roster.js"; import type { AgentTool, RunnerDeps } from "../types.js"; import type { ContainmentFace } from "../../tools/fs/index.js"; import type { PlacedReadDenyMatcher } from "../../tools/fs/read-deny-home.js"; import { type ArtifactStoreRef } from "./read-root-grant.js"; import type { Prepared } from "./contracts.js"; export interface PrepareArtifactInput { /** borrowed-readonly — the deployment's hosting seat and the notice sink the refusal arm announces on. */ deps: Pick<RunnerDeps, "artifactHost" | "onNotice" | "tracer">; /** borrowed-readonly — the engine-minted run id: the host's `onMount` key and every call context's `runId`. */ runId: string; /** borrowed-readonly — the host task id, the call context's audit attribution. */ taskId: string; /** borrowed-readonly — the acquired session id (notice attribution and the call context's `sessionId`). */ sessionId: string; /** borrowed-readonly — the spawned name this run carries, when any (call-context attribution only). */ agentName: string | undefined; /** borrowed-readonly — the run's effective approver (`spec.onAsk ?? deps.onAsk`, the seat the tool gate resolves at): * the tool's shared-read consent gate rides it as a mount dep (a core mount's execute ctx is minimal). */ onAsk: OnAsk | undefined; /** borrowed-readonly — the leg's live permission-mode seat; the tool's shared-read consent gate arbitrates at it before * the approver is consulted (a released read is delivered, undisclosed to nobody: the gate records it). */ permissionMode: PermissionModeController; /** borrowed-readonly — the run's resolved env: the byte source of a published local file. */ executionEnv: ExecutionEnv; /** borrowed-readonly — the canonical task root the fs fence contains reads to; undefined ⇒ no local-file publish. */ rootCanonical: string | undefined; /** borrowed-readonly — the extra containment roots (write and read-only) the fence admits, read per call (the run's * live set: an in-flight read-root grant widens it). */ additionalRootsCanonical: () => readonly string[]; /** borrowed-readonly — the read-deny matcher in force for the run, when any. */ readDenyMatcher: PlacedReadDenyMatcher | undefined; /** borrowed-readonly — the resolved read face (`"open"` lifts root containment for reads). */ resolvedReadFace: ContainmentFace | undefined; /** borrowed-readonly — the tracked-cwd cell; `current` is read per call as the relative-path base. */ handsCwdRef: Prepared["cwdRef"]; /** borrowed-mutable — the run's roster builder; writer here: ONE mount when the seat is valid. */ roster: RosterBuilder; /** borrowed-readonly — the first-party result-offload wrapper every core mount passes through (a large read or a conflict snapshot is offloaded, not inlined). */ firstPartyOffload: (tool: AgentTool) => AgentTool; /** borrowed-mutable — the env-hand membership set the memory content-origin face reads (a tool that reads the execution env's files is a hand); writer here: `add("Artifact")` on the mount. */ envHandToolNames: Set<string>; /** borrowed-mutable — the run's store cell the in-flight read-root grant reads (minted by the hands phase; absent on * a hands-less leg, which has no grant); writer here: the declared `storageDir`'s physical path once the * declaration validates. */ artifactStoreRef?: ArtifactStoreRef; } export interface PrepareArtifactResult { /** owned — the mounted face's plane, or undefined when nothing mounted (absent seat, or an invalid one). */ artifactPlane: ArtifactPlane | undefined; } export declare function prepareArtifact(input: PrepareArtifactInput): PrepareArtifactResult;