[eric] browser: prune abandoned-navigate detours at distill so recorded skills and route hints stay clean

This commit is contained in:
ciregenz
2026-06-06 04:49:19 -07:00
parent cdbdec775b
commit 4e320033ad
2 changed files with 49 additions and 1 deletions
+17 -1
View File
@@ -309,7 +309,23 @@ def distill_steps(action_log: list[dict]) -> list[dict]:
productive_count += 1
if productive_count == 0:
return []
return steps
return _prune_detours(steps)
def _prune_detours(steps: list[dict]) -> list[dict]:
"""Drop an abandoned-page detour: a BrowserNavigate whose page was never
acted on because the very next step navigates somewhere else. Conservative
on purpose, only consecutive navigates qualify (if a page had been used,
a Type/Click/etc would sit between them), so a needed step is never removed.
This keeps a wrong-turn (e.g. the wrong profile, then the right one) out of
a recorded macro without any reachability guesswork."""
out: list[dict] = []
for i, s in enumerate(steps):
nxt = steps[i + 1] if i + 1 < len(steps) else None
if s.get("tool") == "BrowserNavigate" and nxt is not None and nxt.get("tool") == "BrowserNavigate":
continue # this navigate's page was abandoned immediately; skip it
out.append(s)
return out
def first_unsafe_step(steps: list[dict]) -> tuple[int, str]:
+32
View File
@@ -665,3 +665,35 @@ def test_route_hint_adoption_matching(_isolated_skills):
# the Message and Send clicks did not run
assert adopted[0] and adopted[1] and adopted[3]
assert not adopted[2] and not adopted[4]
# --- conservative detour pruning ---------------------------------------------
def test_distill_prunes_abandoned_navigate_detour():
# wrong profile opened (navigate), abandoned for a search (navigate), then
# the right profile + the real productive steps. The first navigate is a
# detour: nothing acted on its page before the next navigate.
log = [
{"tool": "BrowserNavigate", "input": {"url": "https://x.com/in/wrong"}, "ok": True},
{"tool": "BrowserNavigate", "input": {"url": "https://x.com/search?q=tyler"}, "ok": True},
{"tool": "BrowserClickIndex", "input": {"index": 1}, "ok": True,
"clicked_role": "link", "clicked_name": "Tyler Chen"},
{"tool": "BrowserType", "input": {"selector": "#msg", "text": "hi"}, "ok": True},
]
steps = sk.distill_steps(log)
urls = [s["params"].get("url") for s in steps if s["tool"] == "BrowserNavigate"]
assert urls == ["https://x.com/search?q=tyler"] # the abandoned wrong nav dropped
assert [s["tool"] for s in steps] == ["BrowserNavigate", "BrowserClickByName", "BrowserType"]
def test_distill_keeps_navigate_that_was_acted_on():
# a navigate followed by a real action on that page is NOT a detour.
log = [
{"tool": "BrowserNavigate", "input": {"url": "https://x.com/form"}, "ok": True},
{"tool": "BrowserType", "input": {"selector": "#q", "text": "hi"}, "ok": True},
{"tool": "BrowserNavigate", "input": {"url": "https://x.com/results"}, "ok": True},
{"tool": "BrowserClickIndex", "input": {"index": 2}, "ok": True,
"clicked_role": "button", "clicked_name": "Go"},
]
steps = sk.distill_steps(log)
urls = [s["params"].get("url") for s in steps if s["tool"] == "BrowserNavigate"]
assert urls == ["https://x.com/form", "https://x.com/results"] # both kept