/** * UI prompts for goal-driven-loop. * * Wraps Pi's UI methods with timed auto-defaults to avoid * blocking the user forever. */ export interface UIContext { hasUI: boolean; select: ( title: string, options: string[], opts?: { timeout?: number } ) => Promise; notify: (message: string, level?: "info" | "warn" | "error") => void; confirm: ( title: string, message: string, opts?: { timeout?: number } ) => Promise; } const DEFAULT_TIMEOUT_MS = 10_000; const STAGNATION_NOTIFY_THRESHOLD = 2; /** * Prompt the user to resolve a stale goal state. * Returns the choice or undefined on timeout. * Auto-default: "continue" */ export async function promptStaleState( ctx: UIContext ): Promise<"continue" | "replace" | "abandon" | undefined> { if (!ctx.hasUI) { return "continue"; } const choice = await ctx.select( "已有目标在进行中", ["继续当前目标", "替换为新目标", "放弃当前目标"], { timeout: DEFAULT_TIMEOUT_MS } ); switch (choice) { case "继续当前目标": return "continue"; case "替换为新目标": return "replace"; case "放弃当前目标": return "abandon"; default: return "continue"; } } /** * Notify the user that the goal is being delegated to comet. */ export function notifyCoarseGrainedDelegation( ctx: UIContext, goal: string ): void { if (!ctx.hasUI) return; ctx.notify( `目标粒度较大,已委托给 comet 全流程处理:${goal}`, "info" ); } /** * Notify the user about mid-loop granularity upgrade. */ export function notifyMidLoopUpgrade(ctx: UIContext, goal: string): void { if (!ctx.hasUI) return; ctx.notify( `执行中发现目标比预期复杂,已升级到 comet:${goal}`, "info" ); } /** * Notify the user about stagnation that auto-recovery couldn't fix. * Called after STAGNATION_NOTIFY_THRESHOLD auto-recovery attempts. */ export function notifyStagnation( ctx: UIContext, goal: string, passedCount: number, totalCount: number, iteration: number ): void { if (!ctx.hasUI) return; ctx.notify( `目标停滞:${goal} (${passedCount}/${totalCount} 通过, 第 ${iteration} 轮)。自动策略调整未奏效,请人工介入。`, "warn" ); } /** * Check if we should notify the user about stagnation yet. */ export function shouldNotifyStagnation( consecutiveStagnations: number ): boolean { return consecutiveStagnations > STAGNATION_NOTIFY_THRESHOLD; }