fix(background_process): do not consume the delivery budget on transient wake-up refusals
start_session_turn() answers 409 retryable=True while the Agent runtime is stale, 409 process_wakeup_paused while wake-ups are paused, and 409 with active_stream_id while the session is busy with another turn. The bridge released the durable claim as a plain failure each time, so a burst of refusals within seconds terminally dropped a completion whose origin session was alive and waiting. release_async_delegation_delivery(..., retryable=True) now forwards the refund to an Agent core whose release_event_delivery() accepts the `retryable` keyword (NousResearch/hermes-agent#120028), detected through inspect.signature, and falls back to the historical plain release on an older core. Hard rejections keep the bounded budget.
This commit is contained in:
1 parent
b1774b45a9
commit
9b6851eaf1
3 files changed
+228
-3
No files matched your search
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
from collections import OrderedDict
|
||||
from dataclasses import dataclass
|
||||
import inspect
|
||||
import logging
|
||||
import math
|
||||
import re
|
||||
@@ -451,16 +452,46 @@ def complete_async_delegation_delivery(
|
||||
_mark_legacy_async_delivery_complete(claim.delegation_id)
|
||||
|
||||
|
||||
def _release_accepts_retryable(release_fn: Any) -> bool:
|
||||
"""Whether the core ``release_event_delivery`` supports ``retryable=``.
|
||||
|
||||
Older Agent cores predate the keyword; calling them with it would raise
|
||||
``TypeError`` and skip the release entirely.
|
||||
"""
|
||||
try:
|
||||
params = inspect.signature(release_fn).parameters
|
||||
except (TypeError, ValueError):
|
||||
return False
|
||||
if "retryable" in params:
|
||||
return params["retryable"].kind in (
|
||||
inspect.Parameter.KEYWORD_ONLY,
|
||||
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
||||
)
|
||||
return any(p.kind is inspect.Parameter.VAR_KEYWORD for p in params.values())
|
||||
|
||||
|
||||
def release_async_delegation_delivery(
|
||||
evt: Any,
|
||||
claim: AsyncDelegationDeliveryClaim,
|
||||
*,
|
||||
retryable: bool = False,
|
||||
) -> None:
|
||||
"""Release a failed claim so a later WebUI consumer can retry it."""
|
||||
"""Release a failed claim so a later WebUI consumer can retry it.
|
||||
|
||||
``retryable=True`` tells the core the refusal was transient, so the claimed
|
||||
attempt is refunded instead of counting against the bounded delivery
|
||||
budget (``tools.async_delegation.release_event_delivery(...,
|
||||
retryable=True)``). A core that predates the keyword gets a plain release:
|
||||
the attempt is then consumed as before, never an exception.
|
||||
"""
|
||||
try:
|
||||
if claim.durable:
|
||||
from tools.async_delegation import release_event_delivery
|
||||
|
||||
release_event_delivery(evt, claim.claim_id)
|
||||
if retryable and _release_accepts_retryable(release_event_delivery):
|
||||
release_event_delivery(evt, claim.claim_id, retryable=True)
|
||||
else:
|
||||
release_event_delivery(evt, claim.claim_id)
|
||||
except Exception:
|
||||
logger.warning(
|
||||
"Failed to release durable async delegation delivery for %s",
|
||||
|
||||
Reference in new issue
Block a user