* 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>
* 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>
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
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
* fix: expand common language syntax highlighting
* fix: wire limited Shiki languages into ChatUI
* fix: register bundled aliases for chat code blocks
* fix: include Go grammar in T2I Shiki runtime
* fix(i18n): add missing en-US dashboard translations
Fill 26 keys present in zh-CN but missing from en-US locale files:
- tool-use: the whole dialogs.syncProvider subtree (MCP server sync
dialog showed untranslated keys in English UI)
- config-metadata: section hints for knowledgebase and websearch
- provider: vllm_rerank description
- subagent: personaPreview label
Verified all en-US locale files now have full key parity with zh-CN.
* fix(i18n): move syncProvider keys to the tooluse namespace root
McpServersSection.vue resolves features.tooluse.syncProvider.* (the
subtree must sit at the file root); the previous commit had mirrored
zh-CN's placement under dialogs, which the namespace lookup never
reaches. Also drop form.personaPreview: the component consumes
cards.personaPreview (already present); form.personaPreview is an
unused key.
* fix(provider): exclude cached tokens from Gemini input usage accounting
Gemini's prompt_token_count already includes tokens served from cache.
_extract_usage was passing it straight to TokenUsage.input_other while also
setting input_cached to cached_content_token_count, so usage.input double
counted cached tokens and inflated context-occupancy stats. Subtract cached
tokens from input_other, matching the OpenAI provider's accounting.
* docs(provider): clarify _extract_usage reads response usage metadata
Address Sourcery review: the method receives GenerateContentResponseUsageMetadata,
not a candidate, so correct the docstring's opening line.
Anthropic's input_tokens only covers tokens after the last cache breakpoint;
cache_creation_input_tokens (tokens written into a new cache entry) were
dropped entirely from TokenUsage, so usage.input/total undercounted requests
that create a fresh cache entry. Fold cache_creation_input_tokens into
input_other in both _extract_usage and the streaming _update_usage, matching
the OpenAI provider's accounting where input_other holds all non-cache-read
input (including cache writes).
Official formula: total_input = cache_read + cache_creation + input_tokens.
* feat: automatically record UMO names
* refactor: record UMO names only after wake
* refactor: record UMO names during wake checks
* refactor: extract UMO auto-name recorder
* feat(platform): enrich group metadata across adapters
* perf(platform): make group member lookup opt-in
* Revert "perf(platform): make group member lookup opt-in"
This reverts commit 896b4b895b.
Legacy plugins installed before install-source persistence (PR #9037) have
no plugin_install_sources record, so the backend falls back to an implicit
source record. The frontend update check skipped implicit sources entirely,
so these plugins never showed available updates until the user manually
re-bound or reinstalled the plugin.
Include implicit sources in the update check: they resolve to the default
registry, so match them against the default market by repo/name. Only
matched plugins surface an update; unmatched ones stay silent, so this
cannot introduce false positives. Also fix the misspelled online_vesion
field name so the backend payload matches what the frontend reads.
AstrBotConfig._write_config_snapshot calls tempfile.mkstemp(dir=directory)
without verifying the directory exists. When a config profile is created
for the first time (e.g. create_conf instantiates AstrBotConfig with a
brand-new path), __init__ calls save_config before the directory is
guaranteed to exist, and mkstemp raises FileNotFoundError.
Add os.makedirs(directory, exist_ok=True) before mkstemp. This is the
standard defensive pattern for atomic-write helpers.
Fixes three intermittently-failing dashboard tests:
- test_t2i_set_active_template_syncs_all_configs
- test_t2i_reset_default_template_syncs_all_configs
- test_t2i_update_active_template_reloads_all_schedulers
Closes#9855.
Copy non-empty buffered text elements before clearing them when an image is inserted, and avoid emitting empty blocks for image-first messages.
Co-authored-by: liruihan <liruihan@example.com>
* fix(dashboard): make skill editor dialog responsive on small screens
- Enable fullscreen mode for skill editor dialog on mdAndDown breakpoints
- Switch skill-editor grid to single-column stacked layout on mobile
- Constrain files panel height and enforce monaco editor min-height
* fix(dashboard): override skill editor dialog max-height on small screens
Address Sourcery-ai broader_impact finding on PR #9873: the base
`.skill-editor-dialog { max-height: min(88vh, 980px); overflow: hidden; }`
remains active in fullscreen mode on short mobile viewports (e.g.
landscape phones), where the stacked 20vh file tree + 40vh editor plus
title and action bar can exceed 88vh. Combined with `overflow: hidden`,
content gets clipped and the save/cancel buttons become unreachable.
Override `.skill-editor-dialog` within the existing
`@media (max-width: 860px)` block to lift the 88vh cap and allow
vertical scrolling when content overflows the viewport.
This is a minimal fix for the temporary solution; the 860-960px gap
between the media query and Vuetify's `mdAndDown` (960px) breakpoint is
accepted as a known limitation.
Preserve structured conversation history for cron and background-task wakeups so normal context truncation can process it.
Refs #9763
Co-authored-by: liruihan <liruihan@example.com>