diff --git a/agent/rate_limit_credits.py b/agent/rate_limit_credits.py index 57962a042f..e98da3695f 100644 --- a/agent/rate_limit_credits.py +++ b/agent/rate_limit_credits.py @@ -123,10 +123,8 @@ class RateLimitCreditsMixin: """ if getattr(self, "notice_callback", None) is None and getattr(self, "notice_clear_callback", None) is None: return - if not self._credits_notices_enabled(): - return state = getattr(self, "_credits_state", None) - if state is None: + if not self._credits_notices_enabled() or state is None: return try: from agent.credits_tracker import evaluate_credits_notices, is_free_tier_model, new_credits_latch @@ -153,13 +151,12 @@ class RateLimitCreditsMixin: return cached enabled = True try: - from hermes_cli.config import load_config as _load_config - _cfg = _load_config() or {} - _display = _cfg.get("display") if isinstance(_cfg, dict) else None - if isinstance(_display, dict) and "credits_notices" in _display: - enabled = bool(_display.get("credits_notices")) + from hermes_cli.config import load_config + display = (load_config() or {}).get("display") + if isinstance(display, dict) and "credits_notices" in display: + enabled = bool(display["credits_notices"]) except Exception: - enabled = True + pass self._credits_notices_enabled_cache = enabled return enabled diff --git a/agent/rate_limit_tracker.py b/agent/rate_limit_tracker.py index 90094ab6b5..7eccdcfee9 100644 --- a/agent/rate_limit_tracker.py +++ b/agent/rate_limit_tracker.py @@ -189,16 +189,14 @@ def format_rate_limit_compact(state: RateLimitState) -> str: if not state.has_data: return "No rate limit data." - rm, rh, tm, th = state.requests_min, state.requests_hour, state.tokens_min, state.tokens_hour - - parts = [] - if rm.limit > 0: - parts.append(f"RPM: {rm.remaining}/{rm.limit}") - if rh.limit > 0: - parts.append(f"RPH: {_fmt_count(rh.remaining)}/{_fmt_count(rh.limit)} (resets {_fmt_seconds(rh.remaining_seconds_now)})") - if tm.limit > 0: - parts.append(f"TPM: {_fmt_count(tm.remaining)}/{_fmt_count(tm.limit)}") - if th.limit > 0: - parts.append(f"TPH: {_fmt_count(th.remaining)}/{_fmt_count(th.limit)} (resets {_fmt_seconds(th.remaining_seconds_now)})") - - return " | ".join(parts) + # (tag, bucket, count formatter, show reset) — RPM stays raw digits, hourly windows show the reset. + windows = ( + ("RPM", state.requests_min, str, False), + ("RPH", state.requests_hour, _fmt_count, True), + ("TPM", state.tokens_min, _fmt_count, False), + ("TPH", state.tokens_hour, _fmt_count, True), + ) + return " | ".join( + f"{tag}: {fmt(b.remaining)}/{fmt(b.limit)}" + (f" (resets {_fmt_seconds(b.remaining_seconds_now)})" if reset else "") + for tag, b, fmt, reset in windows if b.limit > 0 + ) diff --git a/agent/reactions.py b/agent/reactions.py index d1a97194bb..0312701940 100644 --- a/agent/reactions.py +++ b/agent/reactions.py @@ -39,6 +39,4 @@ _VIBE_RE = re.compile( def detect_reaction(text: str | None) -> str | None: """Return the reaction kind for *text* (currently :data:`VIBE`), or ``None``.""" - if not text: - return None - return VIBE if _VIBE_RE.search(text) else None + return VIBE if text and _VIBE_RE.search(text) else None diff --git a/agent/reasoning_params.py b/agent/reasoning_params.py index 50eebc04d1..fafdab7c04 100644 --- a/agent/reasoning_params.py +++ b/agent/reasoning_params.py @@ -122,11 +122,10 @@ class ReasoningParamsMixin: if not supported: return None - effort = "medium" - if self.reasoning_config and isinstance(self.reasoning_config, dict): - if self.reasoning_config.get("enabled") is False: - return None - effort = str(self.reasoning_config.get("effort", "medium")).strip().lower() + cfg = self.reasoning_config if isinstance(self.reasoning_config, dict) else {} + if cfg.get("enabled") is False: + return None + effort = str(cfg.get("effort", "medium")).strip().lower() if effort == "xhigh" and "xhigh" not in supported and "high" in supported: effort = "high" diff --git a/agent/retry_utils.py b/agent/retry_utils.py index 2371e352bc..96652b6fb9 100644 --- a/agent/retry_utils.py +++ b/agent/retry_utils.py @@ -38,12 +38,11 @@ def parse_retry_after_seconds(value_or_headers: Any) -> Optional[float]: if not callable(getter): return None try: - value = getter("Retry-After") - if value is None: - value = getter("retry-after") + raw = getter("Retry-After") + if raw is None: + raw = getter("retry-after") except Exception: return None - raw = value if raw is None or isinstance(raw, bool): return None if isinstance(raw, (int, float)): @@ -77,10 +76,7 @@ def jittered_backoff(attempt: int, *, base_delay: float = 5.0, max_delay: float tick = _jitter_counter exponent = max(0, attempt - 1) - if exponent >= 63 or base_delay <= 0: - delay = max_delay - else: - delay = min(base_delay * (2 ** exponent), max_delay) + delay = max_delay if (exponent >= 63 or base_delay <= 0) else min(base_delay * (2 ** exponent), max_delay) # Seed from time + counter so coarse clocks still decorrelate. seed = (time.time_ns() ^ (tick * 0x9E3779B9)) & 0xFFFFFFFF diff --git a/agent/review_idle_queue.py b/agent/review_idle_queue.py index 6f4ec3fe13..404992c534 100644 --- a/agent/review_idle_queue.py +++ b/agent/review_idle_queue.py @@ -44,16 +44,14 @@ def defer_mode(task_cfg: Optional[Dict[str, Any]]) -> str: def defer_max_age_s(task_cfg: Optional[Dict[str, Any]]) -> float: - raw = (task_cfg or {}).get("defer_max_age_s", _MAX_AGE_DEFAULT_S) try: - value = float(raw) + value = float((task_cfg or {}).get("defer_max_age_s", _MAX_AGE_DEFAULT_S)) except (TypeError, ValueError): return _MAX_AGE_DEFAULT_S return value if value > 0 else _MAX_AGE_DEFAULT_S -def review_targets_managed_local(agent: Any, - task_cfg: Optional[Dict[str, Any]]) -> bool: +def review_targets_managed_local(agent: Any, task_cfg: Optional[Dict[str, Any]]) -> bool: """Would this review fork decode on the llama-server WE manage? Resolves the review runtime as the fork will and exact-matches its netloc against @@ -63,10 +61,7 @@ def review_targets_managed_local(agent: Any, resolving the runtime on the turn's tail. """ try: - from agent.auxiliary_client import ( - _is_managed_local_endpoint, - _managed_local_netloc, - ) + from agent.auxiliary_client import _is_managed_local_endpoint, _managed_local_netloc if not _managed_local_netloc(): return False @@ -118,8 +113,7 @@ class ReviewIdleQueue: # ── queue ──────────────────────────────────────────────────── - def enqueue(self, agent: Any, session_key: str, - kwargs: Dict[str, Any]) -> None: + def enqueue(self, agent: Any, session_key: str, kwargs: Dict[str, Any]) -> None: """Add (or replace — newest snapshot wins) a session's pending review. Keeps the ORIGINAL enqueue time on coalesce so a busy session cannot push its @@ -131,8 +125,7 @@ class ReviewIdleQueue: self._pending[session_key] = _PendingReview(agent, session_key, kwargs, enqueued_at) self._ensure_thread() self._wake.set() - logger.info("Background review deferred (session=%s, queued=%d)", - session_key[-12:], len(self._pending)) + logger.info("Background review deferred (session=%s, queued=%d)", session_key[-12:], len(self._pending)) def pending_count(self) -> int: with self._lock: @@ -143,8 +136,7 @@ class ReviewIdleQueue: def _ensure_thread(self) -> None: with self._lock: if self._thread is None or not self._thread.is_alive(): - self._thread = threading.Thread( - target=self._run, daemon=True, name="bg-review-idle-queue") + self._thread = threading.Thread(target=self._run, daemon=True, name="bg-review-idle-queue") self._thread.start() def _quiet_for(self) -> float: @@ -160,17 +152,16 @@ class ReviewIdleQueue: if not self._pending: return None now = self._now() - aged = [p for p in sorted(self._pending.values(), key=lambda p: p.enqueued_at) + aged = [p for p in self._pending.values() if now - p.enqueued_at >= defer_max_age_s(p.kwargs.get("task_cfg"))] - candidate = aged[0] if aged else None + candidate = min(aged, key=lambda p: p.enqueued_at) if aged else None if candidate is None: if self._quiet_for() < _IDLE_SETTLE_S or not self._server_idle(): return None with self._lock: if not self._pending: return None - candidate = min(self._pending.values(), - key=lambda p: p.enqueued_at) + candidate = min(self._pending.values(), key=lambda p: p.enqueued_at) with self._lock: return self._pending.pop(candidate.session_key, None) @@ -187,20 +178,15 @@ class ReviewIdleQueue: if item is not None: if not self._still_enabled(item): logger.info( - "Deferred background review dropped: reviews " - "were disabled while it was queued (session=%s)", + "Deferred background review dropped: reviews were disabled while it was queued (session=%s)", item.session_key[-12:]) continue logger.info( - "Dispatching deferred background review " - "(session=%s, waited=%.0fs, queued=%d)", - item.session_key[-12:], - self._now() - item.enqueued_at, - self.pending_count()) + "Dispatching deferred background review (session=%s, waited=%.0fs, queued=%d)", + item.session_key[-12:], self._now() - item.enqueued_at, self.pending_count()) item.agent._spawn_background_review_now(**item.kwargs) except Exception: # noqa: BLE001 — dispatcher must survive anything - logger.warning("Deferred review dispatch failed", - exc_info=True) + logger.warning("Deferred review dispatch failed", exc_info=True) if item is None: time.sleep(_POLL_INTERVAL_S) diff --git a/agent/runtime_cwd.py b/agent/runtime_cwd.py index 4e173f3cfc..bf35ba37f1 100644 --- a/agent/runtime_cwd.py +++ b/agent/runtime_cwd.py @@ -58,6 +58,14 @@ def scope_terminal_cwd() -> str: return terminal_env("TERMINAL_CWD", "") +def _existing_dir(raw: str, label: str) -> Path | None: + p = Path(raw).expanduser() + if p.is_dir(): + return p + logger.warning("%s does not exist: %s", label, raw) + return None + + def _resolve_configured_cwd(*, override_is_final: bool) -> Path | None: """Session override, then TERMINAL_CWD; each validated as a real directory. @@ -67,19 +75,11 @@ def _resolve_configured_cwd(*, override_is_final: bool) -> Path | None: override = _SESSION_CWD.get() override = "" if override is _UNSET else str(override).strip() if override: - p = Path(override).expanduser() - if p.is_dir(): + p = _existing_dir(override, "configured working directory") + if p is not None or override_is_final: return p - logger.warning("configured working directory does not exist: %s", override) - if override_is_final: - return None raw = scope_terminal_cwd().strip() - if raw: - p = Path(raw).expanduser() - if p.is_dir(): - return p - logger.warning("TERMINAL_CWD does not exist: %s", raw) - return None + return _existing_dir(raw, "TERMINAL_CWD") if raw else None def resolve_agent_cwd() -> Path: diff --git a/agent/side_question.py b/agent/side_question.py index 75bc74eba8..4f4ade5c7b 100644 --- a/agent/side_question.py +++ b/agent/side_question.py @@ -113,8 +113,8 @@ def _side_question_task_config() -> Dict[str, Any]: cfg = load_config_readonly() except Exception: return {} - aux = cfg.get("auxiliary", {}) if isinstance(cfg.get("auxiliary"), dict) else {} - task = aux.get(SIDE_QUESTION_TASK, {}) + aux = cfg.get("auxiliary") + task = aux.get(SIDE_QUESTION_TASK) if isinstance(aux, dict) else None return task if isinstance(task, dict) else {} diff --git a/agent/ssl_guard.py b/agent/ssl_guard.py index d3110af382..b27ef5ecee 100644 --- a/agent/ssl_guard.py +++ b/agent/ssl_guard.py @@ -58,8 +58,7 @@ def verify_ca_bundle() -> None: logger.debug("SSL CA bundle guard skipped via HERMES_SKIP_SSL_GUARD") return for env_var in _CA_BUNDLE_ENV_VARS: - value = os.getenv(env_var) - if value: + if value := os.getenv(env_var): _validate_bundle_path(env_var, value) try: import certifi diff --git a/agent/terminal_env_registry.py b/agent/terminal_env_registry.py index 7e4fe6eb75..47d5f75639 100644 --- a/agent/terminal_env_registry.py +++ b/agent/terminal_env_registry.py @@ -30,10 +30,7 @@ BUILTIN_BACKEND_NAMES = frozenset({ def _reject_builtin_collision(name: str) -> None: - raise ValueError( - f"Terminal backend name '{name}' is reserved for the built-in " - f"{name} backend and cannot be registered by a plugin" - ) + raise ValueError(f"Terminal backend name '{name}' is reserved for the built-in {name} backend and cannot be registered by a plugin") _registry: ProviderRegistry[TerminalEnvironmentProvider] = ProviderRegistry( @@ -64,10 +61,7 @@ def provider_flag(name: str, attr: str, default=False): try: return getattr(provider, attr, default) except Exception: - logger.debug( - "Terminal environment provider '%s' attribute '%s' raised", - name, attr, exc_info=True, - ) + logger.debug("Terminal environment provider '%s' attribute '%s' raised", name, attr, exc_info=True) return default @@ -84,8 +78,5 @@ def plugin_strip_env_keys() -> frozenset: try: keys.update(provider.strip_env_keys) except Exception: - logger.debug( - "Terminal environment provider strip_env_keys raised", - exc_info=True, - ) + logger.debug("Terminal environment provider strip_env_keys raised", exc_info=True) return frozenset(keys) diff --git a/agent/thinking_timeout_guidance.py b/agent/thinking_timeout_guidance.py index 1bc28e12aa..8a6f20c78f 100644 --- a/agent/thinking_timeout_guidance.py +++ b/agent/thinking_timeout_guidance.py @@ -29,9 +29,7 @@ def is_thinking_timeout(classified: object, model: str, error_msg: str) -> bool: from agent.reasoning_timeouts import get_reasoning_stale_timeout_floor reason = getattr(classified, "reason", None) - if getattr(reason, "value", None) != "timeout": - return False - if get_reasoning_stale_timeout_floor(model) is None: + if getattr(reason, "value", None) != "timeout" or get_reasoning_stale_timeout_floor(model) is None: return False error_msg_lower = (error_msg or "").lower() return any(p in error_msg_lower for p in _THINKING_TIMEOUT_SUBSTRINGS) diff --git a/agent/transcription_registry.py b/agent/transcription_registry.py index 11a0919dd9..365f91eb8e 100644 --- a/agent/transcription_registry.py +++ b/agent/transcription_registry.py @@ -27,9 +27,8 @@ _BUILTIN_NAMES = frozenset({ def _warn_builtin_collision(key: str) -> None: logger.warning( - "Transcription provider '%s' shadows a built-in name; registration " - "ignored. Built-in STT providers (%s) always win — pick a different " - "name.", + "Transcription provider '%s' shadows a built-in name; registration ignored. " + "Built-in STT providers (%s) always win — pick a different name.", key, ", ".join(sorted(_BUILTIN_NAMES)), )