workflows/options

Source: src/workflows/options.ts

What every combinator shares: the same options, under the same names, with the same defaults.

Combinators are functions, not classes. No inheritance, no global registry. They compose because they all take a Result in and give a Result back.

offerBoth

function

export function offerBoth(first: ToolOffer | undefined, second: ToolOffer | undefined): ToolOffer | undefined { /* … */ }

Two offers as one: what first offers an agent, then what second does.

Whichever shape either answers in, the sum is asked for the id, because a list spread beside a function is how a swarm handed its members the board and would have thrown on a caller’s offer written the other way.

SpawnFn

type

export type SpawnFn = (agent: Agent, options: SpawnOptions) => Promise<Subagent>;

The spawn function a combinator uses. Injection point for tests.

ToolOffer

type

export type ToolOffer = (agent: Agent) => ToolDefinition[] | CustomToolsFor | undefined;

What a workflow offers each of its agents beyond their own tools.

A function of the agent, because the answer differs by agent: a reviewer is offered the verdict tool and the worker beside it is not. What it answers is {@link SpawnOptions.customTools}: a list, or a function of the id to come when a tool needs to know who holds it.

WorkflowOptions

type

export type WorkflowOptions = {
	/** Absent, each agent's frontmatter decides, then `"task"`. Persistence is asked for, never assumed. */
	lifetime?: Lifetime;
	/** Propagated down to every `session.prompt()`, and closes open sessions. */
	signal?: AbortSignal;
	/**
	 * Deadline **per turn**, not for the whole workflow. No default.
	 *
	 * A chain of five steps with `timeoutMs: 60_000` can legitimately run for
	 * five minutes; what it cannot do is hang forever on one of them. See
	 * {@link AskOptions.timeoutMs} for why that guard is needed at all.
	 */
	timeoutMs?: number;
	/** A single listener for the whole workflow. Compose with {@link combineReporters}. */
	onEvent?: EventListener;
	/** Report onto an existing bus instead of a private one - the extension's case. */
	bus?: EventBus;
	/** Working directory of every subagent. Defaults to the process's own. */
	cwd?: string;
	/** Where the session files live. Implied by `exportDir`; set it to move them. */
	sessionDir?: string;
	/**
	 * Where every subagent of this workflow writes its transcript when it
	 * closes. See {@link SpawnOptions.exportDir}: it implies a session
	 * directory, and it is opt-in.
	 *
	 * Because the pool closes in a `finally`, an interrupted workflow still
	 * exports what it managed to do.
	 */
	exportDir?: string;
	/** Give every subagent of this workflow its own herdr split. Opt-in. */
	openInHerdr?: boolean;
	/**
	 * Model pattern for **every** subagent of this workflow.
	 *
	 * An override, like {@link SpawnOptions.model}, and for the same reason: it
	 * is what lets one workflow run against different models without touching an
	 * agent file. It beats every agent's frontmatter - a sweep that let a pinned
	 * agent through would measure a mixture.
	 */
	model?: string;
	/** Defaults to the real {@link spawn}. */
	spawn?: SpawnFn;
	/**
	 * Tools combo defines, chosen per agent.
	 *
	 * A function rather than a list, because the answer differs by agent: a
	 * reviewer is offered the verdict tool and the worker beside it is not, and
	 * a collector shared between two agents could not say which of them spoke.
	 *
	 * Returning a {@link CustomToolsFor} instead of a list defers the choice one
	 * step further, to the moment the subagent's id exists - see
	 * {@link SpawnOptions.customTools}. The pool passes either through untouched:
	 * only a tool that spawns children needs the id, and nothing else should pay
	 * for it.
	 */
	customTools?: ToolOffer;
	/**
	 * The subagent every subagent of this workflow hangs under.
	 *
	 * Set when a workflow is itself the work of a subagent, which today means
	 * `delegateTool`. It is what turns a flat list of measurements into a tree.
	 */
	parentId?: string;
};

Options common to every workflow - same names, same defaults, everywhere.