/** * The discover loop — the only place the agent loops (invariant #3). It observes the page, * asks the LLM for the next action, acts, and repeats until done, emitting a Scenario that * later replays with no LLM (invariant #4). LLM is behind the LlmClient seam (invariant #5). * * Module layout: prompt (LLM surface) · decision (Decision→Step + shared execution) · * capture (per-step expect) · grounding (freeze-time assertions). This file owns only the loop. */ import type { Driver, LlmClient, PerceptionAdapter } from "../ports.js"; import type { Scenario, Step } from "../types.js"; import type { TracePhase, TraceScope } from "../trace.js"; import type { ActionPolicy, Decision } from "./decision.js"; export type { ActionPolicy, Decision, PolicyContext, PolicyVerdict } from "./decision.js"; export { applyDecision, decisionToStep, parseDecision } from "./decision.js"; export { rankElements, renderElements, renderRankedElements } from "./prompt.js"; export interface DiscoverOptions { driver: Driver; llm: LlmClient; baseUrl?: string; maxSteps?: number; onStep?: (decision: Decision, step?: Step) => void; /** Abort discovery between steps (a host's Stop button). */ signal?: AbortSignal; /** * Allow the freeze to carry LLM-judged `expect` assertions (semantic checks). Off by default: * `expect` needs an LlmCritic at replay, so the deterministic critic fails it (invariant #4). * When off, only evidence-grounded mechanical assertions are frozen — replay stays LLM-free. */ semanticChecks?: boolean; /** * URL substrings whose 4xx/5xx is product noise (e.g. analytics), excluded from assertion * grounding — mirror of `RunScenarioOptions.benign`, so a product-marked noisy endpoint * can't strip `no-failed-requests` from the freeze during discovery. */ benign?: string[]; /** Gate proposed actions (block destructive controls, cap wandering, stop on a goal). Absent → no * gate (every action runs) — behaviour unchanged. */ policy?: ActionPolicy; /** Correct perceived element state for widgets that expose it outside a11y, before the model sees * the page (a11y-native perception seam). Absent → the raw snapshot is used, unchanged. */ perceive?: PerceptionAdapter; /** Per-event trace scope (spec/core/trace.md); absent → no emission. */ trace?: TraceScope; /** Phase stamped on this discovery's events: "discover" normally, "heal" when it IS the * outcome-heal re-discovery (the phase says why it ran, the kinds say what ran). */ tracePhase?: TracePhase; } export declare function discover(intent: string, opts: DiscoverOptions): Promise;