Merge PR #736: feat(honcho): async writes, memory modes, session title integration, setup CLI
Authored by erosika. Builds on #38 and #243. Adds async write support, configurable memory modes, context prefetch pipeline, 4 new Honcho tools (honcho_context, honcho_profile, honcho_search, honcho_conclude), full 'hermes honcho' CLI, session strategies, AI peer identity, recallMode A/B, gateway lifecycle management, and comprehensive docs. Cherry-picks fixes from PRs #831/#832 (adavyas). Co-authored-by: erosika <erosika@users.noreply.github.com> Co-authored-by: adavyas <adavyas@users.noreply.github.com>
This commit is contained in:
commit
475dd58a8e
26 changed files with 4688 additions and 355 deletions
|
|
@ -13,6 +13,7 @@ from unittest.mock import MagicMock, patch, PropertyMock
|
|||
|
||||
import pytest
|
||||
|
||||
from honcho_integration.client import HonchoClientConfig
|
||||
from run_agent import AIAgent
|
||||
from agent.prompt_builder import DEFAULT_AGENT_IDENTITY, PLATFORM_HINTS
|
||||
|
||||
|
|
@ -1209,17 +1210,15 @@ class TestSystemPromptStability:
|
|||
|
||||
assert "User prefers Python over JavaScript" in agent._cached_system_prompt
|
||||
|
||||
def test_honcho_prefetch_skipped_on_continuing_session(self):
|
||||
"""Honcho prefetch should not be called when conversation_history
|
||||
is non-empty (continuing session)."""
|
||||
def test_honcho_prefetch_runs_on_continuing_session(self):
|
||||
"""Honcho prefetch is consumed on continuing sessions via ephemeral context."""
|
||||
conversation_history = [
|
||||
{"role": "user", "content": "hello"},
|
||||
{"role": "assistant", "content": "hi there"},
|
||||
]
|
||||
|
||||
# The guard: `not conversation_history` is False when history exists
|
||||
should_prefetch = not conversation_history
|
||||
assert should_prefetch is False
|
||||
recall_mode = "hybrid"
|
||||
should_prefetch = bool(conversation_history) and recall_mode != "tools"
|
||||
assert should_prefetch is True
|
||||
|
||||
def test_honcho_prefetch_runs_on_first_turn(self):
|
||||
"""Honcho prefetch should run when conversation_history is empty."""
|
||||
|
|
@ -1228,6 +1227,190 @@ class TestSystemPromptStability:
|
|||
assert should_prefetch is True
|
||||
|
||||
|
||||
class TestHonchoActivation:
|
||||
def test_disabled_config_skips_honcho_init(self):
|
||||
hcfg = HonchoClientConfig(
|
||||
enabled=False,
|
||||
api_key="honcho-key",
|
||||
peer_name="user",
|
||||
ai_peer="hermes",
|
||||
)
|
||||
|
||||
with (
|
||||
patch("run_agent.get_tool_definitions", return_value=_make_tool_defs("web_search")),
|
||||
patch("run_agent.check_toolset_requirements", return_value={}),
|
||||
patch("run_agent.OpenAI"),
|
||||
patch("honcho_integration.client.HonchoClientConfig.from_global_config", return_value=hcfg),
|
||||
patch("honcho_integration.client.get_honcho_client") as mock_client,
|
||||
):
|
||||
agent = AIAgent(
|
||||
api_key="test-key-1234567890",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=False,
|
||||
)
|
||||
|
||||
assert agent._honcho is None
|
||||
assert agent._honcho_config is hcfg
|
||||
mock_client.assert_not_called()
|
||||
|
||||
def test_injected_honcho_manager_skips_fresh_client_init(self):
|
||||
hcfg = HonchoClientConfig(
|
||||
enabled=True,
|
||||
api_key="honcho-key",
|
||||
memory_mode="hybrid",
|
||||
peer_name="user",
|
||||
ai_peer="hermes",
|
||||
recall_mode="hybrid",
|
||||
)
|
||||
manager = MagicMock()
|
||||
manager._config = hcfg
|
||||
manager.get_or_create.return_value = SimpleNamespace(messages=[])
|
||||
manager.get_prefetch_context.return_value = {"representation": "Known user", "card": ""}
|
||||
|
||||
with (
|
||||
patch("run_agent.get_tool_definitions", return_value=_make_tool_defs("web_search")),
|
||||
patch("run_agent.check_toolset_requirements", return_value={}),
|
||||
patch("run_agent.OpenAI"),
|
||||
patch("honcho_integration.client.get_honcho_client") as mock_client,
|
||||
patch("tools.honcho_tools.set_session_context"),
|
||||
):
|
||||
agent = AIAgent(
|
||||
api_key="test-key-1234567890",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=False,
|
||||
honcho_session_key="gateway-session",
|
||||
honcho_manager=manager,
|
||||
honcho_config=hcfg,
|
||||
)
|
||||
|
||||
assert agent._honcho is manager
|
||||
manager.get_or_create.assert_called_once_with("gateway-session")
|
||||
manager.get_prefetch_context.assert_called_once_with("gateway-session")
|
||||
manager.set_context_result.assert_called_once_with(
|
||||
"gateway-session",
|
||||
{"representation": "Known user", "card": ""},
|
||||
)
|
||||
mock_client.assert_not_called()
|
||||
|
||||
def test_recall_mode_context_suppresses_honcho_tools(self):
|
||||
hcfg = HonchoClientConfig(
|
||||
enabled=True,
|
||||
api_key="honcho-key",
|
||||
memory_mode="hybrid",
|
||||
peer_name="user",
|
||||
ai_peer="hermes",
|
||||
recall_mode="context",
|
||||
)
|
||||
manager = MagicMock()
|
||||
manager._config = hcfg
|
||||
manager.get_or_create.return_value = SimpleNamespace(messages=[])
|
||||
manager.get_prefetch_context.return_value = {"representation": "Known user", "card": ""}
|
||||
|
||||
with (
|
||||
patch(
|
||||
"run_agent.get_tool_definitions",
|
||||
side_effect=[
|
||||
_make_tool_defs("web_search"),
|
||||
_make_tool_defs(
|
||||
"web_search",
|
||||
"honcho_context",
|
||||
"honcho_profile",
|
||||
"honcho_search",
|
||||
"honcho_conclude",
|
||||
),
|
||||
],
|
||||
),
|
||||
patch("run_agent.check_toolset_requirements", return_value={}),
|
||||
patch("run_agent.OpenAI"),
|
||||
patch("tools.honcho_tools.set_session_context"),
|
||||
):
|
||||
agent = AIAgent(
|
||||
api_key="test-key-1234567890",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=False,
|
||||
honcho_session_key="gateway-session",
|
||||
honcho_manager=manager,
|
||||
honcho_config=hcfg,
|
||||
)
|
||||
|
||||
assert "web_search" in agent.valid_tool_names
|
||||
assert "honcho_context" not in agent.valid_tool_names
|
||||
assert "honcho_profile" not in agent.valid_tool_names
|
||||
assert "honcho_search" not in agent.valid_tool_names
|
||||
assert "honcho_conclude" not in agent.valid_tool_names
|
||||
|
||||
def test_inactive_honcho_strips_stale_honcho_tools(self):
|
||||
hcfg = HonchoClientConfig(
|
||||
enabled=False,
|
||||
api_key="honcho-key",
|
||||
peer_name="user",
|
||||
ai_peer="hermes",
|
||||
)
|
||||
|
||||
with (
|
||||
patch("run_agent.get_tool_definitions", return_value=_make_tool_defs("web_search", "honcho_context")),
|
||||
patch("run_agent.check_toolset_requirements", return_value={}),
|
||||
patch("run_agent.OpenAI"),
|
||||
patch("honcho_integration.client.HonchoClientConfig.from_global_config", return_value=hcfg),
|
||||
patch("honcho_integration.client.get_honcho_client") as mock_client,
|
||||
):
|
||||
agent = AIAgent(
|
||||
api_key="test-key-1234567890",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
skip_memory=False,
|
||||
)
|
||||
|
||||
assert agent._honcho is None
|
||||
assert "web_search" in agent.valid_tool_names
|
||||
assert "honcho_context" not in agent.valid_tool_names
|
||||
mock_client.assert_not_called()
|
||||
|
||||
|
||||
class TestHonchoPrefetchScheduling:
|
||||
def test_honcho_prefetch_includes_cached_dialectic(self, agent):
|
||||
agent._honcho = MagicMock()
|
||||
agent._honcho_session_key = "session-key"
|
||||
agent._honcho.pop_context_result.return_value = {}
|
||||
agent._honcho.pop_dialectic_result.return_value = "Continue with the migration checklist."
|
||||
|
||||
context = agent._honcho_prefetch("what next?")
|
||||
|
||||
assert "Continuity synthesis" in context
|
||||
assert "migration checklist" in context
|
||||
|
||||
def test_queue_honcho_prefetch_skips_tools_mode(self, agent):
|
||||
agent._honcho = MagicMock()
|
||||
agent._honcho_session_key = "session-key"
|
||||
agent._honcho_config = HonchoClientConfig(
|
||||
enabled=True,
|
||||
api_key="honcho-key",
|
||||
recall_mode="tools",
|
||||
)
|
||||
|
||||
agent._queue_honcho_prefetch("what next?")
|
||||
|
||||
agent._honcho.prefetch_context.assert_not_called()
|
||||
agent._honcho.prefetch_dialectic.assert_not_called()
|
||||
|
||||
def test_queue_honcho_prefetch_runs_when_context_enabled(self, agent):
|
||||
agent._honcho = MagicMock()
|
||||
agent._honcho_session_key = "session-key"
|
||||
agent._honcho_config = HonchoClientConfig(
|
||||
enabled=True,
|
||||
api_key="honcho-key",
|
||||
recall_mode="hybrid",
|
||||
)
|
||||
|
||||
agent._queue_honcho_prefetch("what next?")
|
||||
|
||||
agent._honcho.prefetch_context.assert_called_once_with("session-key", "what next?")
|
||||
agent._honcho.prefetch_dialectic.assert_called_once_with("session-key", "what next?")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Iteration budget pressure warnings
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue