Address review feedback on the rich edit error classification:
- Transport, rate-limit, and unexpected errors now propagate instead of
returning False. Returning False made send_delta fall through to an
immediate legacy edit_message_text, which under connection-pool
exhaustion doubled demand and discarded the buffered retry state that
ChannelManager relies on.
- 'Message is not modified' is treated as success: when the rich edit is
applied server-side but its response times out, the retry inside
_call_with_retry reports the edit as already applied, and the previous
BadRequest branch would have let the legacy edit overwrite the
successful rich result.
- False is now returned only for capability errors (pre-10.1 servers,
which still trip the rich latch) and content-shaped rejections, where
the legacy HTML path is the intended fallback.
Adds regression coverage for a direct NetworkError (propagates, buffer
kept for manager retry) and TimedOut followed by Message-is-not-modified
(treated as success, no legacy overwrite).
The rich branch in send_delta(stream_end=True) was unreachable: it was
guarded by 'not buf.message_id' after an earlier return had already
ensured buf.message_id is set, so sendRichMessage never fired with
streaming enabled and the final message always went through the legacy
HTML editMessageText path.
Bot API 10.1 added a rich_message parameter to editMessageText, which
upgrades an existing message to rich in place. Use it at stream end via
do_api_request so the streaming preview keeps its identity — no
delete-and-resend, so none of the flickering or dropped line breaks
that made rich-at-stream-end fail in #4470.
Capability errors (server older than 10.1) trip the existing
_rich_send_disabled latch and fall back to the legacy HTML path, which
is unchanged.
Fixes#5516
* refactor(agent): unify runner request fitting
* fix(agent): fit every runner model request
* fix(agent): count resumed state during request fitting
* refactor(agent): consolidate request fitting state
* refactor(agent): defer transcript assembly to runner
Keep persisted history and the fresh turn as explicit inputs until the Runner assembles the provider transcript. Preserve ContextBuilder and direct AgentRunner compatibility while making the save boundary structural.
Refs NAN-81.
* fix(providers): preserve mixed adjacent user content
The IMAP poll loop previously downloaded the entire message body for
every UNSEEN message before running any filter (self-sent, SPF/DKIM,
allow-list), and only learned the UID by parsing it back out of that
fetch response. Rejected messages stay unseen and get re-fetched in
full on every subsequent poll.
Switch to UID SEARCH (UIDs come back directly, no per-message fetch
needed to learn them) so already-processed UIDs are skipped before any
network fetch, then fetch headers only to evaluate every filter — the
full body is downloaded only for messages that pass every check and
are actually delivered. No behavior change: filter outcomes and
\Seen semantics are unchanged.
* refactor(agent): decouple loop from message tool state
* refactor(agent): scope message delivery tracking per run
* refactor(agent): clarify message delivery scope name