refactor(acp): rewrite imports and update infra for hermes_agent.acp

Rewrite all acp_adapter imports to hermes_agent.acp in source, tests,
and pyproject.toml. Convert relative imports to absolute per manifest
convention. Strip sys.path hack from entry.py (redundant with editable
install). Update pyproject.toml entry point and packages.find.

Part of #14586, #14182
This commit is contained in:
alt-glitch 2026-04-23 20:52:20 +05:30
parent 193f3b8339
commit 420c4d02e2
16 changed files with 61 additions and 67 deletions

2
cli.py
View file

@ -8454,7 +8454,7 @@ class HermesCLI:
# in terminal_tool is populated for this thread. The main thread
# registration (run() line ~9046) is invisible here because
# _callback_tls is threading.local(). Matches the pattern used
# by acp_adapter/server.py for ACP sessions.
# by hermes_agent/acp/server.py for ACP sessions.
set_sudo_password_callback(self._sudo_password_callback)
set_approval_callback(self._approval_callback)
try:

View file

@ -1,5 +1,5 @@
"""Allow running the ACP adapter as ``python -m acp_adapter``."""
"""Allow running the ACP adapter as ``python -m hermes_agent.acp``."""
from .entry import main
from hermes_agent.acp.entry import main
main()

View file

@ -6,7 +6,7 @@ and starts the ACP agent server.
Usage::
python -m acp_adapter.entry
python -m hermes_agent.acp.entry
# or
hermes acp
# or
@ -16,7 +16,6 @@ Usage::
import asyncio
import logging
import sys
from pathlib import Path
from hermes_constants import get_hermes_home
@ -104,13 +103,8 @@ def main() -> None:
logger = logging.getLogger(__name__)
logger.info("Starting hermes-agent ACP adapter")
# Ensure the project root is on sys.path so ``from run_agent import AIAgent`` works
project_root = str(Path(__file__).resolve().parent.parent)
if project_root not in sys.path:
sys.path.insert(0, project_root)
import acp
from .server import HermesACPAgent
from hermes_agent.acp.server import HermesACPAgent
agent = HermesACPAgent()
try:

View file

