87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
"""An external-process (ACP) provider can ship from outside this tree.
|
|
|
|
The known-provider gate, the binary, the argv and the env var names used to be
|
|
spelled out for one vendor, so a profile registered from a plugin died with
|
|
"Unknown provider" before any client was built. This registers a provider the
|
|
way a standalone package does — before importing ``hermes_cli`` — and walks the
|
|
real resolution path, asserting ``copilot-acp`` is unchanged alongside it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import stat
|
|
|
|
import pytest
|
|
|
|
from providers import register_provider
|
|
from providers.base import ProviderProfile
|
|
|
|
|
|
class _AcmeACPProfile(ProviderProfile):
|
|
def create_client(self, **kwargs):
|
|
return ("acme-client", kwargs)
|
|
|
|
def fetch_models(self, **kwargs):
|
|
return None
|
|
|
|
|
|
register_provider(
|
|
_AcmeACPProfile(
|
|
name="acme-acp",
|
|
aliases=("acme",),
|
|
display_name="Acme ACP",
|
|
base_url="acp://acme",
|
|
auth_type="external_process",
|
|
process_command="acme-cli",
|
|
process_args=("--acp",),
|
|
process_command_env_vars=("ACME_CLI_PATH",),
|
|
process_args_env_var="ACME_ACP_ARGS",
|
|
)
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def fake_cli(tmp_path, monkeypatch):
|
|
bindir = tmp_path / "bin"
|
|
bindir.mkdir()
|
|
for name in ("acme-cli", "copilot", "custom-acme"):
|
|
exe = bindir / name
|
|
exe.write_text("#!/bin/sh\nexit 0\n")
|
|
exe.chmod(exe.stat().st_mode | stat.S_IEXEC)
|
|
monkeypatch.setenv("PATH", f"{bindir}{os.pathsep}{os.environ.get('PATH', '')}")
|
|
return bindir
|
|
|
|
|
|
def test_an_out_of_tree_external_process_provider_resolves_end_to_end(fake_cli, monkeypatch):
|
|
from hermes_cli.auth import PROVIDER_REGISTRY, resolve_external_process_provider_credentials, resolve_provider
|
|
from hermes_cli.runtime_provider import resolve_runtime_provider
|
|
|
|
assert PROVIDER_REGISTRY["acme"] is PROVIDER_REGISTRY["acme-acp"]
|
|
assert PROVIDER_REGISTRY["acme-acp"].auth_type == "external_process"
|
|
assert resolve_provider("acme") == "acme-acp"
|
|
|
|
creds = resolve_external_process_provider_credentials("acme-acp")
|
|
assert (creds["command"], creds["args"], creds["api_key"]) == (str(fake_cli / "acme-cli"), ["--acp"], "acme-acp")
|
|
|
|
monkeypatch.setenv("ACME_CLI_PATH", str(fake_cli / "custom-acme"))
|
|
monkeypatch.setenv("ACME_ACP_ARGS", "--acp=true --verbose")
|
|
creds = resolve_external_process_provider_credentials("acme-acp")
|
|
assert (creds["command"], creds["args"]) == (str(fake_cli / "custom-acme"), ["--acp=true", "--verbose"])
|
|
|
|
runtime = resolve_runtime_provider(requested="acme", target_model="acme")
|
|
assert (runtime["provider"], runtime["base_url"], runtime["source"]) == ("acme-acp", "acp://acme", "process")
|
|
|
|
|
|
def test_copilot_acp_launch_details_are_unchanged(fake_cli, monkeypatch):
|
|
from hermes_cli.auth import resolve_external_process_provider_credentials
|
|
from hermes_cli.runtime_provider import resolve_runtime_provider
|
|
|
|
creds = resolve_external_process_provider_credentials("copilot-acp")
|
|
assert creds["command"] == str(fake_cli / "copilot")
|
|
assert (creds["args"], creds["api_key"], creds["base_url"]) == (["--acp", "--stdio"], "copilot-acp", "acp://copilot")
|
|
|
|
monkeypatch.setenv("COPILOT_CLI_PATH", str(fake_cli / "custom-acme"))
|
|
assert resolve_external_process_provider_credentials("copilot-acp")["command"] == str(fake_cli / "custom-acme")
|
|
assert resolve_runtime_provider(requested="copilot-acp", target_model="x")["base_url"] == "acp://copilot"
|