mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-27 17:58:07 +00:00
fix(tui_gateway): scope secrets and MCP discovery to the active profile (#67605)
The dashboard/desktop profile switch was partial — switching to profile X ran the launch profile's resources in two ways: 1. MCP discovery was gated on the launch profile's config having mcp_servers. If the launch profile had none, the background thread never started and zero MCP servers existed for every profile. Fix: always start discovery and let discover_mcp_tools() handle the empty-config case. 2. The profile secret scope (.env credentials) was never installed on the tui_gateway path. get_secret() fell through to os.environ, resolving secrets from the launch profile instead of the selected one. Fix: install set_secret_scope(build_profile_secret_scope(...)) alongside every set_hermes_home_override() call site: - compute_host.py:_ensure_server_session (build-time) - server.py:_build (lazy resume) - server.py:_handle_resume_session (_make_agent scope) - server.py:_handle_resume_session (_init_session scope) - server.py:_handle_submit_or_edit (per-turn handler)
This commit is contained in:
parent
b93fd077c0
commit
2db6b8c85b
2 changed files with 42 additions and 0 deletions
|
|
@ -436,12 +436,15 @@ class ComputeHost:
|
|||
profile_home = str(frame.get("profile_home") or "")
|
||||
session_db = None
|
||||
home_token = None
|
||||
secret_token = None
|
||||
try:
|
||||
if profile_home:
|
||||
from hermes_constants import set_hermes_home_override
|
||||
from agent.secret_scope import build_profile_secret_scope, set_secret_scope
|
||||
from hermes_state import SessionDB
|
||||
|
||||
home_token = set_hermes_home_override(profile_home)
|
||||
secret_token = set_secret_scope(build_profile_secret_scope(Path(profile_home)))
|
||||
session_db = SessionDB(db_path=Path(profile_home) / "state.db")
|
||||
agent = server._make_agent(
|
||||
sid,
|
||||
|
|
@ -457,8 +460,10 @@ class ComputeHost:
|
|||
if home_token is not None:
|
||||
try:
|
||||
from hermes_constants import reset_hermes_home_override
|
||||
from agent.secret_scope import reset_secret_scope
|
||||
|
||||
reset_hermes_home_override(home_token)
|
||||
reset_secret_scope(secret_token)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@ from datetime import datetime
|
|||
from pathlib import Path
|
||||
from typing import Any, NamedTuple, Optional
|
||||
|
||||
from agent.secret_scope import (
|
||||
build_profile_secret_scope,
|
||||
reset_secret_scope,
|
||||
set_secret_scope,
|
||||
)
|
||||
from hermes_constants import (
|
||||
get_hermes_home,
|
||||
get_hermes_home_override,
|
||||
|
|
@ -1834,6 +1839,7 @@ def _start_agent_build(sid: str, session: dict) -> None:
|
|||
worker = None
|
||||
notify_registered = False
|
||||
home_token = None
|
||||
secret_token = None
|
||||
profile_home = current.get("profile_home")
|
||||
try:
|
||||
tokens = _set_session_context(key)
|
||||
|
|
@ -1843,6 +1849,12 @@ def _start_agent_build(sid: str, session: dict) -> None:
|
|||
session_db = None
|
||||
if profile_home:
|
||||
home_token = set_hermes_home_override(profile_home)
|
||||
try:
|
||||
from agent.secret_scope import build_profile_secret_scope, set_secret_scope
|
||||
|
||||
secret_token = set_secret_scope(build_profile_secret_scope(Path(profile_home)))
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
|
||||
|
|
@ -1963,6 +1975,13 @@ def _start_agent_build(sid: str, session: dict) -> None:
|
|||
finally:
|
||||
if home_token is not None:
|
||||
reset_hermes_home_override(home_token)
|
||||
if secret_token is not None:
|
||||
try:
|
||||
from agent.secret_scope import reset_secret_scope
|
||||
|
||||
reset_secret_scope(secret_token)
|
||||
except Exception:
|
||||
pass
|
||||
# _attach_worker already closed the worker if this session was
|
||||
# reaped mid-build; only the late notify registration can still
|
||||
# leak (session.close unregistered before _build registered it).
|
||||
|
|
@ -7474,6 +7493,11 @@ def _(rid, params: dict) -> dict:
|
|||
home_token = (
|
||||
set_hermes_home_override(str(profile_home)) if profile_home is not None else None
|
||||
)
|
||||
secret_token = (
|
||||
set_secret_scope(build_profile_secret_scope(Path(str(profile_home))))
|
||||
if profile_home is not None
|
||||
else None
|
||||
)
|
||||
try:
|
||||
db.reopen_session(target)
|
||||
# One lineage SELECT feeds both projections (see the interactive resume
|
||||
|
|
@ -7515,6 +7539,8 @@ def _(rid, params: dict) -> dict:
|
|||
finally:
|
||||
if home_token is not None:
|
||||
reset_hermes_home_override(home_token)
|
||||
if secret_token is not None:
|
||||
reset_secret_scope(secret_token)
|
||||
|
||||
# Double-checked locking: another concurrent resume may have created the
|
||||
# live session while we were building. Re-check under the lock; if it won,
|
||||
|
|
@ -7545,6 +7571,11 @@ def _(rid, params: dict) -> dict:
|
|||
if profile_home is not None
|
||||
else None
|
||||
)
|
||||
init_secret_token = (
|
||||
set_secret_scope(build_profile_secret_scope(Path(str(profile_home))))
|
||||
if profile_home is not None
|
||||
else None
|
||||
)
|
||||
try:
|
||||
_init_session(
|
||||
sid,
|
||||
|
|
@ -7559,6 +7590,8 @@ def _(rid, params: dict) -> dict:
|
|||
finally:
|
||||
if init_home_token is not None:
|
||||
reset_hermes_home_override(init_home_token)
|
||||
if init_secret_token is not None:
|
||||
reset_secret_scope(init_secret_token)
|
||||
if sid in _sessions:
|
||||
if stored_runtime_overrides.get("model_override") is not None:
|
||||
_sessions[sid]["model_override"] = stored_runtime_overrides[
|
||||
|
|
@ -11609,6 +11642,7 @@ def _run_prompt_submit(
|
|||
approval_token = None
|
||||
session_tokens = []
|
||||
home_token = None # per-turn HERMES_HOME override for a resumed remote profile
|
||||
secret_token = None
|
||||
goal_followup = None # set by the post-turn goal hook below
|
||||
tts_queue = None # streaming-TTS feed for this turn (voice mode)
|
||||
one_turn_restore = session.pop("one_turn_model_restore", None)
|
||||
|
|
@ -11641,6 +11675,7 @@ def _run_prompt_submit(
|
|||
_profile_home_str = session.get("profile_home")
|
||||
if _profile_home_str:
|
||||
home_token = set_hermes_home_override(_profile_home_str)
|
||||
secret_token = set_secret_scope(build_profile_secret_scope(Path(_profile_home_str)))
|
||||
# The sudo password callback is thread-local (tools.terminal_tool
|
||||
# _callback_tls), so wiring it on the build thread doesn't reach this
|
||||
# turn thread — terminal sudo prompts would fall through to /dev/tty
|
||||
|
|
@ -12164,6 +12199,8 @@ def _run_prompt_submit(
|
|||
pass
|
||||
if home_token is not None:
|
||||
reset_hermes_home_override(home_token)
|
||||
if secret_token is not None:
|
||||
reset_secret_scope(secret_token)
|
||||
_clear_session_context(session_tokens)
|
||||
# Clear the per-turn interim callback so a stale closure from
|
||||
# this turn can't fire during a later turn on the same agent.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue