Commit graph

4 commits

Author SHA1 Message Date
Hermes Agent
7487afbd99 test(gateway): update stale expectation — #31884 surfaces retry hint for uninterrupted zero-call drops
The PR predates #31884, which changed the non-interrupted api_calls==0
empty path from silence to a retry hint. Flip the contributed test to
assert the current (correct) behavior.
2026-07-06 03:42:14 -07:00
AIalliAI
a14caf7759 fix(gateway): stop post-/stop stale interrupt from silently swallowing the next message
A /stop sets _interrupt_requested on the session's cached agent, but the
flag is only cleared by the turn finalizer.  When the stopped run is hung
or still draining, the flag survives the forced lock release and the
session's NEXT user message is killed at the top of the tool loop
(conversation_loop.py interrupt check): the run completes with
interrupted=True, api_calls=0 and an empty response, which
_normalize_empty_agent_response passed through as pure silence — the
user's message was swallowed with no trace except a
'response ready: ... api_calls=0 response=0 chars' log line.

Two-layer fix:

- _interrupt_and_clear_session now evicts the cached agent whenever it
  releases the running state.  The next message rebuilds the agent from
  session history (mirroring the /new and /model paths), while the old
  agent object keeps its interrupt flag so a hung drain still dies when
  it unblocks.  This intentionally does NOT clear the flag in place:
  turn_context deliberately preserves a pending interrupt across turn
  start (it carries interrupt-message delivery), and clearing it could
  revive a hung run the user just stopped.

- _normalize_empty_agent_response distinguishes a drain from a swallowed
  turn: an interrupted run that did work (api_calls > 0) stays silent as
  before (deliberate stop/steer; queued messages are delivered by the
  recursive drain inside _run_agent), but an interrupted run with ZERO
  api_calls never processed the user's message at all and now surfaces a
  'send it again' notice instead of nothing.

Same silent-delivery class as a1f76ba7e (#29346), which covered the
extract-stripped case; regression tests added next to that coverage.

Fixes #44212
2026-07-06 03:42:14 -07:00
teknium1
43b8ba4181 fix(telegram): preserve Bot API update queue on watcher reconnect
After a prolonged outage the in-process network-error ladder escalates to
fatal and GatewayRunner._platform_reconnect_watcher rebuilds a fresh adapter
that reconnects through the bootstrap path. That path called
start_polling(drop_pending_updates=True), discarding every update Telegram
queued during the outage — all messages sent while the bot was down were
silently lost. The in-process ladder and 409-conflict handler already passed
drop_pending_updates=False; only bootstrap did not distinguish a cold first
boot from a reconnect.

Thread an is_reconnect signal from the watcher through
_connect_adapter_with_timeout into adapter.connect(). The base
BasePlatformAdapter.connect() gains a keyword-only is_reconnect=False so every
adapter inherits a tolerant signature (no per-platform breakage when the
runner forwards the kwarg). Telegram translates is_reconnect into
drop_pending_updates=not is_reconnect on both the polling and webhook bootstrap
calls. Cold boot still drops the stale queue; a watcher reconnect preserves it.

Fixes #46621.

Co-authored-by: annguyenNous <annguyen@nousresearch.com>
Co-authored-by: kyssta-exe <kyssta-exe@users.noreply.github.com>
Co-authored-by: Kewe63 <Kewe63@users.noreply.github.com>
2026-06-25 21:29:57 -07:00
firefly
a1f76ba7e9 fix(gateway): recover extract-stripped tool responses on all platforms (#29346)
The extract pipeline (extract_media/extract_images/extract_local_files +
directive strips) can reduce a non-empty tool-using response to empty
text_content with no deliverable attachment. The 'if text_content' send
guard then silently skips delivery: a 'response ready' log with no
'Sending response', no error, and the answer never reaches the user.

- A2: snapshot the pre-extract response; when extraction yields empty text
  and no image/local/media attachment, deliver the recovered original from
  the post-extract_media body (so a spaced MEDIA path can't leak). Applies
  on ALL platforms (supersedes the Discord-only #33842 and the unsafe
  raw-fallback #29499).
- A3: loud delivery invariant - a non-empty response that produces nothing
  deliverable logs response_delivery_dropped at ERROR; every recovery logs
  response_delivery_recovered. No silent drop survives.
- Factor a _strip_media_directives helper for the [[...]] strips; MEDIA
  stripping stays owned by extract_media, whose grammar handles spaced and
  quoted paths.
- Salvaged + de-scoped the #33842 test harness to all platforms; added
  unrecoverable-drop and no-leak regression tests.
2026-06-01 17:31:32 -07:00