Repository navigation
fix(providers): custom OpenAI-compatible node models keep synced vision capability (#14081) - #14428
Merged
Merged
Conversation
…on capability (#14081) Vision Bridge gates on getResolvedModelCapabilities().supportsVision, whose resolveVisionCapability() never consulted the per-connection syncedAvailableModels row that already made /v1/models report capabilities.vision:true for a custom node's synced model. Add a positive-only syncedAvailableModelVision source (bulk-loaded in ModelCapabilityResolutionSnapshot, on-demand DB helper otherwise) so the guardrail agrees with the catalog it feeds instead of rerouting an image-capable model as text-only.
4 of 5 tasks
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 #14081
Root cause
A custom OpenAI-compatible node's synced model persists a per-connection
supportsVisionboolean on itssyncedAvailableModelsrow (detectVisionInputinsrc/lib/providerModels/modelDiscovery.ts)./v1/modelscorrectly reads that field throughbuildSyncedCapabilities(src/app/api/v1/models/syncedCapabilities.ts) and reportscapabilities.vision: true.The Vision Bridge guardrail (
src/lib/guardrails/visionBridge.ts) gates ongetResolvedModelCapabilities(model).supportsVision, whoseresolveVisionCapability()(src/lib/modelCapabilities.ts) had no code path back tosyncedAvailableModelsat all — confirmed byModelCapabilityResolutionSnapshot, which bulk-loads models.dev sync data and several override maps but never this per-connection table. The guardrail disagreed with the catalog it feeds and rerouted an image-capable custom-node model as text-only, causing the fallback model to 400 on the image request.Fix
Added a new positive-only vision source,
syncedAvailableModelVision(src/lib/db/models/syncedAvailableModelVision.ts):ModelCapabilityResolutionSnapshot(mirrorscustomVisionOverrides) so catalog/build-local generation stays one SQLite read instead of N+1 queries.getResolvedModelCapabilities()when no snapshot is supplied (the Vision Bridge guardrail's per-request path).resolveVisionCapability()as a new parameter, checked after theisKnownTextOnlyDespiteSynchard override (so the fix(sse): route image requests only to confirmed-vision combo targets #4071 safety net is never bypassed) and before the last-resort model-id heuristic.trueornull— neverfalse— so it can add vision capability but never downgrade another source's verdict.Regression test
tests/unit/vision-bridge-custom-node-modalities-14081.test.ts(2 cases):/v1/modelscatalog andgetResolvedModelCapabilitiesagree onvision:truefor a synced custom-node row (both the on-demand path and the snapshot-backed path).supportsVision:false, or no row at all, is never upgraded totrueby this source (fix(sse): route image requests only to confirmed-vision combo targets #4071 regression guard).RED on the unfixed code (verified via
git apply -Rof the fix, no branch switch):GREEN after the fix:
Gates run
node --import tsx/esm --test tests/unit/vision-bridge-custom-node-modalities-14081.test.ts→ 2/2 passnpm run typecheck:core→ exit 0npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files>→ exit 0node scripts/check/check-file-size.mjs→ no violations on touched filesnode scripts/check/check-complexity.mjs→ OK — 2904 violations (baseline 3218)node scripts/check/check-cognitive-complexity.mjs→ OK — 1316 violations (baseline 1437)node scripts/check/check-changelog-integrity.mjs→ OK.env.exampledrift +open-sse/executors/codex.tsfile-size drift) — not touched by this PR.Existing tests aligned
None — ran the full touched-area vision/capability suite (142 tests across
model-capability-resolution-snapshot-9199,model-capabilities-kimi-k3-vision-8250,model-capabilities-path-shaped-vision-8032,command-code-mimo-v2-5-safety,command-code-registry-vision,vision-bridge-cc-no-reroute,vision-bridge-custom-path-id-12758,guardrails/visionBridge*,combo-vision-aware-routing,combo-multimodal-capability-13847,fusion-vision-panel-3378,vision-compression-authoritative-capability-7237,api-models-hide-paid-6328, etc.) — all 142 passed unmodified, no #4071-class regression.Plan-file:
_tasks/pipeline/bugs/2-implementing/14081-fix-providers-custom-openai-compatible-node-models-lose-input-.plan.md