fix(tui-gateway): stale session_id is refused once at the config.set seam for every session-scoped key
Sweep of the #119983 shape: `reasoning` had the same stale-session -> global-write fall-through as `fast`/`yolo` (a reaped session_id wrote agent.reasoning_effort into config.yaml and answered success), and `model` already carried its own 4001. One check at the dispatcher replaces the three per-handler guards: a non-empty session_id this backend no longer holds, on a key whose sessionless branch writes a wider scope (config.yaml agent.*, the process env every later child inherits), answers 4001 so the client resumes. `scope="global"` is still honoured; a request with no session_id at all is still the sessionless path. Live (temp home, stale id): base wrote reasoning_effort: high and HERMES_YOLO_MODE=1; head leaves config.yaml and os.environ byte-identical and answers 4001 for all three.
This commit is contained in:
@@ -162,10 +162,6 @@ _FAST_WORDS = {"fast": "fast", "on": "fast", "normal": "normal", "off": "normal"
|
||||
|
||||
|
||||
def _set_fast(rid, params, key, value, session):
|
||||
if session is None and params.get("session_id"):
|
||||
# A runtime id this backend no longer holds (reaped / re-minted) must not reach the sessionless
|
||||
# branch: it persists agent.service_tier for every surface. 4001 lets the client resume it.
|
||||
return _sess_nowait(params, rid)[1]
|
||||
raw = _word(value)
|
||||
agent = session.get("agent") if session else None
|
||||
if agent is not None:
|
||||
@@ -282,10 +278,6 @@ def _set_yolo(rid, params, key, value, session):
|
||||
enable = _BOOL_WORDS.get(raw, not is_session_yolo_enabled(skey))
|
||||
(enable_session_yolo if enable else disable_session_yolo)(skey)
|
||||
_emit_session_info(params.get("session_id", ""), session)
|
||||
elif params.get("session_id"):
|
||||
# Stale runtime id: the process flag below never reaches this session's approvals, yet every
|
||||
# child spawned afterwards (compute host, a terminal's `hermes`) inherits the flip.
|
||||
return _sess_nowait(params, rid)[1]
|
||||
else:
|
||||
enable = _BOOL_WORDS.get(raw, not is_truthy_value(os.environ.get("HERMES_YOLO_MODE")))
|
||||
if enable:
|
||||
@@ -479,12 +471,21 @@ _CONFIG_SETTERS = {
|
||||
"cwd": _set_cwd, "terminal.cwd": _set_cwd, "workdir": _set_cwd,
|
||||
"prompt": _set_prompt, "personality": _set_personality, "skin": _set_skin}
|
||||
|
||||
# Keys whose sessionless branch writes a different, wider scope than the session branch (config.yaml's
|
||||
# agent.* for every surface, the process env every later child inherits). A non-empty session_id this
|
||||
# backend no longer holds (reaped / re-minted) is a stale session, not "no session": it answers 4001 so
|
||||
# the client resumes, never the global write. An explicit scope="global" is still honoured.
|
||||
_SESSION_SCOPED_KEYS = frozenset({"model", "fast", "yolo", "reasoning"})
|
||||
|
||||
|
||||
@method("config.set")
|
||||
@_profile_scoped
|
||||
def _(rid, params: dict) -> dict:
|
||||
key, value = params.get("key", ""), params.get("value", "")
|
||||
session = _sessions.get(params.get("session_id", ""))
|
||||
if session is None and params.get("session_id") and key in _SESSION_SCOPED_KEYS \
|
||||
and _word(params.get("scope")) != "global":
|
||||
return _sess_nowait(params, rid)[1]
|
||||
handler = _CONFIG_SETTERS.get(key)
|
||||
if handler is None and key.startswith("details_mode."):
|
||||
handler = _set_details_section
|
||||
|
||||
Reference in New Issue
Block a user