Telegram long-polling floods the log in two ways:
1. python-telegram-bot performs getUpdates through httpx, which logs every request at INFO level. httpx/httpcore were missing from LogManager._NOISY_LOGGER_LEVELS, so those per-request lines (one every ~10s) leaked through.
2. _on_polling_error logged a full traceback for every polling error, including non-network errors such as Conflict (two bot instances polling the same token). Log a concise one-line message for non-network errors and keep the traceback only for NetworkError, which still needs it for recovery.
* feat: group model selection by provider source
* feat: optimize model selector with source filters and sticky groups
* fix: align model filter borders and hide single-source filter
* fix(qqofficial): always send the state=10 closing frame in C2C streaming
QQ's C2C streaming protocol ends a stream with a state=10 frame whose
content must end with \n. AstrBot only sent it while unsent text
remained in the buffer: once the throttled middle frames had flushed
the full reply and the generator ended with an empty tail, no closing
frame went out at all. QQ then timed the stream out and rolled the
whole message back to the first packet, which is why a full 850-char
reply ended up displaying only its first few characters (#10066), and
why some streams hang in "generating" forever.
Close every open segment: when the stream is open (a frame id exists)
but the tail buffer is empty, send a minimal "\n" closing frame; when
nothing was ever sent (no id), keep sending nothing. The tool_call
break path closes the same way through a shared helper so an empty
segment cannot orphan its stream either.
Regression tests pin both paths against a fake _post_send: empty tail
after a middle flush, and break arriving on an empty but open segment.
* fix(qqofficial): treat an empty-Plain tail as empty for the closing frame
Review on #10069: a buffer holding only Plain("") components has a
truthy chain, so the "\n" fallback was skipped, _post_send_one rejected
the empty parsed content, and no state=10 frame went out for an opened
stream. Check for sendable content (non-empty text or a non-Plain
component) instead of chain non-emptiness. Regression test pins the
empty-Plain tail after a middle flush.
* refactor: prepare model images in the local process stage
Prepare current input images before agent construction and after the request hook. Keep original attachments intact and preserve existing tool image behavior.
Reuse the compression toggle for PNG stills and animation montages, with event-owned working files and portable history serialization.
Validation: 2571 Linux tests, 495 Windows regression tests, dashboard build, and live text/JPEG/GIF calls with agnes-3.0-flash.
* test: read source files as UTF-8 in image boundary check
* fix: avoid blanket PNG conversion of model input images
* fix: support updating installed plugins from uploaded archives
* fix: update existing plugins through URL installation
* fix: skip temporary directories during plugin discovery
* fix: stage plugin installs and backups in system temp
* test: align dashboard plugin installer mock with staging API
* feat(dashboard): add chat history pagination and reasoning blocks (#9652)
* refactor(dashboard): remove reasoning char count and loading text
* feat(dashboard): load earlier messages on scroll up
* refactor(dashboard): remove reasoning retry label
* refactor(dashboard): remove thread panel pagination and lazy reasoning
Restore the thread panel to pre-#9652 behavior: full history without
pagination and inline reasoning content. Reverts the out-of-scope thread
additions while keeping main-session pagination and reasoning lazy-loading.
* chore: retrigger smoke test
* fix(dashboard): pause automatic history loading after failure
* feat(dashboard): show progress while loading earlier messages
* fix(dashboard): show reasoning loading errors and retry action
* style(dashboard): align chat loading errors with chat UI
* style(dashboard): make chat loading errors more compact
* refactor(chat): retain complete message content in history pages
* refactor(dashboard): expand reasoning directly from history pages
* refactor(api): remove lazy chat message retrieval endpoint
* fix(kb): space out concurrent waiters in the URL cleaning RateLimiter
URL content cleaning processes all chunks with asyncio.gather and a
shared RateLimiter. Every coroutine read the same last_call_time
before sleeping, so they all woke up at the same moment and fired
their requests together; the configured RPM did not bound that burst
and larger documents could trip the upstream limit.
Reserve the next release slot under a lock (sleeping outside it), so
waiters are released one interval apart, in order. Idle time is still
credited and max_rpm=0 still disables limiting.
Fixes#9995
* fix(kb): reserve RateLimiter slots under a lock so waiters do not burst
The first commit only carried the test; this adds the RateLimiter change
it exercises. Each waiter now reserves the next release slot under an
asyncio.Lock and sleeps until that slot, so concurrent callers are
released one interval apart instead of waking up together.
* fix(kb): preserve rate limit spacing after event loop stalls
---------
Co-authored-by: Soulter <905617992@qq.com>
* fix(lark): fall back to private chat ID when open ID send fails
Private file sends can fail with error 230101 when addressed by open ID,
even though the same file can be delivered to the private chat ID.
Persist private open ID to chat ID mappings from incoming messages,
scoped by platform and app ID, while preserving existing session IDs.
Keep open ID as the primary recipient and retry each rejected message
once with its known private chat ID, reusing the content and UUID.
Do not resend successful components or retry transport exceptions.
Propagate proactive send and attachment upload failures to callers so
failed deliveries are not reported as successful. Preserve the existing
boolean failure handling for replies.
Refs: #9989
* test(lark): cover private chat fallback and delivery failures
Reproduce rejected open ID file sends and verify that the same uploaded
file is retried once with the private chat ID and original UUID.
Cover successful primary sends, mixed message chains, failed deliveries,
upload failures, group routing, transport timeouts, and reply behavior.
Verify stored routes survive adapter recreation, remain scoped to the
bot, and cannot be overwritten by group messages.
Isolate sender-name tests from persistent route storage and supply the
platform and app identity required by route persistence.
Validation: 26 related tests passed; ruff format and ruff check passed.
Live Feishu API validation remains pending application credentials.
Refs: #9989
* feat(chatui): refine settings, composer and streaming experience
* style(chatui): compact composer and narrow message layouts
* style(chatui): align composer gutters and remove excess height
* style(chatui): give composer editing area more height
* fix(chatui): preserve reading width when side panels open
* fix: correct At/AtAll branch order in message outline
Original logic checked At first and then AtAll. However, because AtAll is a subclass of At, the AtAll branch would never be executed. This change moves AtAll before At to ensure the code behaves correctly.
* test: assert AtAll outline renders as [At:全体成员]
WebChat generates its title on the platform session, while the conversation history reads the conversation title column, so WebChat rows were listed as untitled. Fall back to the session display name when a conversation has no title, and let conversation search match session titles as well.
Entering the Data & Logs -> Logs page froze the WebUI for seconds because ConsoleDisplayer rendered each historical log line with a separate appendChild plus a forced synchronous reflow (scrollTop = scrollHeight) per line, and used innerText which triggers a style recalc on every assignment.
Batch the rendered lines into a DocumentFragment and append it once, scroll to the bottom a single time, and use textContent instead of innerText. This collapses O(n) reflows into one and eliminates the main-thread freeze.
_run_job marked a cron job "completed" unless an exception escaped, but
_woke_main_agent never checked the agent runner's terminal state: a run
that dies with a malformed function call at max steps ends in
AgentState.ERROR with no exception, so cron_jobs showed
status=completed, last_error=NULL, and the user only ever saw the
intermediate messages (#9980).
_woke_main_agent now raises when the runner ends in AgentState.ERROR
(carrying the final error text when there is one) and when the main
agent fails to build at all; _run_job's existing handler records both as
failed with last_error. The runner base class gains a read-only `state`
property so callers no longer reach into `_state`.
Tests: two regression cases on _run_job (ERROR terminal state, build
failure) asserting status=failed with the detail in last_error; both red
on current master and green here. Existing fake runners in the file got
the state attribute the runner contract now documents.
Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
Sandboxed processes can write to shared temp roots, so a named session
log there could be replaced with a symlink to a host file that host-side
reads and appends would follow. Keep managed shell output on an anonymous
temporary file handle instead of a named path.
Also stop _resolve_path_from_sandbox from consulting a booter under the
local runtime: workspace and local-file checks already enforce caller
permissions, and the fallback branch probed the host shell without them.
Reject such paths with FileNotFoundError instead.