Only mark installed plugins as updatable when the marketplace version is a known newer version, including pre-release-to-stable transitions. Conflict resolution also keeps per-plugin marketplace source lookup from current master.
* refactor: migrate to fastapi
* structure refactor
* fix: pyright fix
* refactor: improve error handling and public messages in plugin services
* feat(api): refactor API client integration and enhance request handling
- Updated API client configuration to use a dedicated HTTP client.
- Introduced utility functions for generating options, queries, and form data for API requests.
- Refactored multiple API methods to utilize the new utility functions for improved consistency and readability.
- Renamed types for clarity and updated import statements accordingly.
feat(docs): add script to update OpenAPI JSON from YAML spec
- Created a Python script to convert OpenAPI YAML specification to JSON format.
- The script supports customizable input and output paths.
- Ensured the script handles directory creation for output paths and validates the YAML structure.
* fix
* feat(auth): implement rate limiting for v1 login endpoint and enhance request handling
* Refactor dashboard API routers to use legacy_router for backward compatibility
- Changed all instances of dashboard_router to legacy_router across multiple API modules including platform, plugins, providers, sessions, skills, stats, subagents, t2i, tools, updates, and asgi_runtime.
- Updated route definitions to ensure existing endpoints remain functional under the new router structure.
- Introduced support for Quart request context in asgi_runtime to enhance compatibility with existing Quart-based plugins.
- Added a test case to validate the functionality of the new Quart request context handling in plugin extensions.
* chore: remove cli test
* fix: update dashboard tests for fastapi migration
* chore: satisfy ruff checks
* fix: update openapi api key scopes
* fix: sync config scope chip selection
* fix: restore quart dependency
* docs: clarify quart plugin api compatibility
* docs: update openapi scope documentation
* fix: use singular skill openapi scope
* fix: hide update service exception details
* fix: address fastapi review comments
* fix: address dashboard review findings
* docs: revert unrelated package deployment changes
* docs: update agent api generation guidance
* feat: add plugin page web api helpers
* docs: add plugin page bridge demo
* fix: type plugin upload files
* fix: stabilize plugin page uploads
* fix: type plugin web request proxy
* docs: remove plugin page docs example
* fix: authenticate plugin page SSE bridge
* fix: preserve repo source on plugin reinstall
* fix(dashboard): align extension market matching with repo identity
Use normalized repo keys as the primary identity when matching
installed extensions with marketplace plugins in useExtensionPage.
Only fall back to name matching for installed extensions that do
not have a repo, and normalize name lookups consistently on both
sides. Also clear stale online_version when no marketplace plugin
is matched.
* feat(plugin): support icon field in metadata.yaml for sidebar icon
* feat(sidebar): add isRawTitle support for non-i18n sidebar titles
* feat(sidebar): add usePluginSidebarItems composable for dynamic plugin WebUI entries
* feat(sidebar): inject plugin WebUI items into sidebar before More group
* refactor(plugin-page): remove header, make iframe full-screen
* feat(sidebar): restore plugin WebUI collapsible group
* fix(plugin-page): prevent iframe from capturing mousemove during sidebar resize
- Use absolute positioning instead of negative margin for full-screen layout
- Zero container padding for plugin page route in FullLayout
- Disable pointer-events on iframe during sidebar drag to avoid event capture
* refactor(sidebar): share plugin state reactively instead of polling
- Replace polling + events with module-level reactive shared state
- useExtensionPage.getExtensions() populates pluginSidebarState
- usePluginSidebarItems uses computed() to derive sidebar menu
- Zero additional API calls, updates instantly on any plugin change
* fix(sidebar): restore initial plugin data fetch on sidebar mount
* feat(sidebar): render plugin icons via MDI SVG CDN instead of subset font
- Plugin icons loaded from https://cdn.jsdelivr.net/npm/@mdi/svg@7/svg/
- Removes subset limitation - plugins can use any MDI icon
- Fallback to subset font class for built-in sidebar items
- Default icon remains mdi-puzzle when plugin doesn't specify one
* fix(sidebar): render plugin icons as inline SVG with currentColor for theme matching
* docs: add plugin sidebar icon documentation
* docs: require mdi- prefix for plugin icon field
* chore: ruff format
* fix: address review feedback
- Add SVG sanitization to prevent XSS via v-html (reject <script>, event handlers)
- Extract MORE_GROUP_KEY shared constant to avoid hardcoded i18n key
- Parallel SVG loading with Promise.all instead of serial
- Pure buildPluginItems, mutate iconSvg in place to avoid redundant rebuilds
- Fallback to default icon SVG when loading fails
- Revert accidental pnpm-lock.yaml changes
* chore: remove webui icon
---------
Co-authored-by: Soulter <905617992@qq.com>
* feat(plugin): pass theme through plugin page asset URLs and initial context
Add theme query parameter propagation through the plugin page asset pipeline
so that the bridge SDK initial context includes isDark.
* feat(plugin): inject data-theme and color-scheme into plugin page HTML
Set data-theme on <html> and add color-scheme meta tag server-side
to prevent flash when entering plugin pages in dark mode.
* feat(webui): add isDark getter to customizer store
* feat(webui): sync theme to plugin iframe via URL param and postMessage
Append theme query parameter to iframe src URL and include isDark
in the postMessage context. Watch uiTheme changes to re-send context.
* feat(bridge): auto-apply data-theme from context in plugin bridge SDK
Set data-theme attribute on document.documentElement when context
includes isDark, enabling live theme switching via postMessage.
* docs: add light/dark theme adaptation guide for plugin pages
Add theme adaptation section to existing plugin-pages docs in both
Chinese and English, covering CSS variables and onContext() usage.
* test: add theme sync tests for plugin page bridge and content
Verify isDark in bridge SDK initial context with various theme params,
and verify data-theme and color-scheme injection in rewritten HTML.
* fix(plugin): use case-insensitive regex for head tag in HTML rewrite
Replace string match for <head> with case-insensitive regex to handle
uppercase tags and tags with attributes, preventing duplicate injection
of color-scheme meta tag.
* refactor(webui): generalize isDark getter to support any dark theme
Replace hardcoded PurpleThemeDark check with suffix-based detection
so all dark theme variants are recognized automatically.
* refactor(plugin): extract theme helpers for HTML rewriting
Extract _get_request_theme and _apply_theme_to_html to eliminate
duplicate theme-parsing logic and isolate HTML mutation. Use case-
insensitive regex for head tag detection to prevent duplicate
injection when tags use mixed casing.
* style: apply ruff formatting to plugin page tests
Wrap long function call lines for consistency with project style.
* fix(plugin): handle existing data-theme and case-sensitive fallback in HTML rewrite
Strip any existing data-theme attribute before adding the new one to
prevent duplicate attributes. Use case-insensitive regex for the
<head> fallback insertion to avoid corrupting <html> tag attributes.
* fix(webui): add null guard to isDark getter
Guard against undefined uiTheme to prevent TypeError when the
theme config has not been initialized.
* fix(webui): centralize theme mapping and preserve hash in plugin page URL
Extract themeParam computed to avoid drift between URL and context.
Include hash fragment in iframe URL to support SPA hash routing.
* fix(webui): address CR feedback - deduplicate color-scheme meta, harden isDark getter, consolidate theme source
- _apply_theme_to_html: strip existing color-scheme meta before injecting to
avoid duplicates; merge data-theme strip+add into single-pass regex callback
- customizer.ts: replace brittle endsWith('Dark') with explicit theme name check
- _rewrite_plugin_page_html: use _get_request_theme() directly instead of
reading theme from extra_query_params
* fix(webui): 简化 isDark 推导、优化查询参数构建、使用暗色主题集合
- isDark 推导简化为 theme == "dark"(None == "dark" 为 False,去掉多余三元表达式)
- _prepare_plugin_page_query_params 改为线性构建,先计算再构建字典
- isDark getter 改用显式 DARK_THEMES Set,替代硬编码单值比较
---------
Co-authored-by: lxfight <lxfight@192.168.5.50>
* feat: future task UI
* fix: update filter label for UMO in English and Chinese locales
* feat: enhance cron job management with delivery target handling and UI improvements
* fix: update session label to indicate optional delivery target
* feat: add tooltip for last run time and error in cron job display
* fix(console): use toast for pip-install error display
The pip-install dialog displayed error messages as unstyled inline
<small> text with no color differentiation from success messages.
Replaced with useToast() to show errors as red snackbar, consistent
with the rest of the dashboard.
* fix(console): use i18n for pip-install toast fallback messages
* feat: add TOTP two-factor authentication for dashboard login
* fix: ensure TOTP verification uses UTC for accurate time comparison
* fix: update recovery code validation logic for disabling TOTP
* test: add unit tests for TOTP functionality and recovery code validation
* chore: format
* feat: add trust_proxy_headers switch for auth rate-limit IP source
* feat: make dashboard auth rate-limit configurable via system settings
Add auth_rate_limit config block to dashboard settings with enable
(default: true), average_interval (default: 1.0s), and max_burst
(default: 3) options. The dashboard auth middleware now reads from
config instead of using hardcoded values. The average_interval and
max_burst fields are conditionally shown only when rate limiting is
enabled.
* fix: normalize dashboard client IP from trusted proxy headers
* refactor: encapsulate rate limiter state into registry, add TTL
* feat: show dynamic page title during two-factor verification
* fix: require two-factor verification for protected config saves
* chore: format
* refactor: reorganize TOTP verification UI components for better layout
* refactor: clean up recovery stage UI by removing unused styles and improving label handling
* docs: add TOTP two-factor authentication documentation for WebUI
---------
Co-authored-by: Soulter <905617992@qq.com>
* fix: plugin name in the marketplace does not match the local plugin
* chore: update test
* Update astrbot/dashboard/routes/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* Update astrbot/dashboard/routes/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* Update astrbot/dashboard/routes/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* chore: reformat code
* Clean up unused variables in useExtensionPage.js
Removed unused sets for installed repositories and names.
* fix: 统一repo匹配逻辑,移除fallback
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* feat(plugin): add pages field to plugin list API response
Include discovered page names for each plugin in the /api/plugin/get
response, so the frontend can determine whether a plugin has a WebUI
without an extra detail request.
* feat(webui): add direct WebUI access button on plugin cards
- Add "open-webui" button on plugin cards when plugin has pages
- Navigate to plugin's first page directly from the card
- Adjust PluginPagePage iframe height for better UX
- Add i18n labels (zh-CN/en-US/ru-RU)
* perf(plugin): use asyncio.gather for concurrent page discovery
Replace sequential await loop with concurrent processing to avoid
blocking on disk I/O when discovering plugin pages.
* fix(webui): disable open plugin UI button when plugin is deactivated
Prevent navigation to a disabled plugin's WebUI page which would
result in an error.
* test: update plugin API tests to match pages field in list response
- test_plugin_get_excludes_scanned_pages: expect pages field now present
- test_plugins: use name-based lookup instead of exact count assertion
---------
Co-authored-by: lxfight <lxfight@192.168.5.50>
* fix(webui): enforce 12-char dashboard password policy with backend+frontend validation
* fix(i18n): update password policy hints and validation rules for improved security
* test: adapt dashboard auth fixtures for hashed default password
* fix(security): increase PBKDF2 iterations
* feat(auth): implement secure login challenge and proof verification
* chore: ruff format
* fix(auth): update md5 import syntax for consistency
* feat(dashboard): implement random password generation for empty dashboard password
* feat(auth): enforce plaintext password requirement for legacy MD5 hashes
* fix(i18n): update password hint texts to reflect auto-generated initial passwords
* feat(dashboard): implement password change requirement and reset logic
* feat(auth): implement account setup flow and password change requirements
* feat: Implement legacy password support and upgrade mechanism
- Added `hash_legacy_dashboard_password` function for MD5 hashing of passwords.
- Updated configuration handling to store both PBKDF2 and legacy password hashes.
- Introduced logic to check if password storage has been upgraded and if a password change is required.
- Modified dashboard authentication routes to handle legacy password checks and prompts for upgrades.
- Updated frontend to display warnings for legacy password storage and required upgrades.
- Enhanced tests to cover scenarios for legacy password handling and migration to new storage format.
* fix(logo): update text color styles to use CSS variables for consistency
* feat(dashboard): upgrade password storage and enforce change requirement
* fix(dashboard): update minimum password length from 12 to 10 characters
* fix(dashboard): update minimum password length from 10 to 8 characters
---------
Co-authored-by: RC-CHN <1051989940@qq.com>
* feat: enhance plugin page internationalization
- Updated PluginRoute to read initial context from JWT and set it in the bridge SDK.
- Added methods to retrieve locale and plugin metadata for better i18n support.
- Enhanced pluginI18n utility to resolve page-specific translations and added new functions for page titles and descriptions.
- Modified PluginPagePage and PluginDetailPage to utilize new i18n features for dynamic content rendering.
- Improved documentation for plugin page i18n structure and usage.
- Added tests to verify the correct integration of i18n in plugin pages and context handling.
* fix test
* feat: supports plugin to add skills
* fix tests
* fix: fs tools
* Add tests for plugin skills handling and improve skill management
- Implement test for restricted local member reading plugin skill inventory even if the plugin is inactive.
- Ensure that the skill synchronization process retains built-in skills when local skills are empty, including proper handling of plugin paths.
- Update dashboard tests to verify that plugin details include components when requested.
- Enhance skill metadata enrichment tests to include inactive plugin-provided skills for inventory.
- Add filtering tests for plugin skills based on current configuration, ensuring only allowed plugins are considered and inactive plugins are skipped.
Co-authored-by: Copilot <copilot@github.com>
* fix: handle PPIO platform context-length error messages (#7888)
* fix: 压缩算法删除 user 消息 Bug 修复
* perf: improve truncate algo
* fix: improve context length error detection for PPIO platform compatibility
- Extend error detection to handle PPIO's error message format:
'The input is longer than the model's context length'
- Add case-insensitive matching using .lower() for robustness
- Maintain backward compatibility with existing 'maximum context length' check
This fixes the issue where PPIO platform models (e.g., ppio/zai-org/glm-5-turbo)
would fail with AgentState.ERROR due to unrecognized context length errors.
---------
Co-authored-by: Soulter <905617992@qq.com>
* fix: 支持微信客服文件消息 (#7923)
* fix: 支持微信客服文件消息
* fix: remove WeCom file message placeholder
* fix(provider): fix Anthropic custom headers and system prompt compatibility (#7587)
* fix(provider): fix Anthropic custom headers and system prompt compatibility
- Pass custom_headers via AsyncAnthropic's `default_headers` parameter
instead of creating a separate httpx.AsyncClient. This avoids
`isinstance` check failures when multiple httpx installations exist
on sys.path (e.g. bundled Python + system Python).
- Use list format for the `system` parameter (`[{"type": "text", ...}]`)
instead of a plain string. The list format is supported by the official
Anthropic API and is also compatible with third-party API proxies that
reject the string format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(provider): fix Anthropic custom headers and system prompt compatibility
- Pass custom_headers via AsyncAnthropic's `default_headers` parameter
instead of creating a separate httpx.AsyncClient. This avoids
`isinstance` check failures when multiple httpx installations exist
on sys.path (e.g. bundled Python + system Python).
- Use list format for the `system` parameter (`[{"type": "text", ...}]`)
instead of a plain string. The list format is supported by the official
Anthropic API and is also compatible with third-party API proxies that
reject the string format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add test unit
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* perf: improve logic of adding models
Co-authored-by: piexian <piexian@users.noreply.github.com>
* chore: remove redundant logger messages and improve log clarity
Co-authored-by: Copilot <copilot@github.com>
* chore: ruff format
* docs: update knowledge base docs
closes: #7962
* fix(#7907): send_message_to_user cron 场景下 session 容错 (#7911)
* fix: send_message_to_user cron 场景下 session 容错 (#7907)
- LLM 在主动场景可能只传 session_id 而非完整三段式,
from_str 失败时用 current_session 补全前两段。
Co-authored-by: Copilot <copilot@github.com>
* fix: 限制 session 补全仅对裸 session_id 生效,避免误修带冒号的错误输入 (#7907)
* feat: add session information to cron job payload
Co-authored-by: Copilot <copilot@github.com>
* fix: improve clarity and consistency of safety mode prompts
Co-authored-by: Copilot <copilot@github.com>
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Weilong Liao <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
* perf: tool rendering in conversation page (#7937)
* fix(dashboard): route conversation history tool messages through ToolCallCard
When viewing conversation history, large tool outputs (e.g. a single
git log --stat producing tens of KB) caused the browser renderer to
freeze. Root cause: formattedMessages mapped every role (including
tool / system / _checkpoint) into user/bot bubbles, and bot plain
strings went through markstream-vue's MarkdownRender. Single 88KB
tool messages plus 88-of-them adding up to ~349KB of synchronous
markdown parsing was enough to block the main thread for 5+ seconds.
This patch:
- Indexes tool-role messages by tool_call_id
- Filters formattedMessages to user/assistant only — tool, system and
_checkpoint roles no longer render as standalone bubbles
- Converts assistant.tool_calls (OpenAI shape, with tc.name/tc.arguments
fallbacks) into the existing tool_call MessagePart, attaching the
paired result so MessageList's ToolCallCard renders it (default
collapsed, no longer feeds large strings into the markdown renderer)
- Drops empty placeholder plain parts when an assistant message only
carries tool_calls
- Sets ts/finished_ts to 0 as a sentinel: ToolCallCard.toolCallDuration
returns "" when startTime <= 0, suppressing a misleading "0ms"
duration that would otherwise appear because conversation history
has no real timing data
Behavior change: tool results are now embedded in their assistant's
ToolCallCard.result instead of appearing as separate bot bubbles.
This matches the main chat UI's behavior.
Fixes#7929
Refs #7372#7456
* style(dashboard): use single scrollbar in conversation history preview
ToolCallCard's result/args panes have their own max-height + overflow,
which produced a nested scrollbar when nested inside the history
preview's already-scrollable .conversation-messages-container. Override
those constraints inside the preview only — the outer 500px-bounded
container already provides scroll bounds, so a single scrollbar feels
cleaner. The main chat UI is unaffected.
---------
Co-authored-by: wanger <wanger@example.com>
* fix: ruff format
* feat: add python tool timeout param (#7953)
* feat: add python tool timeout param
* Update python.py
---------
Co-authored-by: Weilong Liao <37870767+Soulter@users.noreply.github.com>
* fix: 钉钉连接超时后自动重连失败 (#7924)
* fix: improve DingTalk adapter error handling in run() method
* fix: add retry logic for DingTalk SDK task unexpected exit
* fix: use task.add_done_callback to wake thread on task completion, handle UnboundLocalError
* refactor: extract retry logic into handle_retry helper function
---------
Co-authored-by: Blueteemo <Blueteemo@users.noreply.github.com>
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: leonforcode <leonbeyourside01@gmail.com>
Co-authored-by: AstralSolipsism <134063164+AstralSolipsism@users.noreply.github.com>
Co-authored-by: Pink YuDeer <wer00001@outlook.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: piexian <piexian@users.noreply.github.com>
Co-authored-by: NayukiMeko <ChibaNayuki@163.com>
Co-authored-by: wanger <122891289+10knamesmore@users.noreply.github.com>
Co-authored-by: wanger <wanger@example.com>
Co-authored-by: Haoran Xu <3230105281@zju.edu.cn>
Co-authored-by: 千岚之夏 <108566281+Blueteemo@users.noreply.github.com>
Co-authored-by: Blueteemo <Blueteemo@users.noreply.github.com>
* fix(dashboard): route conversation history tool messages through ToolCallCard
When viewing conversation history, large tool outputs (e.g. a single
git log --stat producing tens of KB) caused the browser renderer to
freeze. Root cause: formattedMessages mapped every role (including
tool / system / _checkpoint) into user/bot bubbles, and bot plain
strings went through markstream-vue's MarkdownRender. Single 88KB
tool messages plus 88-of-them adding up to ~349KB of synchronous
markdown parsing was enough to block the main thread for 5+ seconds.
This patch:
- Indexes tool-role messages by tool_call_id
- Filters formattedMessages to user/assistant only — tool, system and
_checkpoint roles no longer render as standalone bubbles
- Converts assistant.tool_calls (OpenAI shape, with tc.name/tc.arguments
fallbacks) into the existing tool_call MessagePart, attaching the
paired result so MessageList's ToolCallCard renders it (default
collapsed, no longer feeds large strings into the markdown renderer)
- Drops empty placeholder plain parts when an assistant message only
carries tool_calls
- Sets ts/finished_ts to 0 as a sentinel: ToolCallCard.toolCallDuration
returns "" when startTime <= 0, suppressing a misleading "0ms"
duration that would otherwise appear because conversation history
has no real timing data
Behavior change: tool results are now embedded in their assistant's
ToolCallCard.result instead of appearing as separate bot bubbles.
This matches the main chat UI's behavior.
Fixes#7929
Refs #7372#7456
* style(dashboard): use single scrollbar in conversation history preview
ToolCallCard's result/args panes have their own max-height + overflow,
which produced a nested scrollbar when nested inside the history
preview's already-scrollable .conversation-messages-container. Override
those constraints inside the preview only — the outer 500px-bounded
container already provides scroll bounds, so a single scrollbar feels
cleaner. The main chat UI is unaffected.
---------
Co-authored-by: wanger <wanger@example.com>
* feat: supports to download plugins via astrbot official plugin storage
* fix: improve exception message for missing root directory name in PluginUpdator
* feat: Implement plugin internationalization support
- Added support for plugins to provide localized names, descriptions, and configuration texts through JSON files in the `.astrbot-plugin/i18n` directory.
- Updated various components to utilize the new internationalization functions, including `ConfigItemRenderer`, `ExtensionCard`, `ItemCard`, `ObjectEditor`, `PluginSetSelector`, and `TemplateListEditor`.
- Enhanced the `usePluginI18n` utility to resolve plugin-specific translations based on the current locale.
- Modified the `common` store to include an `i18n` field for plugin metadata.
- Updated documentation to include guidelines for plugin internationalization.
- Added tests to ensure proper loading of localization files and integration with plugin metadata.
* perf: code quality
* feat: update config path handling for internationalization support
* feat: update ExtensionCard variant to outlined and adjust InstalledPluginsTab layout for better responsiveness
* feat: update MCP servers management UI and add descriptions for better clarity
* feat: enhance OutlinedActionListItem component with clickable functionality and new slots
feat(i18n): update English, Russian, and Chinese translations for extension and knowledge base features
fix: improve DocumentDetail and KBDetail views with outlined card styles and remove unnecessary dividers
refactor: streamline KBList component to use OutlinedActionListItem for better UI consistency
style: adjust styles for knowledge base components and improve responsive design
test: add security tests for skill file browser and editor to prevent path traversal and file size issues
* feat: update UI components and styles for improved layout and readability
* feat: add PluginDetailPage component for detailed plugin information display
refactor: remove extension preference storage management and related tests
chore: clean up useExtensionPage by removing unused preference storage logic
* feat: add getHandlerDisplayName function for improved handler name display
* feat: add EPUB parsing support for knowledge base and file reader
* feat: update supported file formats for document upload in knowledge base
* feat: enhance EPUB parser to support spine order and generic containers
* makeitdown parse epub
* update parser
* fix