@sema-agent/core
Version:
Stateless, task-oriented AI agent core
139 lines (138 loc) • 10.2 kB
TypeScript
/**
* PrepareTask's PROMPT-INPUTS phase: the prompt provider selection, the runtime
* feature flags the harness-context block gates on (so it never claims a mechanism the task lacks),
* the three-source user system prompt + the caller's append block, the fenced MCP server-instructions
* block, the environment facts (client zone + date basis, knowledge cutoff, the deployment's sandbox
* axes, resume-continuity facts on a durable-resume leg only, the hands facts + the one batched env
* probe with its cwd/pwd alignment guard) and the git-status lane probe. The body is moved verbatim
* from the driver's own stretch; its interface is the dependency list that stretch had implicitly.
*
* ASYNC BY CONTENT: the stretch awaits the env probe (hands) and the git-status lane probe (always).
* It sits past prepareTask's first await, so the driver's `await` adds no window a caller could reach.
*
* The one input computed by the DRIVER rather than read here: `failClosedReason` — the
* self-orchestration fail-closed advisory's text. Its helper takes the whole `TaskSpec`/`RunnerDeps`
* (it audits several deployment seats), which this phase's narrow `spec`/`deps` seats cannot satisfy
* The driver evaluates the helper in the Input literal and this phase only announces
* the result on the operator lane, exactly where the stretch always did.
*
* Nothing here throws on its own: the env probe and the alignment guard are best-effort (a stub/odd env
* just omits the shell-derived facts), and the git lane degrades through `onDegrade` → `deps.onError`.
*/
import type { ExecutionEnv, ThinkingLevel } from "../../internal/harness.js";
import type { Model } from "../../internal/llm.js";
import { type EnvironmentFacts, type PromptProvider } from "../../prompts/default.js";
import type { ContainmentFace } from "../../tools/fs/index.js";
import type { LockedPreflight } from "../locked-config.js";
import type { MaterializedMcp } from "../mcp.js";
import type { ResolvedRole } from "../roles.js";
import type { RunnerDeps, TaskSpec } from "../types.js";
import type { SessionTreeEntry } from "../../internal/harness-types.js";
import type { DateAnchorRead, PrepareResume, PromptFeatureFlags, RunInternals, ToolFaceSnapshot } from "./contracts.js";
import type { AdvertisedWritableDirs } from "./advertised-writable-dirs.js";
import { type GitStatusLaneRef } from "./git-status-frame.js";
import { type ContextWindowOverlay } from "../context-settings.js";
export interface PreparePromptInputsInput {
/** borrowed-readonly — the REBOUND spec (`spec′`). Read: `promptProvider`, `hooks` (flag), `systemPrompt`
* / `appendSystemPrompt` (the user prompt sources), `clientContext` (zone, email), `envFacts` (the
* deployment's sandbox + resume facts), `compaction` (the within-task flag). Never mutated. */
spec: Pick<TaskSpec, "promptProvider" | "hooks" | "systemPrompt" | "appendSystemPrompt" | "clientContext" | "envFacts" | "compaction">;
/** borrowed-readonly — deployment deps: `promptProvider` (fallback), `hooks` (flag), `onError` (the
* operator lane: fail-closed advisory, cwd misalignment, git-lane degrade), `modelKnowledgeCutoffs`.
* Receiver preserved (`deps.onError?.(…)`). */
deps: Pick<RunnerDeps, "promptProvider" | "hooks" | "onError" | "modelKnowledgeCutoffs">;
/** borrowed-readonly — the self-orchestration fail-closed advisory (null = nothing to announce),
* evaluated by the DRIVER against the whole spec/deps (see the module header). */
failClosedReason: string | null;
/** borrowed-readonly — the locked preflight; only `toolPolicy` presence is read (the policy flag). */
lockedPreflight: Pick<LockedPreflight, "toolPolicy">;
/** borrowed-readonly — whether self-orchestration is ACTIVE (the same gate that mounted the
* workflow tool): drives the orchestration prompt flags. */
selfOrchestrationActive: boolean;
/** borrowed-readonly — the task's execution env: `isIsolated` for the isolation flag, `exec` for the
* one batched probe, `canonicalPath` for the alignment guard. Never re-bound, never destroyed here. */
executionEnv: ExecutionEnv;
/** borrowed-readonly — the session's reminder mark (rides the prompt facts for the declaration). */
reminderMark: string;
/** borrowed-readonly — the resolved read face (the open-reads flag + the structured env fact). */
resolvedReadFace: ContainmentFace | undefined;
/** borrowed-readonly — the resolved write face (the open-writes flag + the structured env fact). */
resolvedWriteFace: ContainmentFace | undefined;
/** borrowed-readonly — the frozen tool face; only `defer` is read (the Workflow short-pointer flag). */
toolFaceSnapshot: Pick<ToolFaceSnapshot, "defer">;
/** borrowed-readonly — the resolved prompt profile (rides the flags to the legacy ctx). */
promptProfile: "simple" | "classic";
/** borrowed-readonly — the fable-mitigations profile axis (rides the flags with the profile). */
fableMitigations: boolean;
/** borrowed-readonly — trusted internals: `goalMode` (goal flag), `isolation` (worktree flag),
* `defaultSystemPrompt` (the third prompt source). `undefined` on a standalone prepare. */
internals: Pick<RunInternals, "goalMode" | "isolation" | "defaultSystemPrompt"> | undefined;
/** borrowed-readonly — the resolved, role-folded reasoning tier (the awareness flag's input). */
thinking: ThinkingLevel | undefined;
/** borrowed-readonly — the factory-minted isolated env, read for PRESENCE only (the worktree flag's
* belt over the fail-closed isolation guard). */
ownedEnv: ExecutionEnv | undefined;
/** borrowed-readonly — the leg's effective-delegation facts; only `isNonForkChild` is read. */
delegation: {
readonly isNonForkChild: boolean;
};
/** borrowed-readonly — the resolved role; only its `systemPrompt` preset is read (second source). */
resolvedRole: Pick<ResolvedRole, "systemPrompt">;
/** borrowed-readonly — the materialized MCP roster; only `serverInstructions` is read (fenced). */
mcp: Pick<MaterializedMcp, "serverInstructions">;
/** borrowed-readonly — the resolved model (id for the env line + the cutoff lookup). */
model: Model;
/** borrowed-readonly — the run's external-content-target fold (the single-source disclosure fact). */
externalContentTargetActive: boolean;
/** borrowed-readonly — the durable-resume carrier, read for PRESENCE only (resume facts copy on a
* resume leg and never on a fresh one). */
resume: PrepareResume | undefined;
/** borrowed-readonly — whether a real execution env is mounted (the hands facts + both probes). */
handsEnabled: boolean;
/** borrowed-readonly — the FINAL task root: the env `cwd` fact and the git lane's root. */
taskRootFinal: string;
/** borrowed-readonly — the canonical extra working roots (copied into the env facts). */
additionalRootsCanonical: readonly string[];
/** borrowed-readonly — the canonical extra read-only roots (copied into the env facts). */
additionalReadRootsCanonical: readonly string[];
/** borrowed-readonly — the advertised-writable-directory seat (hands only). The scratchpad section is
* rendered only when the seat did not SKIP the scratchpad — a directory the fence refused is not advertised. */
advertisedWritableDirs?: AdvertisedWritableDirs;
/** borrowed-readonly — the acquired session's id (operator-line context). */
sessionId: string;
/** borrowed-readonly — the acquired session; only `getBranch` is read (the date anchor). */
session: {
getBranch(): Promise<ReadonlyArray<SessionTreeEntry>>;
};
/** borrowed-readonly — the deployment's window overlay for this leg, as it reads at PREPARE. The prompt's
* context-management sentence must not claim mid-task summarization a deployment has turned off for this
* model; the seat is live, so a later swap's effect on the SENTENCE lands at the next prepare while its
* effect on the BEHAVIOR lands at the next boundary — stated, not sworn away. */
contextOverlay?: ContextWindowOverlay;
}
export interface PreparePromptInputsResult {
/** owned — the prompt provider in force (`spec` ?? `deps` ?? the default). */
provider: PromptProvider;
/** owned — the runtime feature flags (see {@link PromptFeatureFlags}). */
featureFlags: PromptFeatureFlags;
/** owned — the user system prompt: `spec.systemPrompt ?? resolvedRole.systemPrompt ?? internals.defaultSystemPrompt`. */
userSystemPrompt: string | undefined;
/** owned — the caller's append block (`spec.appendSystemPrompt`). */
userAppendSystemPrompt: string | undefined;
/** owned — the fenced MCP server-instructions block, or undefined when no server declared any. */
mcpInstructionsBlock: string | undefined;
/** owned — the environment facts the env tail renders from. Filled here; no later phase writes it
* (the run loop re-renders only the date through `renderWithDate`). */
envFacts: EnvironmentFacts;
/** owned — whether the client zone validated (the date-change seam re-renders in the same zone). */
tzValid: boolean;
/** owned — the client's declared zone as given (paired with `tzValid`; unvalidated on its own). */
userTz: string | undefined;
/** owned — the session's date anchor as read here; `envFacts.date` is its prefix date when present. */
dateAnchor: DateAnchorRead | undefined;
/** owned — the git-status lane's run-local state (empty on a hands-less leg); the run loop and the checkpoint
* serializer mutate its fields from here on (`announced`, `mirrorOwed`, …; the frame's receipt rides the leg's shared `Prepared.frameReceipts`). */
gitStatusRef: GitStatusLaneRef;
}
/** The M10 phase body — prepareTask's prompt-inputs stretch, verbatim (see the module header). */
export declare function preparePromptInputs(input: PreparePromptInputsInput): Promise<PreparePromptInputsResult>;