mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-26 01:01:40 +00:00
Adds full ACP support enabling hermes-agent to work as a coding agent inside VS Code (via vscode-acp extension), Zed, JetBrains IDEs, and any ACP-compatible editor. ## New module: acp_adapter/ - server.py: HermesACPAgent implementing all 15 Agent protocol methods (initialize, authenticate, new/load/list/fork/resume session, prompt, cancel, set mode/model/config, on_connect) - session.py: Thread-safe SessionManager with per-session AIAgent lifecycle - events.py: Callback factories translating hermes callbacks to ACP session_update notifications (tool_call, agent_thought, agent_message) - tools.py: Tool kind mapping (20+ tools → read/edit/execute/search/fetch/think) and content builders (diffs for file edits, terminal output, text previews) - permissions.py: Bridges hermes approval_callback to ACP requestPermission RPC for dangerous command approval dialogs in the editor - auth.py: Provider credential verification - entry.py: CLI entry point with .env loading and stderr logging ## Integration points - run_agent.py: ACP tool bridge hook in _execute_tool_calls() for delegating file/terminal operations to the editor - hermes_cli/main.py: 'hermes acp' subcommand - pyproject.toml: [acp] optional dependency, hermes-acp entry point, included in [all] extras (auto-installed via install.sh) ## Supporting files - acp_registry/agent.json: ACP Registry manifest - acp_registry/icon.svg: Hermes caduceus icon - docs/acp-setup.md: User-facing setup guide for VS Code, Zed, JetBrains ## Tests - 41 new tests across 5 test files covering tools, sessions, permissions, server lifecycle, and auth - Full test suite: 2901 passed, 0 failures ## User flow 1. hermes is already installed (install.sh) 2. Install 'ACP Client' extension in VS Code 3. Configure: command='hermes', args=['acp'] 4. Chat with Hermes in the editor — diffs, terminals, approval dialogs, thinking blocks all rendered natively
44 lines
1.8 KiB
Python
44 lines
1.8 KiB
Python
"""Tests for acp_adapter.auth — provider detection."""
|
|
|
|
import pytest
|
|
|
|
from acp_adapter.auth import has_provider, detect_provider
|
|
|
|
|
|
class TestHasProvider:
|
|
def test_has_provider_with_openrouter_key(self, monkeypatch):
|
|
monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
|
|
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
|
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-test")
|
|
assert has_provider() is True
|
|
|
|
def test_has_provider_with_anthropic_key(self, monkeypatch):
|
|
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
|
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
|
monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-test")
|
|
assert has_provider() is True
|
|
|
|
def test_has_no_provider(self, monkeypatch):
|
|
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
|
monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
|
|
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
|
assert has_provider() is False
|
|
|
|
|
|
class TestDetectProvider:
|
|
def test_detect_openrouter_first(self, monkeypatch):
|
|
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-test")
|
|
monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-test")
|
|
assert detect_provider() == "openrouter"
|
|
|
|
def test_detect_anthropic_when_no_openrouter(self, monkeypatch):
|
|
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
|
monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-test")
|
|
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
|
assert detect_provider() == "anthropic"
|
|
|
|
def test_detect_none_when_empty(self, monkeypatch):
|
|
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
|
monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
|
|
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
|
assert detect_provider() is None
|