mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-11 13:41:53 +00:00
fix(gateway): prevent Discord disconnects from blocking event loop
models_dev.py's fetch uses a synchronous requests.get(timeout=15). Called from the async gateway message handlers, it blocked the event loop for up to 15s, starving Discord heartbeats and causing ClientConnectionResetError disconnects. Adds get_model_context_length_async() which offloads the entire sync resolution chain to a worker thread via asyncio.to_thread(), and switches the two async gateway call sites (_prepare_inbound_message_text, _handle_message_with_agent) to await it. The loop stays responsive; the sync path remains the single source of truth for the cache. Salvaged from PR #22753 by @itenev. Follow-up: dropped the unused fetch_models_dev_async/lookup_models_dev_context_async aiohttp variants from the original PR (dead code with zero callers that had drifted from the sync cache logic) — the to_thread wrapper already runs the sync path off-loop, so they were redundant.
This commit is contained in:
parent
d57a4c197c
commit
f981d47cb0
3 changed files with 34 additions and 4 deletions
|
|
@ -2155,6 +2155,35 @@ def get_model_context_length(
|
|||
return DEFAULT_FALLBACK_CONTEXT
|
||||
|
||||
|
||||
async def get_model_context_length_async(
|
||||
model: str,
|
||||
base_url: str = "",
|
||||
api_key: str = "",
|
||||
config_context_length: int | None = None,
|
||||
provider: str = "",
|
||||
custom_providers: list | None = None,
|
||||
) -> int:
|
||||
"""Async variant of get_model_context_length.
|
||||
|
||||
Offloads the entire synchronous resolution chain (which contains
|
||||
blocking HTTP calls via ``requests``) to a background thread so it
|
||||
does not freeze the asyncio event loop and cause Discord heartbeat
|
||||
timeouts.
|
||||
|
||||
Shares all logic with the sync version — no code duplication.
|
||||
"""
|
||||
import asyncio
|
||||
return await asyncio.to_thread(
|
||||
get_model_context_length,
|
||||
model,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
config_context_length=config_context_length,
|
||||
provider=provider,
|
||||
custom_providers=custom_providers,
|
||||
)
|
||||
|
||||
|
||||
def estimate_tokens_rough(text: str) -> int:
|
||||
"""Rough token estimate (~4 chars/token) for pre-flight checks.
|
||||
|
||||
|
|
|
|||
|
|
@ -9762,7 +9762,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
if "@" in message_text:
|
||||
try:
|
||||
from agent.context_references import preprocess_context_references_async
|
||||
from agent.model_metadata import get_model_context_length
|
||||
from agent.model_metadata import get_model_context_length_async
|
||||
|
||||
_msg_cwd = os.environ.get("TERMINAL_CWD", os.path.expanduser("~"))
|
||||
_msg_runtime = _resolve_runtime_agent_kwargs()
|
||||
|
|
@ -9776,7 +9776,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
_msg_config_ctx = int(_msg_raw_ctx)
|
||||
except Exception:
|
||||
pass
|
||||
_msg_ctx_len = get_model_context_length(
|
||||
_msg_ctx_len = await get_model_context_length_async(
|
||||
self._model,
|
||||
base_url=self._base_url or _msg_runtime.get("base_url") or "",
|
||||
api_key=_msg_runtime.get("api_key") or "",
|
||||
|
|
@ -10114,7 +10114,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
if history and len(history) >= 4:
|
||||
from agent.model_metadata import (
|
||||
estimate_messages_tokens_rough,
|
||||
get_model_context_length,
|
||||
get_model_context_length_async,
|
||||
)
|
||||
|
||||
# Read model + compression config from config.yaml.
|
||||
|
|
@ -10215,7 +10215,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
pass
|
||||
|
||||
if _hyg_compression_enabled:
|
||||
_hyg_context_length = get_model_context_length(
|
||||
_hyg_context_length = await get_model_context_length_async(
|
||||
_hyg_model,
|
||||
base_url=_hyg_base_url or "",
|
||||
api_key=_hyg_api_key or "",
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json"
|
|||
|
||||
# Auto-extracted from noreply emails + manual overrides
|
||||
AUTHOR_MAP = {
|
||||
"5848605+itenev@users.noreply.github.com": "itenev", # PR #22753 salvage (asyncify model-context resolution in gateway message path so blocking requests.get can't starve Discord heartbeats)
|
||||
"290873280+rrevenanttt@users.noreply.github.com": "rrevenanttt", # PR #40773 salvage (close hardline rm bypass via quoted paths and ${HOME} brace form)
|
||||
"290871358+Vesna-9@users.noreply.github.com": "Vesna-9", # PR #41274 salvage (collapse shell line continuations before dangerous/hardline pattern matching so `rm -rf \<newline>/` can't bypass the yolo-proof hardline floor)
|
||||
"214165399+kernel-t1@users.noreply.github.com": "kernel-t1", # PR #41349 salvage (.env sanitizer: only split when line starts with a known KEY= and preceding values are plain tokens; keep URL/query/whitespace secrets verbatim)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue