mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-07-16 12:40:18 +00:00
fix(toolsets): only forward staged toolsets from empty composer + clear on session load (#4490 Codex follow-up)
Gate-found: staged _pendingSessionToolsets could leak into a later New Chat started from an existing session (newSession forwarded it whenever it was an array; loadSession never cleared it). Gate the forward on !S.session and clear the staged value when a real session loads. +2 regression tests. Co-authored-by: claw-io <claw-io@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- **The composer Tools chip can now stage per-session toolsets before the first conversation exists (#4490).** Applying a custom toolset from the empty composer stores it for the next new session instead of silently no-oping (the documented per-session override #493 was unreachable on a brand-new session), `/api/session/new` now accepts the staged `enabled_toolsets` value with the same structural validation as `/api/session/toolsets`, and staged values are cleared on workspace/profile context switches and when a real session loads so they cannot leak into an unrelated later New Chat. Thanks @claw-io.
|
||||
- **The composer Tools chip can now stage per-session toolsets before the first conversation exists (#4490).** Applying a custom toolset from the empty composer stores it for the next new session instead of silently no-oping (the documented per-session override #493 was unreachable on a brand-new session), `/api/session/new` now accepts the staged `enabled_toolsets` value with the same structural validation as `/api/session/toolsets`, and staged values are cleared on workspace/profile context switches and when a real session loads so they cannot leak into an unrelated later New Chat. Thanks @franksong2702.
|
||||
|
||||
## [v0.51.515] — 2026-06-19 — Release RZ (remote-gateway approvals work again + conversation history threaded)
|
||||
|
||||
|
||||
+8
-1
@@ -692,7 +692,10 @@ async function newSession(flash, options={}){
|
||||
if(S.session&&S.session.session_id) reqBody.prev_session_id=S.session.session_id;
|
||||
if(options&&options.worktree) reqBody.worktree=true;
|
||||
if(_activeProject&&_activeProject!==NO_PROJECT_FILTER) reqBody.project_id=_activeProject;
|
||||
if(Array.isArray(S._pendingSessionToolsets)) reqBody.enabled_toolsets=S._pendingSessionToolsets;
|
||||
// Only forward a pre-session toolset override staged on the empty composer
|
||||
// (no active session). Once a real session is loaded, an abandoned staged
|
||||
// value must not silently leak into a later New Chat (#4490 follow-up).
|
||||
if(!S.session && Array.isArray(S._pendingSessionToolsets)) reqBody.enabled_toolsets=S._pendingSessionToolsets;
|
||||
// Carry the visible picker selection into the new session. Without this,
|
||||
// /api/session/new falls back to config.yaml defaults (e.g. gpt-5.5) even
|
||||
// when the user already chose cursor/composer-2.5 in the composer chip.
|
||||
@@ -1069,6 +1072,10 @@ async function loadSession(sid){
|
||||
return;
|
||||
}
|
||||
S.session=data.session;
|
||||
// Loading a real existing session abandons any pre-session toolset override
|
||||
// staged on the empty composer — clear it so it can't leak into a later New
|
||||
// Chat started from this session (#4490 follow-up).
|
||||
S._pendingSessionToolsets=null;
|
||||
if(typeof _hydrateTodosFromSession==='function') _hydrateTodosFromSession(S.session);
|
||||
S.session._modelResolutionDeferred=true;
|
||||
S.lastUsage={...(data.session.last_usage||{})};
|
||||
|
||||
@@ -97,6 +97,32 @@ def test_new_session_request_consumes_pending_toolsets_once():
|
||||
assert "S._pendingSessionToolsets=null" in after_assignment
|
||||
|
||||
|
||||
def test_pending_toolsets_only_forwarded_from_empty_composer():
|
||||
"""The staged override must only be forwarded when there is no active session.
|
||||
|
||||
Without the `!S.session` guard, a toolset staged on the empty composer would
|
||||
leak into a later New Chat started from an existing session (#4490 follow-up).
|
||||
"""
|
||||
compact = SESSIONS_JS.replace(" ", "")
|
||||
post_start = compact.index("api('/api/session/new'")
|
||||
before_post = compact[:post_start]
|
||||
# The forwarding line must be gated on the no-session (empty composer) state.
|
||||
assert "!S.session&&Array.isArray(S._pendingSessionToolsets)" in before_post
|
||||
|
||||
|
||||
def test_load_existing_session_clears_staged_toolsets():
|
||||
"""Loading a real existing session must clear any abandoned staged override.
|
||||
|
||||
loadSession() assigns S.session=data.session on the success path; the staged
|
||||
value is cleared there so a subsequent New Chat does not inherit it (#4490).
|
||||
"""
|
||||
body = _function_body(SESSIONS_JS, "async function loadSession")
|
||||
compact = body.replace(" ", "")
|
||||
assign = compact.index("S.session=data.session")
|
||||
# The clear must accompany the real-session assignment, not only the create path.
|
||||
assert "S._pendingSessionToolsets=null" in compact[assign : assign + 400]
|
||||
|
||||
|
||||
def test_workspace_and_profile_switches_clear_pending_toolsets():
|
||||
for marker in (
|
||||
"function promptWorkspacePath",
|
||||
|
||||
Reference in New Issue
Block a user