UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

218 lines (217 loc) • 17.9 kB
/** * PrepareTask's WIRING-MANIFEST phase, verbatim from the driver: the run's own frozen approver * seat, the loud ungated-write warning (hand band / destructive MCP / first-party write tools with no effect-aware gate, * deduped per deployment and tool-set shape), the PreToolUse context stash and the blocked-call set, the settlement and * bare-rejection sidebands, the turn halt fact, the suspend infrastructure predicates (restore surface gap, durable * infra, the task-axis lane with its INACTIVE line), usage governance, the platform-suspend arming, the synthesized * durableApproval, the effective wiring manifest, the peer lane's ask fold and drain binding, the park predicate as ONE * named const, the durable-gate-unavailable notice, the hook identity mint and the hook env face. The four helpers only * this segment called moved with it (usage governance, the per-deployment warn ledger, the MCP manifest projection, the * durable-gate notice). The interface is the dependency list the segment had implicitly. * * SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await, so the phase adds no yield between the policy-chain * station before it and the gate registration after it (a stretch with no await is extracted as a sync * function). Read-stability of the host handles for the call: {@link RunInternals} (`@contract prepare.deps-read-stable`). * * One read changed spelling and nothing else: the manifest's MCP face read `mcp?.statuses ?? []` while `mcp` had long * been the protocol-tools phase's non-null handle; the optional chain was dead and is now the plain member read. */ import type { AgentHarness, ExecutionEnv } from "../../internal/harness.js"; import { type PeerLaneRefs } from "../../agents/peer-session-drain.js"; import type { SessionBoxBinding } from "../task-notification.js"; import type { OnQuestion } from "../ask-question.js"; import type { CheckpointStore } from "../checkpoint-store.js"; import { type HookEnvCapabilities, type HookInvocationIdentity, type Hooks } from "../hooks.js"; import type { LockedPreflight } from "../locked-config.js"; import type { MaterializedMcp } from "../mcp.js"; import type { SessionStore } from "../session.js"; import { type ToolResultStore } from "../tool-result-store.js"; import { type OnAsk, type ToolPolicy } from "../tool-policy.js"; import type { GateOutcome } from "../gate-outcome.js"; import type { RunnerDeps, RuntimeCaps, TaskSpec, ToolEffect, ToolExecuteContext } from "../types.js"; import { type LegWriteProtection } from "./write-protection-station.js"; import { type UsageWindow } from "../usage-window-store.js"; import type { ToolRoster } from "../tool-roster.js"; import { type AutoModeArmFact, type WiringManifest, type WiringManifestMcpEntry } from "../wiring-manifest.js"; import { type PermissionModeController } from "../mode-policy.js"; import type { AnnounceOnceSink, Prepared, PrepareResume, RunInternals, UsageGovernance } from "./contracts.js"; export interface PrepareWiringManifestInput { /** borrowed-readonly — the REBOUND spec. Read: `onAsk` (the own seat), `onQuestion` (the question seam), `handsReadOnly` / `tools` (the ungated scan), * `resourceSuspend` (the task-axis lane), `durableApproval` / `principal` (the synthesis and the notice), `interactiveTools` / * `mcp` / `checkpointStore` (manifest cells and the notice's cause), `enablePlanMode` (the gate-machinery predicate's * plan-mode term). Never mutated. */ spec: Pick<TaskSpec, "onAsk" | "onQuestion" | "handsReadOnly" | "tools" | "resourceSuspend" | "durableApproval" | "principal" | "interactiveTools" | "mcp" | "checkpointStore" | "enablePlanMode" | "hooks" | "peerPresence">; /** borrowed-readonly — the deployment seats, whole: `onAsk` (the seat's deps half), `onError` (the warning), `executionEnv` * (the hook-env predicate), `checkpointStore` (durable infra), the manifest's dozen wiring facts (`backgroundAgentStore`, * `permissionRuleStore`, `permissionRuleSyncWired`, `onBackgroundChildEvent`, `lockedConfig`, `compliancePostureResolver`, * `memoryScopeAdmission`, `retentionPolicy`, `onElicit`), `onNotice`, the write-protection judge's compile seats * (`writeProtectedPaths`, `memoryEngineDir`), and the usage-governance seats (`usageWindowStore`, * `now`, `onUsageGovernance`…) the helper reads through the whole record. */ deps: RunnerDeps; /** borrowed-readonly — the trusted spawn-side channel: `questionFaceStripped`, `isDelegatedChild`, `onTaskNotification`, * `peerSelfRef`, `explicitAgentName` (the drain + the identity), `insideFork` / `agentName` / `spawnAgentType` / `parentToolCallId` (the identity). */ internals: Pick<RunInternals, "questionFaceStripped" | "isDelegatedChild" | "onTaskNotification" | "peerSelfRef" | "explicitAgentName" | "spawnAgentType" | "insideFork" | "agentName" | "parentToolCallId"> | undefined; /** borrowed-readonly — the resume leg, or undefined (the manifest's leg derivation reads presence only). */ resume: Pick<PrepareResume, "seed"> | undefined; /** borrowed-readonly — the acquired session id. */ sessionId: string; /** borrowed-readonly — the run's invocation id. */ runId: string; /** borrowed-readonly — the per-task identity (the hook identity's taskId). */ hostTaskId: string; /** borrowed-readonly — the registry scope the peer drain binds under. */ taskScope: string; /** borrowed-readonly — the resolved hook record (`spec.hooks ?? deps.hooks`): the effect-aware-gate term, the tracked flag and the hook-env consumer test. */ hooks: Hooks | undefined; /** borrowed-readonly — whether the deployment declared its screening face observational (then it is no gate). */ preToolUseObservational: boolean; /** borrowed-readonly — the caller-facing policy layers; only their COUNT is read (an effect-aware gate exists). */ policyLayers: ReadonlyArray<unknown>; /** borrowed-readonly — the policy chain's effective policy, or undefined; only its PRESENCE is read (the first term of the * gate-machinery predicate below). Never called here. */ effectivePolicy: ToolPolicy | undefined; /** borrowed-readonly — whether an execution env is wired (the hand band exists at all). */ handsEnabled: boolean; /** borrowed-readonly — the resolved task root: the base a `base: "root"` write tool's relative spelling resolves against. */ taskRootFinal: string; /** borrowed-readonly — the materialized MCP handle: `tools` (the destructive-ungated scan) and `statuses` (the manifest face). */ mcp: Pick<MaterializedMcp, "tools" | "statuses">; /** borrowed-readonly — the assembled safety vocabulary (the ungated scans and the manifest's armed cell). Read only. */ irreversibleTools: ReadonlySet<string>; /** borrowed-readonly — see `irreversibleTools`. */ egressTools: ReadonlySet<string>; /** borrowed-readonly — the hands phase mounted the shell READ STATION (a real shell was mounted): the gate * machinery must run for it, under every doctrine — the read-only face's containment IS that station. */ shellReadStationArmed: boolean; /** borrowed-readonly — the effect collection; read only here (the ungated scans). */ toolEffects: ReadonlyMap<string, ToolEffect>; /** borrowed-readonly — the per-task owned env when a factory minted one (durable infra, the hook-env predicate). */ ownedEnv: ExecutionEnv | undefined; /** borrowed-readonly — the run's resolved env (the hook env face is built over it). */ executionEnv: ExecutionEnv; /** borrowed-readonly — the run's offload store, or undefined (a volatile store disqualifies durable suspend). */ offloadStore: ToolResultStore | undefined; /** borrowed-readonly — the once-per-session ledger's operator sink (the INACTIVE line, once per session). */ onceLedger: Pick<AnnounceOnceSink, "onError">; /** borrowed-readonly — the resolved usage windows, or undefined. */ usageWindows: readonly UsageWindow[] | undefined; /** borrowed-readonly — the env-lifetime suspend instant, or undefined (platform-suspend arming). */ envLifetimeSuspendAt: number | undefined; /** borrowed-readonly — the resolved per-principal entitlements (forceDurableGate). */ runtimeCaps: RuntimeCaps | undefined; /** borrowed-readonly — the resolved interaction posture (a manifest cell). */ resolvedInteractionPosture: ToolExecuteContext["interactionPosture"]; /** borrowed-readonly — the question-face phase's durable-face decision (the composition-lie detector reuses it). */ durableQuestionFace: boolean; /** borrowed-readonly — the live question face, or undefined (the notice's effective fact). */ liveQuestionFace: OnQuestion | undefined; /** borrowed-readonly — the leg's checkpoint store, resolved once by the question-face phase. */ checkpointStore: CheckpointStore | undefined; /** borrowed-readonly — the session store (durability declaration and transcript tier). */ sessions: SessionStore; /** borrowed-readonly — the model gate's per-leg read face, or undefined. */ modelGateManifest: WiringManifest["modelGate"]; /** borrowed-readonly — the leg's minted tool roster: rides the manifest's `tools` section and is the * source of the hand band's write-capable names for the ungated-write warning (what actually MOUNTED). */ toolRoster: ToolRoster; /** borrowed-readonly — from the read-face phase: the built-in read-deny TIERS that leg's own * resolution materially activated; relayed onto the manifest (present iff non-empty), never * re-derived from `deps` here (which by this phase sits past that phase's await). */ readDenyBuiltinTiersActive: readonly string[]; /** borrowed-readonly — from the LSP phase's manager fold: gates the manifest's LSP section (absent ⇒ byte-identical manifest). */ lspManagerWired: boolean; /** borrowed-readonly — from the LSP phase: is the diagnostics lane live? The `lane` word's only input. */ lspDiagnosticsLive: boolean; /** borrowed-readonly — from the file-history phase's one fold of the two off switches: the manifest's word, relayed. */ fileHistoryFact: NonNullable<WiringManifest["fileHistory"]>; /** borrowed-readonly — the arming outcome the caps phase reads live (the manifest's auto-mode face at this leg's start). */ autoModeArmReason: () => AutoModeArmFact; /** borrowed-readonly — the leg's live permission-mode seat: its receipt at this leg's start rides the manifest, and the * peer lane reads the effective mode through the refs filled here. */ permissionMode: PermissionModeController; /** borrowed-readonly — the frozen preflight; only `mcp` (the declared servers the manifest face joins). */ lockedPreflight: Pick<LockedPreflight, "mcp">; /** borrowed-mutable — the peer lane's late-bound facts. Writer here: `askEffective` ← the manifest's ask derivation (the * one fold of this session's permission-mode class). */ peerLaneRefs: PeerLaneRefs; /** borrowed-mutable — #1036's settlement seam, minted by the orchestrator. This phase writes * its two predicate seats (`boxBacked` / `wantsEffects`) when it binds the drain; the ledgers * themselves are written later, by the harness receipt sink, the compaction commit beat and the * drain's own passes. */ frameSettlement: import("../frame-settlement.js").FrameSettlement; /** borrowed-readonly — the session-box drain's mount verdict (prepare-task's one judgment): present ⇒ this leg drains its own box. */ sessionBox: SessionBoxBinding | undefined; /** borrowed-readonly — the built harness the peer drain binds to. */ harness: AgentHarness; /** borrowed-readonly — the durable-suspend holder; the drain's parked predicate reads `token` at run time. Not written here. */ pausedRef: Prepared["pausedRef"]; /** borrowed-readonly — the FROZEN approver seat (the notice's liveApprover fact). */ frozenOnAsk: OnAsk | undefined; /** borrowed-readonly — the LIVE half of the inherited chain (the notice reads its content mandates). */ liveInheritedGate: RunInternals["inheritedGate"]; /** borrowed-readonly — the effective delegation facts (the identity's isDelegatedChild). */ delegation: { isDelegatedChild: boolean; }; } export interface PrepareWiringManifestResult { /** owned — the run's own approver seat (spec over deps), read by the gate-fold station. */ onAsk: OnAsk | undefined; /** borrowed-mutable — PreToolUse `additionalContext` per call id. Writers: the gate (phase 1 stash), the post-tool handler * (one-shot drain). */ preToolContexts: Map<string, string[]>; /** borrowed-mutable — the call ids the gate blocked or suspended (`Prepared.blockedToolCalls`). Writers: the gate; readers * delete one-shot. */ blockedToolCalls: Set<string>; /** borrowed-mutable — the gate-outcome sideband (`Prepared.gateOutcomes`). Writer: the gate station; the frame mint reads and * deletes. Nothing else may write it. */ gateOutcomes: Map<string, GateOutcome>; /** borrowed-mutable — the turn's halt fact (`Prepared.batchHaltRef`). Writer: the judgment site; cleared at the next request. */ batchHaltRef: Prepared["batchHaltRef"]; /** owned — whether any consumer of the blocked set is wired (populate only then). */ blockedTracked: boolean; /** owned — the restore-surface gap of a declared-suspendable adapter, or undefined for a complete / non-suspendable one. */ incompleteSuspendAdapter: readonly ("resumeVM" | "postResumeInit")[] | undefined; /** owned — the infrastructure half of suspend eligibility (no task opt-in in it). */ durableSuspendInfraReady: boolean; /** owned — the task-axis lane: the infrastructure plus the caller's opt-in. */ resourceSuspendEligible: boolean; /** owned — the run's usage-governance handle, or undefined (`Prepared.usageGovernance`). */ usageGovernance: UsageGovernance | undefined; /** owned — whether the suspend saga must be armed for a PLATFORM cause. */ platformSuspendArmed: boolean; /** owned — the effective durable-approval opt-in: the caller's, or the scope synthesized for a forced durable gate. */ durableApproval: TaskSpec["durableApproval"]; /** owned — this leg's EFFECTIVE wiring manifest (`Prepared.wiringManifest`). */ wiringManifest: WiringManifest; /** owned — the leg's write-protection judge, or undefined when the table was emptied (no judge, no tighten mounted): * its gate input (`check`) for the gate station and its target judge for the shell station — one compile, never two. */ writeProtection: LegWriteProtection | undefined; /** owned — THE park predicate as one named const (`parkLane.effective === true`). */ parkLaneArmed: boolean; /** owned — THE gate-machinery activation predicate as one named const: a policy, a screening hook, an egress or * irreversible tool, an eligible resource lane, an armed platform lane, or plan mode. The ask lane, the suspend saga, * the boundary parks, the park closure and the gate station are built exactly when it holds. */ gateMachineryActive: boolean; /** owned — THE identity mint of this leg (`Prepared.hookIdentity`), one frozen envelope every hook station reuses. */ hookIdentity: HookInvocationIdentity; /** owned — the read-only env capability face every hook context carries, or undefined (no hook consumer, or no env wired). */ hookEnvFace: HookEnvCapabilities | undefined; /** owned — the session box this leg's drain was BOUND on (the mount judgment ∧ an injector to drain into); the notification * lane binds the park seat on exactly this value, so "parked here" and "drained there" are one fact. */ sessionBoxBound: SessionBoxBinding | undefined; } /** * The wiring manifest's per-server MCP read face for one leg ({@link WiringManifest.mcp}): every * server the leg's FROZEN entry snapshot declared, in declaration order, joined by name to this leg's * materialization statuses. Pure projection — no connection logic, no second look at any transport: * · a status `connected` ⇒ `connected` with the mounted roster size (the intake's post-filter count); * · a status `failed` ⇒ `failed` with the failure record the materialization stamped (`errorCode`/`delivered`/ * `httpStatus` = the MCP vocabulary's `McpFailure` spread flat) and the remote text SECRET-REDACTED (an HTTP endpoint's error body rides the SDK's message * verbatim, and a body that echoes the bearer it rejected must not reach a stream consumer), * then neutralized + bounded to the reminder's own 240 (the same bound the once-per-session * ledger applies to that text — one face, one width); * · no status at all ⇒ `skipped` (the declaration stands, this leg produced no attempt record for it). * `source` is echoed from the declaration (single-line, bounded; core reads nothing off it), and * `liveness` is the status record's own observation deep-copied (see {@link WiringManifestMcpEntry.liveness}). * The entries are fresh objects so the manifest never aliases the status records the refresh face mutates. */ export declare function mcpManifestEntries(entries: ReadonlyArray<import("../types.js").McpServerSpec> | undefined, statuses: ReadonlyArray<import("../mcp.js").McpServerStatus>): WiringManifestMcpEntry[]; /** The M18 phase body — prepareTask's wiring-manifest stretch, verbatim (see the module header). */ export declare function prepareWiringManifest(input: PrepareWiringManifestInput): PrepareWiringManifestResult;