fix(honcho): isolate session routing for multi-user gateway (#1500)
Salvaged from PR #1470 by adavyas. Core fix: Honcho tool calls in a multi-session gateway could route to the wrong session because honcho_tools.py relied on process-global state. Now threads session context through the call chain: AIAgent._invoke_tool() → handle_function_call() → registry.dispatch() → handler **kw → _resolve_session_context() Changes: - Add _resolve_session_context() to prefer per-call context over globals - Plumb honcho_manager + honcho_session_key through handle_function_call - Add sync_honcho=False to run_conversation() for synthetic flush turns - Pass honcho_session_key through gateway memory flush lifecycle - Harden gateway PID detection when /proc cmdline is unreadable - Make interrupt test scripts import-safe for pytest-xdist - Wrap BibTeX examples in Jekyll raw blocks for docs build - Fix thread-order-dependent assertion in client lifecycle test - Expand Honcho docs: session isolation, lifecycle, routing internals Dropped from original PR: - Indentation change in _create_request_openai_client that would move client creation inside the lock (causes unnecessary contention) Co-authored-by: adavyas <adavyas@users.noreply.github.com>
This commit is contained in:
parent
eb4f0348e1
commit
dd7921d514
17 changed files with 522 additions and 252 deletions
|
|
@ -930,8 +930,10 @@ class TestConcurrentToolExecution:
|
|||
mock_hfc.assert_called_once_with(
|
||||
"web_search", {"q": "test"}, "task-1",
|
||||
enabled_tools=list(agent.valid_tool_names),
|
||||
honcho_manager=None,
|
||||
honcho_session_key=None,
|
||||
)
|
||||
assert result == "result"
|
||||
assert result == "result"
|
||||
|
||||
def test_invoke_tool_handles_agent_level_tools(self, agent):
|
||||
"""_invoke_tool should handle todo tool directly."""
|
||||
|
|
@ -1584,6 +1586,38 @@ class TestSystemPromptStability:
|
|||
should_prefetch = not conversation_history
|
||||
assert should_prefetch is True
|
||||
|
||||
def test_run_conversation_can_skip_honcho_sync_for_synthetic_turns(self, agent):
|
||||
captured = {}
|
||||
|
||||
def _fake_api_call(api_kwargs):
|
||||
captured.update(api_kwargs)
|
||||
return _mock_response(content="done", finish_reason="stop")
|
||||
|
||||
agent._honcho = MagicMock()
|
||||
agent._honcho_session_key = "session-1"
|
||||
agent._honcho_config = SimpleNamespace(
|
||||
ai_peer="hermes",
|
||||
memory_mode="hybrid",
|
||||
write_frequency="async",
|
||||
recall_mode="hybrid",
|
||||
)
|
||||
agent._use_prompt_caching = False
|
||||
|
||||
with (
|
||||
patch.object(agent, "_honcho_sync") as mock_sync,
|
||||
patch.object(agent, "_queue_honcho_prefetch") as mock_prefetch,
|
||||
patch.object(agent, "_persist_session"),
|
||||
patch.object(agent, "_save_trajectory"),
|
||||
patch.object(agent, "_cleanup_task_resources"),
|
||||
patch.object(agent, "_interruptible_api_call", side_effect=_fake_api_call),
|
||||
):
|
||||
result = agent.run_conversation("synthetic flush turn", sync_honcho=False)
|
||||
|
||||
assert result["completed"] is True
|
||||
assert captured["messages"][-1]["content"] == "synthetic flush turn"
|
||||
mock_sync.assert_not_called()
|
||||
mock_prefetch.assert_not_called()
|
||||
|
||||
|
||||
class TestHonchoActivation:
|
||||
def test_disabled_config_skips_honcho_init(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue