Skip to content

fix(vision): patch-based Anthropic image-token model + doc sync#27

Merged
teamchong merged 5 commits into
teamchong:mainfrom
rldyourmnd:fix/anthropic-vision-patch-model
Jul 18, 2026
Merged

fix(vision): patch-based Anthropic image-token model + doc sync#27
teamchong merged 5 commits into
teamchong:mainfrom
rldyourmnd:fix/anthropic-vision-patch-model

Conversation

@rldyourmnd

Copy link
Copy Markdown
Contributor

Fixes #26.

Grounds the Anthropic image-token cost on the current documented 28-px patch model and syncs the docs. Verified against Anthropic's primary docs (patch formula + tier table + reference count_image_tokens, reproduced exactly).

  • src/core/anthropic-vision.ts (new): patchTokens, anthropicVisionProfile(model), anthropicVisionTokens(model,w,h) with the documented long-edge + token-budget downscale (standard 1568/1568, high-res 2576/4784). Matches Anthropic's worked cost table (e.g. 1928² high-res → 4761; 1928² standard → 1521; 1568×728 → 1456).
  • gate (imageTokensForRows) now counts per-image 28-px patches; the 10% conservatism is renamed ANTHROPIC_GATE_MARGIN and kept ONLY at the gate — the documented formula carries no margin. pxpipe pages are ≤ 1568×728, so no tier downscale ever applies to proxy output and the net gate shift is ~4%.
  • export (exportImageTokens) routes claude models through anthropicVisionTokens (accurate, un-margined reporting).
  • DEFAULTS.cols 313 → 312 (1568 px == MAX_WIDTH_PX); fix shrinkColsToContent's stale "no-op" docstring and render.ts's stale page-cap header.
  • docs (README, RENDER_SIZING, TRANSFORM_INFO, legibility audit) synced to 1568×728 / 312-col / 28k-char geometry, 6000/6000 thresholds, and the patch billing model.
  • tests/anthropic-vision.test.ts covers the patch math, tiers, and downscale; export tests updated off the /750 numbers.

Full suite green (638 on this branch); typecheck + build green. (I also verified the whole PR set merges and stays green together — see the integration note.)

@rldyourmnd

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up making anthropicVisionTokens an exact translation of Anthropic's documented resize, not an approximation. The old continuous sqrt+decrement scale matched the common cost table but drifted on extreme aspect ratios (it scaled both edges by one factor and floored, instead of pinning the long edge and rounding the short one) — e.g. standard-tier 2510×7800 billed 1064, the code gave 1008. Now it uses fitsTier() + a binary search over the long edge (short edge = round(long × aspect), swap-recurse for portrait), and the tests cover the full official cost table on both tiers, the three extreme-aspect counterexamples, and a 400-case property check vs an independent reference. Also fixed two stale comments (~50k chars~28k; px/750 → the exact 28-px patch count). Only the general-purpose estimator changes; pxpipe pages are ≤1568×728 so the resize never fires for proxy output.

…cols

Anthropic no longer bills images by (width*height)/750; the current docs document
a 28-px PATCH model: ceil(w/28)*ceil(h/28) visual tokens, after downscaling to the
model tier's long-edge / token-budget limits (standard 1568/1568, high-res
2576/4784 for Fable 5 / Mythos 5 / Opus 4.8 / Opus 4.7 / Sonnet 5). /750 was a
~4-5% continuous approximation of that same 28^2 grid and ignored the downscale,
so it grossly overcharged large images.

- new src/core/anthropic-vision.ts: patchTokens(), anthropicVisionProfile(model),
  anthropicVisionTokens(model,w,h) with the exact documented downscale (matches
  Anthropic's reference count_image_tokens and its worked cost table)
- gate (imageTokensForRows) now counts per-image 28-px patches; the 10% safety
  bias is renamed ANTHROPIC_GATE_MARGIN and kept ONLY at the gate (the documented
  formula in anthropic-vision.ts carries no margin). pxpipe pages are <=1568x728
  so no tier downscale applies; net gate shift ~4%
- export (exportImageTokens) routes claude models through anthropicVisionTokens
  (accurate, un-margined reporting)
- remove ANTHROPIC_PIXELS_PER_TOKEN / IMAGE_COST_SAFETY_MARGIN (internal only)
- transform DEFAULTS.cols 313 -> 312 so the slab is 1568 px (== render.ts
  MAX_WIDTH_PX; 313 -> 1573 px overshot the cap)
- fix shrinkColsToContent's stale 'no-op / returns cols unchanged' docstring (it
  delegates to measureContentCols)
