Commit graph

4 commits

Author SHA1 Message Date
Teknium
60092f728c fix(mcp): move auto-reload opt-out to top-level mcp: section + regression tests
Follow-up on the salvaged #67449: auxiliary.mcp is the side-LLM task
provider block (provider/model/timeout for MCP aux calls) — a watcher
behavior toggle doesn't belong there. Move it to a new top-level mcp:
runtime section and read it from the same freshly-parsed config.yaml the
watcher already diffs (no second load_config() per tick, and flipping the
toggle + editing mcp_servers in one edit behaves correctly).

Also adds a regression test for the salvaged #55701 false-positive fix:
${VAR} templates in mcp_servers made the raw-yaml-vs-expanded-snapshot
comparison permanently unequal, so ANY save_config_value() rewrite (e.g.
/reasoning changing agent.reasoning_effort) fired a full MCP reconnect.

Credits: @OYLFLMH (#55701 env-expand fix), @TurgutKural (#67449 opt-out).
2026-07-20 00:41:05 -07:00
Turgut Kural
1abcccdeba fix(mcp): read opt-out toggle from auxiliary.mcp, not top-level mcp
The opt-out default was declared in DEFAULT_CONFIG["auxiliary"]["mcp"][...]
but the watcher in _check_config_mcp_changes() read top-level
load_config().get("mcp") — a key that does not exist in the loaded
config shape. Consequently the declared default was never observed and
the fallback stayed True at runtime: setting auto_reload_on_config_change
to false in config.yaml silently did nothing.

Resolve through the same path the default is declared on:
  cfg["auxiliary"]["mcp"]["auto_reload_on_config_change"]

Tests:
- test_optout_disables_auto_reload: mocked config now mirrors the real
  DEFAULT_CONFIG shape (auxiliary.mcp), so the test exercises the actual
  lookup path instead of a separately mocked shape.
- test_optout_path_is_auxiliary_mcp_not_top_level: regression guard — a
  config that sets ONLY top-level mcp.auto_reload_on_config_change=false
  must NOT disable the reload. This pins the config-path contract so a
  future regression to _cfg.get("mcp") is caught.

Addresses sweeper review: the declared default was never observed at
runtime because the watcher read a different config path than the one
where the default was defined.

Co-authored-by: Turgut Kural <turgut.kural@gmail.com>
2026-07-20 00:41:05 -07:00
Turgut Kural
5c2d098bb0 feat(mcp): add opt-out for automatic MCP reload on config change (cache-safe)
The automatic MCP reload added in #1474 watches config.yaml's mcp_servers
section every 5s and reloads on any change. Every reload rebuilds the agent
tool surface and INVALIDATES the provider prompt cache — the next message
re-sends the full input prefix, which is expensive on long-context /
high-reasoning models. When config.yaml is rewritten frequently (external
tooling, multiple Hermes instances, or a flapping MCP server that rewrites
config), this causes silent, repeated cache-breaking reloads.

Add `mcp.auto_reload_on_config_change` (default: true, backward compatible).
When set to false:
- The config change is still DETECTED (watcher keeps running).
- No automatic reload happens.
- The user is told the config changed, that new settings are NOT yet
  applied, and how to apply them on their own terms with /reload-mcp —
  including the explicit warning that /reload-mcp invalidates the prompt
  cache.

Manual /reload-mcp is unaffected and still works for users who want to
apply changes deliberately.

Tests: extend TestMCPConfigWatch with test_optout_disables_auto_reload.

Co-authored-by: Turgut Kural <turgut.kural@gmail.com>
2026-07-20 00:41:05 -07:00
Siddharth Balyan
f3006ebef9
refactor(tests): re-architect tests + fix CI failures (#5946)
* refactor: re-architect tests to mirror the codebase

* Update tests.yml

* fix: add missing tool_error imports after registry refactor

* fix(tests): replace patch.dict with monkeypatch to prevent env var leaks under xdist

patch.dict(os.environ) can leak TERMINAL_ENV across xdist workers,
causing test_code_execution tests to hit the Modal remote path.

* fix(tests): fix update_check and telegram xdist failures

- test_update_check: replace patch("hermes_cli.banner.os.getenv") with
  monkeypatch.setenv("HERMES_HOME") — banner.py no longer imports os
  directly, it uses get_hermes_home() from hermes_constants.

- test_telegram_conflict/approval_buttons: provide real exception classes
  for telegram.error mock (NetworkError, TimedOut, BadRequest) so the
  except clause in connect() doesn't fail with "catching classes that do
  not inherit from BaseException" when xdist pollutes sys.modules.

* fix(tests): accept unavailable_models kwarg in _prompt_model_selection mock
2026-04-07 17:19:07 -07:00
Renamed from tests/test_cli_mcp_config_watch.py (Browse further)