fix(desktop): persist the whole discovered model list when saving an endpoint

Test enumerates a custom provider's catalogue and the panel holds the result
in discoveredModels, but the save payload never carried it, so only the one
model the user hand-typed reached providers.<id>.models. Every downstream
picker reads that map straight from config.yaml with no live probe, which is
why a proxy serving 18 models offered exactly one.

Send the discovered list and merge it onto the entry, so models already
known keep their context lengths.

Fixes #69988

Co-authored-by: asorry75 <33794789+asorry75@users.noreply.github.com>
This commit is contained in:
Brooklyn Nicholson 2026-07-24 21:12:36 -05:00
parent bfe7460c79
commit de6375ebc5
3 changed files with 18 additions and 8 deletions

View file

@ -58,7 +58,7 @@ function formFromEndpoint(endpoint: CustomEndpoint): EndpointForm {
}
}
function toPayload(form: EndpointForm): CustomEndpointUpdate {
function toPayload(form: EndpointForm, models?: string[]): CustomEndpointUpdate {
const contextLength = Number.parseInt(form.contextLength, 10)
return {
@ -69,7 +69,8 @@ function toPayload(form: EndpointForm): CustomEndpointUpdate {
api_key: form.apiKey.trim() || undefined,
context_length: Number.isFinite(contextLength) && contextLength > 0 ? contextLength : undefined,
discover_models: form.discoverModels,
make_default: form.makeDefault
make_default: form.makeDefault,
models: models?.length ? models : undefined
}
}
@ -125,7 +126,7 @@ export function CustomEndpointsSettings({ onConfigSaved, onMainModelChanged }: C
async function handleSave() {
try {
setSaving(true)
const response = await saveCustomEndpoint(toPayload(form))
const response = await saveCustomEndpoint(toPayload(form, discoveredModels))
setEndpoints(response.endpoints)
const saved = response.endpoints.find(endpoint => endpoint.id === response.id)

View file

@ -182,6 +182,7 @@ export interface CustomEndpointUpdate {
id?: string
make_default?: boolean
model: string
models?: string[]
name: string
}

View file

@ -1271,6 +1271,7 @@ class CustomEndpointUpdate(BaseModel):
context_length: Optional[int] = None
discover_models: bool = True
make_default: bool = False
models: Optional[List[str]] = None
class MessagingPlatformUpdate(BaseModel):
@ -7700,13 +7701,20 @@ def _write_custom_endpoint(cfg: Dict[str, Any], body: CustomEndpointUpdate) -> T
"model": model,
"discover_models": bool(body.discover_models),
})
# Same for the model map: the panel names one default model, it does not
# enumerate the provider's catalogue. Keep the other models (and their
# context lengths) and just ensure this one is present.
# Same for the model map: merge rather than replace, so existing models
# keep their context lengths. ``body.models`` is the catalogue the panel's
# Test button already discovered — without it only the one hand-typed
# model survived Save, and every picker showed a single-entry list for a
# provider serving dozens (#69988). A payload with no ``models`` (older
# UI) still just ensures the named default is present.
existing_models = entry.get("models")
models_map: Dict[str, Any] = dict(existing_models) if isinstance(existing_models, dict) else {}
current_model_entry = models_map.get(model)
models_map[model] = dict(current_model_entry) if isinstance(current_model_entry, dict) else {}
for candidate in (*(body.models or ()), model):
model_id = str(candidate).strip()
if not model_id:
continue
current = models_map.get(model_id)
models_map[model_id] = dict(current) if isinstance(current, dict) else {}
entry["models"] = models_map
if body.context_length and body.context_length > 0:
entry["context_length"] = int(body.context_length)