/** * Failure vocabulary. * * Every one of these is *thrown*, never returned. pi only sets `isError: true` * on a tool result when `execute()` throws — a returned object with an `error` * field looks to the model exactly like a successful search that found nothing. * * `SearchChallengeError` is the one the agent is expected to act on rather than * just report: it means a human has to touch the browser before search can work * again, so its message says so in words the agent can pass to the operator. */ /** The search engine served a captcha, consent wall, or other human check. */ export class SearchChallengeError extends Error { override readonly name = "SearchChallengeError"; /** Machine-readable flavour of the challenge, for callers that branch on it. */ readonly challenge: string; /** The page the human needs to visit to clear it. */ readonly pageUrl: string; /** Which browser is blocked, e.g. "10.88.0.25:9223 (built-in default)". */ readonly endpoint: string; constructor(options: { challenge: string; pageUrl: string; endpoint: string; detail?: string | undefined }) { super( [ `Search is blocked by a human verification challenge (${options.challenge}).`, options.detail ? `Page said: ${options.detail}` : null, `This cannot be solved by the agent — a person has to clear it in the browser at ${options.endpoint}.`, `Ask the user to open ${options.pageUrl} in that Chrome, complete the challenge or accept the consent dialog,`, `then retry the search. The cookie it sets persists in that browser profile, so one pass unblocks later searches.`, ] .filter((line) => line !== null) .join(" "), ); this.challenge = options.challenge; this.pageUrl = options.pageUrl; this.endpoint = options.endpoint; } } /** The browser could not be reached or spoke CDP badly. */ export class BrowserUnavailableError extends Error { override readonly name = "BrowserUnavailableError"; } /** The search itself ran but produced nothing usable. */ export class NoResultsError extends Error { override readonly name = "NoResultsError"; } /** The per-search deadline expired, or the user pressed Esc. */ export class SearchAbortedError extends Error { override readonly name = "SearchAbortedError"; } export const messageOf = (e: unknown): string => (e instanceof Error ? e.message : String(e));