Update exact-match test assertions in send.test.ts to include the new
allow_sending_without_reply: true parameter. Tests using objectContaining
already pass, but several tests use exact object matching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a Telegram message that OpenClaw is replying to gets deleted before
delivery, the Telegram API rejects the entire sendMessage call with
"message to be replied not found". This causes the bot's response to be
silently lost and stuck in the failed delivery queue permanently.
Setting allow_sending_without_reply: true tells Telegram to deliver the
message as a standalone message if the reply target no longer exists,
instead of failing the entire request.
Applied to all 6 locations across 4 source files where
reply_to_message_id is set:
- send.ts: buildTelegramReplyParams (both reply_parameters and plain reply)
- bot/delivery.send.ts: buildTelegramSendParams
- draft-stream.ts: draft stream reply params
- bot-handlers.runtime.ts: error reply messages (file too large, media download failed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codex P1: entries deferred by the recovery time budget kept retryCount=0
forever, so they could loop across restarts without ever reaching MAX_RETRIES.
After breaking on deadline, call failDelivery() for all remaining entries
so retryCount is incremented. Entries stay in queue until MAX_RETRIES is
reached and they are pruned normally.
Also updates the maxRecoveryMs test to assert retryCount=1 on deferred entries.
The stdio tuple overload resolves differently across @types/node versions
(v20 vs v24/v25). Cast the spawn() result to ChildProcessWithoutNullStreams
to ensure proc.stderr?.on/off type-checks regardless of installed @types/node.
P1-C: After now >= deadline, the old code would iterate all remaining queue
entries and call failDelivery() on each — O(n) work that nullified the
maxRecoveryMs wall-clock cap on large queues.
Fix: break out of the recovery loop immediately when the deadline is exceeded.
Remaining entries are picked up on next startup unchanged (retryCount not
incremented). The deadline means 'stop here', not 'fail everything remaining'.
When delivery recovery ran out of the 60s time budget, remaining pending
entries were silently deferred to the next restart with no retryCount
increment. This caused them to loop forever across restarts, never hitting
MAX_RETRIES and never moving to failed/.
Fix: call failDelivery() on each remaining entry before breaking out of
the recovery loop (both the deadline check and the backoff-exceeds-deadline
check). This increments retryCount so that entries eventually exhaust
MAX_RETRIES and are permanently skipped.
Fixes#24353
Prevents crash when totals is undefined in byModel/byProvider/byAgent
sort comparators. Fixes 'Cannot read properties of undefined (reading
totalTokens)' crash that causes context overflow in active sessions.