/** * Conditional — routing composition: evaluates branches in order, runs the first match. * * Pattern: Builder (GoF) + Adapter over footprintjs's `addDeciderFunction`. * Role: core-flow/ layer. Picks exactly ONE branch based on a predicate * (sync function of input) OR an LLM decision. Chosen branch * receives `{ message }` and returns a string. * Emits: agentfootprint.composition.enter / exit + * composition.route_decided (via compositionRecorder). * * v1 of this primitive supports `.when(id, predicate, runner)` + `.otherwise(id, runner)`. * LLM-gated routing (`.whenLLM(id, prompt, runner)`) lands in Phase 5. */ import { type FlowchartCheckpoint, type RunOptions, type StructureRecorder } from 'footprintjs'; import type { GroupMetadata, GroupTranslator } from '../core/translator.js'; import type { RunnerPauseOutcome } from '../core/pause.js'; import type { Runner } from '../core/runner.js'; import { RunnerBase } from '../core/RunnerBase.js'; export interface ConditionalOptions { readonly name?: string; readonly id?: string; /** * Optional build-time recorders passed through to footprintjs's * `flowChart()` factory. Each recorder observes per-node build * events (`onStageAdded` / `onSubflowMounted` / etc.) for this * composition's internal chart (Seed + Route decider + each branch * mount + Finalize). When omitted, no build-time observation is * wired up. */ readonly structureRecorders?: readonly StructureRecorder[]; /** * Optional per-COMPOSITION translator (UI-agnostic). See * `core/translator.ts`. When attached, `runner.getUIGroup()` invokes * it with the Conditional's `GroupMetadata` (kind `'Conditional'`, * id, name, branches as members, plus `extra.fallbackId`). * Returns `undefined` when omitted. */ readonly groupTranslator?: GroupTranslator; } export interface ConditionalInput { readonly message: string; } export type ConditionalOutput = string; type BranchChild = Runner<{ message: string; }, string>; export type Predicate = (input: ConditionalInput) => boolean; interface BranchEntry { readonly id: string; readonly name: string; readonly runner: BranchChild; /** Undefined for the `otherwise` fallback. */ readonly predicate?: Predicate; /** Optional per-method translator override for THIS branch only. */ readonly groupTranslator?: GroupTranslator; } /** * Options bag accepted by `ConditionalBuilder.when()` and `.otherwise()` * for per-method overrides. Backwards-compatible — when the trailing * arg is a string, it's still treated as `name`. */ export interface ConditionalBranchOptions { /** Human-friendly name for this branch. Default: the branch id. */ readonly name?: string; /** Per-method translator override. See `BranchEntry.groupTranslator`. */ readonly groupTranslator?: GroupTranslator; } export declare class Conditional extends RunnerBase { readonly name: string; readonly id: string; private readonly branches; private readonly fallbackId; private readonly opts; private currentRunContext; constructor(opts: ConditionalOptions, branches: readonly BranchEntry[], fallbackId: string); static create(opts?: ConditionalOptions): ConditionalBuilder; protected getGroupTranslator(): GroupTranslator | undefined; /** Conditional: one member per branch (.when / .otherwise), plus * `extra.fallbackId` marking the otherwise branch. Per-method * overrides (L1c) take precedence over the branch runner's own * translator. */ protected buildUIGroupMetadata(): GroupMetadata; run(input: ConditionalInput, options?: RunOptions): Promise; resume(checkpoint: FlowchartCheckpoint, input?: unknown, options?: RunOptions): Promise; private createExecutor; private finalizeResult; private buildChart; } /** * Fluent builder. Branches evaluate in registration order; first matching * predicate wins. `.otherwise()` is the mandatory fallback. */ export declare class ConditionalBuilder { private readonly opts; private readonly branches; private fallbackRegistered; private fallbackId; private readonly seenIds; constructor(opts: ConditionalOptions); /** * Register a predicate-gated branch. `predicate` is a pure sync function * of the Conditional's input; if it returns true, the corresponding * runner executes. Branches evaluate in registration order. * * Fourth arg accepts EITHER a legacy bare `name` string OR a * `ConditionalBranchOptions` bag containing `name` and/or a per-method * `groupTranslator` override. The override applies ONLY to this * branch's `member.uiGroup`. */ when(id: string, predicate: Predicate, runner: BranchChild, nameOrOpts?: string | ConditionalBranchOptions): this; /** * Register the fallback branch. Exactly ONE must be registered before build(). * Third arg accepts a legacy `name` string OR a `ConditionalBranchOptions` * bag (same shape as `.when()`). */ otherwise(id: string, runner: BranchChild, nameOrOpts?: string | ConditionalBranchOptions): this; build(): Conditional; } export {};