fix(ollama): route models by advertised capability - #11088
Merged
diegosouzapw merged 2880 commits intoAug 23, 2026
Merged
Conversation
) (diegosouzapw#10363) Obrigado — feature real e bem verificada: POST /v1/images/edits rejeitava o provider built-in openrouter mesmo ele suportando edição por imagem de referência via sua Image API unificada. Traduz a imagem de entrada para o formato input_references documentado do OpenRouter e despacha para /api/v1/images, removendo o prefixo do provider do model id antes de encaminhar. Nota: o contribuidor não conseguiu rodar o teste localmente (better-sqlite3 ausente no ambiente dele) — rodei aqui. Validação (worktree própria a partir de origin/release/v3.8.50, merge limpo, 0 conflitos): - typecheck:core limpo, complexity/cognitive-complexity dentro do baseline - tests/unit/10197-openrouter-image-edits-route.test.ts — 3/3 passando (forward bem-sucedido, credenciais ausentes 401, rate-limit)
Merged — clean extraction from diegosouzapw#10358's genuinely new content (see PR body for the rationale: an unrelated .planning/codebase/ scaffolding dump was dropped). typecheck/file-size/changelog/provider-consistency gates clean, 18/18 tests passing.
…iegosouzapw#10900) Merged — reimplementation extracting the non-conflicting Recent Requests panel + excludeTests allowlist fix from diegosouzapw#8450 (see PR body for the full scoping rationale, including why the topology UX rework was deliberately excluded — it contradicts the already-shipped diegosouzapw#8428). typecheck/file-size/changelog/complexity/cognitive-complexity/i18n-coverage gates all clean, 2/2 unit + 1/1 vitest passing.
…pw#10904) Merged — extraction of the one still-uncovered fix from diegosouzapw#8634 (the other two items — mode "search"→CONCISE downgrade, pplx-opus generation — were already applied on this release tip). typecheck/file-size/changelog/complexity/cognitive-complexity gates all clean, 32/32 tests passing.
…dispatcher-timeout-10214 fix(network): bound direct-path response-start timeout and retry on fresh socket (diegosouzapw#10214)
Obrigado — bug real: GET /v1/files aceitava limit negativo sem validação (`-5 || 20` avalia truthy em -5, então Math.min(-5, 10000) = -5 passava direto). Agora valida integer/positivo/tamanho e retorna 400 estruturado para valores inválidos, preservando o default 20 e o máximo 10.000. Validação (worktree combinado a partir de origin/release/v3.8.50, 0 conflitos): - typecheck:core limpo, complexity/cognitive-complexity dentro do baseline - tests/integration/files-api-limit-validation.test.ts — 5/5 passando - tests/integration/files-api.test.ts — 12/12 passando (sem regressão) - tests/unit/batch_api.test.ts teve 1 falha, confirmada DRIFT pré-existente idêntica no tip puro do release (não relacionada, timing de cancelamento de batch)
…eToGeminiRequest (diegosouzapw#10658) Obrigado — bug real: a tradução direta claudeToGeminiRequest emitia mensagens consecutivas do mesmo role em contents[], o que a API do Gemini rejeita com HTTP 400 (turnos alternados user/model são obrigatórios). Traz claudeToGeminiRequest à paridade com openaiToGeminiRequest reutilizando mergeConsecutiveSameRoleContents. Validação (worktree combinado a partir de origin/release/v3.8.50, merge limpo, 0 conflitos): - typecheck:core limpo, complexity/cognitive-complexity dentro do baseline - tests/unit/claude-to-gemini-consecutive-roles.test.ts — 7/7 passando - tests/unit/claude-to-gemini-budget-tokens-zero-6813.test.ts — 2/2 passando (sem regressão)
…ols (diegosouzapw#10668) Obrigado — PR muito bem documentado e verificado. Adiciona o gateway TabiToken (Anthropic-first, /v1/messages, x-api-key) e estende hcnsec de 1 para 4 protocolos (Chat, Responses, Anthropic Messages, Gemini). AlternateFormat ganha o hook urlBuilder opcional (necessário para o path model-scoped do Gemini), compartilhado com o provider gemini nativo em vez de duplicado. Reconciliado nesta sessão contra o release tip atualizado (base drift real: 343→345 canônicos entre quando o PR foi criado e o merge, mais os PRs diegosouzapw#10673/diegosouzapw#10658 mergeados nesse meio-tempo). Conflitos em contagens de providers (docs, file-size baseline, teste de partição) resolvidos additivamente. Validação (reconciliação a partir de origin/release/v3.8.50): - typecheck:core limpo, complexity/cognitive-complexity dentro do baseline - npm run check:provider-consistency — OK (266 REGISTRY entries, 346 providers canônicos, 0 exceções) - 40/40 testes passando (newapi-gateway-providers, hcnsec-provider, providers-constants-split, alternate-formats)
…ngEfforts (diegosouzapw#10788) glm-5.1, glm-5.2, deepseek-v4-pro and deepseek-v4-flash declared supportsReasoning:true but no supportedThinkingEfforts, so the catalog's appendSyncedEffortVariants() pass (which only synthesizes -low/-high/-max ids from an already-populated capabilities.effort_tiers) never exposed a selectable effort tier for them, unlike gpt-oss:20b/120b. Add the documented low/medium/high/max vocabulary (see supportsMaxEffortForProvider's isOllamaCloud comment in reasoningEffort.ts).
…00 (diegosouzapw#10849) v1SearchSchema.provider was a hard-coded z.enum that rejected any id outside its list before the route's own resolveSearchProvider() check ever ran, so unknown/short-alias provider ids (grok, brave, serper, ...) always surfaced a generic "Invalid request" instead of the informative "Unknown search provider: <id>" message. Relax the schema to a free-form string and let resolveSearchProvider() own runtime validation (as it already did for ids that passed the enum). Also extend SEARCH_PROVIDER_ALIASES with short-form aliases mirroring the existing jina/jina-ai pattern (brave, serper, perplexity, exa, tavily, google-pse, linkup, ollama, searchapi, youcom, searxng, zai, duckduckgo), and surface the first Zod validation issue's field name instead of the generic message for other still-invalid fields (e.g. search_type).
…apshot (diegosouzapw#10156) Live SSE frames for a phase:"commentary" message were already dropped per diegosouzapw#6199, but the terminal response.completed.response.output array was forwarded verbatim whenever the upstream echoed the same item back non-empty, since backfillResponsesCompletedOutput only fills an empty array. Reuse the existing isResponsesCommentaryMessageItem predicate to filter the terminal snapshot's output array (and, defensively, the backfill buffer it can be seeded from) so both representations agree. Regression test added to tests/unit/responses-commentary-passthrough-6199.test.ts reproducing the exact upstream shape from the issue.
…igravity-multiaccount-quota fix(domain): treat unreported Antigravity quota fraction as unknown, not exhausted (diegosouzapw#10095)
…ponses-commentary-sse fix(sse): strip commentary items from Responses response.completed snapshot (diegosouzapw#10156)
…yground-endpoint-selector fix: route Playground ChatTab Send to the selected endpoint (diegosouzapw#10592)
…bo-log-error-body fix: log upstream error body in COMBO per-target failure warnings (diegosouzapw#10597)
…-unconditional-stats fix: skip expensive RTK compression stats computation on no-op runs (diegosouzapw#10765)
…ncode-effort-tiers fix(open-sse): declare Ollama Cloud reasoning models' supportedThinkingEfforts (diegosouzapw#10788)
…o-oauth-dedup fix(db): disambiguate Kiro OAuth dedup by profileArn (diegosouzapw#10815)
…ge-scan-cookie-bridge fix(config): exclude cookie-auth image bridges from unprefixed model scan (diegosouzapw#10848)
…rch-provider-400 fix(api): POST /v1/search names unknown providers instead of opaque 400 (diegosouzapw#10849)
…ta-alias-lookup fix(sse): canonicalize alias provider ids before quota fetcher lookup (diegosouzapw#10877)
…iegosouzapw#10650) Obrigado — bug real: MUSIC_PROVIDERS.minimax declara format "minimax-music" e seus modelos são publicados pelo catálogo, mas handleMusicGeneration nunca teve um branch para esse format — todo request minimax/* caía no guard final com "Unsupported music format", modelos anunciados mas inalcançáveis. Handler completo cobrindo os dois output formats (url/hex), envelope base_resp, endpoint regional, e guarda local de credencial ausente. Validação (worktree própria a partir de origin/release/v3.8.50, merge limpo, 0 conflitos): - typecheck:core limpo, complexity/cognitive-complexity dentro do baseline - tests/unit/minimax-music-generation.test.ts — 9/9 passando
…fjs (diegosouzapw#10610) Implements diegosouzapw#10536: upgrade @atjsh/llmlingua-2 2.0.3 → 2.0.5 and drop @tensorflow/tfjs from the LLMLingua SLM optional stack. Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts, 20 files): - 48/48 focused llmlingua/colocate/docker unit tests pass (author-reported, reproduced). - check-file-size, check-changelog-integrity: OK. - grep confirms no remaining source imports of @tensorflow/tfjs. - typecheck:core: clean. - check-complexity / check-cognitive-complexity: OK, both under baseline. Co-authored-by: jonlwheat2-gif <jonlwheat2-gif@users.noreply.github.com>
…as resolver (diegosouzapw#11107) Validated on the combined batch board over tip 8a42aee: static gates clean (changelog, file-size 159 frozen, complexity 2621<=2774, cognitive 1181<=1223, dead-code 408<=416), typecheck:core clean, 107 focused tests green. Combo precedence preserved when a requested name matches an existing combo or combo/* prefix, and hidden/disabled models are skipped during alias resolution (wildcard + mapped). model-alias-seed-fallback green. Related to diegosouzapw#10124. Thank you @SCys!
…configured (diegosouzapw#11097) Validated on the combined batch board over tip 8a42aee: static gates clean (changelog, file-size 159 frozen, complexity 2621<=2774, cognitive 1181<=1223, dead-code 408<=416), typecheck:core clean, 107 focused tests green. Zero-credential /v1/search now actually reaches the fallback-only providers (duckduckgo-free/searxng) instead of erroring before the last-resort block could run — the dead-code path is live. Also carries a one-line suppressHydrationWarning on the logo. Thank you @Egorich-print!
Validated on the combined batch board over tip 0b41259: static gates clean (changelog, file-size 160 frozen, complexity 2628<=2774, cognitive 1187<=1223, dead-code 408<=416, docs-counts green at 351 providers, provider-consistency 268/351/0), typecheck:core clean, 430+ focused tests green across 5 groups. Comment-only correction verified against the vendor page wording: DeepSeek peak windows are Monday-Friday (35h/week), prices unchanged. Thank you @xyzs996 — precise sourcing, both language footnotes reconciled!
…apw#11166) Validated on the combined batch board over tip 0b41259: static gates clean (changelog, file-size 160 frozen, complexity 2628<=2774, cognitive 1187<=1223, dead-code 408<=416, docs-counts green at 351 providers, provider-consistency 268/351/0), typecheck:core clean, 430+ focused tests green across 5 groups. Prime Agent joins the CLI agents catalog with runtime entry + doc counts synced (35 tools; CLI-TOOLS.md row). cli-catalog-acpspawnable 26/26. Thank you @arminanton!
…le input limit (diegosouzapw#11179) Validated on the combined batch board over tip 0b41259: static gates clean (changelog, file-size 160 frozen, complexity 2628<=2774, cognitive 1187<=1223, dead-code 408<=416, docs-counts green at 351 providers, provider-consistency 268/351/0), typecheck:core clean, 430+ focused tests green across 5 groups. max_context_window now wins over the pricing-tier context_window in Codex catalog parsing — context-aware fallback stops demoting codex behind smaller targets. Live evidence (390K served past 272K) plus the live-shape regression test. Thank you @excessivechaos!
…214]) (diegosouzapw#11209) Validated on the combined batch board over tip 0b41259: static gates clean (changelog, file-size 160 frozen, complexity 2628<=2774, cognitive 1187<=1223, dead-code 408<=416, docs-counts green at 351 providers, provider-consistency 268/351/0), typecheck:core clean, 430+ focused tests green across 5 groups. GLM-family upstreams reject message arrays with no user turn (400 [1214], verified live 2026-08-23); the synthetic user turn keeps Claude Code sessions on opencode-go alive. Thank you @linhdmn!
diegosouzapw#11214) Validated on the combined batch board over tip 0b41259: static gates clean (changelog, file-size 160 frozen, complexity 2628<=2774, cognitive 1187<=1223, dead-code 408<=416, docs-counts green at 351 providers, provider-consistency 268/351/0), typecheck:core clean, 430+ focused tests green across 5 groups. muse-spark's all-reasoning empty-answer payloads (41 failures in 2h captured live) now floor the output budget so the model can actually emit content — no more empty-content 502 churn. Thank you @linhdmn!
…souzapw#11159) Validated on the combined batch board over tip 0b41259: static gates clean, typecheck:core clean, 430+ focused tests green across 5 groups. postbuild's esbuild spawn now resolves cross-platform (no more ENOENT after a successful Next compile on Windows). build-tool-runner-win-shim suite green. Thank you @aliyosufi — first contribution, welcome!
Validated on the combined batch board over tip 0b41259: static gates clean, typecheck:core clean, 430+ focused tests green across 5 groups. --tray returns after readiness and survives terminal close, with tray-mode autostart on macOS/Windows/Linux while headless Linux keeps the systemd user service. tray-detached + autostart suites green. Closes diegosouzapw#11229. Thank you @tuandinh0801!
…gosouzapw#11225) (diegosouzapw#11231) Validated on the combined batch board: gates clean, typecheck clean, focused tests green. Exactly one Market id rewritten at the createTask seam (google-imagen/nano-banana-2 → nano-banana-2); every other namespaced id forwards byte-identical — the contract is stated and tested precisely. Fixes diegosouzapw#11225. Thank you @xiaoyaner0201!
…entic replay (diegosouzapw#10959) (diegosouzapw#11178) Merged after conflict resolution onto the post-diegosouzapw#10961 tip (verified no clobber of today's plaintext-wins work — the resolver functions were appended and the chatCore call-site swapped; a first --theirs attempt was caught reverting diegosouzapw#10961 and redone hunk-by-hunk). resolveIncompatibleReasoningAction now defaults single-target incompatible reasoning to drop while combos keep their explicit strategy, with the x-omniroute-reasoning-fallback header override. 21/21 reasoning suites green, typecheck clean. Fixes diegosouzapw#10959. Thank you @adevwithpurpose!
Merged after conflict resolution (validated on the combined batch board + this branch): stale drift files (package.json/package-lock/.gitignore) kept at tip; the two modals merged additively — AWS SigV4 fields coexist with the chatgpt-web-codex tunnel fields and the diegosouzapw#11156 Enter-handler mirror (vitest 2/2 re-run). file-size gate green with the dated AddApiKeyModal 1173 entry (owner-authorized). aws-polly modal + provider-validation-specialty 127/127. Base was mistakenly main; retargeted to release/v3.8.50. Credentials stay in the protected field; nothing logged. Thank you @rafacpti23!
Merged after conflict resolution (validated on the combined batch board + this branch): component integrated with diegosouzapw#10489's health-race semantics (stale-check invalidation, 3-state badge, correct useCallback deps — your validation gate and tutorial are preserved on top); the two pre-gate tests updated to validate-search-before-enable (contract propagation, commented); the docs/superpowers planning files were dropped — project rule keeps planning artifacts out of docs/ (they live in the private _tasks/ repo). Base was mistakenly main; retargeted. qdrant-config-card 7/7 + qdrant-routes integration 18/18. Thank you @rafacpti23 — the pre-enable real-search gate closes a real misconfiguration footgun!
…ovider + sign-in) (diegosouzapw#11205) Merged after conflict resolution: the 5 conflicting test files were the base-red drains that diegosouzapw#11201 already landed on the tip — kept the tip versions; the feature content is untouched. Validated on the combined batch board + this branch: codex-app-server + codex-gpt56-catalog 25/25, typecheck:core clean, docs-counts green (351 providers), provider-consistency 268/351/0. The opt-in codex-app-server transport (JSON-RPC-over-WS, turn/completed-awaited close, Responses SSE bridge) leaves the default codex path untouched. Thank you @arminanton — a 3.4k-line transport with the docs wave and tests to match!
…zapw#10055 drain already landed)
This was referenced Aug 23, 2026
yourspraveen
pushed a commit
to yourspraveen/OmniRoute
that referenced
this pull request
Aug 23, 2026
…oviders diegosouzapw#11088 removed filterChatSelectableModels from importManagedModels for EVERY provider, but the compensating read-time filter (resolveLocalSyncedEndpointRoute) is gated on isSelfHostedChatProvider. So non-local providers lost the filter with nothing replacing it: an OpenAI sync now persists gpt-image-2, sora-2-pro and any model declaring /v1/images/generations straight into chat selections. Reproduced on main (which carries diegosouzapw#11088) as well as on this branch, and NOT on the pristine release tip — so it is a defect in the merged change, not in the port. Verified by tests/unit/managed-model-import.test.ts, which asserts both result.discoveredModels and the persisted getSyncedAvailableModels("openai"). Self-hosted providers keep the new behaviour — non-chat models still persist and are filtered at read time — so diegosouzapw#11087's goal is untouched: the Ollama capability suite stays 3/3. Also registers the third getProviderCredentials site diegosouzapw#11088 added in embeddings/service.ts with the hard-lease inventory ledger (2 -> 3). The site resolves through getProviderCredentials with the connection allowlist from resolveLocalSyncedEndpointRoute and handles allRateLimited, so it is fenced like the two existing sites; the ledger simply had not been told.
diegosouzapw
pushed a commit
that referenced
this pull request
Aug 23, 2026
…11088 to the release line (#11271) Validated on the combined 8-PR board: ollama-local-capabilities-routing 3/3, managed-model-import 9/9 (including the integration with the carried Gemini-3.5-Flash cleanup from #11259), 88/88 across the board's focused suites, typecheck:core + dashboard-typecheck clean, gates within baseline. This brings #11088 to the release line — it had squash-merged to main by base error (mine) — AND fixes the two defects the port caught: the global filter drop that leaked image/video models into OpenAI chat selections (now scoped to self-hosted providers) and the unregistered hard-lease credential site. Exemplary port discipline: byte-identical carry + the corrections in a separate reviewable commit + the superpowers docs deliberately left out. main still needs the same two-line fix. Thank you @yourspraveen!
diegosouzapw
pushed a commit
that referenced
this pull request
Aug 24, 2026
…k the release PR The living release PR #8875 was CONFLICTING, which makes GitHub skip EVERY pull_request workflow silently (no ci.yml, no semgrep, no DAST). Back-merging main restores a computable merge ref. Strategy `-s ours`: main is a stale snapshot of the release line (PR #11088 was merged into main from a release-tip base, dragging ~5094 files). All 7 main-only commits were verified as already represented on this branch: - #11088 ollama capability routing -> ported here as #11271 (6d4c484) - #11075 shared passthrough providers -> ported here as #11165 (92ef3c7) - #10055 getModelsDevPricing memoization -> present (modelsDevSync.ts) - #10026 hide health-check excluded models -> present and extended (catalog.ts) - /_tasks anchored gitignore hardening -> present (.gitignore:288) - nanoid/dompurify Dependabot bumps -> identical versions main-only files intentionally NOT carried over: - changelog.d/fixes/10286-gemini-3-5-flash-thinking.md + its regression test: the fix landed here as #10450 and was then deliberately superseded by 2764812 "eliminate Gemini 3.5 Flash". The test fails on this branch by design. - public/providers/hackclub.svg: provider removed here (migration 162). - docs/superpowers/**/2026-08-23-qdrant-*: planning artifacts belong in _tasks/ (AGENTS.md), never under docs/.
diegosouzapw
added a commit
that referenced
this pull request
Aug 28, 2026
…nc-back step 2/2
The eighteen commits main carries beyond the cycle branch, and what each one
became here:
already in release/v3.8.51 by its own PR (no-op, verified by content):
b090b60 / 026e1ca deps: nanoid 3.3.18 equal, dompurify 3.4.14 newer
918fba5 .gitignore: /_tasks already anchored
5f0a394 #10026 hide health-check-excluded models — same helper, 5 call sites
c68cda7 #11075 shared passthrough providers — superseded by #11071/#11078
superseded, one piece kept:
ca23eed #10055 memoize models.dev pricing — the cycle memoizes on the
catalog cache version already; only the resetDbInstance() hook is
ported, wired to that memo
applied as-is:
8778ea7 stamp dist/BUILD_SHA before the npm provenance gate (#11721)
aa52351 decouple the Bun image from the release manifest (#11724)
925feb2 let the bun digest artifact be absent (#11740)
b65ef33 size the install-upgrade gate to a measured run
0ce2123 #11845 converge install/upgrade schemas (migration renumbered in
the next commit: 163 collides with 163_radar_feed_cache_generated_at)
b7c07ed #11855 install-upgrade gate on disk, not tmpfs
8e2fb04 #11864 drop *.nft.json from the npm tarball (413)
dea6bb8 #11877 publish npm from a hosted runner (provenance 422)
handled by the sync script that follows (CHANGELOG protocol):
b4ec780 Release v3.8.50 — squash of content this branch already carries
5458026 / c44c0a2 CHANGELOG aggregation, stats and top-25
applied separately (its own commit, ten files):
65e8115 #11088 Ollama capability routing — a 5,094-file squash from a
stale base; only the Ollama files are the change
Every cherry-pick that touched a file this branch had also changed was
resolved by hand and re-run through the tests both sides own for it.
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.
Fixes #11087
Summary
/api/showcapability probesValidation
node --import tsx/esm --test tests/unit/ollama-local-capabilities-routing.test.tsnpm run typecheck:corenpm run lint(0 errors; 6 pre-existing warnings)npm run test:vitest(34 files, 291 tests passed)npm run check:cyclesnpm run check:any-budget:t11npm run check:tracked-artifactsThe regression test uses placeholder loopback hosts and generated connection IDs; no internal hostnames or connection UUIDs are published.
CI status
⚠️ base-red inherited— the base tip (main@ c68cda7) is already red on theLint job. Run 32542442026
on the unmodified base fails
check:file-sizewith:open-sse/services/accountFallback.ts: 1968 > congelado 1966tests/unit/account-fallback-service.test.ts: 1570 > congelado 1563Neither file is touched by this PR. Per the release-green policy these are
mid-cycle ratchet drift, rebaselined at release — not a contributor concern.
The one file-size violation this PR did introduce
(
src/app/api/providers/[id]/models/route.ts: 2269 > congelado 2250) is fixedin 6d66499 by extracting the
/api/showprobe wiring intodiscovery/helpers.ts::enrichOllamaLocalModels(); the route file is back to itsfrozen 2249 lines with no behavior change.
The Build job failure is environmental, not a code defect: fork PRs are
deliberately excluded from the self-hosted
omni-releaserunner by theruns-onguard inci.yml, so this run fell back toubuntu-latest, where theTurbopack production build was killed after 20 min (
The operation was canceled.). The same commit's base built fine in 40 min on the 32-coreself-hosted runner. See the
OMNIROUTE_USE_TURBOPACK=0note inscripts/build/build-next-isolated.mjsre: memory-constrained machines.The Unit Tests (2/8) failure is a CI flake, not a defect. The shard reports
3530 passed / 1 failed, and the single failure is in
tests/unit/build/should-promote-latest-5301.test.ts— a release-script testuntouched by this PR:
status: 0withstdout: 'false\n'shows the script ran to completion andreturned the correct answer (a pre-release must not promote
latest);execFileSyncraisedEPIPEon the closed pipe regardless. Nothing in thisPR touches
scripts/ci/ortests/unit/build/.Ollama version requirements
/api/showhas existed since early Ollama, but thecapabilitiesarray itreturns is version-gated. Discovery degrades safely on older servers — the Zod
schema marks
capabilitiesoptional, a non-2xx/throwing probe yieldsnull,and
applyOllamaShowCapabilitiesreturns the model unenriched — so old serversget exactly the pre-PR behavior, never an error.
completion,embedding,vision,tools,insertthinkingimageSo the embeddings half of this fix needs Ollama ≥ 0.6.4 and the image half needs
≥ 0.14.0; below those the routing simply falls through to the previous path.