{# SETTINGS · System → CUSTOM PROVIDERS (Task 4). The operator-managed, open-ended set of provider credentials (name + base URL + masked API key), separate from the fixed built-in provider-key fields above. Persisted OUTSIDE the schema under `custom_providers` (app.settings) and preserved across every System save. This whole region is one HTMX swap target (#sys-custom-providers): adding or removing a provider POSTs and swaps the refreshed list back in. The stored API key is NEVER rendered — a configured key shows as the "•••• set" mask, exactly like the built-in secret fields. Context: custom_providers : [{id, name, base_url, has_key, key_display}] (masked) cp_added : name of a just-added provider (success flash) | None cp_removed : truthy if a provider was just removed cp_error : error string (add/remove failure) | None selected_key : current project key (kept on the POST query string) #}
{# inline status flash after an add / remove #} {% if cp_error %} {% elif cp_added %}
Added. {{ cp_added }} saved to the console app-DB — key stored masked.
{% elif cp_removed %}
Removed. Custom provider deleted from the local store.
{% endif %} {# existing custom providers — name · base URL · masked key · remove #} {% if custom_providers %}
{% for p in custom_providers %}
{{ p.name }} {% if p.base_url %}{{ p.base_url }}{% endif %} {{ p.key_display if p.has_key else 'no key' }} {# Test — probe {base_url}/models with the stored key (OpenAI-compatible). #} {% if p.has_key %} {% endif %}
{% endfor %}
{% else %}
No custom providers yet — add one below.
{% endif %} {# "+ Add provider" affordance. The button reveals an inline add form (pure CSS via a hidden checkbox toggle — no JS needed). The form POSTs name + base URL + API key; the API key field is masked on type (password input). On success the server swaps this whole region back in, which resets the form + collapses it. #}
{# The form element carries the HTMX attrs; the inputs above reference it via form="cp-add" so the layout can place them in a grid while still submitting together. Submit swaps the refreshed region back into #sys-custom-providers. #}