mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(delegate): declare stateless channel in one-shot and cron so delegate_task returns results
run_agent._dispatch_delegate_task forces background=True for every top-level
delegation, and async_delivery_supported() returns True for any session that
never binds the capability. On runners that cannot receive a completion after
their turn ends, that combination silently discards every subagent result: the
model gets a dispatch handle, ends its turn, and reports 'waiting for results'.
Two such runners never bind the capability:
* hermes -z (one-shot) prints one final response and exits. It bypasses cli.py,
so nothing drains process_registry.completion_queue (only the interactive
process_loop and the gateway watchers do).
* cron run_job clears the HERMES_SESSION_* routing keys, so a completion event
carries session_key="" — _enrich_async_delegation_routing cannot resolve it
and _inject_watch_notification drops it ("no routing metadata"). By then
run_job has already shipped the job's final response via _deliver_result;
there is no turn left to re-enter. Worse, get_current_session_key() can fall
back to the ambient os.environ HERMES_SESSION_KEY, so a cron subagent's output
can be routed into an unrelated user chat rather than merely dropped.
Add declare_stateless_channel() and bind it in both runners, routing
delegate_task to its existing inline/synchronous path — the same fallback the
stateless HTTP adapter already relies on, and the fix suggested in #63142. The
helper binds only the capability: set_session_vars() would also latch
_session_context_engaged, which a pure single-process one-shot must not trigger.
Also correct two agent-facing strings that hardcoded 'stateless HTTP API' as the
only channel without async delivery (delegate_tool, terminal_tool); they now name
the actual condition.
Repro (before): hermes -z 'Use delegate_task to spawn a subagent that replies
BANANA. Report its reply.' -> "Waiting for the subagent's response...", exit 0,
no BANANA. After: BANANA is returned in-turn.
Fixes #53027
Fixes #63142
This commit is contained in:
parent
c48d53413a
commit
3d9be27895
6 changed files with 168 additions and 11 deletions
|
|
@ -2832,10 +2832,11 @@ def delegate_task(
|
|||
_sync_result = _execute_and_aggregate()
|
||||
if isinstance(_sync_result, dict):
|
||||
_sync_result["note"] = (
|
||||
"background=true is not available on this endpoint (stateless "
|
||||
"HTTP API — no channel to deliver a detached subagent result "
|
||||
"after the turn ends), so the subagent(s) ran SYNCHRONOUSLY and "
|
||||
"the result is included above."
|
||||
"background=true is not available in this session — it cannot "
|
||||
"receive a detached subagent result after the turn ends (a "
|
||||
"one-shot runner such as `hermes -z` or a cron job, or a "
|
||||
"stateless HTTP endpoint). The subagent(s) ran SYNCHRONOUSLY "
|
||||
"and the result is included above."
|
||||
)
|
||||
return json.dumps(_sync_result, ensure_ascii=False)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue