mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-12 20:57:42 +02:00
[eric] browser: nudge the agent toward the fast captured-API tier once per host
This commit is contained in:
@@ -328,6 +328,7 @@ async def run_browser_agent(
|
||||
recent_tool_calls: list[tuple[str, str, str]] = []
|
||||
loop_trigger_count = 0
|
||||
card_gone_streak = 0 # consecutive "card is gone" results -> fail fast, don't spin
|
||||
route_hinted_hosts: set[str] = set() # surface the fast network tier once per host
|
||||
|
||||
# Stagnation state: busy-but-stuck detection (no URL change + failures
|
||||
# across a run of actions), distinct from the exact-repeat loop above.
|
||||
@@ -1022,6 +1023,21 @@ async def run_browser_agent(
|
||||
session.browser_domains.append(domain)
|
||||
except Exception:
|
||||
pass
|
||||
# The fast tier is ~0% used because the agent never thinks to ask.
|
||||
# Once per host, when safe GET routes have been captured, nudge it:
|
||||
# reading via the API beats re-scraping, especially in a batch loop.
|
||||
try:
|
||||
_rc = int(result.get("routes_available") or 0)
|
||||
_rhost = browser_skills.host_of(result.get("url") or last_seen_url)
|
||||
if _rc > 0 and _rhost and _rhost not in route_hinted_hosts:
|
||||
route_hinted_hosts.add(_rhost)
|
||||
content_blocks = content_blocks + [{"type": "text", "text": (
|
||||
f"\n\n💡 {_rc} of this site's own API endpoint(s) were captured. To READ "
|
||||
"data (and especially to repeat a read for many items), BrowserReplayRoute "
|
||||
"(or a replay_route step in BrowserRepeatFlow) is much faster and more "
|
||||
"reliable than navigating + scraping. See BrowserListRoutes.")}]
|
||||
except Exception:
|
||||
pass
|
||||
if is_loop:
|
||||
loop_trigger_count += 1
|
||||
repeat_count = sum(1 for c in recent_tool_calls if c == call_key)
|
||||
|
||||
@@ -902,6 +902,31 @@ def test_batch_replay_uses_the_fast_network_route_per_value(monkeypatch):
|
||||
assert any("u=ada" in u for u in routes) and any("u=grace" in u for u in routes)
|
||||
|
||||
|
||||
def test_captured_routes_are_surfaced_once_per_host(monkeypatch):
|
||||
# Drives the dead network tier: when safe GET routes exist, the agent gets a
|
||||
# ONE-TIME nudge per host toward BrowserReplayRoute, not on every navigation.
|
||||
BH._browser_history.clear()
|
||||
primary = FakeLLM([
|
||||
Resp([_rp("go 1"), _tu("BrowserNavigate", url="https://docs.google.com/a")]),
|
||||
Resp([_rp("go 2"), _tu("BrowserNavigate", url="https://docs.google.com/b")]),
|
||||
Resp([Blk("text", "done")], stop_reason="end_turn"),
|
||||
])
|
||||
sent = _install(monkeypatch, primary, FakeAux())
|
||||
orig = BA.ws_manager.send_browser_command
|
||||
|
||||
async def _with_routes(request_id, action, browser_id, params, tab_id=""):
|
||||
if action == "navigate":
|
||||
return {"text": f"Navigated to {params.get('url')}", "url": params.get("url"), "routes_available": 4}
|
||||
return await orig(request_id, action, browser_id, params, tab_id)
|
||||
monkeypatch.setattr(BA.ws_manager, "send_browser_command", _with_routes, raising=False)
|
||||
|
||||
asyncio.run(BA.run_browser_agent(task="browse", browser_id="b1", model="sonnet", initial_url=DOC_URL))
|
||||
# messages are cumulative across calls, so count within ONE call's full
|
||||
# conversation: the nudge must appear exactly once for docs.google.com (not per nav)
|
||||
final_convo = json.dumps(primary.calls[-1]["messages"])
|
||||
assert final_convo.count("API endpoint(s) were captured") == 1
|
||||
|
||||
|
||||
def test_browser_wait_routes_through_smart_wait_and_returns_early(monkeypatch):
|
||||
# BrowserWait must no longer be a blind sleep: it probes the page (evaluate)
|
||||
# and returns as soon as it's settled, well under the requested cap.
|
||||
|
||||
@@ -96,7 +96,20 @@ async function handleNavigate(wv: BrowserWebview, params: Record<string, any>):
|
||||
} catch (err: any) {
|
||||
if (!err?.message?.includes('ERR_ABORTED')) throw err;
|
||||
}
|
||||
return { text: `Navigated to ${url}`, url };
|
||||
// Count the safe GET endpoints captured for this site so the backend can nudge
|
||||
// the agent toward the fast network path (the audit found it's ~0% used).
|
||||
let routesAvailable = 0;
|
||||
try {
|
||||
const bridge = (window as any).openswarm?.cdpRoutesGet as
|
||||
| ((id: number, origin?: string) => Promise<any[]>) | undefined;
|
||||
if (bridge) {
|
||||
let origin = '';
|
||||
try { origin = new URL(wv.getURL()).origin; } catch {}
|
||||
const routes = (await bridge(wv.getWebContentsId(), origin)) || [];
|
||||
routesAvailable = routes.filter((r) => r && r.safe).length;
|
||||
}
|
||||
} catch {}
|
||||
return { text: `Navigated to ${url}`, url, routes_available: routesAvailable };
|
||||
}
|
||||
|
||||
async function handleClick(wv: BrowserWebview, params: Record<string, any>): Promise<Record<string, any>> {
|
||||
|
||||
Reference in New Issue
Block a user