5258 Commits
Author SHA1 Message Date
Soulter 3c7adafa13 chore: bump version to 4.28.2 v4.28.2 2026-09-27 23:02:23 +08:00
pingandDevin aefce70a2e fix: compare platform message history cutoff in UTC
platform_message_history.created_at stores UTC wall-clock values
(written via TimestampMixin's datetime.now(timezone.utc)), but
delete_platform_message_offset computed the cutoff from naive local
datetime.now(). On hosts outside UTC the comparison was shifted by the
local offset, so the wrong slice of history was deleted.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-27 23:00:55 +08:00
RuochenPan 8d5dd15f34 fix: preserve datetime storage across SQLModel upgrades 2026-09-27 23:00:54 +08:00
Soulter ab42c0d9b7 chore: bump version to 4.28.1 (#10085) v4.28.1 2026-09-14 23:11:06 +08:00
氕氙 02fef48c26 fix: preserve input image geometry under CUA sandbox and warn on oversized images (#10071)
* fix: skip input image resize under CUA sandbox to keep pixel coordinates 1:1

* feat: warn when CUA passthrough images may exceed provider upload limits

* fix: keep configured montage cap for animated inputs under CUA sandbox
2026-09-14 23:27:50 +09:00
玲因 e79c0d7aa0 fix: reduce Telegram log spam from polling and conflict errors (#10027) (#10046)
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.
2026-09-14 22:27:33 +08:00
Wei Chengqian 7ee03f2293 fix: preserve OpenAI endpoint resolution for empty api_base (#10079) 2026-09-14 21:48:46 +08:00
Soulter 56cbc4a4a6 feat: optimize model selection with source filters and sticky groups (#10084)
* 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
2026-09-14 21:43:02 +08:00
Yufeng He 31d798944d fix(qqofficial): always send the state=10 closing frame in C2C streaming (#10069)
* 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.
2026-09-14 21:30:35 +08:00
Soulter d524b8708a fix: standardize provider user agents with the AstrBot version (#10082) 2026-09-14 21:24:00 +08:00
氕氙 bd046ed299 feat: adaptively prepare model input images in the local process stage (#9703)
* 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
2026-09-14 01:43:09 +08:00
Soulter 4007d645c9 fix: use selected model in webchat side threads (#10065) 2026-09-13 20:07:24 +08:00
Soulter 7ec39bdef0 fix: support plugin updates through URL and file installation (#10053)
* 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
2026-09-12 15:05:58 +08:00
w31rd c264e1d92a feat: unify /new and /reset behavior (#10004)
* feat: unify new and reset conversation behavior

* fix(i18n): align conversation isolation labels

* fix(i18n): clarify group conversation permission hints

* feat: centralize conversation command permissions

* fix(i18n): clarify administrator-only command permissions

* docs: correct conversation command permission instructions

* test: isolate conversation restart command registration

* feat: follow conversation isolation for restart permissions
2026-09-12 14:19:58 +08:00
Soulter 11cab79dc7 feat(dashboard): show desktop update download progress (#10050) 2026-09-12 13:57:12 +08:00
Wei Chengqian fae2c120ef feat(chatui): paginate chat history (#9667)
* 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
2026-09-12 13:56:22 +08:00
Soulter 72928aa7c9 fix: preserve image attachment paths after event cleanup (#10042)
* fix: preserve image attachment paths after event cleanup

* fix: retain local image references when normalization fails

* revert: undo local image reference normalization change
2026-09-12 12:31:10 +08:00
beeminesandbeemines f2ead2922e fix: restore session model fallback for proactive agents (#10028)
Co-authored-by: beemines <182060364+beemines@users.noreply.github.com>
2026-09-12 11:16:38 +08:00
Lukas BuckandSoulter 8b5f38885e fix(kb): space out concurrent waiters in the URL cleaning RateLimiter (#10015)
* 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>
2026-09-10 23:42:17 +08:00
若月千鸮 0f445f5eff fix(agent): deliver skills-like fallback replies when streaming (#10025)
* fix(agent): deliver skills-like fallback replies when streaming

* fix(agent): limit fallback fix to missing streaming events
2026-09-10 23:34:33 +08:00
PyuraMazo 0d40d34185 feat: enhance slider robustness (#10037)
* fix: validate numeric config bounds if slider exists

* feat: add min/max labels to slider
2026-09-10 23:33:04 +08:00
Soulter da1bc7df55 fix(ci): exclude temporary dashboard artifacts from PyPI source packages (#10036) 2026-09-10 23:25:42 +08:00
Soulter c6eefb5544 perf(dashboard): reduce bundled font and diagram assets (#10034) 2026-09-10 23:04:59 +08:00
Soulter 5cc5617233 feat(chatui): reuse Shiki for workspace code previews (#10023) 2026-09-10 23:01:57 +08:00
NayukiChiba 32a751394c fix(lark): Ensure Lark private messages are delivered reliably by falling back from rejected open IDs to known chat IDs without duplicating successful sends. (#10018)
* 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
2026-09-10 22:53:17 +08:00
Soulter 48024574c8 feat(chatui): refine settings, composer and streaming experience (#10021)
* 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
2026-09-10 22:08:02 +08:00
Soulter 6fb50cae91 feat(webchat): enable reasoning display by default (#10020)
* feat(webchat): enable reasoning display by default

* fix(webchat): sync reasoning flag expectations and API docs
2026-09-10 10:36:24 +08:00
DFGHJ43 5935430b1d fix: correct At/AtAll branch order in message outline (#9993)
* 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:全体成员]
2026-09-10 00:34:25 +08:00
WangPan59and王磐 5195ec694c fix: resolve field loss, error code swallowing, and parameter validation issues in web search tool (#9979)
* feat: 优化网络搜索工具并更新单元测试

* fix: 修复 Code Review 指出的两个问题

---------

Co-authored-by: 王磐 <wangpan.com>
2026-09-10 00:25:21 +08:00
Sekken 312ec36d55 fix(webui): fall back to WebChat session titles in conversation history (#9983)
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.
2026-09-10 00:15:52 +08:00
玲因 67b8725ee8 fix: batch console log rendering to avoid UI freeze (#9988) (#9990)
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.
2026-09-09 23:51:47 +08:00
Wei Chengqian 6dde01b7e9 fix: resolve persisted current conversation before deletion (#10003) 2026-09-09 23:48:45 +08:00
Soulter ee98243825 perf: improve provider dialog (#10007) 2026-09-09 23:47:29 +08:00
Yufeng He 5f12620118 fix(cron): record active-agent job failure when the runner ends in ERROR (#9987)
_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>
2026-09-09 22:43:27 +08:00
若月千鸮 25374205b6 fix(cron): honor session context compression settings (#9992)
* fix(cron): honor session context compression settings

* fix(agent): share session compression config across wakeups
2026-09-09 17:32:01 +08:00
KazusaUwU 6494ac22e5 fix(dashboard): reject stale WebUI assets in desktop-managed mode (#9898) 2026-09-09 11:44:06 +09:00
Soulter a412146401 chore: bump version to 4.28.0 (#9975)
* chore: bump version to 4.28.0

* update
v4.28.0
2026-09-08 00:38:18 +08:00
dependabot[bot] d8d37f520f chore(deps): bump docker/setup-qemu-action in the github-actions group (#9974)
Bumps the github-actions group with 1 update: [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action).


Updates `docker/setup-qemu-action` from 4.2.0 to 4.3.0
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-08 00:38:10 +08:00
Soulter 48d0da79ae feat: include Python version in metrics uploads (#9973) 2026-09-07 23:41:11 +08:00
Cui Yuxuan ec848fc2c3 feat(i18n): add Japanese localization (#9955) 2026-09-07 22:21:48 +08:00
Soulter 1651ef245e fix: isolate event loop watchdog stack dumps (#9941) 2026-09-07 21:56:42 +08:00
Sekken 47297fa4b1 fix(webui): show WebChat conversations in history lists (#9910) 2026-09-07 21:53:40 +08:00
Soulter ff86d3276c fix: honor computer runtime settings in proactive agents (#9971)
* fix: honor computer runtime settings in proactive agents

* fix: default missing computer runtimes to none
2026-09-07 21:33:57 +08:00
山海学社OMSocietyandOMSociety 2f504d3235 fix(qqofficial): render markdown for proactive send_by_session messages (#9914)
* fix(qqofficial): render markdown for proactive send_by_session messages

* fix(qqofficial): preserve use_markdown_ when splitting media chains

* fix(qqofficial): fall back to content when markdown payload is rejected

* feat(qqofficial): add use_markdown config to gate default markdown sending

* feat(dashboard): add i18n entries for qqofficial use_markdown config

* fix(qqofficial): expose use_markdown on webhook template and clarify label

Add use_markdown to the QQ Official (Webhook) config template so new
webhook platforms expose and save the setting in the WebUI, matching the
WebSocket template. Rename the field label from the ambiguous '主动消息发送模式'
to the clearer '主动消息使用 Markdown' (en/ru translations updated).

Add a regression test asserting both QQ Official templates expose use_markdown.

---------

Co-authored-by: OMSociety <OMSociety@users.noreply.github.com>
2026-09-07 17:05:54 +08:00
liwei zhengandzenfun 77da504998 fix: Enable unit test CI on three platforms (Windows, macOS, Linux). (#9954)
* ci: run unit tests on ubuntu, windows, and macos

* ci: promote macos lane to blocking now that it passes

* fix: make the unit test suite pass on Windows

* fix: address Windows CI encoding failures and review findings

- Force UTF-8 stdio for python children on Windows (exec, managed
  sessions, python tool) so non-ASCII output survives ANSI code pages
- Try cp936/gbk before mbcs in the decode fallback so Chinese output is
  not silently mojibake'd on non-Chinese Windows
- Use PowerShell call-operator quoting for space-containing executables
- Narrow the require_symlink skip to WinError 1314 and raise other OSErrors
- Raise managed-shell test yield budget to absorb CI cold starts

* fix: restore POSIX shell quoting in test_computer exec tests

The PowerShell call-operator form is a syntax error in POSIX shells;
generate the command per platform instead.

* fix: support mixed platform path mappings

* fix: preserve Windows shell output encoding

---------

Co-authored-by: zenfun <zenfun510@gmail.com>
2026-09-07 08:38:04 +08:00
xiaoxuan010 bd4b198a5f fix: limit knowledge base document page size options to drop invalid 'All' value (#9908)
The v-data-table-server in DocumentsTab inherits Vuetify's default
items-per-page-options [10, 25, 50, 100, -1], where -1 renders as 'All'.
Selecting it sends page_size=-1, which the backend clamps to 1, so the
document list shows only one item.

Explicitly set :items-per-page-options to [10, 25, 50, 100] so the 'All'
option is no longer offered, consistent with other pages such as
ConversationPage.

Closes #9907
2026-09-06 19:11:26 +08:00
wangyuxy9805-webandwangyuxy9805-web 1fc3d33455 fix: preserve context prefix during tool requery (#9957)
Co-authored-by: wangyuxy9805-web <319040411+wangyuxy9805-web@users.noreply.github.com>
2026-09-06 18:48:55 +08:00
Shxiao 610eab06c8 fix: preserve user content in dict-type config items (#9958) 2026-09-06 18:39:49 +08:00
KazusaUwU 6b84809052 fix(provider): serialize Gemini thinking levels correctly (#9899) 2026-09-04 10:28:39 +08:00
Hayston 9852285bda fix: resolve plugin market detail mix-up for same-named plugins (#9925)
Two market entries can share the same metadata `name` (different
authors), but the detail flow used `name` as the unique key:

- `openMarketPluginDetail` navigated with `plugin.name` as the route
  param, so both entries resolved to the same detail route;
- `selectedMarketPlugin` matched `item.name === pluginId`, always
  returning the first same-named entry (wrong version/author/repo/README);
- duplicate `v-for` keys (`plugin.name`) caused Vue to reuse wrong
  component instances in the market list;
- the random-plugins section keyed its sampling Map by `name`, collapsing
  same-named entries.

Introduce `getMarketPluginKey(plugin)` (`market_plugin_id || repo ||
name`) as the unique market identity, use it for navigation, list keys,
detail lookup (name kept as fallback for legacy deep links), and the
random-plugins sampling.

Fixes #9924
2026-09-04 00:49:28 +08:00