fix(ui): preserve endpoint-style custom slugs host:port in model parsers (#6884)

This commit is contained in:
webtecnica committed 2026-09-24 08:50:30 -03:00
1 parent 7db2695a5e
commit c784ef7a12
2 files changed
+55 -6

No files matched your search

+35 -5
View File
@@ -2982,9 +2982,19 @@ function _getOptionProviderId(opt){
const value=String(opt.value||'');
if(value.startsWith('@') && value.includes(':')){
// Non-greedy parse for @custom:<slug>:<model> — provider is the slug only.
// For @custom:backup:model-a:free → provider="custom:backup", not "custom:backup:model-a"
// Preserves endpoint-style host:port custom slugs (e.g. custom:localhost:11434)
// while keeping colon-bearing model ids (e.g. @custom:backup:model-a:free -> custom:backup).
if(value.startsWith('@custom:')){
const afterCustom=value.substring('@custom:'.length);
const parts=afterCustom.split(':');
if(parts.length>=3 && /^\d+$/.test(parts[1])){
const port=parseInt(parts[1], 10);
const host=parts[0];
const hl=host.toLowerCase();
if(port>=1 && port<=65535 && (hl==='localhost' || host.includes('.'))){
return 'custom:'+host+':'+parts[1];
}
}
const firstColon=afterCustom.indexOf(':');
if(firstColon>=0) return 'custom:'+afterCustom.substring(0,firstColon);
return 'custom:'+afterCustom;
@@ -2998,9 +3008,19 @@ function _providerFromModelValue(modelId){
const value=String(modelId||'').trim();
if(value.startsWith('@')&&value.includes(':')){
// Non-greedy parse for @custom:<slug>:<model> — provider is the slug only.
// For @custom:backup:model-a:free → provider="custom:backup", not "custom:backup:model-a"
// Preserves endpoint-style host:port custom slugs (e.g. custom:localhost:11434)
// while keeping colon-bearing model ids (e.g. @custom:backup:model-a:free -> custom:backup).
if(value.startsWith('@custom:')){
const afterCustom=value.substring('@custom:'.length);
const parts=afterCustom.split(':');
if(parts.length>=3 && /^\d+$/.test(parts[1])){
const port=parseInt(parts[1], 10);
const host=parts[0];
const hl=host.toLowerCase();
if(port>=1 && port<=65535 && (hl==='localhost' || host.includes('.'))){
return 'custom:'+host+':'+parts[1];
}
}
const firstColon=afterCustom.indexOf(':');
if(firstColon>=0) return 'custom:'+afterCustom.substring(0,firstColon);
return 'custom:'+afterCustom;
@@ -3018,9 +3038,19 @@ function _modelPickerOptionIdentity(modelId, providerId){
if(exactPrefix && value.toLowerCase().startsWith(exactPrefix.toLowerCase())){
value=value.substring(exactPrefix.length);
}else if(value.startsWith('@custom:')){
const namedProvider=value.substring('@custom:'.length);
const splitAt=namedProvider.indexOf(':');
value=splitAt>=0 ? namedProvider.substring(splitAt+1) : namedProvider;
const afterCustom=value.substring('@custom:'.length);
const parts=afterCustom.split(':');
let splitAt=-1;
if(parts.length>=3 && /^\d+$/.test(parts[1])){
const port=parseInt(parts[1], 10);
const host=parts[0];
const hl=host.toLowerCase();
if(port>=1 && port<=65535 && (hl==='localhost' || host.includes('.'))){
splitAt=parts[0].length + 1 + parts[1].length;
}
}
if(splitAt<0) splitAt=afterCustom.indexOf(':');
value=splitAt>=0 ? afterCustom.substring(splitAt+1) : afterCustom;
}else{
value=value.substring(value.indexOf(':')+1);
}
@@ -229,9 +229,16 @@ const modelAFree = {
dataset: {}, // no data-model — normal catalog render path
parentElement: group,
};
const localhostGroup = {tagName: 'OPTGROUP', dataset: {provider: 'custom:localhost:11434'}};
const llama = {
value: '@custom:localhost:11434:llama3.2',
textContent: 'llama3.2',
dataset: {},
parentElement: localhostGroup,
};
const select = {
id: 'modelSelect',
options: [luna, sol, modelAFree],
options: [luna, sol, modelAFree, llama],
querySelectorAll() { return []; },
get selectedOptions() { return [sol]; },
get value() { return sol.value; },
@@ -242,6 +249,8 @@ process.stdout.write(JSON.stringify({
nonDefault: _modelStateForSelect(select, '@custom:hetmer.net:sol'),
defaultUnprefixed: _modelStateForSelect(select, 'luna'),
colonBearingModel: _modelStateForSelect(select, '@custom:hetmer.net:model-a:free'),
localhostEndpoint: _modelStateForSelect(select, '@custom:localhost:11434:llama3.2'),
missingOptionCustomInput: _modelStateForSelect(select, '@custom:localhost:11434:mistral-custom'),
}));
"""
@@ -276,6 +285,16 @@ def test_non_default_named_custom_provider_model_strips_qualified_prefix():
"model": "model-a:free",
"model_provider": "custom:hetmer.net",
}
# Endpoint-style custom provider (e.g. host:port derived from base_url authority):
# preserves full custom:localhost:11434 for both catalog and missing-option paths.
assert payload["localhostEndpoint"] == {
"model": "llama3.2",
"model_provider": "custom:localhost:11434",
}
assert payload["missingOptionCustomInput"] == {
"model": "mistral-custom",
"model_provider": "custom:localhost:11434",
}
# Round-trip: send -> persist -> restore for a colon-bearing named