@ -15,7 +15,7 @@ from typing import Any, Callable, Deque, Dict
import acp
from .tools import (
from hermes_agent.acp.tools import (
build_tool_complete,
build_tool_start,
make_tool_call_id,

View file

@ -52,15 +52,15 @@ try:
except ImportError:
from acp.schema import AuthMethod as AuthMethodAgent # type: ignore[attr-defined]
from acp_adapter.auth import detect_provider
from acp_adapter.events import (
from hermes_agent.acp.auth import detect_provider
from hermes_agent.acp.events import (
make_message_cb,
make_step_cb,
make_thinking_cb,
make_tool_progress_cb,
)
from acp_adapter.permissions import make_approval_callback
from acp_adapter.session import SessionManager, SessionState
from hermes_agent.acp.permissions import make_approval_callback
from hermes_agent.acp.session import SessionManager, SessionState
logger = logging.getLogger(__name__)

View file

@ -8516,7 +8516,7 @@ Examples:
def cmd_acp(args):
"""Launch Hermes Agent as an ACP server."""
try:
from acp_adapter.entry import main as acp_main
from hermes_agent.acp.entry import main as acp_main
acp_main()
except ImportError:

View file

@ -117,7 +117,7 @@ all = [
[project.scripts]
hermes = "hermes_cli.main:main"
hermes-agent = "run_agent:main"
hermes-acp = "acp_adapter.entry:main"
hermes-acp = "hermes_agent.acp.entry:main"
[tool.setuptools]
py-modules = ["run_agent", "model_tools", "toolsets", "batch_runner", "trajectory_compressor", "toolset_distributions", "cli", "hermes_constants", "hermes_state", "hermes_time", "hermes_logging", "rl_cli", "utils"]
@ -126,7 +126,7 @@ py-modules = ["run_agent", "model_tools", "toolsets", "batch_runner", "trajector
hermes_cli = ["web_dist/**/*"]
[tool.setuptools.packages.find]
include = ["agent", "agent.*", "tools", "tools.*", "hermes_cli", "gateway", "gateway.*", "tui_gateway", "tui_gateway.*", "cron", "acp_adapter", "plugins", "plugins.*"]
include = ["agent", "agent.*", "tools", "tools.*", "hermes_cli", "gateway", "gateway.*", "tui_gateway", "tui_gateway.*", "cron", "hermes_agent", "hermes_agent.*", "plugins", "plugins.*"]
[tool.pytest.ini_options]
testpaths = ["tests"]

View file

@ -1,6 +1,6 @@
"""Tests for acp_adapter.auth — provider detection."""
"""Tests for hermes_agent.acp.auth — provider detection."""
from acp_adapter.auth import has_provider, detect_provider
from hermes_agent.acp.auth import has_provider, detect_provider
class TestHasProvider:

View file

@ -1,8 +1,8 @@
"""Tests for acp_adapter.entry startup wiring."""
"""Tests for hermes_agent.acp.entry startup wiring."""
import acp
from acp_adapter import entry
from hermes_agent.acp import entry
def test_main_enables_unstable_protocol(monkeypatch):

View file

@ -1,4 +1,4 @@
"""Tests for acp_adapter.events — callback factories for ACP notifications."""
"""Tests for hermes_agent.acp.events — callback factories for ACP notifications."""
import asyncio
from concurrent.futures import Future
@ -9,7 +9,7 @@ import pytest
import acp
from acp.schema import ToolCallStart, ToolCallProgress, AgentThoughtChunk, AgentMessageChunk
from acp_adapter.events import (
from hermes_agent.acp.events import (
make_message_cb,
make_step_cb,
make_thinking_cb,
@ -48,7 +48,7 @@ class TestToolProgressCallback:
cb = make_tool_progress_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
# Run callback in the event loop context
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -72,7 +72,7 @@ class TestToolProgressCallback:
cb = make_tool_progress_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -89,7 +89,7 @@ class TestToolProgressCallback:
cb = make_tool_progress_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -107,7 +107,7 @@ class TestToolProgressCallback:
progress_cb = make_tool_progress_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
step_cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -135,7 +135,7 @@ class TestThinkingCallback:
cb = make_thinking_cb(mock_conn, "session-1", loop)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -150,7 +150,7 @@ class TestThinkingCallback:
cb = make_thinking_cb(mock_conn, "session-1", loop)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
cb("")
mock_rcts.assert_not_called()
@ -169,7 +169,7 @@ class TestStepCallback:
cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, {})
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -187,7 +187,7 @@ class TestStepCallback:
cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, {})
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
cb(1, [{"name": "unknown_tool", "result": "ok"}])
mock_rcts.assert_not_called()
@ -199,7 +199,7 @@ class TestStepCallback:
cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, {})
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -218,8 +218,8 @@ class TestStepCallback:
cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, {})
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts, \
patch("acp_adapter.events.build_tool_complete") as mock_btc:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts, \
patch("hermes_agent.acp.events.build_tool_complete") as mock_btc:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -240,8 +240,8 @@ class TestStepCallback:
cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, {})
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts, \
patch("acp_adapter.events.build_tool_complete") as mock_btc:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts, \
patch("hermes_agent.acp.events.build_tool_complete") as mock_btc:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -259,8 +259,8 @@ class TestStepCallback:
cb = make_step_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts, \
patch("acp_adapter.events.build_tool_complete") as mock_btc:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts, \
patch("hermes_agent.acp.events.build_tool_complete") as mock_btc:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -280,8 +280,8 @@ class TestStepCallback:
tool_call_meta = {}
loop = event_loop_fixture
with patch("acp_adapter.events.make_tool_call_id", return_value="tc-meta"), \
patch("acp_adapter.events._send_update") as mock_send, \
with patch("hermes_agent.acp.events.make_tool_call_id", return_value="tc-meta"), \
patch("hermes_agent.acp.events._send_update") as mock_send, \
patch("agent.display.capture_local_edit_snapshot", return_value="snapshot"):
cb = make_tool_progress_cb(mock_conn, "session-1", loop, tool_call_ids, tool_call_meta)
cb("tool.started", "write_file", None, {"path": "diff-test.txt", "content": "hello"})
@ -306,7 +306,7 @@ class TestMessageCallback:
cb = make_message_cb(mock_conn, "session-1", loop)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
future = MagicMock(spec=Future)
future.result.return_value = None
mock_rcts.return_value = future
@ -321,7 +321,7 @@ class TestMessageCallback:
cb = make_message_cb(mock_conn, "session-1", loop)
with patch("acp_adapter.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
with patch("hermes_agent.acp.events.asyncio.run_coroutine_threadsafe") as mock_rcts:
cb("")
mock_rcts.assert_not_called()

View file

@ -27,9 +27,9 @@ from acp.schema import (
ToolCallStart,
)
from acp_adapter.server import HermesACPAgent
from acp_adapter.session import SessionManager
from acp_adapter.tools import build_tool_start
from hermes_agent.acp.server import HermesACPAgent
from hermes_agent.acp.session import SessionManager
from hermes_agent.acp.tools import build_tool_start
# ---------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
"""Tests for acp_adapter.permissions — ACP approval bridging."""
"""Tests for hermes_agent.acp.permissions — ACP approval bridging."""
import asyncio
from concurrent.futures import Future
@ -11,7 +11,7 @@ from acp.schema import (
DeniedOutcome,
RequestPermissionResponse,
)
from acp_adapter.permissions import make_approval_callback
from hermes_agent.acp.permissions import make_approval_callback
def _make_response(outcome):
@ -37,7 +37,7 @@ def _setup_callback(outcome, timeout=60.0):
future = MagicMock(spec=Future)
future.result.return_value = response
with patch("acp_adapter.permissions.asyncio.run_coroutine_threadsafe", return_value=future):
with patch("hermes_agent.acp.permissions.asyncio.run_coroutine_threadsafe", return_value=future):
cb = make_approval_callback(mock_rp, loop, session_id="s1", timeout=timeout)
result = cb("rm -rf /", "dangerous command")
@ -68,7 +68,7 @@ class TestApprovalMapping:
future = MagicMock(spec=Future)
future.result.side_effect = TimeoutError("timed out")
with patch("acp_adapter.permissions.asyncio.run_coroutine_threadsafe", return_value=future):
with patch("hermes_agent.acp.permissions.asyncio.run_coroutine_threadsafe", return_value=future):
cb = make_approval_callback(mock_rp, loop, session_id="s1", timeout=0.01)
result = cb("rm -rf /", "dangerous")
@ -82,7 +82,7 @@ class TestApprovalMapping:
future = MagicMock(spec=Future)
future.result.return_value = None
with patch("acp_adapter.permissions.asyncio.run_coroutine_threadsafe", return_value=future):
with patch("hermes_agent.acp.permissions.asyncio.run_coroutine_threadsafe", return_value=future):
cb = make_approval_callback(mock_rp, loop, session_id="s1", timeout=1.0)
result = cb("echo hi", "demo")

View file

@ -1,4 +1,4 @@
"""Tests for acp_adapter.entry._BenignProbeMethodFilter.
"""Tests for hermes_agent.acp.entry._BenignProbeMethodFilter.
Covers both the isolated filter logic and the full end-to-end path where a
client sends a bare JSON-RPC ``ping`` request over stdio and the acp runtime
@ -18,7 +18,7 @@ import pytest
from acp.exceptions import RequestError
from acp_adapter.entry import _BenignProbeMethodFilter
from hermes_agent.acp.entry import _BenignProbeMethodFilter
# -- Unit tests on the filter itself ----------------------------------------

View file

@ -1,4 +1,4 @@
"""Tests for acp_adapter.server — HermesACPAgent ACP server."""
"""Tests for hermes_agent.acp.server — HermesACPAgent ACP server."""
import asyncio
import os
@ -28,8 +28,8 @@ from acp.schema import (
TextContentBlock,
Usage,
)
from acp_adapter.server import HermesACPAgent, HERMES_VERSION
from acp_adapter.session import SessionManager
from hermes_agent.acp.server import HermesACPAgent, HERMES_VERSION
from hermes_agent.acp.session import SessionManager
from hermes_state import SessionDB
@ -97,7 +97,7 @@ class TestAuthenticate:
@pytest.mark.asyncio
async def test_authenticate_with_matching_method_id(self, agent, monkeypatch):
monkeypatch.setattr(
"acp_adapter.server.detect_provider",
"hermes_agent.acp.server.detect_provider",
lambda: "openrouter",
)
resp = await agent.authenticate(method_id="openrouter")
@ -106,7 +106,7 @@ class TestAuthenticate:
@pytest.mark.asyncio
async def test_authenticate_is_case_insensitive(self, agent, monkeypatch):
monkeypatch.setattr(
"acp_adapter.server.detect_provider",
"hermes_agent.acp.server.detect_provider",
lambda: "openrouter",
)
resp = await agent.authenticate(method_id="OpenRouter")
@ -115,7 +115,7 @@ class TestAuthenticate:
@pytest.mark.asyncio
async def test_authenticate_rejects_mismatched_method_id(self, agent, monkeypatch):
monkeypatch.setattr(
"acp_adapter.server.detect_provider",
"hermes_agent.acp.server.detect_provider",
lambda: "openrouter",
)
resp = await agent.authenticate(method_id="totally-invalid-method")
@ -124,7 +124,7 @@ class TestAuthenticate:
@pytest.mark.asyncio
async def test_authenticate_without_provider(self, agent, monkeypatch):
monkeypatch.setattr(
"acp_adapter.server.detect_provider",
"hermes_agent.acp.server.detect_provider",
lambda: None,
)
resp = await agent.authenticate(method_id="openrouter")
@ -272,7 +272,7 @@ class TestListAndFork:
@pytest.mark.asyncio
async def test_list_sessions_pagination_first_page(self, agent):
from acp_adapter import server as acp_server
from hermes_agent.acp import server as acp_server
infos = [
{"session_id": f"s{i}", "cwd": "/tmp", "title": None, "updated_at": 0.0}

View file

@ -1,4 +1,4 @@
"""Tests for acp_adapter.session — SessionManager and SessionState."""
"""Tests for hermes_agent.acp.session — SessionManager and SessionState."""
import contextlib
import io
@ -8,7 +8,7 @@ from types import SimpleNamespace
import pytest
from unittest.mock import MagicMock, patch
from acp_adapter.session import SessionManager, SessionState
from hermes_agent.acp.session import SessionManager, SessionState
from hermes_state import SessionDB
@ -38,7 +38,7 @@ class TestCreateSession:
def test_create_session_registers_task_cwd(self, manager, monkeypatch):
calls = []
monkeypatch.setattr("acp_adapter.session._register_task_cwd", lambda task_id, cwd: calls.append((task_id, cwd)))
monkeypatch.setattr("hermes_agent.acp.session._register_task_cwd", lambda task_id, cwd: calls.append((task_id, cwd)))
state = manager.create_session(cwd="/tmp/work")
assert calls == [(state.session_id, "/tmp/work")]

View file

@ -1,8 +1,8 @@
"""Tests for acp_adapter.tools — tool kind mapping and ACP content building."""
"""Tests for hermes_agent.acp.tools — tool kind mapping and ACP content building."""
import pytest
from acp_adapter.tools import (
from hermes_agent.acp.tools import (
TOOL_KIND_MAP,
build_tool_complete,
build_tool_start,