test(honcho): trim salvage coverage to the invariants; drop duplicate ACP session_cwd stamp
Salvage of #93452 (@outpoints). Keep one invariant per fix: resolver-level "automatic title never remaps a strategy session", integration "provider routes by logical workspace, not process cwd", agent-level "title provenance + cwd reach the provider", deferred Desktop/TUI build threads the session cwd, seeded branch titles are derived, and the workspace-move E2E. Drop the plumbing/legacy-shape tests that re-assert the same contract. acp_adapter: AIAgent(cwd=...) now stamps session_cwd itself, so the direct assignment after construction was a duplicate.
This commit is contained in:
@@ -425,9 +425,6 @@ class SessionManager:
|
||||
logger.debug("ACP: bounded MCP discovery wait failed", exc_info=True)
|
||||
|
||||
agent = AIAgent(**kwargs)
|
||||
# Codex app-server sessions spawn lazily on the first turn; stamp the ACP
|
||||
# workspace so the Codex runtime starts from the editor cwd, not ours.
|
||||
agent.session_cwd = cwd
|
||||
# ACP stdio: stdout is protocol-only JSON-RPC; agent chatter goes to stderr.
|
||||
agent._print_fn = _acp_stderr_print
|
||||
return agent
|
||||
|
||||
@@ -116,7 +116,6 @@ class TestCreateSession:
|
||||
state = SessionManager(db=None).create_session(cwd=str(workspace))
|
||||
|
||||
assert observed["cwd"] == str(workspace)
|
||||
assert state.agent.session_cwd == str(workspace)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -145,43 +145,6 @@ class TestMemoryManagerUserIdThreading:
|
||||
assert provider._init_kwargs["cwd"] == str(tmp_path)
|
||||
agent.close()
|
||||
|
||||
@pytest.mark.parametrize("cwd", [None, ""])
|
||||
def test_cwdless_agent_still_initializes_memory_provider(self, cwd):
|
||||
from run_agent import AIAgent
|
||||
|
||||
provider = RecordingProvider()
|
||||
|
||||
with patch(
|
||||
"model_tools.get_tool_definitions",
|
||||
return_value=[],
|
||||
), patch(
|
||||
"model_tools.check_toolset_requirements",
|
||||
return_value={},
|
||||
), patch(
|
||||
"agent.process_bootstrap.OpenAI",
|
||||
), patch(
|
||||
"hermes_cli.config.load_config_readonly",
|
||||
return_value={"memory": {"provider": "recording"}},
|
||||
), patch(
|
||||
"plugins.memory.load_memory_provider",
|
||||
return_value=provider,
|
||||
):
|
||||
agent = AIAgent(
|
||||
api_key="test-key-1234567890",
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
quiet_mode=True,
|
||||
skip_context_files=True,
|
||||
platform="cli",
|
||||
session_id="session-without-cwd",
|
||||
cwd=cwd,
|
||||
)
|
||||
|
||||
assert agent.session_cwd is None
|
||||
assert provider._init_session_id == "session-without-cwd"
|
||||
assert "cwd" not in provider._init_kwargs
|
||||
agent.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Mem0 provider user_id tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -130,38 +130,6 @@ class TestResolveSessionNameTitle:
|
||||
result = cfg.resolve_session_name("/my/project", session_title="the-title")
|
||||
assert result == "manual-name"
|
||||
|
||||
@pytest.mark.parametrize("session_strategy", ["per-directory", "per-repo", "global"])
|
||||
def test_explicit_title_beats_non_session_strategy(self, session_strategy):
|
||||
cfg = HonchoClientConfig(session_strategy=session_strategy)
|
||||
result = cfg.resolve_session_name(
|
||||
"/some/dir",
|
||||
session_title="my-project",
|
||||
session_title_source="user",
|
||||
)
|
||||
assert result == "my-project"
|
||||
|
||||
def test_missing_title_source_preserves_legacy_title_override(self):
|
||||
cfg = HonchoClientConfig(session_strategy="per-repo")
|
||||
|
||||
result = cfg.resolve_session_name(
|
||||
"/some/dir",
|
||||
session_title="legacy-title",
|
||||
)
|
||||
|
||||
assert result == "legacy-title"
|
||||
|
||||
def test_title_source_parameter_preserves_legacy_positional_arguments(self):
|
||||
cfg = HonchoClientConfig(session_strategy="per-session")
|
||||
|
||||
result = cfg.resolve_session_name(
|
||||
"/some/dir",
|
||||
None,
|
||||
"session-id",
|
||||
"agent:main:telegram:dm:42",
|
||||
)
|
||||
|
||||
assert result == "agent-main-telegram-dm-42"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("session_strategy", "title_source", "expected"),
|
||||
[
|
||||
@@ -191,62 +159,6 @@ class TestResolveSessionNameTitle:
|
||||
)
|
||||
assert result == expected
|
||||
|
||||
def test_provider_preserves_strategy_for_automatic_title(self):
|
||||
from plugins.memory.honcho import HonchoMemoryProvider
|
||||
|
||||
cfg = HonchoClientConfig(session_strategy="per-repo")
|
||||
provider = HonchoMemoryProvider()
|
||||
with patch.object(HonchoClientConfig, "_git_repo_name", return_value="repo-name"):
|
||||
result = provider._resolve_session_key(
|
||||
cfg,
|
||||
"session-id",
|
||||
session_title="generated-title",
|
||||
session_title_source="llm",
|
||||
)
|
||||
assert result == "repo-name"
|
||||
|
||||
def test_provider_resolves_session_cwd_not_process_cwd(
|
||||
self,
|
||||
monkeypatch,
|
||||
tmp_path,
|
||||
):
|
||||
"""Desktop/gateway backends launch from $HOME; Honcho routing must use
|
||||
the agent's logical workspace, not the process cwd."""
|
||||
import agent.runtime_cwd as runtime_cwd
|
||||
from agent.runtime_cwd import set_session_cwd
|
||||
from plugins.memory.honcho import HonchoMemoryProvider
|
||||
|
||||
process_cwd = tmp_path / "home"
|
||||
terminal_cwd = tmp_path / "terminal"
|
||||
project = tmp_path / "projects" / "myapp"
|
||||
process_cwd.mkdir()
|
||||
terminal_cwd.mkdir()
|
||||
project.mkdir(parents=True)
|
||||
monkeypatch.chdir(process_cwd)
|
||||
monkeypatch.setenv("TERMINAL_CWD", str(terminal_cwd))
|
||||
cfg = HonchoClientConfig(
|
||||
session_strategy="per-repo",
|
||||
sessions={
|
||||
str(process_cwd): "process-cwd-fallback",
|
||||
str(terminal_cwd): "terminal-cwd-fallback",
|
||||
},
|
||||
)
|
||||
provider = HonchoMemoryProvider()
|
||||
token = set_session_cwd(str(project))
|
||||
try:
|
||||
with patch.object(
|
||||
HonchoClientConfig,
|
||||
"_git_repo_name",
|
||||
side_effect=lambda cwd: Path(cwd).name,
|
||||
) as repo_name:
|
||||
result = provider._resolve_session_key(cfg, "session-id")
|
||||
finally:
|
||||
runtime_cwd._SESSION_CWD.reset(token)
|
||||
|
||||
repo_name.assert_called_once_with(str(project))
|
||||
assert result == project.name
|
||||
|
||||
|
||||
def test_title_sanitized(self):
|
||||
cfg = HonchoClientConfig()
|
||||
result = cfg.resolve_session_name("/some/dir", session_title="my project/name!")
|
||||
|
||||
@@ -12,9 +12,6 @@ from hermes_cli.profiles import _get_default_hermes_home
|
||||
|
||||
import pytest
|
||||
|
||||
import hermes_state_common
|
||||
from hermes_state import SessionDB
|
||||
from plugins.memory.honcho import client as honcho_client
|
||||
from plugins.memory.honcho.client import (
|
||||
HonchoClientConfig,
|
||||
get_honcho_client,
|
||||
@@ -27,19 +24,6 @@ from plugins.memory.honcho.client import (
|
||||
|
||||
|
||||
class TestHonchoClientConfigDefaults:
|
||||
def test_automatic_title_sources_share_state_store_vocabulary(self):
|
||||
automatic_sources = frozenset(
|
||||
{
|
||||
hermes_state_common.TITLE_SOURCE_DERIVED,
|
||||
hermes_state_common.TITLE_SOURCE_LLM,
|
||||
}
|
||||
)
|
||||
|
||||
assert honcho_client._AUTOMATIC_SESSION_TITLE_SOURCES == automatic_sources
|
||||
assert SessionDB.TITLE_SOURCE_DERIVED == hermes_state_common.TITLE_SOURCE_DERIVED
|
||||
assert SessionDB.TITLE_SOURCE_LLM == hermes_state_common.TITLE_SOURCE_LLM
|
||||
assert SessionDB.TITLE_SOURCE_USER == hermes_state_common.TITLE_SOURCE_USER
|
||||
|
||||
def test_default_values(self):
|
||||
config = HonchoClientConfig()
|
||||
assert config.host == "hermes"
|
||||
|
||||
@@ -5,7 +5,6 @@ import sys
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -18,47 +17,6 @@ from tui_gateway.host_supervisor import (
|
||||
)
|
||||
|
||||
|
||||
def test_agent_build_receives_seeded_workspace_cwd(tmp_path, monkeypatch):
|
||||
workspace = tmp_path / "workspace"
|
||||
workspace.mkdir()
|
||||
monkeypatch.setattr(server, "_sessions", {})
|
||||
|
||||
observed: dict[str, str] = {}
|
||||
|
||||
def fake_make_agent(*_args, **_kwargs):
|
||||
observed["cwd"] = _kwargs["cwd_override"]
|
||||
return SimpleNamespace(session_id="conversation-id")
|
||||
|
||||
def fake_init_session(sid, key, agent, history, *, cwd=None, **_kwargs):
|
||||
server._sessions[sid] = {
|
||||
"agent": agent,
|
||||
"session_key": key,
|
||||
"history": history,
|
||||
"cwd": cwd,
|
||||
}
|
||||
|
||||
monkeypatch.setattr(server, "_make_agent", fake_make_agent)
|
||||
monkeypatch.setattr(server, "_transfer_db_to_agent", lambda *_args: False)
|
||||
monkeypatch.setattr(server, "_init_session", fake_init_session)
|
||||
|
||||
host = ComputeHost(stdout=io.StringIO(), heartbeat_secs=0)
|
||||
try:
|
||||
host._ensure_server_session(
|
||||
server,
|
||||
{
|
||||
"sid": "ui-session",
|
||||
"session_key": "conversation-id",
|
||||
"cwd": str(workspace),
|
||||
"source": "desktop",
|
||||
"history": [],
|
||||
},
|
||||
)
|
||||
finally:
|
||||
host.close()
|
||||
|
||||
assert observed["cwd"] == str(workspace)
|
||||
|
||||
|
||||
def _json_lines(out: io.StringIO) -> list[dict]:
|
||||
frames = []
|
||||
for line in out.getvalue().splitlines():
|
||||
|
||||
Reference in New Issue
Block a user