Review follow-up: byModel is ai-gateway's normalized internal form
(parseModelScopedBody treats only `default` and actual model names as
scope keys); the raw config saved to disk is `default` plus top-level
model-name keys. The help text, i18n rows and the round-trip test now
use that raw shape.
The provider dialog had no field for either, so both were config-file
only: invisible in the UI and only editable by hand-writing the config
or writing to the config database directly.
Adds two JSON boxes to the Advanced settings section, next to the usage
connector body that already uses this pattern. They open pre-filled with
whatever the provider carries, and a malformed or non-object value blocks
the save with an inline error instead of writing something the gateway
would ignore.
extraBody and extraHeaders leave providerManualFieldsForSave now that the
draft round-trips them; billing, provider and transformer stay there.
Review follow-up: the spec hard-codes English UI strings ("Providers"
nav, the "Edit <name>" provider aria-label), but the web UI defaults to
the system language, so the suite failed on zh-locale hosts. The
Playwright context locale is now pinned per suite, which keeps the
selectors deterministic without dual-language lookups everywhere.
Drives the real management UI: seeds a provider carrying extraBody,
extraHeaders and a transformer, opens the edit dialog, saves, and asserts
the three fields are still there afterwards.
The spec fails on the unpatched build and passes with the fix, so it
guards the regression rather than the helper alone.
The CLI web server bootstrap moves out of cli-web.spec.ts into
cli-web-runtime.ts so both specs can start their own instance.
Saving a provider from the setup dialog replaced the stored entry with an
object rebuilt from the dialog draft, so every field the form does not
expose was dropped: extraBody, extraHeaders, transformer, billing and the
legacy provider protocol alias.
These only ever come from a hand-written config, and the loss is silent —
the provider keeps working, just without the upstream parameters it was
configured with. Re-typing a base URL on a provider carrying
`extraBody: { default: { reasoning_effort: "high" } }` is enough to turn
reasoning off with no error and no visible change in the UI.
Carry those fields over from the existing provider on edit. The legacy
apiKey/apikey/baseUrl/baseurl aliases are deliberately not carried over:
the form writes the canonical api_key/api_base_url, and a stale alias
would shadow the value the user just typed.