This commit is contained in:
commit
ff3de220d8
4 changed files with 110 additions and 8 deletions
|
|
@ -2756,7 +2756,13 @@ def set_reasoning_display(show: bool) -> dict:
|
|||
return get_reasoning_status()
|
||||
|
||||
|
||||
def set_reasoning_effort(effort: str) -> dict:
|
||||
def set_reasoning_effort(
|
||||
effort: str,
|
||||
*,
|
||||
model_id: str | None = None,
|
||||
provider_id: str | None = None,
|
||||
base_url: str | None = None,
|
||||
) -> dict:
|
||||
"""Persist ``agent.reasoning_effort`` to the active profile's config.yaml.
|
||||
|
||||
Mirrors CLI ``/reasoning <level>``: same key, same valid values
|
||||
|
|
@ -2781,7 +2787,11 @@ def set_reasoning_effort(effort: str) -> dict:
|
|||
config_data["agent"] = agent_cfg
|
||||
_save_yaml_config_file(config_path, config_data)
|
||||
reload_config()
|
||||
return get_reasoning_status()
|
||||
return get_reasoning_status(
|
||||
model_id=model_id,
|
||||
provider_id=provider_id,
|
||||
base_url=base_url,
|
||||
)
|
||||
|
||||
|
||||
def set_hermes_default_model(model_id: str) -> dict:
|
||||
|
|
|
|||
|
|
@ -7446,7 +7446,18 @@ def handle_post(handler, parsed) -> bool:
|
|||
return j(handler, set_reasoning_display(False))
|
||||
return bad(handler, f"display must be show|hide|on|off (got '{display}')")
|
||||
if effort is not None:
|
||||
return j(handler, set_reasoning_effort(effort))
|
||||
model_id = str(body.get("model") or "").strip() or None
|
||||
provider_id = str(body.get("provider") or "").strip() or None
|
||||
base_url = str(body.get("base_url") or "").strip() or None
|
||||
return j(
|
||||
handler,
|
||||
set_reasoning_effort(
|
||||
effort,
|
||||
model_id=model_id,
|
||||
provider_id=provider_id,
|
||||
base_url=base_url,
|
||||
),
|
||||
)
|
||||
return bad(handler, "reasoning: must supply 'display' or 'effort'")
|
||||
except ValueError as e:
|
||||
return bad(handler, str(e))
|
||||
|
|
|
|||
16
static/ui.js
16
static/ui.js
|
|
@ -2004,16 +2004,21 @@ function _formatReasoningEffortLabel(effort){
|
|||
return effort;
|
||||
}
|
||||
|
||||
function _reasoningEffortQuery(){
|
||||
function _reasoningEffortContext(){
|
||||
const sel=$('modelSelect');
|
||||
const model=(S&&S.session&&S.session.model)||(sel&&sel.value)||'';
|
||||
let provider=(S&&S.session&&S.session.model_provider)||'';
|
||||
if(!provider&&sel&&model&&typeof _modelStateForSelect==='function'){
|
||||
provider=_modelStateForSelect(sel, model).model_provider||'';
|
||||
}
|
||||
const params=new URLSearchParams();
|
||||
if(model) params.set('model', model);
|
||||
if(provider) params.set('provider', provider);
|
||||
const ctx={};
|
||||
if(model) ctx.model=model;
|
||||
if(provider) ctx.provider=provider;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
function _reasoningEffortQuery(){
|
||||
const params=new URLSearchParams(_reasoningEffortContext());
|
||||
const qs=params.toString();
|
||||
return qs?('?'+qs):'';
|
||||
}
|
||||
|
|
@ -2146,7 +2151,8 @@ document.addEventListener('click',function(e){
|
|||
const opt=e.target.closest('.reasoning-option');
|
||||
const effort=opt&&opt.dataset.effort;
|
||||
if(effort){
|
||||
api('/api/reasoning',{method:'POST',body:JSON.stringify({effort:effort})})
|
||||
const payload=Object.assign({effort:effort},_reasoningEffortContext());
|
||||
api('/api/reasoning',{method:'POST',body:JSON.stringify(payload)})
|
||||
.then(function(st){
|
||||
_applyReasoningChip((st&&st.reasoning_effort)||effort, st||{});
|
||||
showToast('🧠 Reasoning effort set to '+((st&&st.reasoning_effort)||effort));
|
||||
|
|
|
|||
75
tests/test_issue3958_reasoning_post_session_context.py
Normal file
75
tests/test_issue3958_reasoning_post_session_context.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import api.config as cfg
|
||||
import yaml
|
||||
|
||||
|
||||
def read(path):
|
||||
return Path(path).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_set_reasoning_effort_returns_status_for_explicit_model(tmp_path, monkeypatch):
|
||||
cfgfile = tmp_path / "config.yaml"
|
||||
cfgfile.write_text(
|
||||
yaml.safe_dump(
|
||||
{
|
||||
"model": {"default": "gpt-4o", "provider": "openai"},
|
||||
"agent": {"reasoning_effort": ""},
|
||||
},
|
||||
sort_keys=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(cfg, "_get_config_path", lambda: cfgfile)
|
||||
monkeypatch.setattr(cfg, "reload_config", lambda: None)
|
||||
|
||||
seen = {}
|
||||
|
||||
def fake_resolve(model_id, provider_id=None, base_url=None):
|
||||
seen["args"] = (model_id, provider_id, base_url)
|
||||
if model_id == "claude-opus-4-7":
|
||||
return ["minimal", "low", "medium", "high", "xhigh", "max"]
|
||||
return []
|
||||
|
||||
monkeypatch.setattr(cfg, "resolve_model_reasoning_efforts", fake_resolve)
|
||||
|
||||
status = cfg.set_reasoning_effort(
|
||||
"high",
|
||||
model_id="claude-opus-4-7",
|
||||
provider_id="anthropic",
|
||||
)
|
||||
|
||||
assert seen["args"] == ("claude-opus-4-7", "anthropic", None)
|
||||
assert status["reasoning_effort"] == "high"
|
||||
assert status["supported_efforts"] == [
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max",
|
||||
]
|
||||
|
||||
|
||||
def test_ui_posts_reasoning_context_with_effort():
|
||||
src = read("static/ui.js")
|
||||
assert "function _reasoningEffortContext()" in src
|
||||
assert "new URLSearchParams(_reasoningEffortContext())" in src
|
||||
assert "Object.assign({effort:effort},_reasoningEffortContext())" in src
|
||||
|
||||
|
||||
def test_reasoning_post_route_threads_model_context():
|
||||
src = read("api/routes.py")
|
||||
match = re.search(
|
||||
r"if parsed\.path == \"/api/reasoning\":(.*?)return bad\(handler, \"reasoning: must supply 'display' or 'effort'\"\)",
|
||||
src,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match, "The /api/reasoning POST route block must exist"
|
||||
body = match.group(1)
|
||||
assert 'body.get("model")' in body
|
||||
assert 'body.get("provider")' in body
|
||||
assert 'set_reasoning_effort(' in body
|
||||
assert "model_id=model_id" in body
|
||||
assert "provider_id=provider_id" in body
|
||||
Loading…
Reference in a new issue