fix(chat): keep new session model authoritative
This commit is contained in:
1 parent
af1ee81f06
commit
6bcc9689aa
3 files changed
+51
-11
No files matched your search
+19
-9
@@ -1576,20 +1576,30 @@ function applyBotName(){
|
|||||||
// options are enough for first paint; the dynamic provider list can settle
|
// options are enough for first paint; the dynamic provider list can settle
|
||||||
// after the saved session is visible.
|
// after the saved session is visible.
|
||||||
const _hydrateBootModelDropdown=()=>populateModelDropdown().then(()=>{
|
const _hydrateBootModelDropdown=()=>populateModelDropdown().then(()=>{
|
||||||
|
const sessionModelState=S.session&&S.session.model
|
||||||
|
? {model:S.session.model,model_provider:S.session.model_provider||null}
|
||||||
|
: null;
|
||||||
const savedState=(typeof _readPersistedModelState==='function')
|
const savedState=(typeof _readPersistedModelState==='function')
|
||||||
? _readPersistedModelState()
|
? _readPersistedModelState()
|
||||||
: (localStorage.getItem('hermes-webui-model')?{model:localStorage.getItem('hermes-webui-model'),model_provider:null}:null);
|
: (localStorage.getItem('hermes-webui-model')?{model:localStorage.getItem('hermes-webui-model'),model_provider:null}:null);
|
||||||
const savedModel=savedState&&savedState.model;
|
// Active sessions are authoritative. On fresh boot without a restored
|
||||||
// Guardrail: prefer profile/server default on boot when available.
|
// session, keep the profile/server default ahead of stale browser model
|
||||||
// Persisted browser model state should not override a valid default model.
|
// state when a default exists.
|
||||||
const allowBootSavedModelOverride=!window._defaultModel;
|
const stateToApply=sessionModelState||(!window._defaultModel?savedState:null);
|
||||||
if(savedModel && $('modelSelect') && allowBootSavedModelOverride){
|
const savedModel=stateToApply&&stateToApply.model;
|
||||||
|
if(savedModel && $('modelSelect')){
|
||||||
const applied=(typeof _applyModelToDropdown==='function')
|
const applied=(typeof _applyModelToDropdown==='function')
|
||||||
? _applyModelToDropdown(savedModel,$('modelSelect'),savedState.model_provider||null)
|
? (sessionModelState
|
||||||
|
? _applyModelToDropdown(sessionModelState.model,$('modelSelect'),sessionModelState.model_provider||null)
|
||||||
|
: _applyModelToDropdown(savedState.model,$('modelSelect'),savedState.model_provider||null))
|
||||||
: null;
|
: null;
|
||||||
if(!applied) $('modelSelect').value=savedModel;
|
if(!applied) $('modelSelect').value=stateToApply.model;
|
||||||
// If the value didn't take (model not in list), clear the bad pref
|
// If the value didn't take (model not in list), clear the bad pref only
|
||||||
if(!applied&&$('modelSelect').value!==savedModel){
|
// for persisted browser preferences. Active sessions remain authoritative.
|
||||||
|
if(!applied&&sessionModelState&&typeof _ensureModelOptionInDropdown==='function'){
|
||||||
|
_ensureModelOptionInDropdown(sessionModelState.model,$('modelSelect'),sessionModelState.model_provider||null);
|
||||||
|
}
|
||||||
|
else if(!applied&&!sessionModelState&&$('modelSelect').value!==stateToApply.model){
|
||||||
if(typeof _clearPersistedModelState==='function') _clearPersistedModelState();
|
if(typeof _clearPersistedModelState==='function') _clearPersistedModelState();
|
||||||
else {
|
else {
|
||||||
localStorage.removeItem('hermes-webui-model');
|
localStorage.removeItem('hermes-webui-model');
|
||||||
|
|||||||
+11
-2
@@ -490,8 +490,17 @@ async function newSession(flash, options={}){
|
|||||||
const sessionProvider=S.session.model_provider||null;
|
const sessionProvider=S.session.model_provider||null;
|
||||||
const currentProvider=currentModelState.model_provider||null;
|
const currentProvider=currentModelState.model_provider||null;
|
||||||
if(S.session.model!==modelSel.value || sessionProvider !== currentProvider){
|
if(S.session.model!==modelSel.value || sessionProvider !== currentProvider){
|
||||||
_applyModelToDropdown(S.session.model,modelSel,sessionProvider);
|
let sessionModelApplied=_applyModelToDropdown(S.session.model,modelSel,sessionProvider);
|
||||||
if(typeof syncModelChip==='function') syncModelChip();
|
if(!sessionModelApplied){
|
||||||
|
const opt=document.createElement('option');
|
||||||
|
opt.value=S.session.model;
|
||||||
|
opt.textContent=typeof getModelLabel==='function'?getModelLabel(S.session.model):S.session.model;
|
||||||
|
opt.dataset.custom='1';
|
||||||
|
opt.dataset.provider=sessionProvider||'';
|
||||||
|
modelSel.appendChild(opt);
|
||||||
|
sessionModelApplied=_applyModelToDropdown(S.session.model,modelSel,sessionProvider);
|
||||||
|
}
|
||||||
|
if(sessionModelApplied&&typeof syncModelChip==='function') syncModelChip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Reset per-session visual state: a fresh chat is idle even if another
|
// Reset per-session visual state: a fresh chat is idle even if another
|
||||||
|
|||||||
@@ -35,6 +35,27 @@ def test_new_chat_syncs_model_picker_when_default_provider_changes_but_model_id_
|
|||||||
assert "_applyModelToDropdown(S.session.model,modelSel,sessionProvider)" in fn
|
assert "_applyModelToDropdown(S.session.model,modelSel,sessionProvider)" in fn
|
||||||
|
|
||||||
|
|
||||||
|
def test_new_chat_inserts_session_model_when_static_picker_lacks_default():
|
||||||
|
fn = _new_session_function()
|
||||||
|
assert "sessionModelApplied" in fn
|
||||||
|
assert "document.createElement('option')" in fn
|
||||||
|
assert "opt.value=S.session.model" in fn
|
||||||
|
assert "opt.dataset.provider=sessionProvider||''" in fn
|
||||||
|
assert "modelSel.appendChild(opt)" in fn
|
||||||
|
|
||||||
|
|
||||||
|
def test_boot_model_hydration_prefers_active_session_over_persisted_model():
|
||||||
|
boot_js = Path("static/boot.js").read_text(encoding="utf-8")
|
||||||
|
marker = "const sessionModelState=S.session&&S.session.model"
|
||||||
|
assert marker in boot_js
|
||||||
|
session_branch = boot_js[boot_js.index(marker) : boot_js.index("if(S.session) syncTopbar();", boot_js.index(marker))]
|
||||||
|
assert "_applyModelToDropdown(sessionModelState.model,$('modelSelect'),sessionModelState.model_provider||null)" in session_branch
|
||||||
|
assert "savedState" in session_branch
|
||||||
|
assert session_branch.index("sessionModelState") < session_branch.index("savedState"), (
|
||||||
|
"active session model must be considered before localStorage so stale saved model preferences cannot override new chats"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_new_chat_does_not_send_stale_dropdown_model_when_session_has_default_model():
|
def test_new_chat_does_not_send_stale_dropdown_model_when_session_has_default_model():
|
||||||
assert "model:S.session.model||$('modelSelect').value" in MESSAGES_JS
|
assert "model:S.session.model||$('modelSelect').value" in MESSAGES_JS
|
||||||
assert "model_provider:S.session.model_provider||null" in MESSAGES_JS
|
assert "model_provider:S.session.model_provider||null" in MESSAGES_JS
|
||||||
|
|||||||
Reference in new issue
Block a user