agent: a profile switch now survives the turn that made it
switch_profile repoints the session with one narrow UPDATE, and the run's own
save() — which lands right after every tool batch, the switch's own batch
included — wrote its stale in-memory profile back over it. The post-turn
reload then read the row it had just clobbered, saw no change, and left the
turn bound to the old profile's tools: the agent called exactly the tools
switch_profile had just advertised ("Newly available: ssh_exec, terminal, …")
and got "tool not found" for every one of them. Prod shows both halves — the
session that reported two switches kept the profile it started with, and
agent.profile_reloaded appears zero times in the whole boot.

The reload now compares against the profile the run is bound to
(bound_profile_id), which set_profile cannot move, instead of against
session.profile_id, which the store either rewrites or mutates to the new
value — making the old guard false in both branches by construction. And
save() leaves the profile_id column alone on conflict: set_profile owns it
after creation, the same way name/created_at are owned elsewhere.

A tool the live tool_map does not hold is now logged (tool.not_found, with
profile and live tool count). It previously left no trace at all in the
journal, which is why this took a database dig to find.

Three tests, each verified to fail without its fix: the next LLM call is
offered the new profile's tools, save() does not rewrite profile_id, and a
missing tool is logged.
1 parent 718ed53 commit 25843cca40f1a81f7662b9b69e94ef1023dc9b58
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 5 hours ago
Showing 8 changed files
View
docs/mechanics.md
View
docs/profiles.md
View
navi/core/agent.py
View
navi/core/pg_session_store.py
View
navi/core/tool_executor.py
View
tests/unit/core/test_agent.py
View
tests/unit/core/test_pg_session_store.py
View
tests/unit/core/test_tool_executor.py