/** * design/98 §3.1 (S8c) — the `run_workflow` TOOL an LLM calls to author + run its own workflow. Mounted ONLY * when self-orchestration is active (design/98 §1.2: opt-in + a HARD `WorkflowScriptRunner` + a governance * baseline). Params are ONLY `{ script, args }` — it NEVER accepts `depth` (the nesting depth is a trusted * internal channel, design/98 §0.1). `effect: "write"` (spawning agents is an irreversible side effect → it * passes the design/37 policy gate; each spawned agent then passes its OWN governed gate). * * Flow: size-cap the script → statically validate `meta` (no eval) → `startWorkflow` with the GOVERNED * primitives + hard caps → return `{ runId }` IMMEDIATELY → on completion, notify the originator via the * {@link WorkflowCompletionNotifier} seam. */ import type { AgentTool } from "../internal/harness.js"; import type { Model } from "../internal/llm.js"; import type { Runner } from "../core/runner/runtask.js"; import type { WorkflowGovernanceBaseline } from "../core/types.js"; import type { WorkflowRunStore } from "../core/workflow-run-store.js"; import type { WorkflowJournalStore } from "../core/workflow-journal-store.js"; import type { TaskRegistry } from "../core/task-registry.js"; import type { TaskNotificationPayload } from "../core/task-notification.js"; import type { WorkflowAgentHandle } from "./workflow.js"; import type { WorkflowScriptRunner } from "./workflow-script-runner.js"; import { type NamedWorkflowListing, type WorkflowScriptStore } from "./workflow-script-store.js"; import { type WorkflowSizeGuideline } from "./workflow-size-guideline.js"; /** Reserved name of the injected self-orchestration tool. Audit [485]④ (2026-07-07): CC's primary * name is `Workflow` with `RunWorkflow` as the alias — CC-trained prompts address "Workflow", so the * primary flips to match; `RunWorkflow`/`run_workflow` remain callable via tool-name-aliases. */ export declare const RUN_WORKFLOW_TOOL_NAME = "Workflow"; /** * design/98 §D.5 — the seam the deployment implements to RE-INVOKE the originating LLM when its workflow * finishes. Core calls `notify` once per run (at most once — `runId` dedup) with a REDACTED, BOUNDED summary; * the service routes it back through its task-notification path (cross-replica via the WorkflowRunStore). */ export interface WorkflowCompletionNotifier { notify(input: { runId: string; task_id?: string; task_type?: "workflow"; toolUseId?: string; sourceTaskId?: string; /** service [368]: the ORIGINATING session id (the run that spawned this workflow), threaded from the * Runner so a deployment's completion inbox resolves the target session lookup-free. */ originatingSessionId?: string; principal?: string; status: "completed" | "failed"; /** Redacted + length-bounded — never the host's internal paths/tokens. */ summary: string; result?: string; usage?: unknown; }): Promise | void; /** * 黑板 [405](poll-then-also-notify 双投): the ORIGINATING session was served this run's TERMINAL * state IN-BAND (a `TaskOutput` poll through the task registry returned a non-running snapshot) — * the deployment should ack/drop any still-pending completion-inbox entry for (originatingSessionId, * runId), so a later stream-open doesn't re-deliver a `workflow_complete` the model already * consumed. Fired at most once per run, AFTER `notify` may already have enqueued (the whole point: * the poll usually wins the race in-turn). Optional; errors are swallowed. The shell-side same-process * seed dedup remains the belt — this is the durable/cross-restart half. */ ackServed?(input: { runId: string; originatingSessionId?: string; sourceTaskId?: string; principal?: string; }): Promise | void; } /** design/98 §D.6 — the deployment's hard CEILINGS for an LLM-authored workflow (the tool forces them; a * script may only tighten). All optional; sensible defaults bound a runaway script. */ export interface WorkflowLimits { /** Max script source length (chars). Default 100_000. */ maxScriptChars?: number; /** Max cumulative agents. Default 50. */ maxAgents?: number; /** Whole-workflow wall-clock cap (ms). Default 600_000 (10 min). */ totalTimeoutMs?: number; /** Per-child task timeout (sec). Default 300. */ perAgentTimeoutSec?: number; /** Per-child cost ceiling (USD). Forced onto every child. */ childMaxCostUsd?: number; /** Per-child token ceiling. Forced onto every child. */ childMaxTokens?: number; /** Per-child turn ceiling. */ childMaxTurns?: number; /** Workflow token budget (`ctx.agent` throws once reached). */ budget?: number; /** Max returned-result size (chars). Default 100_000. */ maxResultChars?: number; /** Max single log-line length (chars). Default 10_000. */ maxLogChars?: number; /** * 黑板 [663]③ — CC 2.1.202+ config key `workflowSizeGuideline`: ADVISORY workflow size guidance * (NOT a cap — the hard ceiling stays `maxAgents`). small/medium/large append CC's verbatim * "keep workflows under N agents … guideline, not a hard limit" section to the Workflow tool card * (CC :17593321 `Bvs + Wvs(…)`); "unrestricted"/unset injects nothing (byte-identical card). * Lives on the limits object so it rides the EXISTING `RunnerDeps.workflowLimits` threading — * deployments configure it as `workflowLimits: { sizeGuideline }` with no new prepare-task seam. * `RunWorkflowToolDeps.sizeGuideline` (direct construction) takes precedence when both are set. */ sizeGuideline?: WorkflowSizeGuideline; } /** * design/140 §6 1b — pick the LLM-facing guidance text for one named workflow: `whenToUse` when declared, * else the description (the agents-side `agentWhenToUseText`/CC `tIl` selection shape, workflows arm — * workflows have no lean variant, so the fallback chain is just whenToUse → description). */ export declare function workflowWhenToUseText(m: { description?: string; whenToUse?: string; }): string | undefined; /** * design/140 §6 1b — render the named-workflow roster block appended to the Workflow tool card (the * consumption face `meta.whenToUse` previously lacked). Line shape mirrors the agent roster (CC `tIl`, * subagent.ts precedent): `- name: whenToUse-or-description`. Returns undefined when nothing is registered * (the card stays byte-identical to the pre-140 form). */ export declare function renderNamedWorkflowListing(entries: ReadonlyArray): string | undefined; export interface RunWorkflowToolDeps { /** The Runner that executes child tasks (the workflow's `ctx.agent` → `runner.runTask`). */ runner: Runner; /** The HARD sandbox (asserted `safeForUntrustedScripts:true`). */ scriptRunner: WorkflowScriptRunner; /** Deployment-trusted governance every spawned agent inherits (design/98 §2.5). */ governanceBaseline: WorkflowGovernanceBaseline; /** Model catalog (for the name→Model allowlist resolution). */ models?: Record; /** F4 agentType registry: deployment agent definitions `agent(…, {agentType})` resolves (SHADOW over * built-in Explore/Plan; `builtinAgents:false` removes the built-ins). Same registry the Agent tool uses. */ agents?: import("../core/types.js").AgentDefinition[]; builtinAgents?: boolean; /** Optional run store for cross-replica `/workflows` observability (opt-in). */ store?: WorkflowRunStore; /** design/97 CORE-9 (Part A) — optional LOAD-BEARING resume journal: records each agent result so a * `resumeFromRunId` re-run replays the unchanged prefix (durable cross-replica resume). Opt-in. */ journalStore?: WorkflowJournalStore; /** design/97 CORE-9 (Part B) — optional steerable-handle sink. When set, the script's `agent()` primitive runs * each agent STEERABLE and emits its {@link WorkflowAgentHandle} here (the script never sees the handle); the * deployment registers it by runId+label to route a human/cross-replica steer. Unset ⇒ non-steerable. Opt-in. */ onAgentSpawn?: (handle: WorkflowAgentHandle) => void; /** Tenant/grouping key for the run. */ scope?: string; /** Completion re-invoke seam. */ notifier?: WorkflowCompletionNotifier; /** service [368]: the originating session id, threaded into every completion notify. */ originatingSessionId?: string; /** Process-local unified task registry. When present, RunWorkflow returns `task_id === runId` with a `w*` id. */ taskRegistry?: TaskRegistry; /** design/115 P2 core slice: run-local task-notification sink for SDK event + live model XML injection. */ taskNotification?: (notification: TaskNotificationPayload) => void; /** Runner-owned owner fallback for registry access when the execute context is unavailable. */ taskOwner?: string; /** Hard ceilings. */ limits?: WorkflowLimits; /** B5/F2 (CC scriptPath/name surface): optional script-persistence seam. When wired, EVERY invocation's * resolved script is persisted (best-effort) and its path returned in the tool result; `scriptPath` * re-runs a persisted file and `name` resolves a saved workflow. Absent ⇒ inline `script` only. */ scriptStore?: WorkflowScriptStore; /** design/140 §6 1c — `false` removes the BUILT-IN named workflows (`team-discussion`, …) wholesale (the * `builtinAgents:false` analog). Default ON: `{name}` resolves a built-in even with NO deployment script * store; a deployment `scriptStore.resolveName` hit for the same name always SHADOWS the built-in. */ builtinWorkflows?: boolean; /** 黑板 [663]③ (CC `workflowSizeGuideline`) — advisory size guideline appended to the tool card. * Direct-construction face; wins over `limits.sizeGuideline` (the RunnerDeps-reachable channel). * See {@link WorkflowLimits.sizeGuideline}. */ sizeGuideline?: WorkflowSizeGuideline; /** The originating task id + principal, threaded to the notifier. */ sourceTaskId?: string; principal?: string; /** TRUSTED nesting depth from the run's internals (NOT a tool param) — passed to `startWorkflow` so a * cross-process child workflow is rejected by the one-level guard. */ workflowDepth?: number; /** The HOST task's effective working root — threaded into every spawned agent's trusted internals so a * TOC env factory can root the child at the parent's cwd (CC parity; blackboard 2026-07-03). */ parentCwd?: string; /** Call-time getter for the HOST task's current thinking level — a spawned agent with no explicit * script/baseline `thinking` inherits it (the parentCwd/model-snapshot companion). */ parentThinking?: () => import("../core/types.js").TaskSpec["thinking"]; } /** * Build the `run_workflow` tool. ASSERTS the runner is a hard sandbox (defense in depth — prepare-task only * mounts it under the same gate). Returns a structured error (not a throw) for an LLM-correctable problem * (oversized / malformed-meta / nesting), so the model can fix and retry. * * Async since codex F3: the card's named-workflow roster is derived from the SAME sources the execute path * resolves against (built-ins probed through `resolveName` shadowing + awaited `list()`), so the card can * never advertise a workflow the call would resolve differently. */ export declare function createRunWorkflowTool(d: RunWorkflowToolDeps): Promise; //# sourceMappingURL=run-workflow-tool.d.ts.map