import { type OAuthAccountPools } from "../config/account-pools.js"; import { type CompactionThresholdPair } from "../config/compaction-threshold.js"; import { type ServiceTierInheritSettingValue } from "../config/service-tier.js"; import type { Settings } from "../config/settings.js"; import type { CustomTool } from "../extensibility/custom-tools/types.js"; import { type TaskEffort } from "@oh-my-pi/pi-tui/thinking"; import type { ToolSession } from "../tools/index.js"; import { type DiscoveryResult } from "./discovery.js"; import { type SubagentToolResult } from "./executor.js"; import { type PreparedSeanceSession } from "./seance.js"; import { type AgentDefinition } from "./types.js"; import type { AgentProgress, SingleResult, StructuredSubagentOutput, StructuredSubagentSchemaMode, StructuredSubagentSchemaSource } from "@oh-my-pi/pi-tui/tools/task"; import type { WorkPoolYieldItem } from "./workpool-yield.js"; import { type PerCallModelGrants } from "./model-approval.js"; /** Final structured completion metadata returned for a schema-bearing run. */ export type StructuredSubagentSchemaResult = StructuredSubagentOutput; /** A schema validation or extraction error attached to structured completion metadata. */ export type StructuredSubagentSchemaError = NonNullable; /** A selected schema paired with its source and enforcement mode. */ export interface StructuredSubagentSchemaResolution { schema: unknown; source: StructuredSubagentSchemaSource; mode: StructuredSubagentSchemaMode; outputSchemaOverridesAgent: boolean; } /** Isolation controls shared by the task and eval surfaces. */ export interface StructuredSubagentIsolationControls { requested?: boolean; merge?: "patch" | "branch"; apply?: boolean; } /** Identity and presentation metadata supplied by the calling surface. */ export interface StructuredSubagentIdentity { /** A previously reserved output/registry id. */ id?: string; /** Stable user-facing label used when allocating a new id. */ label?: string; } /** One normalized child invocation. */ export interface StructuredSubagentRequest { session: ToolSession; invocationKind: "task" | "eval"; assignment: string; context?: string; agent?: string; /** Saved source session selected for the bundled seance agent. */ sourceSession?: string; /** * Model chosen by host code (SDK callers, `omp cleanse --model`) or, for the * bundled seance agent, the override of its source session's saved model. * Not gated by `task.perCallModel`. */ model?: string | string[]; /** * Per-call `model` from the model-facing surfaces (task items, eval `agent()` * and `workpool()`): gated by `task.perCallModel`, exact-only, and limited to * operator-approved models. */ perCallModel?: string; /** * The model-facing `model` of a task call naming the `seance` agent. Honoured as * the source-session override only when that name resolves to the bundled seance; * a project or user agent shadowing the name gets it as a {@link perCallModel}. */ seanceModel?: string | string[]; /** Presence, rather than truthiness, makes this the highest-priority schema. */ outputSchema?: unknown; schemaMode?: StructuredSubagentSchemaMode; /** * `false` = no output schema (caller, agent, or session) and no `yield` tool: * the child's final assistant message is its result. An agent declaring * `structured: true` keeps both, resolved as if this were `true`. Default `true`. */ structured?: boolean; /** Per-spawn thinking effort mapped onto the resolved model's supported range; overrides the agent's default selector. */ effort?: TaskEffort; /** Caller's description of how open-ended the work is; steers the child's `auto` thinking classification. */ solutionSpace?: string; identity?: StructuredSubagentIdentity; index?: number; parentToolCallId?: string; detached?: boolean; invokedAt?: number; acquiredAt?: number; isolation?: StructuredSubagentIsolationControls; /** The parent agent name forbidden from recursively spawning itself. */ blockedAgent?: string; /** Preserve a completed temporary artifacts directory for an agent:// handle. */ retainArtifacts?: boolean; /** * Invoked instead of immediate cleanup when a temporary artifacts * directory is retained (`retainArtifacts`). Callers that outlive this * call — e.g. an async job body — take ownership of the returned * disposal closure and MUST eventually run it once the retained handle * is no longer needed, or the directory leaks for the process lifetime. */ onArtifactsRetained?: (cleanup: () => Promise) => void; /** Task UI agents keep live registry references; eval one-shots normally do not. */ keepAlive?: boolean; /** Task frontends may inherit LSP; eval frontends normally set this false. */ enableLsp?: boolean; /** Explicitly pass false for plan mode or invocation kinds that must not use IRC. */ enableIrc?: boolean; /** `0` disables executor wall-clock timeout. Undefined inherits settings. */ maxRuntimeMs?: number; /** Kernel-defined tools explicitly exposed to this child. */ customTools?: CustomTool[]; /** Workpool items accepted by the child yield tool during this turn. */ workPoolYieldItems?: WorkPoolYieldItem[]; signal?: AbortSignal; onProgress?: (progress: AgentProgress) => void; /** See {@link ExecutorOptions.onToolResult}. */ onToolResult?: (result: SubagentToolResult) => void; } /** A normalized preflight result, reusable by tests and adapters. */ export interface EffectiveSubagentPolicy { discovery: DiscoveryResult; agentName: string; agent: AgentDefinition; effectiveAgent: AgentDefinition; modelOverride?: string[]; /** Prepared read-only source fork for the bundled seance agent. */ preparedSession?: PreparedSeanceSession; /** Explicit pre-expansion model role alias selected for this run. */ modelRole?: string; /** Extension routing note explaining a `before_subagent_spawn` model replacement. */ modelRoute?: string; /** Exact-name `task.agentServiceTierOverrides` entry for this agent, applied after model resolution. */ serviceTierOverride?: ServiceTierInheritSettingValue; /** Exact-name entry normalized to both child compaction threshold fields. */ compactionThresholdOverride?: CompactionThresholdPair; /** Exact-name `task.agentAccountPools` entry: the only OAuth accounts the child may use, per listed provider. */ oauthAccountPools?: OAuthAccountPools; /** Absent for a per-call `model`: a requested model that cannot run fails instead of falling back to the parent's. */ parentActiveModelPattern?: string; /** Whether the child gets the `yield` tool; see {@link StructuredSubagentRequest.structured}. */ structured: boolean; /** Present for a per-call `model`: every model the child sends to must stay approved by these grants. */ perCallModelGrants?: PerCallModelGrants; schema: StructuredSubagentSchemaResolution; planMode: boolean; isIsolated: boolean; mergeMode: "patch" | "branch"; applyChanges: boolean; enableLsp: boolean; enableIrc: boolean; /** Caller `effort` hint to apply; dropped when the agent's level comes from the user's `^model:level` tag. */ effort?: TaskEffort; } /** Settled child execution plus data needed by the frontends' own rendering. */ export interface StructuredSubagentResult { result: SingleResult; policy: EffectiveSubagentPolicy; mergeSummary: string; changesApplied: boolean | null; artifactsDir: string; temporaryArtifacts: boolean; } /** Machine-readable failure category so adapters can retain their native errors. */ export declare class StructuredSubagentError extends Error { readonly kind: "preflight" | "isolation" | "execution"; /** The child's settled result, when the child finished before a later step failed. */ readonly result?: SingleResult; constructor(kind: "preflight" | "isolation" | "execution", message: string, options?: ErrorOptions & { result?: SingleResult; }); } /** * Render the subagent user prompt. Only the template is formatted: the assignment is inserted * afterwards with its interior whitespace intact (paragraph breaks, Markdown hard breaks, table * padding), so inline and file-backed instructions reach the subagent identically. */ export declare function renderSubagentUserPrompt(assignment: string): string; /** * A blank `model` is absence, not a selector: callers that emit JSON pad optional * fields with `""` or `[]`, and whitespace alone names no model. */ export declare function normalizeModelSelector(model: T): T | undefined; /** * Why a per-call `model` cannot be used before dispatch: the `task.perCallModel` gate first, so a * caller is never told to fix a selector it may not send, then anything but one exact * `provider/model-id[:level]` selector. `undefined` when there is no problem. */ export declare function invalidModelSelectorReason(model: unknown, label: string, gate: { settings: Settings; invocationKind: "task" | "eval"; }): string | undefined; /** * Resolve every policy shared by task and eval before allocating artifacts or * dispatching work. Callers translate {@link StructuredSubagentError} into * their own wire-level error surface. */ export declare function resolveEffectiveSubagentPolicy(request: StructuredSubagentRequest): Promise; /** Reserve a session-global agent id only after preflight has succeeded. */ export declare function reserveStructuredSubagentId(session: ToolSession, identity: StructuredSubagentIdentity | undefined): Promise; /** * Execute a validated subagent. Preflight errors occur before any artifact * lease or child dispatch; callers keep responsibility for their result text. */ export declare function runStructuredSubagent(request: StructuredSubagentRequest): Promise; /** Build the recovery suffix used by adapters after an isolated failure. */ export declare function buildStructuredSubagentRecoveryHint(result: SingleResult, artifactsDir: string): Promise;