Fix new chats using profile default model
This commit is contained in:
1 parent
dc57d358eb
commit
19ad20afff
4 files changed
+59
-21
No files matched your search
+29
-2
@@ -1340,6 +1340,27 @@ def get_session(sid, metadata_only=False):
|
||||
return s
|
||||
raise KeyError(sid)
|
||||
|
||||
def _profile_default_model_state(profile=None):
|
||||
"""Return the default model/provider configured for *profile*."""
|
||||
default_model = ""
|
||||
default_provider = None
|
||||
try:
|
||||
from api.profiles import get_hermes_home_for_profile
|
||||
config_path = Path(get_hermes_home_for_profile(profile)) / "config.yaml"
|
||||
config_data = _cfg._load_yaml_config_file(config_path)
|
||||
except Exception:
|
||||
config_data = {}
|
||||
|
||||
model_cfg = config_data.get("model", {}) if isinstance(config_data, dict) else {}
|
||||
if isinstance(model_cfg, str):
|
||||
default_model = model_cfg.strip()
|
||||
elif isinstance(model_cfg, dict):
|
||||
default_model = str(model_cfg.get("default") or "").strip()
|
||||
default_provider = str(model_cfg.get("provider") or "").strip() or None
|
||||
|
||||
return default_model or get_effective_default_model(), default_provider
|
||||
|
||||
|
||||
def new_session(workspace=None, model=None, profile=None, model_provider=None, project_id=None, worktree_info=None):
|
||||
"""Create a new in-memory session.
|
||||
|
||||
@@ -1372,13 +1393,19 @@ def new_session(workspace=None, model=None, profile=None, model_provider=None, p
|
||||
profile = get_active_profile_name()
|
||||
except ImportError:
|
||||
profile = None
|
||||
effective_model = model or get_effective_default_model()
|
||||
if model:
|
||||
effective_model = model
|
||||
effective_model_provider = model_provider
|
||||
else:
|
||||
effective_model, effective_model_provider = _profile_default_model_state(profile)
|
||||
if model_provider:
|
||||
effective_model_provider = model_provider
|
||||
wt = worktree_info if isinstance(worktree_info, dict) else None
|
||||
workspace_path = (wt.get('path') if wt and wt.get('path') else workspace) if wt else workspace
|
||||
s = Session(
|
||||
workspace=workspace_path or get_last_workspace(),
|
||||
model=effective_model,
|
||||
model_provider=model_provider,
|
||||
model_provider=effective_model_provider,
|
||||
profile=profile,
|
||||
project_id=project_id,
|
||||
worktree_path=wt.get('path') if wt else None,
|
||||
|
||||
@@ -460,23 +460,7 @@ async function newSession(flash, options={}){
|
||||
const switchWs=S._profileSwitchWorkspace;
|
||||
S._profileSwitchWorkspace=null;
|
||||
const inheritWs=switchWs||(S.session?S.session.workspace:null)||(S._profileDefaultWorkspace||null);
|
||||
// Use the saved default model for new sessions (#872). The user's saved
|
||||
// default_model (from Settings) takes priority over the chat-header dropdown
|
||||
// value, which reflects the *previous* session's model. Fall back to the
|
||||
// dropdown value only when no default_model is configured.
|
||||
const modelSel=$('modelSelect');
|
||||
const selectedDefaultModel=window._defaultModel||(modelSel&&modelSel.value)||'';
|
||||
let defaultApplied=false;
|
||||
if(window._defaultModel&&modelSel&&typeof _applyModelToDropdown==='function'){
|
||||
defaultApplied=!!_applyModelToDropdown(window._defaultModel,modelSel,window._activeProvider||null);
|
||||
}
|
||||
const canQualify=!window._defaultModel||defaultApplied||(modelSel&&modelSel.value===selectedDefaultModel);
|
||||
const newModelState=(canQualify&&typeof _modelStateForSelect==='function')
|
||||
? _modelStateForSelect(modelSel,selectedDefaultModel)
|
||||
: {model:selectedDefaultModel,model_provider:null};
|
||||
const reqBody={
|
||||
model:newModelState.model,
|
||||
model_provider:newModelState.model_provider||null,
|
||||
workspace:inheritWs,
|
||||
profile:S.activeProfile||'default',
|
||||
};
|
||||
|
||||
@@ -266,6 +266,30 @@ def test_sessions_js_sends_profile_in_new_session_post():
|
||||
)
|
||||
|
||||
|
||||
def test_new_session_uses_explicit_profile_default_model_and_provider(tmp_path, monkeypatch):
|
||||
"""New chats must inherit the selected profile's config default."""
|
||||
import api.profiles as p
|
||||
import api.models as m
|
||||
|
||||
monkeypatch.setattr(p, "_DEFAULT_HERMES_HOME", tmp_path)
|
||||
profile_home = tmp_path / "profiles" / "pepper"
|
||||
profile_home.mkdir(parents=True)
|
||||
(profile_home / "config.yaml").write_text(
|
||||
"model:\n default: pepper-profile-model\n provider: pepper-provider\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with patch.object(m.Session, 'save', return_value=None):
|
||||
s = m.new_session(workspace=str(tmp_path), profile="pepper")
|
||||
try:
|
||||
assert s.model == "pepper-profile-model"
|
||||
assert s.model_provider == "pepper-provider"
|
||||
assert s.profile == "pepper"
|
||||
finally:
|
||||
with m.LOCK:
|
||||
m.SESSIONS.pop(s.session_id, None)
|
||||
|
||||
|
||||
def test_get_hermes_home_for_profile_rejects_path_traversal():
|
||||
"""R19j: get_hermes_home_for_profile() must reject names that don't match
|
||||
_PROFILE_ID_RE (e.g. path traversal like '../../etc') and return the base
|
||||
|
||||
@@ -1171,10 +1171,13 @@ class TestFrontendModelProviderState:
|
||||
assert "_modelStateForSelect" in src
|
||||
assert "model_provider:modelState.model_provider||null" in src
|
||||
|
||||
def test_new_session_sends_model_provider(self):
|
||||
def test_new_session_lets_profile_config_choose_default_model_provider(self):
|
||||
src = _read("static/sessions.js")
|
||||
assert "_modelStateForSelect(modelSel,selectedDefaultModel)" in src
|
||||
assert "model_provider:newModelState.model_provider||null" in src
|
||||
start = src.index("async function newSession(")
|
||||
body = src[start:src.index("const data=await api('/api/session/new'", start)]
|
||||
assert "profile:S.activeProfile||'default'" in body
|
||||
assert "model:newModelState.model" not in body
|
||||
assert "model_provider:newModelState.model_provider||null" not in body
|
||||
|
||||
def test_ui_has_json_model_state_storage(self):
|
||||
src = _read("static/ui.js")
|
||||
|
||||
Reference in new issue
Block a user