Skip to content

fix(vision): apply proactive embed cap to browser_vision screenshots - #47468

Open
Stromweld wants to merge 2 commits into
NousResearch:mainfrom
Stromweld:fix/browser-vision-embed-cap
Open

fix(vision): apply proactive embed cap to browser_vision screenshots#47468
Stromweld wants to merge 2 commits into
NousResearch:mainfrom
Stromweld:fix/browser-vision-embed-cap

Conversation

@Stromweld

Copy link
Copy Markdown

Summary

Fixes #47467browser_vision now applies the same proactive embed cap that vision_analyze uses before embedding screenshots into conversation history.

Problem

browser_vision takes full-page screenshots (--full) that routinely exceed 7900px on long web pages (docs, PRs, Confluence). Without the proactive resize check, these oversized images get baked into immutable conversation history and trigger non-retryable 400 errors from providers (Anthropic 8000px limit, Copilot similar), permanently bricking the session.

The vision_analyze tool already has this protection (lines 758-766 of vision_tools.py), but browser_vision in browser_tool.py was bypassing it entirely.

Changes

  • Import _resize_image_for_vision, _image_exceeds_dimension, _EMBED_TARGET_BYTES, and _EMBED_MAX_DIMENSION from vision_tools
  • Apply proactive embed cap check after base64 encoding but before passing to _build_native_vision_tool_result
  • Log when auto-resize triggers (bytes_over / dims_over) for debugging
  • The resized data_url is shared between the native fast path AND the auxiliary vision LLM path, so both are protected

Testing

Verified against the actual problematic screenshot (1280×14567 px, 2.12 MB):

  • _image_exceeds_dimension() correctly detects it as over the 7900px cap
  • _resize_image_for_vision() successfully downsizes it
  • All imports resolve cleanly

Note

This PR was created with AI assistance (Hermes Agent v0.16.0, Claude Opus 4.6).

browser_vision takes full-page screenshots (--full) that can easily
exceed provider dimension limits (8000px per side) on long web pages.
Unlike vision_analyze which applies the proactive embed cap (_EMBED_TARGET_BYTES
/ _EMBED_MAX_DIMENSION) before embedding images into conversation history,
browser_vision was passing raw full-resolution base64 directly to
_build_native_vision_tool_result.

Once an oversized image is baked into immutable conversation history, it
triggers non-retryable 400 errors from the provider on every subsequent
turn, permanently bricking the session (retries cannot clear bytes/pixels
that are already in the request history).

This patch imports and applies the same proactive resize checks that
vision_tools._vision_analyze_native uses:
- Check if base64 > _EMBED_TARGET_BYTES (4 MB)
- Check if longest dimension > _EMBED_MAX_DIMENSION (7900px)
- Auto-resize with Pillow before embedding if either limit is exceeded

The resize applies to both the native fast path and the auxiliary vision
LLM path since they share the data_url variable.

Reproducer: use browser_vision on any page taller than ~8000px (most
documentation pages, GitHub PRs, Confluence pages). The resulting
full-page PNG will be 10,000-15,000+ pixels tall, pass the byte check
but fail the dimension check, and brick the session on the next turn.

Signed-off-by: Corey Hemminger <hemminger@hotmail.com>
@alt-glitch alt-glitch added type/bug Something isn't working comp/tools Tool registry, model_tools, toolsets tool/browser Browser automation (CDP, Playwright) tool/vision Vision analysis and image generation P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jun 16, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #39226 — same fix: apply the proactive embed cap (_EMBED_MAX_DIMENSION / _image_exceeds_dimension) to browser_vision screenshots before embedding into conversation history. #39226 (open, 2026-06-04) is the canonical fix-PR; #44922 is also a duplicate of it. Related: dimension-clamp PR #25838 and the originating issue #47467. The proactive cap is still absent on main (only the reactive resize-on-400 path exists in tools/browser_tool.py), so the underlying bug remains live.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for isolating the native browser_vision gap. Current main still sends the raw full-page screenshot into the native tool-result envelope (tools/browser_tool.py:4021,4060-4080), while vision_analyze applies the shared cap (tools/vision_tools.py:1018-1028).

Problems

  • The new resize call at PR tools/browser_tool.py:3259 is not a guaranteed cap: _resize_image_for_vision returns its last candidate after five unsuccessful attempts (tools/vision_tools.py:737-742), and the PR immediately attaches that result at lines 3269-3274. A candidate still exceeding the byte or pixel cap can therefore enter immutable history.
  • No regression test is included. Existing native browser coverage only verifies that an image part is returned (tests/tools/test_browser_console.py:403-440).

Suggested changes

  • Validate both post-resize byte size and decoded dimensions before native attachment; return a tool error if either constraint remains unmet.
  • Add native-path regressions for tall low-byte and byte-heavy screenshots that inspect the emitted data URL.

Automated hermes-sweeper review.

Comment thread tools/browser_tool.py
"(bytes_over=%s, dims_over=%s), auto-resizing...",
_over_bytes, _over_dims,
)
data_url = _resize_image_for_vision(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_resize_image_for_vision returns its final candidate after five attempts even if it still fails the requested byte or pixel constraints (tools/vision_tools.py:737-742). Validate the returned data URL's byte size and decoded dimensions before the native envelope at line 3270, and return a tool error if it is still over either cap.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new commit should have suggested changes

@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Jul 14, 2026
…achment

Per review #4696844968: _resize_image_for_vision returns its best attempt
after 5 rounds even when constraints aren't met. Validate byte size and
decoded pixel dimensions before passing data_url to the native envelope.
Return tool_error if either cap is still exceeded to prevent baking an
oversized embed into immutable history.

Also add 3 regression tests for the native path:
- tall low-byte screenshot → resize triggers, native path succeeds
- byte-heavy screenshot → resize triggers, native path succeeds
- resize failure (5-attempt exhaustion) → tool_error returned

Note: Pillow imports inside browser_vision are lazy so patches target
tools.vision_tools.* not tools.browser_tool.*

AI assistance: Hermes Agent v0.16.0, claude-sonnet-4.6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users tool/browser Browser automation (CDP, Playwright) tool/vision Vision analysis and image generation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

browser_vision skips proactive embed cap — oversized full-page screenshots brick sessions

3 participants