import type { TSchema } from "typebox"; import type { AgentContextWindowStats, AgentUsage } from "./agent.js"; import { type WorkflowAgentOptions } from "./agent.js"; import type { AgentHistoryEntry } from "./agent-history.js"; import { type AgentRegistry } from "./agent-registry.js"; import type { WorkflowCompactionPolicyName } from "./compaction-policy.js"; import { type CollectFinalizationOptions, type FinalizationCheckResult } from "./conductor-finalization.js"; import type { ConductorRunStatus } from "./conductor-types.js"; import { type ContextModeRegistry, type ContextPrimitives, type SystemPromptMode } from "./context-mode.js"; import { WorkflowErrorCode } from "./errors.js"; import { type HarnessConfigRegistry } from "./harness-config.js"; import { type HarnessSelection } from "./harness-selector.js"; import { type LoopGuardOptions } from "./loop-detector.js"; import { type ModelTierConfig } from "./model-tier-config.js"; import { type PrototypeSafetyOptions, type PrototypeSafetyResult } from "./prototype-safety.js"; import { type StageCheckOptions, type StageCheckResult } from "./stage-check.js"; export interface WorkflowMetaPhase { title: string; detail?: string; model?: string; } export interface WorkflowMeta { name: string; description: string; phases?: WorkflowMetaPhase[]; /** Default model for agents whose phase has no route and that set no model/tier. */ model?: string; } /** One cached agent() result, keyed by its deterministic call index. */ export interface JournalEntry { index: number; /** sha256 of the call's identity (prompt + model + phase + agentType + schema). */ hash: string; result: unknown; /** Agent label used by the original live agent call, when this entry came from agent(). */ label?: string; /** Agent phase used by the original live agent call, when this entry came from agent(). */ phase?: string; /** Tokens used by the original live agent call, preserved for resume replay. */ tokens?: number; /** Provider usage reported by the original live agent call, when available. */ usage?: AgentUsage; /** Context-window occupancy stats captured for this agent, when measurable. */ contextWindow?: AgentContextWindowStats; /** Resolved model used by the original live agent call, when known. */ model?: string; /** ISO timestamp for the original live agent start. */ startedAt?: string; /** ISO timestamp for the original live agent end. */ endedAt?: string; /** Compact tool/message history from the original live agent call, replayed on resume. */ history?: AgentHistoryEntry[]; } /** * Global resources shared across a run and any workflow() nested inside it, so * the 16-concurrent / 1000-total caps and the token budget hold across nesting * instead of each level getting its own limiter and counters. */ export interface SharedRuntime { limiter: (fn: () => Promise) => Promise; agentCount: number; spent: number; tokenUsage: { input: number; output: number; total: number; cost: number; cacheRead: number; cacheWrite: number; }; depth: number; } interface WorkflowAgentRunner { run(prompt: string, options?: unknown): Promise; } export interface WorkflowAgentTelemetryConfig { tier?: string; agentType?: string; requestedModel?: string; modelSource?: "agent" | "agentType" | "tier" | "phase" | "main" | "session-default"; contextMode?: string; context?: ContextPrimitives; timeoutMs?: number | null; retries?: number; maxContextTokens?: number; contextReserveTokens?: number; promptTokensEstimate?: number; compactionPolicy?: WorkflowCompactionPolicyName | null; } export interface WorkflowRunOptions extends WorkflowAgentOptions { args?: unknown; agent?: WorkflowAgentRunner; /** The session's main model (provider/id), shown in /workflows for default agents. */ mainModel?: string; /** * Named subagent definitions for `agent({ agentType })`. Snapshotted once per * run for determinism. Defaults to scanning `.pi/agents` (project) + `~/.pi/agents`. * Injectable for tests. */ agentRegistry?: AgentRegistry; /** * Model-tier snapshot for this run. undefined loads the machine config once; * null explicitly disables it. Injectable for deterministic tests/embedders. */ modelTierConfig?: ModelTierConfig | null; concurrency?: number; /** Retry attempts after a recoverable agent failure. Default 0. */ agentRetries?: number; tokenBudget?: number | null; /** Default hard cap for provider input/context tokens per agent. */ agentMaxContextTokens?: number | null; /** Default reserve subtracted from model context windows for occupancy. */ agentContextReserveTokens?: number | null; /** Default per-agent compaction posture. "auto" makes local/no-cache models compact earlier. */ compactionPolicy?: WorkflowCompactionPolicyName | null; signal?: AbortSignal; /** Maximum number of agents allowed in this run. Default: 1000 */ maxAgents?: number; /** Timeout per agent in milliseconds. null/omitted means no hard timeout. */ agentTimeoutMs?: number | null; /** Wall-clock timeout for the whole async workflow script. null means no hard timeout. */ workflowTimeoutMs?: number | null; /** Detect repeated identical agent() calls. Default is warn-only. */ loopGuard?: LoopGuardOptions; /** Whether to persist logs to disk. Default: true */ persistLogs?: boolean; /** Run ID for persistence. Auto-generated if not provided. */ runId?: string; /** * Directory to persist each subagent's NDJSON transcript into (one file per * subagent). When set, subagent sessions are file-backed so the full message * stream survives disposal — matching Claude Code's `agent-.jsonl` per-subagent * transcripts. When omitted, subagents use in-memory sessions. */ transcriptDir?: string; /** Resume: cached agent results keyed by deterministic call index. */ resumeJournal?: Map; /** Resume: the run being resumed (informational; enables resume mode). */ resumeFromRunId?: string; /** Called after each live agent completes so the caller can persist the journal. */ onAgentJournal?: (entry: JournalEntry) => void; /** * Run-level default context posture — the LOWEST-precedence layer, beneath the * agentType frontmatter and the per-call `agent()` options. Set by a slash * command's `--mode ` flag so e.g. `/code-review --mode isolated` runs * every reviewer clean-room without editing any agent `.md`. */ contextMode?: string; /** Run-level harness runtime selector (`--harness-type`); wired: drives HarnessSelection snapshot, expandHarnessConfig, clean-skip, and agent() seams. */ harness_type?: string; /** Run-level harness capability/config selector (`--harness-config`); wired: drives HarnessSelection snapshot, expandHarnessConfig, clean-skip, and agent() seams. */ harness_config?: string; inheritProjectContext?: boolean; systemPromptMode?: SystemPromptMode; inheritSkills?: boolean; inheritMainRules?: boolean; /** * Named context-mode registry (built-ins + project-defined). Defaults to the * built-ins. Threaded from settings by the extension entry so a project's * `contextModes` are resolvable here and in tool-driven runs. */ contextModeRegistry?: ContextModeRegistry; /** Persisted run state loaded by the caller for resume, so the harness selection snapshot can be reused. */ persistedRunState?: import("./run-persistence.js").PersistedRunState; /** Harness config registry for expansion. Snapshotted once per run, mirroring agentRegistry. Injectable for tests. */ harnessConfigRegistry?: HarnessConfigRegistry; /** Run-level read-only flag; when set, the harness expansion and agent fence enforce read-only tool policy. */ readOnly?: boolean; /** Called immediately after the run's harness selection snapshot is resolved. */ onHarnessSelection?: (selection: HarnessSelection) => void; /** Internal: shared runtime inherited by a nested workflow() call. */ sharedRuntime?: SharedRuntime; /** Resolve a saved-workflow name to its script, enabling `workflow('name', args)`. */ loadSavedWorkflow?: (name: string) => string | undefined; /** * Host-side mechanical verification used by the stageCheck() workflow global. * Defaults to native TypeScript/Biome detection in src/stage-check.ts. */ stageCheck?: (options: StageCheckOptions) => Promise; /** * Ask the human a checkpoint() question and resolve to their reply. Threaded from * a UI-bearing tool context. Absent => headless: checkpoint() takes its declared * default (and journals it), so a detached/background run never hangs. */ confirm?: (promptText: string, options: CheckpointOptions) => Promise; onLog?: (message: string) => void; onPhase?: (title: string) => void; onAgentStart?: (event: { agentCallId?: string; label: string; phase?: string; prompt: string; model?: string; startedAt?: string; agentConfig?: WorkflowAgentTelemetryConfig; }) => void; onAgentEnd?: (event: { agentCallId?: string; label: string; phase?: string; result: unknown; tokens?: number; usage?: AgentUsage; contextWindow?: AgentContextWindowStats; worktree?: string; model?: string; agentConfig?: WorkflowAgentTelemetryConfig; error?: string; errorCode?: WorkflowErrorCode; recoverable?: boolean; startedAt?: string; endedAt?: string; }) => void; onAgentHistory?: (event: { label: string; phase?: string; history: AgentHistoryEntry[]; }) => void; /** Called to broadcast the current semantic status of the workflow run. */ onSemanticStatus?: (status: ConductorRunStatus) => void; /** * Injectable finalization-check callback so tests can avoid real git/gh. * When omitted, defaults to `checkFinalization` from conductor-finalization. */ finalizationCheck?: (cwd: string, opts?: CollectFinalizationOptions) => Promise; /** * Injectable prototype-mode safety check so tests can avoid real git state. * When omitted, defaults to the deterministic git worktree checker. */ prototypeSafetyCheck?: (cwd: string, opts?: PrototypeSafetyOptions) => Promise; onTokenUsage?: (usage: { input: number; output: number; total: number; cost: number; cacheRead?: number; cacheWrite?: number; }) => void; } export interface WorkflowRunResult { meta: WorkflowMeta; result: T; logs: string[]; phases: string[]; agentCount: number; durationMs: number; runId?: string; tokenUsage?: { input: number; output: number; total: number; cost: number; cacheRead?: number; cacheWrite?: number; }; /** Harness selection snapshot for this run, exposed for resume and telemetry. */ harnessSelection?: HarnessSelection; } export interface AgentOptions { label?: string; phase?: string; schema?: TSchemaDef; /** * Run this agent on a specific model (`provider/modelId` or a bare `modelId`). * The workflow author chooses per-agent models per the routing policy in the * tool guidelines (e.g. a lighter model for exploration, the main model for * analysis). When omitted, the session's main model is used. */ model?: string; /** * Coarse model tier ("small" | "medium" | "big"), resolved from the user's * model-tiers config (see /workflows-models). An explicit `model` takes * precedence; a tier takes precedence over the phase model. When the tier has * no configured entry it falls back to the session's main model. */ tier?: string; isolation?: "worktree"; /** * Name of a registered subagent definition (`.pi/agents/.md`, project > * user). Binds that definition's tool allow/denylist, model, and body prompt * to this agent. An explicit `model` overrides the definition's model; the * definition's model overrides `tier`/phase. An unknown name logs a warning * and falls back to default tools/model (with the name as a prose hint). */ agentType?: string; /** * Context-inheritance posture: a named mode (`focused` | `isolated` | `scoped` * | `legacy` | a project-defined mode) that expands to the primitives below. The * agentType definition may set its own; these call-level fields override it * (runtime > frontmatter). Default `focused` (main-agent rules don't leak in). */ contextMode?: string; /** Tentative per-call harness runtime selector; inert until Issue D wires expansion. */ harness_type?: string; /** Tentative per-call harness capability/config selector; inert until Issue D wires expansion. */ harness_config?: string; /** * Per-call read-only fence. Narrow-only: the effective readOnly is `run-level * readOnly || agentOptions.readOnly`, so a call (e.g. the Issue Delivery verifier) * can add the fence but cannot lift a run-level one. Filters WRITE_TOOL_NAMES from * the resolved tool set. */ readOnly?: boolean; /** Load project AGENTS.md / context files into this subagent. Default true. */ inheritProjectContext?: boolean; /** "append": base prompt + role-as-task (default); "replace": role IS the base system prompt. */ systemPromptMode?: SystemPromptMode; /** Load skills into this subagent. Default true. */ inheritSkills?: boolean; /** * Per-agent **skills allowlist**: load ONLY these named skills into the * subagent, regardless of `inheritSkills`/`contextMode`. An empty array is a * fence that loads ZERO skills (equivalent to `inheritSkills:false`). * `undefined` preserves the resolved context posture's skill behavior. * Unknown names warn and are skipped (the run never fails). Wins over * `inheritSkills`/`contextMode` for the skills channel. */ skills?: string[]; /** Inherit the main-agent append channel (`.pi/APPEND_SYSTEM.md`). Default false (no leak). */ inheritMainRules?: boolean; /** Per-call coding-tool allowlist. Undefined = agentType/default tool policy. */ tools?: string[]; /** Per-call coding-tool denylist, applied after the allowlist. */ disallowedTools?: string[]; /** Override timeout for this specific agent. null means no hard timeout. */ timeoutMs?: number | null; /** Hard cap for provider input/context tokens for this agent. */ maxContextTokens?: number | null; /** Override the reserve subtracted from model context windows for occupancy. */ contextReserveTokens?: number | null; /** Per-agent compaction posture. Overrides the run-level compactionPolicy. */ compactionPolicy?: WorkflowCompactionPolicyName | null; /** Retry attempts after a recoverable failure for this specific agent. */ retries?: number; } /** Options for a human checkpoint() — a deterministic, journaled, replayable gate. */ export interface CheckpointOptions { /** Reply used when no UI is available (headless/background) and headless != "abort". */ default?: unknown; /** Headless behavior: "default" (take `default`/true) or "abort" (throw). Default "default". */ headless?: "default" | "abort"; /** Confirm | free-text input | pick-one. Affects the hash and the UI widget. */ kind?: "confirm" | "input" | "select"; /** For kind "select". */ choices?: string[]; /** Per-checkpoint timeout in ms for the interactive prompt. */ timeoutMs?: number; } export declare function runWorkflow(script: string, options?: WorkflowRunOptions): Promise>; export declare function parseWorkflowScript(script: string): { meta: WorkflowMeta; body: string; }; export {};