mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 01:21:43 +00:00
Merge PR #1879: feat: integrate GitHub Copilot providers
This commit is contained in:
commit
8422196e89
33 changed files with 2700 additions and 168 deletions
62
cli.py
62
cli.py
|
|
@ -1069,6 +1069,8 @@ class HermesCLI:
|
|||
self._provider_source: Optional[str] = None
|
||||
self.provider = self.requested_provider
|
||||
self.api_mode = "chat_completions"
|
||||
self.acp_command: Optional[str] = None
|
||||
self.acp_args: list[str] = []
|
||||
self.base_url = (
|
||||
base_url
|
||||
or os.getenv("OPENAI_BASE_URL")
|
||||
|
|
@ -1380,27 +1382,35 @@ class HermesCLI:
|
|||
return [("class:status-bar", f" {self._build_status_bar_text()} ")]
|
||||
|
||||
def _normalize_model_for_provider(self, resolved_provider: str) -> bool:
|
||||
"""Strip provider prefixes and swap the default model for Codex.
|
||||
|
||||
When the resolved provider is ``openai-codex``:
|
||||
|
||||
1. Strip any ``provider/`` prefix (the Codex Responses API only
|
||||
accepts bare model slugs like ``gpt-5.4``, not ``openai/gpt-5.4``).
|
||||
2. If the active model is still the *untouched default* (user never
|
||||
explicitly chose a model), replace it with a Codex-compatible
|
||||
default so the first session doesn't immediately error.
|
||||
|
||||
If the user explicitly chose a model — *any* model — we trust them
|
||||
and let the API be the judge. No allowlists, no slug checks.
|
||||
|
||||
Returns True when the active model was changed.
|
||||
"""
|
||||
if resolved_provider != "openai-codex":
|
||||
return False
|
||||
|
||||
"""Normalize provider-specific model IDs and routing."""
|
||||
current_model = (self.model or "").strip()
|
||||
changed = False
|
||||
|
||||
if resolved_provider == "copilot":
|
||||
try:
|
||||
from hermes_cli.models import copilot_model_api_mode, normalize_copilot_model_id
|
||||
|
||||
canonical = normalize_copilot_model_id(current_model, api_key=self.api_key)
|
||||
if canonical and canonical != current_model:
|
||||
if not self._model_is_default:
|
||||
self.console.print(
|
||||
f"[yellow]⚠️ Normalized Copilot model '{current_model}' to '{canonical}'.[/]"
|
||||
)
|
||||
self.model = canonical
|
||||
current_model = canonical
|
||||
changed = True
|
||||
|
||||
resolved_mode = copilot_model_api_mode(current_model, api_key=self.api_key)
|
||||
if resolved_mode != self.api_mode:
|
||||
self.api_mode = resolved_mode
|
||||
changed = True
|
||||
except Exception:
|
||||
pass
|
||||
return changed
|
||||
|
||||
if resolved_provider != "openai-codex":
|
||||
return False
|
||||
|
||||
# 1. Strip provider prefix ("openai/gpt-5.4" → "gpt-5.4")
|
||||
if "/" in current_model:
|
||||
slug = current_model.split("/", 1)[1]
|
||||
|
|
@ -1676,6 +1686,8 @@ class HermesCLI:
|
|||
base_url = runtime.get("base_url")
|
||||
resolved_provider = runtime.get("provider", "openrouter")
|
||||
resolved_api_mode = runtime.get("api_mode", self.api_mode)
|
||||
resolved_acp_command = runtime.get("command")
|
||||
resolved_acp_args = list(runtime.get("args") or [])
|
||||
if not isinstance(api_key, str) or not api_key:
|
||||
self.console.print("[bold red]Provider resolver returned an empty API key.[/]")
|
||||
return False
|
||||
|
|
@ -1687,9 +1699,13 @@ class HermesCLI:
|
|||
routing_changed = (
|
||||
resolved_provider != self.provider
|
||||
or resolved_api_mode != self.api_mode
|
||||
or resolved_acp_command != self.acp_command
|
||||
or resolved_acp_args != self.acp_args
|
||||
)
|
||||
self.provider = resolved_provider
|
||||
self.api_mode = resolved_api_mode
|
||||
self.acp_command = resolved_acp_command
|
||||
self.acp_args = resolved_acp_args
|
||||
self._provider_source = runtime.get("source")
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url
|
||||
|
|
@ -1719,6 +1735,8 @@ class HermesCLI:
|
|||
"base_url": self.base_url,
|
||||
"provider": self.provider,
|
||||
"api_mode": self.api_mode,
|
||||
"command": self.acp_command,
|
||||
"args": list(self.acp_args or []),
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -1787,6 +1805,8 @@ class HermesCLI:
|
|||
"base_url": self.base_url,
|
||||
"provider": self.provider,
|
||||
"api_mode": self.api_mode,
|
||||
"command": self.acp_command,
|
||||
"args": list(self.acp_args or []),
|
||||
}
|
||||
effective_model = model_override or self.model
|
||||
self.agent = AIAgent(
|
||||
|
|
@ -1795,6 +1815,8 @@ class HermesCLI:
|
|||
base_url=runtime.get("base_url"),
|
||||
provider=runtime.get("provider"),
|
||||
api_mode=runtime.get("api_mode"),
|
||||
acp_command=runtime.get("command"),
|
||||
acp_args=runtime.get("args"),
|
||||
max_iterations=self.max_turns,
|
||||
enabled_toolsets=self.enabled_toolsets,
|
||||
verbose_logging=self.verbose,
|
||||
|
|
@ -1831,6 +1853,8 @@ class HermesCLI:
|
|||
runtime.get("provider"),
|
||||
runtime.get("base_url"),
|
||||
runtime.get("api_mode"),
|
||||
runtime.get("command"),
|
||||
tuple(runtime.get("args") or ()),
|
||||
)
|
||||
|
||||
if self._pending_title and self._session_db:
|
||||
|
|
@ -3756,6 +3780,8 @@ class HermesCLI:
|
|||
base_url=turn_route["runtime"].get("base_url"),
|
||||
provider=turn_route["runtime"].get("provider"),
|
||||
api_mode=turn_route["runtime"].get("api_mode"),
|
||||
acp_command=turn_route["runtime"].get("command"),
|
||||
acp_args=turn_route["runtime"].get("args"),
|
||||
max_iterations=self.max_turns,
|
||||
enabled_toolsets=self.enabled_toolsets,
|
||||
quiet_mode=True,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue