Compare commits

...

1 Commits

Author SHA1 Message Date
Teknium
61540c1ab5 fix: four small CLI/config fixes — UTF-8 encoding, pairing hint, credential_pool key, header normalization
1. cli.py: add encoding='utf-8' to config file open (fixes Windows codepage issues)
   — contributed by @zhangchn (#7063)

2. hermes_cli/gateway.py: {platform} {code} → <platform> <code> in pairing hint
   — contributed by @konsisumer (#7057)

3. agent/smart_model_routing.py: add missing credential_pool key in cheap route
   — contributed by @kuishou68 (#7025)

4. agent/rate_limit_tracker.py: normalize headers to lowercase before lookup
   (RFC 7230: HTTP header names are case-insensitive)
   — contributed by @kuishou68 (#7019)
2026-04-10 05:33:24 -07:00
4 changed files with 11 additions and 6 deletions

View File

@@ -97,8 +97,12 @@ def parse_rate_limit_headers(
Returns None if no rate limit headers are present.
"""
# Normalize to lowercase so lookups work regardless of how the server
# capitalises headers (HTTP header names are case-insensitive per RFC 7230).
lowered = {k.lower(): v for k, v in headers.items()}
# Quick check: at least one rate limit header must exist
has_any = any(k.lower().startswith("x-ratelimit-") for k in headers)
has_any = any(k.startswith("x-ratelimit-") for k in lowered)
if not has_any:
return None
@@ -109,9 +113,9 @@ def parse_rate_limit_headers(
# resource="tokens", suffix="-1h" -> per-hour
tag = f"{resource}{suffix}"
return RateLimitBucket(
limit=_safe_int(headers.get(f"x-ratelimit-limit-{tag}")),
remaining=_safe_int(headers.get(f"x-ratelimit-remaining-{tag}")),
reset_seconds=_safe_float(headers.get(f"x-ratelimit-reset-{tag}")),
limit=_safe_int(lowered.get(f"x-ratelimit-limit-{tag}")),
remaining=_safe_int(lowered.get(f"x-ratelimit-remaining-{tag}")),
reset_seconds=_safe_float(lowered.get(f"x-ratelimit-reset-{tag}")),
captured_at=now,
)

View File

@@ -181,6 +181,7 @@ def resolve_turn_route(user_message: str, routing_config: Optional[Dict[str, Any
"api_mode": runtime.get("api_mode"),
"command": runtime.get("command"),
"args": list(runtime.get("args") or []),
"credential_pool": runtime.get("credential_pool"),
},
"label": f"smart route → {route.get('model')} ({runtime.get('provider')})",
"signature": (

2
cli.py
View File

@@ -319,7 +319,7 @@ def load_cli_config() -> Dict[str, Any]:
# Load from file if exists
if config_path.exists():
try:
with open(config_path, "r") as f:
with open(config_path, "r", encoding="utf-8") as f:
file_config = yaml.safe_load(f) or {}
_file_has_terminal_config = "terminal" in file_config

View File

@@ -1799,7 +1799,7 @@ def _setup_standard_platform(platform: dict):
print_warning(" Open access enabled — anyone can use your bot!")
elif access_idx == 1:
print_success(" DM pairing mode — users will receive a code to request access.")
print_info(" Approve with: hermes pairing approve {platform} {code}")
print_info(" Approve with: hermes pairing approve <platform> <code>")
else:
print_info(" Skipped — configure later with 'hermes gateway setup'")
continue