mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
fix(cron): scope inline calls to reported transport
This commit is contained in:
parent
47c91e4c34
commit
02063ece11
3 changed files with 31 additions and 16 deletions
|
|
@ -293,22 +293,18 @@ def _dispatch_nonstreaming_api_request(agent, api_kwargs: dict, *, make_client):
|
|||
|
||||
|
||||
def should_use_direct_api_call(agent) -> bool:
|
||||
"""True when the LLM call must run inline instead of on the interrupt worker.
|
||||
"""Whether a cron OpenAI-wire request should skip the interrupt worker.
|
||||
|
||||
``interruptible_api_call`` / ``interruptible_streaming_api_call`` run every
|
||||
request on a spawned daemon worker so the conversation loop can poll for an
|
||||
interactive interrupt during the blocking HTTP round-trip. Cron jobs execute
|
||||
their turn inside the gateway's *nested* thread pools (cron-scheduler →
|
||||
parallel/sequential pool → per-job pool → ``run_conversation``); stacking the
|
||||
interrupt worker on top of that wedges before the socket even opens on the
|
||||
2nd+ call of a tool-using turn (#62151), while the identical job runs fine
|
||||
via ``hermes cron tick`` (foreground, no nested gateway pools). Cron has no
|
||||
interactive interrupt surface — its only stop signal is the scheduler's
|
||||
inactivity watchdog, which fires from the outer thread — so running inline
|
||||
removes the deadlock class without giving anything up. This predicate is the
|
||||
single extension point for any future non-interactive, nested-pool context.
|
||||
Issue #62151 is specific to OpenRouter's chat-completions path inside the
|
||||
gateway cron thread stack. Keep native/Codex/Bedrock/MoA transports on their
|
||||
established workers: their cancellation and client ownership differ, and
|
||||
the report provides no evidence that those paths share the pre-HTTP wedge.
|
||||
"""
|
||||
return getattr(agent, "platform", None) == "cron"
|
||||
return (
|
||||
getattr(agent, "platform", None) == "cron"
|
||||
and getattr(agent, "api_mode", None) == "chat_completions"
|
||||
and getattr(agent, "provider", None) != "moa"
|
||||
)
|
||||
|
||||
|
||||
def direct_api_call(agent, api_kwargs: dict):
|
||||
|
|
|
|||
|
|
@ -40,12 +40,21 @@ def _make_agent(*, platform="cron"):
|
|||
return agent
|
||||
|
||||
|
||||
def test_should_use_direct_api_call_only_for_cron_platform():
|
||||
def test_should_use_direct_api_call_only_for_cron_openai_wire():
|
||||
assert should_use_direct_api_call(_make_agent(platform="cron")) is True
|
||||
assert should_use_direct_api_call(_make_agent(platform="cli")) is False
|
||||
assert should_use_direct_api_call(_make_agent(platform="telegram")) is False
|
||||
assert should_use_direct_api_call(_make_agent(platform=None)) is False
|
||||
|
||||
for api_mode in ("codex_responses", "anthropic_messages", "bedrock_converse"):
|
||||
agent = _make_agent(platform="cron")
|
||||
agent.api_mode = api_mode
|
||||
assert should_use_direct_api_call(agent) is False
|
||||
|
||||
moa = _make_agent(platform="cron")
|
||||
moa.provider = "moa"
|
||||
assert should_use_direct_api_call(moa) is False
|
||||
|
||||
|
||||
def test_direct_api_call_runs_inline_and_closes_client():
|
||||
agent = _make_agent()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ def _make_agent(*, platform="cron"):
|
|||
agent = MagicMock()
|
||||
agent.platform = platform
|
||||
agent.api_mode = "chat_completions"
|
||||
agent.provider = "openrouter"
|
||||
agent._interrupt_requested = False
|
||||
agent._touch_activity = MagicMock()
|
||||
agent._create_request_openai_client = MagicMock()
|
||||
|
|
@ -28,12 +29,21 @@ def _make_agent(*, platform="cron"):
|
|||
return agent
|
||||
|
||||
|
||||
def test_should_use_direct_api_call_only_for_cron_platform():
|
||||
def test_should_use_direct_api_call_only_for_cron_openai_wire():
|
||||
assert should_use_direct_api_call(_make_agent(platform="cron")) is True
|
||||
assert should_use_direct_api_call(_make_agent(platform="cli")) is False
|
||||
assert should_use_direct_api_call(_make_agent(platform="telegram")) is False
|
||||
assert should_use_direct_api_call(_make_agent(platform=None)) is False
|
||||
|
||||
for api_mode in ("codex_responses", "anthropic_messages", "bedrock_converse"):
|
||||
agent = _make_agent(platform="cron")
|
||||
agent.api_mode = api_mode
|
||||
assert should_use_direct_api_call(agent) is False
|
||||
|
||||
moa = _make_agent(platform="cron")
|
||||
moa.provider = "moa"
|
||||
assert should_use_direct_api_call(moa) is False
|
||||
|
||||
|
||||
def test_direct_api_call_runs_two_sequential_requests_on_same_thread():
|
||||
"""Mirror the 2nd+ call failure mode: two back-to-back completions.create."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue