mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-13 21:27:41 +02:00
[aidan] fix/web-search: nudge model to browser fallback when search backends fail
This commit is contained in:
+12
-2
@@ -74,6 +74,15 @@ P_GROUNDED_ATTEMPT_TIMEOUT = 48.0 # just above the providers' own 45s httpx tim
|
||||
# Local httpx + trafilatura fetch of a real page; the fast path for /fetch (normal pages return in <2s). Set just above WebFetchTool's own 30s httpx ceiling so a valid-but-slow page still completes locally instead of being clipped down to a grounded summary; only a truly hung server gets cut.
|
||||
P_LOCAL_FETCH_TIMEOUT = 32.0
|
||||
|
||||
# When every search backend fails, point the model at the in-product browser (always-on CreateBrowserAgent tool) instead of telling it to "wait and retry", which it can't do and just relays as a dead end. The real Chromium renders pages and isn't subject to the DDG scrape throttle.
|
||||
def p_browser_fallback_nudge(query: str) -> str:
|
||||
return (
|
||||
"Don't stop here: fall back to the in-product browser, which renders real pages and "
|
||||
"isn't subject to this rate limit. Call CreateBrowserAgent with a task like: "
|
||||
f'"Search the web for: {query}. Report the top results with their titles and URLs, '
|
||||
'plus a direct answer if you find one."'
|
||||
)
|
||||
|
||||
|
||||
async def p_gemini_grounded_call(api_key: str, prompt: str, *, use_url_context: bool) -> dict:
|
||||
"""Call Gemini with googleSearch (+ optionally urlContext) grounding.
|
||||
@@ -470,11 +479,12 @@ async def search(body: SearchBody) -> dict:
|
||||
else:
|
||||
tail = (
|
||||
"DuckDuckGo is rate-limiting this network and every configured provider "
|
||||
"errored (see details below). Wait a moment and retry."
|
||||
"errored (see details below)."
|
||||
)
|
||||
nudge = p_browser_fallback_nudge(body.query)
|
||||
return {
|
||||
"query": body.query,
|
||||
"results": f"No results for: {body.query}\n\n{tail}",
|
||||
"results": f"No results for: {body.query}\n\n{tail}\n\n{nudge}",
|
||||
"backend": "none",
|
||||
"cascade_errors": errors,
|
||||
}
|
||||
|
||||
@@ -128,6 +128,22 @@ async def test_everything_fails_is_honest_not_empty(monkeypatch):
|
||||
assert "Settings" in res["results"] or "API key" in res["results"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_everything_fails_nudges_browser_not_retry(monkeypatch):
|
||||
# All-fail must hand the model the browser as an escape hatch, not a dead-end "wait and retry".
|
||||
p_ddg_throttled(monkeypatch)
|
||||
monkeypatch.setattr(W, "p_resolve_openai_api_key", lambda: "okey") # configured but errors
|
||||
|
||||
async def p_openai_boom(*a, **k):
|
||||
raise RuntimeError("openai down")
|
||||
monkeypatch.setattr(W, "p_openai_websearch", p_openai_boom)
|
||||
|
||||
res = await search(SearchBody(query="sony zv-e10 price"))
|
||||
assert res["backend"] == "none"
|
||||
assert "CreateBrowserAgent" in res["results"]
|
||||
assert "retry" not in res["results"].lower()
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------- /fetch mirrors /search: local httpx + trafilatura is the fast path, grounded fetchers are the fallback for JS/paywalled pages, every attempt is bounded. --------------------------------------------------------------------------
|
||||
|
||||
from backend.apps.web.web import fetch, FetchBody
|
||||
|
||||
Reference in New Issue
Block a user