fix(config): use Hermes config.yaml as single source of default model (#773)

Removes split-brain where WebUI Settings persisted default_model separately from Hermes runtime config.yaml. New POST /api/default-model endpoint writes to config.yaml. Existing saved values migrated on first load.

Fixes #761

Co-authored-by: aronprins <aronprins@users.noreply.github.com>
This commit is contained in:
nesquena-hermes
2026-04-20 15:12:01 -07:00
committed by GitHub
parent f35ac3a727
commit 63f9b719bb
8 changed files with 192 additions and 41 deletions

View File

@@ -321,7 +321,8 @@ async function _saveOnboardingDefaults(){
if(!known){
await api('/api/workspaces/add',{method:'POST',body:JSON.stringify({path:workspace})});
}
const body={default_workspace:workspace,default_model:model};
// Model persisted by /api/onboarding/setup — no /api/default-model call needed here
const body={default_workspace:workspace};
if(password) body._set_password=password;
const saved=await api('/api/settings',{method:'POST',body:JSON.stringify(body)});
if(ONBOARDING.status){

View File

@@ -1075,6 +1075,7 @@ document.addEventListener('drop',e=>{e.preventDefault();dragCounter=0;wrap.class
let _settingsDirty = false;
let _settingsThemeOnOpen = null; // track theme at open time for discard revert
let _settingsSkinOnOpen = null; // track skin at open time for discard revert
let _settingsHermesDefaultModelOnOpen = '';
let _settingsSection = 'conversation';
function switchSettingsSection(name){
@@ -1220,9 +1221,10 @@ async function loadSettingsPanel(){
const modelSel=$('settingsModel');
if(modelSel){
modelSel.innerHTML='';
let models=null;
try{
const models=await api('/api/models');
for(const g of (models.groups||[])){
models=await api('/api/models');
for(const g of ((models||{}).groups||[])){
const og=document.createElement('optgroup');
og.label=g.provider;
for(const m of g.models){
@@ -1233,7 +1235,8 @@ async function loadSettingsPanel(){
modelSel.appendChild(og);
}
}catch(e){}
modelSel.value=settings.default_model||'';
_settingsHermesDefaultModelOnOpen=(models&&models.default_model)||'';
modelSel.value=_settingsHermesDefaultModelOnOpen;
modelSel.addEventListener('change',_markSettingsDirty,{once:false});
}
// Send key preference
@@ -1320,6 +1323,7 @@ function _applySavedSettingsUi(saved, body, opts){
_settingsSkinOnOpen=skin||'default';
const bar=$('settingsUnsavedBar');
if(bar) bar.style.display='none';
_settingsHermesDefaultModelOnOpen=body.default_model||_settingsHermesDefaultModelOnOpen||'';
renderMessages();
if(typeof syncTopbar==='function') syncTopbar();
if(typeof renderSessionList==='function') renderSessionList();
@@ -1327,6 +1331,7 @@ function _applySavedSettingsUi(saved, body, opts){
async function saveSettings(andClose){
const model=($('settingsModel')||{}).value;
const modelChanged=(model||'')!==(_settingsHermesDefaultModelOnOpen||'');
const sendKey=($('settingsSendKey')||{}).value;
const showTokenUsage=!!($('settingsShowTokenUsage')||{}).checked;
const showCliSessions=!!($('settingsShowCliSessions')||{}).checked;
@@ -1336,7 +1341,6 @@ async function saveSettings(andClose){
const language=($('settingsLanguage')||{}).value||'en';
const sidebarDensity=($('settingsSidebarDensity')||{}).value==='detailed'?'detailed':'compact';
const body={};
if(model) body.default_model=model;
if(sendKey) body.send_key=sendKey;
body.theme=theme;
@@ -1357,6 +1361,14 @@ async function saveSettings(andClose){
if(pw && pw.trim()){
try{
const saved=await api('/api/settings',{method:'POST',body:JSON.stringify({...body,_set_password:pw.trim()})});
if(modelChanged && model){
try{
await api('/api/default-model',{method:'POST',body:JSON.stringify({model})});
body.default_model=model;
}catch(_modelErr){
if(typeof showToast==='function') showToast('Failed to update default model — settings saved');
}
}
_applySavedSettingsUi(saved, body, {sendKey,showTokenUsage,showCliSessions,theme,skin,language,sidebarDensity});
showToast(t(saved.auth_just_enabled?'settings_saved_pw':'settings_saved_pw_updated'));
_hideSettingsPanel();
@@ -1365,6 +1377,14 @@ async function saveSettings(andClose){
}
try{
const saved=await api('/api/settings',{method:'POST',body:JSON.stringify(body)});
if(modelChanged && model){
try{
await api('/api/default-model',{method:'POST',body:JSON.stringify({model})});
body.default_model=model;
}catch(_modelErr){
if(typeof showToast==='function') showToast('Failed to update default model — settings saved');
}
}
_applySavedSettingsUi(saved, body, {sendKey,showTokenUsage,showCliSessions,theme,skin,language,sidebarDensity});
showToast(t('settings_saved'));
_hideSettingsPanel();