Skip to content

feat(page): print the eval-js value bare and use exception_detail for failures - #72

Merged
giordano-lucas merged 2 commits into
mainfrom
t3code/eval-js-output-and-exception-detail
Aug 25, 2026
Merged

feat(page): print the eval-js value bare and use exception_detail for failures#72
giordano-lucas merged 2 commits into
mainfrom
t3code/eval-js-output-and-exception-detail

Conversation

@giordano-lucas

Copy link
Copy Markdown
Member

Two changes to notte page, both about surfacing what actually happened.

1. eval-js output

Before, a successful eval printed two lines:

Successfully executed action: evaluate_js
Result:  Hacker News

so the value could not be piped without post-processing — and when the evaluated value was legitimately empty the Result: line was skipped entirely (it was gated on Markdown != ""), leaving only a success banner.

Now the value prints alone on stdout and the status line goes to stderr:

title=$(notte page eval-js "document.title")
notte page eval-js "JSON.stringify([...document.links].map(a => a.href))" | jq length

Interactive use is unchanged (stderr still shows in the terminal), and -o json still prints the full execution result. Help text documents the contract.

2. exception_detail across every page command

The API serializes a failure twice: exception is a bare string rendered in whatever ErrorConfig mode the server ran in — and the API runs set_error_mode("user"), so it is usually the generic "Sorry, this action cannot be executed at the moment." — while exception_detail (nottelabs/notte#907, already in the generated client) carries the concrete error type, the per-audience messages and the retry/notify flags.

A new shared executionFailureError helper prefers the structured field, so a failed action now reports e.g.

ActionExecutionError: Failed to execute action: evaluate_js on https://x. Reason: ReferenceError: foo is not defined

instead of the generic sentence. It falls back to the legacy exception string, then message, for API builds that predate the field. Wired into both failure sites: printExecuteResponse (used by click, fill, goto, scroll, press, wait, … — every page action) and eval-js.

Tests

internal/cmd/execution_failure_test.go: prefers structured detail over the generic string, falls back to user_message when dev_message is absent, legacy-string path, message-only path, and the nothing-to-go-on path. Full go test ./internal/... and go vet ./... pass.

🤖 Generated with Claude Code

… failures

eval-js printed "Successfully executed action: evaluate_js" followed by
"Result:  <value>", so the evaluated value could not be piped without
post-processing, and a legitimately empty value vanished entirely (the
Result line was skipped when markdown was empty). The value now prints
alone on stdout with the status line on stderr; -o json is unchanged.

Failures across every page command now prefer the structured
exception_detail (nottelabs/notte#907) over the legacy `exception`
string. That string is rendered in whatever ErrorConfig mode the server
ran in, which for the API is "user" - so a failed action reported
"Sorry, this action cannot be executed at the moment." instead of the
JavaScript error. The shared helper reports the concrete error type and
the developer message, falling back to the legacy string for API builds
that predate the field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown

Greptile Summary

The PR makes page eval-js emit only its evaluated value on stdout while moving status text to stderr, and centralizes failed page-action formatting around exception_detail.

  • Adds structured execution-failure fallback handling and focused unit coverage.
  • Applies the helper to generic page actions and eval-js.
  • Documents the new pipeline-oriented eval-js output contract.

Confidence Score: 4/5

The developer-message path should be sanitized before merging because failed page actions can otherwise print unbounded or control-bearing service text directly to the terminal.

The new action-level error helper bypasses the existing message sanitizer and is now reachable from both generic page actions and eval-js failures.

Files Needing Attention: internal/cmd/output_helpers.go, internal/cmd/page.go

Important Files Changed

Filename Overview
internal/cmd/output_helpers.go Adds shared structured failure formatting, but forwards DevMessage without the sanitization used by the established API error path.
internal/cmd/page.go Routes page failures through the new helper and separates eval-js result and status streams.
internal/cmd/execution_failure_test.go Covers structured-detail preference and fallback ordering, though it does not exercise output sanitization.

Fix all with Greploop Fix All in Claude Code

Prompt To Fix All With AI
### Issue 1
internal/cmd/output_helpers.go:240-254
**Developer errors bypass sanitization**

If `DevMessage` contains control characters or excessive text, `executionFailureError` forwards it as an ordinary error without the sanitization applied by the API error path, causing failed page actions to emit raw terminal sequences or unbounded output on stderr.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat(page): print the eval-js value bare..." | Re-trigger Greptile

Comment thread internal/cmd/output_helpers.go
Exercises the two shapes the docs promise - title=$(notte page eval-js
"document.title") capturing the value alone, and piping
JSON.stringify(...) output into a JSON parser - plus a JS null arriving
as "null" rather than empty, -o json still emitting the envelope, and a
failing script exiting non-zero with the actual JavaScript error instead
of the generic user-facing sentence.

The shared harness prepends `-o json`, so these use a text-mode runner:
the point is what a shell sees without --output json.

Note the filename: page_eval_js_test.go would end in _js, which Go reads
as the js/wasm GOOS suffix and silently excludes from every other
platform's build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@giordano-lucas
giordano-lucas merged commit aa1b09c into main Aug 25, 2026
3 checks passed
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