Repository navigation
fix(sse): feed compression pipeline the authoritative vision capability (#7237) - #7560
Merged
Merged
Conversation
…ty (#7237) chatCore.ts fed applyCompressionAsync's supportsVision option from isVisionModelId() — the deliberately-conservative model-id fragment heuristic in src/shared/constants/visionModels.ts — instead of the authoritative getResolvedModelCapabilities().supportsVision used by every other vision-aware path (e.g. the vision-bridge guardrail). gpt-5.5 is registered with supportsVision:true in modelSpecs.ts, but the fragment list has no gpt-5.x entry, so the heuristic wrongly returned false. That false reached lite.ts's replaceImageUrls(), whose gate is `supportsVision !== false`, silently stripping every image_url block before the request ever reached the executor. getResolvedModelCapabilities().supportsVision resolves to null (not false) for genuinely unknown models, which the same !== false gate already treats as preserve-by-default — matching the conservative semantics used elsewhere and avoiding the #4071/#4012 class of bug (blinding a model that can actually see).
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
…ty (cheaper-inference#7237) (cheaper-inference#7560) chatCore.ts fed applyCompressionAsync's supportsVision option from isVisionModelId() — the deliberately-conservative model-id fragment heuristic in src/shared/constants/visionModels.ts — instead of the authoritative getResolvedModelCapabilities().supportsVision used by every other vision-aware path (e.g. the vision-bridge guardrail). gpt-5.5 is registered with supportsVision:true in modelSpecs.ts, but the fragment list has no gpt-5.x entry, so the heuristic wrongly returned false. That false reached lite.ts's replaceImageUrls(), whose gate is `supportsVision !== false`, silently stripping every image_url block before the request ever reached the executor. getResolvedModelCapabilities().supportsVision resolves to null (not false) for genuinely unknown models, which the same !== false gate already treats as preserve-by-default — matching the conservative semantics used elsewhere and avoiding the cheaper-inference#4071/cheaper-inference#4012 class of bug (blinding a model that can actually see).
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…ty (cheaper-inference#7237) (cheaper-inference#7560) chatCore.ts fed applyCompressionAsync's supportsVision option from isVisionModelId() — the deliberately-conservative model-id fragment heuristic in src/shared/constants/visionModels.ts — instead of the authoritative getResolvedModelCapabilities().supportsVision used by every other vision-aware path (e.g. the vision-bridge guardrail). gpt-5.5 is registered with supportsVision:true in modelSpecs.ts, but the fragment list has no gpt-5.x entry, so the heuristic wrongly returned false. That false reached lite.ts's replaceImageUrls(), whose gate is `supportsVision !== false`, silently stripping every image_url block before the request ever reached the executor. getResolvedModelCapabilities().supportsVision resolves to null (not false) for genuinely unknown models, which the same !== false gate already treats as preserve-by-default — matching the conservative semantics used elsewhere and avoiding the cheaper-inference#4071/cheaper-inference#4012 class of bug (blinding a model that can actually see).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #7237
Root cause
open-sse/handlers/chatCore.ts:1330fed thesupportsVisionflag intoapplyCompressionAsyncfromisVisionModelId(effectiveModel)— thedeliberately-conservative model-id fragment heuristic in
src/shared/constants/visionModels.ts(its own docstring says to keep itconservative: newly-released vision models get zero-touch support via the
models.dev sync, not this fallback) — instead of the authoritative
getResolvedModelCapabilities().supportsVisionthat every othervision-aware path (notably the vision-bridge guardrail) uses.
gpt-5.5is registered withsupportsVision: trueinsrc/shared/constants/modelSpecs.ts, but the fragment list has nogpt-5.x entry, so the heuristic wrongly returned
false. That spuriousfalsereachedopen-sse/services/compression/lite.ts::replaceImageUrls(),whose gate is
supportsVision !== false— it only strips images when toldexplicitly
false— so everyimage_urlblock was silently replaced witha
[image: png]text placeholder before the request ever reachedAgentRouter/Freemodel.dev (or any other openai-compat passthrough
provider).
This also explains the three symptoms in the report: it reproduces even
though the model is marked
vision: true; disabling Vision Bridge changesnothing (separate code path — lite compression runs earlier); and
"updating model capabilities" in the UI never helped because
modelCapabilityOverrides.tsonly supports amax_tokenoverride, thereis no vision override to set.
Fix
Swap the heuristic for the authoritative capability at the single call
site:
getResolvedModelCapabilities().supportsVisionisboolean | nullandfalls back to the same conservative heuristic internally only when no
spec/registry/sync data exists — so genuinely unknown models resolve to
null, whichlite.ts's!== falsegate already treats aspreserve-by-default. This avoids re-introducing the #4071/#4012 class of
bug (blinding a model that can actually see).
Regression test
tests/unit/vision-compression-authoritative-capability-7237.test.ts—4 assertions:
isVisionModelId('gpt-5.5') === falsewhile theauthoritative spec says
supportsVision: truereplaceImageUrlspreserves the image when fed the authoritativecapability (the fixed behavior)
strips the image)
applyCompressionAsync(..., 'lite', ...)withmodel: 'gpt-5.5'— the image_url block and its original data URLsurvive intact
RED→GREEN: reproduced the pre-fix behavior standalone (feeding
isVisionModelId('gpt-5.5')—false— intoapplyCompressionAsync)and confirmed the placeholder strip:
[{ "type": "text", "text": "[image: png]" }]Post-fix, the same flow (feeding
getResolvedModelCapabilities(...).supportsVision)preserves the image_url block unchanged — verified both via the
standalone repro and the 4/4 passing regression test.
Gates run (all green)
node scripts/check/check-file-size.mjs— OK (no frozen file grew)node scripts/check/check-complexity.mjs— OK (2054 ≤ baseline 2056)node scripts/check/check-cognitive-complexity.mjs— OK (889 ≤ baseline 890)npm run typecheck:core— clean (chatCore.ts is outside the typecheck:coreallowlist, so also sanity-compiled it against the full
tsconfig.json;the pre-existing strict-mode errors it reports are all in unrelated
regions of the file, none touching the changed import or the compression
call site)
npx eslint --suppressions-location config/quality/eslint-suppressions.json open-sse/handlers/chatCore.ts tests/unit/vision-compression-authoritative-capability-7237.test.ts— cleantests/unit/compression/lite.test.ts,tests/unit/vision-detection-consistency.test.ts,tests/unit/guardrails/visionBridge.test.ts,tests/unit/combo-vision-aware-routing.test.ts,tests/unit/model-capabilities-mimo-vision-override.test.ts,tests/unit/model-capabilities-mistral-vision-sync-4073.test.ts,tests/unit/llm-selector-custom-vision-models.test.ts,tests/unit/command-code-vision.test.ts,tests/unit/vision-compression-authoritative-capability-7237.test.tstests/unit/chatcore-compression-usage-receipt.test.ts,tests/unit/chatcore-translation-paths.test.ts,tests/unit/chatcore-compression-settings.test.ts,tests/unit/chatcore-compression-combo-predicates.test.ts,tests/unit/chatcore-compression-integration.test.ts,tests/unit/chatcore-compression-analytics-write.test.ts,tests/unit/chatcore-caveman-output-analytics.test.ts,tests/unit/chatcore-compression-cache-stats.test.tsNot confirmed by this mechanism
Per the analysis plan-file,
claude-opus-4-6/4-7/4-8ids match theexisting
claude-opus-4fragment, so this specific mechanism should notaffect them. If the reporter's Claude cases are also broken, that would
be a second, separate cause worth tracking in a follow-up.