diff --git a/backend/apps/agents/tools/search/search_startpage.py b/backend/apps/agents/tools/search/search_startpage.py index 692cb578..30dd0465 100644 --- a/backend/apps/agents/tools/search/search_startpage.py +++ b/backend/apps/agents/tools/search/search_startpage.py @@ -11,13 +11,18 @@ returns the real result page. Parsing is anchored on `result-link` / `gl-title-link` and the `description` paragraph, never on the emotion CSS hashes in the same class attributes, which change build to build. -Returns None when Startpage served a challenge instead of results, so the -caller can tell "closed" apart from "genuinely no hits".""" +Answers a `StartpageAnswer` rather than a string because "closed" and +"genuinely no hits" look identical on the wire (both are a 200 with no result +anchors) and the caller has to act on them differently: a refusal is a failed +tier that should count against the engine, an empty result set is the honest +answer to a nonsense query. Startpage names the second case itself, in an +"Uh-oh, there are no results for this search" page.""" import html import re -from typing import List, Optional +from typing import List +from pydantic import BaseModel, ConfigDict from typeguard import typechecked from backend.apps.agents.tools.browser_http import browser_request @@ -36,6 +41,15 @@ P_DESC_RE = re.compile( # Startpage inlines a