Skip to content

Navigator: capture rejection signal + give the AI a stop() tool#39

Open
DavertMik wants to merge 4 commits into
mainfrom
feat/navigate-cli-command
Open

Navigator: capture rejection signal + give the AI a stop() tool#39
DavertMik wants to merge 4 commits into
mainfrom
feat/navigate-cli-command

Conversation

@DavertMik
Copy link
Copy Markdown
Contributor

@DavertMik DavertMik commented May 24, 2026

Summary

Two Navigator improvements that together fix the failure mode where Navigator burns 9 retry attempts on a form that is actually being rejected by the server, not by a bad locator.

Commit 1 — Feed back why the URL didn't change

When a click runs cleanly but the URL doesn't change to the expected target, Navigator now:

  • Diffs the post-click state against the pre-click state and extracts any new alert / alertdialog / status ARIA messages.
  • Includes both the alert text and the ARIA diff in the next retry prompt.

Reuses the existing ActionResult.diff infrastructure. Adds one helper extractAlerts(snapshot) to src/utils/aria.ts.

Commit 2 — Give Navigator a stop(reason) tool + fix the prompt contradiction

Even with the rejection signal fed back, Navigator was still stuck: the retry prompt told the model both "this is NOT a locator issue" AND "propose new solutions" in the same turn, and the model had no tool to opt out.

This commit:

  • Replaces tools = undefined in resolveState with a single stop(reason) tool the AI can call when no locator change can help (wrong credentials, missing knowledge, captcha, blocking error). Mirrors Tester's existing stop tool pattern at tester.ts:938.
  • Branches the retry prompt: app-side rejection → call stop() or correct the submitted data (two clear choices, no locator changes); click didn't register → propose new locator strategies (old behaviour).
  • When stop() is called, the reason is logged at error level and surfaced in the existing interactive failure prompt so the user knows what to fix.

No control-flow rewrite — the model can still emit code blocks in text; the tool is an optional escape.

Test plan

  • bun run format / bun run lint:fix clean
  • No new type errors in edited files
  • extractAlerts smoke-tested across 7 snapshot shapes (named, YAML-colon, container-with-text, status, alertdialog, nested, empty)
  • ./bin/explorbot-cli.ts navigate / against the demo app: happy path still succeeds on first attempt in ~10s with ARIA locators
  • Manual: temporarily put bad credentials in your .env, run explorbot navigate /, expect Navigator to call stop() after seeing the rejection alert (instead of looping 9 times). I couldn't run this end-to-end in CI because explorbot's loadEnv overwrites command-line env vars, and the demo's experience file caches the correct credentials. Easy to verify locally.

🤖 Generated with Claude Code

DavertMik and others added 4 commits May 24, 2026 00:50
Exposes the AI Navigator as a one-shot CLI command. Exits 0 when the
target URL is reached and 1 otherwise, so it can be used as a
reachability probe in CI. Inherits --session and all common options,
making it the canonical way to capture an authenticated session for
downstream agents in a single command.

Also restructures docs/commands.md to treat CLI as a first-class
surface alongside TUI: a comprehensive reference table, per-command
sections showing both invocations side by side, and coverage of the
previously-undocumented CLI-only commands.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a click succeeds but the URL stays put, Navigator now diffs the
page and extracts any new alert/status/alertdialog messages, then
includes them (plus the ARIA changes) in the next retry prompt. This
breaks the loop where Navigator would re-fire 9 syntactic locator
variants against a form that was actually being rejected by the
server. The retry prompt now tells the model to re-examine credentials
or input data before changing locators when the page reacted.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Navigator's resolveState loop was passing tools=undefined to the AI,
so the model had no way to signal "this is hopeless, the page is
rejecting the submit." Combined with a retry prompt that, on
app-rejection, told the model both "do not change the locator" AND
"propose new solutions" in the same turn — the model spent its full
retry budget mutating locators that were already correct.

This adds a stop(reason) tool the AI can call when no locator change
will help (wrong credentials, missing knowledge, captcha, blocking
error). When called, the reason is logged at error level and surfaced
in the existing interactive failure prompt so the user knows what to
fix.

The retry prompt is restructured so the two paths are mutually
exclusive:
- if the page reacted (alerts / ARIA changes): two clear choices —
  call stop(reason), or correct the submitted data using known
  knowledge. Do not change the locator.
- if the page did not react: propose new locator strategies (the old
  behaviour).

No control-flow rewrite — the model can still emit code blocks in
text; the tool is an optional escape valve, mirroring how Tester uses
its stop() tool at tester.ts:938.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@DavertMik DavertMik changed the title Add navigate CLI command + feed back why URL didn't change Navigator: capture rejection signal + give the AI a stop() tool May 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant