d364473620
vertex, bedrock and copilot-acp each overrode ProviderProfile.fetch_models with an identical `return None`, and the overrides could not simply be deleted because the base implementation derives a URL from base_url and would GET e.g. bedrock-runtime.../models or acp://copilot/models. ProviderProfile now carries `supports_model_listing` (default True); the base fetch_models returns None before touching the network when it is False, and the three SDK/subprocess-backed profiles set it in their constructors instead of overriding. Separately, two catalog GETs still went through bare urllib.request.urlopen: commandcode's fetch_models and hermes_cli.models._fetch_ai_gateway_models (which sends the AI Gateway bearer). Both now use the redirect-safe open_credentialed_url path (_urlopen_model_catalog_request in models.py, also applied to the unauthenticated fetch_ai_gateway_models for consistency). This is a security behavior change: a cross-origin redirect from either endpoint no longer forwards the Authorization/attribution headers to the redirect target. The AI Gateway tests that patched the global urlopen are repointed at hermes_cli.models._urlopen_model_catalog_request (the seam tests/hermes_cli/test_models.py already uses), the commandcode test patches open_credentialed_url on the plugin module, and two invariant tests pin the no-network guard and the bearer routing.
41 lines
1.6 KiB
Python
41 lines
1.6 KiB
Python
"""GitHub Copilot ACP provider profile.
|
|
|
|
copilot-acp does not speak OpenAI-over-HTTP: it drives an external ACP subprocess over
|
|
stdio, so the profile supplies its own client via :meth:`ProviderProfile.create_client`.
|
|
An out-of-tree ACP provider (``~/.hermes/plugins/model-providers/`` or a pip entry point)
|
|
uses the same three lines without touching core.
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
from providers import register_provider
|
|
from providers.base import ProviderProfile
|
|
|
|
|
|
class CopilotACPProfile(ProviderProfile):
|
|
"""GitHub Copilot ACP — external process, no REST models endpoint."""
|
|
|
|
def create_client(self, **client_kwargs: Any) -> Any:
|
|
"""Build the ACP stdio shim rather than an HTTP client."""
|
|
from agent.copilot_acp_client import CopilotACPClient
|
|
|
|
return CopilotACPClient(**client_kwargs)
|
|
|
|
|
|
copilot_acp = CopilotACPProfile(
|
|
name="copilot-acp", aliases=("github-copilot-acp", "copilot-acp-agent"),
|
|
api_mode="chat_completions", # ACP subprocess uses chat_completions routing
|
|
env_vars=(), # Managed by ACP subprocess
|
|
base_url="acp://copilot", # ACP internal scheme
|
|
auth_type="external_process",
|
|
supports_model_listing=False, # model listing is handled by the ACP subprocess
|
|
# How to launch the CLI; env var names predate this profile (formerly hardcoded in
|
|
# hermes_cli/auth.py), so existing setups keep working.
|
|
process_command="copilot",
|
|
process_args=("--acp", "--stdio"),
|
|
process_command_env_vars=("HERMES_COPILOT_ACP_COMMAND", "COPILOT_CLI_PATH"),
|
|
process_args_env_var="HERMES_COPILOT_ACP_ARGS",
|
|
)
|
|
|
|
register_provider(copilot_acp)
|