/** * The search-results-page loop guard (#14), re-homed onto the NATIVE browser path. * * A live v2 session spent ~30 browser navigations going to * `cn.bing.com/search?q=…`, one query per round trip, each snapshot 200-500 * tokens. That is the exact pattern design goal 3 exists to kill, happening on * the web channel: `tm_search` already queries bing (and six other engines) and * returns a deduped, RRF-fused hit list in ONE call, so a browser navigation to * a SERP is a slower, dumber version of a tool the agent already has. * * The guard was deleted with the self-built browser (`d668817`) because that * tool was its only consumer — but the problem it guards is independent of * WHICH browser opens the page. It now rides `src/host/v2-browser-gate.ts`, * which already sees the exact URL of every native `browser_*` navigation at * `execute.before`. The pure logic lives here so it can be pinned without a * live desktop. * * The browser is still the legitimate fallback — bing's HTML is sometimes an * anti-bot shell and only a real browser gets through — so this is a RATE * LIMIT, not a ban: the first `limit` navigations to a given engine+query go * through, and past that the navigation is refused until the agent has tried * `tm_search`. Refusing outright would remove the one path that survives a JS * challenge, and removing a working fallback to fix a misuse is the wrong trade. * * Accounting is PER PROCESS and keyed by engine+query: one shared browser * catalog serves every agent, so "how many times has this conversation opened * THIS search" is a conversation-level fact, and a different query gets its own * budget rather than being punished for an earlier one. */ export interface SerpTarget { /** the tm_search engine that covers this host, "" when none does */ engine: string; query: string; host: string; } /** Pure: a search-results URL tm_search can already produce, or null. */ export declare function serpTarget(raw: unknown): SerpTarget | null; export interface SerpVerdict { target: SerpTarget; /** how many times THIS engine+query has been navigated to, including this one */ count: number; limit: number; blocked: boolean; } export declare const SERP_NAV_LIMIT = 3; export declare function createSerpLoopGuard(limit?: number): { /** call BEFORE navigating; records the attempt either way */ observe(url: unknown): SerpVerdict | null; /** total SERP navigations observed, across every engine+query */ seen(): number; }; /** The line the agent reads. It names the replacement call rather than just * refusing, because "don't do that" without "do this instead" costs a second * round for the model to work the difference out. */ export declare function serpRedirect(v: SerpVerdict): string; export declare function serpRefusal(v: SerpVerdict): string; //# sourceMappingURL=serp-loop.d.ts.map