- tests/anthropic-vision.test.ts covers the patch math, tiers, and downscale;
  export tests updated from the /750 numbers to the patch model

Full suite green (638); typecheck + build green.
The docs described a superseded render/billing regime. Bring README,
RENDER_SIZING, TRANSFORM_INFO, and the legibility audit in line with the code
(render.ts constants) and Anthropic's current 28-px patch cost model:

- geometry: 1928×1928 / 384 cols / 1932-px height / ~92k chars-per-page →
  1568×728 / 312 cols / 728-px height / ~28k chars-per-page (render.ts today)
- shrinkColsToContent: 'no-op, returns cols unchanged' → it delegates to
  measureContentCols (shrink-to-content is active; RENDER_SIZING's core thesis
  and the 'why full width' section were inverted)
- thresholds: minReminderChars=1000 / minToolResultChars=2000 → 6000 / 6000
- billing: (w·h)/750 → ⌈w/28⌉×⌈h/28⌉ patch model + tiers; a 1568×728 page is
  56×26 = 1456 tokens; RENDER_SIZING's 'unresolved billing gap' section is
  resolved and removed
- legibility audit gets a dated note pointing px/750 → the exact patch count

Docs-only; no code touched in this commit. Relative links still resolve.
The render.ts header still claimed pages cap at ~1932×1932 px (the pre-clamp
regime). They cap at 1568×728 (1.14 MP) today — under both Anthropic tiers'
limits, billed at the raw 28-px patch count with no server-side downscale.
…ize reference

The downscale used a continuous sqrt seed + decrement loop, which matched
Anthropic's worked cost table but drifted on extreme aspect ratios (it scaled
both edges by one factor and floored, instead of pinning the long edge and
rounding the short one). E.g. standard-tier 2510×7800 billed 1064, not 1008.

- replace the approximation with a direct translation of the documented
  algorithm: fitsTier() (padded patch edges ≤ maxLongEdge AND patch count ≤
  budget) + resizedSize() (binary-search the long edge, short edge =
  round(long × aspect), swap-recurse for portrait). patchTokens() stays the raw
  no-resize counter.
- tests: the full official cost table on both tiers, the three extreme-aspect
  counterexamples (2510×7800→1064, 1194×4171→952, 2384×1625→1551), and a
  400-case deterministic property test vs an independent reference translation.
- fix stale comments: transform.ts slab '~50k chars' → '~28k chars/page at the
  1568×728 cap'; render.ts MAX_HEIGHT_PX + MAX_WIDTH_PX comments now describe the
  exact 28-px patch billing (px/750 kept only as the historical measured slope).

Only affects the general-purpose estimator (export/reporting); pxpipe pages are
≤1568×728 so the resize never fires for proxy output. Full suite green (639).
… (rebase integration)

Rebase-integration step: main refactored all vision-cost math into the unified
visionTokensForModel router (openai.ts) after this branch was opened, so the
patch model is wired in there instead of the old export.ts path. The Claude
branch of visionTokensForModel now calls anthropicVisionTokens; export reporting
and the GPT-history estimate inherit it. Drop the now-unused ANTHROPIC_PIXELS_PER_TOKEN
/ IMAGE_COST_SAFETY_MARGIN imports, refresh the stale w*h/750 doc comments, and
update the two tests that hardcoded the old formula (a full 1568x728 page is now
56x26 = 1456 tokens; claude-opus-4-8 768x1932 high-res = 28x69 = 1932). Also drop
the obsolete "Claude >5x GPT" export test — with the accurate patch model a full
page is ~equal to gpt-4o, which the adjacent not.toBe test already covers.
@teamchong
teamchong force-pushed the fix/anthropic-vision-patch-model branch from 3a99a1a to 0cf790d Compare July 18, 2026 23:50
@teamchong
teamchong merged commit 028f6a7 into teamchong:main Jul 18, 2026
1 check 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.

Anthropic vision cost uses the retired w×h/750 formula, not the documented 28-px patch count

2 participants