fix(cron): scope inline calls to reported transport

This commit is contained in:
kshitijk4poor 2026-07-11 10:54:22 +05:30 committed by kshitij
parent 47c91e4c34
commit 02063ece11
3 changed files with 31 additions and 16 deletions

View file

@ -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):

View file

@ -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()

View file

@ -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."""