Skip to content

feat(bridge): normalize images to 2048px long edge before vision describe self-call - #10287

Merged
diegosouzapw merged 7 commits into
release/v3.8.50from
feat/bridge-image-normalize
Aug 14, 2026
Merged

feat(bridge): normalize images to 2048px long edge before vision describe self-call#10287
diegosouzapw merged 7 commits into
release/v3.8.50from
feat/bridge-image-normalize

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

PR-B of the OCR/image-to-text migration series (plan: _tasks/superpowers/plans/2026-08-13-ocr-image-to-text-migration.md; pattern migrated from freellmapi's image-normalize.ts).

  • open-sse/utils/imageNormalize.ts (new): normalizeImageBuffer / normalizeDataUri — downscale images to a 2048px long edge before they are sent to the vision model. sharp is loaded via dynamic import with a null fallback: if the native binary is unavailable, everything passes through untouched and nothing ever throws (normalizeDataUri is contractually no-throw). No package.json change — sharp ^0.35.3 is already a regular dependency.
  • Integration at the Vision Bridge's single self-fetch chokepoint (fetchRemoteImageAsDataUri in visionBridgeHelpers.ts): every bridge-initiated remote image fetch is normalized before the describe/reroute self-call. User-inline data URIs never enter this path — passthrough payloads are untouched (verified in review: resolveImageAsDataUri and ensureBase64ImagesForClaudeWire short-circuit data: URIs before the fetch helper).
  • Rationale (documented in docs/security/GUARDRAILS.md): OpenAI/Anthropic downscale to ~2048 long edge server-side anyway; sending smaller images cuts tokens and latency with no quality loss for description.

Validation (TDD)

  • New: image-normalize 4/4 (incl. width- and height-dominant resize with real post-resize dimension asserts and garbage-bytes passthrough) · vision-bridge-image-normalize 2/2 (decodes the actual payload sent through the fetch DI spy and asserts ≤2048).
  • Canaries all green: guardrails/visionBridge 29/29, repro-8430 3/3, preserve-on-failure-4012 2/2, vision-bridge-mode 4/4, task-aware 5/5, describe-cache 3/3, cc-no-reroute 8/8, env-override 15/15, settings-schema 2/2.
  • vision-bridge-policy-reroute-6640: red on the loaded devbox and identically red on the pristine base via temp revert — the failure is the [resourcePressure] cgroup_ratio 503 guard tripping under load, unrelated to this diff (controller re-verified in isolation). CI runners will exercise it uncontended.
  • typecheck:core 0 · prettier/eslint clean · check:docs-all 0.

⚠️ base-red inherited: #9985 (ESLint errors from #10240/#9448 — unrelated to this diff)

Route the bridge's own fetchRemoteImageAsDataUri() output through
normalizeDataUri() (long-edge cap 2048) before handing it to the vision
model — matches the resize cap OpenAI/Anthropic already apply, cutting
upload bytes/latency. Scoped to the bridge's self-fetched images only,
never the user's raw passthrough payload (HR#20 opt-in principle).
Add a 100x4096 PNG case to image-normalize.test.ts alongside the existing
width-dominant one, so normalizeImageBuffer's long-edge cap is proven on
both axes.
@diegosouzapw
diegosouzapw merged commit f1673f6 into release/v3.8.50 Aug 14, 2026
22 checks passed
@diegosouzapw
diegosouzapw deleted the feat/bridge-image-normalize branch August 14, 2026 16:06
@diegosouzapw diegosouzapw mentioned this pull request Aug 15, 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.

2 participants