fix(agent): preserve route URL path identity
This commit is contained in:
@@ -112,6 +112,7 @@ from agent.model_metadata import (
|
||||
strip_codex_context_variant_suffix as _strip_codex_ctx_variant,
|
||||
)
|
||||
from hermes_cli.config import get_hermes_home
|
||||
from hermes_cli.route_identity import normalize_route_base_url
|
||||
from hermes_constants import OPENROUTER_BASE_URL
|
||||
from utils import base_url_host_matches, base_url_hostname, env_float, is_truthy_value, model_forces_max_completion_tokens, normalize_proxy_env_vars
|
||||
|
||||
@@ -2903,7 +2904,7 @@ def _normalize_chain_label(provider: str) -> str:
|
||||
def _unhealthy_cache_key(provider: str, base_url: Optional[str] = None) -> Any:
|
||||
"""Provider-wide key, or endpoint-specific key for an explicit custom endpoint."""
|
||||
label = _normalize_chain_label(provider)
|
||||
endpoint = _custom_health_base_url(provider, base_url).lower().rstrip("/")
|
||||
endpoint = normalize_route_base_url(_custom_health_base_url(provider, base_url))
|
||||
if endpoint:
|
||||
return "custom-endpoint", endpoint
|
||||
return label
|
||||
|
||||
@@ -15,6 +15,8 @@ from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
from hermes_cli.route_identity import normalize_route_base_url
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -51,7 +53,8 @@ class BackendIdentity:
|
||||
base_url: Optional[str] = None,
|
||||
) -> "BackendIdentity":
|
||||
return cls(
|
||||
provider=_norm(provider), model=_norm(model), base_url=_norm(base_url).rstrip("/"),
|
||||
provider=_norm(provider), model=_norm(model),
|
||||
base_url=normalize_route_base_url(base_url),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -4156,6 +4156,19 @@ class TestAuxUnhealthyCache:
|
||||
or_try.assert_not_called()
|
||||
custom_try.assert_not_called()
|
||||
|
||||
def test_custom_health_url_identity_preserves_path_and_query_case(self):
|
||||
from agent.auxiliary_client import _is_provider_unhealthy, _mark_provider_unhealthy
|
||||
|
||||
_mark_provider_unhealthy("custom", base_url="https://Example.test/API/v1/")
|
||||
|
||||
assert _is_provider_unhealthy("custom", "https://example.TEST/API/v1") is True
|
||||
assert _is_provider_unhealthy("custom", "https://example.test/api/v1") is False
|
||||
|
||||
_mark_provider_unhealthy("custom", base_url="https://example.test/API/v1?token=AbC")
|
||||
assert _is_provider_unhealthy(
|
||||
"custom", "https://example.test/API/v1?token=abc",
|
||||
) is False
|
||||
|
||||
def test_call_llm_marks_provider_unhealthy_on_402(self, monkeypatch):
|
||||
"""A 402 from call_llm causes the provider to be marked unhealthy
|
||||
so the next call skips it instead of re-trying the same depleted
|
||||
|
||||
@@ -85,10 +85,24 @@ class TestSameCredentialSurface:
|
||||
class TestSameEndpoint:
|
||||
def test_same_explicit_url_is_same_endpoint(self):
|
||||
a = _id("a", "m1", "http://host:8000/v1/")
|
||||
b = _id("b", "m2", "http://HOST:8000/v1") # trailing slash + case
|
||||
b = _id("b", "m2", "http://HOST:8000/v1") # trailing slash + host case
|
||||
assert same_endpoint(a, b)
|
||||
assert should_skip_candidate(a, b, FailureScope.ENDPOINT)
|
||||
|
||||
def test_path_and_query_case_distinguish_endpoints(self):
|
||||
failed = _id("custom", "m", "https://Example.test/API/v1?token=AbC")
|
||||
|
||||
assert not should_skip_candidate(
|
||||
_id("custom", "m", "https://example.test/api/v1?token=AbC"),
|
||||
failed,
|
||||
FailureScope.ENDPOINT,
|
||||
)
|
||||
assert not should_skip_candidate(
|
||||
_id("custom", "m", "https://example.test/API/v1?token=abc"),
|
||||
failed,
|
||||
FailureScope.ENDPOINT,
|
||||
)
|
||||
|
||||
def test_different_urls_are_different_endpoints(self):
|
||||
assert not same_endpoint(
|
||||
_id("a", "m", "http://h1/v1"), _id("a2", "m", "http://h2/v1")
|
||||
|
||||
Reference in New Issue
Block a user