Custom OpenAI-Compatible Provider

A custom provider is an OpenAI Chat Completions-compatible service configured by name, Base URL, and API key. The provider type determines the wire protocol; model names do not.

Resolved behavior

The historical host-only behavior produced /models and /chat/completions, and a non-JSON 200 response was once accepted as a valid credential response. The current resolver adds /v1 for a host-only custom Base URL, and the credential/model-listing path requires a JSON response.

Address contract

Configured valueResolved API Base
https://hosthttps://host/v1
https://host/https://host/v1
https://host/v1https://host/v1
https://host/compatible-mode/v1unchanged

The stored value remains the user's input. Model listing, credential validation, enabled-model registration, and inference use the resolved value.

Data flow and failures

GET {base}/models validates credentials and lists models. A successful validation response must be JSON. Model rows are stored with api=openai-completions and the resolved Base URL. Runtime inference uses POST {base}/chat/completions.

Authentication rejection, balance errors, rate limits, transport failures, non-JSON success pages, malformed model envelopes, and empty model lists remain distinct observable outcomes. Error text must not include API keys or response bodies.

Compatibility

Existing custom providers and enabled model rows are interpreted at read time with the same resolver, so no configuration migration or re-creation is required. Built-in provider protocols retain their current resolution rules.

Acceptance criteria

Implementation evidence

Implemented through the shared provider Base URL resolver, credential validator, generic OpenAI-compatible model fetcher, listing normalizer, and enabled-model registry. Focused provider tests cover host-only resolution, explicit-path preservation, legacy enabled rows, and non-JSON success responses. The packaged App resolved Yuanheng to https://nan.meta-api.vip/v1 and fetched 10 remote models in the default profile.