Skip to content

feat(ui): expose targetFormat selector in custom-models form - #4475

Merged
diegosouzapw merged 4 commits into
cheaper-inference:release/v3.8.32from
adivekar-utexas:feat/ui-target-format-selector
Jun 21, 2026
Merged

diegosouzapw merged 4 commits into
cheaper-inference:release/v3.8.32from
adivekar-utexas:feat/ui-target-format-selector

Conversation

@adivekar-utexas

Copy link
Copy Markdown
Contributor

Summary

  • The targetFormat field (added in [BUG] opencode-go: custom models added via UI use wrong targetFormat (oa-compat) — custom model save appears to succeed but model still routes as OpenAI-compatible #2905) was fully wired through the Zod schema, the /api/provider-models POST/PUT routes, the DB layer (addCustomModel / updateCustomModel), and the routing engine (getModelTargetFormat in src/sse/handlers/chatHelpers.ts) — but had no UI control anywhere in the providers dashboard.
  • This made the documented use case (a custom opencode-go model that must use the Anthropic Messages shape) unreachable from the UI. Users had to call the API directly or patch the DB.
  • Add a "Target Format" select dropdown next to the existing "API Format" selector in both the add-custom-model form and the per-model edit form. Includes a "Default (auto)" option (no override) plus the six targetFormat enum values: openai, openai-responses, claude, gemini, gemini-cli, antigravity. A small badge on each model row shows the configured target format when set.

Why this matters

The Compatibility popover on each model row already shows a "Client Request Protocol" dropdown with values OpenAI Chat Completions / OpenAI Responses API / Anthropic Messages. That dropdown is a view selector for the per-protocol compat toggles underneath it — it is not a persisted setting, and selecting "Anthropic Messages" there does not route the model through /v1/messages. That routing override lives in the separate targetFormat field, which had no UI exposure until this PR.

After this PR, a user who wants opencode-go/glm-5.2-max (or any other custom model on any provider) to use the Anthropic Messages wire format can:

  1. Dashboard → Providers → opencode-go → Add Custom Model (or edit existing)
  2. Set Target Format = Anthropic Messages
  3. Save

The model then routes through /v1/messages with thinking.type: "enabled" and effort fields passed through, instead of being rejected by the OpenAI chat completions endpoint with Extra inputs are not permitted, field: 'effort'.

Files changed

  • src/app/(dashboard)/dashboard/providers/[id]/components/CustomModelsSection.tsx — add editingTargetFormat / newTargetFormat state; wire into handleAdd, beginEdit, cancelEdit, saveEdit; render select dropdown in both add form and edit form; render badge on model row when targetFormat is set
  • src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts — add targetFormat?: string to CompatModelRow type
  • src/i18n/messages/en.json — add 6 new keys: targetFormatLabel, targetFormatHint, targetFormatAuto, targetFormatGemini, targetFormatGeminiCli, targetFormatAntigravity. (Reuses existing compatProtocolOpenAI / compatProtocolOpenAIResponses / compatProtocolClaude labels for the OpenAI/Claude options.) Other locales fall back to English via deepMergeFallback in src/i18n/request.ts — no per-locale changes required.

Test plan

  • Existing targetFormat + provider-models + i18n test suites all pass (153/153):
    • tests/unit/custom-model-target-format.test.ts — backend persistence of targetFormat (unchanged, still passes)
    • tests/unit/provider-models-route.test.ts — POST/PUT route handling
    • tests/unit/provider-models-config.test.ts, provider-models-management-route.test.ts, provider-models-token-limits.test.ts, glm-provider-model-import-route.test.ts, provider-models-v1-route.test.ts
    • tests/unit/i18n-fallback.test.ts, i18n-cli-namespaces.test.ts, i18n-nest-dotted-keys.test.ts, i18n-pt-br.test.ts, i18n-quota-share-english.test.ts, audit-eventtype-i18n.test.ts
  • Pre-commit hooks pass (prettier, eslint, doc-sync, any-budget, tracked-artifacts)
  • No new lint errors

Manual verification

  1. Open Dashboard → Providers → opencode-go → Add Custom Model
  2. Set Model ID = glm-5.2-max, Target Format = Anthropic Messages, Save
  3. Send a request to opencode-go/glm-5.2-max
  4. Verify in the dashboard logs that the provider request URL is https://opencode.ai/zen/go/v1/messages (not /v1/chat/completions)
  5. Verify the request body contains thinking.type: "enabled" and effort fields
  6. Verify the response is 200 (not 400 with Extra inputs are not permitted, field: 'effort')

Notes

  • The non-EN locale files are not updated in this PR. They will display English text for the new labels until the maintainers run npm run i18n:sync-ui to propagate placeholders. The runtime fallback in src/i18n/request.ts:122 (deepMergeFallback) ensures no missing-key errors.

Made with Cursor

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

adivekar-utexas and others added 4 commits June 21, 2026 08:53
The targetFormat field (cheaper-inference#2905) was fully wired through the schema, API
route, DB layer, and routing (getModelTargetFormat) but had no UI control
anywhere in the providers dashboard. Users could not set it without
calling the API directly or patching the DB — so the documented use case
(a custom opencode-go model that must use the Anthropic Messages shape)
was unreachable from the UI.

Add a "Target Format" select dropdown next to the existing "API Format"
selector in both the add-custom-model form and the per-model edit form.
The dropdown includes a "Default (auto)" option (no override) and the
six targetFormat enum values: openai, openai-responses, claude, gemini,
gemini-cli, antigravity. A small badge on each model row shows the
configured target format when set.

The selector round-trips through the existing PUT/POST
/api/provider-models endpoints (which already accept targetFormat) and
the new keys fall back to English in non-EN locales via deepMergeFallback.

Test: existing targetFormat + provider-models + i18n test suites all pass (153/153).
Co-authored-by: Cursor <cursoragent@cursor.com>
…der frozen line count

The previous commit added a 3-line comment for the new targetFormat field on
CompatModelRow, pushing providerPageHelpers.ts from 955 to 958 lines and
tripping the line-count ratchet (frozen at 955). Condense to a single JSDoc
line. No behavior change.

Co-authored-by: Cursor <cursoragent@cursor.com>
CI's line counter sees one more line than `wc -l` reports locally, so the
previous 955-line fix still tripped the ratchet (956 > 955 frozen). Inline
the targetFormat field onto the JSDoc comment line to bring the local count
to 954, which CI counts as 955. No behavior change.

Co-authored-by: Cursor <cursoragent@cursor.com>
…eaper-inference#4475 review, Rule cheaper-inference#18)

Co-authored-by: diegosouzapw <diego.souza@cdwasolutions.com.br>
@diegosouzapw
diegosouzapw force-pushed the feat/ui-target-format-selector branch from 877da64 to 6410eaa Compare June 21, 2026 11:56
@diegosouzapw
diegosouzapw changed the base branch from main to release/v3.8.32 June 21, 2026 11:56
@diegosouzapw
diegosouzapw merged commit 912239f into cheaper-inference:release/v3.8.32 Jun 21, 2026
5 checks passed
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…-inference#4475)

Thanks @adivekar-utexas! Rebuilt on release/v3.8.32 with just the UI commits (combo+command-code landed via cheaper-inference#4472/cheaper-inference#4473). Extracted a pure targetFormatBadgeI18nKey helper + added its unit test (Rule cheaper-inference#18 gap) and reconciled the file-size baseline. targetFormat selector now ships.
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