reload: pick up the new code, and drop MCP tools that are gone
reload_tools reported success while three separate things kept it from
doing what it says.

The bytecode cache is keyed on (mtime in whole seconds, file size), so a
tool edited to the same length inside the same second as its previous
load re-ran the OLD code — the reload was real, the new version was not
live. The loader now compiles the source itself instead of consulting
__pycache__ (importlib.invalidate_caches() does not help here).

MCP registrations only ever grew: register_mcp_tools called
register_external, and unregister_external was used in one place, so a
server removed from the config or a tool a server stopped exposing
stayed in the registry and failed only when the model called it. Reload
now clears external tools and rebuilds them.

enabled.json naming a tool that failed to load (the gmail/html2text case)
was visible only as a log line. It is now part of the report.

The reload itself moves to navi/core/reload.py, one implementation shared
by the tool and the admin route, so the two cannot leave different
toolsets behind. list_tools.py also read enabled.json through its own
cwd-relative path, which made it disagree with the real toolset, and the
class-based loader rejected execute(self, params, ctx=None) — the shape
every built-in uses.
1 parent bd8d695 commit 4c1f2834357cf0e1a042c400b675ace534d6e62c
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 10 hours ago
Showing 8 changed files
View
navi/core/registry.py
View
navi/core/reload.py 0 → 100644
View
navi/tools/_internal/loader.py
View
navi/tools/list_tools.py
View
navi/tools/reload_tools.py
View
tests/unit/core/test_reload.py 0 → 100644
View
tests/unit/tools/test_loader.py 0 → 100644
View
tests/unit/tools/test_reload_tools.py 0 → 100644