/** * sim/executor.ts — the default Executor: one pi-gui agent sub-loop per * operate delegation. This is the TS counterpart of mirofish's execution * layer reached through `sandbox.exec()`: the planner hands over a semantic * intent; a grounding agent (pi-gui itself) looks at the screen and lands it * in as many primitive steps as it takes. * * Statelessness is the contract, not a limitation: each exec() runs a FRESH * agent context ("the assistant remembers nothing between delegations" — the * planner's thread bridge exists precisely for this), while the DRIVER stays * alive across delegations so the surface (tabs, logins, app state) persists. * * Substeps are assembled from the loop's own events: gui_act's verb becomes * the action name, tool results stay verbatim (never rewritten), the * observation verdict "frozen" becomes the honesty marker `noop`, and * llm/device spans are derived from event timing for the run waterfall. */ import type { MutableModels } from "@earendil-works/pi-ai"; import type { ExecHooks, ExecOptions, ExecResult, Executor } from "./models.ts"; export interface PiGuiExecutorOptions { /** Grounding model ("provider/model-id"). Defaults to PI_GUI_SIM_EXEC_MODEL, * then the planner's default chain. */ model?: string; driver?: string; strategy?: string; cdpUrl?: string; /** Max primitive steps per delegation (the planner may lower it per call). */ maxSteps?: number; /** When set, a screenshot is captured after every gui_act and written here; * SubStep.shot carries the file path. Unset = no per-substep captures. */ shotDir?: string; /** Test seam: pre-configured registry (faux provider). */ models?: MutableModels; } /** The task text handed to the grounding agent — mirrors the three channels * of mirofish's ExecOptions: intent, bridging context, and the expect anchor * the executor must verify on screen and report first. */ export declare function execTaskText(command: string, opts: ExecOptions): string; export declare class PiGuiExecutor implements Executor { private opts; readonly kind: string; private profile; private shotSeq; constructor(opts?: PiGuiExecutorOptions); private execModel; /** The driver is built lazily on first use and BORROWED by every sub-loop; * close() is the owner's (host's) call. */ private ensureProfile; exec(command: string, opts: ExecOptions, hooks?: ExecHooks): Promise; /** Current-frame capture for the planner's observation (written to shotDir * when set so the ref is a stable path; skipped otherwise). */ snapshot(): Promise; state(): Promise<{ title?: string; } | null>; /** Release the underlying driver connection (owner call, mirrors runGuiTask's * own close semantics — the managed browser itself stays alive). */ close(): Promise; }