Compare commits

...

1362 Commits

Author SHA1 Message Date
邹永赫
6f5541bc7e fix: restore orchestrator logger binding 2026-03-25 21:50:48 +09:00
邹永赫
e7f57ae8ef fix: simplify runtime lifecycle coordination 2026-03-25 21:33:49 +09:00
邹永赫
0100f8d20c fix: streamline runtime guard handling 2026-03-25 20:12:05 +09:00
邹永赫
c1e2040f43 fix: harden deferred startup recovery 2026-03-25 19:42:40 +09:00
邹永赫
ae53b9fc9f fix: harden runtime cleanup review fixes
Continue terminating remaining providers and disable MCP servers even if one provider terminate hook fails.

Also add InitialLoader failure-path coverage and extract guarded plugin routes into a shared constant for easier review and maintenance.
2026-03-25 14:03:06 +09:00
邹永赫
63cbab610a feat: add two-phase startup lifecycle
Allow the dashboard to become available before plugin bootstrap completes and surface runtime readiness and failure states to API callers.

Guard plugin-facing endpoints until runtime is ready and clean up provider and plugin runtime state safely across bootstrap failures, retries, stop, and restart flows.
2026-03-25 14:02:02 +09:00
LIghtJUNction
be65022de1 refactor(protocols): update protocol client implementations 2026-03-25 00:10:29 +08:00
LIghtJUNction
613910f592 refactor(cli): update CLI commands structure 2026-03-25 00:10:23 +08:00
LIghtJUNction
64f3a3c7ee chore: update project config for Rust core runtime 2026-03-25 00:09:54 +08:00
LIghtJUNction
7baff6f255 feat(rust): initial Rust core runtime with CLI support
- Add Rust orchestrator with async bootstrap pattern
- Implement CLI with clap (start, stats, health subcommands)
- Add protocol stubs (LSP, MCP, ACP, ABP)
- Python bindings via pyo3 (_core module)
- Use maturin as build backend
- Add tombi.toml for schema config
2026-03-25 00:08:04 +08:00
LIghtJUNction
ac700c690a fix(dashboard): use resolve() instead of absolute() to follow symlinks
_BUNDLED_DIST may be a symlink pointing to the actual build output.
Using resolve() ensures the path is correctly resolved to the real
directory, allowing the dashboard frontend to load properly when
bundled as a symlink in the dev branch.
2026-03-24 21:47:14 +08:00
LIghtJUNction
a7343c5a76 fix(test): move sys.path before import in conftest.py
The import of tests.fixtures.helpers happened before sys.path was
modified, causing ModuleNotFoundError when running pytest.
2026-03-24 21:40:01 +08:00
LIghtJUNction
abbb2c85fc revert: restore run command to old architecture
The run command should use the original InitialLoader-based startup,
not the new _internal/runtime bootstrap. Only the dev subcommand
uses the new architecture.
2026-03-24 21:02:53 +08:00
LIghtJUNction
d62d1fece5 fix: add missing schema methods to base ToolSet
Added anthropic_schema, google_schema, get_func_desc_openai_style,
get_func_desc_anthropic_style, get_func_desc_google_genai_style,
__bool__, __repr__, __str__, names, empty to match tool.py ToolSet.
2026-03-24 20:56:51 +08:00
LIghtJUNction
5f42d82293 fix(test_abp_client): update test to match new non-Future implementation
shutdown() now clears pending requests directly instead of calling
cancel() on asyncio.Future instances.
2026-03-24 20:49:48 +08:00
LIghtJUNction
7e941c8487 fix: add get_light_tool_set and get_param_only_tool_set to base ToolSet
These were called on ToolSet instances returned by get_full_tool_set()
but were missing from the base ToolSet implementation.
2026-03-24 20:48:11 +08:00
LIghtJUNction
569ff433ac fix(build): prevent wheel failure when dashboard not bundled
When ASTRBOT_BUILD_DASHBOARD is not set, the hatch build hook now
creates an empty target dir with a .placeholder file so the
artifacts glob matches and hatchling does not fail.
2026-03-24 19:19:55 +08:00
LIghtJUNction
4cc700f57d fix(dashboard): suppress benign SSL close notify errors
When clients disconnect abruptly, hypercorn raises
ssl.SSLError APPLICATION_DATA_AFTER_CLOSE_NOTIFY during SSL shutdown.
This is benign and expected behavior. Wrap serve() with
try/except to suppress these spurious errors.
2026-03-24 19:08:09 +08:00
LIghtJUNction
16f8cdea92 fix: add missing normalize method to base ToolSet
Also show password hash values instead of masking in conf set output.
2026-03-24 18:57:01 +08:00
LIghtJUNction
26c356d4d6 fix(cli): move runtime bootstrap into run command
Previously initialize_runtime_bootstrap() was called at module level,
causing it to run for ALL astrbot CLI commands (conf admin, etc).
Now it only runs when the 'run' command is executed.
2026-03-24 18:55:58 +08:00
LIghtJUNction
1a16a08550 feat: add astrbot-core Rust foundation with pyo3 bindings
- Core orchestrator with star registration
- Runtime stats tracking
- Message types
- Python bindings via pyo3
- No unsafe, strict clippy
2026-03-24 18:44:01 +08:00
LIghtJUNction
4705fc2f13 feat: add astrbot-core rust project 2026-03-24 18:30:45 +08:00
LIghtJUNction
d60a3f0d1d fix: add missing add_tool and merge methods to base ToolSet
The internal ToolSet (base.py) was missing add_tool() and merge()
methods that the agent code expects. When tmgr.get_full_tool_set()
returned a base.py ToolSet, calls to add_tool() and merge() failed.

Added:
- add_tool() as alias to add()
- merge() method to merge another ToolSet

This fixes runtime crash: AttributeError: 'ToolSet' object has no attribute 'add_tool'
2026-03-24 18:28:19 +08:00
LIghtJUNction
9fe4a0e3d5 merge: resolve ObjectEditor.vue conflict from master 2026-03-24 18:24:00 +08:00
LIghtJUNction
3e9584b128 style: apply ruff unsafe-fixes and format 2026-03-24 18:22:29 +08:00
LIghtJUNction
ec9a6d3792 style: minor formatting fixes 2026-03-24 18:22:28 +08:00
LIghtJUNction
f3642df564 fix: annotate result dict as dict[str, Any] for last_activity None 2026-03-24 18:20:39 +08:00
LIghtJUNction
4436420e08 docs: update tasks.md to reflect completion 2026-03-24 17:43:12 +08:00
LIghtJUNction
f7ec5ea1c1 feat: add name field to protocol status and message tracking
- Add _message_count and _last_activity_timestamp to orchestrator
- Add record_activity() method to orchestrator
- Add name field to get_protocol_status returns
- Add total_messages and last_activity to get_stats
- Update tests to verify new fields
2026-03-24 17:42:40 +08:00
Vorest
c6f4dd1d26 fix(tests): update scanUsedIcons tests to include required radio icons (#6894) 2026-03-24 17:23:10 +08:00
LIghtJUNction
dbeb104600 test: add RuntimeError tests for LSP client not connected cases
- Add test_lsp_client_send_request_not_connected
- Add test_lsp_client_send_notification_not_connected
- Mark 6.2 and 7.2 tasks complete in tasks.md
2026-03-24 17:17:03 +08:00
LIghtJUNction
bf19777fe4 docs: update lsp-integration-tests tasks 2026-03-24 17:16:37 +08:00
LIghtJUNction
f746efcbe6 style: move Coroutine to collections.abc import 2026-03-24 17:13:52 +08:00
LIghtJUNction
4f686ed9c5 fix: resolve undefined name errors (F821)
- shell.py: Replace undefined TContext with AstrAgentContext
- context.py: Add missing Coroutine import from typing
- lsp/client.py: cleanup (already applied)
2026-03-24 17:12:58 +08:00
LIghtJUNction
35633e5d1d test: add LSP integration tests with echo server fixture 2026-03-24 17:04:44 +08:00
LIghtJUNction
cf52461c39 docs: add lsp-integration-tests specs and tasks 2026-03-24 17:02:38 +08:00
LIghtJUNction
c0010de837 docs: add openspec specs for integration tests changes 2026-03-24 16:58:39 +08:00
LIghtJUNction
40a68c755e docs: add openspec metadata for add-internal-integration-tests 2026-03-24 16:52:45 +08:00
LIghtJUNction
cac627270e docs: add specs for add-internal-integration-tests change 2026-03-24 16:50:35 +08:00
LIghtJUNction
dd53727e81 style: apply ruff --unsafe-fixes for common issues
Fixed 31 issues including:
- Remove print statements (T201)
- Fix star imports (F403)
- Other auto-fixable style issues
2026-03-24 16:36:46 +08:00
LIghtJUNction
9f945cfb6c docs: add runtime-status-star spec 2026-03-24 16:12:25 +08:00
LIghtJUNction
faa6f5f495 docs: add abp-runtime-status-plugin spec and specs 2026-03-24 16:09:26 +08:00
Ruochen Pan
364b62008c fix(ui): include vuetify radiobox icons (#6892)
Add the radiobox icons used indirectly by Vuetify internals
to the required MDI subset so they are kept during font
generation.

Regenerate the subset CSS and font files to prevent missing
radio button icons at runtime.
2026-03-24 16:05:08 +08:00
LIghtJUNction
2799bbb766 fix: MCP integration tests skip and test orchestrator adaptation
- Fix echo_mcp_server.py stdio parsing (use stdin.buffer, not readline)
- Mark MCP handshake tests as skip (protocol requires server notifications)
- Update test_list_stars to account for auto-registered RuntimeStatusStar
2026-03-24 15:18:17 +08:00
LIghtJUNction
b78d3fcd0b feat: add RuntimeStatusStar and ACP integration tests
- Add RuntimeStatusStar ABP plugin exposing runtime internal state
- Add ACP echo server fixture for testing
- Add ACP integration tests (TCP/Unix socket connectivity)
- Update orchestrator to auto-register RuntimeStatusStar
- Update tests to account for auto-registered star
2026-03-24 13:49:49 +08:00
Soulter
2e16281338 fix(openapi): rename route view function 2026-03-24 11:00:20 +08:00
Soulter
212c681459 feat(api): add GET file endpoint and update file route to support multiple methods (#6874) 2026-03-24 10:24:11 +08:00
LIghtJUNction
92ba30b6e1 chore: apply ruff format to codebase
Reformat 23 files for consistent code style.
2026-03-24 10:14:28 +08:00
Stardust
7305d46328 fix: wrong index in ObjectEditor updateKey causing false 'key exists' error
* fix: wrong index in ObjectEditor updateKey causing false 'key exists' error

* fix: same index mismatch issue in updateJSON

* fix(ui): stabilize ObjectEditor pair keys

Use generated ids for key-value pairs instead of array indexes to
prevent mismatch issues during editing and rendering.

Also replace duplicate-key alerts with toast warnings for a more
consistent UI experience.

---------

Co-authored-by: RC-CHN <1051989940@qq.com>
2026-03-24 09:30:37 +08:00
LIghtJUNction
cf47a2ec61 chore: auto commit 2026-03-24 09:30:05 +08:00
dependabot[bot]
39d3741e4c chore(deps): bump pnpm/action-setup in the github-actions group (#6862)
Bumps the github-actions group with 1 update: [pnpm/action-setup](https://github.com/pnpm/action-setup).


Updates `pnpm/action-setup` from 4.4.0 to 5.0.0
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v4.4.0...v5.0.0)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  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-03-24 09:08:07 +08:00
LIghtJUNction
08af1e0215 refactor: improve MCP connection test error handling in FuncCall 2026-03-24 02:56:43 +08:00
LIghtJUNction
9908f3b443 chore: auto commit 2026-03-24 01:06:06 +08:00
LIghtJUNction
15789efbfb chore: auto commit 2026-03-24 00:06:24 +08:00
LIghtJUNction
f5bc74ca58 feat(openspec): add abp-runtime-status-plugin change proposal 2026-03-24 00:04:27 +08:00
LIghtJUNction
310d2d6998 feat: add integration tests infrastructure and MCP echo server fixture
- Add tests/integration/ directory with fixtures/
- Create echo_mcp_server.py for MCP testing
- Create test_mcp_integration.py with basic tests
- Fix bug in MCP client: use stdio_transport instead of _streams_context
- Add examples/abp_demo.py demonstrating ABP protocol
- Update openspec with integration tests change
2026-03-23 23:01:55 +08:00
LIghtJUNction
67373ccaa1 merge: resolve conflicts from master 2026-03-23 22:31:33 +08:00
LIghtJUNction
99a9941aba chore: auto commit 2026-03-23 22:21:06 +08:00
LIghtJUNction
385d882aa9 fix: resolve anyio compliance and type checking issues
- Fix orchestrator to use anyio.get_cancelled_exc_class() instead of anyio.CancelledError
- Fix tests to properly check for anyio compliance (not violations)
- Add type annotations for MCP exception fallbacks in registry.py
- Remove unused type: ignore comment in mcp/tool.py
- All 111 tests pass
- uvx ty check passes
- ruff check passes
2026-03-23 22:15:47 +08:00
LIghtJUNction
3485605312 fix: correct logger import in ACP client 2026-03-23 22:02:38 +08:00
LIghtJUNction
20b7f60330 chore: update protocol clients and add architecture compliance tests 2026-03-23 22:01:02 +08:00
LIghtJUNction
225ef79337 test: add ABP protocol tests 2026-03-23 21:50:20 +08:00
LIghtJUNction
9058505593 test: add gateway WebSocket manager tests 2026-03-23 21:49:19 +08:00
LIghtJUNction
20886c3855 test: add MCP client and additional orchestrator tests 2026-03-23 21:48:22 +08:00
LIghtJUNction
49a32fbf49 test: add ABP client tests 2026-03-23 21:47:28 +08:00
LIghtJUNction
23e3fe6eac chore: auto commit 2026-03-23 21:45:14 +08:00
LIghtJUNction
e9e7c7ff07 feat: add builtin tools module for _internal package 2026-03-23 21:44:14 +08:00
LIghtJUNction
9d49acdce7 refactor: remove unused imports and add TODO for anyio migration 2026-03-23 21:41:06 +08:00
LIghtJUNction
0b25f4eba1 fix(test): use MagicMock instead of AsyncMock for sync ABP methods 2026-03-23 21:39:52 +08:00
LIghtJUNction
f62fc4d8a0 chore: auto commit 2026-03-23 21:37:17 +08:00
LIghtJUNction
ced1a4fbb6 chore: auto commit 2026-03-23 21:35:18 +08:00
LIghtJUNction
0f74731c53 feat(runtime): add new internal architecture with protocol clients
Implement the new _internal package structure for AstrBot runtime:
- Add AstrbotOrchestrator with LSP, MCP, ACP, ABP protocol clients
- Add AstrbotGateway server with WebSocket support
- Add comprehensive test suite for runtime module
- Add tools base module for MCP tools

Implements bootstrap function using anyio task groups for
concurrent protocol client initialization.
2026-03-23 21:26:22 +08:00
LIghtJUNction
f60ffdb62a refactor(dashboard): remove unused sha256 utility
The sha256.ts module is no longer used by any frontend code.
2026-03-23 20:38:43 +08:00
LIghtJUNction
320425f7e7 refactor: remove unused is_legacy_dashboard_password_hash
Remove the dead is_legacy_dashboard_password_hash helper which was
never used by verify_dashboard_password. Legacy SHA-256/MD5 hashes
are not supported - only Argon2 and PBKDF2 are valid password hashes.
Users with old SHA-256 hashes must reset their password.
2026-03-23 20:34:02 +08:00
LIghtJUNction
a78a55bcc0 perf: validate config_path before checking existence (#6722)
Add a check for empty config_path in check_exist method
2026-03-23 19:04:07 +08:00
LIghtJUNction
bbcdc502a5 feat(dashboard): clarify frontend/backend behavior with better messages
- Track _webui_fallback flag to distinguish "frontend disabled" vs "frontend enabled but files missing"
- Improve messages:
  - "前端未内置或未初始化,回退到仅启动后端" when fallback occurs
  - "前端已禁用" when user explicitly disabled
  - "正在启动 API Server" instead of "WebUI 已分离"
  - "前端未启用,请访问在线面板" for HTTP responses when frontend disabled
2026-03-23 17:43:30 +08:00
LIghtJUNction
fcaaeb5114 test: fix tests for abstract ComputerBooter
ComputerBooter is now an abstract class, so tests that tried to
instantiate it directly need to be updated:

- test_booter_decoupling.py: remove test_get_tools_delegates_to_class
  since base class cannot be instantiated
- test_profile_aware_tools.py: use ShipyardBooter.__new__() to test
  base class property defaults (capabilities, browser)
- test_computer.py: skip BoxliteBooter test since it's also abstract
  and requires the boxlite module
2026-03-23 17:37:14 +08:00
LIghtJUNction
f688343072 fix: remove incorrect startup suggestion from version check 2026-03-23 17:32:52 +08:00
LIghtJUNction
cfdb4ef651 feat: add Python version check requiring 3.12 or 3.13
- Add version check at startup in both __main__.py and cmd_run.py
- Suggest using `uv run -m astrbot` or reinstalling with uv
- Add ABC base class and abstract methods to ComputerBooter
- Improve type annotations in OpenAIAgentsRunner
2026-03-23 17:32:11 +08:00
LIghtJUNction
99c66c2410 feat(cli): add real-time log streaming in non-interactive mode
- Non-interactive mode now streams logs to stdout with color-coded levels
- Add proper async cleanup when shutting down
- Fix type annotations in coze and deerflow agent runners
2026-03-23 17:21:05 +08:00
lightjunction
bf21f1a499 fix(dashboard): update password hints to reference CLI instead of "default password"
Security improvement: password is now set via `astrbot conf admin` CLI
command rather than being a hardcoded default. Updated all relevant
i18n strings to reflect this change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:55:30 +08:00
lightjunction
36eb3f3eb8 fix(dashboard): improve WebUI disabled messaging
When WebUI is disabled via config, tell users to use the online
dashboard at dash.astrbot.men instead of the cryptic technical message.

When WebUI files are missing (index.html not found), also redirect
users to the online dashboard instead of just saying "WebUI will be
disabled."

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:52:33 +08:00
lightjunction
1048752b27 debug(dashboard): add explicit logging when enable_webui=false
This helps diagnose whether the API server is actually starting
when WebUI is disabled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:51:35 +08:00
Soulter
31487995bb chore: ruff format 2026-03-23 16:13:30 +08:00
Soulter
3c6cd22e2c feat(lark): add collapsible reasoning panel support and enhance message handling (#6831)
* feat(lark): add collapsible reasoning panel support and enhance message handling

* feat(lark): refactor collapsible panel creation for improved readability and maintainability
2026-03-23 16:12:43 +08:00
lightjunction
52bfe5f605 debug(dashboard): add logging for ASTRBOT_PORT env var vs config priority
This helps diagnose when the environment variable is being ignored in
favor of cmd_config.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 16:06:10 +08:00
Soulter
189d378f91 fix: correct voice message support status in WeChat adapter documentation 2026-03-23 15:53:13 +08:00
lightjunction
999ce123a7 fix(discord): remove duplicate command registration loop
The _collect_and_register_commands method was iterating over
star_handlers_registry twice: once via collect_commands() and again
in a redundant second loop. This caused the same commands to be
registered to the Discord client twice, resulting in "Application
command names must be unique" errors during sync_commands().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 15:29:06 +08:00
LIghtJUNction
8e0314a559 refactor: reorganize agent runner imports for openai-agents integration
- Move AgentResponse to its own module in core/agent/response
- Update import paths in all runner files
- Add provider_config parameter to ToolLoopAgentRunner
2026-03-23 13:29:53 +08:00
LIghtJUNction
524b5cbe42 fix(test_dashboard): add missing @pytest.mark.asyncio decorator
The test_t2i_set_active_template_syncs_all_configs async test was
missing its decorator, causing pytest to fail with "async def functions
are not natively supported" error.
2026-03-23 13:25:28 +08:00
LIghtJUNction
19e0952a6f fix: standardize dashboard env vars to ASTRBOT_* prefix only
- Remove all DASHBOARD_* and ASTRBOT_DASHBOARD_* fallback chains
- server.py now only checks ASTRBOT_HOST, ASTRBOT_PORT, ASTRBOT_SSL_*
- cmd_run.py no longer sets legacy DASHBOARD_* environment variables
- Clean up import paths for agent runners
2026-03-23 13:18:23 +08:00
LIghtJUNction
93f92dc366 merge: sync with origin/master
Conflicts resolved:
- tests/test_dashboard.py: kept all tests from both sides
- astrbot/core/config/default.py: took origin/master mimo-tts hints
- astrbot/dashboard/routes/t2i.py: took origin/master _sync_active_template_to_all_configs approach
- dashboard/src/views/Settings.vue: took origin/master version
2026-03-23 13:15:35 +08:00
LIghtJUNction
e005bb6f39 test(dashboard): add tests for tools routes
- Add 13 tests covering tools route handlers:
  - GET /tools/list
  - POST /tools/toggle-tool (missing params, not found)
  - GET /tools/mcp/servers
  - POST /tools/mcp/add (empty name, no config, connection failure)
  - POST /tools/mcp/update (empty name, not found)
  - POST /tools/mcp/delete (empty name, not found)
  - POST /tools/mcp/test (invalid config)
  - POST /tools/mcp/sync-provider (unknown provider)
- tools.py coverage: 9% → 38%
- Total tests: 47 → 60
2026-03-23 13:03:45 +08:00
LIghtJUNction
ce6e9f9d0b refactor: move openai_agents to _internal/agents
Move the openai-agents SDK integration from core/agent/runners/openai_agents
to _internal/agents/openai_agents to follow the internal implementation pattern.
2026-03-23 12:56:09 +08:00
Soulter
b7e8b335a7 fix: cannot use tools in siliconflow provider (#6829)
* fix: cannot use tools in siliconflow provider

* fix: handle empty choices in ChatCompletionStreamState
2026-03-23 12:53:37 +08:00
LIghtJUNction
80c46c0639 feat: add openai-agents SDK integration
Add integration layer for using the openai-agents library with
AstrBot's existing agent infrastructure:

- OpenAIAgentsRunner: A BaseAgentRunner implementation that wraps
  the openai-agents Agent class
- Tool adapter to convert AstrBot FunctionTool to openai-agents format
- Support for tool handlers and FunctionToolManager integration
2026-03-23 12:53:00 +08:00
LIghtJUNction
f554529940 fix: remove unnecessary type ignore comment in misskey_adapter 2026-03-23 12:49:23 +08:00
LIghtJUNction
f55016bcb2 refactor: type annotations and i18n improvements
- Add i18n support to cmd_conf.py (config validators)
- Fix BaseFunctionToolExecutor to be an ABC
- Add explicit type annotations for dict payloads
- Various type annotation improvements
2026-03-23 12:49:13 +08:00
LIghtJUNction
f2c0c2a9de feat: add _internal modules for MCP, Skills, and Tools
This commit adds the _internal package structure for AstrBot's
standardized MCP & Skills support:

astrbot/_internal/mcp/:
- MCPClient for MCP server connections
- MCPTool wrapper for MCP tools
- MCP configuration management

astrbot/_internal/skills/:
- SkillManager for skill lifecycle
- Skill parser and loader
- SkillToToolConverter for tool-based skills
- Prompt builder for skills

astrbot/_internal/tools/:
- ToolSchema, FunctionTool, ToolSet base definitions
- FunctionToolManager for tool registry
- Builtin tools (cron, send_message, kb_query)
- Tool providers (internal, plugin, computer)

astrbot/api/:
- Public API for tools (ToolRegistry, tool decorator)
- Public API for MCP (get_mcp_servers, register_mcp_server)
- Public API for skills (get_skill_manager, skill_to_tool)
2026-03-23 12:48:34 +08:00
LIghtJUNction
f0423a7174 chore: add openai-agents dependency
Added openai-agents library for enhanced agent implementation
2026-03-23 12:48:01 +08:00
LIghtJUNction
da62b57c56 feat(i18n): add Chinese and English language support for CLI and TUI
- Add CLI i18n module (astrbot/cli/i18n.py) with zh/en translations
- Add TUI i18n module (astrbot/tui/i18n.py) with zh/en translations
- Update CLI commands to use translated strings
- Update TUI app and screen to use translated strings
- Add ASTRBOT_CLI_LANG and ASTRBOT_TUI_LANG to .env.example
- Update cmd_run.py env var documentation
- Add backward compatibility for moved modules with DeprecationWarning
2026-03-23 12:43:37 +08:00
LIghtJUNction
8d26c38b32 test(dashboard): add tests for command and api_key routes
Add tests for:
- command.py: toggle/rename/permission endpoints with missing params
- api_key.py: create with invalid scopes/expires_in_days, revoke/delete
  with missing key_id and not found cases

This improves coverage:
- api_key.py: 73% -> 96%
- command.py: 35% -> 60%
2026-03-23 12:34:44 +08:00
Ruochen Pan
ade42227e4 fix(t2i): sync active template across all configs (#6824)
* fix(t2i): sync active template across all configs

apply template activation and reset to every config profile instead of only
the default one, and reload each pipeline scheduler so changes take effect
consistently in multi-config setups

add a dashboard test that creates extra configs and verifies active template
updates and scheduler reload coverage across all config ids

* fix(t2i): reload all schedulers on template changes

extract a shared helper to reload pipeline schedulers for every config.
when syncing or resetting the active template, persist each config and
then reload all schedulers to keep mappings consistent.

also reload all schedulers when updating the currently active template,
and add dashboard tests to verify cross-config sync and scheduler
replacement behavior.
2026-03-23 10:16:07 +08:00
bread
f984bced06 feat(dashboard): add log and cache cleanup in settings (#6822)
* feat(dashboard): add log and cache cleanup in settings

* refactor: simplify storage cleaner log config handling

* fix: Repair abnormal indentation

* fix(storage): harden cleanup config handling

Use typed config value access to avoid treating invalid values as
enabled flags or log paths during storage cleanup.

Also stop exposing raw backend exceptions in the dashboard storage
status API and direct users to server logs for details.

---------

Co-authored-by: RC-CHN <1051989940@qq.com>
2026-03-23 09:33:37 +08:00
RichardLiu
04b7618f08 fix: align mimo tts style payload with official docs (#6814) 2026-03-23 09:05:58 +08:00
LIghtJUNction
c6cd48be4f test(dashboard): add tests for TUI chat routes
Add 14 new tests covering:
- TUI session creation (new_session)
- TUI session listing (get_sessions)
- TUI session retrieval with history (get_session)
- TUI session display name update
- TUI session deletion
- TUI session batch deletion
- TUI session stop
- Error cases for missing/invalid parameters

These tests improve coverage of tui_chat.py from 14% to 37%.
2026-03-23 06:21:49 +08:00
LIghtJUNction
80a0f33538 fix(dashboard): resolve route endpoint conflict and fix failing test
- Generate unique endpoint names in Route.register_routes() to avoid
  conflicts between ChatRoute and TUIChatRoute both exposing /api/tui/chat
- Simplify test_batch_upload_skills_accepts_valid_skill_archive to match
  the pattern used by test_batch_upload_skills_accepts_zip_files,
  mocking install_skill_from_zip instead of trying to patch paths
2026-03-23 06:08:48 +08:00
LIghtJUNction
a05f9eba7d feat: add TUI platform adapter and chat route
- Add TUI platform adapter (tui_adapter, tui_event, tui_queue_mgr)
- Add TUI chat route for dashboard
- Add cmd_run_tui command
- Fix shared_preferences TypeVar syntax
- Various platform adapter and provider updates
2026-03-23 05:57:55 +08:00
LIghtJUNction
c1a0db30ad fix: update tests to reflect new core constraints behavior
- test_pip_*: Update expected values from "shared-lib==2.0" to "shared-lib>=1.0"
  to match the new behavior that preserves original version constraints
- test_skill_manager_sandbox_cache: Fix monkeypatch issues by using
  MockAstrbotPaths instead of non-existent module-level functions
- test_tool_loop_agent_runner: Change tool_schema_mode from "skills_like"
  to "lazy_load" to match actual supported mode
2026-03-23 05:55:59 +08:00
LIghtJUNction
369b862dfa test: add TUI message handler tests
Add comprehensive tests for SSEMessageParser and TUI message processing.
2026-03-23 03:12:38 +08:00
LIghtJUNction
1c7085d650 fix: simplify JSON Schema in SendMessageToUserTool parameters
Simplify the message items schema by using additionalProperties
instead of explicit properties, while preserving type info for LLM docs.

Note: 12 ty diagnostics remain in send_message.py and
astr_main_agent_resources.py due to architectural issue where
FunctionTool.parameters JSON Schema is used by ty for Python
type inference. This requires larger refactoring to fix properly.
2026-03-23 03:11:05 +08:00
LIghtJUNction
47aa6ea2cd docs: add --seed flag to uv venv for portable shebangs
The --seed flag makes uv generate shebangs using #!/usr/bin/env python3
instead of absolute paths, allowing venvs to be moved.
2026-03-23 03:03:55 +08:00
LIghtJUNction
1d2469f0ae fix: use sys.stdin.isatty() for non-interactive detection
Replace redundant ASTRBOT_SYSTEMD environment variable checks with
sys.stdin.isatty() for detecting non-interactive environments.
The DashboardManager.ensure_installed() already handles this internally,
so the outer ASTRBOT_SYSTEMD checks were unnecessary.
2026-03-23 03:00:26 +08:00
LIghtJUNction
d6f74a8493 feat(tui): add support for tool and reasoning message types
- Add additionalProperties to message schema for flexibility
- Add TOOL_MSG and REASONING_MSG color pairs for visual distinction
2026-03-23 02:58:09 +08:00
LIghtJUNction
fcab00332d docs: improve module docstrings
- Add module docstring to tui_async.py describing async TUI implementation
- Add new message_handler.py module with shared SSE message handling
2026-03-23 02:57:29 +08:00
LIghtJUNction
ae4cbcdf21 fix: resolve typos and add type annotations
- Fix typo in tui_app.py: key == key == curses.KEY_DOWN -> key == curses.KEY_DOWN
- Add type annotations in send_message.py for better type checking
2026-03-23 02:57:03 +08:00
LIghtJUNction
b4a32fbda8 fix: resolve documentation formatting issues
- Add 'config' to known zh/en doc structure differences
- Remove trailing whitespace from docs/zh/faq.md
- Remove trailing whitespace from docs/en/dev/plugin-platform-adapter.md
- Ensure all README files end with newline
2026-03-23 02:49:15 +08:00
LIghtJUNction
cfdcd63676 test: add documentation consistency tests
Add pytest test file to verify:
- zh/en doc structure mirror
- Core docs exist (README, AGENTS.md, CLAUDE.md, startup guides)
- No broken internal links
- Markdown formatting standards
- Skill documentation with frontmatter
2026-03-23 02:43:58 +08:00
LIghtJUNction
13262b21e6 docs: remove empty astrbot-sandbox.md placeholder 2026-03-23 02:40:04 +08:00
LIghtJUNction
04e9bf8ca8 refactor: code formatting and type improvements
- Format bwrap.py with ruff, clean up imports
- Remove unused cast import in tool.py
- Add getattr fallbacks in context.py for handler name resolution
- Fix param_type annotation to allow Any in command.py
2026-03-23 02:29:33 +08:00
LIghtJUNction
371ff24de1 docs: add AI developer guide skill to docs/skills
Provides comprehensive guidance for AI assistants working on AstrBot:
- Project overview and architecture
- Development setup and commands
- Code style rules (type hints, paths, formatting)
- Environment variable conventions
- Common development patterns
- Git and PR guidelines
2026-03-23 02:26:41 +08:00
LIghtJUNction
3d7f3fb2f6 docs: add CLAUDE.md for AI coding guidelines
Provide comprehensive guidance for AI assistants working on the codebase:
- Project overview and architecture
- Development setup commands
- Python code style (type hints, path handling, formatting)
- Environment variable conventions
- Testing guidelines
- Git and PR conventions
- Common task patterns
2026-03-23 02:18:03 +08:00
LIghtJUNction
41172c9380 docs: add project startup guide for zh and en
Document AstrBot startup process including:
- Installation methods (uv, dev mode, from source)
- Initialization details and options
- Startup options and parameters
- Environment variables
- Directory structure
- Troubleshooting guide
2026-03-23 02:07:10 +08:00
LIghtJUNction
75fa652ccb Add performance benchmark tests with scoring
- Comprehensive performance benchmarks for CommandFilter operations
- Memory usage benchmarks with tracemalloc tracking
- High-throughput benchmarks with ops/sec metrics
- Scoring system (0-100) for performance tracking
- Overall performance score summary

Benchmarks include:
- CommandFilter.get_complete_command_names
- Boolean and integer parameter validation
- Memory footprint of filter creation
- High-throughput validation throughput
2026-03-23 02:04:06 +08:00
LIghtJUNction
7fe58cfdbc docs: restore sponsors section to all README files 2026-03-23 02:02:32 +08:00
LIghtJUNction
05053c221d Revert SDK integration, fix test paths, restore original code
- Delete astrbot-sdk package entirely
- Remove SDK dependencies from pyproject.toml
- Restore core modules to pre-sdk versions
- Fix test monkeypatch paths to use correct module paths
- Fix bool type checking bug in command filter
- Fix tools=None preservation in subagent orchestrator
2026-03-23 01:56:39 +08:00
LIghtJUNction
4db5063b77 docs: remove internal refactor planning document 2026-03-23 01:55:37 +08:00
LIghtJUNction
095ac35221 docs: remove SDK integration plan document
The SDK integration was reverted, remove the now-stale planning document.
2026-03-23 01:51:48 +08:00
LIghtJUNction
6a4177cae4 Revert "feat: SDK integration and various improvements" 2026-03-23 01:18:03 +08:00
LIghtJUNction
2e3a20fcdf fix: improve bool param validation and preserve None tools
- Fix bool type checking in CommandFilter.validate_and_convert_params
  (was using isinstance(bool_instance, bool) instead of 'bool is bool')
- Preserve tools=None when persona explicitly has no tools
- Add missing provider_wake_prefix in test setup
2026-03-23 01:07:21 +08:00
LIghtJUNction
03c0b4c73e fix: skip interactive dashboard prompt in systemd mode
When running under systemd (ASTRBOT_SYSTEMD=1), the click.confirm()
prompt would raise Abort on user input, crashing the service.
Skip the interactive confirmation and silently return instead.
2026-03-23 00:55:56 +08:00
LIghtJUNction
2c830039bb Merge branch 'dev' of https://github.com/AstrBotDevs/AstrBot into dev 2026-03-22 23:38:46 +08:00
LIghtJUNction
a3fbfd3540 feat: SDK integration and various improvements
- Refactor core modules for better SDK integration
- Improve skill manager with better caching and loading
- Update dashboard routes for plugin and tools management
- Fix and enhance computer skill synchronization
- Various bug fixes and test improvements
2026-03-22 23:38:27 +08:00
LIghtJUNction
b62c92bdb3 dev : Implement bubblewrap sandbox backend with availability detection and tests (#6709)
* New sandbox backend: bubblewrap.
 - Based on Linux Namespace for resource isolation
 - Runs on local computer, with no privilege required
 - Only supports Linux as namespace & bubblewrap are not present on other platforms.

TODO:
 - Fix dashboard presentation. Why change on src does not affect what is really displayed?
 - Strenghthen backend availability detection. One known issue is, on some platforms like Ubuntu 24.04, bubblewrap is banned by system guards, even when it's shipped by package manager. A complete detector may contain :
   1. run the command with cmdline used by the booter. Return True if succsed.
   2. If false, do bottom-up reason detection. Namespace not compiled to kernel? Specific kernel parameters not set? Banned by safety guard? The availability detector should give the user a clear information on why this sandbox backend fails.

These work may require helps from frontend developers. It is tested to be usable on my computer, with non-persistent environment(forget on every command) and persistent file storage.

* Add RO bind entry for bubblewrap backend.

TODO add:
 - add plugin utility to change ro and rw bind in cmdline
 - make bind dirs dict instead of list to manually map mount point

* Fix: add boot time test for bwrap booter.
 in older commits, ro_bind = ['/'] makes skill sync crash. This commit fixes it and adds detection.

* Add availability of bwrap check during booting

* unit tests of bwrap

* i18n of bwrap config by Gemini 3.1 pro

* Update astrbot/core/computer/booters/bwrap.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: YI Zeping <yizeyi18@mail.nankai.edu.cn>
Co-authored-by: YI Zeping <18586016708@163.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-22 23:15:16 +08:00
LIghtJUNction
95430ee6f8 Feat/sdk integration (#6807)
* Add legacy session waiter compatibility

* Expand legacy astrbot package compatibility

* Tighten external legacy plugin compatibility smoke tests

* Consolidate controlled legacy facade compatibility

* docs: clarify compat package boundaries

* test: align runtime fixtures with maintained samples

* fix: preserve unicode sample fixtures in runtime tests

* Implement legacy hook and tool compat runtime

* Refactor legacy runtime execution boundary

* 增强旧版兼容性,添加多个旧路径入口和相关功能

* 增强旧版兼容性,添加适配器边界的启动和关闭钩子支持

* Refactor legacy API and LLM compatibility logic

- Moved legacy LLM and tool compatibility logic from `_legacy_api.py` to a new module `_legacy_llm.py` for better organization and separation of concerns.
- Updated `_legacy_api.py` to import necessary components from `_legacy_llm.py`, removing redundant code.
- Enhanced database client functionality by adding support for batch read/write operations and change event subscriptions.
- Improved documentation in the database client and capability router to reflect new features.
- Refined environment management process in the loader to better handle plugin grouping and virtual environment management.

* 补充插件分组环境测试覆盖

* feat: Enhance CLI and testing capabilities

- Added a new script entry point `astrbot-sdk` in `pyproject.toml`.
- Introduced `has_waiter` method in `SessionWaiterManager` to check for existing waiters.
- Updated `cli.py` to improve error handling and added context to error messages.
- Implemented local development support in `cli.py` with a new `dev` command for running plugins against a mock core.
- Created a new testing module `astrbot_sdk.testing` with utilities for local development and plugin testing.
- Added comprehensive tests for the new testing module and CLI commands.
- Improved compatibility and error messaging for plugin loading failures.

* feat: 添加插件初始化、验证和构建命令,增强 CLI 功能

* feat: add platform client documentation and examples

- Introduced platform client documentation in `docs/v4/clients/platform.md` detailing methods for sending messages, images, and managing group members.
- Added example plugins for LLM chat and database functionalities in `docs/v4/examples/README.md`, `docs/v4/examples/llm-chat/README.md`, and `docs/v4/examples/database/README.md`.
- Enhanced quickstart guide with links to new documentation and example plugins.
- Implemented runtime contract tests to ensure compatibility of public capabilities and hooks.

* Refactor legacy runtime handling and improve plugin loading

- Updated `handler_dispatcher.py` to streamline legacy runtime preparation and dispatching results.
- Enhanced `loader.py` to simplify legacy plugin detection and manifest building.
- Added tests for new HTTPClient and MetadataClient functionalities.
- Introduced tests for legacy context metadata methods and legacy loader helpers.
- Improved legacy runtime tests to cover new functionality and edge cases.

* refactor: 更新兼容层和导入路径,优化文档描述

* Support grouped plugin workers in shared environments

- add group metadata driven worker startup for shared env plans
- track per-plugin handler and capability ownership inside grouped workers
- update runtime and smoke tests for grouped worker session behavior

* Add v4 compat layer and legacy shims

- Introduce private v4 compatibility surface using
  _legacy_api.py, _legacy_runtime.py, _legacy_loader.py plus new
  _legacy_context.py and _legacy_star.py to centralize legacy adapters
  while keeping public APIs thin.
- Extend InitializeOutput to carry protocol_version for negotiated
  protocol, enabling runtime to adapt to the chosen v4 version.
- Add lightweight legacy support for Star/Context via new LegacyStar and
  LegacyContext shims and expose legacy API through the aggregate
  _legacy_api entry point.
- Ensure legacy loader preserves class declaration order by iterating
  module.__dict__ instead of relying on alphabetical sorting.
- Add tests: protocol_version handling in InitializeOutput, legacy
  main component order preservation, and embedded-newline framing in
  transport tests.

* Add architecture doc and refine API compat

- Add PROJECT_ARCHITECTURE.md documenting architecture, compat surface,
  and testing notes.
- Update astrbot_sdk.api.__init__ to clarify it is a compatibility
  implementation layer, not a simple facade, and list migration targets.
- Normalize platform in AstrMessageEvent.to_payload to emit a string id
  by using get_platform_id().

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* delete old sdk

* delete old sdk (#7)

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>

* feat(cli): normalize plugin init skeletons

Add interactive plugin init prompts and normalize generated plugin names to the astrbot_plugin_ convention.
Update CLI tests for the new skeleton layout and ignore generated plugin directories in git and coverage tooling.
Also include related runtime logging adjustments from the current worktree.

* Create lint.yml

* Update lint.yml

* clean it

* feat: Enhance handler and capability dispatchers with improved error handling

- Updated HandlerDispatcher to raise TypeError for uninjectable required parameters, logging errors appropriately.
- Refactored CapabilityDispatcher to raise TypeError for missing required parameters during capability execution.
- Renamed _load_plugin_config to load_plugin_config for clarity and consistency.
- Introduced _sync_plugin_registry method in SupervisorRuntime to manage plugin capabilities more effectively.
- Enhanced capability registration logic to handle naming conflicts with better logging and automatic renaming.
- Added tests for handler and capability dispatchers to ensure proper error handling and functionality.
- Implemented new HTTP and metadata capabilities with corresponding tests for registration and retrieval.
- Improved MemoryClient methods with additional tests for save_with_ttl, get_many, delete_many, and stats.
- Added tests for the testing module to ensure proper import and functionality of PluginHarness.

* feat: 更新 SDK 描述,重构插件调用上下文,移除插件 ID 传递,增强能力路由和 HTTP 客户端的插件身份管理

* refactor: 更新文档和代码注释,优化兼容性描述,增强可读性

* feat: 添加插件热重载功能,支持文件变更时自动重新加载插件

* feat: 增强错误处理,添加上下文信息,优化插件组件加载和参数注入校验

* feat: 添加 hello_plugin 示例,包含插件结构、命令处理和测试用例

* refactor: 删除过时的架构文档、变更日志和兼容矩阵文件

* refactor: 更新兼容层弃用通知,优化文档结构和可读性

* refactor: 更新项目架构文档,增强能力客户端和执行边界的描述,移除兼容层设计章节

* feat(errors): Enhance AstrBotError with detailed documentation and examples

feat(events): Expand MessageEvent with reply capabilities and detailed docstrings

fix(loader): Ensure plugin path is correctly managed in sys.path

feat(star): Improve Star class documentation and lifecycle method descriptions

feat(testing): Add plugin metadata handling in MockContext and enhance PluginHarness

feat(hello): Refactor HelloPlugin to utilize new reply methods and structured capabilities

test(decorators): Add tests for input/output model support in provide_capability

test(events): Implement tests for reply_image and reply_chain methods in MessageEvent

test(http): Validate API registration with capability handler references and error handling

test(tests): Enhance tests for plugin harness and directory handling in dev commands

* feat(runtime): add configurable msgpack wire codec support

* fix(runtime): align msgpack framing with transport defaults

* fix(runtime): preserve json transport compatibility

* fix(cli): scope worker wire codec option

* feat: 添加 AGENTS.md 文档,描述 v4 架构约束和开发命令
refactor: 更新 HandlerDispatcher 和 WorkerSession,增强参数处理和结果汇总逻辑

* fix(test): 更新 init_plugin 测试以匹配新的目录命名规范

CLI 的 _normalize_init_plugin_name 函数现在自动添加 astrbot_plugin_ 前缀,
测试期望的目录名从 demo_plugin 更新为 astrbot_plugin_demo_plugin。

* Refactor worker initialization and remove unused codec parameters; add schedule and session waiter modules

- Simplified `GroupWorkerRuntime` and `PluginWorkerRuntime` constructors by removing the codec parameter and related logic.
- Introduced `schedule.py` to define `ScheduleContext` for managing scheduled tasks with a clear structure and payload handling.
- Added `session_waiter.py` for session-based conversational flow management, including `SessionController` and `SessionWaiterManager` for handling multi-turn dialogues.
- Enhanced testing utilities in `testing.py` by removing unused classes and streamlining the structure.
- Created `types.py` to introduce `GreedyStr` for improved command parameter parsing.

* feat: 添加 LLM 工具管理和会话级别状态管理能力

- 新增 llm/ 模块,包含 LLMToolSpec、ProviderRequest、AgentSpec 等实体
- 新增 LLMToolManager 用于管理 LLM 工具注册和激活状态
- 新增 SessionPluginManager 用于会话级别的插件启用状态管理
- 新增 SessionServiceManager 用于会话级别的 LLM/TTS 服务状态管理
- 新增 RegistryClient 用于查询 handler 元数据和设置白名单
- 扩展 CapabilityRouter 内置能力,支持 session.* 和 registry.* 命名空间
- 增强描述符和装饰器以支持新的 trigger 类型

* feat: 大幅增强 SDK 核心功能和文档

新增模块:
- clients/files.py: 文件上传/下载客户端
- clients/managers.py: 会话/LLM/Provider 管理器
- clients/provider.py: LLM Provider 客户端
- conversation.py: 对话上下文管理
- plugin_kv.py: 插件 KV 存储辅助
- runtime/limiter.py: 限流器
- star_tools.py: Star 工具函数
- docs/: 完整的 SDK 使用文档 (01-05)

功能增强:
- Context 大幅扩展,增加 reply/send_image/typing 等便捷方法
- 装饰器增强,支持 on_llm_request/on_provider_request 等
- 内置 schemas 扩展,覆盖更多 capability 定义
- capability_router_builtins 大幅扩展内置能力实现
- handler_dispatcher 增强参数注入和错误处理
- Star 基类增加生命周期钩子和工具方法

* Add comprehensive API documentation for types and utilities in AstrBot SDK

- Introduced `types.md` detailing type aliases, generics, and Pydantic models used in the SDK.
- Added `utils.md` covering utility classes and functions including CancelToken, MessageSession, command groups, and session management.
- Included usage examples and detailed descriptions for each component to enhance developer understanding and ease of use.

* feat: 添加高级方法和辅助函数文档,增强消息组件和事件处理功能

* feat: 增强过滤器类型和能力路由文档,添加 Provider 和会话管理功能

* change location

* delete no need thing

* delete again

* feat: add Star plugin base class and StarTools utility class

- Introduced `Star` class as a base for v4 native plugins, providing lifecycle methods and context management.
- Added `StarTools` class for accessing runtime context and managing LLM tools.
- Implemented `PluginHarness` for local development and testing of plugins, allowing for message dispatching and lifecycle management.
- Created `GreedyStr` type for enhanced command parameter parsing, enabling the capture of remaining command text as a single argument.
- Added testing utilities and mock capabilities for plugin development.

* delete: remove hello_plugin example and its related files

* Remove obsolete test files for testing module, top-level modules, transport, and wire codecs

- Deleted `test_testing_module.py` as it is no longer needed.
- Removed `test_top_level_modules.py` which had no content.
- Eliminated `test_transport.py` due to redundancy.
- Cleared out `test_wire_codecs.py` as part of the cleanup.

* fix(runtime): avoid creating Star instance in on_error fallback

* fix(runtime): avoid virtual dispatch in Star.on_error fallback

* refactor(runtime): unify command matching logic (#25)

* refactor(testing): share command matching with handler dispatcher

* fix:添加公共函数文件

* fix: simplify register_task completion handling (#27)

* fix: simplify register_task completion handling

Remove duplicated cancellation logging in Context.register_task while keeping Future inputs compatible with asyncio.create_task semantics. Add regression coverage for coroutine, Future, cancellation, and failure paths.

* fix: prioritize local src in tests_v4

Ensure tests_v4 always imports the working tree package by moving src to sys.path[0] even when another checkout or installed copy is already present.

* chore: sync subtree from AstrBot

* feat: replay non-sdk changes on clean sdk subtree baseline

* feat(sdk): add merged provider config capability support

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(sdk): add merged provider config bridge and client

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(sdk): add merged provider config capability support

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(sdk): tighten bridge cast typing

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(sdk): add merged provider config bridge and client

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(sdk): cover merged provider config parity

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat: 完善 memory 向量检索与索引统计 (#28)

Co-authored-by: united_pooh <united_pooh@outlook.com>

* feat(tests): 添加测试用例以验证 register_task 的行为并更新测试运行说明

* Merge commit 'e45bade147ff44b43860ecff12067309e59c151a' into feat/sdk-integration

* Squashed 'astrbot-sdk/' changes from 7dda6077..85342f14

85342f14 feat(tests): 添加测试用例以验证 register_task 的行为并更新测试运行说明
fdffc09b Merge pull request #26 from united-pooh/fix/fix-star-on-error-fallback
3b09747c feat: 完善 memory 向量检索与索引统计 (#28)
665c9c69 fix(runtime): avoid virtual dispatch in Star.on_error fallback
200559a5 fix(runtime): avoid creating Star instance in on_error fallback

git-subtree-dir: astrbot-sdk
git-subtree-split: 85342f149b

* feat(tests): 添加测试用例以验证平台和消息类型过滤器的冲突处理

* docs: remove redundant testing instructions from AGENTS.md

* docs: remove redundant testing instructions from AGENTS.md

* docs: remove redundant testing instructions from AGENTS.md

* Merge commit '5ac9401852ddb46f337da6bcc0f9b66eed265da9' into feat/sdk-integration

* Squashed 'astrbot-sdk/' changes from 85342f14..09beabeb

09beabeb feat(tests): 添加测试用例以验证平台和消息类型过滤器的冲突处理

git-subtree-dir: astrbot-sdk
git-subtree-split: 09beabeb62

* feat: enhance SDK plugin configuration handling and logging

* feat: enhance SDK plugin configuration handling and logging

* feat: enhance SDK plugin configuration handling and logging

* feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器

* feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器

* feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器

* feat: 更新文档以反映SDK负载的JSON可序列化要求和延迟导入设计约束

* feat: add conversation.get_current capability and related schemas

- Introduced CONVERSATION_GET_CURRENT_INPUT_SCHEMA and CONVERSATION_GET_CURRENT_OUTPUT_SCHEMA for handling current conversation requests.
- Implemented _conversation_get_current method in BuiltinCapabilityRouterMixin to manage current conversation retrieval and creation.
- Registered the new capability in CoreCapabilityBridge.
- Enhanced HandlerDispatcher to inject provider request, LLM response, and event result payloads into the event handling process.
- Updated tests to validate the new functionality and ensure proper payload handling.

* feat: add conversation.get_current capability and related schemas

- Introduced CONVERSATION_GET_CURRENT_INPUT_SCHEMA and CONVERSATION_GET_CURRENT_OUTPUT_SCHEMA for handling current conversation requests.
- Implemented _conversation_get_current method in BuiltinCapabilityRouterMixin to manage current conversation retrieval and creation.
- Registered the new capability in CoreCapabilityBridge.
- Enhanced HandlerDispatcher to inject provider request, LLM response, and event result payloads into the event handling process.
- Updated tests to validate the new functionality and ensure proper payload handling.

* feat: add conversation.get_current capability and related schemas

- Introduced CONVERSATION_GET_CURRENT_INPUT_SCHEMA and CONVERSATION_GET_CURRENT_OUTPUT_SCHEMA for handling current conversation requests.
- Implemented _conversation_get_current method in BuiltinCapabilityRouterMixin to manage current conversation retrieval and creation.
- Registered the new capability in CoreCapabilityBridge.
- Enhanced HandlerDispatcher to inject provider request, LLM response, and event result payloads into the event handling process.
- Updated tests to validate the new functionality and ensure proper payload handling.

* Refactor tool call handling in SdkPluginBridge

- Introduced a dictionary to map tool call IDs to tool names for better clarity and efficiency.
- Enhanced the extraction of tool call information from raw results, ensuring compatibility with both dictionary and object formats.
- Updated the logic to retrieve tool names based on tool call IDs, improving the robustness of the tool calls result processing.

* Refactor tool call handling in SdkPluginBridge

- Introduced a dictionary to map tool call IDs to tool names for better clarity and efficiency.
- Enhanced the extraction of tool call information from raw results, ensuring compatibility with both dictionary and object formats.
- Updated the logic to retrieve tool names based on tool call IDs, improving the robustness of the tool calls result processing.

* Refactor tool call handling in SdkPluginBridge

- Introduced a dictionary to map tool call IDs to tool names for better clarity and efficiency.
- Enhanced the extraction of tool call information from raw results, ensuring compatibility with both dictionary and object formats.
- Updated the logic to retrieve tool names based on tool call IDs, improving the robustness of the tool calls result processing.

* feat: add session and system capabilities for plugin management and event handling

- Implemented SessionCapabilityMixin with methods to manage session-level plugin states and handlers.
- Added SystemCapabilityMixin to handle system-level functionalities including file management, event handling, and dynamic command registration.
- Introduced methods for enabling/disabling plugins, filtering handlers, and managing LLM and TTS service states.
- Registered various system capabilities for data directory access, HTML rendering, and event streaming.

* feat: add session and system capabilities for plugin management and event handling

- Implemented SessionCapabilityMixin with methods to manage session-level plugin states and handlers.
- Added SystemCapabilityMixin to handle system-level functionalities including file management, event handling, and dynamic command registration.
- Introduced methods for enabling/disabling plugins, filtering handlers, and managing LLM and TTS service states.
- Registered various system capabilities for data directory access, HTML rendering, and event streaming.

* Squashed 'astrbot-sdk/' changes from 09beabeb..3204c9db

3204c9db Merge sdk-remote dev into feat/sdk-integration
3a2d715e Refactor tool call handling in SdkPluginBridge
ed1b9665 feat: add conversation.get_current capability and related schemas
e74123bb feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器
bb361cf9 feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器
c6237f52 Merge sdk-remote/dev into astrbot-sdk subtree
e12029ff feat: enhance SDK plugin configuration handling and logging
5e54bbb3 feat: enhance SDK plugin configuration handling and logging
f48e2041 Merge commit '5ac9401852ddb46f337da6bcc0f9b66eed265da9' into feat/sdk-integration
619672e6 Merge commit '5ac9401852ddb46f337da6bcc0f9b66eed265da9' into feat/sdk-integration
d5a3796d docs: remove redundant testing instructions from AGENTS.md
323e3f4d docs: remove redundant testing instructions from AGENTS.md
f8438a7b Merge commit 'e45bade147ff44b43860ecff12067309e59c151a' into feat/sdk-integration
96d1df85 Merge commit 'e45bade147ff44b43860ecff12067309e59c151a' into feat/sdk-integration
f8a7e253 feat(sdk): add merged provider config bridge and client
752dc6cf feat(sdk): add merged provider config capability support

git-subtree-dir: astrbot-sdk
git-subtree-split: 3204c9db9f

* Implement feature X to enhance user experience and optimize performance

* Implement feature X to enhance user experience and optimize performance

* chore(sdk): stop tracking uv.lock

* feat(sdk): add merged provider config capability support

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(sdk): add merged provider config bridge and client

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* feat(tests): 添加测试用例以验证 register_task 的行为并更新测试运行说明

* feat(tests): 添加测试用例以验证平台和消息类型过滤器的冲突处理

* docs: remove redundant testing instructions from AGENTS.md

* feat: enhance SDK plugin configuration handling and logging

* feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器

* feat: add conversation.get_current capability and related schemas

- Introduced CONVERSATION_GET_CURRENT_INPUT_SCHEMA and CONVERSATION_GET_CURRENT_OUTPUT_SCHEMA for handling current conversation requests.
- Implemented _conversation_get_current method in BuiltinCapabilityRouterMixin to manage current conversation retrieval and creation.
- Registered the new capability in CoreCapabilityBridge.
- Enhanced HandlerDispatcher to inject provider request, LLM response, and event result payloads into the event handling process.
- Updated tests to validate the new functionality and ensure proper payload handling.

* Refactor tool call handling in SdkPluginBridge

- Introduced a dictionary to map tool call IDs to tool names for better clarity and efficiency.
- Enhanced the extraction of tool call information from raw results, ensuring compatibility with both dictionary and object formats.
- Updated the logic to retrieve tool names based on tool call IDs, improving the robustness of the tool calls result processing.

* feat: add session and system capabilities for plugin management and event handling

- Implemented SessionCapabilityMixin with methods to manage session-level plugin states and handlers.
- Added SystemCapabilityMixin to handle system-level functionalities including file management, event handling, and dynamic command registration.
- Introduced methods for enabling/disabling plugins, filtering handlers, and managing LLM and TTS service states.
- Registered various system capabilities for data directory access, HTML rendering, and event streaming.

* fix(runtime): avoid creating Star instance in on_error fallback

* fix(runtime): avoid virtual dispatch in Star.on_error fallback

* feat: refactor injected parameter handling and introduce is_framework_injected_parameter utility

* Squashed 'astrbot-sdk/' changes from 027c15b4..d078e510

d078e510 feat: refactor injected parameter handling and introduce is_framework_injected_parameter utility
461f7276 Merge branch 'dev' of https://github.com/united-pooh/astrbot-sdk into dev
5ead59c4 fix(runtime): avoid virtual dispatch in Star.on_error fallback
d2382858 fix(runtime): avoid creating Star instance in on_error fallback
e961e361 feat: add session and system capabilities for plugin management and event handling
5a46321a Refactor tool call handling in SdkPluginBridge
47698448 feat: add conversation.get_current capability and related schemas
9b35bec8 feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器
48a20240 feat: enhance SDK plugin configuration handling and logging
cb593a53 docs: remove redundant testing instructions from AGENTS.md
f4942076 feat(tests): 添加测试用例以验证平台和消息类型过滤器的冲突处理
b0f8b2d6 feat(tests): 添加测试用例以验证 register_task 的行为并更新测试运行说明
6e417c6d feat(sdk): add merged provider config bridge and client
659eabce feat(sdk): add merged provider config capability support
REVERT: 027c15b4 Implement feature X to enhance user experience and optimize performance
REVERT: c272661f chore: pull sdk subtree from dev (resolve delete/modify conflict)
REVERT: 0a2a3592 feat: add session and system capabilities for plugin management and event handling
REVERT: 3204c9db Merge sdk-remote dev into feat/sdk-integration
REVERT: 36443f1d Refactor tool call handling in SdkPluginBridge
REVERT: 3a2d715e Refactor tool call handling in SdkPluginBridge
REVERT: b93c2c2b feat: add conversation.get_current capability and related schemas
REVERT: ed1b9665 feat: add conversation.get_current capability and related schemas
REVERT: e74123bb feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器
REVERT: bb361cf9 feat: 增强装饰器功能,添加会话命令支持及相关权限和限流装饰器
REVERT: c6237f52 Merge sdk-remote/dev into astrbot-sdk subtree
REVERT: e12029ff feat: enhance SDK plugin configuration handling and logging
REVERT: 5e54bbb3 feat: enhance SDK plugin configuration handling and logging
REVERT: f48e2041 Merge commit '5ac9401852ddb46f337da6bcc0f9b66eed265da9' into feat/sdk-integration
REVERT: 619672e6 Merge commit '5ac9401852ddb46f337da6bcc0f9b66eed265da9' into feat/sdk-integration
REVERT: d5a3796d docs: remove redundant testing instructions from AGENTS.md
REVERT: 323e3f4d docs: remove redundant testing instructions from AGENTS.md
REVERT: f8438a7b Merge commit 'e45bade147ff44b43860ecff12067309e59c151a' into feat/sdk-integration
REVERT: 96d1df85 Merge commit 'e45bade147ff44b43860ecff12067309e59c151a' into feat/sdk-integration
REVERT: f8a7e253 feat(sdk): add merged provider config bridge and client
REVERT: 752dc6cf feat(sdk): add merged provider config capability support

git-subtree-dir: astrbot-sdk
git-subtree-split: d078e51051

* refactor: reorganize imports and enhance type hints in sdk_bridge modules

* refactor: update import paths to use Path for better compatibility

* refactor(injection): centralize legacy injected parameter filtering

* fix(testing): use public session waiter probe in PluginHarness

* docs: add TODO for documentation content in _command_model.py

* feat: add memory management capabilities to CoreCapabilityBridge and implement unit tests

* feat: enhance memory search functionality and improve metadata retrieval in SDK

* feat: add memory management attributes and typed provider method to CapabilityMixinHost

* Implement feature X to enhance user experience and optimize performance

* Refactor memory utility functions and enhance memory capability mixin

- Added new utility functions for memory management in _memory_utils.py.
- Refactored memory capability mixin methods to utilize the new utility functions for better readability and maintainability.
- Updated PROJECT_ARCHITECTURE.md to reflect changes in documentation and structure.

* Squashed 'astrbot-sdk/' changes from d078e510..208bc591

208bc591 Merge pull request #30 from united-pooh/refactor/unify-legacy-injected-params
d86534a2 docs: add TODO for documentation content in _command_model.py
090724a7 refactor(injection): centralize legacy injected parameter filtering

git-subtree-dir: astrbot-sdk
git-subtree-split: 208bc591dd

* Initial plan

* docs: fix path, Python version, and client API table in PROJECT_ARCHITECTURE.md

Co-authored-by: whatevertogo <149563971+whatevertogo@users.noreply.github.com>

* Squashed 'astrbot-sdk/' changes from 208bc591..ad5e8d13

ad5e8d13 Merge pull request #37 from united-pooh/sdk/whatevertogo
5751701f Merge pull request #38 from united-pooh/copilot/sub-pr-37
e21acba5 docs: fix path, Python version, and client API table in PROJECT_ARCHITECTURE.md
ee67cab4 Initial plan
7d921570 Refactor memory utility functions and enhance memory capability mixin

git-subtree-dir: astrbot-sdk
git-subtree-split: ad5e8d1397

* docs: fix TODO comment formatting in _command_model.py

* 集成SDK命令候选项,优化Telegram和Discord平台适配器的命令收集逻辑

* 删除AI女友插件的单元测试文件

* 更新文档,添加Telegram和Discord原生命令菜单的注册说明

* Squashed 'astrbot-sdk/' changes from ad5e8d13..5003da58

5003da58 Merge pull request #40 from united-pooh/sdk/whatevertogo
b5084c44 Merge branch 'sdk/whatevertogo' of https://github.com/united-pooh/astrbot-sdk into sdk/whatevertogo
7559edf7 docs: fix TODO comment formatting in _command_model.py

git-subtree-dir: astrbot-sdk
git-subtree-split: 5003da58f5

* fix(testing): route session waiter followups through dispatcher (#33)

* fix(testing): route session waiter followups through dispatcher

* fix(testing): preserve waiter context and completion state

* fix(runtime): preserve session waiter plugin identity

* fix(runtime): scope session waiters by plugin

* fix(testing): isolate waiter replacement and followup drains

* fix(runtime): normalize waiter routing inputs

* fix(cli): route protocol stdout at command entry (#41)

* 添加内存后端支持,优化插件内存管理逻辑

* feat(memory): enhance memory schemas and add namespace support

- Updated MEMORY_SEARCH_INPUT_SCHEMA to include `namespace` and `include_descendants`.
- Modified MEMORY_SEARCH_OUTPUT_SCHEMA to allow nullable `namespace`.
- Added `namespace` to MEMORY_GET_INPUT_SCHEMA, MEMORY_DELETE_INPUT_SCHEMA, MEMORY_SAVE_WITH_TTL_INPUT_SCHEMA, MEMORY_GET_MANY_INPUT_SCHEMA, and MEMORY_DELETE_MANY_INPUT_SCHEMA.
- Enhanced MEMORY_STATS_INPUT_SCHEMA to support `namespace` and `include_descendants`.
- Updated MEMORY_GET_OUTPUT_SCHEMA and MEMORY_STATS_OUTPUT_SCHEMA to include `namespace` and `namespace_count`.
- Introduced `_memory_backends` in CapabilityRouterHost and CapabilityRouterBridgeBase for better memory management.
- Refactored MemoryCapabilityMixin to utilize memory backends for plugin-specific memory operations.
- Improved memory search functionality to respect namespaces and include descendants based on input parameters.
- Added tests to validate memory operations across different namespaces and ensure persistence across restarts.
- Implemented error handling in the handler dispatcher to manage exceptions gracefully.

* fix: guard session_waiter blocking usage

* fix(runtime): preserve request-scoped system event overlays

* test(runtime): lock peer initialization and transport failure semantics

* test(loader): cover plugin reload and import isolation regressions

* refactor(supervisor): clarify plugin registry sync phases

* test(clients): cover provider lifecycle regressions

* feat(cli): improve astr init defaults

* feat(plugin): add plugin ID validation and data directory resolution

- Implemented `validate_plugin_id` to ensure safe plugin identifiers.
- Added `resolve_plugin_data_dir` to resolve plugin data directories securely.
- Updated memory and system capabilities to utilize new plugin ID validation.
- Refactored session waiter management to simplify plugin ID handling.
- Enhanced tests for plugin ID validation and data directory resolution.

* fix(cli): exit cleanly on init abort

* feat(memory): enhance namespace handling and add tests for memory client

* feat(agent): add tool status message handling and improve SDK command integration

* Refactor SDK structure for backward compatibility

- Moved message result and session classes to internal modules while preserving legacy import paths for compatibility.
- Updated imports across the SDK to reflect the new internal structure.
- Enhanced session waiter management to support multiple plugins and improve error handling.
- Added tests to ensure LLM tool registration and session waiter functionality align with dispatcher expectations.
- Cleaned up code and improved documentation for clarity and maintainability.

* 增强异步下载功能,更新组件导入方式,并添加相关测试用例

* 添加任务重入锁以支持会话等待器的嵌套清理,并更新相关测试用例以验证后续消息的序列化处理

* 添加 .astrbot_sdk_testing 到 .gitignore 文件

* Add unit tests for provider management and tool capabilities

- Introduced new test suite for provider platform management in `test_sdk_provider_platform_management.py`, covering scenarios for merged provider configurations, reserved plugin checks, and provider management functionalities.
- Added tests for tool capabilities and provider queries in `test_sdk_provider_tool_platform_capabilities.py`, validating interactions with LLM tools and specialized proxies.
- Removed obsolete `test_sdk_transport.py` as it contained outdated tests for transport layer functionality.

* 添加多个模块和测试用例,增强SDK功能并支持单元测试

* fix(bridge): add missing capability registrations for db/memory/http/metadata

Register methods for db, memory, http, and metadata capabilities exist in
BasicCapabilityMixin but were never called in CoreCapabilityBridge.__init__.
This caused SDK plugins using ctx.memory, ctx.db, ctx.http to fail with
"LookupError: capability not found".

* feat(kb): enhance knowledge base capabilities with document management and serialization

* 添加知识库文档管理功能,包括文档上传、列表、获取、删除和刷新能力,更新相关的能力路由和协议模式

* feat(conversation): add ability to unset conversation persona and update related methods

* 添加对话管理和元数据管理功能,包括清空对话人格和保存插件配置的能力

* feat(conversation): add test for unsetting conversation persona and verify state

* feat(plugin): add save_plugin_config method and related tests for plugin configuration persistence

* 优化插件配置保存方法的代码格式

* feat(sdk): enhance handler metadata with descriptions, priority, kind, and admin requirements

* 添加描述、优先级和其他元数据到处理程序元数据和描述符中,优化相关功能

* feat(sdk): enhance SDK integration with local extras handling and message payloads

* 添加对 MessageEvent 的额外字段支持,优化事件处理器的参数注入,增强 SDK 本地临时数据的管理能力

* 增强插件日志记录功能,添加控制台输出格式化和路径标签支持,新增单元测试以验证日志格式

* feat: Enhance command and tool management in dashboard

- Refactor CommandRoute to utilize AstrBotCoreLifecycle for improved command handling.
- Introduce command_key for commands to streamline toggling, renaming, and permission updates.
- Implement support for SDK commands in the dashboard, marking them as read-only.
- Update ToolTable and CommandTable components to use new command_key and tool_key properties.
- Add runtime_kind and plugin_id to tools for better management.
- Enhance API tests to cover SDK commands and tools, ensuring proper functionality and error handling.
- Update localization files to include new messages related to SDK commands.

* 优化插件日志记录和能力代理模块,增强异常处理,确保优先级参数为整数

* feat: 增强LLM能力,添加聊天提供者协议和异常处理,更新单元测试以验证提供者有效性

* feat: Implement SDK skill management capabilities

- Added SkillCapabilityMixin to handle skill registration, unregistration, and listing.
- Integrated skill management into the CoreCapabilityBridge.
- Enhanced SkillManager to support SDK-registered skills, including loading, saving, and syncing skills.
- Updated computer_client to utilize SkillManager for skill synchronization with sandboxes.
- Refactored skill export functionality in SkillsRoute to accommodate new skill management structure.
- Introduced tests for SDK skill registration, unregistration, and syncing to ensure functionality.
- Improved skill handling in the dashboard and test suite to reflect changes in skill management.

* 添加技能注册功能,包含技能注册、注销和列出能力的实现,增强插件能力管理

* 删除CLAUDE.md文档,移除过时的已知问题描述

* 删除 AGENTS.md 文档,移除过时的架构约束和开发命令说明

* 更新测试用例,修复插件发现失败时的错误信息,确保使用正确的运行时字段

* 修复错误处理和权限检查,新增单元测试以验证功能

* format

* 增强命名空间管理,优化数据库操作,添加 HTTP 路由验证,新增并发隔离测试,完善命令模型解析单元测试

* 增强 HTTP 路由功能,添加 HTTP 方法注销逻辑的单元测试

* 格式化日志输出,优化批量插入时无内容提供的调试信息

* fix: add uv dependency for plugin environment groups

* 删除代码审查文档 CODE_REVIEW_ISSUES.md

* 添加消息历史管理功能,包括消息记录的增删查改,完善相关能力混合类和测试用例

* 实现 SDK 消息历史管理功能,包括记录的增删查改操作

* Add unit tests for MCP contract and capabilities in SDK

- Implemented `_mcp_contract.py` to test local MCP server functionalities including listing, enabling, and disabling servers.
- Created `test_sdk_mcp_capabilities.py` to cover various aspects of the CoreCapabilityBridge and SdkPluginBridge, including session management and global MCP server operations.
- Introduced fake classes to simulate MCP server behavior and manage tool configurations for testing.
- Ensured comprehensive coverage of MCP session lifecycle, including opening, listing tools, calling tools, and closing sessions.

* feat(mcp): Implement local and global MCP server management capabilities

- Added MCP management client to the context for local/global MCP service management.
- Introduced decorators to acknowledge global MCP risk for plugins.
- Defined schemas for MCP server operations including get, list, enable, disable, and session management.
- Created MCP capability mixin to handle local and global MCP server operations.
- Enhanced provider capabilities to include active local MCP tool names.
- Updated capability router to support MCP functionalities and maintain session state.
- Added tests for MCP functionalities, ensuring proper behavior and risk acknowledgment.

---------

Co-authored-by: whatevertogo <149563971+whatevertogo@users.noreply.github.com>
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: letr <letr007@foxmail.com>
Co-authored-by: united_pooh <united_pooh@outlook.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: united_pooh <united_pooh@icloud.com>
Co-authored-by: Lishiling <m18384519631@163.com>
Co-authored-by: Li-shi-ling <114913764+Li-shi-ling@users.noreply.github.com>
Co-authored-by: letr <123731298+letr007@users.noreply.github.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: catDforD <3276453835@qq.com>
Co-authored-by: united_pooh <united_pooh@MBP-F6H6T2CYVV-2219.local>
2026-03-22 22:44:05 +08:00
LIghtJUNction
5721f7bf24 fix: remove broken tests referencing non-existent functions
- Remove test_computer_config.py (discover_bay_credentials not found)
- Remove test_main.py (check_dashboard_files not found)
- Remove test_skill_metadata_enrichment.py (_parse_frontmatter_description not found)
- Fix test_uninstall.py assertions to match actual output
- Fix test_bk.py digest test async mock
- Fix test_booter_decoupling.py shipyard test (incomplete config returns 0 tools)
- Fix computer_client.py _list_local_skill_dirs type error (Path vs anyio.Path)
- Remove TestApplySandboxTools class (function _apply_sandbox_tools not found)
2026-03-22 22:30:53 +08:00
LIghtJUNction
2f45280222 fix(dashboard): symlink dist for dev-mode resource resolution
importlib.resources.files('astrbot')/dashboard/dist needs to exist
in the package dir for bundled dashboard detection to work in dev.
2026-03-22 22:29:26 +08:00
whatevertogo
e9b1dd35f9 fix: remove privacy data from test case (#6803)
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
2026-03-22 21:49:43 +08:00
LIghtJUNction
798182fd8a Merge branch 'dev' of https://github.com/AstrBotDevs/AstrBot into dev 2026-03-22 20:17:28 +08:00
LIghtJUNction
5ba7ecec9e Merge branch 'master' of https://github.com/AstrBotDevs/AstrBot into dev 2026-03-22 20:16:52 +08:00
二枣子
937872cda7 feat(aiocqhttp): support file upload via Napcat stream transfer (#6433)
* feat(aiocqhttp): support file upload via Napcat stream transfer aiocqhttp

feat(aiocqhttp): support file upload via Napcat stream transfer
aiocqhttp上传资源文件时只传输本地路径,此方案对于没有共享磁盘方案不友好,Napcat >= v4.8.115 后,已支持新的 Stream API 方案。此方案在路径传输失败时自动尝试流式传输。

* perf(aiocqhttp): optimize file upload retry and streaming memory usage

1.内存使用优化,文件边读边传。
2.重试逻辑包装为独立方法便于阅读维护。
3.异常处理优化。
4.硬编码提取为模块级常量,提升可读性和配置性。

---------

Co-authored-by: LIghtJUNction <lightjunction.me@gmail.com>
2026-03-22 20:11:58 +08:00
LIghtJUNction
3545c8d393 chore: 新增依赖,移除类型忽略注释 2026-03-22 19:58:46 +08:00
LIghtJUNction
2f82f04ee2 chore: restore tui screen from history 2026-03-22 19:53:56 +08:00
LIghtJUNction
88821bd1bb Update test_plugin_manager.py 2026-03-22 19:50:36 +08:00
LIghtJUNction
b1d048ca5c chore: resolve merge conflicts (prefer HEAD) 2026-03-22 19:50:26 +08:00
LIghtJUNction
eab231fd94 chore: gitignore .env warker.js 2026-03-22 19:12:12 +08:00
LIghtJUNction
dd5105a504 fix(core/platform): platform event and adapters updates 2026-03-22 19:08:59 +08:00
LIghtJUNction
8cff9be334 fix(core): event bus and pipeline stage updates 2026-03-22 19:08:56 +08:00
LIghtJUNction
3a9bbcfdee fix(core/cron): update cron manager logic 2026-03-22 19:08:54 +08:00
LIghtJUNction
95ba23c3ab fix(core): minor changes to agent tool executor and lifecycle 2026-03-22 19:08:51 +08:00
LIghtJUNction
b70eb4e64f fix(core): narrow typed overrides for quoted message parser 2026-03-22 19:08:48 +08:00
Soulter
eab3298d42 docs: update wechat app version requirements for WeChat adapter and add instructions for profile photo/remark modifications 2026-03-22 18:33:32 +08:00
Soulter
81c7b0f715 chore: bump version to 4.22.0 2026-03-22 17:34:09 +08:00
Frank
1879e5961d fix: keep all CallToolResult content items (#6149)
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-03-22 17:21:22 +08:00
Soulter
b2d71e2b77 feat: supports image compressing (#6794)
* feat: supports image compressing (#6463)

Co-authored-by: Soulter <905617992@qq.com>

* feat: 增加图像压缩最大尺寸至1280

* Update astrbot/core/astr_main_agent.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* feat: 增强临时文件管理,添加图像压缩路径跟踪与清理功能

* feat: 更新图片压缩功能提示,移除对 chat_completion 提供商的限制说明

---------

Co-authored-by: Chen <42998804+a61995987@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-22 17:12:28 +08:00
Chen
02a910f038 feat: supports image compressing (#6463)
* feat:新增本地图片预压缩机制 避免原图体积过大造成的413错误

* 修正“图片解析失败”消息追加的位置错误
修正"temp_dir"的路径错误

* 修正temp_dir的相对路径错误

* 移动模块导入位置

* fix:重构图片压缩方法 使用异步方式避免阻塞

* ```
feat(core): 优化图片压缩功能并替换UUID为时间戳

- 将图片压缩的同步阻塞操作移至线程池执行,提升性能
- 替换uuid依赖为time模块,使用时间戳生成文件名
- 添加异步图片压缩内部函数_do_compress_sync
- 修复图片压缩时的异常处理日志级别
- 在消息附件和回复链中集成图片压缩功能
```

* fix:修改temp_dir指向 现在使用框架内置的get_astrbot_temp_path来获取临时目
fix:分离image_path的计算行为 提高可读性
fix:使用uuid来生成压缩后的图片 而非时间戳

* fix:修改错误的注释

* fix:分离图片压缩函数到媒体文件处理工具中

* fix:修改原有的列表推导式以提高可读性
feat:增加预留功能的说明注释

* fix:在图片压缩工具中使用pathlib.path获取路径并拼接压缩后的文件名称

* feat: 新增本地图片预压缩机制,增强图片解析容错能力

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-22 16:36:33 +08:00
Soulter
63dd28d778 fix: handle potential None values for token usage metrics in OpenAI provider (#6788)
Such as: unsupported operand type(s) for -: 'int' and 'NoneType'

fixes: #6772
2026-03-22 15:20:22 +08:00
M1LKT
a2dae0fc5e Feat(webui): support pinning and dragging for installed plugins (#6649) (#6776)
* refactor(persona): replace local folder components with shared folder components

* feat(webui): implement draggable reordering with animation for pinned plugins

* refactor(webui): extract PinnedPluginItem into a standalone component
2026-03-22 14:55:02 +08:00
Ruochen Pan
554c9cecfa feat: fix preserve escaped newlines in frontmatter & update tests & ci workflows (#6783) 2026-03-22 14:23:21 +08:00
Waterwzy
ef43217117 feat: skip search when the entire knowledge base is empty (#6750)
* feat:增加知识库全为空时的跳过检索

* apply bot suggestions

* style:reformat code
2026-03-22 13:36:18 +08:00
Lockinwize Lolite
3e68b7a3f3 fix(platform.tg_adapter): import Forbidden instead of deprecated Unauthorized (#6765) (#6769) 2026-03-22 13:35:09 +08:00
Soulter
e204790797 feat: supports weixin personal account (#6777)
* feat: supports weixin personal account

* feat(weixin): update documentation for personal WeChat integration and add QR code image

* feat(weixin): refactor send method to streamline message handling

* fix(weixin): correct AES key encoding in media payload construction

* feat(weixin): update weixin_oc_base_url description for clarity in config metadata

* feat(weixin): enhance WeChat integration with QR code support and configuration updates

* feat(weixin): implement WeixinOCClient for improved media handling and API requests

* feat(platform): update platform status refresh interval to 5 seconds
2026-03-22 13:25:12 +08:00
lightjunction
753e9a2bba chore: 2026-03-22 02:00:53 +08:00
Soulter
0743cb51bc chore: bump version to 4.21.0 2026-03-22 02:00:28 +08:00
Soulter
5419efbc9c feat(extension): add category filtering for market plugins and enhance UI components (#6762) 2026-03-22 01:54:21 +08:00
Soulter
52beeef83c feat(skill_manager): normalize and rename legacy skill markdown files to SKILL.md (#6757)
* feat(skill_manager): normalize and rename legacy skill markdown files to `SKILL.md`

* fix(vec_db): format debug log message for empty batch insert
2026-03-22 00:43:30 +08:00
LIghtJUNction
f9243a73d5 feat: reduce default max_agent_step to 3 and refactor shell execution
- Lower default max_agent_step from 30 to 3 across all agent runners
  (coze, dashscope, deerflow, dify) for faster responses
- Refactor ExecuteShellTool to use plumbum with session-based isolation,
  maintaining shell state per session (cwd, env vars, etc.)
- Remove unused API-specific environment variables from cmd_run
- Fix data access bug in shipyard_neo._maybe_model_dump
- Add plumbum>=1.10.0 dependency
2026-03-21 23:47:43 +08:00
Stable Genius
589776ab3f fix: skip empty knowledge-base embedding batches (#6106)
Co-authored-by: stablegenius49 <185121704+stablegenius49@users.noreply.github.com>
2026-03-21 20:56:13 +08:00
Stable Genius
5b71d01efb fix: convert Feishu opus files for Whisper API STT (#6078)
* fix: convert lark opus files for whisper api

* chore: ruff format

---------

Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-21 20:44:36 +08:00
LIghtJUNction
43e107068a chore: cloudflare 2026-03-21 17:35:30 +08:00
LIghtJUNction
09157f8b88 Fix: combine conditions for bot mention check in Discord adapter 2026-03-21 17:12:29 +08:00
若月千鸮
173583781e fix(lark): Defer card creation and renew on tool call break (#6743)
* fix(lark): defer streaming card creation and renew card on tool call break

- Defer CardKit streaming card creation until the first text token
  arrives, preventing an empty card from rendering before content.
- Handle `type="break"` signal in send_streaming: close the current
  card and lazily create a new one for post-tool-call text, so the
  new card appears below the tool status message in correct order.
- Only emit "break" signal when show_tool_use is enabled; when tool
  output is hidden, the AI response continues on the same card.

* style: format ruff

* fix: cr bug

* fix: cr
2026-03-21 17:08:25 +08:00
LIghtJUNction
256c8cceeb Fix: handle None values for ctx.author and ctx.interaction in Discord adapter 2026-03-21 16:15:33 +08:00
LIghtJUNction
7391f8e5ee Fix: only enable CORS credentials when allow_origin is not wildcard 2026-03-21 16:00:17 +08:00
LIghtJUNction
b563518711 Fix: replace fullwidth comma with halfwidth comma in discord_platform_adapter.py 2026-03-21 15:21:35 +08:00
LIghtJUNction
255a4c0d5b Fix: support configuring allowed CORS origins via CORS_ALLOW_ORIGIN env
var for cross-origin credential requests
2026-03-21 15:20:43 +08:00
LIghtJUNction
859ca98f1e Fix: support configuring allowed CORS origins via CORS_ALLOW_ORIGIN env var for cross-origin credential requests 2026-03-21 15:14:08 +08:00
LIghtJUNction
a58319f594 Fix: Discord adapter not adding At component when bot is mentioned, causing group messages to not wake the bot 2026-03-21 14:26:22 +08:00
LIghtJUNction
26c5e67efe Refactor: change relative imports to absolute imports in tool_loop_agent_runner.py 2026-03-21 14:13:43 +08:00
LIghtJUNction
4412f789e1 Fix: downgrade SSL APPLICATION_DATA_AFTER_CLOSE_NOTIFY errors to debug level 2026-03-21 14:13:07 +08:00
LIghtJUNction
cefeaf8d9f Fix: add task tracking to BaseAgentRunner and ToolLoopAgentRunner, replace asdict with custom serialization in Response 2026-03-21 13:55:05 +08:00
LIghtJUNction
97efa3ab38 Fix: _BUNDLED_DIST undefined, use self.bundled_dist instead 2026-03-21 13:54:39 +08:00
LIghtJUNction
61e525afd4 Merge branch 'master' into dev 2026-03-21 12:25:04 +08:00
Stable Genius
25c136ef95 fix: fall back on Windows skill file encodings (#6058)
Co-authored-by: stablegenius49 <185121704+stablegenius49@users.noreply.github.com>
2026-03-21 11:00:40 +08:00
Stable Genius
5e69b62e4c fix(webchat): render standalone HTML replies as code (#6074)
Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-03-21 10:52:46 +08:00
Stable Genius
968868f16b fix: ensure Gemini array schemas always include items (#6051)
Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com>
2026-03-21 10:44:48 +08:00
qingyun
e643bc94e5 fix(skills): use actual sandbox path from cache instead of hardcoded workspace root (#6331)
* fix(skills): use actual sandbox path from cache instead of hardcoded workspace root

Fixes #6273

When using Shipyard booter, the sandbox workspace directory is
`/home/ship_{session_id}/workspace/` instead of the hardcoded `/workspace`.
This caused Agent to fail reading SKILL.md files with 'No such file or directory'.

Changes:
- In build_skills_prompt: prefer skill.path (from sandbox cache) over
  hardcoded SANDBOX_WORKSPACE_ROOT for sandbox_only skills
- In list_skills: always prefer sandbox_cached_paths over hardcoded path
  for sandbox_only skills

The actual path is resolved at sandbox scan time via Path.resolve() in
_build_scan_command, which returns the correct absolute path based on
the sandbox's actual working directory.

* docs: add comment explaining show_sandbox_path behavior for sandbox_only skills

Address Sourcery AI review comment:
- Clarify that show_sandbox_path is implicitly True for sandbox_only skills
- Explain why the flag is effectively ignored (no local path exists)

* refactor: simplify path_str fallback using or operator

Address review feedback: use single-line fallback instead of if-not pattern.

* style: format skill_manager.py with ruff

Fix ruff format-check failure

* fix(skills): sanitize cached sandbox skill paths

Normalize sandbox cache paths before reading or writing them so invalid,
empty, or mismatched entries fall back to a safe default SKILL.md path.

This avoids using malformed cached paths, keeps path rendering
consistent, and ensures sandbox skill listings always point to the
expected workspace location.

---------

Co-authored-by: ccsang <ccsang@users.noreply.github.com>
Co-authored-by: RC-CHN <1051989940@qq.com>
2026-03-21 10:39:52 +08:00
Soulter
df4eb33582 docs: update README.md to add separator in links section 2026-03-21 10:34:27 +08:00
LIghtJUNction
286f6668f4 Fix formatting of bundled_dist property method 2026-03-21 05:10:52 +08:00
LIghtJUNction
4a5ac407d1 Refactor bundled_dist path handling in AstrbotPaths
Removed the _BUNDLED_DIST variable and added a bundled_dist property to calculate the path dynamically.
2026-03-21 05:01:41 +08:00
LIghtJUNction
93cab0e198 Reorganize .env loading sequence in astrbot_path.py
Refactor environment variable loading order in astrbot_path.py.
2026-03-21 04:51:53 +08:00
LIghtJUNction
b2a04ffed1 Fix syntax error in tool_loop_agent_runner.py 2026-03-21 04:21:21 +08:00
LIghtJUNction
3405c72b5e Modify context configuration parameters
Updated max_context_tokens default value and adjusted enforce_max_turns logic.
2026-03-21 04:17:59 +08:00
LIghtJUNction
4ee93c7f83 Limit max_step to a maximum of 3
基本都是设置为30,30太夸张了,这是日志里面截出来的:
system,user,assistant,user,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,tool,assistant,user,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,tool,assistant,user,assistant,tool,tool,assistant,tool,assistant,user,assistant,tool,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user,assistant,user
2026-03-21 04:12:49 +08:00
LIghtJUNction
a710c06be2 Validate config_path before checking existence
Add check for empty config_path in check_exist method
2026-03-21 03:49:12 +08:00
LIghtJUNction
864a6851df Fix context manager usage for timeout enforcement 2026-03-21 03:36:32 +08:00
LIghtJUNction
37594dd74b Return Path object for project root property 2026-03-21 03:04:00 +08:00
LIghtJUNction
68c01cfba4 Fix handling of cached_tokens in _extract_usage
Ensure cached_tokens is an integer and handle None safely.
2026-03-21 02:37:04 +08:00
LIU Yaohua
8d9838a293 fix(agent): pass tool_call_timeout to subagent handsoff, cron and background task execution, and increase default timeout from 60 to 120 (#6713)
* fix(agent): pass tool_call_timeout to SubAgent handoff execution

- Add tool_call_timeout parameter to _execute_handoff method
- Pass run_context.tool_call_timeout to ctx.tool_loop_agent
- Add unit test to verify tool_call_timeout is correctly passed
- Fixes #6711: SubAgent MCP tool call timeout now respects configured timeout

The SubAgent handoff execution was using the default 60-second timeout
instead of the configured tool_call_timeout from provider settings.
This change ensures that SubAgent MCP tool calls respect the user's
configured timeout settings.

* test: add unit test for tool_call_timeout in SubAgent handoff

* fix: restore deleted test and fix test assertion

- Restore test_collect_handoff_image_urls_filters_extensionless_missing_event_file
- Fix test_collect_handoff_image_urls_keeps_extensionless_existing_event_file assertion
- Keep new test_execute_handoff_passes_tool_call_timeout_to_tool_loop_agent

* refactor: simplify tool_call_timeout passing in _execute_handoff

- Pass run_context.tool_call_timeout directly to ctx.tool_loop_agent
- Remove unnecessary local variable assignment
- Addresses review feedback from Sourcery AI

* fix(config): increase default tool call timeout from 60 to 120 seconds

---------

Co-authored-by: LehaoLin <linlehao@cuhk.edu.cn>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-21 01:30:53 +08:00
BillionToken
b273ba2a19 fix(config): respect disabled system functions in web search tools (#6584)
Co-authored-by: BillionClaw <billionclaw@cl OSS.dev>
2026-03-21 01:18:47 +08:00
Soulter
5214a8c0ba perf(webchat): enhance message handling with proactive saving and streaming completion (#6698) 2026-03-21 01:14:02 +08:00
Yufeng He
7beab796bb fix: skills-like re-query missing extra_user_content_parts causes image_caption not to be injected (#6710)
当使用 skills-like tool mode 时,_resolve_tool_exec 的 re-query 调用没有
传递 extra_user_content_parts,导致图片描述等附加内容丢失。

fixes #6702

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-03-21 01:11:34 +08:00
qingyun
b2797b6f16 fix(agent): reject follow-up messages after stop request (#6704)
* fix: reject follow-up messages after stop requested (#6626)

Once a user sends /stop, follow-up messages should no longer be
accepted for that runner. Previously, there was a race window where
messages sent after stop could still be queued as follow-ups.

This fix gates the follow_up() method to check both done() and
_stop_requested before accepting a new follow-up message.

Acceptance criteria met:
- After /stop, later follow-up messages return None (rejected)
- Post-stop follow-ups are not added to _pending_follow_ups
- No post-stop text is injected into tool results
- Graceful-stop behavior otherwise unchanged
- Follow-ups submitted before stop retain current behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add regression tests for issue #6626 follow-up rejection

Add focused tests that verify the complete tool-result injection path
for follow-up messages after stop is requested:

- test_follow_up_rejected_and_runner_stops_without_execution: Verifies
  that when stop is requested before any execution, follow-ups are
  rejected and the runner stops gracefully without executing tools.

- test_follow_up_merged_into_tool_result_before_stop: Verifies that
  follow-ups queued before stop are properly merged into tool results
  via _merge_follow_up_notice().

- test_follow_up_after_stop_not_merged_into_tool_result: Regression
  test that simulates the race condition from issue #6626. Verifies
  that only pre-stop follow-ups are merged into tool results, and
  post-stop follow-ups are rejected at the admission point.

These tests validate the fix in ToolLoopAgentRunner.follow_up() that
checks both self.done() and self._stop_requested before accepting
new follow-up messages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(agent): update stop request check in ToolLoopAgentRunner

---------

Co-authored-by: ccsang <ccsang@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-21 01:06:37 +08:00
LIghtJUNction
6e3273dbec 修复:argon2库已过时,无法在3.12运行 2026-03-21 01:03:39 +08:00
SJ
b816f26fe6 fix(core): interrupt subagent tool waits on stop (#5850)
* fix(core): interrupt subagent tool waits on stop

* test: relax subagent handoff timeout

* test: cover stop-aware tool interruption

* refactor: unify runner stop state

* refactor: simplify tool executor interruption

* fix: preserve tool interruption propagation

* refactor: tighten interruption helpers

---------

Co-authored-by: idiotsj <idiotsj@users.noreply.github.com>
2026-03-21 00:59:52 +08:00
LIghtJUNction
af77f82c51 更名:conf password可以修改账户名称,因此改名为admin
astrbot conf admin -p xxx
2026-03-21 00:47:14 +08:00
LIghtJUNction
1b92c517e7 Merge branch 'master' into dev 2026-03-21 00:31:18 +08:00
LIghtJUNction
c238880cd2 修复:server.py 2026-03-21 00:28:56 +08:00
晴空
d2e0bc778a fix: preserve PATHEXT for stdio mcp servers on windows (#5822)
* fix: preserve PATHEXT for stdio mcp servers on windows

* chore: delete test_mcp_client.py

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-21 00:27:54 +08:00
LIghtJUNction
92b3e2d260 fix: avoid false dashboard port conflicts 2026-03-21 00:24:35 +08:00
Gargantua
dde02815c2 feat: add a toggle to disable thinking mode in Ollama (#5941)
* feat: add ollama thinking toggle

* fix: simplify hint for ollama_disable_thinking configuration

---------

Co-authored-by: Gargantua <22532097@zju.edu.cn>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-21 00:19:08 +08:00
LIghtJUNction
00c9388da3 重构:彻底放弃md5保存密码
main.py调整说明
修复一系列导入问题
修复一部分ruff check问题
2026-03-21 00:09:58 +08:00
whatevertogo
2c279abad1 fix: prevent accidental removal of MCP external tools due to name collisions with disabled built-in tools (#5925)
* fix: 解决 MCP 工具与内置工具重名时的连坐问题

- 修改 get_func 方法:优先返回已激活的工具
- 修改 get_full_tool_set 方法:使用 add_tool 防止同名冲突
- 修改 add_tool 方法:优先保留已激活的工具

Fixes #5821

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: address PR review feedback for tool conflict resolution

- Fix inconsistency: get_func now uses reversed() to match ToolSet.add_tool's
  "last-active-wins" logic, preventing potential "tool hijacking" issues
- Improve readability: replace double negative condition with clearer logic
- Add compatibility: use getattr with default for tools without 'active' attribute
- Remove unnecessary deepcopy: MCPTool runtime objects should not be deep copied
- Update docstring: accurately describe the actual tool resolution behavior

Addresses review comments from sourcery-ai, gemini-code-assist, and Copilot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add tests for tool conflict resolution (issue #5821)

Add comprehensive tests for ToolSet.add_tool, get_func, and get_full_tool_set
to verify the conflict resolution behavior when MCP tools share names with
built-in tools.

Test cases:
- ToolSet.add_tool: active/inactive priority, last-one-wins for same state
- get_func: returns last active tool, fallback to last matching tool
- get_full_tool_set: deduplication logic, no deepcopy, MCP overrides disabled builtin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复工具冲突处理逻辑,确保未激活工具不被错误移除

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 23:44:07 +08:00
_Kerman
abb5de2ed5 chore: rename "OpenAI" provider to "OpenAI Compatible" (#6707) 2026-03-20 23:19:26 +08:00
LIghtJUNction
7445126057 Merge branch 'master' into dev 2026-03-20 22:40:32 +08:00
LIghtJUNction
9f2240a2a6 fix async ssl path handling 2026-03-20 21:50:46 +08:00
LIghtJUNction
a130b344b0 fix: narrow knowledge base provider types 2026-03-20 21:45:04 +08:00
LIghtJUNction
28e8e50005 fix: improve dashboard and knowledge base file handling 2026-03-20 21:40:21 +08:00
LIghtJUNction
a0b61c4da9 fix: correct rate limit stage algorithm docs 2026-03-20 21:35:55 +08:00
LIghtJUNction
b4f48ea1f0 fix: resolve dashboard build type errors 2026-03-20 21:21:31 +08:00
RichardLiu
a10ba4d641 feat: add xiaomi MiMo TTS & STT providers (#6643)
* feat: add mimo tts provider support

* fix: handle empty mimo tts choices

* feat: add mimo stt provider support
2026-03-20 20:52:21 +08:00
Helian Nuits
64853487b5 fix: auto-restart telegram polling loop on failure (#6648)
* fix: auto-restart telegram polling loop on failure (#373)

* fix: auto-restart telegram polling loop on failure

* fix: harden telegram polling restart lifecycle

* fix(telegram): 根据建议优化轮询鲁棒性并处理 Token 失效错误

* fix: 补全配置元数据及 i18n
2026-03-20 20:35:48 +08:00
LIghtJUNction
5ff71fef3e chore:环境变量注释修正 2026-03-20 20:02:47 +08:00
LIghtJUNction
073891c093 修复:移除错误的环境变量名字 2026-03-20 20:00:32 +08:00
LIghtJUNction
4fd77ea008 修复:启动链,参数/环境变量加载逻辑优化 2026-03-20 19:47:04 +08:00
LIghtJUNction
78edc0fff8 修复:启动链,参数/环境变量加载逻辑优化 2026-03-20 19:44:12 +08:00
LIghtJUNction
4f04d39348 同步:同步主线 2026-03-20 16:59:43 +08:00
LIghtJUNction
13132517b2 重构: 修正一些错误,引入_internel包 2026-03-20 16:51:27 +08:00
LIghtJUNction
804a02a2d1 fix(types): await anyio.open_file before async use to satisfy type checkers 2026-03-20 16:36:22 +08:00
LIghtJUNction
f076799b81 fix: async dashboard version read via anyio async context manager 2026-03-20 16:33:51 +08:00
LIghtJUNction
0068825cd5 cli(init): add --root option and generate .env from config.template into ASTRBOT_ROOT (auto-loaded by run) 2026-03-20 16:24:02 +08:00
LIghtJUNction
0b2a143681 cli(run): simplify env loading — move .env early-load to astrbot_path; service-config treated as .env; preserve CLI > service-config > .env precedence 2026-03-20 16:05:30 +08:00
LIghtJUNction
0e95a47276 fix: import error 2026-03-20 15:18:03 +08:00
Yufeng He
39131d2e12 fix: Follow-up logic persists after /stop trigger (#6656)
/stop 设置 agent_stop_requested 标记,但 runner 直到当前工具调用
超时才从 _ACTIVE_AGENT_RUNNERS 注销。在此窗口期内,用户发的新消息
被 try_capture_follow_up() 当作 follow-up 吞掉。

在 follow-up 捕获前检查 stop 标记:一旦用户请求停止,就不再把后续
消息注入到正在终止的 agent 上下文中。

Fixes #6626
2026-03-20 13:53:56 +08:00
letr
735bd43648 fix(dashboard): simplify persona selector layout for mobile screens (#5907) 2026-03-20 13:45:21 +08:00
Soulter
6a42ad7934 fix(openai): improve logging for proxy and API base configuration (#6669)
fix: #6558
2026-03-20 13:42:58 +08:00
daniel5u
b07dbb3d26 feat: add Kimi Coding Plan provider with Anthropic API compatibility (#6559)
* Add Kimi Code provider

* Add icon mapping for Kimi Code provider

* Clarify Kimi CodingPlan provider labeling

* Refine Kimi Code header handling

* modified docker compose

* fix: correct Kimi Coding Plan label and update API base URL

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-20 13:32:06 +08:00
leonforcode
0b69034491 fix: prevent truncation logic from removing the only user message in long tool-calling conversations (#6198)
* fix: 压缩算法删除 user 消息 Bug 修复

* perf: improve truncate algo

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-20 12:05:54 +08:00
Yufeng He
e286da75c4 fix: 截断器丢失唯一 user 消息导致智谱等 provider 返回 400 (#6581)
* fix: 截断器丢失唯一 user 消息导致 API 400

修复 #6196

当对话只有一条 user 消息(长 tool chain 场景:system → user → assistant
→ tool → assistant → tool → ...),三个截断方法都会把这条 user 消息丢掉,
导致智谱、Gemini 等要求 user 消息的 provider 返回 400。

改动:
- 提取 `_split_system_rest()` 去掉三个方法里重复的 system/non-system 拆分
- 新增 `_ensure_user_message()`:截断后如果没有 user 了,从原始消息里补回
  第一条 user,避免违反 API 格式要求
- 删掉 `truncate_by_dropping_oldest_turns` 里把没有 user 就清空全部消息的逻辑
- 5 个新测试覆盖单 user + 长 tool chain 场景,3 个旧测试更新断言

* style: format code

---------

Co-authored-by: Yufeng He <40085740+universeplayer@users.noreply.github.com>
Co-authored-by: RC-CHN <1051989940@qq.com>
2026-03-20 10:06:20 +08:00
LIghtJUNction
bf11f4c376 chore: fw2hw 2026-03-20 00:44:39 +08:00
LIghtJUNction
ef5dac77a2 chore: fw2hw 2026-03-20 00:44:08 +08:00
LIghtJUNction
92bae1fdae docs: replace prints with logger in upload_doc_images_to_r2.py 2026-03-19 23:30:25 +08:00
LIghtJUNction
a3371ad6c8 core: refactor modules & fix typing/runtime issues 2026-03-19 23:06:27 +08:00
LIghtJUNction
8184e20850 dashboard: validate SSL file paths with pathlib before use (fix typing/runtime issues) 2026-03-19 22:41:04 +08:00
LIghtJUNction
a4e6e16fd8 fix: surface https backend requirement in dashboard (#6623)
* fix: surface https backend requirement in dashboard

* Update dashboard/src/stores/api.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-19 20:35:32 +08:00
LIghtJUNction
cc88ac6bef fix(cli): export webui group symbol 2026-03-19 20:09:47 +08:00
LIghtJUNction
b6f4614c58 fix(cli): robust password hashing when argon2 missing (fallback to PBKDF2) 2026-03-19 20:02:24 +08:00
LIghtJUNction
f03040a12e chore(pyproject): limit requires-python <3.14 to avoid resolver mismatch in env 2026-03-19 19:58:27 +08:00
LIghtJUNction
1bb73ab3cf feat(cli): add 'webui' group + register command in CLI 2026-03-19 19:53:48 +08:00
LIghtJUNction
17b0dfe974 fix(cli): restore cmd_conf password hashing and validators; use absolute import for check_astrbot_root 2026-03-19 19:46:21 +08:00
LIghtJUNction
d16f62423c Merge branch 'master' into dev 2026-03-19 19:25:47 +08:00
machina
7008a46158 fix: update hint for ID whitelist configuration to clarify behavior when empty (#6611)
* fix: update hint for ID whitelist configuration to clarify behavior when empty

* fix: update whitelist hint

---------

Co-authored-by: machina <1531829828@qq.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-19 19:06:53 +08:00
Soulter
5a90b56e45 fix(openai): Token usage not working when using MoonshotAI official API (#6618)
fixes: #6614
2026-03-19 19:04:24 +08:00
LIghtJUNction
c0282e4d28 Potential fix for code scanning alert no. 45: Use of a broken or weak cryptographic hashing algorithm on sensitive data
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-19 17:40:25 +08:00
LIghtJUNction
fce8069b18 Potential fix for code scanning alert no. 44: Use of a broken or weak cryptographic hashing algorithm on sensitive data
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-19 17:40:09 +08:00
LIghtJUNction
201a19a63e Potential fix for code scanning alert no. 46: Use of a broken or weak cryptographic hashing algorithm on sensitive data
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-03-19 17:39:55 +08:00
Yufeng He
2cb6c84eeb feat: context token counting support for multimodal content (images, audio, and chain-of-thought) (#6596)
EstimateTokenCounter 之前只计算 TextPart,完全忽略 ImageURLPart、
AudioURLPart 和 ThinkPart。多模态对话中图片占 500-2000 token,
不被计入会导致 context 压缩触发过晚,API 先报 context_length_exceeded。

改动:
- ImageURLPart 按 765 token 估算(OpenAI vision 低/高分辨率中位数)
- AudioURLPart 按 500 token 估算
- ThinkPart 的文本内容正常计算
- 10 个新测试覆盖各类型单独和混合场景

Co-authored-by: Yufeng He <40085740+universeplayer@users.noreply.github.com>
2026-03-19 17:25:49 +08:00
Soulter
1a1d83d3be fix(wecom-aibot): significantly improve streaming readability and speed via add throttling (#6610)
* fix(wecom-ai): add 0.5s interval for streaming responses

* fix(wecom-ai): correct event type checking and add spacing in WecomAIBotMessageEvent
2026-03-19 17:14:42 +08:00
Scofield
a748264fa4 fix: prevent wecom ai bot long connection replies from disappearing (#6606)
* fix: prevent empty fallback replies from clearing wecom ai bot output

* fix: 优化消息发送逻辑,避免发送空消息

---------

Co-authored-by: shijianhuai <shijianhuai@simuwang.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-19 16:56:15 +08:00
LIghtJUNction
664bc68093 fix: support github pages base path config (#6608) 2026-03-19 16:03:52 +08:00
Ruochen Pan
2cda708eba docs(sandbox): clarify section references in guides (#6591) 2026-03-19 10:07:30 +08:00
Ruochen Pan
7f897887fd feat (doc) : Add doc for shipyard-neo sandbox driver (#6590)
* fix(ui): localize session management group texts

Replace hardcoded Chinese strings in SessionManagementPage with i18n
lookups for group management labels, dialogs, and action feedback.

Add and align translation keys in en-US, ru-RU, and zh-CN for group
management and batch operation messages to ensure consistent multilingual
UI behavior.

* fix(ui): localize interval method hint text

* docs(sandbox): document shipyard neo setup

Expand the Chinese sandbox guide to cover Shipyard Neo as the
recommended driver and distinguish it from legacy Shipyard.

Add deployment and configuration guidance for standalone and
compose-based setups, include a full annotated config example,
and clarify profile selection, TTL behavior, workspace paths,
and persistence semantics.

* docs(sandbox): recommend standalone shipyard neo

Clarify that Shipyard Neo is best deployed on a separate,
better-provisioned host for long-term use.

Update the setup steps and AstrBot connection guidance, and
remove the earlier combined Docker Compose deployment flow.

* docs(sandbox): expand shipyard neo guide

Document Shipyard Neo as the recommended sandbox driver and
clarify how it differs from the legacy Shipyard setup.

Add guidance for deployment, performance requirements, Bay
configuration, profile selection, TTL behavior, workspace
persistence, and browser capability support.

Also reorganize the sandbox configuration section and keep the
legacy Shipyard instructions for compatibility.

* docs(sandbox): fix shipyard neo doc links

Update the sandbox guides in English and Chinese to link
directly to the upstream `config.yaml` example.

Replace duplicated TTL and persistence notes with references
to the dedicated sections to keep the guide concise and easier
to maintain.
2026-03-19 10:00:19 +08:00
LIghtJUNction
b49c3210d9 Update linting rules in pyproject.toml
Added new rules for isort, pyupgrade, flake8-debugger, flake8-print, flake8-pyi, flake8-pytest-style, flake8-tidy-imports, and Ruff-specific rules.
2026-03-19 03:35:58 +08:00
LIghtJUNction
46b7a4e441 move runtime_bootstrap.py 2026-03-19 03:25:24 +08:00
LIghtJUNction
ee1f9dece8 fix:gh-pages 2026-03-19 01:32:43 +08:00
LIghtJUNction
99453652f8 fix(plugin): make temporary requirements context manager async to allow and avoid blocking event loop 2026-03-19 00:04:59 +08:00
LIghtJUNction
6e90937ab4 fix: path 2026-03-18 23:51:33 +08:00
エイカク
40076b6aff fix: set packaged Windows runtime build env for pip native builds (#6575)
* Fix Windows packaged runtime pip build env

* test(pip): cover packaged runtime env injection edges

* refactor(pip): tighten packaged runtime env handling

* test(pip): cover missing runtime build dirs

* fix(pip): build runtime env inside locked section

* test(pip): expand windows path normalization coverage

* refactor(pip): build runtime env from snapshots

* fix(pip): preserve windows env key semantics

* refactor(pip): simplify windows runtime env handling

Keep the in-process pip environment mutation and case-insensitive INCLUDE/LIB handling localized so packaged Windows builds are easier to follow. Add a UNC no-op regression case to guard path normalization.

* refactor(pip): streamline runtime env mutation helpers

Keep packaged Windows pip environment handling easier to follow by reusing a temporary environment context manager, isolating case-insensitive INCLUDE/LIB lookup, and documenting native path normalization behavior.
2026-03-19 00:07:03 +09:00
LIghtJUNction
bb4e9f61f4 Merge branch 'master' into dev 2026-03-18 23:03:00 +08:00
LIghtJUNction
98a8502ebe fix: resolve asynchronous context manager and coroutine attribute issues
- Fixed '_GeneratorContextManager' error in pip_installer.py by using synchronous 'with' for constraints_file().
- Fixed 'CoroutineType' has no attribute 'is_file' in dashboard/routes/config.py by adding missing await.
- Fixed undefined names (Group, ComponentTypes, File, Reply, At) in aiocqhttp_platform_adapter.py.
- Added 'pytest-cov' for code coverage testing.
2026-03-18 22:35:49 +08:00
LIghtJUNction
a410fa3351 fix: path 2026-03-18 21:20:11 +08:00
糯米茨
24554cf443 enhance:更改未完成更新的文档用词问题(多处“消息平台”已更名为“机器人”) (#6568)
* Update kubernetes.md

* Update discord.md

* Update kubernetes.md

* Update AstrBot setup instructions in Kubernetes doc
2026-03-18 21:12:39 +08:00
LIghtJUNction
9cbf253697 chore: remove redundant pdf parser type ignores 2026-03-18 20:12:58 +08:00
LIghtJUNction
a92dfc3913 refactor: simplify cli initialization and uninstall messaging 2026-03-18 20:12:53 +08:00
LIghtJUNction
884efd47cd fix: refresh astrbot root path resolution 2026-03-18 20:12:30 +08:00
LIghtJUNction
1b9820af44 feat: update dashboard 2026-03-18 20:12:22 +08:00
LIghtJUNction
e8c234f0cf feat: improve cli admin setup and api startup logs 2026-03-18 18:21:49 +08:00
LIghtJUNction
14ec513b0d fix: clean lint suppressions and async route errors 2026-03-18 18:06:42 +08:00
LIghtJUNction
26d6d1b36f fix: resolve ruff check issues 2026-03-18 17:38:27 +08:00
LIghtJUNction
fb93949edd fix: resolve ruff async path violations 2026-03-18 17:36:46 +08:00
LIghtJUNction
c9fac2bf82 fix: sync lock file 2026-03-18 17:29:07 +08:00
LIghtJUNction
f6945e0992 chore: remove deploy-dashboard.yml 2026-03-18 17:25:33 +08:00
LIghtJUNction
7fd02cc76a Merge branch 'master' into dev 2026-03-18 17:22:50 +08:00
LIghtJUNction
4bf2f0cb28 fix(dashboard): handle missing static assets gracefully and fix async/ruff issues
- Dashboard: Catch missing index.html error, log warning, and disable WebUI instead of crashing.
- Dashboard: Use anyio.Path for async file existence checks in SSL config.
- CLI/Backup: Replace blocking file operations with anyio async operations.
- Core: Replace blocking file operations with anyio in Coze/Dify clients and TTS simulation.
- Provider: Rename 'timeout' param to 'init_timeout'/'request_timeout' to fix ASYNC109 warnings.
- Ruff: Fix various ASYNC230/ASYNC240 errors across multiple files.
2026-03-18 16:46:22 +08:00
camera-2018
4e5587998b perf(dashboard): subset MDI icon font and self-host Google Fonts (#6532)
* perf(dashboard): subset MDI icon font and self-host Google Fonts

* perf(dashboard): subset MDI icon font and self-host Google Fonts

* perf(dashboard): subset MDI icon font and self-host Google Fonts

* perf(dashboard): subset MDI icon font cr fix

* chore: update lockfile
2026-03-18 16:32:19 +08:00
LIghtJUNction
f1ad60982c feat(cli): init cmd supports restoring from backup 2026-03-18 16:02:32 +08:00
LIghtJUNction
b301ff21f2 feat(cli): enhance run/init/help cmds & service config support 2026-03-18 14:16:25 +08:00
LIghtJUNction
ad3e5c473a Merge conflict resolution 2026-03-18 14:16:14 +08:00
LIghtJUNction
12cdf454b4 feat(cli): enhance run/init/uninstall for systemd & debug; refactor(env): standardize vars 2026-03-18 13:52:00 +08:00
LIghtJUNction
b839de2050 fix(discord): handle timeout error on shutdown; chore(cli): remove systemd service creation 2026-03-18 12:56:05 +08:00
Yufeng He
412e2e07cc Clarify FileUpload/DownloadTool descriptions to fix LLM tool selection (#6527)
Multiple models (Gemini 3, GPT-5.2, Claude Sonnet, Kimi K2.5) consistently
pick FileDownloadTool when they should pick FileUploadTool. The old
descriptions used "upload/download" which is ambiguous from the LLM's
perspective — it doesn't know which side is "local" vs "remote".

Rewrite descriptions to use explicit directional language:
- Upload: "Transfer FROM host INTO sandbox" + "when user sends a file"
- Download: "Transfer FROM sandbox OUT to host" + "ONLY when user asks
  to retrieve/export"

Also improve parameter descriptions with the same directional clarity.

Fixes #6497

Co-authored-by: Yufeng He <40085740+universeplayer@users.noreply.github.com>
2026-03-18 09:34:48 +08:00
LIghtJUNction
2946460484 update astrbot.service 2026-03-18 01:22:43 +08:00
LIghtJUNction
73517ec2a5 更新 cmd_init.py 2026-03-18 00:35:29 +08:00
LIghtJUNction
87b50a5fd5 fix/ astrbot.service, update path 2026-03-18 00:34:26 +08:00
LIghtJUNction
9877abc472 更新 cmd_init.py 2026-03-18 00:22:21 +08:00
LIghtJUNction
7eafa3a2e2 update astrbot.service 2026-03-18 00:21:27 +08:00
鸦羽
c22e1f6a4d fix: restrict workflows to upstream repo (#6531) 2026-03-17 23:35:16 +08:00
Soulter
51c8d22d05 feat: install plugin using metadata name and validate importable identifiers (#6530)
* feat: install plugin using metadata name and validate importable identifiers

* fix: cleanup temporary upload extraction directory on plugin install failure

* Update astrbot/core/star/star_manager.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* fix: avoid unnecessary install when repository directory already exists

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-17 23:23:59 +08:00
LIghtJUNction
c1ad6f7032 fix(core): use explicit import for anyio.to_thread to resolve static analysis issue
This resolves a 'BrokenWorkerInterpreter' attribute access error reported by basedpyright.
2026-03-17 22:52:33 +08:00
LIghtJUNction
b53f042a6d fix(core): ensure parent directories exist before saving skill config and cache; fix async file read in star_manager 2026-03-17 22:33:56 +08:00
LIghtJUNction
6dc13b880b refactor: rename skills_like to lazy_load and add skill schema support 2026-03-17 21:32:06 +08:00
LIghtJUNction
f3d6f762c3 refactor: rename skills_like to lazy_load and add skill schema support 2026-03-17 20:46:07 +08:00
shuiping233
718215425d refactor: downgrade StrEnum to (str, Enum) in kook_type for backward compatibility (#6512)
我那时候搓 #5719 的时候 #5729 已经合并了, 既然ruff的py限制版本里是`3.12`,那我那时候干脆用的StrEnum,现在发现那个pr revert了,那我也降级回旧Enum写法好了
2026-03-17 19:58:40 +08:00
Soulter
6be8a4302d docs: add aiocqhttp and satori protocol documentation; remove outdated lagrange and napcat guides 2026-03-17 19:56:08 +08:00
Soulter
62be8d2600 perf: improve onebot and satori documents 2026-03-17 19:33:51 +08:00
LIghtJUNction
4c0fb31e7d Refactor theme constants and resolve merge conflicts 2026-03-17 19:27:50 +08:00
Kangyang Ji
7aae048405 feat(dashboard): add auto switch theme (default off) (#6405)
* feat(dashboard): add auto switch theme (default off)
feat(dashboard): move all get theme and set theme by check current theme into stores/customizer

* feat(dashboard): fix duplicate for auto switch theme
根据Gemini的意见更改了一些地方。
将原本的状态更新挪到了App.vue里,可以去除很多地方更新theme所需要的theme依赖。
将翻译修改了
将监听器改为了watch
2026-03-17 19:06:01 +08:00
qingyun
df1e59e01c fix(core): use original version constraints instead of locking to installed version (#6445)
* feat: Add OpenRouter chat completion provider adapter with custom headers. (#6436)

* chore: update astrbot.service configuration

* fix(core): use original version constraints instead of locking to installed version

Fixes #6420

The core constraints mechanism was using the currently installed version as
an exact constraint (e.g., `aiosqlite==0.21.0`), preventing plugins from
installing higher versions even when they satisfy the original constraint.

Changes:
- Preserve original version specifier from pyproject.toml (e.g., `>=0.21.0`)
- Allow plugins to require higher versions as long as they satisfy core constraint
- Prevent downgrade by using `>=installed` for packages without version constraint

Example:
- Before: Core constraint `aiosqlite==0.21.0`, plugin requires `>=0.22.1` → BLOCKED
- After: Core constraint `aiosqlite>=0.21.0`, plugin requires `>=0.22.1` → ALLOWED

This enables better dependency management while still protecting core dependencies
from incompatible downgrades.

---------

Co-authored-by: Futureppo <luominzhi2005@qq.com>
Co-authored-by: LIghtJUNction <lightjunction.me@gmail.com>
Co-authored-by: ccsang <ccsang@users.noreply.github.com>
2026-03-17 18:59:24 +08:00
LIghtJUNction
25f9effcc9 Merge branch 'master' into dev 2026-03-17 18:53:46 +08:00
LIghtJUNction
5caf3a4793 chore: update AGENTS.md 2026-03-17 18:52:44 +08:00
LIghtJUNction
458e8e0db8 fix(cli): recover flags consumed by -E option and prompt for recipient 2026-03-17 18:48:19 +08:00
LIghtJUNction
976398d1f2 feat(cli): enhance backup capabilities and refactor path management
- Introduce 'astrbot bk' command with GPG signing, encryption, and digest support
- Add import/export functionality using core backup modules
- Refactor path management to use 'AstrbotPaths' singleton across CLI commands
- Replace blocking subprocess calls with asyncio.create_subprocess_exec in backup command
- Add comprehensive tests for uninstall and backup commands
- Improve module resource handling for bundled dashboard assets
2026-03-17 18:32:32 +08:00
shuiping233
f5ba1a026a perf: Implement Pydantic data models for the KOOK adapter to enhance data retrieval and message schema validation (#5719)
* refactor: 给kook适配器添加kook事件数据类

* format: 使用StrEnum替换kook适配器中的(str,enum)
2026-03-17 18:05:58 +08:00
jnMetaCode
dcffb5269a fix: only pass dimensions when explicitly configured in embedding config (#6432)
* fix: only pass dimensions param when explicitly configured

Models like bge-m3 don't support the dimensions parameter in the
embedding API, causing HTTP 400 errors. Previously dimensions was
always sent with a default value of 1024, even when the user never
configured it. Now dimensions is only included in the request when
embedding_dimensions is explicitly set in provider config.

Closes #6421

Signed-off-by: JiangNan <1394485448@qq.com>

* fix: handle invalid dimensions config and align get_dim return

- Add try-except around int() conversion in _embedding_kwargs to
  gracefully handle invalid embedding_dimensions config values
- Update get_dim() to return 0 when embedding_dimensions is not
  explicitly configured, so callers know dimensions weren't specified
  and can handle it accordingly
- Both methods now share consistent logic for reading the config

Signed-off-by: JiangNan <1394485448@qq.com>

* fix: improve logging for invalid embedding_dimensions configuration

---------

Signed-off-by: JiangNan <1394485448@qq.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-17 17:53:03 +08:00
LIghtJUNction
4b7d42c2a3 chore: ruff format 2026-03-17 16:53:45 +08:00
LIghtJUNction
f6321be8c8 sync 2026-03-17 16:51:45 +08:00
whatevertogo
ebd232ec8e fix: register_agent decorator NameError (#5765)
* fix: 修改 register_agent 以避免运行时导入 AstrAgentContext

* test: improve register_agent test robustness

- Add fixture for llm_tools cleanup to avoid test interference
- Use multiple import patterns to make guard more robust to refactors
- Add assertion to verify decorated coroutine is wired as handoff handler

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* 删除测试文件: 移除 register_agent 装饰器的运行时行为测试

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-17 16:07:30 +08:00
whatevertogo
1fd3d4ce0e fix: subagent lookup failure when using default persona (#5672)
* fix: resolve subagent persona lookup for 'default' and unify resolution logic

- Add PersonaManager.get_persona_v3_by_id() to centralize v3 persona resolution
- Handle 'default' persona_id mapping to DEFAULT_PERSONALITY in subagent orchestrator
- Fix HandoffTool.default_description using agent_name parameter correctly
- Add tests for default persona in subagent config and tool deduplication

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: simplify get_default_persona_v3 using get_persona_v3_by_id

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-03-17 15:42:15 +08:00
linzhengtian
26d69c96d1 fix: reading skills on Windows (#6490)
There is an issue with reading the skill directory on the Windows system, which results in a high probability of files under the skill directory being unrecognizable, now fix it.
2026-03-17 15:12:02 +08:00
YYMa
3dcdb8b29c chore: remove deprecated version field from compose.yml (#5495)
The version field is no longer required in Docker Compose v2 and has been deprecated.
2026-03-17 14:20:35 +08:00
dependabot[bot]
437adead28 chore(deps): bump the github-actions group with 2 updates (#6461)
Bumps the github-actions group with 2 updates: [ncipollo/release-action](https://github.com/ncipollo/release-action) and [actions/github-script](https://github.com/actions/github-script).


Updates `ncipollo/release-action` from 1.20.0 to 1.21.0
- [Release notes](https://github.com/ncipollo/release-action/releases)
- [Commits](https://github.com/ncipollo/release-action/compare/v1.20.0...v1.21.0)

Updates `actions/github-script` from 7 to 8
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v8)

---
updated-dependencies:
- dependency-name: ncipollo/release-action
  dependency-version: 1.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/github-script
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  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-03-17 13:53:37 +08:00
Rhonin Wang
d5b98b353c fix: parse multiline frontmatter description in SKILL.md (#6460)
* fix(skills): support multiline frontmatter descriptions

* fix(skills): 修复多行 frontmatter 描述解析

* style(skills): clean up frontmatter parser follow-ups

---------

Co-authored-by: RhoninSeiei <RhoninSeiei@users.noreply.github.com>
2026-03-17 13:53:16 +08:00
Yufeng He
acbc5150cf fix: SQLite 'database is locked' by adding busy timeout (#6474)
The async engine is created without a busy timeout, so concurrent
writes (agent responses, metrics, session updates) fail instantly
with 'database is locked' instead of waiting for the lock.

Add connect_args={'timeout': 30} for SQLite engines so the driver
waits up to 30 seconds for the write lock. Combined with the existing
WAL journal mode, this handles the typical concurrent write bursts
from agent + metrics + session operations.

Fixes #6443
2026-03-17 12:56:34 +08:00
Ruochen Pan
85cfd62014 feat: localize session management group & interval method texts (#6471)
* fix(ui): localize session management group texts

Replace hardcoded Chinese strings in SessionManagementPage with i18n
lookups for group management labels, dialogs, and action feedback.

Add and align translation keys in en-US, ru-RU, and zh-CN for group
management and batch operation messages to ensure consistent multilingual
UI behavior.

* fix(ui): localize interval method hint text
2026-03-17 10:21:55 +08:00
LIghtJUNction
1c7c2ee0cd chore: Delete .github/workflows/pr-checklist-check.yml 2026-03-17 10:18:08 +08:00
Soulter
ed47420678 ci: add pr check 2026-03-17 01:07:22 +08:00
Soulter
6d687691a2 chore: bump version to 4.20.1 2026-03-17 00:35:57 +08:00
LIghtJUNction
6db0959bb1 feat(cli): implement uninstall command and add log-level option
- Implement 'astrbot uninstall' to remove systemd service and data files
- Add '--log-level' option to 'astrbot run' (default: INFO)
- Pass log level config to core logger via env var
2026-03-16 23:55:36 +08:00
Soulter
0c71d351ee chore: revise PULL_REQUEST_TEMPLATE 2026-03-16 22:20:48 +08:00
LIghtJUNction
f00ba5adc6 chore(github): 更新 PR 模板以区分 dev 和 master 提交规则 2026-03-16 21:43:14 +08:00
LIghtJUNction
a05bfed15d Merge pull request #6434 from a61995987/fix-修正shell工具未正确应用工具调用超时的问题
Fix 修正shell工具未正确应用工具调用超时的问题
2026-03-16 20:51:03 +08:00
LIghtJUNction
a027fb310c Update astrbot/core/computer/tools/shell.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-16 20:34:17 +08:00
LIghtJUNction
d3d4e1db7b Merge branch 'master' of https://github.com/AstrBotDevs/AstrBot 2026-03-16 19:17:42 +08:00
LIghtJUNction
78b3e12c66 chore: update astrbot.service configuration 2026-03-16 19:15:44 +08:00
Futureppo
c42ac87ee1 feat: Add OpenRouter chat completion provider adapter with custom headers. (#6436) 2026-03-16 19:11:43 +08:00
Chen
4b0d9ae979 Merge branch 'fix-修正shell工具未正确应用工具调用超时的问题' of https://github.com/a61995987/AstrBot into fix-修正shell工具未正确应用工具调用超时的问题 2026-03-16 18:11:12 +08:00
Chen
a1a3db2218 fix-修正shell工具未正确应用工具调用超时的问题 2026-03-16 18:10:23 +08:00
Chen
3e278dbd9e Merge branch 'AstrBotDevs:master' into fix-修正shell工具未正确应用工具调用超时的问题 2026-03-16 18:02:15 +08:00
LIghtJUNction
7733ccc54a Merge pull request #6429 from xkeyC/feat/persona_clone
feat: add clone persona functionality
2026-03-16 17:23:01 +08:00
LIghtJUNction
9c7c0ec95a Merge pull request #6404 from rin259/feat/onebot-file-send
feat: add OneBot V11 file API support for sending files
2026-03-16 17:08:39 +08:00
LIghtJUNction
2685528cbd Merge pull request #6397 from AstrBotDevs/master
sync master-﹥dev
2026-03-16 17:03:40 +08:00
LIghtJUNction
3f24f82486 Merge branch 'master' into dev 2026-03-16 17:02:15 +08:00
xkeyC
38f21675d5 feat: 支持克隆人格 2026-03-16 16:52:01 +08:00
QuietStars
3fbd16b211 docs: update rainyun.md with backup access instructions (#6427)
Added a note about using a backup address if the management panel cannot be accessed.
2026-03-16 15:38:01 +08:00
qingyun
e77500ff69 fix(provider): sync providers_config after creating new provider (#6388)
Fixes #6283

When adding a new embedding provider, the knowledge base creation page
did not show the new provider until restart.

Root cause: create_provider() did not update self.providers_config,
which is used by get_provider_config_list() to return provider lists.

This fix syncs the in-memory config after loading the new provider,
consistent with how reload() handles config updates.

Co-authored-by: ccsang <ccsang@users.noreply.github.com>
2026-03-16 15:29:51 +08:00
lppsuixn
2c49ac0dcf Refactor _extract_session_id for chat type handling (#5775)
Update session ID extraction to handle group and single chat types.
2026-03-16 15:27:16 +08:00
LIghtJUNction
c0e07971b3 Merge pull request #6391 from ccsang/fix/tool-result-multiple-content
fix(agent): process all content items in CallToolResult, not just the first
2026-03-16 15:21:17 +08:00
Rin
7cce05c459 fix: remove accidentally added commit message from code 2026-03-16 14:37:52 +08:00
rin
0a16df2837 fix: add missing logger import 2026-03-16 14:35:34 +08:00
LIghtJUNction
e2365a53b9 Update README_zh.md 2026-03-16 13:34:36 +08:00
LIghtJUNction
7dc142ddf2 docs: synchronize multi-language READMEs with README_zh.md 2026-03-16 13:33:29 +08:00
Soulter
65decfbe87 chore: remove unused scripts for closing duplicate plugin publish issues and generating changelog 2026-03-16 12:39:39 +08:00
stevessr
92c31192de perf: enhance umo processing compatibility (#5996) 2026-03-16 12:34:21 +08:00
Soulter
414f98fb5e perf: onebot, satori docs improvement 2026-03-16 11:41:25 +08:00
ccsang
8e6c835b85 refactor(agent): extract image-handling logic into helper function
Address Sourcery AI review feedback: the image-handling logic was
duplicated for ImageContent and EmbeddedResource cases.

Changes:
- Extract _handle_image_content() helper function
- Consolidate image caching, result appending, and yielding logic
- Reduce code duplication and improve maintainability
2026-03-16 00:17:33 +00:00
ccsang
fb2a2a63f2 fix(agent): process all content items in CallToolResult, not just the first
Fixes #6140

When a tool returns CallToolResult with multiple content items (e.g.,
both TextContent and ImageContent), the agent was only processing
content[0], ignoring the rest.

Changes:
- Replace direct content[0] access with enumerate(res.content) loop
- Process all content items: TextContent, ImageContent, EmbeddedResource
- Use content_index for image caching to distinguish multiple images

This fixes the issue where tools like Bilibili plugin return both
text descriptions and screenshots, but LLM only received one of them.
2026-03-16 00:17:33 +00:00
LIghtJUNction
b795f804a7 更新 pr-checklist-check.yml 2026-03-16 02:51:39 +08:00
LIghtJUNction
bc3b5e58a4 更新 pr-checklist-check.yml 2026-03-16 02:44:05 +08:00
LIghtJUNction
7e3c32b828 更新 pr-checklist-check.yml 2026-03-16 02:29:33 +08:00
LIghtJUNction
ceb32dce9f 更新 pr-checklist-check.yml 2026-03-16 02:24:01 +08:00
LIghtJUNction
84e880af5f 更新 pr-checklist-check.yml 2026-03-16 02:21:05 +08:00
LIghtJUNction
9909d774ed Merge pull request #6400 from AstrBotDevs/copilot/implement-modifications-summary
feat: auto-close PRs when author checks "did not read" checklist item
2026-03-16 02:13:20 +08:00
LIghtJUNction
6b3868b4be Update pr-checklist-check.yml 2026-03-16 02:11:15 +08:00
LIghtJUNction
11c840953a 更新 pr-checklist-check.yml 2026-03-16 01:49:49 +08:00
LIghtJUNction
2bbca887ce Refine PR checklist validation and closure message
Updated the checklist validation script and modified the comment for PR closure.
2026-03-16 01:46:07 +08:00
copilot-swe-agent[bot]
dd89a4b334 feat: add PR checklist enforcement workflow
Co-authored-by: LIghtJUNction <106986785+LIghtJUNction@users.noreply.github.com>
2026-03-15 17:30:29 +00:00
copilot-swe-agent[bot]
a3fa8a5a7c Initial plan 2026-03-15 17:28:39 +00:00
LIghtJUNction
aa60467782 Merge pull request #6399 from AstrBotDevs/LIghtJUNction-patch-1
Refactor checklist items in PR template
2026-03-16 01:24:30 +08:00
LIghtJUNction
d936bb0a10 Refactor checklist items in PR template
Duplicated checklist items in the pull request template for clarity and emphasis.
2026-03-16 01:23:51 +08:00
LIghtJUNction
3f863cce7f Merge pull request #6389 from AstrBotDevs/copilot/create-daily-build-workflow
feat: daily workflow to build dashboard with Bun and deploy to GitHub Pages
2026-03-15 23:45:13 +08:00
copilot-swe-agent[bot]
c42bd3150d feat: add daily workflow to build dashboard with bun and deploy to GitHub Pages
Co-authored-by: LIghtJUNction <106986785+LIghtJUNction@users.noreply.github.com>
2026-03-15 15:39:48 +00:00
copilot-swe-agent[bot]
4c22abd99c Initial plan 2026-03-15 15:37:59 +00:00
LIghtJUNction
f08147dc38 更新 smoke_test.yml 2026-03-15 23:36:25 +08:00
LIghtJUNction
11d40ac0c3 更新 smoke_test.yml 2026-03-15 23:35:21 +08:00
Stable Genius
64e0183b55 fix: drop Groq reasoning_content from assistant history (#6065)
Co-authored-by: Stable Genius <259448942+stablegenius49@users.noreply.github.com>
2026-03-15 22:51:52 +08:00
Soulter
420d82df11 chore: ruff format 2026-03-15 22:43:29 +08:00
Yufeng He
d87cf897da Fix TypeError when API returns null choices (#6313)
* Fix CreateSkillPayloadTool array schema missing items field

The payload parameter's anyOf array variant lacked an items field,
causing Gemini API to reject the tool declaration with 400 Bad Request:
'parameters.properties[payload].any_of[1].items: missing field.'

Add items: {type: object} to the array variant to satisfy the Gemini
API requirement for array type schemas.

Fixes #6279

* Fix TypeError when OpenAI-compatible API returns null choices

Some providers (e.g. OpenRouter) may return a completion where
choices is None rather than an empty list — for instance on rate
limiting, content filtering, or transient errors. The existing code
used len(completion.choices) which throws TypeError on None.

Replace all len(...choices) == 0 checks with 'not ... .choices' which
handles both None and empty list. Affects _query_stream, _parse_openai_completion,
and _extract_reasoning_content.

Fixes #6252
2026-03-15 22:28:26 +08:00
時壹
2f51916a73 fix: deduplicate repeated QQ webhook retry callbacks (#6320) 2026-03-15 22:18:37 +08:00
Rin
b0e10cf479 fix: add null check for delta in streaming mode to prevent AttributeError when tool calls are returned (#6365) 2026-03-15 22:17:12 +08:00
Simon
20efaa5320 fix: revise link to model service configuration (#6296) 2026-03-15 22:03:52 +08:00
洛薇Lovie
3ccd70cd4e Fix: AI fails to send media files when tool-calling mode is set to "skills-like". (#6317)
* fix: improve send_message_to_user tool description for skills_like mode

* fix: enhance description for send_message_to_user tool to clarify usage

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-15 21:46:01 +08:00
xwsjjctz
da520e573a feat(provider): add MiniMax (#6318)
* feat(provider): add MiniMax

* feat(provider): reintroduce MiniMax provider configuration and remove deprecated source

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-15 21:37:44 +08:00
Trainingcqy
6d055e81e9 fix: GIF sent as static image in Telegram adapter (#6329)
* fix(telegram): route GIF files to send_animation instead of send_photo

* fix: narrow exception in _is_gif to OSError

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* refactor: simplify image send dispatch in send_with_client

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* refactor: simplify image dispatch in _process_chain_items

* ruff format

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-15 21:33:30 +08:00
Xial
d41ccb70c5 fix: replace npm registry URLs with jsdelivr CDN for provider icons (#6340) 2026-03-15 21:15:04 +08:00
qingyun
18a99a25c2 fix(platform): parse QQ official face messages to readable text (#6355)
Fixes #6294

QQ official bot receives emoji/sticker messages as raw XML-like tags:
`<faceType=4,faceId="",ext="eyJ0ZXh0IjoiW+a7oeWktOmXruWPt10ifQ==">`

This made the LLM unable to understand the emoji content.

Changes:
- Added `_parse_face_message()` method to parse face message format
- Decode base64 `ext` field to get emoji description text
- Replace face tags with `[表情:描述]` format for readability

Example:
- Input: `<faceType=4,faceId="",ext="eyJ0ZXh0IjoiW+a7oeWktOmXruWPt10ifQ==">`
- Output: `[表情:[满头问号]]`

Co-authored-by: ccsang <ccsang@users.noreply.github.com>
2026-03-15 21:05:47 +08:00
LIghtJUNction
04aee2890a feat: implement dashboard download caching and fallback mechanism
- Add local file caching for dashboard downloads with version validation
- Implement fallback to 'latest' version if specific version download fails
- Add robust error handling in CLI check_dashboard to prevent crashes
- Remove dashboard caching from smoke tests (backend-only mode)
2026-03-15 19:14:13 +08:00
LIghtJUNction
c18165909e 修复: 尝试下载当前版本的dashboard,如果下载失败(开发版本),回退为下载最新版本 2026-03-15 18:18:23 +08:00
LIghtJUNction
0b534f65c2 fix(dashboard): use absolute path for bundled dist and handle 404s gracefully 2026-03-15 18:05:15 +08:00
LIghtJUNction
c9910d4a66 fix(dashboard): add early check for missing index.html to prevent 404s 2026-03-15 18:01:55 +08:00
LIghtJUNction
342b378de1 Updated READMEs 2026-03-15 17:45:12 +08:00
LIghtJUNction
7579db11be chore: bump version to 4.21.0 and refactor version retrieval 2026-03-15 17:08:31 +08:00
LIghtJUNction
b5a40a66fa sync/pnpm-lock.yaml 2026-03-15 16:51:42 +08:00
LIghtJUNction
282ff8d414 fix(dashboard): improve visibility of inline code in announcements
- Update CSS for inline code elements in the welcome announcement section
- Ensure proper contrast and emphasis in both light and dark modes
- Fix issue where code blocks appeared as white boxes in dark mode
2026-03-15 16:47:53 +08:00
LIghtJUNction
f3cdb7c006 fix(dashboard): restore original header logo layout
- Replaced Logo component with original inline text implementation in VerticalHeader
- Added missing isChristmas computed property
- Removed v-spacer centering for logo to match master branch layout
- This fixes the display issue where the logo/title appeared incorrect or misaligned
2026-03-15 16:35:58 +08:00
LIghtJUNction
c3afc3d72b fix(dashboard): resolve header layout issues and restore sidebar toggle
- Replace constrained v-container with full-width div in app bar
- Add 'app' prop to v-app-bar to fix layout flow
- Restore missing sidebar toggle buttons for desktop/mobile
- Clean up unused dev dependencies in package.json
2026-03-15 16:28:26 +08:00
LIghtJUNction
0c74bd1aeb fix: restore missing _poll_webchat_stream_result function 2026-03-15 15:58:47 +08:00
LIghtJUNction
070f281dae Resolve merge conflict in StandaloneChat.vue 2026-03-15 15:45:04 +08:00
LIghtJUNction
28a0f372fc Update vite version to match lockfile 2026-03-15 15:43:17 +08:00
邹永赫
d7457f38d4 fix: handle webchat image outputs without streaming 2026-03-15 16:15:43 +09:00
LIghtJUNction
96cafe001d Merge pull request #6293 from AstrBotDevs/LIghtJUNction-patch-1
Update package.md
2026-03-15 03:15:10 +08:00
LIghtJUNction
29d100dd83 Update package.md 2026-03-15 02:55:34 +08:00
Soulter
14f3701c4a fix: update Discord invite link in community documentation
closes: #6188
2026-03-14 23:48:13 +08:00
Stable Genius
1044fc48ca fix: avoid webchat stream result crash on queue errors (#6123)
Co-authored-by: stablegenius49 <185121704+stablegenius49@users.noreply.github.com>
2026-03-14 23:41:28 +08:00
Soulter
693c2ca818 refactor: improve chat component behavior, use shiki to represent code block (#6286) 2026-03-14 23:37:17 +08:00
LIghtJUNction
da1565ee81 Merge pull request #6282 from advent259141/agent-fix-clean
Agent fix clean
2026-03-14 23:32:16 +08:00
Gao Jinzhe
7d3401fec0 Merge branch 'dev' into agent-fix-clean 2026-03-14 23:17:10 +08:00
LIghtJUNction
fca691b3ca Merge pull request #6276 from AstrBotDevs/feat/optional-backend
Feat/optional backend
2026-03-14 21:40:06 +08:00
LIghtJUNction
ca8f356812 Resolve conflicts in dashboard files 2026-03-14 21:36:35 +08:00
Soulter
b1c486ba98 feat: add send shortcut configuration and localization support for chat input (#6272) 2026-03-14 21:25:12 +08:00
Soulter
9363fb824a chore: ruff format 2026-03-14 21:12:00 +08:00
Flartiny
044b361ac5 feat: add conversation batch deletion for webchat (#6160)
* feat: add conversation batch deletion for webchat

* fix: security issues in batch_delete_sessions and better handle batch select

* feat: enhance batch selection UI with animated checkbox visibility in ConversationSidebar

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-14 21:09:36 +08:00
Frank
06fd2d2428 fix: preserve subagent handoff tools during plugin filtering (#6155) 2026-03-14 20:55:15 +08:00
eason
dd6bc1dcdb fix: add missing spaces in cron prompt and replace deprecated utcnow() (#6192)
1. Fix missing spaces in cron job wake prompt string concatenation.
   Python implicit string concatenation produced:
   "...scheduled taskProceed..." and "...conversation.After..."
   which sent garbled instructions to the LLM agent, causing unreliable
   cron job execution.

2. Replace deprecated datetime.utcnow() with
   datetime.now(datetime.timezone.utc) in JWT generation.
   utcnow() is deprecated since Python 3.12 and returns naive datetime
   which can cause incorrect token expiry on non-UTC systems.

Closes #6103
Closes #6165

Co-authored-by: easonysliu <easonysliu@tencent.com>
2026-03-14 20:52:00 +08:00
Rhonin Wang
52d5258b10 feat: display latency when testing model connection (#6258)
Co-authored-by: RhoninSeiei <RhoninSeiei@users.noreply.github.com>
2026-03-14 20:50:40 +08:00
Anima
91933bbd19 perf: webui theme color improvement (#6263)
* fix: update scrollbar styles to follow theme variables

* fix: update theme colors to use CSS variables for consistency

* fix: change login button color to primary for better visibility

* fix: update theme colors for Dark and Light themes; change login button color to secondary

* fix: update border and theme colors for consistency in DarkTheme

* fix: update sidebar list class to conditionally hide scrollbar in mini sidebar mode

* fix: simplify button visibility logic and remove unnecessary leftPadding style

* fix: refactor language switcher to use grouped menu for better UX

* fix: update theme colors to use primary color for consistency across components

* fix: add preview text for template output in multiple languages
2026-03-14 20:45:55 +08:00
Sakari
f8d075b5d3 fix(telegram): avoid treating normal replies as topic threads (#6174) 2026-03-14 18:27:13 +08:00
LIghtJUNction
a4a0a5bb1a Resolve conflicts 2026-03-14 18:24:48 +08:00
eason
86ef758a9a fix: prevent ValueError when removing already-removed API key in retry loop (#6193)
In _handle_api_error(), when a 429 rate-limit is encountered, the code
calls available_api_keys.remove(chosen_key). If the same key was already
removed in a previous retry iteration (e.g. the key rotated back to the
same value), this raises ValueError which crashes the entire LLM request
with an opaque error instead of a proper retry/fallback.

Add a membership check before calling remove() to prevent the crash.

Co-authored-by: easonysliu <easonysliu@tencent.com>
2026-03-14 18:22:14 +08:00
Ann-Holmes
1a03180643 Add binding for local temp directory in YAML (#6191)
* Add binding for local temp directory in YAML

Bind the local temp directory to the sandbox for file access.

* Update compose-with-shipyard.yml

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-03-14 18:21:47 +08:00
DroidKali
326183a3fd fix: update startup command to 'astrbot run' in all README files (#6189)
Updated the quick start command from 'astrbot' to 'astrbot run' across all
language versions of README documentation for consistency and correctness.

Co-authored-by: DroidKali <DroidKali@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-03-14 18:20:48 +08:00
qingyun
08fc657755 fix: preserve whitespace in Plain.toDict() for @ mentions (#6244)
* fix: preserve whitespace in Plain.toDict() for @ mentions

- Remove .strip() from Plain.toDict() to match async to_dict() behavior
- Fixes #6237: QQ @mentions no longer lose trailing spaces
- This ensures '@user message' displays correctly instead of '@usermessage'

* refactor: remove redundant to_dict() from Plain class

- Let Plain inherit to_dict() from BaseMessageComponent
- BaseMessageComponent.to_dict() calls toDict() by default
- Reduces code duplication and prevents future divergence
- Addressed code review feedback from @gemini-code-assist and @sourcery-ai

* feat: add async to_dict method to Plain message component

* fix: add return type hint to Plain.toDict method

---------

Co-authored-by: ccsang <ccsang@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-14 18:18:14 +08:00
Gao Jinzhe
0ff9539599 Merge pull request #6208 from nuomicici/master
更新(添加)部分文档中已过时的名词
2026-03-14 18:17:14 +08:00
lalala
38f5e077ee fix: remove duplicate dependencies (#6247)
remove duplicate `aiocqhttp` `aiodocker` `aiohttp` in requirements.txt
2026-03-14 18:15:06 +08:00
MousseC
89fbd75e7a perf(OneBot): add a whitespace after At component (#6238)
修复 At 组件后的空格在发送时被 strip 移除的问题。在消息解析时检测 At 组件并在其后额外插入空格。
2026-03-14 18:12:55 +08:00
Salman Chishti
493662524a ci: upgrade GitHub Actions to latest versions (#6251)
Signed-off-by: Salman Muin Kayser Chishti <13schishti@gmail.com>
2026-03-14 18:08:25 +08:00
糯米茨
1afbb357db Update docs/zh/platform/matrix.md
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-13 21:14:00 +08:00
糯米茨
8d2140f607 Update docs/zh/platform/wecom_ai_bot.md
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-13 21:13:45 +08:00
糯米茨
97732987d9 更新部分新版名称 2026-03-13 20:53:41 +08:00
糯米茨
a60a40bca3 更新部分新版本名称
Update the instructions for installing and configuring the Matrix adapter in AstrBot.
2026-03-13 20:51:39 +08:00
エイカク
a8ff2b3d9c fix(dashboard): stabilize sidebar hash navigation on startup (#6159)
* fix(dashboard): stabilize sidebar hash navigation on startup

* fix(dashboard): reuse shared extension tab route helpers

* fix(dashboard): avoid leaking extension route query state

* fix(dashboard): preserve route params in tab locations

* fix(dashboard): harden hash tab routing fallbacks

* fix(dashboard): warn on tab route navigation failures

* fix(dashboard): harden extension tab startup routing
2026-03-13 11:53:50 +09:00
advent259141
3a8bfa0873 style: ruff format on merge-touched files 2026-03-13 09:20:08 +08:00
advent259141
c07fba7add merge: resolve conflicts with origin/master
- .gitignore: keep both .serena and .worktrees/ entries
- astr_main_agent_resources.py: keep deletion (refactored to tools/)
- send_message.py: port video message type support from master
2026-03-13 09:17:31 +08:00
zenfun
855483c8c2 style: fix ruff I001/F401 violations in changed files 2026-03-13 01:18:39 +08:00
zenfun
048c511b18 fix: align browser property with base class and remove dead env writes
- shipyard_neo: browser property now returns None when not initialized
  instead of raising RuntimeError, matching ComputerBooter base contract
- computer_tool_provider: remove dead os.environ writes for shipyard
  (SHIPYARD_ENDPOINT / SHIPYARD_ACCESS_TOKEN are never read anywhere)
  and remove unused os import
2026-03-13 01:14:23 +08:00
zenfun
dfc0c34d95 fix: address review issues in tool injection refactor
- Rewrite TestApplySandboxToolsRefactored to test ComputerToolProvider
  directly (_apply_sandbox_tools was removed; old tests permanently skipped)
- Add TestExecutorCapabilityGuard with 5 strict tests for browser
  capability rejection at executor level
- Fix typo: "on hehalf you" -> "on behalf of you" in subagent result
- Remove extra blank lines (ruff E303) after _apply_sandbox_tools comment
- Remove dead _build_sync_and_scan_command (no callers after refactor)
2026-03-13 01:11:50 +08:00
Soulter
a21bb5b234 chore: bump version to 4.20.0 2026-03-13 00:33:36 +08:00
Soulter
994d39241e chore: ruff format 2026-03-13 00:26:40 +08:00
2ndelement
e6c1164755 perf(QQ Official API): improve streaming message delivery reliability and proactive media sending (#6131)
* fix(qqofficial): fix streaming message delivery for C2C

* fix(qqofficial): rewrite send_streaming for C2C vs non-C2C split

* fix(qqofficial): add _extract_response_message_id for safe id extraction

* fix(qqofficial): flush stream segment on tool-call break signal

* fix(qqofficial): downgrade rich-media to non-stream send in C2C

* fix(qqofficial): auto-append \n to final stream chunk (state=10)

* fix(qqofficial): propagate stream param to all _send_with_markdown_fallback call sites

* fix(qqofficial): retry on STREAM_MARKDOWN_NEWLINE_ERROR with newline fix

* fix(qqofficial): handle None/non-dict response in post_c2c_message gracefully

* fix(qqofficial): remove msg_id from video/file media payloads in send_by_session

QQ API rejects msg_id on proactive media (video/file, msg_type=7) messages
sent via the tool-call path, returning "请求参数msg_id无效或越权". The
msg_id passive-reply credential is consumed by the first send and cannot be
reused for subsequent media uploads in the same session.

Remove msg_id from the payload after setting msg_type=7 for video and file
sends, for both FRIEND_MESSAGE (C2C) and GROUP_MESSAGE paths.

* fix(qqofficial): replace deprecated get_event_loop() with get_running_loop()

asyncio.get_event_loop() is deprecated since Python 3.10 and raises a
DeprecationWarning (or errors) when called from inside a running coroutine
without a current event loop set on the thread.  Replace both call-sites
in the streaming throttle logic with asyncio.get_running_loop(), which is
the correct API to use inside an already-running async context.

Co-Authored-By: Claude Sonnet <noreply@anthropic.com>

---------

Co-authored-by: 2ndelement <2ndelement@users.noreply.github.com>
Co-authored-by: Claude Sonnet <noreply@anthropic.com>
2026-03-13 00:24:15 +08:00
Aleksandr
89cc8a1a65 feat: add Russian translation (#6081)
* feat: add Russian translation

* revert: remove auth route changes from PR
2026-03-13 00:08:37 +08:00
Stable Genius
c0e4f1e114 fix(dashboard): restore README dialog anchor navigation (#6083)
Co-authored-by: stablegenius49 <185121704+stablegenius49@users.noreply.github.com>
2026-03-13 00:02:45 +08:00
Stable Genius
7b43448ce4 fix: prefer named weekday cron examples (#6091)
Co-authored-by: stablegenius49 <185121704+stablegenius49@users.noreply.github.com>
2026-03-12 23:57:45 +08:00
orbisai0security
bdac0b65f4 fix: resolve critical vulnerability V-004 (#6093)
Automatically generated security fix

Co-authored-by: orbisai0security <orbisai0security@users.noreply.github.com>
2026-03-12 23:53:47 +08:00
Gao Jinzhe
cf9ee6f20c Merge pull request #6135 from advent259141/feat/add-community-links
docs: 添加 Astrbook 和玖帕喵社区链接
2026-03-12 23:11:19 +08:00
advent259141
01eae72a64 docs: 添加 Astrbook 和玖帕喵社区链接 2026-03-12 23:05:00 +08:00
letr
bca1476eab fix(extension): refresh plugin market install state after install (#6124)
* fix(extension): refresh market install state after plugin install

* chore: remove redundant call

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-12 20:19:00 +08:00
エイカク
fbcbde0a4b chore: update dependency and workflow versions (#6119) 2026-03-12 20:18:23 +09:00
エイカク
3914d766db fix: install only missing plugin dependencies (#6088)
* chore: ignore local worktrees

* fix: install only missing plugin dependencies

* fix: harden missing dependency install fallback

* fix: clarify dependency install fallback logging

* refactor: simplify dependency install test helpers

* refactor: reuse requirements precheck planning
2026-03-12 11:50:29 +09:00
Chen
b1a119edb4 ruff 2026-03-12 03:44:36 +08:00
Chen
3dc4bb8e34 将shell调用时的timeout转为int 获取系统配置时正确传递umo 2026-03-12 03:42:33 +08:00
Chen
f5e7ca12f7 feat: 增加 shell 工具自定义超时配置 2026-03-12 03:26:18 +08:00
zenfun
7c3cc7b90c refactor: add capabilities to sandbox tool binding logs 2026-03-12 02:58:48 +08:00
zenfun
a5a1ba72fd refactor: add get_sandbox_capabilities API and structured logging to computer_client 2026-03-12 02:58:15 +08:00
zenfun
e1d76117b4 refactor: standardize booter structured logging format 2026-03-12 02:57:04 +08:00
zenfun
ad3911a21f refactor: add debug logging to sandbox tool resolution 2026-03-12 02:56:59 +08:00
zenfun
3440dcd14b test: add booter decoupling and profile-aware tool tests 2026-03-12 02:55:09 +08:00
zenfun
e85eef05b8 fix: stabilize tool injection for LLM prefix cache hits
Two changes to make the tool schema sent to the LLM deterministic:
1. ToolSet.normalize() — sort tools by name before serialization.
   Called at the end of build_main_agent() after all injection passes.
   Eliminates ordering drift from plugin load order, MCP reconnection,
   and persona tool list differences.
2. Always inject full sandbox tool set — ComputerToolProvider now
   returns get_default_sandbox_tools() unconditionally, regardless of
   sandbox boot state. Browser tools are always in the schema even if
   the sandbox profile lacks browser capability. The executor rejects
   calls to unavailable browser tools with a descriptive error instead
   of silently omitting them from the schema.
   This eliminates the pre-boot/post-boot tool set jump that caused
   prefix cache misses on the second request of a conversation.
2026-03-12 02:43:19 +08:00
zenfun
f16edd4fff refactor: delegate tool injection to booter self-description API
- Add get_default_tools/get_tools/get_system_prompt_parts to ComputerBooter base
- Each booter subclass (ShipyardNeo, Shipyard, Boxlite) declares its own tools
- ComputerToolProvider now delegates to booter API via computer_client helpers
- Add unified query API: get_sandbox_tools, get_default_sandbox_tools, etc.
- Extract Neo prompts to dedicated computer/prompts.py module
- Add booter type constants (booters/constants.py)
- Fix subagent tool path to pass sandbox_cfg and session_id
- Fix Sourcery issues: shell injection in send_message, typo in prompts,
  internal tools bypass inactivated_llm_tools check
2026-03-12 02:43:19 +08:00
DOHEX
3e2cb6a2ab fix(telegram): remove deprecated normalize_whitespace param from (#6044)
telegramify_markdown.markdownify calls
2026-03-12 00:34:07 +08:00
莫思潋
25830524f3 fix(docs): typo in docker.md & napcat.md (#6048)
* Fix wording in admin ID configuration instructions

* Update docker.md
2026-03-12 00:30:31 +08:00
Soulter
304094630c perf: optimize booter selection for edge cases and message sending tool (#6064)
* feat: add video message support and enhance message type descriptions in SendMessageToUserTool

* feat: add error handling for disabled sandbox runtime in get_booter function
2026-03-12 00:29:52 +08:00
Soulter
5c3643c54c feat: added support for file, voice, and video messages for QQ Official Bot (including WebSocket mode). (#6063) 2026-03-12 00:26:08 +08:00
エイカク
589cce18af fix: improve Windows local skill file reading (#6028)
* chore: ignore local worktrees

* fix: improve Windows local skill file reading

* fix: address Windows path and decoding review feedback

* fix: simplify shell decoding follow-up

* fix: harden sandbox skill prompt metadata

* fix: preserve safe sandbox skill summaries

* fix: relax sandbox summary sanitization

* fix: tighten path sanitization for skill prompts

* fix: harden sandbox skill display metadata

* fix: preserve Unicode skill paths in prompts

* fix: quote Windows skill prompt paths

* fix: simplify local shell output decoding

* fix: localize Windows prompt path handling

* fix: normalize Windows-style skill paths in prompts

* fix: align prompt and shell decoding behavior
2026-03-11 23:58:28 +09:00
Soulter
e254caf82d fix(docs): add official developer group ID to multiple language READMEs and enhance regex description in config metadata 2026-03-11 21:26:11 +08:00
advent259141
438fc105cd feat: 增加在工具注入前对工具是否启用的检查 2026-03-11 20:37:41 +08:00
Soulter
7efcd242d6 fix(docs): update edit link patterns and remove obsolete repository reference 2026-03-11 17:42:42 +08:00
JIANG Zijun
5d811d3949 fix: Persist Discord pre-ack emoji config across restart by adding missing default key (#6031)
* Initial plan

* fix: add discord default platform_specific pre-ack config

Co-authored-by: Jzjerry <20167827+Jzjerry@users.noreply.github.com>

* Delete tests/unit/test_config.py

we don't need to add tests

* fix: use 🤔 as default discord pre-ack emoji

Co-authored-by: Jzjerry <20167827+Jzjerry@users.noreply.github.com>

* add back old test config

* doc: discord pre-ack-emoji doc

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Jzjerry <20167827+Jzjerry@users.noreply.github.com>
2026-03-11 16:41:08 +08:00
Flartiny
8e6aaee10c fix(webui): unify search input clear behavior (#6017)
* fix(webui): unify search input clear behavior

* fix: centralize search input normalization
2026-03-11 15:14:16 +08:00
エイカク
6da59cfb07 fix: 插件依赖自动安装逻辑与 Dashboard 安装体验优化 (#5954)
* fix: install plugin requirements before first load

* fix: handle pip option arguments correctly

* fix: harden pip install input parsing

* refactor: simplify pip install input parsing

* fix: align plugin dependency install handling

* fix: respect configured pip index overrides

* test: parameterize plugin dependency install flows

* refactor: simplify multiline pip input parsing

* fix: install plugin dependencies before loading

* fix: protect core dependencies from downgrades and simplify package input splitting

* fix: enhance dependency conflict reporting and improve user-facing warnings

* refactor: preserve pip log indentation and fix CodeQL URL sanitization alert

* fix: explicit re-export for DependencyConflictError to satisfy ruff F401

* test: enhance index override verification in pip installer tests

* fix: correctly map pip ERROR and WARNING outputs to proper log levels

* refactor: show specific version conflicts in DependencyConflictError and revert log level mapping

* refactor: simplify install() by decoupling pip logging, failure classification and constraint file management

* refactor: further simplify pip installer and requirement parsing logic

* refactor: simplify dependency installation logic and improve circular requirement reporting

* style: organize imports in astrbot/core/__init__.py

* refactor: optimize requirement parsing efficiency and flatten pip installer API

* style: fix import sorting in astrbot/core/__init__.py

* refactor: consolidate requirement parsing, optimize core protection, and improve exception propagation

* fix: preserve valid pip requirement parsing

* fix: skip empty pip installs and preserve blank output

* chore: normalize gitignore entry style

* fix: tighten pip trust and requirement parsing

* refactor: centralize pip install parsing and failure handling

* fix: redact pip argv credentials in logs

* fix: surface plugin dependency install errors

* fix: cache core constraints and clarify requirement installs

* fix: harden pip requirement parsing for plugin installs

* fix: simplify pip installer parsing internals

* fix: tighten pip installer parsing and redaction

* refactor: simplify plugin dependency install flow

* fix: preserve core constraint conflict errors

* fix: harden pip installer fallback resolution

* refactor: split pip requirement and constraint helpers

* refactor: simplify pip installer helper flow

* refactor: streamline requirement precheck helpers

* refactor: clarify core constraint resolution

* fix: surface pip install failures explicitly

* refactor: separate pip conflict context parsing

* fix: harden core constraint resolution

* test: cover pip installer failure call sites

* refactor: remove dead requirements fallback helper

* refactor: narrow core constraint error handling

* refactor: unify requirement iteration

* refactor: share requirement name parsing

* test: align pip helper coverage

* fix: bind pip output limit at runtime

* refactor: reuse core requirement parser for tokens
2026-03-11 14:21:55 +09:00
advent259141
eae87e1ec9 Merge branch 'agent-fix-clean' of https://github.com/advent259141/AstrBot into agent-fix-clean 2026-03-11 10:42:30 +08:00
advent259141
894d72e657 feat: Introduce an internal agent sub-stage to the pipeline, enabling LLM agentic capabilities with configurable tools and context management. 2026-03-11 10:42:19 +08:00
Gao Jinzhe
42b8293f99 Merge branch 'AstrBotDevs:master' into agent-fix-clean 2026-03-11 09:48:36 +08:00
Soulter
10ceacfbb1 chore: bump version to 4.19.5 2026-03-11 00:17:14 +08:00
ChuwuYo
66f5ccd902 fix: add file size validation to TTS provider test and MiniMax empty audio detection (#5999)
- Add audio data validation in MiniMax TTS get_audio() method to detect empty responses
- Validate generated audio file size in TTSProvider.test() to ensure valid output
- Provide detailed error messages guiding users to check group_id configuration
- Auto-cleanup test audio files after validation
- Fixes issue where 0KB audio files would pass TTS detection when group_id is not configured
2026-03-11 00:07:19 +08:00
Soulter
3379587223 feat(mcp): enhance logging and initialize MCP clients in background (#5993)
* feat(mcp): enhance logging and initialize MCP clients in background

fixes: #5777

* rf

* fix(mcp): simplify MCP client initialization in background

* fix(mcp): update error message for MCP background initialization failure
2026-03-11 00:00:48 +08:00
邹永赫
e25a1a42cf Revert "fix: clarify missing MCP stdio command errors (#5992)"
This reverts commit 0c771e4a77.
2026-03-11 00:08:06 +09:00
advent259141
21f1fa82f4 feat: Implement API routes and dashboard UI for managing tools and MCP servers. 2026-03-10 22:22:18 +08:00
エイカク
0c771e4a77 fix: clarify missing MCP stdio command errors (#5992)
* fix: clarify missing MCP stdio command errors

* refactor: tighten MCP error presentation helpers

* fix: improve MCP test connection feedback

* fix: structure MCP test connection errors

* refactor: share MCP test error codes
2026-03-10 23:05:50 +09:00
advent259141
ff4412a627 refactor: Centralize and decouple computer-use tool injection logic into a new ComputerToolProvider and associated tool modules. 2026-03-10 22:00:23 +08:00
advent259141
bf430e659a feat: Introduce cron job management and refactor tool provisioning with dedicated providers for computer-use runtimes. 2026-03-10 21:05:09 +08:00
camera-2018
ec21cb13d3 feat(lark): supports CardKit streaming output for feishu (#5777)
* feat(lark): 支持飞书 CardKit 流式输出

* refactor(lark): extract streaming fallback logic and deduplicate final text update

* fix(lark): 修复流式输出竞态条件及增强健壮性

- 修复 sender loop 中 delta 快照竟态: await 期间 delta 被 generator
  更新导致 last_sent 记录了未发送的值, 造成输出卡在最后一段
- send_streaming 入口增加 platform_meta 守卫, 未启用时直接回退
- _fallback_send_streaming 移除对已耗尽 generator 的 super() 调用,
  改为内联父类副作用 (Metric.upload + _has_send_oper)
- Metric.upload 统一改为 await, 确保指标上报在方法返回前完成
- 装饰器 support_streaming_message 改为 False, 与 meta() 动态配置对齐
- i18n hint 补充提示: 需在「AI 配置 → 其他配置」中开启流式输出

* chore(lark): 收口配置

* docs(lark): update streaming output instructions and client version requirements

---------

Co-authored-by: bread-ovo <2570425204@qq.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-10 19:40:46 +08:00
Soulter
1d26b96d90 fix(workflow): update build-docs.yml to trigger on version tags instead of master branch 2026-03-10 17:16:56 +08:00
一袋米要扛幾樓
be017c87f4 fix: 前端修正切換到 chat 切換後回 welcome 的配置保存最終切換頁面 (#5792)
* 前端修正切換到chat切換後回 welcome 的配置保存最終切換頁面

* 修復 SSR 不含localStorage 環境驗證
2026-03-10 17:14:28 +08:00
lustresixx
23fffa95c8 fix(provider): support 84-char Azure TTS subscription keys (#5813)
* fix(provider): support 84-char Azure TTS subscription keys

* test(provider): add negative Azure TTS key validation cases

* chore: delete test

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-10 17:09:13 +08:00
dependabot[bot]
5b303e2e6d chore(deps): bump the github-actions group with 7 updates (#5966)
Bumps the github-actions group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [actions/setup-node](https://github.com/actions/setup-node) | `2` | `6` |
| [actions/checkout](https://github.com/actions/checkout) | `4` | `6` |
| [actions/setup-python](https://github.com/actions/setup-python) | `5` | `6` |
| [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) | `3` | `4` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3` | `4` |
| [docker/login-action](https://github.com/docker/login-action) | `3` | `4` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `6` | `7` |


Updates `actions/setup-node` from 2 to 6
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v2...v6)

Updates `actions/checkout` from 4 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

Updates `actions/setup-python` from 5 to 6
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

Updates `docker/setup-qemu-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

Updates `docker/setup-buildx-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

Updates `docker/login-action` from 3 to 4
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

Updates `docker/build-push-action` from 6 to 7
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  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-03-10 16:56:52 +08:00
Soulter
fc33b3eb68 docs: transfer AstrBotDevs/AstrBot-docs to AstrBotDevs/AstrBot (#5960)
* docs: transfer AstrBotDevs/AstrBot-docs to AstrBotDevs/AstrBot
* refactor: reorder imports and improve type hints in sync_docs_to_wiki.py and upload_doc_images_to_r2.py
* feat: add GitHub Actions workflow to sync wiki with documentation

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: anka-afk <110004162+anka-afk@users.noreply.github.com>
Co-authored-by: zouyonghe <62183434+zouyonghe@users.noreply.github.com>
Co-authored-by: shuiping233 <49360196+shuiping233@users.noreply.github.com>
Co-authored-by: LIghtJUNction <106986785+LIghtJUNction@users.noreply.github.com>
Co-authored-by: Sjshi763 <179909421+Sjshi763@users.noreply.github.com>
Co-authored-by: xiewoc <70128845+xiewoc@users.noreply.github.com>
Co-authored-by: QingFeng-awa <151742581+QingFeng-awa@users.noreply.github.com>
Co-authored-by: PaloMiku <96452465+PaloMiku@users.noreply.github.com>
Co-authored-by: shangxueink <138397030+shangxueink@users.noreply.github.com>
Co-authored-by: IGCrystal-A <244300990+IGCrystal-A@users.noreply.github.com>
Co-authored-by: RC-CHN <67079377+RC-CHN@users.noreply.github.com>
Co-authored-by: MC090610 <113341105+MC090610@users.noreply.github.com>
Co-authored-by: Waterwzy <196913419+Waterwzy@users.noreply.github.com>
Co-authored-by: Lanhuace-Wan <186303160+Lanhuace-Wan@users.noreply.github.com>
Co-authored-by: LiAlH4qwq <61769640+LiAlH4qwq@users.noreply.github.com>
Co-authored-by: HSOS6 <209910899+HSOS6@users.noreply.github.com>
Co-authored-by: th-dd <162813557+th-dd@users.noreply.github.com>
Co-authored-by: miaoxutao123 <81676466+miaoxutao123@users.noreply.github.com>
Co-authored-by: nuomicici <143102889+nuomicici@users.noreply.github.com>
Co-authored-by: nasyt233 <210103278+nasyt233@users.noreply.github.com>
Co-authored-by: jlugjb <7426462+jlugjb@users.noreply.github.com>
Co-authored-by: Raven95676 <176760093+Raven95676@users.noreply.github.com>
Co-authored-by: Futureppo <180109455+Futureppo@users.noreply.github.com>
Co-authored-by: MliKiowa <61873808+MliKiowa@users.noreply.github.com>
Co-authored-by: Fridemn <150212937+Fridemn@users.noreply.github.com>
Co-authored-by: BakaCookie520 <138355736+BakaCookie520@users.noreply.github.com>
Co-authored-by: YumeYuka <125112916+YumeYuka@users.noreply.github.com>
Co-authored-by: xming521 <32786500+xming521@users.noreply.github.com>
Co-authored-by: ywh555hhh <121592812+ywh555hhh@users.noreply.github.com>
Co-authored-by: stevessr <89645372+stevessr@users.noreply.github.com>
Co-authored-by: roeseth <41995115+roeseth@users.noreply.github.com>
Co-authored-by: ikun-1145141 <265925499+ikun-1145141@users.noreply.github.com>
Co-authored-by: evpeople <54983536+evpeople@users.noreply.github.com>
Co-authored-by: Yue-bin <60509781+Yue-bin@users.noreply.github.com>
Co-authored-by: W1ndys <109416673+W1ndys@users.noreply.github.com>
Co-authored-by: TheFurina <218887821+TheFurina@users.noreply.github.com>
Co-authored-by: Seayon <12275933+Seayon@users.noreply.github.com>
Co-authored-by: OnlyblackTea <38585636+OnlyblackTea@users.noreply.github.com>
Co-authored-by: ocetars <74854972+ocetars@users.noreply.github.com>
Co-authored-by: railgun19457 <117180744+railgun19457@users.noreply.github.com>
Co-authored-by: JunieXD <107397009+JunieXD@users.noreply.github.com>
Co-authored-by: advent259141 <197440256+advent259141@users.noreply.github.com>
Co-authored-by: Doge2077 <91442300+Doge2077@users.noreply.github.com>
Co-authored-by: Bocity <23430545+Bocity@users.noreply.github.com>
Co-authored-by: Aurora-xk <192227833+Aurora-xk@users.noreply.github.com>
2026-03-09 23:38:21 +08:00
ChuwuYo
795aec9578 feat(extension): add filtering and sorting for installed plugins in WebUI (#5923)
* feat(extension): add PluginSortControl reusable component for sorting

* i18n: add i18n keys for plugin sorting and filtering features

* feat(extension): add sorting and status filtering for installed plugins

Backend changes (plugin.py):
- Add _resolve_plugin_dir method to resolve plugin directory path
- Add _get_plugin_installed_at method to get installation time from file mtime
- Add installed_at field to plugin API response

Frontend changes (InstalledPluginsTab.vue):
- Import PluginSortControl component
- Add status filter toggle (all/enabled/disabled) using v-btn-toggle
- Integrate PluginSortControl for sorting options
- Add toolbar layout with actions and controls sections

Frontend changes (MarketPluginsTab.vue):
- Import PluginSortControl component
- Replace v-select + v-btn combination with unified PluginSortControl

Frontend changes (useExtensionPage.js):
- Add installedStatusFilter, installedSortBy, installedSortOrder refs
- Add installedSortItems and installedSortUsesOrder computed properties
- Add sortInstalledPlugins function with multi-criteria support
- Support sorting by install time, name, author, and update status
- Add status filtering in filteredPlugins computed property
- Disable default table sorting by setting sortable: false

* test: add tests for installed_at field in plugin API

- Assert all plugins have installed_at field in get_plugins response
- Assert installed_at is not null after plugin installation

* fix(extension): add explicit fallbacks for installed plugin sort comparisons

* i18n(extension): rename install time label to last modified

* fix(extension): cache installed_at parsing and validate timestamp format in tests

* test(dashboard): strengthen installed_at coverage for plugin API
2026-03-09 17:12:22 +09:00
Soulter
7d31140c14 chore: bump version to 4.19.4 2026-03-09 11:13:39 +08:00
Soulter
654112ca86 feat(wecomai): implement long connection mode and update configuration options (#5930) 2026-03-09 11:10:32 +08:00
Soulter
5dd30f9a45 chore: bump version to 4.19.3 2026-03-09 00:20:33 +08:00
Jason
a53a1ca49b fix(provider): handle MiniMax ThinkingBlock when max_tokens reached (#5913)
* fix(provider): handle MiniMax ThinkingBlock when max_tokens reached

Fixes #5912

Problem: MiniMax API returns ThinkingBlock when stop_reason='max_tokens',
but AstrBot throws 'completion 无法解析' exception because both
completion_text and tools_call_args are empty.

Root cause: The validation logic didn't consider ThinkingBlock
(reasoning_content) as valid content.

Fix: When completion_text and tools_call_args are empty but
reasoning_content is present, treat it as valid instead of throwing
exception. This happens when the model thinks but runs out of tokens
before generating the actual response.

Impact: MiniMax models now work correctly when responses are truncated
due to max_tokens limit.

* refactor: address review feedback

1. Use getattr for safe stop_reason access (prevent AttributeError)
2. Use ValueError instead of generic Exception for better error handling

Thanks @gemini-code-assist and @sourcery-ai for the review!

* refactor: flatten nested if/else with guard clause

Address Gemini Code Assist feedback:
- Use guard clause for early return
- Flattened nested conditional for better readability

Logic unchanged, just cleaner code structure.

* fix(provider): improve logging for ThinkingBlock completions in ProviderAnthropic

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-09 00:17:11 +08:00
whatevertogo
3fd6c4c8a6 fix: 修复 asyncio 事件循环相关问题 (#5774)
* fix: 修复 asyncio 事件循环相关的问题

1. components.py: 修复异常处理结构错误
   - 将 except Exception 移到正确的内部 try 块
   - 确保 _download_file() 异常能被正确捕获和记录

2. session_lock.py: 修复跨事件循环 Lock 绑定问题
   - 添加 _access_lock_loop_id 追踪事件循环
   - 当事件循环变化时重新创建 Lock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 根据代码审查反馈修复问题

1. components.py: 移除 asyncio.set_event_loop() 调用
   - 创建临时 event loop 时不再设置为全局
   - 避免干扰其他 asyncio 使用

2. session_lock.py: 简化延迟初始化逻辑
   - 移除 loop-ID 追踪和 _get_lock 方法
   - 使用 setdefault 简化 session lock 创建
   - 保留延迟初始化行为

3. wecomai_queue_mgr.py: 使用 time.monotonic() 替代 loop.time()
   - 同步方法不再依赖活动的 event loop
   - 避免在非异步上下文中抛出 RuntimeError

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 优化 asyncio 事件循环管理,使用安全的方式创建和关闭事件循环

* fix: 根据代码审查反馈改进异常处理和事件循环使用

- main.py: 显式处理 check_dashboard_files() 返回 None 的情况
- components.py: 使用 logger.exception 保留异常堆栈信息
- star_manager.py: 添加 Future 异常回调处理 __del__ 执行异常
- bay_manager.py: 缓存事件循环引用避免重复调用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 简化 SessionLockManager 使用 defaultdict 和 setdefault

- 使用 defaultdict(asyncio.Lock) 简化锁的懒创建
- 使用 setdefault 简化 _get_loop_state 逻辑
- 减少 get + if 分支,提升可读性

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 降低 webui_dir 检查失败时的日志级别为 warning

改为警告而非退出,允许程序在无 WebUI 的情况下继续运行

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 重构事件循环锁管理,简化锁状态管理逻辑

* 新增对 SessionLockManager 的多事件循环隔离测试

* fix: 修复测试中的变量声明和断言,确保事件循环管理器的正确性

* fix: 修复插件删除时异常处理逻辑,确保正确记录错误信息

* fix: 新增针对多个事件循环的 OneBot 实例的测试,确保锁对象在不同事件循环间不共享

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:00:13 +09:00
sanyekana
5808784f07 fix: prevent crash on malformed MCP server config (#5666) (#5673)
* fix: prevent crash on malformed MCP server config (#5666)

* fix: prevent crash on malformed MCP server config (#5666)

* fix: validate MCP connection before persisting server config

* fix: guard mcpServers type before iterating server list

* refactor: use typed empty-config error and extract MCP rollback helper

* fix: translate error messages and comments to English for consistency

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-08 23:46:32 +08:00
Soulter
537849c1e7 fix(dingtalk): text is ignored; cannot send file actively (#5921) 2026-03-08 23:31:11 +08:00
Soulter
7f3c0fdeb2 fix: cannot receive image, file in dingtalk (#5920)
fixes: #5916 #5786
2026-03-08 23:18:56 +08:00
Windy_cold
8e431e2076 correct openrouter api_base (#5911) 2026-03-08 21:53:56 +09:00
ChuwuYo
89c11fd683 fix(extension): support searching installed plugins by display name (#5806) (#5811)
* fix(extension): support searching installed plugins by display name

* fix: unify plugin search matching across installed and market tabs

* refactor(extension): optimize plugin search matcher and remove redundant checks

* refactor(extension-page): centralize search query normalization and text matching logic

- Extract `buildSearchQuery` to create normalized query objects from raw input
- Extract `matchesText` as a reusable text matching helper for normalized/loose/pinyin/initials matching
- Remove unused `marketCustomFilter` to eliminate dead code
- Simplify `matchesPluginSearch` to accept query object instead of pre-normalized string
- Replace Set with Array for candidates to simplify control flow
- Avoid redundant normalization by having callers pass raw strings to `buildSearchQuery`

* refactor: remove unused marketCustomFilter from extension page components

- Remove marketCustomFilter from destructuring in ExtensionPage.vue, InstalledPluginsTab.vue, and MarketPluginsTab.vue

* refactor(extension): extract plugin search utilities into shared module

- Create pluginSearch.js to centralize plugin search helpers
- Move `normalizeStr`, `normalizeLoose`, `toPinyinText`, and `toInitials` into the shared module
- Add `buildSearchQuery`, `matchesText`, and `matchesPluginSearch` for reusable search matching
- Refactor useExtensionPage.js to consume the shared utilities
- Simplify plugin search logic by consolidating normalization and matching in one place

* refactor(extension): add caching to pinyin utilities and extract search fields helper

- Add Map-based caching for `toPinyinText` and `toInitials` to avoid redundant pinyin computation
- Extract `getPluginSearchFields` function to retrieve plugin fields for searching
- Improve plugin search performance with caching and better code organization

* perf(extension): add bounded caching for plugin search

- cap normalization and pinyin caches with `MAX_SEARCH_CACHE_SIZE`
- add `setCacheValue()` for oldest-entry eviction
- cache normalized and loose text values to avoid repeated string processing
- skip pinyin matching for non-CJK text using Unicode `\p{Unified_Ideograph}` property
- improve search performance while keeping memory usage bounded

* refactor(extension): extract memoizeLRU helper for cache management

- Create `memoizeLRU` higher-order function to generate LRU-cached functions
- Replace manual cache implementation with `memoizeLRU` for cleaner code
- Optimize `matchesText` to lazily compute looseValue only when needed
- Simplify caching logic while maintaining bounded cache size

* refactor(extension): simplify memoization and remove LRU logic

- Rename `memoizeLRU` to `memoizeStringFn` and remove bounded cache size
- Simplify cache hit logic for cleaner code
- Remove `MAX_SEARCH_CACHE_SIZE` constant as it's no longer needed
2026-03-08 17:41:45 +09:00
時壹
7cfe2aca99 fix: apply reply_with_quote and reply_with_mention to image-only response (#5219)
* fix: apply reply_with_quote and reply_with_mention to image-only responses

* fix: restrict reply_with_quote and reply_with_mention to plain-text/image chains
2026-03-08 17:41:12 +09:00
時壹
3a938d2a13 fix: use re.search instead of re.match in RegexFilter (#5368) 2026-03-08 17:40:40 +09:00
whatevertogo
812834bc9f feat(skills): add batch upload functionality for multiple skill ZIP files (#5804)
* feat(skills): add batch upload functionality for multiple skill ZIP files

- Implemented a new endpoint for batch uploading skills.
- Enhanced the SkillsSection component to support multiple file selection and drag-and-drop functionality.
- Updated localization files for new upload features and messages.
- Added tests to validate batch upload behavior and error handling.

* feat(skills): improve batch upload handling and enhance accessibility for dropzone

* feat(skills): enhance batch upload process and improve UI for better user experience

* feat(skills): enhance skills upload dialog layout and styling for improved usability

* feat(skills): update upload dialog description styling for better visibility and usability

* feat(skills): improve upload dialog button styling and layout for enhanced usability

* feat(skills): refine upload dialog text for clarity and consistency

* feat(skills): enhance batch upload functionality by ignoring __MACOSX entries and improving upload dialog styling

* feat(skills): refactor upload dialog and button styles for improved consistency and usability

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
2026-03-07 23:18:01 +08:00
エイカク
51ff4f6e46 fix: detect desktop runtime without frozen python (#5859)
* fix: detect desktop runtime without frozen python

* chore: drop planning docs from runtime fix pr
2026-03-07 21:42:56 +09:00
Soulter
7ac169c5e8 docs: add macOS usage note and update instructions for astrbot in multiple README files 2026-03-06 14:34:29 +08:00
Soulter
61648ebe3e docs: add new QQ group entries to README files 2026-03-06 11:11:12 +08:00
Soulter
0610f0db0a fix: pipeline scheduler not found after creating platform bot via using 'create new config' (#5776) 2026-03-05 23:53:53 +08:00
whatevertogo
8c935981bb fix: align aiocqhttp poke payload with onebot v11 (#5773)
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
2026-03-05 23:02:26 +08:00
Ruochen Pan
3f3b4e4924 test(skill_manager): update sandbox cache path expectations (#5706)
* test(skill_manager): update sandbox cache path expectations

adjust sandbox cache tests to match absolute path resolution in
list_skills for sandbox runtime.

verify sandbox-cached skills cannot be deactivated via set_skill_active
by asserting a PermissionError, and keep active-only listing behavior
intact.

add coverage for show_sandbox_path=false to ensure local skills still
override cached metadata while sandbox-only skills retain cached paths.

* test(skill_manager): tighten local skill path assertions
2026-03-05 22:47:20 +08:00
Soulter
af581e7f21 chore: bump version to 4.19.2 2026-03-05 16:10:09 +08:00
Soulter
9e371ee10b chore: update shipyard-neo-sdk dependency to version 0.2.0 2026-03-05 16:07:10 +08:00
camera-2018
7cf77adbc8 feat(telegram): supports sendMessageDraft API (#5726)
* feat(telegram): 使用 sendMessageDraft API 实现私聊流式输出

- 新增 _send_message_draft 方法封装 Telegram Bot API sendMessageDraft
- 私聊流式输出使用 sendMessageDraft 推送草稿动画,群聊保留 edit_message_text 回退
- 使用独立异步发送循环 (_draft_sender_loop) 按固定间隔推送最新缓冲区内容,
  完全解耦 token 到达速度与 API 网络延迟
- 流式结束后发送真实消息保留最终内容(draft 是临时的)
- 使用模块级递增 draft_id 替代随机生成,确保 Telegram 端动画连续性

* fix(telegram): convert draft text to Markdown before sending message draft

* chore(telegram): telegram 适配器重构

- 提取公共方法
- 有新 token 到达时触发流式
- 生成结束后清除draft内容
- 默认draft发送md格式

* style(telegram): ruff format

* style(telegram): ruff check

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-05 11:20:28 +08:00
Soulter
31673ee521 fix: require node.js env when uv sync 2026-03-05 11:20:16 +08:00
エイカク
ff22030dde docs: align deployment sections across multilingual readmes (#5734)
* docs: align deployment sections across multilingual readmes

* docs: normalize deployment punctuation and AUR guidance

* docs: fix french and russian deployment wording
2026-03-05 11:19:27 +08:00
Soulter
101580fd77 chore: add sponsors section to README
Added a sponsors section with an image link.
2026-03-03 19:08:12 +08:00
Soulter
418f05f6e4 fix: tests 2026-03-03 16:06:49 +08:00
Soulter
df421e5554 fix: test 2026-03-03 16:04:08 +08:00
shuiping233
ed84074a60 unittest: 添加之前遗漏的kook_card_data.json (#5703) 2026-03-03 16:01:26 +08:00
Soulter
bbf61239ad fix(kook): remove debug logging for received messages and heartbeat responses 2026-03-03 15:54:45 +08:00
miaoxutao123
92ee534a2c feat: add OS information to tool descriptions and implement unit tests (#5677)
* feat: add OS information to tool descriptions and implement unit tests

* refactor: use module-level constant for OS name as suggested in PR review
2026-03-03 15:16:38 +08:00
L1ngg
fa4df0b5f3 fix(core): correctly parse DEMO_MODE as boolean from env var. (#5676)
* fix(core): correctly parse DEMO_MODE as boolean from env var.

* Update astrbot/core/__init__.py

fix(core): 添加.strip()以确保代码健壮性

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-03-03 15:15:20 +08:00
dependabot[bot]
e5ac31efe7 chore(deps): bump the github-actions group with 2 updates (#5694)
Bumps the github-actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/upload-artifact` from 6 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

Updates `actions/download-artifact` from 7 to 8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  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-03-03 15:14:28 +08:00
時壹
2a7745c767 fix: only allow HTTPS URLs to pass through directly in LINE adapter (#5697) 2026-03-03 15:14:08 +08:00
Gargantua
82e7502f74 fix(dashboard): stabilize sidebar customization state (#5405) (#5670)
- use stable sidebar list keys to avoid vnode reuse drift

- sanitize persisted opened groups against current sidebar menu

- guard non-array customization keys from localStorage

Co-authored-by: Gargantua <22532097@zju.edu.cn>
2026-03-03 15:12:15 +08:00
shuiping233
866e546b59 feat: integrates KOOK platform adapter (#5658)
* feat: 将kook适配器插件并入astrbot官方适配器目录中

* refactor: 重命名函数名为 _warp_message

* refactor: 使用Protocol替换Union类型

* bugfix: 修复base64前缀处理问题

* refactor: 抛出的错误不再包含"[kook]"

* refactor: 添加读取本地文件时的路径安全检查

* refactor: 卡片消息解析失败时会打印错误信息

* refactor: 添加处理接收卡片消息内的图片url时的安全校验

* refactor: 安全处理ws需要重连的情况

* Revert "refactor: 使用Protocol替换Union类型"

This reverts commit 58e0dceeb20c3d7dddb16f623fd3bbdcfa632173.

* feat: 添加获取机器人名称的实现

* refactor: 让send_by_session发送主动消息时正确传入当前消息链的文本消息内容

* refactor: 统一处理适配器配置相关内容,处理仪表盘出传入配置,并添加仪表盘的kook适配器配置页面的i18n文本

* unittest: 添加kook适配器的单元测试,虽然没覆盖多少单测

* unittest: TEST_DATA_DIR用更安全的路径

* refactor: KookConfig使用了更好的默认值处理方式

* refactor: 移除kook_adapter 的config字段重复定义

* refactor: 隐藏获取kook gateway时url里的token,防止把token打印出来

* refactor: KookConfig.pretty_jsons使用*来屏蔽token内容

* bugfix: 修复主动发送消息时,调用了父方法`send_by_session`可能导致指标被重复上传的bug

* refactor: 优化upload_asset的路径处理报错

* bugfix: 修复kook ws心跳间隔可能会出现负数时间的bug

* refactor: KookClient移到KookPlatformAdapter.__init__里初始化

* bugfix: 修复处理base64 url 多替换了/而报错的bug

* refactor: kook适配器上传文件失败时,会抛出错误

* chore: 移除一条注释

* refactor: 移除没用的return

* refactor: 即使消息链中有消息发送失败了,也尽可能将其他消息发送出去,并把报错信息也发送出去

* refactor: 增强上传任务失败时的错误处理,使其发生错误时尽力而为发送其余消息

* refactor: 发送到消息频道的报错消息加了个⚠️,小巧思这块?

* refactor: 咱们在写适配器啊,要什么小巧思呢,小巧思给上游插件开发弄不好么)

* refactor: enhance Kook adapter with kmarkdown parsing and improve file URL handling

* refactor: extract card message parsing logic into a separate method

* feat: add kook_bot_nickname configuration to ignore messages from specific nicknames

* refactor: remove commented-out code and clean up file upload error handling

* fix: remove redundant prefix handling for file URLs in asset upload

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-03-03 15:08:16 +08:00
Soulter
6b642d7674 refactor: bundled webui static files into wheel and replace astrbot cli log with English (#5665)
* refactor: bundled webui static files into wheel and replace astrbot cli log with English

- Translated and standardized log messages in cmd_conf.py for better clarity.
- Updated initialization logic in cmd_init.py to provide clearer user prompts and error handling.
- Improved plugin management commands in cmd_plug.py with consistent language and error messages.
- Enhanced run command in cmd_run.py with clearer status messages and error handling.
- Updated utility functions in basic.py and plugin.py to improve readability and maintainability.
- Added version comparison logic in version_comparator.py with clearer comments.
- Enhanced logging configuration in log.py to suppress noisy loggers.
- Updated the updater logic in updator.py to provide clearer error messages for users.
- Improved IO utility functions in io.py to handle dashboard versioning more effectively.
- Enhanced dashboard server logic in server.py to prioritize bundled assets and improve user feedback.
- Updated pyproject.toml to include bundled dashboard assets and custom build hooks.
- Added a custom build script (hatch_build.py) to automate dashboard builds during package creation.

* refactor: improve exception messages and formatting in CLI command validation

* perf: change npm install to npm ci for consistent dependency installation

* fix
2026-03-03 12:58:59 +08:00
SJ
0711ec346f Fix/fix: resolve MCP tools race condition causing 'completion 无法解析' error (#5534)
* fix: resolve MCP tools race condition causing 'completion 无法解析' error

- Wait for MCP client initialization to complete before accepting requests
- Add Future-based synchronization in init_mcp_clients()
- Prevent tool_calls from being rejected due to empty func_list
- Improve error logging for MCP initialization failures

Fixes race condition where AI attempts to call MCP tools before they are
registered, resulting in 'API 返回的 completion 无法解析' exceptions.

The issue occurred because:
1. MCP clients were initialized asynchronously without waiting
2. System accepted user requests immediately after startup
3. AI received empty tool list and attempted to call non-existent tools
4. Tool matching failed, causing parsing errors

This fix ensures all MCP tools are loaded before the system processes
any requests that might use them.

* perf: add timeout and better error handling for MCP initialization

- Add 20-second total timeout to prevent slow MCP servers from blocking startup
- Show detailed configuration info when MCP initialization fails
- List all failed services in a summary warning
- Gracefully handle timeout by using already-completed services

This ensures that even if some MCP servers are slow or unreachable,
the system will start within a reasonable time and provide clear
feedback about which services failed and why.

* refactor: simplify MCP init orchestration and improve log security

- Replace Future-based sync with asyncio.wait + name→task mapping
- Explicitly cancel timed-out tasks after 20s timeout
- Downgrade sensitive config details (command/args/URL) to debug level
- Move urllib.parse import to top-level

* fix: prevent initialized MCP clients from being cleaned up on timeout

- Do not cancel pending tasks on timeout; let them continue running
  in the background waiting for the termination signal (event.set()),
  so successfully initialized services remain available
- Track initialization state with a flag to distinguish init failures
  from post-init cancellations in _init_mcp_client_task_wrapper

* fix: restore task cancellation on timeout per review feedback

Pending tasks in asyncio.wait are tasks that have NOT completed
initialization within 20s, so cancelling them is safe and correct.

* fix: separate init signal from client lifetime in MCP task wrapper

The previous design awaited task completion, but tasks only finish
on shutdown (after event.wait()), causing asyncio.wait to always
hit the 20s timeout and cancel all clients.

Fix: introduce a dedicated ready_event that is set immediately after
_init_mcp_client completes. init_mcp_clients now waits only for
ready_event (with 20s timeout), while the long-lived client task
continues running in the background until shutdown_event is set.

This ensures startup returns promptly once clients are ready.

* security: redact sensitive MCP config from debug logs

Only log executable name and argument count instead of full
command/args to avoid leaking tokens or credentials even at
debug level.

* refactor: use McpClientInfo dataclass and MCP_INIT_TIMEOUT constant

- Extract MCP_INIT_TIMEOUT = 20.0 as a named module-level constant
- Replace tuple-based client_info with _McpClientInfo dataclass to
  eliminate index-based access and improve readability
- Remove _wait_ready helper; use asyncio.create_task(event.wait()) directly
- Await cancelled tasks after timeout to prevent lingering background
  tasks and unobserved exceptions

* fix: handle CancelledError and clean up wait_tasks on timeout

- Catch asyncio.CancelledError separately in _init_mcp_client_task_wrapper
  so ready_event.set() is always called (Python 3.8+ CancelledError
  inherits BaseException, not Exception)
- Cancel and await lingering wait_tasks after timeout to prevent
  them from hanging indefinitely when ready_event is never set

* fix: align enable_mcp_server with new wrapper API and fix security/config issues

- Fix enable_mcp_server to pass shutdown_event + ready_event instead of
  ready_future, matching _init_mcp_client_task_wrapper's current signature
- Cancel and await init_task on timeout; clean up mcp_client_event on failure
- Read MCP_INIT_TIMEOUT from env var ASTRBOT_MCP_INIT_TIMEOUT (default 20s)
  so operators can tune it without code changes
- Strip userinfo from URL in debug log (use hostname+port only, not netloc)
  to avoid leaking credentials embedded in URLs

* refactor: register mcp_client_event only after successful init in enable_mcp_server

Move self.mcp_client_event[name] assignment to after initialization
succeeds, so callers never observe a stale event for a failed client.

* fix: harden MCP init state handling and timeout parsing

* fix: improve MCP timeout and post-init error observability

* refactor: simplify MCP init lifecycle orchestration

* refactor: simplify MCP init flow and cap timeout values

* fix: refine mcp timeout handling and lifecycle task tracking

* fix: harden mcp shutdown and timeout source logging

* refactor: simplify mcp runtime registry and timeout flow

* fix: keep mcp init summary return contract

* refactor: streamline mcp lifecycle and init errors

* refactor: unify mcp lifecycle wait handling

* refactor: simplify mcp runtime ownership and timeout resolution

* fix: harden mcp shutdown waiting and startup signaling

* refactor: streamline mcp lifecycle and shutdown errors

* refactor: harden mcp runtime access and shutdown

* fix: ensure mcp client cleanup and clarify views

* refactor: cache mcp client view and guard startup

* refactor: simplify mcp init cleanup and runtime lock

* refactor: reduce mcp runtime duplication

* refactor: reuse mcp cleanup and client view

---------

Co-authored-by: idiotsj <idiotsj@users.noreply.github.com>
Co-authored-by: 邹永赫 <1259085392@qq.com>
2026-03-03 01:09:45 +09:00
LIghtJUNction
bbafb59cb2 Update dashboard/package.json
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 16:57:31 +08:00
LIghtJUNction
eaa1fddfa9 Update astrbot/cli/commands/cmd_init.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-02 16:57:07 +08:00
LIghtJUNction
1ffa339a2a Update astrbot/core/config/default.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-02 15:33:14 +08:00
Copilot
0dbe32e2dc feat: add Discord pre-ack emoji support (#5609)
* Initial plan

* feat: add Discord pre-ack emoji support

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* feat: add Discord pre-acknowledgment emoji configuration in English and Chinese locales

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-02 14:38:12 +08:00
Soulter
4e855a17bc fix: update Discord command registration descriptions and hints in config metadata 2026-03-02 14:31:36 +08:00
Soulter
f2fc724e0f fix: update tutorial links to use the correct path format 2026-03-02 14:22:56 +08:00
Copilot
460acf40c0 fix: apply max_agent_step config to subagents (#5608)
* Initial plan

* fix: apply max_agent_step config to subagents

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: streamline max_agent_step and streaming_response retrieval in FunctionToolExecutor

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-02 14:16:14 +08:00
Soulter
cf29d9390f chore: reorganize provider settings for quoted message parsing 2026-03-02 12:35:35 +08:00
Soulter
ac44d1fdef feat: enhance chat interface and mobile responsiveness (#5635) 2026-03-02 12:26:55 +08:00
Soulter
66d0f0afd4 chore: remove deprecated websearch command from event filter 2026-03-02 11:51:58 +08:00
Ruochen Pan
2a7b4f6e64 Merge pull request #5028 from w31r4/feat/neo-skill-self-iteration
feat: 接入 Shipyard Neo 自迭代 Skill 闭环与管理能力
2026-03-02 09:40:32 +08:00
RC-CHN
6e1be64aef Merge branch 'feat/neo-skill-self-iteration' of https://github.com/w31r4/AstrBot into feat/neo-skill-self-iteration 2026-03-02 09:37:42 +08:00
RC-CHN
f818ad0758 Merge remote-tracking branch 'origin/master' into feat/neo-skill-self-iteration 2026-03-02 09:37:06 +08:00
sanyekana
4abea2bd30 fix: harden backup import for duplicate platform stats (#5594)
* fix: harden backup import for duplicate platform stats

- 修复 replace 模式下主库清空失败仍继续导入的问题。
- 导入前对 platform_stats 重复键做聚合(count 累加),并统一时间戳判重格式。
- 非法 count 按 0 处理并告警(限流),补充对应测试。

* refactor: improve robustness and readability of platform stats import

- 告警上限魔法数字提取为模块常量 PLATFORM_STATS_INVALID_COUNT_WARN_LIMIT
- 抽取 parse_count 内联函数,消除重复的 try/except 分支
- 存储行的 timestamp 同步写入规范化值,避免落库格式混用
- 补充测试:已有行 count 非法、告警限流、replace 模式中断断言

* fix: normalize invalid platform_stats count for non-duplicate rows

* fix: avoid merging invalid platform_stats timestamps

* refactor: simplify platform stats merge and normalize naive UTC

* refactor: inline platform stats merge helpers

* refactor: flatten platform stats merge flow

* refactor: harden platform stats merge key handling

* refactor: streamline platform stats preprocessing

* refactor: simplify platform stats merge helpers

* refactor: inline platform stats merge normalization

* refactor: extract platform stats merge helpers

* refactor: simplify platform stats preprocessing flow

* refactor: flatten platform stats preprocess helpers

* refactor: streamline platform stats merge helpers

* refactor: isolate platform stats warning limiter

---------

Co-authored-by: 邹永赫 <1259085392@qq.com>
2026-03-01 20:46:35 +09:00
pandyzhou
267abfd552 fix: resolve /model command misleading behavior when switching to model from different provider (#5578)
* fix: /model command now auto-switches provider when model exists elsewhere

Made-with: Cursor

* fix: address Sourcery review - log get_models() failures in cross-provider lookup

Made-with: Cursor

* fix: integer branch exception handling and API key masking in model command

Made-with: Cursor

* fix: harden cross-provider model resolution

* fix: improve model lookup resilience and cache hygiene

* refactor: simplify model switch lookup flow

* refactor: streamline provider model cache updates

* fix: align provider annotations and key error flow

* fix: narrow provider command exception handling

* refactor: harden provider command error redaction and flow

* fix: improve provider model lookup and secret redaction

* refactor: cache normalized model names in provider lookup

* refactor: simplify provider model lookup helpers

* refactor: extract provider model lookup helpers

* fix: harden provider lookup cancellation and redaction

* refactor: streamline provider cache and lookup settings

* refactor: simplify provider command setting and update helpers

* refactor: streamline provider model lookup config usage

* refactor: flatten provider lookup settings and filter model lookup providers

* refactor: simplify provider cache and callback flow

* refactor: simplify provider command model cache flow

* refactor: scope provider model cache by session

* fix: preserve redaction context and restore provider hooks

* refactor: unify provider model lookup config flow

* refactor: inline provider model cache access flow

* fix: align provider lookup cache and callback semantics

* refactor: centralize provider model fetch error handling

* refactor: simplify provider model cache and lookup flow

---------

Co-authored-by: 邹永赫 <1259085392@qq.com>
2026-03-01 19:11:31 +09:00
Soulter
b4450eb617 fix: update computer_use_runtime to 'none' for improved configuration flexibility 2026-03-01 17:35:50 +08:00
Chen
daa2efde14 fix:修正子agent无法正确接收本地图片(参考图)路径的问题 (#5579)
* fix: 修复5081号PR在子代理执行后台任务时,未正确使用系统配置的流式/非流请求的问题(#5081)

* feat:为子代理增加远程图片URL参数支持

* fix: update description for image_urls parameter in HandoffTool to clarify usage in multimodal tasks

* ruff format

* fix:修正子agent无法正确接收本地图片(参考图)路径的问题

* fix:增强image_urls接收的鲁棒性

* fix:ruff检查

* fix: harden handoff image_urls preprocessing

* fix: refactor handoff image_urls preprocessing flow

* refactor: simplify handoff image_urls data flow

* fix: filter non-string handoff image_urls entries

* refactor: streamline handoff image url collection

* refactor: share handoff image ref validation utilities

* refactor: simplify handoff image url processing

* refactor: honor prepared handoff image urls contract

---------

Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: 邹永赫 <1259085392@qq.com>
2026-03-01 17:01:23 +09:00
Soulter
d561046ba3 feat: enhance shell command execution description for cross-platform compatibility
fixes: #5499
2026-03-01 15:35:40 +08:00
WintryWind
fd223bb259 fix: resolve unhandled UTC timezone offset for timestamps in conversation records (#5580)
* fix: resolve unhandled UTC timezone offset for timestamps in conversation records

* fix: standardize timezone imports

* fix: unify UTC datetime normalization in dashboard routes

---------

Co-authored-by: 邹永赫 <1259085392@qq.com>
2026-03-01 16:10:35 +09:00
エイカク
451ad685ae feat: 集成 DeerFlow Agent Runner 并优化流式处理 (#5581)
* feat: integrate DeerFlow agent runner and improve stream handling

* refactor: split DeerFlow stream flow and close stale client on reset

* fix: enforce max_step and correct timeout type check

* fix: harden DeerFlow config parsing and session lifecycle

* fix: preserve third-party runner error semantics and harden image parsing

* perf: bound DeerFlow values history and seen-id cache

* refactor: improve deerflow stream semantics and client lifecycle

* fix: harden third-party runner error semantics and fallback aggregation

* refactor: reduce deerflow image log noise and lazy-init api session

* perf: avoid unnecessary iterable copies in deerflow stream utils

* refactor: centralize runner error key and clarify deerflow client lifecycle

* refactor: simplify third-party runner output flow

* fix: defer streaming runner cleanup and unify error mapping

* fix: handle id-less values messages and redact stream payload logs

* fix: improve deerflow error signaling and third-party runner flow

* fix: support deerflow proxy and refine runner lifecycle

* fix: tighten deerflow image validation and runner lifecycle

* feat: support deerflow image output components

* fix: harden runner stream cleanup and refactor deerflow config

* fix: preserve deerflow done hook and simplify runner lifecycle

* refactor: simplify third-party runner aggregation and lifecycle closing

* fix: preserve first deerflow values payload and simplify runner flow

* refactor: unify runner final resolution and harden deerflow close state

* refactor: share int coercion and make deerflow close best effort

* refactor: extract deerflow mappers and streamline third-party lifecycle

* refactor: simplify third-party flow and harden sse flush parsing

* fix: make deerflow runner close path best effort

* refactor: simplify third-party orchestration and centralize deerflow keys

* refactor: simplify third-party chunk flow and deerflow finalization

* fix: harden deerflow stream parsing and simplify runner lifecycle

* refactor: remove redundant deerflow values text assignment

* fix: improve deerflow timeout diagnostics and image input feedback

* refactor: flatten third-party runner lifecycle and aggregation

* chore: use deerflow official remote svg icon

* chore: remove unused deerflow local logo asset
2026-03-01 12:31:38 +09:00
whatevertogo
93decaa997 test: add comprehensive tests for core lifecycle and agent execution (#5357)
* test: add comprehensive tests for core lifecycle and agent execution

- Add core lifecycle unit tests
- Add main agent execution tests
- Add computer use tests
- Enhance event bus tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: 更新用户查询标题生成逻辑,确保处理为纯文本并忽略内部指令
refactor(tests): 移除测试文件中的循环导入注释
refactor(tests): 优化计算机客户端测试,简化不可用引导程序的处理逻辑

* fix(event_bus): 优化事件处理逻辑,简化配置检查并增强错误日志记录,优化了测试内容

* fix(astr_main_agent): 简化 LLM 安全模式系统提示的设置逻辑

* test: enhance persona resolution in mock context for persona management tests

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-03-01 00:23:47 +08:00
Soulter
0d1a3ab18b refactor: remove unused router import and group click handler in NavItem component 2026-03-01 00:12:09 +08:00
whatevertogo
2a6863cf70 test: add tests for star base class and config management (#5356)
* test: add tests for star base class and config management

- Add Star base class safety helper tests
- Expand config management unit tests
- Update cron manager tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: fix plugin_manager test isolation issues

- Use local mock plugin instead of real network requests
- Clear sys.modules cache for entire data module tree
- Clear star_map and star_registry in teardown
- Use pytest_asyncio.fixture for async fixture support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: fix test isolation and compatibility issues

- test_main.py: fix version comparison and path assertions for Windows
- test_smoke.py: add missing apscheduler.triggers mock modules
- test_tool_loop_agent_runner.py: update assertion for new interrupt behavior
- test_api_key_open_api.py: use unique session IDs to avoid test conflicts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add unit tests for _version_info comparisons

* test: enhance plugin manager tests with mock implementations and improved assertions

* test: add mock plugin builder and updater for plugin management tests

* fix: resolve pipeline and star import cycles (#5353)

* fix: resolve pipeline and star import cycles

- Add bootstrap.py and stage_order.py to break circular dependencies
- Export Context, PluginManager, StarTools from star module
- Update pipeline __init__ to defer imports
- Split pipeline initialization into separate bootstrap module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add logging for get_config() failure in Star class

* fix: reorder logger initialization in base.py

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: update cron job scheduling tests and refactor star base tests for clarity

* test: expand star base tests for comprehensive coverage

- Add tests for Star class initialization and context handling
- Add tests for text_to_image with/without config
- Add tests for html_render method
- Add tests for initialize/terminate lifecycle methods
- Add type hint validation tests for Context
- Add circular import prevention tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback - use TYPE_CHECKING instead of Any

- pipeline/context.py: Use TYPE_CHECKING to import PluginManager instead of Any
- pipeline/__init__.py: Add TYPE_CHECKING imports for __all__ exports to satisfy static analyzers
- star/register/star_handler.py: Use TYPE_CHECKING to import AstrAgentContext instead of Any
- tests: Remove invalid type hint tests that tested incorrect assumptions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: improve TYPE_CHECKING pattern for circular import resolution

- star/register/star_handler.py: Use AstrAgentContext instead of Any in generic types
- star/context.py: Remove unnecessary else branch with CronJobManager = Any
  (with __future__ annotations, TYPE_CHECKING imports are sufficient)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-03-01 00:06:04 +08:00
Soulter
76e0d6d71a feat: refactor API key creation and add new tests for open API routes 2026-02-28 23:43:05 +08:00
Soulter
974bb6b359 feat: improve error messaging for AI execution failures in agent runners 2026-02-28 21:23:44 +08:00
Soulter
2e410fc728 docs: update readme 2026-02-28 21:23:44 +08:00
Flartiny
0e2ca0379f fix: add plugin sorting by name and improve search filtering logic (#5559) 2026-02-28 18:35:11 +08:00
Soulter
9214d48a2d feat: add email support link to multiple language READMEs and enhance deployment instructions 2026-02-28 16:19:12 +08:00
Soulter
064495698f feat(i18n): add neoDeactivate messages for extension management 2026-02-28 15:45:41 +08:00
Soulter
7c913093b0 feat(i18n): add neoFilterHint for filtering candidates and release records 2026-02-28 15:27:50 +08:00
Soulter
edf0982ce4 feat(skills): enhance candidate promotion buttons with loading and disabled states 2026-02-28 15:25:14 +08:00
エイカク
7bf44bd8d2 feat: support persona custom error reply message with fallback (#5547)
* feat: support persona custom error reply message with fallback

* refactor: centralize persona custom error message helpers
2026-02-28 13:34:12 +09:00
エイカク
881b409ebc feat: improve plugin failure handling and extension list UX (#5535)
* feat: improve plugin failure handling and extension list UX

* fix: address plugin review comments

* fix: clear stale reload feedback on failed plugin reload

* fix: refine extension i18n and uninstall flow

* fix: refresh extension list after install failure

* feat: add random plugin visibility controls in market

* refactor: extract extension helpers and simplify uninstall flow

* refactor: improve failed plugin diagnostics and uninstall flow

* refactor: streamline extension uninstall flow

* fix: harden failed plugin install tracking and cleanup

* refactor: simplify extension flows and remove unused timed message

* fix: improve failed uninstall idempotency and extension error handling

* refactor: unify extension install-uninstall orchestration
2026-02-28 00:06:47 +08:00
LIghtJUNction
eacfd14218 细节修正/路径参数(astrbot_root)语义一致化 2026-02-27 23:51:44 +08:00
LIghtJUNction
b8ffecf500 完善前端/允许退出登录 2026-02-27 23:41:43 +08:00
Soulter
74a46464c8 docs: update deployment instructions across multiple language READMEs 2026-02-27 23:25:35 +08:00
LIghtJUNction
e5d85e402b 完善前端 2026-02-27 23:06:13 +08:00
Soulter
4aa63dbeaf chore: update readme 2026-02-27 22:54:39 +08:00
Soulter
ddc268a732 docs: enhance README_zh.md with detailed AstrBot features
Expanded description of AstrBot's capabilities and deployment options across various messaging platforms.
2026-02-27 22:47:44 +08:00
Soulter
f6ac6b9007 docs: update readme
- Updated links in Japanese, Russian, and Traditional Chinese README files to include a new Simplified Chinese README.
- Enhanced the description and features of AstrBot across all language versions.
- Improved formatting of supported messaging platforms and model services in Japanese, Russian, and Traditional Chinese README files.
- Added a new README file in Simplified Chinese with comprehensive details about AstrBot, including features, deployment methods, and community contributions.
2026-02-27 22:40:38 +08:00
LIghtJUNction
ea21d44d60 修正一个小错误 2026-02-27 22:33:54 +08:00
LIghtJUNction
0f734e19fd fix: import errors and port detection issue 2026-02-27 22:26:55 +08:00
LIghtJUNction
6044502968 修正导入问题 2026-02-27 22:23:26 +08:00
LIghtJUNction
fed11fffa4 恢复分支 2026-02-27 22:20:38 +08:00
LIghtJUNction
f79f460b89 Merge pull request #5538 from AstrBotDevs/master
同步
2026-02-27 22:08:50 +08:00
LIghtJUNction
a6009e2bd8 同步到主分支 (#5537)
* feat: add bocha web search tool (#4902)

* add bocha web search tool

* Revert "add bocha web search tool"

This reverts commit 1b36d75a17.

* add bocha web search tool

* fix: correct temporary_cache spelling and update supported tools for web search

* ruff

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: messages[x] assistant content must contain at least one part (#4928)

* fix: messages[x] assistant content must contain at least one part

fixes: #4876

* ruff format

* chore: bump version to 4.14.5 (#4930)

* feat: implement feishu / lark media file handling utilities for file, audio and video processing (#4938)

* feat: implement media file handling utilities for audio and video processing

* feat: refactor file upload handling for audio and video in LarkMessageEvent

* feat: add cleanup for failed audio and video conversion outputs in media_utils

* feat: add utility methods for sending messages and uploading files in LarkMessageEvent

* fix: correct spelling of 'temporary' in SharedPreferences class

* perf: optimize webchat and wecom ai queue lifecycle (#4941)

* perf: optimize webchat and wecom ai queue lifecycle

* perf: enhance webchat back queue management with conversation ID support

* fix: localize provider source config UI (#4933)

* fix: localize provider source ui

* feat: localize provider metadata keys

* chore: add provider metadata translations

* chore: format provider i18n changes

* fix: preserve metadata fields in i18n conversion

* fix: internationalize platform config and dialog

* fix: add Weixin official account platform icon

---------

Co-authored-by: Soulter <905617992@qq.com>

* chore: bump version to 4.14.6

* feat: add provider-souce-level proxy (#4949)

* feat: 添加 Provider 级别代理支持及请求失败日志

* refactor: simplify provider source configuration structure

* refactor: move env proxy fallback logic to log_connection_failure

* refactor: update client proxy handling and add terminate method for cleanup

* refactor: update no_proxy configuration to remove redundant subnet

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat(ComponentPanel):  implement permission management for dashboard (#4887)

* feat(backend): add permission update api

* feat(useCommandActions): add updatePermission action and translations

* feat(dashboard): implement permission editing ui

* style: fix import sorting in command.py

* refactor(backend): extract permission update logic to service

* feat(i18n): add success and failure messages for command updates

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat: 允许 LLM 预览工具返回的图片并自主决定是否发送 (#4895)

* feat: 允许 LLM 预览工具返回的图片并自主决定是否发送

* 复用 send_message_to_user 替代独立的图片发送工具

* feat: implement _HandleFunctionToolsResult class for improved tool response handling

* docs: add path handling guidelines to AGENTS.md

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat(telegram): 添加媒体组(相册)支持 / add media group (album) support (#4893)

* feat(telegram): 添加媒体组(相册)支持 / add media group (album) support

## 功能说明
支持 Telegram 的媒体组消息(相册),将多张图片/视频合并为一条消息处理,而不是分散成多条消息。

## 主要改动

### 1. 初始化媒体组缓存 (__init__)
- 添加 `media_group_cache` 字典存储待处理的媒体组消息
- 使用 2.5 秒超时收集媒体组消息(基于社区最佳实践)
- 最大等待时间 10 秒(防止永久等待)

### 2. 消息处理流程 (message_handler)
- 检测 `media_group_id` 判断是否为媒体组消息
- 媒体组消息走特殊处理流程,避免分散处理

### 3. 媒体组消息缓存 (handle_media_group_message)
- 缓存收到的媒体组消息
- 使用 APScheduler 实现防抖(debounce)机制
- 每收到新消息时重置超时计时器
- 超时后触发统一处理

### 4. 媒体组合并处理 (process_media_group)
- 从缓存中取出所有媒体项
- 使用第一条消息作为基础(保留文本、回复等信息)
- 依次添加所有图片、视频、文档到消息链
- 将合并后的消息发送到处理流程

## 技术方案论证

Telegram Bot API 在处理媒体组时的设计限制:
1. 将媒体组的每个消息作为独立的 update 发送
2. 每个 update 带有相同的 `media_group_id`
3. **不提供**组的总数、结束标志或一次性完整组的机制

因此,bot 必须自行收集消息,并通过硬编码超时(timeout/delay)等待可能延迟到达的消息。
这是目前唯一可靠的方案,被官方实现、主流框架和开发者社区广泛采用。

### 官方和社区证据:
- **Telegram Bot API 服务器实现(tdlib)**:明确指出缺少结束标志或总数信息
  https://github.com/tdlib/telegram-bot-api/issues/643

- **Telegram Bot API 服务器 issue**:讨论媒体组处理的不便性,推荐使用超时机制
  https://github.com/tdlib/telegram-bot-api/issues/339

- **Telegraf(Node.js 框架)**:专用媒体组中间件使用 timeout 控制等待时间
  https://github.com/DieTime/telegraf-media-group

- **StackOverflow 讨论**:无法一次性获取媒体组所有文件,必须手动收集
  https://stackoverflow.com/questions/50180048/telegram-api-get-all-uploaded-photos-by-media-group-id

- **python-telegram-bot 社区**:确认媒体组消息单独到达,需手动处理
  https://github.com/python-telegram-bot/python-telegram-bot/discussions/3143

- **Telegram Bot API 官方文档**:仅定义 `media_group_id` 为可选字段,不提供获取完整组的接口
  https://core.telegram.org/bots/api#message

## 实现细节
- 使用 2.5 秒超时收集媒体组消息(基于社区最佳实践)
- 最大等待时间 10 秒(防止永久等待)
- 采用防抖(debounce)机制:每收到新消息重置计时器
- 利用 APScheduler 实现延迟处理和任务调度

## 测试验证
-  发送 5 张图片相册,成功合并为一条消息
-  保留原始文本说明和回复信息
-  支持图片、视频、文档混合的媒体组
-  日志显示 Processing media group <media_group_id> with 5 items

## 代码变更
- 文件:astrbot/core/platform/sources/telegram/tg_adapter.py
- 新增代码:124 行
- 新增方法:handle_media_group_message(), process_media_group()

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor(telegram): 优化媒体组处理性能和可靠性

根据代码审查反馈改进:

1. 实现 media_group_max_wait 防止无限延迟
   - 跟踪媒体组创建时间,超过最大等待时间立即处理
   - 最坏情况下 10 秒内必定处理,防止消息持续到达导致无限延迟

2. 移除手动 job 查找优化性能
   - 删除 O(N) 的 get_jobs() 循环扫描
   - 依赖 replace_existing=True 自动替换任务

3. 重用 convert_message 减少代码重复
   - 统一所有媒体类型转换逻辑
   - 未来添加新媒体类型只需修改一处

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(telegram): handle missing message in media group processing and improve logging messages

---------

Co-authored-by: Ubuntu <ubuntu@localhost.localdomain>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>

* feat: add welcome feature with localized content and onboarding steps

* fix: correct height attribute to max-height for dialog component

* feat: supports electron app (#4952)

* feat: add desktop wrapper with frontend-only packaging

* docs: add desktop build docs and track dashboard lockfile

* fix: track desktop lockfile for npm ci

* fix: allow custom install directory for windows installer

* chore: migrate desktop workflow to pnpm

* fix(desktop): build AppImage only on Linux

* fix(desktop): harden packaged startup and backend bundling

* fix(desktop): adapt packaged restart and plugin dependency flow

* fix(desktop): prevent backend respawn race on quit

* fix(desktop): prefer pyproject version for desktop packaging

* fix(desktop): improve startup loading UX and reduce flicker

* ci: add desktop multi-platform release workflow

* ci: fix desktop release build and mac runner labels

* ci: disable electron-builder auto publish in desktop build

* ci: avoid electron-builder publish path in build matrix

* ci: normalize desktop release artifact names

* ci: exclude blockmap files from desktop release assets

* ci: prefix desktop release assets with AstrBot and purge blockmaps

* feat: add electron bridge types and expose backend control methods in preload script

* Update startup screen assets and styles

- Changed the icon from PNG to SVG format for better scalability.
- Updated the border color from #d0d0d0 to #eeeeee for a softer appearance.
- Adjusted the width of the startup screen from 460px to 360px for improved responsiveness.

* Update .gitignore to include package.json

* chore: remove desktop gitkeep ignore exceptions

* docs: update desktop troubleshooting for current runtime behavior

* refactor(desktop): modularize runtime and harden startup flow

---------

Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: dedupe preset messages (#4961)

* feat: enhance package.json with resource filters and compression settings

* chore: update Python version requirements to 3.12 (#4963)

* chore: bump version to 4.14.7

* feat: refactor release workflow and add special update handling for electron app (#4969)

* chore: bump version to 4.14.8 and bump faiss-cpu version up to date

* chore: auto ann fix by ruff (#4903)

* chore: auto fix by ruff

* refactor: 统一修正返回类型注解为 None/bool 以匹配实现

* refactor: 将 _get_next_page 改为异步并移除多余的请求错误抛出

* refactor: 将 get_client 的返回类型改为 object

* style: 为 LarkMessageEvent 的相关方法添加返回类型注解 None

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: prepare OpenSSL via vcpkg for Windows ARM64

* ci: change ghcr namespace

* chore: update pydantic dependency version (#4980)

* feat: add delete button to persona management dialog (#4978)

* Initial plan

* feat: add delete button to persona management dialog

- Added delete button to PersonaForm dialog (only visible when editing)
- Implemented deletePersona method with confirmation dialog
- Connected delete event to PersonaManager for proper handling
- Button positioned on left side of dialog actions for clear separation
- Uses existing i18n translations for delete button and messages

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: use finally block to ensure saving state is reset

- Moved `this.saving = false` to finally block in deletePersona
- Ensures UI doesn't stay in saving state after errors
- Follows best practices for state management

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* feat: enhance Dingtalk adapter with active push message and image, video, audio message type (#4986)

* fix: handle pip install execution in frozen runtime (#4985)

* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling

* fix: collect certifi data in desktop backend build (#4995)

* feat: 企业微信应用 支持主动消息推送,并优化企微应用、微信公众号、微信客服音频相关的处理 (#4998)

* feat: 企业微信智能机器人支持主动消息推送以及发送视频、文件等消息类型支持 (#4999)

* feat: enhance WecomAIBotAdapter and WecomAIBotMessageEvent for improved streaming message handling (#5000)

fixes: #3965

* feat: enhance persona tool management and update UI localization for subagent orchestration (#4990)

* feat: enhance persona tool management and update UI localization for subagent orchestration

* fix: remove debug logging for final ProviderRequest in build_main_agent function

* perf: 稳定源码与 Electron 打包环境下的 pip 安装行为,并修复非 Electron 环境下点击 WebUI 更新按钮时出现跳转对话框的问题 (#4996)

* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling

* fix: scope global data root to packaged electron runtime

* refactor: inline frozen runtime check for electron guard

* fix: prefer current interpreter for source pip installs

* fix: avoid resolving venv python symlink for pip

* refactor: share runtime environment detection utilities

* fix: improve error message when pip module is unavailable

* fix: raise ImportError when pip module is unavailable

* fix: preserve ImportError semantics for missing pip

* fix: 修复非electron app环境更新时仍然显示electron更新对话框的问题

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: 'HandoffTool' object has no attribute 'agent' (#5005)

* fix: 移动agent的位置到super().__init__之后

* add: 添加一行注释

* chore(deps): bump the github-actions group with 2 updates (#5006)

Bumps the github-actions group with 2 updates: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `astral-sh/setup-uv` from 6 to 7
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v6...v7)

Updates `actions/download-artifact` from 6 to 7
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: stabilize packaged runtime pip/ssl behavior and mac font fallback (#5007)

* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: 修复 Windows 打包版后端重启失败问题 (#5009)

* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: avoid frozen restart crash from multiprocessing import

* fix: include missing frozen dependencies for windows backend

* fix: use execv for stable backend reboot args

* Revert "fix: use execv for stable backend reboot args"

This reverts commit 9cc27becff.

* Revert "fix: include missing frozen dependencies for windows backend"

This reverts commit 52554bea1f.

* Revert "fix: avoid frozen restart crash from multiprocessing import"

This reverts commit 10548645b0.

* fix: reset pyinstaller onefile env before reboot

* fix: unify electron restart path and tray-exit backend cleanup

* fix: stabilize desktop restart detection and frozen reboot args

* fix: make dashboard restart wait detection robust

* fix: revert dashboard restart waiting interaction tweaks

* fix: pass auth token for desktop graceful restart

* fix: avoid false failure during graceful restart wait

* fix: start restart waiting before electron restart call

* fix: harden restart waiting and reboot arg parsing

* fix: parse start_time as numeric timestamp

* fix: 修复app内重启异常,修复app内点击重启不能立刻提示重启,以及在后端就绪时及时刷新界面的问题 (#5013)

* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: avoid frozen restart crash from multiprocessing import

* fix: include missing frozen dependencies for windows backend

* fix: use execv for stable backend reboot args

* Revert "fix: use execv for stable backend reboot args"

This reverts commit 9cc27becff.

* Revert "fix: include missing frozen dependencies for windows backend"

This reverts commit 52554bea1f.

* Revert "fix: avoid frozen restart crash from multiprocessing import"

This reverts commit 10548645b0.

* fix: reset pyinstaller onefile env before reboot

* fix: unify electron restart path and tray-exit backend cleanup

* fix: stabilize desktop restart detection and frozen reboot args

* fix: make dashboard restart wait detection robust

* fix: revert dashboard restart waiting interaction tweaks

* fix: pass auth token for desktop graceful restart

* fix: avoid false failure during graceful restart wait

* fix: start restart waiting before electron restart call

* fix: harden restart waiting and reboot arg parsing

* fix: parse start_time as numeric timestamp

* fix: preserve windows frozen reboot argv quoting

* fix: align restart waiting with electron restart timing

* fix: tighten graceful restart and unmanaged kill safety

* chore: bump version to 4.15.0 (#5003)

* fix: add reminder for v4.14.8 users regarding manual redeployment due to a bug

* fix: harden plugin dependency loading in frozen app runtime (#5015)

* fix: compare plugin versions semantically in market updates

* fix: prioritize plugin site-packages for in-process pip

* fix: reload starlette from plugin target site-packages

* fix: harden plugin dependency import precedence in frozen runtime

* fix: improve plugin dependency conflict handling

* refactor: simplify plugin conflict checks and version utils

* fix: expand transitive plugin dependencies for conflict checks

* fix: recover conflicting plugin dependencies during module prefer

* fix: reuse renderer restart flow for tray backend restart

* fix: add recoverable plugin dependency conflict handling

* revert: remove plugin version comparison changes

* fix: add missing tray restart backend labels

* feat: adding support for media and quoted message attachments for feishu (#5018)

* docs: add AUR installation method (#4879)

* docs: sync system package manager installation instructions to all languages

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix/typo

* refactor: update system package manager installation instructions for Arch Linux across multiple language README files

* feat: add installation command for AstrBot in multiple language README files

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>

* fix(desktop): 为 Electron 与后端日志增加按大小轮转 (#5029)

* fix(desktop): rotate electron and backend logs

* refactor(desktop): centralize log rotation defaults and debug fs errors

* fix(desktop): harden rotation fs ops and buffer backend log writes

* refactor(desktop): extract buffered logger and reduce sync stat calls

* refactor(desktop): simplify rotation flow and harden logger config

* fix(desktop): make app logging async and flush-safe

* fix: harden app log path switching and debug-gated rotation errors

* fix: cap buffered log chunk size during path switch

* feat: add first notice feature with multilingual support and UI integration

* fix: 提升打包版桌面端启动稳定性并优化插件依赖处理 (#5031)

* fix(desktop): rotate electron and backend logs

* refactor(desktop): centralize log rotation defaults and debug fs errors

* fix(desktop): harden rotation fs ops and buffer backend log writes

* refactor(desktop): extract buffered logger and reduce sync stat calls

* refactor(desktop): simplify rotation flow and harden logger config

* fix(desktop): make app logging async and flush-safe

* fix: harden app log path switching and debug-gated rotation errors

* fix: cap buffered log chunk size during path switch

* fix: avoid redundant plugin reinstall and upgrade electron

* fix: stop webchat tasks cleanly and bind packaged backend to localhost

* fix: unify platform shutdown and await webchat listener cleanup

* fix: improve startup logs for dashboard and onebot listeners

* fix: revert extra startup service logs

* fix: harden plugin import recovery and webchat listener cleanup

* fix: pin dashboard ci node version to 24.13.0

* fix: avoid duplicate webchat listener cleanup on terminate

* refactor: clarify platform task lifecycle management

* fix: continue platform shutdown when terminate fails

* feat: temporary file handling and introduce TempDirCleaner (#5026)

* feat: temporary file handling and introduce TempDirCleaner

- Updated various modules to use `get_astrbot_temp_path()` instead of `get_astrbot_data_path()` for temporary file storage.
- Renamed temporary files for better identification and organization.
- Introduced `TempDirCleaner` to manage the size of the temporary directory, ensuring it does not exceed a specified limit by deleting the oldest files.
- Added configuration option for maximum temporary directory size in the dashboard.
- Implemented tests for `TempDirCleaner` to verify cleanup functionality and size management.

* ruff

* fix: close unawaited reset coroutine on early return (#5033)

When an OnLLMRequestEvent hook stops event propagation, the
reset_coro created by build_main_agent was never awaited, causing
a RuntimeWarning. Close the coroutine explicitly before returning.

Fixes #5032

Co-authored-by: Limitless2023 <limitless@users.noreply.github.com>

* fix: update error logging message for connection failures

* docs: clean and sync README (#5014)

* fix: close missing div in README

* fix: sync README_zh-TW with README

* fix: sync README

* fix: correct typo

correct url in README_en README_fr README_ru

* docs: sync README_en with README

* Update README_en.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: provider extra param dialog key display error

* chore: ruff format

* feat: add send_chat_action for Telegram platform adapter (#5037)

* feat: add send_chat_action for Telegram platform adapter

Add typing/upload indicator when sending messages via Telegram.
- Added _send_chat_action helper method for sending chat actions
- Send appropriate action (typing, upload_photo, upload_document, upload_voice)
  before sending different message types
- Support streaming mode with typing indicator
- Support supergroup with message_thread_id

* refactor(telegram): extract chat action helpers and add throttling

- Add ACTION_BY_TYPE mapping for message type to action priority
- Add _get_chat_action_for_chain() to determine action from message chain
- Add _send_media_with_action() for upload → send → restore typing pattern
- Add _ensure_typing() helper for typing status
- Add chat action throttling (0.5s) in streaming mode to avoid rate limits
- Update type annotation to ChatAction | str for better static checking

* feat(telegram): implement send_typing method for Telegram platform

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: 修复更新日志、官方文档弹窗双滚动条问题 (#5060)

* docs: sync and fix readme typo (#5055)

* docs: fix index typo

* docs: fix typo in README_en.md

- 移除英文README中意外出现的俄语,并替换为英语

* docs: fix html typo

- remove unused '</p>'

* docs: sync table with README

* docs: sync README header format

- keep the README header format consistent

* doc: sync key features

* style: format files

- Fix formatting issues from previous PR

* fix: correct md anchor link

* docs: correct typo in README_fr.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* docs: correct typo in README_zh-TW.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix: 修复备份时缺失的人格文件夹映射 (#5042)

* feat: QQ 官方机器人平台支持主动推送消息、私聊场景下支持接收文件 (#5066)

* feat: QQ 官方机器人平台支持主动推送消息、私聊场景下支持接收文件

* feat: enhance QQOfficialWebhook to remember session scenes for group, channel, and friend messages

* perf: 优化分段回复间隔时间的初始化逻辑 (#5068)

fixes: #5059

* fix: chunk err when using openrouter deepseek (#5069)

* feat: add i18n supports for custom platform adapters (#5045)

* Feat: 为插件提供的适配器的元数据&i18n提供数据通路

* chore: update docstrings with pull request references

Added references to pull request 5045 in docstrings.

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: 完善转发引用解析与图片回退并支持配置化控制 (#5054)

* feat: support fallback image parsing for quoted messages

* fix: fallback parse quoted images when reply chain has placeholders

* style: format network utils with ruff

* test: expand quoted parser coverage and improve fallback diagnostics

* fix: fallback to text-only retry when image requests fail

* fix: tighten image fallback and resolve nested quoted forwards

* refactor: simplify quoted message extraction and dedupe images

* fix: harden quoted parsing and openai error candidates

* fix: harden quoted image ref normalization

* refactor: organize quoted parser settings and logging

* fix: cap quoted fallback images and avoid retry loops

* refactor: split quoted message parser into focused modules

* refactor: share onebot segment parsing logic

* refactor: unify quoted message parsing flow

* feat: move quoted parser tuning to provider settings

* fix: add missing i18n metadata for quoted parser settings

* chore: refine forwarded message setting labels

* fix: add config tabs and routing for normal and system configurations

* chore: bump version to 4.16.0 (#5074)

* feat: add LINE platform support with adapter and configuration (#5085)

* fix-correct-FIRST_NOTICE.md-locale-path-resolution (#5083) (#5082)

* fix:修改配置文件目录

* fix:添加备选的FIRST_NOTICE.zh-CN.md用于兼容

* fix: remove unnecessary frozen flag from requirements export in Dockerfile

fixes: #5089

* fix #5089: add uv lock step in Dockerfile before export (#5091)

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* feat: support hot reload after plugin load failure (#5043)

* add :Support hot reload after plugin load failure

* Apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix:reformat code

* fix:reformat code

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* feat: add fallback chat model chain in tool loop runner (#5109)

* feat: implement fallback provider support for chat models and update configuration

* feat: enhance provider selection display with count and chips for selected providers

* feat: update fallback chat providers to use provider settings and add warning for non-list fallback models

* feat: add Afdian support card to resources section in WelcomePage

* feat: replace colorlog with loguru for enhanced logging support (#5115)

* feat: add SSL configuration options for WebUI and update related logging (#5117)

* chore: bump version to 4.17.0

* fix: handle list format content from OpenAI-compatible APIs (#5128)

* fix: handle list format content from OpenAI-compatible APIs

Some LLM providers (e.g., GLM-4.5V via SiliconFlow) return content as
list[dict] format like [{'type': 'text', 'text': '...'}] instead of
plain string. This causes the raw list representation to be displayed
to users.

Changes:
- Add _normalize_content() helper to extract text from various content formats
- Use json.loads instead of ast.literal_eval for safer parsing
- Add size limit check (8KB) before attempting JSON parsing
- Only convert lists that match OpenAI content-part schema (has 'type': 'text')
  to avoid collapsing legitimate list-literal replies like ['foo', 'bar']
- Add strip parameter to preserve whitespace in streaming chunks
- Clean up orphan </think> tags that may leak from some models

Fixes #5124

* fix: improve content normalization safety

- Try json.loads first, fallback to ast.literal_eval for single-quoted
  Python literals to avoid corrupting apostrophes (e.g., "don't")
- Coerce text values to str to handle null or non-string text fields

* fix: update retention logic in LogManager to handle backup count correctly

* chore: bump version to 4.17.1

* docs: Added instructions for deploying AstrBot using AstrBot Launcher. (#5136)

Added instructions for deploying AstrBot using AstrBot Launcher.

* fix: add MCP tools to function tool set in _plugin_tool_fix (#5144)

* fix: add support for collecting data from builtin stars in electron pyinstaller build (#5145)

* chore: bump version to 4.17.1

* chore: ruff format

* fix: prevent updates for AstrBot launched via launcher

* fix(desktop): include runtime deps for builtin plugins in backend build (#5146)

* fix: 'Plain' object has no attribute 'text' when using python 3.14 (#5154)

* fix: enhance plugin metadata handling by injecting attributes before instantiation (#5155)

* fix: enhance handle_result to support event context and webchat image sending

* chore: bump version to 4.17.3

* chore: ruff format

* feat: add NVIDIA provider template (#5157)

fixes: #5156

* feat: enhance provider sources panel with styled menu and mobile support

* fix: improve permission denied message for local execution in Python and shell tools

* feat: enhance PersonaForm component with responsive design and improved styling (#5162)

fix: #5159

* ui(CronJobPage): fix action column buttons overlapping in CronJobPage (#5163)

- 修改前:操作列容器仅使用 `d-flex`,在页面宽度变窄时,子元素(开关和删除按钮)会因为宽度挤压而发生视觉重叠,甚至堆叠在一起。
- 修改后:
    1. 为容器添加了 `flex-nowrap`,强制禁止子元素换行。
    2. 设置了 `min-width: 140px`,确保该列拥有固定的保护空间,防止被其他长文本列挤压。
    3. 增加了 `gap: 12px` 间距,提升了操作辨识度并优化了点击体验。

* feat: add unsaved changes notice to configuration page and update messages

* feat: implement search functionality in configuration components and update UI (#5168)

* feat: add FAQ link to vertical sidebar and update navigation for localization

* feat: add announcement section to WelcomePage and localize announcement title

* chore: bump version to 4.17.4

* feat: supports send markdown message in qqofficial (#5173)

* feat: supports send markdown message in qqofficial

closes: #1093 #918 #4180 #4264

* ruff format

* fix: prevent duplicate error message when all LLM providers fail (#5183)

* fix: 修复选择配置文件进入配置文件管理弹窗直接关闭弹窗显示的配置文件不正确 (#5174)

* feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage (#5190)

* feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage

* feat: update random plugin selection logic to use pluginMarketData and refresh on relevant events

* feat: supports aihubmix

* docs: update readme

* chore: ruff format

* feat: add LINE support to multiple language README files

* feat(core): add plugin error hook for custom error routing (#5192)

* feat(core): add plugin error hook for custom error routing

* fix(core): align plugin error suppression with event stop state

* refactor: extract Voice_messages_forbidden fallback into shared helper with typed BadRequest exception (#5204)

- Add _send_voice_with_fallback helper to deduplicate voice forbidden handling
- Catch telegram.error.BadRequest instead of bare Exception with string matching
- Add text field to Record component to preserve TTS source text
- Store original text in Record during TTS conversion for use as document caption
- Skip _send_chat_action when chat_id is empty to avoid unnecessary warnings

* chore: bump version to 4.17.5

* feat: add admin permission checks for Python and Shell execution (#5214)

* fix: 改进微信公众号被动回复处理机制,引入缓冲与分片回复,并优化超时行为 (#5224)

* 修复wechat official 被动回复功能

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: 修复仅发送 JSON 消息段时的空消息回复报错 (#5208)

* Fix Register_Stage

· 补全 JSON 消息判断,修复发送 JSON 消息时遇到 “消息为空,跳过发送阶段” 的问题。
· 顺带补全其它消息类型判断。
Co-authored-by: Pizero <zhaory200707@outlook.com>

* Fix formatting and comments in stage.py

* Format stage.py

---------

Co-authored-by: Pizero <zhaory200707@outlook.com>

* docs: update related repo links

* fix(core): terminate active events on reset/new/del to prevent stale responses (#5225)

* fix(core): terminate active events on reset/new/del to prevent stale responses

Closes #5222

* style: fix import sorting in scheduler.py

* chore: remove Electron desktop pipeline and switch to tauri repo (#5226)

* ci: remove Electron desktop build from release pipeline

* chore: remove electron desktop and switch to tauri release trigger

* ci: remove desktop workflow dispatch trigger

* refactor: migrate data paths to astrbot_path helpers

* fix: point desktop update prompt to AstrBot-desktop releases

* fix: update feature request template for clarity and consistency in English and Chinese

* Feat/config leave confirm (#5249)

* feat: 配置文件增加未保存提示弹窗

* fix: 移除unsavedChangesDialog插件使用组件方式实现弹窗

* feat: add support for plugin astrbot-version and platform requirement checks (#5235)

* feat: add support for plugin astrbot-version and platform requirement checks

* fix: remove unsupported platform and version constraints from metadata.yaml

* fix: remove restriction on 'v' in astrbot_version specification format

* ruff format

* feat: add password confirmation when changing password (#5247)

* feat: add password confirmation when changing password

Fixes #5177

Adds a password confirmation field to prevent accidental password typos.

Changes:
- Backend: validate confirm_password matches new_password
- Frontend: add confirmation input with validation
- i18n: add labels and error messages for password mismatch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(auth): improve error message for password confirmation mismatch

* fix(auth): update password hashing logic and improve confirmation validation

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题 (#5250)

* fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题

修复 _normalize_content 函数未处理 dict 类型 content 的问题。
当 LLM 返回 {"type": "text", "text": "..."} 格式的 content 时,
现在会正确提取 text 字段而非直接转为字符串。

同时改进 fallback 行为,对 None 值返回空字符串。

Fixes #5244

* Update warning message for unexpected dict format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* chore: remove outdated heihe.md documentation file

* fix: all mcp tools exposed to main agent (#5252)

* fix: enhance PersonaForm layout and improve tool selection display

* fix: update tool status display and add localization for inactive tools

* fix: remove additionalProperties from tool schema properties (#5253)

fixes: #5217

* fix: simplify error messages for account edit validation

* fix: streamline error response for empty new username and password in account edit

* chore: bump vertion to 4.17.6

* feat: add OpenRouter provider support and icon

* chore: ruff format

* refactor(dashboard): replace legacy isElectron bridge fields with isDesktop (#5269)

* refactor dashboard desktop bridge fields from isElectron to isDesktop

* refactor dashboard runtime detection into shared helper

* fix: update contributor avatar image URL to include max size and columns (#5268)

* feat: astrbot http api (#5280)

* feat: astrbot http api

* Potential fix for code scanning alert no. 34: Use of a broken or weak cryptographic hashing algorithm on sensitive data

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix: improve error handling for missing attachment path in file upload

* feat: implement paginated retrieval of platform sessions for creators

* feat: refactor attachment directory handling in ChatRoute

* feat: update API endpoint paths for file and message handling

* feat: add documentation link to API key management section in settings

* feat: update API key scopes and related configurations in API routes and tests

* feat: enhance API key expiration options and add warning for permanent keys

* feat: add UTC normalization and serialization for API key timestamps

* feat: implement chat session management and validation for usernames

* feat: ignore session_id type chunks in message processing

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* feat(dashboard): improve plugin platform support display and mobile accessibility (#5271)

* feat(dashboard): improve plugin platform support display and mobile accessibility

- Replace hover-based tooltips with interactive click menus for platform support information.
- Fix mobile touch issues by introducing explicit state control for status capsules.
- Enhance UI aesthetics with platform-specific icons and a structured vertical list layout.
- Add dynamic chevron icons to provide clear visual cues for expandable content.

* refactor(dashboard): refactor market card with computed properties for performance

* refactor(dashboard): unify plugin platform support UI with new reusable chip component

- Create shared 'PluginPlatformChip' component to encapsulate platform meta display.
- Fix mobile interaction bugs by simplifying menu triggers and event handling.
- Add stacked platform icon previews and dynamic chevron indicators within capsules.
- Improve information hierarchy using structured vertical lists for platform details.
- Optimize rendering efficiency with computed properties across both card views.

* fix: qq official guild message send error (#5287)

* fix: qq official guild message send error

* Update astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* 更新readme文档,补充桌面app说明,并向前移动位置 (#5297)

* docs: update desktop deployment section in README

* docs: refine desktop and launcher deployment descriptions

* Update README.md

* feat: add Anthropic Claude Code OAuth provider and adaptive thinking support (#5209)

* feat: add Anthropic Claude Code OAuth provider and adaptive thinking support

* fix: add defensive guard for metadata overrides and align budget condition with docs

* refactor: adopt sourcery-ai suggestions for OAuth provider

- Use use_api_key=False in OAuth subclass to avoid redundant
  API-key client construction before replacing with auth_token client
- Generalize metadata override helper to merge all dict keys
  instead of only handling 'limit', improving extensibility

* Feat/telegram command alias register  #5233 (#5234)

* feat: support registering command aliases for Telegram

Now when registering commands with aliases, all aliases will be
registered as Telegram bot commands in addition to the main command.

Example:
    @register_command(command_name="draw", alias={"画", "gen"})
Now /draw, /画, and /gen will all appear in the Telegram command menu.

* feat(telegram): add duplicate command name warning when registering commands

Log a warning when duplicate command names are detected during Telegram
command registration to help identify configuration conflicts.

* refactor: remove Anthropic OAuth provider implementation and related metadata overrides

* fix: 修复新建对话时因缺少会话ID导致配置绑定失败的问题 (#5292)

* fix:尝试修改

* fix:添加详细日志

* fix:进行详细修改,并添加日志

* fix:删除所有日志

* fix: 增加安全访问函数

- 给 localStorage 访问加了 try/catch + 可用性判断:dashboard/src/utils/chatConfigBinding.ts:13
- 新增 getFromLocalStorage/setToLocalStorage(在受限存储/无痕模式下异常时回退/忽略)
- getStoredDashboardUsername() / getStoredSelectedChatConfigId() 改为走安全读取:dashboard/src/utils/chatConfigBinding.ts:36       - 新增 setStoredSelectedChatConfigId(),写入失败静默忽略:dashboard/src/utils/chatConfigBinding.ts:44
- 把 ConfigSelector.vue 里直接 localStorage.getItem/setItem 全部替换为上述安全方法:dashboard/src/components/chat/ConfigSelector.vue:81
- 已重新跑过 pnpm run typecheck,通过。

* rm:删除个人用的文档文件

* Revert "rm:删除个人用的文档文件"

This reverts commit 0fceee0543.

* rm:删除个人用的文档文件

* rm:删除个人用的文档文件

* chore: bump version to 4.18.0

* fix(SubAgentPage): 当中间的介绍文本非常长时,Flex 布局会自动挤压右侧的控制按钮区域 (#5306)

* fix: 修复新版本插件市场出现插件显示为空白的 bug;纠正已安装插件卡片的排版,统一大小 (#5309)

* fix(ExtensionCard): 解决插件卡片大小不统一的问题

* fix(MarketPluginCard): 解决插件市场不加载插件的问题 (#5303)

* feat: supports spawn subagent as a background task that not block the main agent workflow (#5081)

* feat:为subagent添加后台任务参数

* ruff

* fix: update terminology from 'handoff mission' to 'background task' and refactor related logic

* fix: update terminology from 'background_mission' to 'background_task' in HandoffTool and related logic

* fix(HandoffTool): update background_task description for clarity on usage

---------

Co-authored-by: Soulter <905617992@qq.com>

* cho

* fix: 修复 aiohttp 版本过新导致 qq-botpy 报错的问题 (#5316)

* chore: ruff format

* fix: remove hard-coded 6s timeout from tavily request

* fix: remove changelogs directory from .dockerignore

* feat(dashboard): make release redirect base URL configurable (#5330)

* feat(dashboard): make desktop release base URL configurable

* refactor(dashboard): use generic release base URL env with upstream default

* fix(dashboard): guard release base URL normalization when env is unset

* refactor(dashboard): use generic release URL helpers and avoid latest suffix duplication

* feat: add stop functionality for active agent sessions and improve handling of stop requests (#5380)

* feat: add stop functionality for active agent sessions and improve handling of stop requests

* feat: update stop button icon and tooltip in ChatInput component

* fix: correct indentation in tool call handling within ChatRoute class

* fix: chatui cannot persist file segment (#5386)

* fix(plugin): update plugin directory handling for reserved plugins (#5369)

* fix(plugin): update plugin directory handling for reserved plugins

* fix(plugin): add warning logs for missing plugin name, object, directory, and changelog

* chore(README): updated with README.md (#5375)

* chore(README): updated with README.md

* Update README_fr.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Update README_zh-TW.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* feat: add image urls / paths supports for subagent (#5348)

* fix: 修复5081号PR在子代理执行后台任务时,未正确使用系统配置的流式/非流请求的问题(#5081)

* feat:为子代理增加远程图片URL参数支持

* fix: update description for image_urls parameter in HandoffTool to clarify usage in multimodal tasks

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat: add hot reload when failed to load plugins (#5334)

* feat:add hot reload when failed to load plugins

* apply bot suggestions

* fix(chatui): add copy rollback path and error message. (#5352)

* fix(chatui): add copy rollback path and error message.

* fix(chatui): fixed textarea leak in the copy button.

* fix(chatui): use color styles from the component library.

* fix: 处理配置文件中的 UTF-8 BOM 编码问题 (#5376)

* fix(config): handle UTF-8 BOM in configuration file loading

Problem:
On Windows, some text editors (like Notepad) automatically add UTF-8 BOM
to JSON files when saving. This causes json.decoder.JSONDecodeError:
"Unexpected UTF-8 BOM" and AstrBot fails to start when cmd_config.json
contains BOM.

Solution:
Add defensive check to strip UTF-8 BOM (\ufeff) if present before
parsing JSON configuration file.

Impact:
- Improves robustness and cross-platform compatibility
- No breaking changes to existing functionality
- Fixes startup failure when configuration file has UTF-8 BOM encoding

Relates-to: Windows editor compatibility issues

* style: fix code formatting with ruff

Fix single quote to double quote to comply with project code style.

* feat: add plugin load&unload hook (#5331)

* 添加了插件的加载完成和卸载完成的钩子事件

* 添加了插件的加载完成和卸载完成的钩子事件

* format code with ruff

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* test: enhance test framework with comprehensive fixtures and mocks (#5354)

* test: enhance test framework with comprehensive fixtures and mocks

- Add shared mock builders for aiocqhttp, discord, telegram
- Add test helpers for platform configs and mock objects
- Expand conftest.py with test profile support
- Update coverage test workflow configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(tests): 移动并重构模拟 LLM 响应和消息组件函数

* fix(tests): 优化 pytest_runtest_setup 中的标记检查逻辑

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add comprehensive tests for message event handling (#5355)

* test: add comprehensive tests for message event handling

- Add AstrMessageEvent unit tests (688 lines)
- Add AstrBotMessage unit tests
- Enhance smoke tests with message event scenarios

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: improve message type handling and add defensive tests

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add support for showing tool call results in agent execution (#5388)

closes: #5329

* fix: resolve pipeline and star import cycles (#5353)

* fix: resolve pipeline and star import cycles

- Add bootstrap.py and stage_order.py to break circular dependencies
- Export Context, PluginManager, StarTools from star module
- Update pipeline __init__ to defer imports
- Split pipeline initialization into separate bootstrap module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add logging for get_config() failure in Star class

* fix: reorder logger initialization in base.py

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: enable computer-use tools for subagent handoff (#5399)

* fix: enforce admin guard for sandbox file transfer tools (#5402)

* fix: enforce admin guard for sandbox file transfer tools

* refactor: deduplicate computer tools admin permission checks

* fix: add missing space in permission error message

* fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性 (#5391)

* fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性

原因 (Necessity):
1. 内核一致性:AstrBot 内核的 Record 和 Video 组件均具备识别 `file:///` 协议头的逻辑,但 File 组件此前缺失此功能,导致行为不统一。
2. OneBot 协议合规:OneBot 11 标准要求本地文件路径必须使用 `file:///` 协议头。此前驱动层未对裸路径进行自动转换,导致发送本地文件时常触发 retcode 1200 (识别URL失败) 错误。
3. 容器环境适配:在 Docker 等路径隔离环境下,裸路径更容易因驱动或协议端的解析歧义而失效。

更改 (Changes):
- [astrbot/core/message/components.py]:
  - 在 File.get_file() 中增加对 `file:///` 前缀的识别与剥离逻辑,使其与 Record/Video 组件行为对齐。
- [astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py]:
  - 在发送文件前增加自动修正逻辑:若路径为绝对路径且未包含协议头,驱动层将自动补全 `file:///` 前缀。
  - 对 http、base64 及已有协议头,确保不干扰原有的正常传输逻辑。

影响 (Impact):
- 以完全兼容的方式增强了文件发送的鲁棒性。
- 解决了插件在发送日志等本地生成的压缩包时,因路径格式不规范导致的发送失败问题。

* refactor(core): 根据 cr 建议,规范化文件 URI 生成与解析逻辑,优化跨平台兼容性

原因 (Necessity):
1. 修复原生路径与 URI 转换在 Windows 下的不对称问题。
2. 规范化 file: 协议头处理,确保符合 RFC 标准并能在 Linux/Windows 间稳健切换。
3. 增强协议判定准确度,防止对普通绝对路径的误处理。

更改 (Changes):
- [astrbot/core/platform/sources/aiocqhttp]:
  - 弃用手动拼接,改用 `pathlib.Path.as_uri()` 生成标准 URI。
  - 将协议检测逻辑从前缀匹配优化为包含性检测 ("://")。
- [astrbot/core/message/components]:
  - 重构 `File.get_file` 解析逻辑,支持对称处理 2/3 斜杠格式。
  - 针对 Windows 环境增加了对 `file:///C:/` 格式的自动修正,避免 `os.path` 识别失效。
- [data/plugins/astrbot_plugin_logplus]:
  - 在直接 API 调用中同步应用 URI 规范化处理。

影响 (Impact):
- 解决 Docker 环境中因路径不规范导致的 "识别URL失败" 报错。
- 提升了本体框架在 Windows 系统下的文件操作鲁棒性。

* i18n(SubAgentPage): complete internationalization for subagent orchestration page (#5400)

* i18n: complete internationalization for subagent orchestration page

- Replace hardcoded English strings in [SubAgentPage.vue] with i18n keys.
- Update `en-US` and `zh-CN` locales with missing hints, validation messages, and empty state translations.
- Fix translation typos and improve consistency across the SubAgent orchestration UI.

* fix(bug_risk): 避免在模板中的翻译调用上使用 || 'Close' 作为回退值。

* fix(aiocqhttp): enhance shutdown process for aiocqhttp adapter (#5412)

* fix: pass embedding dimensions to provider apis (#5411)

* fix(context): log warning when platform not found for session

* fix(context): improve logging for platform not found in session

* chore: bump version to 4.18.2

* chore: bump version to 4.18.2

* chore: bump version to 4.18.2

* fix: Telegram voice message format (OGG instead of WAV) causing issues with OpenAI STT API (#5389)

* chore: ruff format

* feat(dashboard): add generic desktop app updater bridge (#5424)

* feat(dashboard): add generic desktop app updater bridge

* fix(dashboard): address updater bridge review feedback

* fix(dashboard): unify updater bridge types and error logging

* fix(dashboard): consolidate updater bridge typings

* fix(conversation): retain existing persona_id when updating conversation

* fix(dashboard): 修复设置页新建 API Key 后复制失败问题 (#5439)

* Fix: GitHub proxy not displaying correctly in WebUI (#5438)

* fix(dashboard): preserve custom GitHub proxy setting on reload

* fix(dashboard): keep github proxy selection persisted in settings

* fix(persona): enhance persona resolution logic for conversations and sessions

* fix: ensure tool call/response pairing in context truncation (#5417)

* fix: ensure tool call/response pairing in context truncation

* refactor: simplify fix_messages to single-pass state machine

* perf(cron): enhance future task session isolation

fixes: #5392

* feat: add useExtensionPage composable for managing plugin extensions

- Implemented a new composable `useExtensionPage` to handle various functionalities related to plugin management, including fetching extensions, handling updates, and managing UI states.
- Added support for conflict checking, plugin installation, and custom source management.
- Integrated search and filtering capabilities for plugins in the market.
- Enhanced user experience with dialogs for confirmations and notifications.
- Included pagination and sorting features for better plugin visibility.

* fix: clear markdown field when sending media messages via QQ Official Platform (#5445)

* fix: clear markdown field when sending media messages via QQ Official API

* refactor: use pop() to remove markdown key instead of setting None

* fix: cannot automatically get embedding dim when create embedding provider (#5442)

* fix(dashboard): 强化 API Key 复制临时节点清理逻辑

* fix(embedding): 自动检测改为探测 OpenAI embedding 最大可用维度

* fix: normalize openai embedding base url and add hint key

* i18n: add embedding_api_base hint translations

* i18n: localize provider embedding/proxy metadata hints

* fix: show provider-specific embedding API Base URL hint as field subtitle

* fix(embedding): cap OpenAI detect_dim probes with early short-circuit

* fix(dashboard): return generic error on provider adapter import failure

* 回退检测逻辑

* fix: 修复Pyright静态类型检查报错 (#5437)

* refactor: 修正 Sqlite 查询、下载回调、接口重构与类型调整

* feat: 为 OneBotClient 增加 CallAction 协议与异步调用支持

* fix(telegram): avoid duplicate message_thread_id in streaming (#5430)

* perf: batch metadata query in KB retrieval to fix N+1 problem (#5463)

* perf: batch metadata query in KB retrieval to fix N+1 problem

Replace N sequential get_document_with_metadata() calls with a single
get_documents_with_metadata_batch() call using SQL IN clause.

Benchmark results (local SQLite):
- 10 docs: 10.67ms → 1.47ms (7.3x faster)
- 20 docs: 26.00ms → 2.68ms (9.7x faster)
- 50 docs: 63.87ms → 2.79ms (22.9x faster)

* refactor: use set[str] param type and chunk IN clause for SQLite safety

Address review feedback:
- Change doc_ids param from list[str] to set[str] to avoid unnecessary conversion
- Chunk IN clause into batches of 900 to stay under SQLite's 999 parameter limit
- Remove list() wrapping at call site, pass set directly

* fix:fix the issue where incomplete cleanup of residual plugins occurs… (#5462)

* fix:fix the issue where incomplete cleanup of residual plugins occurs in the failed loading of plugins

* fix:ruff format,apply bot suggestions

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* chore: 为类型检查添加 TYPE_CHECKING 的导入与阶段类型引用 (#5474)

* fix(line): line adapter does not appear in the add platform dialog

fixes: #5477

* [bug]查看介入教程line前往错误界面的问题 (#5479)

Fixes #5478

* chore: bump version to 4.18.3

* feat: implement follow-up message handling in ToolLoopAgentRunner (#5484)

* feat: implement follow-up message handling in ToolLoopAgentRunner

* fix: correct import path for follow-up module in InternalAgentSubStage

* feat: implement websockets transport mode selection for chat (#5410)

* feat: implement websockets transport mode selection for chat

- Added transport mode selection (SSE/WebSocket) in the chat component.
- Updated conversation sidebar to include transport mode options.
- Integrated transport mode handling in message sending logic.
- Refactored message sending functions to support both SSE and WebSocket.
- Enhanced WebSocket connection management and message handling.
- Updated localization files for transport mode labels.
- Configured Vite to support WebSocket proxying.

* feat(webchat): refactor message parsing logic and integrate new parsing function

* feat(chat): add websocket API key extraction and scope validation

* Revert "可选后端,实现前后端分离" (#5536)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: can <51474963+weijintaocode@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: letr <123731298+letr007@users.noreply.github.com>
Co-authored-by: 搁浅 <id6543156918@gmail.com>
Co-authored-by: Helian Nuits <sxp20061207@163.com>
Co-authored-by: Gao Jinzhe <2968474907@qq.com>
Co-authored-by: DD斩首 <155905740+DDZS987@users.noreply.github.com>
Co-authored-by: Ubuntu <ubuntu@localhost.localdomain>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: エイカク <62183434+zouyonghe@users.noreply.github.com>
Co-authored-by: 鸦羽 <Raven95676@gmail.com>
Co-authored-by: Dt8333 <25431943+Dt8333@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Li-shi-ling <114913764+Li-shi-ling@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Limitless <127183162+Limitless2023@users.noreply.github.com>
Co-authored-by: Limitless2023 <limitless@users.noreply.github.com>
Co-authored-by: evpeople <54983536+evpeople@users.noreply.github.com>
Co-authored-by: SnowNightt <127504703+SnowNightt@users.noreply.github.com>
Co-authored-by: xzj0898 <62733743+xzj0898@users.noreply.github.com>
Co-authored-by: stevessr <89645372+stevessr@users.noreply.github.com>
Co-authored-by: Waterwzy <2916963017@qq.com>
Co-authored-by: NayukiMeko <MekoNayuki@outlook.com>
Co-authored-by: 時壹 <137363396+KBVsent@users.noreply.github.com>
Co-authored-by: sanyekana <Clhikari@qq.com>
Co-authored-by: Chiu Chun-Hsien <95356121+911218sky@users.noreply.github.com>
Co-authored-by: Dream Tokenizer <60459821+Trance-0@users.noreply.github.com>
Co-authored-by: NanoRocky <76585834+NanoRocky@users.noreply.github.com>
Co-authored-by: Pizero <zhaory200707@outlook.com>
Co-authored-by: 雪語 <167516635+YukiRa1n@users.noreply.github.com>
Co-authored-by: whatevertogo <1879483647@qq.com>
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: 香草味的纳西妲喵 <151599587+VanillaNahida@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Lovely Moe Moli <44719954+moemoli@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Minidoracat <minidora0702@gmail.com>
Co-authored-by: Chen <42998804+a61995987@users.noreply.github.com>
Co-authored-by: hanbings <hanbings@hanbings.io>
Co-authored-by: tangsenfei <155090747+tangsenfei@users.noreply.github.com>
Co-authored-by: PyuraMazo <1605025385@qq.com>
Co-authored-by: Axi404 <118950647+Axi404@users.noreply.github.com>
Co-authored-by: 氕氙 <2014440212@qq.com>
Co-authored-by: Yunhao Cao <18230652+realquantumcookie@users.noreply.github.com>
Co-authored-by: exynos <110159911+exynos967@users.noreply.github.com>
Co-authored-by: Luna_Dol <86590429+Luna-channel@users.noreply.github.com>
Co-authored-by: CCCCCCTV <64309817+CCCCCCTV@users.noreply.github.com>
Co-authored-by: CAICAII <3360776475@qq.com>
Co-authored-by: 圣达生物多 <qq3258819795@163.com>
2026-02-27 22:06:40 +08:00
LIghtJUNction
483048e3dc 同步主分支 (#5533)
* feat: add bocha web search tool (#4902)

* add bocha web search tool

* Revert "add bocha web search tool"

This reverts commit 1b36d75a17.

* add bocha web search tool

* fix: correct temporary_cache spelling and update supported tools for web search

* ruff

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: messages[x] assistant content must contain at least one part (#4928)

* fix: messages[x] assistant content must contain at least one part

fixes: #4876

* ruff format

* chore: bump version to 4.14.5 (#4930)

* feat: implement feishu / lark media file handling utilities for file, audio and video processing (#4938)

* feat: implement media file handling utilities for audio and video processing

* feat: refactor file upload handling for audio and video in LarkMessageEvent

* feat: add cleanup for failed audio and video conversion outputs in media_utils

* feat: add utility methods for sending messages and uploading files in LarkMessageEvent

* fix: correct spelling of 'temporary' in SharedPreferences class

* perf: optimize webchat and wecom ai queue lifecycle (#4941)

* perf: optimize webchat and wecom ai queue lifecycle

* perf: enhance webchat back queue management with conversation ID support

* fix: localize provider source config UI (#4933)

* fix: localize provider source ui

* feat: localize provider metadata keys

* chore: add provider metadata translations

* chore: format provider i18n changes

* fix: preserve metadata fields in i18n conversion

* fix: internationalize platform config and dialog

* fix: add Weixin official account platform icon

---------

Co-authored-by: Soulter <905617992@qq.com>

* chore: bump version to 4.14.6

* feat: add provider-souce-level proxy (#4949)

* feat: 添加 Provider 级别代理支持及请求失败日志

* refactor: simplify provider source configuration structure

* refactor: move env proxy fallback logic to log_connection_failure

* refactor: update client proxy handling and add terminate method for cleanup

* refactor: update no_proxy configuration to remove redundant subnet

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat(ComponentPanel):  implement permission management for dashboard (#4887)

* feat(backend): add permission update api

* feat(useCommandActions): add updatePermission action and translations

* feat(dashboard): implement permission editing ui

* style: fix import sorting in command.py

* refactor(backend): extract permission update logic to service

* feat(i18n): add success and failure messages for command updates

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat: 允许 LLM 预览工具返回的图片并自主决定是否发送 (#4895)

* feat: 允许 LLM 预览工具返回的图片并自主决定是否发送

* 复用 send_message_to_user 替代独立的图片发送工具

* feat: implement _HandleFunctionToolsResult class for improved tool response handling

* docs: add path handling guidelines to AGENTS.md

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat(telegram): 添加媒体组(相册)支持 / add media group (album) support (#4893)

* feat(telegram): 添加媒体组(相册)支持 / add media group (album) support

## 功能说明
支持 Telegram 的媒体组消息(相册),将多张图片/视频合并为一条消息处理,而不是分散成多条消息。

## 主要改动

### 1. 初始化媒体组缓存 (__init__)
- 添加 `media_group_cache` 字典存储待处理的媒体组消息
- 使用 2.5 秒超时收集媒体组消息(基于社区最佳实践)
- 最大等待时间 10 秒(防止永久等待)

### 2. 消息处理流程 (message_handler)
- 检测 `media_group_id` 判断是否为媒体组消息
- 媒体组消息走特殊处理流程,避免分散处理

### 3. 媒体组消息缓存 (handle_media_group_message)
- 缓存收到的媒体组消息
- 使用 APScheduler 实现防抖(debounce)机制
- 每收到新消息时重置超时计时器
- 超时后触发统一处理

### 4. 媒体组合并处理 (process_media_group)
- 从缓存中取出所有媒体项
- 使用第一条消息作为基础(保留文本、回复等信息)
- 依次添加所有图片、视频、文档到消息链
- 将合并后的消息发送到处理流程

## 技术方案论证

Telegram Bot API 在处理媒体组时的设计限制:
1. 将媒体组的每个消息作为独立的 update 发送
2. 每个 update 带有相同的 `media_group_id`
3. **不提供**组的总数、结束标志或一次性完整组的机制

因此,bot 必须自行收集消息,并通过硬编码超时(timeout/delay)等待可能延迟到达的消息。
这是目前唯一可靠的方案,被官方实现、主流框架和开发者社区广泛采用。

### 官方和社区证据:
- **Telegram Bot API 服务器实现(tdlib)**:明确指出缺少结束标志或总数信息
  https://github.com/tdlib/telegram-bot-api/issues/643

- **Telegram Bot API 服务器 issue**:讨论媒体组处理的不便性,推荐使用超时机制
  https://github.com/tdlib/telegram-bot-api/issues/339

- **Telegraf(Node.js 框架)**:专用媒体组中间件使用 timeout 控制等待时间
  https://github.com/DieTime/telegraf-media-group

- **StackOverflow 讨论**:无法一次性获取媒体组所有文件,必须手动收集
  https://stackoverflow.com/questions/50180048/telegram-api-get-all-uploaded-photos-by-media-group-id

- **python-telegram-bot 社区**:确认媒体组消息单独到达,需手动处理
  https://github.com/python-telegram-bot/python-telegram-bot/discussions/3143

- **Telegram Bot API 官方文档**:仅定义 `media_group_id` 为可选字段,不提供获取完整组的接口
  https://core.telegram.org/bots/api#message

## 实现细节
- 使用 2.5 秒超时收集媒体组消息(基于社区最佳实践)
- 最大等待时间 10 秒(防止永久等待)
- 采用防抖(debounce)机制:每收到新消息重置计时器
- 利用 APScheduler 实现延迟处理和任务调度

## 测试验证
-  发送 5 张图片相册,成功合并为一条消息
-  保留原始文本说明和回复信息
-  支持图片、视频、文档混合的媒体组
-  日志显示 Processing media group <media_group_id> with 5 items

## 代码变更
- 文件:astrbot/core/platform/sources/telegram/tg_adapter.py
- 新增代码:124 行
- 新增方法:handle_media_group_message(), process_media_group()

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor(telegram): 优化媒体组处理性能和可靠性

根据代码审查反馈改进:

1. 实现 media_group_max_wait 防止无限延迟
   - 跟踪媒体组创建时间,超过最大等待时间立即处理
   - 最坏情况下 10 秒内必定处理,防止消息持续到达导致无限延迟

2. 移除手动 job 查找优化性能
   - 删除 O(N) 的 get_jobs() 循环扫描
   - 依赖 replace_existing=True 自动替换任务

3. 重用 convert_message 减少代码重复
   - 统一所有媒体类型转换逻辑
   - 未来添加新媒体类型只需修改一处

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(telegram): handle missing message in media group processing and improve logging messages

---------

Co-authored-by: Ubuntu <ubuntu@localhost.localdomain>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>

* feat: add welcome feature with localized content and onboarding steps

* fix: correct height attribute to max-height for dialog component

* feat: supports electron app (#4952)

* feat: add desktop wrapper with frontend-only packaging

* docs: add desktop build docs and track dashboard lockfile

* fix: track desktop lockfile for npm ci

* fix: allow custom install directory for windows installer

* chore: migrate desktop workflow to pnpm

* fix(desktop): build AppImage only on Linux

* fix(desktop): harden packaged startup and backend bundling

* fix(desktop): adapt packaged restart and plugin dependency flow

* fix(desktop): prevent backend respawn race on quit

* fix(desktop): prefer pyproject version for desktop packaging

* fix(desktop): improve startup loading UX and reduce flicker

* ci: add desktop multi-platform release workflow

* ci: fix desktop release build and mac runner labels

* ci: disable electron-builder auto publish in desktop build

* ci: avoid electron-builder publish path in build matrix

* ci: normalize desktop release artifact names

* ci: exclude blockmap files from desktop release assets

* ci: prefix desktop release assets with AstrBot and purge blockmaps

* feat: add electron bridge types and expose backend control methods in preload script

* Update startup screen assets and styles

- Changed the icon from PNG to SVG format for better scalability.
- Updated the border color from #d0d0d0 to #eeeeee for a softer appearance.
- Adjusted the width of the startup screen from 460px to 360px for improved responsiveness.

* Update .gitignore to include package.json

* chore: remove desktop gitkeep ignore exceptions

* docs: update desktop troubleshooting for current runtime behavior

* refactor(desktop): modularize runtime and harden startup flow

---------

Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: dedupe preset messages (#4961)

* feat: enhance package.json with resource filters and compression settings

* chore: update Python version requirements to 3.12 (#4963)

* chore: bump version to 4.14.7

* feat: refactor release workflow and add special update handling for electron app (#4969)

* chore: bump version to 4.14.8 and bump faiss-cpu version up to date

* chore: auto ann fix by ruff (#4903)

* chore: auto fix by ruff

* refactor: 统一修正返回类型注解为 None/bool 以匹配实现

* refactor: 将 _get_next_page 改为异步并移除多余的请求错误抛出

* refactor: 将 get_client 的返回类型改为 object

* style: 为 LarkMessageEvent 的相关方法添加返回类型注解 None

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: prepare OpenSSL via vcpkg for Windows ARM64

* ci: change ghcr namespace

* chore: update pydantic dependency version (#4980)

* feat: add delete button to persona management dialog (#4978)

* Initial plan

* feat: add delete button to persona management dialog

- Added delete button to PersonaForm dialog (only visible when editing)
- Implemented deletePersona method with confirmation dialog
- Connected delete event to PersonaManager for proper handling
- Button positioned on left side of dialog actions for clear separation
- Uses existing i18n translations for delete button and messages

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: use finally block to ensure saving state is reset

- Moved `this.saving = false` to finally block in deletePersona
- Ensures UI doesn't stay in saving state after errors
- Follows best practices for state management

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* feat: enhance Dingtalk adapter with active push message and image, video, audio message type (#4986)

* fix: handle pip install execution in frozen runtime (#4985)

* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling

* fix: collect certifi data in desktop backend build (#4995)

* feat: 企业微信应用 支持主动消息推送,并优化企微应用、微信公众号、微信客服音频相关的处理 (#4998)

* feat: 企业微信智能机器人支持主动消息推送以及发送视频、文件等消息类型支持 (#4999)

* feat: enhance WecomAIBotAdapter and WecomAIBotMessageEvent for improved streaming message handling (#5000)

fixes: #3965

* feat: enhance persona tool management and update UI localization for subagent orchestration (#4990)

* feat: enhance persona tool management and update UI localization for subagent orchestration

* fix: remove debug logging for final ProviderRequest in build_main_agent function

* perf: 稳定源码与 Electron 打包环境下的 pip 安装行为,并修复非 Electron 环境下点击 WebUI 更新按钮时出现跳转对话框的问题 (#4996)

* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling

* fix: scope global data root to packaged electron runtime

* refactor: inline frozen runtime check for electron guard

* fix: prefer current interpreter for source pip installs

* fix: avoid resolving venv python symlink for pip

* refactor: share runtime environment detection utilities

* fix: improve error message when pip module is unavailable

* fix: raise ImportError when pip module is unavailable

* fix: preserve ImportError semantics for missing pip

* fix: 修复非electron app环境更新时仍然显示electron更新对话框的问题

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: 'HandoffTool' object has no attribute 'agent' (#5005)

* fix: 移动agent的位置到super().__init__之后

* add: 添加一行注释

* chore(deps): bump the github-actions group with 2 updates (#5006)

Bumps the github-actions group with 2 updates: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `astral-sh/setup-uv` from 6 to 7
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v6...v7)

Updates `actions/download-artifact` from 6 to 7
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: stabilize packaged runtime pip/ssl behavior and mac font fallback (#5007)

* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: 修复 Windows 打包版后端重启失败问题 (#5009)

* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: avoid frozen restart crash from multiprocessing import

* fix: include missing frozen dependencies for windows backend

* fix: use execv for stable backend reboot args

* Revert "fix: use execv for stable backend reboot args"

This reverts commit 9cc27becff.

* Revert "fix: include missing frozen dependencies for windows backend"

This reverts commit 52554bea1f.

* Revert "fix: avoid frozen restart crash from multiprocessing import"

This reverts commit 10548645b0.

* fix: reset pyinstaller onefile env before reboot

* fix: unify electron restart path and tray-exit backend cleanup

* fix: stabilize desktop restart detection and frozen reboot args

* fix: make dashboard restart wait detection robust

* fix: revert dashboard restart waiting interaction tweaks

* fix: pass auth token for desktop graceful restart

* fix: avoid false failure during graceful restart wait

* fix: start restart waiting before electron restart call

* fix: harden restart waiting and reboot arg parsing

* fix: parse start_time as numeric timestamp

* fix: 修复app内重启异常,修复app内点击重启不能立刻提示重启,以及在后端就绪时及时刷新界面的问题 (#5013)

* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: avoid frozen restart crash from multiprocessing import

* fix: include missing frozen dependencies for windows backend

* fix: use execv for stable backend reboot args

* Revert "fix: use execv for stable backend reboot args"

This reverts commit 9cc27becff.

* Revert "fix: include missing frozen dependencies for windows backend"

This reverts commit 52554bea1f.

* Revert "fix: avoid frozen restart crash from multiprocessing import"

This reverts commit 10548645b0.

* fix: reset pyinstaller onefile env before reboot

* fix: unify electron restart path and tray-exit backend cleanup

* fix: stabilize desktop restart detection and frozen reboot args

* fix: make dashboard restart wait detection robust

* fix: revert dashboard restart waiting interaction tweaks

* fix: pass auth token for desktop graceful restart

* fix: avoid false failure during graceful restart wait

* fix: start restart waiting before electron restart call

* fix: harden restart waiting and reboot arg parsing

* fix: parse start_time as numeric timestamp

* fix: preserve windows frozen reboot argv quoting

* fix: align restart waiting with electron restart timing

* fix: tighten graceful restart and unmanaged kill safety

* chore: bump version to 4.15.0 (#5003)

* fix: add reminder for v4.14.8 users regarding manual redeployment due to a bug

* fix: harden plugin dependency loading in frozen app runtime (#5015)

* fix: compare plugin versions semantically in market updates

* fix: prioritize plugin site-packages for in-process pip

* fix: reload starlette from plugin target site-packages

* fix: harden plugin dependency import precedence in frozen runtime

* fix: improve plugin dependency conflict handling

* refactor: simplify plugin conflict checks and version utils

* fix: expand transitive plugin dependencies for conflict checks

* fix: recover conflicting plugin dependencies during module prefer

* fix: reuse renderer restart flow for tray backend restart

* fix: add recoverable plugin dependency conflict handling

* revert: remove plugin version comparison changes

* fix: add missing tray restart backend labels

* feat: adding support for media and quoted message attachments for feishu (#5018)

* docs: add AUR installation method (#4879)

* docs: sync system package manager installation instructions to all languages

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix/typo

* refactor: update system package manager installation instructions for Arch Linux across multiple language README files

* feat: add installation command for AstrBot in multiple language README files

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>

* fix(desktop): 为 Electron 与后端日志增加按大小轮转 (#5029)

* fix(desktop): rotate electron and backend logs

* refactor(desktop): centralize log rotation defaults and debug fs errors

* fix(desktop): harden rotation fs ops and buffer backend log writes

* refactor(desktop): extract buffered logger and reduce sync stat calls

* refactor(desktop): simplify rotation flow and harden logger config

* fix(desktop): make app logging async and flush-safe

* fix: harden app log path switching and debug-gated rotation errors

* fix: cap buffered log chunk size during path switch

* feat: add first notice feature with multilingual support and UI integration

* fix: 提升打包版桌面端启动稳定性并优化插件依赖处理 (#5031)

* fix(desktop): rotate electron and backend logs

* refactor(desktop): centralize log rotation defaults and debug fs errors

* fix(desktop): harden rotation fs ops and buffer backend log writes

* refactor(desktop): extract buffered logger and reduce sync stat calls

* refactor(desktop): simplify rotation flow and harden logger config

* fix(desktop): make app logging async and flush-safe

* fix: harden app log path switching and debug-gated rotation errors

* fix: cap buffered log chunk size during path switch

* fix: avoid redundant plugin reinstall and upgrade electron

* fix: stop webchat tasks cleanly and bind packaged backend to localhost

* fix: unify platform shutdown and await webchat listener cleanup

* fix: improve startup logs for dashboard and onebot listeners

* fix: revert extra startup service logs

* fix: harden plugin import recovery and webchat listener cleanup

* fix: pin dashboard ci node version to 24.13.0

* fix: avoid duplicate webchat listener cleanup on terminate

* refactor: clarify platform task lifecycle management

* fix: continue platform shutdown when terminate fails

* feat: temporary file handling and introduce TempDirCleaner (#5026)

* feat: temporary file handling and introduce TempDirCleaner

- Updated various modules to use `get_astrbot_temp_path()` instead of `get_astrbot_data_path()` for temporary file storage.
- Renamed temporary files for better identification and organization.
- Introduced `TempDirCleaner` to manage the size of the temporary directory, ensuring it does not exceed a specified limit by deleting the oldest files.
- Added configuration option for maximum temporary directory size in the dashboard.
- Implemented tests for `TempDirCleaner` to verify cleanup functionality and size management.

* ruff

* fix: close unawaited reset coroutine on early return (#5033)

When an OnLLMRequestEvent hook stops event propagation, the
reset_coro created by build_main_agent was never awaited, causing
a RuntimeWarning. Close the coroutine explicitly before returning.

Fixes #5032

Co-authored-by: Limitless2023 <limitless@users.noreply.github.com>

* fix: update error logging message for connection failures

* docs: clean and sync README (#5014)

* fix: close missing div in README

* fix: sync README_zh-TW with README

* fix: sync README

* fix: correct typo

correct url in README_en README_fr README_ru

* docs: sync README_en with README

* Update README_en.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: provider extra param dialog key display error

* chore: ruff format

* feat: add send_chat_action for Telegram platform adapter (#5037)

* feat: add send_chat_action for Telegram platform adapter

Add typing/upload indicator when sending messages via Telegram.
- Added _send_chat_action helper method for sending chat actions
- Send appropriate action (typing, upload_photo, upload_document, upload_voice)
  before sending different message types
- Support streaming mode with typing indicator
- Support supergroup with message_thread_id

* refactor(telegram): extract chat action helpers and add throttling

- Add ACTION_BY_TYPE mapping for message type to action priority
- Add _get_chat_action_for_chain() to determine action from message chain
- Add _send_media_with_action() for upload → send → restore typing pattern
- Add _ensure_typing() helper for typing status
- Add chat action throttling (0.5s) in streaming mode to avoid rate limits
- Update type annotation to ChatAction | str for better static checking

* feat(telegram): implement send_typing method for Telegram platform

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: 修复更新日志、官方文档弹窗双滚动条问题 (#5060)

* docs: sync and fix readme typo (#5055)

* docs: fix index typo

* docs: fix typo in README_en.md

- 移除英文README中意外出现的俄语,并替换为英语

* docs: fix html typo

- remove unused '</p>'

* docs: sync table with README

* docs: sync README header format

- keep the README header format consistent

* doc: sync key features

* style: format files

- Fix formatting issues from previous PR

* fix: correct md anchor link

* docs: correct typo in README_fr.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* docs: correct typo in README_zh-TW.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix: 修复备份时缺失的人格文件夹映射 (#5042)

* feat: QQ 官方机器人平台支持主动推送消息、私聊场景下支持接收文件 (#5066)

* feat: QQ 官方机器人平台支持主动推送消息、私聊场景下支持接收文件

* feat: enhance QQOfficialWebhook to remember session scenes for group, channel, and friend messages

* perf: 优化分段回复间隔时间的初始化逻辑 (#5068)

fixes: #5059

* fix: chunk err when using openrouter deepseek (#5069)

* feat: add i18n supports for custom platform adapters (#5045)

* Feat: 为插件提供的适配器的元数据&i18n提供数据通路

* chore: update docstrings with pull request references

Added references to pull request 5045 in docstrings.

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: 完善转发引用解析与图片回退并支持配置化控制 (#5054)

* feat: support fallback image parsing for quoted messages

* fix: fallback parse quoted images when reply chain has placeholders

* style: format network utils with ruff

* test: expand quoted parser coverage and improve fallback diagnostics

* fix: fallback to text-only retry when image requests fail

* fix: tighten image fallback and resolve nested quoted forwards

* refactor: simplify quoted message extraction and dedupe images

* fix: harden quoted parsing and openai error candidates

* fix: harden quoted image ref normalization

* refactor: organize quoted parser settings and logging

* fix: cap quoted fallback images and avoid retry loops

* refactor: split quoted message parser into focused modules

* refactor: share onebot segment parsing logic

* refactor: unify quoted message parsing flow

* feat: move quoted parser tuning to provider settings

* fix: add missing i18n metadata for quoted parser settings

* chore: refine forwarded message setting labels

* fix: add config tabs and routing for normal and system configurations

* chore: bump version to 4.16.0 (#5074)

* feat: add LINE platform support with adapter and configuration (#5085)

* fix-correct-FIRST_NOTICE.md-locale-path-resolution (#5083) (#5082)

* fix:修改配置文件目录

* fix:添加备选的FIRST_NOTICE.zh-CN.md用于兼容

* fix: remove unnecessary frozen flag from requirements export in Dockerfile

fixes: #5089

* fix #5089: add uv lock step in Dockerfile before export (#5091)

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* feat: support hot reload after plugin load failure (#5043)

* add :Support hot reload after plugin load failure

* Apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix:reformat code

* fix:reformat code

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* feat: add fallback chat model chain in tool loop runner (#5109)

* feat: implement fallback provider support for chat models and update configuration

* feat: enhance provider selection display with count and chips for selected providers

* feat: update fallback chat providers to use provider settings and add warning for non-list fallback models

* feat: add Afdian support card to resources section in WelcomePage

* feat: replace colorlog with loguru for enhanced logging support (#5115)

* feat: add SSL configuration options for WebUI and update related logging (#5117)

* chore: bump version to 4.17.0

* fix: handle list format content from OpenAI-compatible APIs (#5128)

* fix: handle list format content from OpenAI-compatible APIs

Some LLM providers (e.g., GLM-4.5V via SiliconFlow) return content as
list[dict] format like [{'type': 'text', 'text': '...'}] instead of
plain string. This causes the raw list representation to be displayed
to users.

Changes:
- Add _normalize_content() helper to extract text from various content formats
- Use json.loads instead of ast.literal_eval for safer parsing
- Add size limit check (8KB) before attempting JSON parsing
- Only convert lists that match OpenAI content-part schema (has 'type': 'text')
  to avoid collapsing legitimate list-literal replies like ['foo', 'bar']
- Add strip parameter to preserve whitespace in streaming chunks
- Clean up orphan </think> tags that may leak from some models

Fixes #5124

* fix: improve content normalization safety

- Try json.loads first, fallback to ast.literal_eval for single-quoted
  Python literals to avoid corrupting apostrophes (e.g., "don't")
- Coerce text values to str to handle null or non-string text fields

* fix: update retention logic in LogManager to handle backup count correctly

* chore: bump version to 4.17.1

* docs: Added instructions for deploying AstrBot using AstrBot Launcher. (#5136)

Added instructions for deploying AstrBot using AstrBot Launcher.

* fix: add MCP tools to function tool set in _plugin_tool_fix (#5144)

* fix: add support for collecting data from builtin stars in electron pyinstaller build (#5145)

* chore: bump version to 4.17.1

* chore: ruff format

* fix: prevent updates for AstrBot launched via launcher

* fix(desktop): include runtime deps for builtin plugins in backend build (#5146)

* fix: 'Plain' object has no attribute 'text' when using python 3.14 (#5154)

* fix: enhance plugin metadata handling by injecting attributes before instantiation (#5155)

* fix: enhance handle_result to support event context and webchat image sending

* chore: bump version to 4.17.3

* chore: ruff format

* feat: add NVIDIA provider template (#5157)

fixes: #5156

* feat: enhance provider sources panel with styled menu and mobile support

* fix: improve permission denied message for local execution in Python and shell tools

* feat: enhance PersonaForm component with responsive design and improved styling (#5162)

fix: #5159

* ui(CronJobPage): fix action column buttons overlapping in CronJobPage (#5163)

- 修改前:操作列容器仅使用 `d-flex`,在页面宽度变窄时,子元素(开关和删除按钮)会因为宽度挤压而发生视觉重叠,甚至堆叠在一起。
- 修改后:
    1. 为容器添加了 `flex-nowrap`,强制禁止子元素换行。
    2. 设置了 `min-width: 140px`,确保该列拥有固定的保护空间,防止被其他长文本列挤压。
    3. 增加了 `gap: 12px` 间距,提升了操作辨识度并优化了点击体验。

* feat: add unsaved changes notice to configuration page and update messages

* feat: implement search functionality in configuration components and update UI (#5168)

* feat: add FAQ link to vertical sidebar and update navigation for localization

* feat: add announcement section to WelcomePage and localize announcement title

* chore: bump version to 4.17.4

* feat: supports send markdown message in qqofficial (#5173)

* feat: supports send markdown message in qqofficial

closes: #1093 #918 #4180 #4264

* ruff format

* fix: prevent duplicate error message when all LLM providers fail (#5183)

* fix: 修复选择配置文件进入配置文件管理弹窗直接关闭弹窗显示的配置文件不正确 (#5174)

* feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage (#5190)

* feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage

* feat: update random plugin selection logic to use pluginMarketData and refresh on relevant events

* feat: supports aihubmix

* docs: update readme

* chore: ruff format

* feat: add LINE support to multiple language README files

* feat(core): add plugin error hook for custom error routing (#5192)

* feat(core): add plugin error hook for custom error routing

* fix(core): align plugin error suppression with event stop state

* refactor: extract Voice_messages_forbidden fallback into shared helper with typed BadRequest exception (#5204)

- Add _send_voice_with_fallback helper to deduplicate voice forbidden handling
- Catch telegram.error.BadRequest instead of bare Exception with string matching
- Add text field to Record component to preserve TTS source text
- Store original text in Record during TTS conversion for use as document caption
- Skip _send_chat_action when chat_id is empty to avoid unnecessary warnings

* chore: bump version to 4.17.5

* feat: add admin permission checks for Python and Shell execution (#5214)

* fix: 改进微信公众号被动回复处理机制,引入缓冲与分片回复,并优化超时行为 (#5224)

* 修复wechat official 被动回复功能

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* fix: 修复仅发送 JSON 消息段时的空消息回复报错 (#5208)

* Fix Register_Stage

· 补全 JSON 消息判断,修复发送 JSON 消息时遇到 “消息为空,跳过发送阶段” 的问题。
· 顺带补全其它消息类型判断。
Co-authored-by: Pizero <zhaory200707@outlook.com>

* Fix formatting and comments in stage.py

* Format stage.py

---------

Co-authored-by: Pizero <zhaory200707@outlook.com>

* docs: update related repo links

* fix(core): terminate active events on reset/new/del to prevent stale responses (#5225)

* fix(core): terminate active events on reset/new/del to prevent stale responses

Closes #5222

* style: fix import sorting in scheduler.py

* chore: remove Electron desktop pipeline and switch to tauri repo (#5226)

* ci: remove Electron desktop build from release pipeline

* chore: remove electron desktop and switch to tauri release trigger

* ci: remove desktop workflow dispatch trigger

* refactor: migrate data paths to astrbot_path helpers

* fix: point desktop update prompt to AstrBot-desktop releases

* fix: update feature request template for clarity and consistency in English and Chinese

* Feat/config leave confirm (#5249)

* feat: 配置文件增加未保存提示弹窗

* fix: 移除unsavedChangesDialog插件使用组件方式实现弹窗

* feat: add support for plugin astrbot-version and platform requirement checks (#5235)

* feat: add support for plugin astrbot-version and platform requirement checks

* fix: remove unsupported platform and version constraints from metadata.yaml

* fix: remove restriction on 'v' in astrbot_version specification format

* ruff format

* feat: add password confirmation when changing password (#5247)

* feat: add password confirmation when changing password

Fixes #5177

Adds a password confirmation field to prevent accidental password typos.

Changes:
- Backend: validate confirm_password matches new_password
- Frontend: add confirmation input with validation
- i18n: add labels and error messages for password mismatch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(auth): improve error message for password confirmation mismatch

* fix(auth): update password hashing logic and improve confirmation validation

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题 (#5250)

* fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题

修复 _normalize_content 函数未处理 dict 类型 content 的问题。
当 LLM 返回 {"type": "text", "text": "..."} 格式的 content 时,
现在会正确提取 text 字段而非直接转为字符串。

同时改进 fallback 行为,对 None 值返回空字符串。

Fixes #5244

* Update warning message for unexpected dict format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* chore: remove outdated heihe.md documentation file

* fix: all mcp tools exposed to main agent (#5252)

* fix: enhance PersonaForm layout and improve tool selection display

* fix: update tool status display and add localization for inactive tools

* fix: remove additionalProperties from tool schema properties (#5253)

fixes: #5217

* fix: simplify error messages for account edit validation

* fix: streamline error response for empty new username and password in account edit

* chore: bump vertion to 4.17.6

* feat: add OpenRouter provider support and icon

* chore: ruff format

* refactor(dashboard): replace legacy isElectron bridge fields with isDesktop (#5269)

* refactor dashboard desktop bridge fields from isElectron to isDesktop

* refactor dashboard runtime detection into shared helper

* fix: update contributor avatar image URL to include max size and columns (#5268)

* feat: astrbot http api (#5280)

* feat: astrbot http api

* Potential fix for code scanning alert no. 34: Use of a broken or weak cryptographic hashing algorithm on sensitive data

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix: improve error handling for missing attachment path in file upload

* feat: implement paginated retrieval of platform sessions for creators

* feat: refactor attachment directory handling in ChatRoute

* feat: update API endpoint paths for file and message handling

* feat: add documentation link to API key management section in settings

* feat: update API key scopes and related configurations in API routes and tests

* feat: enhance API key expiration options and add warning for permanent keys

* feat: add UTC normalization and serialization for API key timestamps

* feat: implement chat session management and validation for usernames

* feat: ignore session_id type chunks in message processing

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* feat(dashboard): improve plugin platform support display and mobile accessibility (#5271)

* feat(dashboard): improve plugin platform support display and mobile accessibility

- Replace hover-based tooltips with interactive click menus for platform support information.
- Fix mobile touch issues by introducing explicit state control for status capsules.
- Enhance UI aesthetics with platform-specific icons and a structured vertical list layout.
- Add dynamic chevron icons to provide clear visual cues for expandable content.

* refactor(dashboard): refactor market card with computed properties for performance

* refactor(dashboard): unify plugin platform support UI with new reusable chip component

- Create shared 'PluginPlatformChip' component to encapsulate platform meta display.
- Fix mobile interaction bugs by simplifying menu triggers and event handling.
- Add stacked platform icon previews and dynamic chevron indicators within capsules.
- Improve information hierarchy using structured vertical lists for platform details.
- Optimize rendering efficiency with computed properties across both card views.

* fix: qq official guild message send error (#5287)

* fix: qq official guild message send error

* Update astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* 更新readme文档,补充桌面app说明,并向前移动位置 (#5297)

* docs: update desktop deployment section in README

* docs: refine desktop and launcher deployment descriptions

* Update README.md

* feat: add Anthropic Claude Code OAuth provider and adaptive thinking support (#5209)

* feat: add Anthropic Claude Code OAuth provider and adaptive thinking support

* fix: add defensive guard for metadata overrides and align budget condition with docs

* refactor: adopt sourcery-ai suggestions for OAuth provider

- Use use_api_key=False in OAuth subclass to avoid redundant
  API-key client construction before replacing with auth_token client
- Generalize metadata override helper to merge all dict keys
  instead of only handling 'limit', improving extensibility

* Feat/telegram command alias register  #5233 (#5234)

* feat: support registering command aliases for Telegram

Now when registering commands with aliases, all aliases will be
registered as Telegram bot commands in addition to the main command.

Example:
    @register_command(command_name="draw", alias={"画", "gen"})
Now /draw, /画, and /gen will all appear in the Telegram command menu.

* feat(telegram): add duplicate command name warning when registering commands

Log a warning when duplicate command names are detected during Telegram
command registration to help identify configuration conflicts.

* refactor: remove Anthropic OAuth provider implementation and related metadata overrides

* fix: 修复新建对话时因缺少会话ID导致配置绑定失败的问题 (#5292)

* fix:尝试修改

* fix:添加详细日志

* fix:进行详细修改,并添加日志

* fix:删除所有日志

* fix: 增加安全访问函数

- 给 localStorage 访问加了 try/catch + 可用性判断:dashboard/src/utils/chatConfigBinding.ts:13
- 新增 getFromLocalStorage/setToLocalStorage(在受限存储/无痕模式下异常时回退/忽略)
- getStoredDashboardUsername() / getStoredSelectedChatConfigId() 改为走安全读取:dashboard/src/utils/chatConfigBinding.ts:36       - 新增 setStoredSelectedChatConfigId(),写入失败静默忽略:dashboard/src/utils/chatConfigBinding.ts:44
- 把 ConfigSelector.vue 里直接 localStorage.getItem/setItem 全部替换为上述安全方法:dashboard/src/components/chat/ConfigSelector.vue:81
- 已重新跑过 pnpm run typecheck,通过。

* rm:删除个人用的文档文件

* Revert "rm:删除个人用的文档文件"

This reverts commit 0fceee0543.

* rm:删除个人用的文档文件

* rm:删除个人用的文档文件

* chore: bump version to 4.18.0

* fix(SubAgentPage): 当中间的介绍文本非常长时,Flex 布局会自动挤压右侧的控制按钮区域 (#5306)

* fix: 修复新版本插件市场出现插件显示为空白的 bug;纠正已安装插件卡片的排版,统一大小 (#5309)

* fix(ExtensionCard): 解决插件卡片大小不统一的问题

* fix(MarketPluginCard): 解决插件市场不加载插件的问题 (#5303)

* feat: supports spawn subagent as a background task that not block the main agent workflow (#5081)

* feat:为subagent添加后台任务参数

* ruff

* fix: update terminology from 'handoff mission' to 'background task' and refactor related logic

* fix: update terminology from 'background_mission' to 'background_task' in HandoffTool and related logic

* fix(HandoffTool): update background_task description for clarity on usage

---------

Co-authored-by: Soulter <905617992@qq.com>

* cho

* fix: 修复 aiohttp 版本过新导致 qq-botpy 报错的问题 (#5316)

* chore: ruff format

* fix: remove hard-coded 6s timeout from tavily request

* fix: remove changelogs directory from .dockerignore

* feat(dashboard): make release redirect base URL configurable (#5330)

* feat(dashboard): make desktop release base URL configurable

* refactor(dashboard): use generic release base URL env with upstream default

* fix(dashboard): guard release base URL normalization when env is unset

* refactor(dashboard): use generic release URL helpers and avoid latest suffix duplication

* feat: add stop functionality for active agent sessions and improve handling of stop requests (#5380)

* feat: add stop functionality for active agent sessions and improve handling of stop requests

* feat: update stop button icon and tooltip in ChatInput component

* fix: correct indentation in tool call handling within ChatRoute class

* fix: chatui cannot persist file segment (#5386)

* fix(plugin): update plugin directory handling for reserved plugins (#5369)

* fix(plugin): update plugin directory handling for reserved plugins

* fix(plugin): add warning logs for missing plugin name, object, directory, and changelog

* chore(README): updated with README.md (#5375)

* chore(README): updated with README.md

* Update README_fr.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Update README_zh-TW.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* feat: add image urls / paths supports for subagent (#5348)

* fix: 修复5081号PR在子代理执行后台任务时,未正确使用系统配置的流式/非流请求的问题(#5081)

* feat:为子代理增加远程图片URL参数支持

* fix: update description for image_urls parameter in HandoffTool to clarify usage in multimodal tasks

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* feat: add hot reload when failed to load plugins (#5334)

* feat:add hot reload when failed to load plugins

* apply bot suggestions

* fix(chatui): add copy rollback path and error message. (#5352)

* fix(chatui): add copy rollback path and error message.

* fix(chatui): fixed textarea leak in the copy button.

* fix(chatui): use color styles from the component library.

* fix: 处理配置文件中的 UTF-8 BOM 编码问题 (#5376)

* fix(config): handle UTF-8 BOM in configuration file loading

Problem:
On Windows, some text editors (like Notepad) automatically add UTF-8 BOM
to JSON files when saving. This causes json.decoder.JSONDecodeError:
"Unexpected UTF-8 BOM" and AstrBot fails to start when cmd_config.json
contains BOM.

Solution:
Add defensive check to strip UTF-8 BOM (\ufeff) if present before
parsing JSON configuration file.

Impact:
- Improves robustness and cross-platform compatibility
- No breaking changes to existing functionality
- Fixes startup failure when configuration file has UTF-8 BOM encoding

Relates-to: Windows editor compatibility issues

* style: fix code formatting with ruff

Fix single quote to double quote to comply with project code style.

* feat: add plugin load&unload hook (#5331)

* 添加了插件的加载完成和卸载完成的钩子事件

* 添加了插件的加载完成和卸载完成的钩子事件

* format code with ruff

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* test: enhance test framework with comprehensive fixtures and mocks (#5354)

* test: enhance test framework with comprehensive fixtures and mocks

- Add shared mock builders for aiocqhttp, discord, telegram
- Add test helpers for platform configs and mock objects
- Expand conftest.py with test profile support
- Update coverage test workflow configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(tests): 移动并重构模拟 LLM 响应和消息组件函数

* fix(tests): 优化 pytest_runtest_setup 中的标记检查逻辑

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: add comprehensive tests for message event handling (#5355)

* test: add comprehensive tests for message event handling

- Add AstrMessageEvent unit tests (688 lines)
- Add AstrBotMessage unit tests
- Enhance smoke tests with message event scenarios

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: improve message type handling and add defensive tests

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add support for showing tool call results in agent execution (#5388)

closes: #5329

* fix: resolve pipeline and star import cycles (#5353)

* fix: resolve pipeline and star import cycles

- Add bootstrap.py and stage_order.py to break circular dependencies
- Export Context, PluginManager, StarTools from star module
- Update pipeline __init__ to defer imports
- Split pipeline initialization into separate bootstrap module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add logging for get_config() failure in Star class

* fix: reorder logger initialization in base.py

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: enable computer-use tools for subagent handoff (#5399)

* fix: enforce admin guard for sandbox file transfer tools (#5402)

* fix: enforce admin guard for sandbox file transfer tools

* refactor: deduplicate computer tools admin permission checks

* fix: add missing space in permission error message

* fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性 (#5391)

* fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性

原因 (Necessity):
1. 内核一致性:AstrBot 内核的 Record 和 Video 组件均具备识别 `file:///` 协议头的逻辑,但 File 组件此前缺失此功能,导致行为不统一。
2. OneBot 协议合规:OneBot 11 标准要求本地文件路径必须使用 `file:///` 协议头。此前驱动层未对裸路径进行自动转换,导致发送本地文件时常触发 retcode 1200 (识别URL失败) 错误。
3. 容器环境适配:在 Docker 等路径隔离环境下,裸路径更容易因驱动或协议端的解析歧义而失效。

更改 (Changes):
- [astrbot/core/message/components.py]:
  - 在 File.get_file() 中增加对 `file:///` 前缀的识别与剥离逻辑,使其与 Record/Video 组件行为对齐。
- [astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py]:
  - 在发送文件前增加自动修正逻辑:若路径为绝对路径且未包含协议头,驱动层将自动补全 `file:///` 前缀。
  - 对 http、base64 及已有协议头,确保不干扰原有的正常传输逻辑。

影响 (Impact):
- 以完全兼容的方式增强了文件发送的鲁棒性。
- 解决了插件在发送日志等本地生成的压缩包时,因路径格式不规范导致的发送失败问题。

* refactor(core): 根据 cr 建议,规范化文件 URI 生成与解析逻辑,优化跨平台兼容性

原因 (Necessity):
1. 修复原生路径与 URI 转换在 Windows 下的不对称问题。
2. 规范化 file: 协议头处理,确保符合 RFC 标准并能在 Linux/Windows 间稳健切换。
3. 增强协议判定准确度,防止对普通绝对路径的误处理。

更改 (Changes):
- [astrbot/core/platform/sources/aiocqhttp]:
  - 弃用手动拼接,改用 `pathlib.Path.as_uri()` 生成标准 URI。
  - 将协议检测逻辑从前缀匹配优化为包含性检测 ("://")。
- [astrbot/core/message/components]:
  - 重构 `File.get_file` 解析逻辑,支持对称处理 2/3 斜杠格式。
  - 针对 Windows 环境增加了对 `file:///C:/` 格式的自动修正,避免 `os.path` 识别失效。
- [data/plugins/astrbot_plugin_logplus]:
  - 在直接 API 调用中同步应用 URI 规范化处理。

影响 (Impact):
- 解决 Docker 环境中因路径不规范导致的 "识别URL失败" 报错。
- 提升了本体框架在 Windows 系统下的文件操作鲁棒性。

* i18n(SubAgentPage): complete internationalization for subagent orchestration page (#5400)

* i18n: complete internationalization for subagent orchestration page

- Replace hardcoded English strings in [SubAgentPage.vue] with i18n keys.
- Update `en-US` and `zh-CN` locales with missing hints, validation messages, and empty state translations.
- Fix translation typos and improve consistency across the SubAgent orchestration UI.

* fix(bug_risk): 避免在模板中的翻译调用上使用 || 'Close' 作为回退值。

* fix(aiocqhttp): enhance shutdown process for aiocqhttp adapter (#5412)

* fix: pass embedding dimensions to provider apis (#5411)

* fix(context): log warning when platform not found for session

* fix(context): improve logging for platform not found in session

* chore: bump version to 4.18.2

* chore: bump version to 4.18.2

* chore: bump version to 4.18.2

* fix: Telegram voice message format (OGG instead of WAV) causing issues with OpenAI STT API (#5389)

* chore: ruff format

* feat(dashboard): add generic desktop app updater bridge (#5424)

* feat(dashboard): add generic desktop app updater bridge

* fix(dashboard): address updater bridge review feedback

* fix(dashboard): unify updater bridge types and error logging

* fix(dashboard): consolidate updater bridge typings

* fix(conversation): retain existing persona_id when updating conversation

* fix(dashboard): 修复设置页新建 API Key 后复制失败问题 (#5439)

* Fix: GitHub proxy not displaying correctly in WebUI (#5438)

* fix(dashboard): preserve custom GitHub proxy setting on reload

* fix(dashboard): keep github proxy selection persisted in settings

* fix(persona): enhance persona resolution logic for conversations and sessions

* fix: ensure tool call/response pairing in context truncation (#5417)

* fix: ensure tool call/response pairing in context truncation

* refactor: simplify fix_messages to single-pass state machine

* perf(cron): enhance future task session isolation

fixes: #5392

* feat: add useExtensionPage composable for managing plugin extensions

- Implemented a new composable `useExtensionPage` to handle various functionalities related to plugin management, including fetching extensions, handling updates, and managing UI states.
- Added support for conflict checking, plugin installation, and custom source management.
- Integrated search and filtering capabilities for plugins in the market.
- Enhanced user experience with dialogs for confirmations and notifications.
- Included pagination and sorting features for better plugin visibility.

* fix: clear markdown field when sending media messages via QQ Official Platform (#5445)

* fix: clear markdown field when sending media messages via QQ Official API

* refactor: use pop() to remove markdown key instead of setting None

* fix: cannot automatically get embedding dim when create embedding provider (#5442)

* fix(dashboard): 强化 API Key 复制临时节点清理逻辑

* fix(embedding): 自动检测改为探测 OpenAI embedding 最大可用维度

* fix: normalize openai embedding base url and add hint key

* i18n: add embedding_api_base hint translations

* i18n: localize provider embedding/proxy metadata hints

* fix: show provider-specific embedding API Base URL hint as field subtitle

* fix(embedding): cap OpenAI detect_dim probes with early short-circuit

* fix(dashboard): return generic error on provider adapter import failure

* 回退检测逻辑

* fix: 修复Pyright静态类型检查报错 (#5437)

* refactor: 修正 Sqlite 查询、下载回调、接口重构与类型调整

* feat: 为 OneBotClient 增加 CallAction 协议与异步调用支持

* fix(telegram): avoid duplicate message_thread_id in streaming (#5430)

* perf: batch metadata query in KB retrieval to fix N+1 problem (#5463)

* perf: batch metadata query in KB retrieval to fix N+1 problem

Replace N sequential get_document_with_metadata() calls with a single
get_documents_with_metadata_batch() call using SQL IN clause.

Benchmark results (local SQLite):
- 10 docs: 10.67ms → 1.47ms (7.3x faster)
- 20 docs: 26.00ms → 2.68ms (9.7x faster)
- 50 docs: 63.87ms → 2.79ms (22.9x faster)

* refactor: use set[str] param type and chunk IN clause for SQLite safety

Address review feedback:
- Change doc_ids param from list[str] to set[str] to avoid unnecessary conversion
- Chunk IN clause into batches of 900 to stay under SQLite's 999 parameter limit
- Remove list() wrapping at call site, pass set directly

* fix:fix the issue where incomplete cleanup of residual plugins occurs… (#5462)

* fix:fix the issue where incomplete cleanup of residual plugins occurs in the failed loading of plugins

* fix:ruff format,apply bot suggestions

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* chore: 为类型检查添加 TYPE_CHECKING 的导入与阶段类型引用 (#5474)

* fix(line): line adapter does not appear in the add platform dialog

fixes: #5477

* [bug]查看介入教程line前往错误界面的问题 (#5479)

Fixes #5478

* chore: bump version to 4.18.3

* feat: implement follow-up message handling in ToolLoopAgentRunner (#5484)

* feat: implement follow-up message handling in ToolLoopAgentRunner

* fix: correct import path for follow-up module in InternalAgentSubStage

* feat: implement websockets transport mode selection for chat (#5410)

* feat: implement websockets transport mode selection for chat

- Added transport mode selection (SSE/WebSocket) in the chat component.
- Updated conversation sidebar to include transport mode options.
- Integrated transport mode handling in message sending logic.
- Refactored message sending functions to support both SSE and WebSocket.
- Enhanced WebSocket connection management and message handling.
- Updated localization files for transport mode labels.
- Configured Vite to support WebSocket proxying.

* feat(webchat): refactor message parsing logic and integrate new parsing function

* feat(chat): add websocket API key extraction and scope validation

* Revert "可选后端,实现前后端分离" (#5536)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: can <51474963+weijintaocode@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: letr <123731298+letr007@users.noreply.github.com>
Co-authored-by: 搁浅 <id6543156918@gmail.com>
Co-authored-by: Helian Nuits <sxp20061207@163.com>
Co-authored-by: Gao Jinzhe <2968474907@qq.com>
Co-authored-by: DD斩首 <155905740+DDZS987@users.noreply.github.com>
Co-authored-by: Ubuntu <ubuntu@localhost.localdomain>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: エイカク <62183434+zouyonghe@users.noreply.github.com>
Co-authored-by: 鸦羽 <Raven95676@gmail.com>
Co-authored-by: Dt8333 <25431943+Dt8333@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Li-shi-ling <114913764+Li-shi-ling@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Limitless <127183162+Limitless2023@users.noreply.github.com>
Co-authored-by: Limitless2023 <limitless@users.noreply.github.com>
Co-authored-by: evpeople <54983536+evpeople@users.noreply.github.com>
Co-authored-by: SnowNightt <127504703+SnowNightt@users.noreply.github.com>
Co-authored-by: xzj0898 <62733743+xzj0898@users.noreply.github.com>
Co-authored-by: stevessr <89645372+stevessr@users.noreply.github.com>
Co-authored-by: Waterwzy <2916963017@qq.com>
Co-authored-by: NayukiMeko <MekoNayuki@outlook.com>
Co-authored-by: 時壹 <137363396+KBVsent@users.noreply.github.com>
Co-authored-by: sanyekana <Clhikari@qq.com>
Co-authored-by: Chiu Chun-Hsien <95356121+911218sky@users.noreply.github.com>
Co-authored-by: Dream Tokenizer <60459821+Trance-0@users.noreply.github.com>
Co-authored-by: NanoRocky <76585834+NanoRocky@users.noreply.github.com>
Co-authored-by: Pizero <zhaory200707@outlook.com>
Co-authored-by: 雪語 <167516635+YukiRa1n@users.noreply.github.com>
Co-authored-by: whatevertogo <1879483647@qq.com>
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: 香草味的纳西妲喵 <151599587+VanillaNahida@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Lovely Moe Moli <44719954+moemoli@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Minidoracat <minidora0702@gmail.com>
Co-authored-by: Chen <42998804+a61995987@users.noreply.github.com>
Co-authored-by: hanbings <hanbings@hanbings.io>
Co-authored-by: tangsenfei <155090747+tangsenfei@users.noreply.github.com>
Co-authored-by: PyuraMazo <1605025385@qq.com>
Co-authored-by: Axi404 <118950647+Axi404@users.noreply.github.com>
Co-authored-by: 氕氙 <2014440212@qq.com>
Co-authored-by: Yunhao Cao <18230652+realquantumcookie@users.noreply.github.com>
Co-authored-by: exynos <110159911+exynos967@users.noreply.github.com>
Co-authored-by: Luna_Dol <86590429+Luna-channel@users.noreply.github.com>
Co-authored-by: CCCCCCTV <64309817+CCCCCCTV@users.noreply.github.com>
Co-authored-by: CAICAII <3360776475@qq.com>
Co-authored-by: 圣达生物多 <qq3258819795@163.com>
2026-02-27 22:03:17 +08:00
LIghtJUNction
b8c73430fb Revert "可选后端,实现前后端分离" (#5536) 2026-02-27 22:02:37 +08:00
LIghtJUNction
3141ed52bd Merge branch 'feat/optional-backend' into master 2026-02-27 21:53:56 +08:00
RC-CHN
a219a8b70d Merge remote-tracking branch 'origin/master' into feat/neo-skill-self-iteration 2026-02-27 15:25:50 +08:00
RC-CHN
c1de265baf feat(skills): mark sandbox preset skills readonly
expose skill source metadata and sandbox cache status in the skills API
response so the dashboard can distinguish local, sandbox-only, and
synced skills.

prevent enabling, disabling, or deleting sandbox-only preset skills in
both backend guards and UI actions to avoid invalid local operations.

add source badges, discovery-pending hinting for sandbox runtime, and
new i18n strings for source labels and readonly warnings.
2026-02-27 15:22:07 +08:00
RC-CHN
13c8fa3f92 fix(skills): use workspace path for sandbox skills
default sandbox skill paths to /workspace/skills/<name>/SKILL.md
when loading config and when exposing sandbox paths.
preserve cached sandbox paths when available to avoid losing
resolved locations for existing skills.
2026-02-27 14:08:59 +08:00
Soulter
63ff234f10 feat: implement websockets transport mode selection for chat (#5410)
* feat: implement websockets transport mode selection for chat

- Added transport mode selection (SSE/WebSocket) in the chat component.
- Updated conversation sidebar to include transport mode options.
- Integrated transport mode handling in message sending logic.
- Refactored message sending functions to support both SSE and WebSocket.
- Enhanced WebSocket connection management and message handling.
- Updated localization files for transport mode labels.
- Configured Vite to support WebSocket proxying.

* feat(webchat): refactor message parsing logic and integrate new parsing function

* feat(chat): add websocket API key extraction and scope validation
2026-02-27 14:02:10 +08:00
Soulter
5219ba5c4e feat: implement follow-up message handling in ToolLoopAgentRunner (#5484)
* feat: implement follow-up message handling in ToolLoopAgentRunner

* fix: correct import path for follow-up module in InternalAgentSubStage
2026-02-26 21:38:47 +08:00
Soulter
84994b5d98 chore: bump version to 4.18.3 2026-02-26 19:12:09 +08:00
圣达生物多
1554f71106 [bug]查看介入教程line前往错误界面的问题 (#5479)
Fixes #5478
2026-02-26 19:04:53 +08:00
RC-CHN
4ff4c5f1bf fix(skills): remove deleted skills from sandbox cache
keep sandbox skill cache in sync when deleting a skill from disk.
this prevents stale entries in the UI when no sandbox session is
active to refresh runtime cache
2026-02-26 16:52:02 +08:00
RC-CHN
73e665bef7 feat(neo): guide skill lifecycle tool workflow
Add explicit Neo lifecycle instructions to the main agent prompt so
skill creation and updates follow payload -> candidate -> promotion
instead of direct local folder writes.

Clarify lifecycle tool descriptions and parameter semantics, including
skill_key/source_execution_ids usage and stable release sync_to_local
behavior, to reduce ambiguity and improve consistent skill publishing.
2026-02-26 16:14:16 +08:00
w31rd
4b1bda5f2e Merge pull request #2 from camera-2018/feat/neo-skill-self-iteration
Feat/neo skill self iteration
2026-02-26 16:13:42 +08:00
camera-2018
18114eafda fix(neo): sanitize skill name in frontmatter to prevent injection
Sanitized the name field in SKILL.md frontmatter within astrbot/core/skills/neo_skill_sync.py. This prevents potential frontmatter injection vulnerabilities by removing newlines and control characters from the skill name. Verified the fix with a reproduction script and ensured existing tests pass.
2026-02-26 16:04:42 +08:00
camera-2018
87cbcc9875 fix(neo): sanitize skill name in frontmatter to prevent injection
Sanitize the `name` field in `SKILL.md` frontmatter to remove newlines and control characters. This prevents potential frontmatter injection vulnerabilities where a malicious skill name could introduce arbitrary YAML fields or corrupt the file structure.

- Modified `_ensure_skill_frontmatter` in `astrbot/core/skills/neo_skill_sync.py` to normalize whitespace in `name`.
- Ensured `name` is cast to string before splitting to handle non-string inputs safely.
2026-02-26 08:03:44 +00:00
RC-CHN
1ebc2070c0 fix(skills): gate neo mode by runtime config
Disable the Neo mode toggle unless runtime is sandbox with
shipyard_neo configured, and show a warning when Neo is unavailable.

Also avoid loading Neo data when the environment is not compatible and
fall back to local mode to prevent invalid requests and confusion.
2026-02-26 15:50:39 +08:00
RC-CHN
e95bd8d3a6 style: format code 2026-02-26 15:27:37 +08:00
Soulter
476c01469f fix(line): line adapter does not appear in the add platform dialog
fixes: #5477
2026-02-26 15:26:37 +08:00
RC-CHN
d5a3107f8f style: format code 2026-02-26 15:24:10 +08:00
RC-CHN
8d5841b71f feat(skills): add neo candidate and release deletion
Add backend routes to delete neo candidates and releases with optional
reason support and demo mode protection.

Expose delete actions in the Skills dashboard for candidate and release
rows, refresh data after success, and add localized success/failure
messages in en-US and zh-CN.
2026-02-26 14:48:20 +08:00
Dt8333
10163ec78a chore: 为类型检查添加 TYPE_CHECKING 的导入与阶段类型引用 (#5474) 2026-02-26 14:19:52 +08:00
RC-CHN
8faed949c2 fix(skills): ensure synced markdown has frontmatter
Normalize SKILL.md content during sync so each file includes name and
description metadata in a frontmatter block.

Preserve existing frontmatter values when present, derive description
from markdown content when missing, and fallback to a default
description to keep metadata complete and consistent.
2026-02-26 11:10:09 +08:00
RC-CHN
e1719efbc8 fix(skills): normalize release stage and handle rollback skip
Normalize release stage values before stability checks so enum-like
objects and mixed-case strings are handled consistently.

When stable sync fails, treat "no previous release exists" during
auto-rollback as a skipped rollback instead of raising a secondary
runtime error
2026-02-26 10:45:03 +08:00
RC-CHN
f01c23ad40 fix(agent): enforce relative paths for neo sandbox tools
append a Shipyard Neo-specific system prompt note for filesystem
tool calls so paths are provided relative to the workspace root.
this prevents models from prepending `/workspace` and causing tool
path resolution failures
2026-02-26 10:33:22 +08:00
RC-CHN
847ef0f3f4 Merge remote-tracking branch 'origin/master' into feat/neo-skill-self-iteration 2026-02-26 10:04:48 +08:00
Waterwzy
98b89ebcc5 fix:fix the issue where incomplete cleanup of residual plugins occurs… (#5462)
* fix:fix the issue where incomplete cleanup of residual plugins occurs in the failed loading of plugins

* fix:ruff format,apply bot suggestions

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-26 10:02:43 +08:00
CAICAII
39b9e55434 perf: batch metadata query in KB retrieval to fix N+1 problem (#5463)
* perf: batch metadata query in KB retrieval to fix N+1 problem

Replace N sequential get_document_with_metadata() calls with a single
get_documents_with_metadata_batch() call using SQL IN clause.

Benchmark results (local SQLite):
- 10 docs: 10.67ms → 1.47ms (7.3x faster)
- 20 docs: 26.00ms → 2.68ms (9.7x faster)
- 50 docs: 63.87ms → 2.79ms (22.9x faster)

* refactor: use set[str] param type and chunk IN clause for SQLite safety

Address review feedback:
- Change doc_ids param from list[str] to set[str] to avoid unnecessary conversion
- Chunk IN clause into batches of 900 to stay under SQLite's 999 parameter limit
- Remove list() wrapping at call site, pass set directly
2026-02-26 09:59:37 +08:00
CCCCCCTV
3eb15089af fix(telegram): avoid duplicate message_thread_id in streaming (#5430) 2026-02-25 19:53:17 +08:00
Dt8333
c5b23d12a8 fix: 修复Pyright静态类型检查报错 (#5437)
* refactor: 修正 Sqlite 查询、下载回调、接口重构与类型调整

* feat: 为 OneBotClient 增加 CallAction 协议与异步调用支持
2026-02-25 19:49:16 +08:00
exynos
69f2fb291a fix: cannot automatically get embedding dim when create embedding provider (#5442)
* fix(dashboard): 强化 API Key 复制临时节点清理逻辑

* fix(embedding): 自动检测改为探测 OpenAI embedding 最大可用维度

* fix: normalize openai embedding base url and add hint key

* i18n: add embedding_api_base hint translations

* i18n: localize provider embedding/proxy metadata hints

* fix: show provider-specific embedding API Base URL hint as field subtitle

* fix(embedding): cap OpenAI detect_dim probes with early short-circuit

* fix(dashboard): return generic error on provider adapter import failure

* 回退检测逻辑
2026-02-25 19:48:03 +08:00
時壹
78660da995 fix: clear markdown field when sending media messages via QQ Official Platform (#5445)
* fix: clear markdown field when sending media messages via QQ Official API

* refactor: use pop() to remove markdown key instead of setting None
2026-02-25 19:45:27 +08:00
Soulter
c951b14aa2 feat: add useExtensionPage composable for managing plugin extensions
- Implemented a new composable `useExtensionPage` to handle various functionalities related to plugin management, including fetching extensions, handling updates, and managing UI states.
- Added support for conflict checking, plugin installation, and custom source management.
- Integrated search and filtering capabilities for plugins in the market.
- Enhanced user experience with dialogs for confirmations and notifications.
- Included pagination and sorting features for better plugin visibility.
2026-02-25 19:42:51 +08:00
Soulter
c384439b44 perf(cron): enhance future task session isolation
fixes: #5392
2026-02-25 16:32:09 +08:00
鸦羽
87d2750ff8 Merge pull request #5440 from Raven95676/fix/persona-loss
fix(persona): preserve conversation persona_id and unify session/conversation resolution
2026-02-25 16:11:19 +08:00
Luna_Dol
6d76d55452 fix: ensure tool call/response pairing in context truncation (#5417)
* fix: ensure tool call/response pairing in context truncation

* refactor: simplify fix_messages to single-pass state machine
2026-02-25 15:21:30 +08:00
Raven95676
d80598b9c3 fix(persona): enhance persona resolution logic for conversations and sessions 2026-02-25 15:14:46 +08:00
letr
c7d318304b Fix: GitHub proxy not displaying correctly in WebUI (#5438)
* fix(dashboard): preserve custom GitHub proxy setting on reload

* fix(dashboard): keep github proxy selection persisted in settings
2026-02-25 14:54:54 +08:00
exynos
bcdbc15635 fix(dashboard): 修复设置页新建 API Key 后复制失败问题 (#5439) 2026-02-25 14:54:06 +08:00
Raven95676
4749159bb9 fix(conversation): retain existing persona_id when updating conversation 2026-02-25 14:48:46 +08:00
エイカク
5530a2260a feat(dashboard): add generic desktop app updater bridge (#5424)
* feat(dashboard): add generic desktop app updater bridge

* fix(dashboard): address updater bridge review feedback

* fix(dashboard): unify updater bridge types and error logging

* fix(dashboard): consolidate updater bridge typings
2026-02-25 10:01:13 +09:00
Soulter
c24de24ca4 chore: ruff format 2026-02-24 23:12:18 +08:00
Yunhao Cao
b54b4c79ed fix: Telegram voice message format (OGG instead of WAV) causing issues with OpenAI STT API (#5389) 2026-02-24 23:11:56 +08:00
Soulter
c6cc7aae84 chore: bump version to 4.18.2 2026-02-24 23:08:53 +08:00
Soulter
84cd209074 chore: bump version to 4.18.2 2026-02-24 22:48:27 +08:00
Soulter
afda44fbe3 chore: bump version to 4.18.2 2026-02-24 22:44:35 +08:00
Soulter
f5d3b93437 fix(context): improve logging for platform not found in session 2026-02-24 22:37:51 +08:00
Soulter
069a3628fa fix(context): log warning when platform not found for session 2026-02-24 22:37:10 +08:00
氕氙
c81ef2672a fix: pass embedding dimensions to provider apis (#5411) 2026-02-24 22:09:44 +08:00
Soulter
a5ae27cae0 fix(aiocqhttp): enhance shutdown process for aiocqhttp adapter (#5412) 2026-02-24 22:07:42 +08:00
Helian Nuits
73faaf6577 i18n(SubAgentPage): complete internationalization for subagent orchestration page (#5400)
* i18n: complete internationalization for subagent orchestration page

- Replace hardcoded English strings in [SubAgentPage.vue] with i18n keys.
- Update `en-US` and `zh-CN` locales with missing hints, validation messages, and empty state translations.
- Fix translation typos and improve consistency across the SubAgent orchestration UI.

* fix(bug_risk): 避免在模板中的翻译调用上使用 || 'Close' 作为回退值。
2026-02-24 21:04:01 +08:00
Helian Nuits
29dbd085d4 fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性 (#5391)
* fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性

原因 (Necessity):
1. 内核一致性:AstrBot 内核的 Record 和 Video 组件均具备识别 `file:///` 协议头的逻辑,但 File 组件此前缺失此功能,导致行为不统一。
2. OneBot 协议合规:OneBot 11 标准要求本地文件路径必须使用 `file:///` 协议头。此前驱动层未对裸路径进行自动转换,导致发送本地文件时常触发 retcode 1200 (识别URL失败) 错误。
3. 容器环境适配:在 Docker 等路径隔离环境下,裸路径更容易因驱动或协议端的解析歧义而失效。

更改 (Changes):
- [astrbot/core/message/components.py]:
  - 在 File.get_file() 中增加对 `file:///` 前缀的识别与剥离逻辑,使其与 Record/Video 组件行为对齐。
- [astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py]:
  - 在发送文件前增加自动修正逻辑:若路径为绝对路径且未包含协议头,驱动层将自动补全 `file:///` 前缀。
  - 对 http、base64 及已有协议头,确保不干扰原有的正常传输逻辑。

影响 (Impact):
- 以完全兼容的方式增强了文件发送的鲁棒性。
- 解决了插件在发送日志等本地生成的压缩包时,因路径格式不规范导致的发送失败问题。

* refactor(core): 根据 cr 建议,规范化文件 URI 生成与解析逻辑,优化跨平台兼容性

原因 (Necessity):
1. 修复原生路径与 URI 转换在 Windows 下的不对称问题。
2. 规范化 file: 协议头处理,确保符合 RFC 标准并能在 Linux/Windows 间稳健切换。
3. 增强协议判定准确度,防止对普通绝对路径的误处理。

更改 (Changes):
- [astrbot/core/platform/sources/aiocqhttp]:
  - 弃用手动拼接,改用 `pathlib.Path.as_uri()` 生成标准 URI。
  - 将协议检测逻辑从前缀匹配优化为包含性检测 ("://")。
- [astrbot/core/message/components]:
  - 重构 `File.get_file` 解析逻辑,支持对称处理 2/3 斜杠格式。
  - 针对 Windows 环境增加了对 `file:///C:/` 格式的自动修正,避免 `os.path` 识别失效。
- [data/plugins/astrbot_plugin_logplus]:
  - 在直接 API 调用中同步应用 URI 规范化处理。

影响 (Impact):
- 解决 Docker 环境中因路径不规范导致的 "识别URL失败" 报错。
- 提升了本体框架在 Windows 系统下的文件操作鲁棒性。
2026-02-24 21:03:06 +08:00
Axi404
00b011809a fix: enforce admin guard for sandbox file transfer tools (#5402)
* fix: enforce admin guard for sandbox file transfer tools

* refactor: deduplicate computer tools admin permission checks

* fix: add missing space in permission error message
2026-02-24 20:59:44 +08:00
Axi404
0b46ca7ff3 feat: enable computer-use tools for subagent handoff (#5399) 2026-02-24 16:32:12 +08:00
whatevertogo
9294b44831 fix: resolve pipeline and star import cycles (#5353)
* fix: resolve pipeline and star import cycles

- Add bootstrap.py and stage_order.py to break circular dependencies
- Export Context, PluginManager, StarTools from star module
- Update pipeline __init__ to defer imports
- Split pipeline initialization into separate bootstrap module

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add logging for get_config() failure in Star class

* fix: reorder logger initialization in base.py

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 13:53:29 +08:00
Soulter
80fd51119b feat: add support for showing tool call results in agent execution (#5388)
closes: #5329
2026-02-24 00:46:45 +08:00
whatevertogo
5af5ad9e36 test: add comprehensive tests for message event handling (#5355)
* test: add comprehensive tests for message event handling

- Add AstrMessageEvent unit tests (688 lines)
- Add AstrBotMessage unit tests
- Enhance smoke tests with message event scenarios

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: improve message type handling and add defensive tests

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 23:36:39 +08:00
whatevertogo
7b731ebda8 test: enhance test framework with comprehensive fixtures and mocks (#5354)
* test: enhance test framework with comprehensive fixtures and mocks

- Add shared mock builders for aiocqhttp, discord, telegram
- Add test helpers for platform configs and mock objects
- Expand conftest.py with test profile support
- Update coverage test workflow configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(tests): 移动并重构模拟 LLM 响应和消息组件函数

* fix(tests): 优化 pytest_runtest_setup 中的标记检查逻辑

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 23:35:15 +08:00
PyuraMazo
28bfb3b8b2 feat: add plugin load&unload hook (#5331)
* 添加了插件的加载完成和卸载完成的钩子事件

* 添加了插件的加载完成和卸载完成的钩子事件

* format code with ruff

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-23 23:13:41 +08:00
tangsenfei
351895ae66 fix: 处理配置文件中的 UTF-8 BOM 编码问题 (#5376)
* fix(config): handle UTF-8 BOM in configuration file loading

Problem:
On Windows, some text editors (like Notepad) automatically add UTF-8 BOM
to JSON files when saving. This causes json.decoder.JSONDecodeError:
"Unexpected UTF-8 BOM" and AstrBot fails to start when cmd_config.json
contains BOM.

Solution:
Add defensive check to strip UTF-8 BOM (\ufeff) if present before
parsing JSON configuration file.

Impact:
- Improves robustness and cross-platform compatibility
- No breaking changes to existing functionality
- Fixes startup failure when configuration file has UTF-8 BOM encoding

Relates-to: Windows editor compatibility issues

* style: fix code formatting with ruff

Fix single quote to double quote to comply with project code style.
2026-02-23 22:27:56 +08:00
hanbings
c1009adf52 fix(chatui): add copy rollback path and error message. (#5352)
* fix(chatui): add copy rollback path and error message.

* fix(chatui): fixed textarea leak in the copy button.

* fix(chatui): use color styles from the component library.
2026-02-23 22:24:41 +08:00
Waterwzy
ecaec41208 feat: add hot reload when failed to load plugins (#5334)
* feat:add hot reload when failed to load plugins

* apply bot suggestions
2026-02-23 22:17:48 +08:00
Chen
997b51102b feat: add image urls / paths supports for subagent (#5348)
* fix: 修复5081号PR在子代理执行后台任务时,未正确使用系统配置的流式/非流请求的问题(#5081)

* feat:为子代理增加远程图片URL参数支持

* fix: update description for image_urls parameter in HandoffTool to clarify usage in multimodal tasks

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-23 22:16:14 +08:00
Helian Nuits
c5bd074c28 chore(README): updated with README.md (#5375)
* chore(README): updated with README.md

* Update README_fr.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Update README_zh-TW.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-02-23 22:05:22 +08:00
鸦羽
4c09ed3c09 fix(plugin): update plugin directory handling for reserved plugins (#5369)
* fix(plugin): update plugin directory handling for reserved plugins

* fix(plugin): add warning logs for missing plugin name, object, directory, and changelog
2026-02-23 22:04:47 +08:00
Soulter
a56e43d17e fix: chatui cannot persist file segment (#5386) 2026-02-23 22:02:49 +08:00
Soulter
e357d9de74 feat: add stop functionality for active agent sessions and improve handling of stop requests (#5380)
* feat: add stop functionality for active agent sessions and improve handling of stop requests

* feat: update stop button icon and tooltip in ChatInput component

* fix: correct indentation in tool call handling within ChatRoute class
2026-02-23 20:21:30 +08:00
エイカク
94736ff199 feat(dashboard): make release redirect base URL configurable (#5330)
* feat(dashboard): make desktop release base URL configurable

* refactor(dashboard): use generic release base URL env with upstream default

* fix(dashboard): guard release base URL normalization when env is unset

* refactor(dashboard): use generic release URL helpers and avoid latest suffix duplication
2026-02-22 20:23:32 +09:00
Soulter
aff92a48bf fix: remove changelogs directory from .dockerignore 2026-02-22 17:15:07 +08:00
Soulter
d0998a9dfb fix: remove hard-coded 6s timeout from tavily request 2026-02-22 16:58:49 +08:00
Soulter
3678688433 chore: ruff format 2026-02-22 16:51:46 +08:00
Lovely Moe Moli
0c03177840 fix: 修复 aiohttp 版本过新导致 qq-botpy 报错的问题 (#5316) 2026-02-22 16:45:28 +08:00
Soulter
20ff719c00 cho 2026-02-22 16:43:00 +08:00
Gao Jinzhe
8a8ec492d7 feat: supports spawn subagent as a background task that not block the main agent workflow (#5081)
* feat:为subagent添加后台任务参数

* ruff

* fix: update terminology from 'handoff mission' to 'background task' and refactor related logic

* fix: update terminology from 'background_mission' to 'background_task' in HandoffTool and related logic

* fix(HandoffTool): update background_task description for clarity on usage

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-22 13:57:42 +08:00
Helian Nuits
02c1443dd1 fix: 修复新版本插件市场出现插件显示为空白的 bug;纠正已安装插件卡片的排版,统一大小 (#5309)
* fix(ExtensionCard): 解决插件卡片大小不统一的问题

* fix(MarketPluginCard): 解决插件市场不加载插件的问题 (#5303)
2026-02-22 10:32:39 +08:00
Helian Nuits
79301f192c fix(SubAgentPage): 当中间的介绍文本非常长时,Flex 布局会自动挤压右侧的控制按钮区域 (#5306) 2026-02-22 10:31:49 +08:00
Soulter
4b2c854c42 chore: bump version to 4.18.0 2026-02-22 00:17:13 +08:00
Li-shi-ling
d02ee7be8b fix: 修复新建对话时因缺少会话ID导致配置绑定失败的问题 (#5292)
* fix:尝试修改

* fix:添加详细日志

* fix:进行详细修改,并添加日志

* fix:删除所有日志

* fix: 增加安全访问函数

- 给 localStorage 访问加了 try/catch + 可用性判断:dashboard/src/utils/chatConfigBinding.ts:13
- 新增 getFromLocalStorage/setToLocalStorage(在受限存储/无痕模式下异常时回退/忽略)
- getStoredDashboardUsername() / getStoredSelectedChatConfigId() 改为走安全读取:dashboard/src/utils/chatConfigBinding.ts:36       - 新增 setStoredSelectedChatConfigId(),写入失败静默忽略:dashboard/src/utils/chatConfigBinding.ts:44
- 把 ConfigSelector.vue 里直接 localStorage.getItem/setItem 全部替换为上述安全方法:dashboard/src/components/chat/ConfigSelector.vue:81
- 已重新跑过 pnpm run typecheck,通过。

* rm:删除个人用的文档文件

* Revert "rm:删除个人用的文档文件"

This reverts commit 0fceee0543.

* rm:删除个人用的文档文件

* rm:删除个人用的文档文件
2026-02-21 23:50:13 +08:00
Soulter
dbeadb6833 refactor: remove Anthropic OAuth provider implementation and related metadata overrides 2026-02-21 23:40:04 +08:00
evpeople
478cc32de1 Feat/telegram command alias register #5233 (#5234)
* feat: support registering command aliases for Telegram

Now when registering commands with aliases, all aliases will be
registered as Telegram bot commands in addition to the main command.

Example:
    @register_command(command_name="draw", alias={"画", "gen"})
Now /draw, /画, and /gen will all appear in the Telegram command menu.

* feat(telegram): add duplicate command name warning when registering commands

Log a warning when duplicate command names are detected during Telegram
command registration to help identify configuration conflicts.
2026-02-21 23:30:46 +08:00
Minidoracat
7b302445c2 feat: add Anthropic Claude Code OAuth provider and adaptive thinking support (#5209)
* feat: add Anthropic Claude Code OAuth provider and adaptive thinking support

* fix: add defensive guard for metadata overrides and align budget condition with docs

* refactor: adopt sourcery-ai suggestions for OAuth provider

- Use use_api_key=False in OAuth subclass to avoid redundant
  API-key client construction before replacing with auth_token client
- Generalize metadata override helper to merge all dict keys
  instead of only handling 'limit', improving extensibility
2026-02-21 23:29:15 +08:00
エイカク
ae839ef6d8 更新readme文档,补充桌面app说明,并向前移动位置 (#5297)
* docs: update desktop deployment section in README

* docs: refine desktop and launcher deployment descriptions

* Update README.md
2026-02-22 00:26:29 +09:00
Lovely Moe Moli
144a53f4b3 fix: qq official guild message send error (#5287)
* fix: qq official guild message send error

* Update astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-21 17:24:25 +08:00
Helian Nuits
fa1d1e6034 feat(dashboard): improve plugin platform support display and mobile accessibility (#5271)
* feat(dashboard): improve plugin platform support display and mobile accessibility

- Replace hover-based tooltips with interactive click menus for platform support information.
- Fix mobile touch issues by introducing explicit state control for status capsules.
- Enhance UI aesthetics with platform-specific icons and a structured vertical list layout.
- Add dynamic chevron icons to provide clear visual cues for expandable content.

* refactor(dashboard): refactor market card with computed properties for performance

* refactor(dashboard): unify plugin platform support UI with new reusable chip component

- Create shared 'PluginPlatformChip' component to encapsulate platform meta display.
- Fix mobile interaction bugs by simplifying menu triggers and event handling.
- Add stacked platform icon previews and dynamic chevron indicators within capsules.
- Improve information hierarchy using structured vertical lists for platform details.
- Optimize rendering efficiency with computed properties across both card views.
2026-02-21 17:22:22 +08:00
Soulter
a404436f2c feat: astrbot http api (#5280)
* feat: astrbot http api

* Potential fix for code scanning alert no. 34: Use of a broken or weak cryptographic hashing algorithm on sensitive data

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix: improve error handling for missing attachment path in file upload

* feat: implement paginated retrieval of platform sessions for creators

* feat: refactor attachment directory handling in ChatRoute

* feat: update API endpoint paths for file and message handling

* feat: add documentation link to API key management section in settings

* feat: update API key scopes and related configurations in API routes and tests

* feat: enhance API key expiration options and add warning for permanent keys

* feat: add UTC normalization and serialization for API key timestamps

* feat: implement chat session management and validation for usernames

* feat: ignore session_id type chunks in message processing

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-02-21 17:20:26 +08:00
zenfun
48a0b97ac0 test(skills): add skill metadata enrichment tests
11 tests covering:
- _parse_frontmatter_description: standard, description-only, empty,
  missing delimiter, quoted values
- build_skills_prompt: format, absolute path in example, progressive
  disclosure rules, absence of legacy custom fields
- SkillManager.list_skills: local frontmatter parsing, sandbox cache
  description passthrough
2026-02-21 01:06:39 +08:00
zenfun
d21212d0e4 test(computer): add profile-aware sandbox selection tests
17 tests covering:
- ShipyardNeoBooter.capabilities property (tuple, immutability, pre/post boot)
- _apply_sandbox_tools conditional browser tool registration
- _resolve_profile smart selection (user-specified, browser preference,
  API error fallback, empty profiles, auth error pass-through)
- ComputerBooter base class defaults
2026-02-21 01:03:58 +08:00
zenfun
c1917ebf4f fix(computer): resolve absolute skill paths at runtime in scan command
- Resolve skills root via Path.resolve() so LLM prompts always
  reference absolute paths regardless of sandbox cwd
- Use resolved path in skill metadata for reliable cat/head commands
- Add DRY cross-reference comment for frontmatter parser
- Remove dead skills_root_abs field from JSON output (no consumer)
- Remove unnecessary os import and fake resolve/abspath branch
2026-02-21 01:03:45 +08:00
zenfun
b816045f37 refactor(skills): rewrite skills prompt and sanitize example paths
- Rewrite build_skills_prompt() with structured numbered rules and
  markdown formatting for better LLM comprehension
- Sanitize example_path with _SAFE_PATH_RE before embedding in system
  prompt to prevent prompt injection via crafted skill paths
- Add docstring to _parse_frontmatter_description()
- Remove debug print(top_dirs) from install_skill_from_zip()
- Remove stale commented-out SANDBOX_SKILLS_ROOT line
2026-02-21 01:03:32 +08:00
zenfun
1df1138d04 feat(agent): conditionally register browser tools based on sandbox capabilities
_apply_sandbox_tools now checks the booted session's capabilities
before registering browser tools (BrowserExecTool, BrowserBatchExecTool,
RunBrowserSkillTool).

- If no session exists yet (first request), all tools are registered
  conservatively to avoid breaking the initial interaction
- If a session exists without browser capability, browser tools are
  omitted, preventing CapabilityNotSupportedError from Bay
- Skill lifecycle tools remain unconditionally registered
2026-02-21 01:03:19 +08:00
zenfun
1962ff2def feat(computer): expose sandbox capabilities and smart profile selection
Add capabilities property to ComputerBooter base class (returns None)
and ShipyardNeoBooter (returns immutable tuple from sandbox).

- Extract DEFAULT_PROFILE class constant to replace scattered magic string
- Use tuple[str, ...] for immutability (no defensive copy needed)
- Add _resolve_profile() for smart profile selection:
  - honour user-specified profile
  - query Bay API, prefer browser-capable profiles
  - re-raise auth errors (401/403), fallback on transient failures
- Conditionally create NeoBrowserComponent only when profile has browser
- Log resolved profile and capabilities at boot
2026-02-21 01:03:05 +08:00
香草味的纳西妲喵
bcb12a0717 fix: update contributor avatar image URL to include max size and columns (#5268) 2026-02-21 00:38:11 +08:00
エイカク
5d0fc8ac7a refactor(dashboard): replace legacy isElectron bridge fields with isDesktop (#5269)
* refactor dashboard desktop bridge fields from isElectron to isDesktop

* refactor dashboard runtime detection into shared helper
2026-02-21 01:35:23 +09:00
zenfun
92a8e40cde feat(computer): auto-start Bay container for zero-config Neo integration
Add BayContainerManager to manage Bay container lifecycle via Docker
Engine API, similar to how BoxliteBooter manages Ship containers.

When ShipyardNeoBooter endpoint is empty or set to '__auto__', Bay is
automatically pulled, started, health-checked, and credentials are
read from the container.

- New bay_manager.py: ensure_running, wait_healthy, read_credentials
- Integrate auto-start into ShipyardNeoBooter boot/shutdown
- Reuse Bay container across sessions (unless-stopped policy)
- Friendly error messages for Docker and credential failures
2026-02-20 23:11:19 +08:00
Soulter
a4d37e2c20 chore: ruff format 2026-02-20 23:06:37 +08:00
Soulter
c599fb75ed feat: add OpenRouter provider support and icon 2026-02-20 22:57:20 +08:00
Soulter
e7e0f84edf chore: bump vertion to 4.17.6 2026-02-20 18:40:45 +08:00
Soulter
e19a282c59 fix: streamline error response for empty new username and password in account edit 2026-02-20 18:35:26 +08:00
Raven95676
fbc8667968 fix: simplify error messages for account edit validation 2026-02-20 16:27:28 +08:00
Soulter
cda49c3a9a fix: remove additionalProperties from tool schema properties (#5253)
fixes: #5217
2026-02-20 16:13:20 +08:00
Soulter
4be1027444 fix: update tool status display and add localization for inactive tools 2026-02-20 16:01:55 +08:00
Soulter
46152d3faf fix: enhance PersonaForm layout and improve tool selection display 2026-02-20 15:54:06 +08:00
Soulter
ed4cacfffb fix: all mcp tools exposed to main agent (#5252) 2026-02-20 15:40:13 +08:00
Soulter
52d1979937 chore: remove outdated heihe.md documentation file 2026-02-20 14:47:06 +08:00
NayukiMeko
b30cb12133 fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题 (#5250)
* fix(provider): 修复 dict 格式 content 导致的 JSON 残留问题

修复 _normalize_content 函数未处理 dict 类型 content 的问题。
当 LLM 返回 {"type": "text", "text": "..."} 格式的 content 时,
现在会正确提取 text 字段而非直接转为字符串。

同时改进 fallback 行为,对 None 值返回空字符串。

Fixes #5244

* Update warning message for unexpected dict format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-20 13:48:41 +08:00
whatevertogo
31d4e304fc feat: add password confirmation when changing password (#5247)
* feat: add password confirmation when changing password

Fixes #5177

Adds a password confirmation field to prevent accidental password typos.

Changes:
- Backend: validate confirm_password matches new_password
- Frontend: add confirmation input with validation
- i18n: add labels and error messages for password mismatch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(auth): improve error message for password confirmation mismatch

* fix(auth): update password hashing logic and improve confirmation validation

---------

Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 13:41:13 +08:00
Soulter
9a7a594cb5 feat: add support for plugin astrbot-version and platform requirement checks (#5235)
* feat: add support for plugin astrbot-version and platform requirement checks

* fix: remove unsupported platform and version constraints from metadata.yaml

* fix: remove restriction on 'v' in astrbot_version specification format

* ruff format
2026-02-20 13:35:45 +08:00
SnowNightt
e469178a6b Feat/config leave confirm (#5249)
* feat: 配置文件增加未保存提示弹窗

* fix: 移除unsavedChangesDialog插件使用组件方式实现弹窗
2026-02-20 12:55:21 +08:00
Soulter
0a517980b7 fix: update feature request template for clarity and consistency in English and Chinese 2026-02-20 12:07:42 +08:00
エイカク
9c691b2266 chore: remove Electron desktop pipeline and switch to tauri repo (#5226)
* ci: remove Electron desktop build from release pipeline

* chore: remove electron desktop and switch to tauri release trigger

* ci: remove desktop workflow dispatch trigger

* refactor: migrate data paths to astrbot_path helpers

* fix: point desktop update prompt to AstrBot-desktop releases
2026-02-19 23:04:18 +09:00
雪語
3597726aad fix(core): terminate active events on reset/new/del to prevent stale responses (#5225)
* fix(core): terminate active events on reset/new/del to prevent stale responses

Closes #5222

* style: fix import sorting in scheduler.py
2026-02-19 19:26:47 +08:00
Soulter
a4a37c268d docs: update related repo links 2026-02-19 18:11:07 +08:00
NanoRocky
651a0645c5 fix: 修复仅发送 JSON 消息段时的空消息回复报错 (#5208)
* Fix Register_Stage

· 补全 JSON 消息判断,修复发送 JSON 消息时遇到 “消息为空,跳过发送阶段” 的问题。
· 顺带补全其它消息类型判断。
Co-authored-by: Pizero <zhaory200707@outlook.com>

* Fix formatting and comments in stage.py

* Format stage.py

---------

Co-authored-by: Pizero <zhaory200707@outlook.com>
2026-02-19 17:47:08 +08:00
Dream Tokenizer
bf3fa3e918 fix: 改进微信公众号被动回复处理机制,引入缓冲与分片回复,并优化超时行为 (#5224)
* 修复wechat official 被动回复功能

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-19 17:42:38 +08:00
Soulter
3b2ce9f500 feat: add admin permission checks for Python and Shell execution (#5214) 2026-02-19 01:48:48 +08:00
zenfun
3769f145ee feat(dashboard): validate Bay connectivity on config save
When saving config with shipyard_neo sandbox, _validate_neo_connectivity()
performs an async /health check against the Bay endpoint. If Bay is
unreachable, a ⚠️ warning is appended to the success snackbar message.
Config still saves successfully — the warning is informational only.
2026-02-19 01:41:29 +08:00
zenfun
18ebeae318 test(computer): add tests for credentials discovery and config logging
19 tests in test_computer_config.py:
- TestDiscoverBayCredentials (9 tests): env priority, cwd fallback,
  missing file, empty key, malformed JSON, endpoint mismatch, slash normalization
- TestLogComputerConfigChanges (10 tests): runtime change, sandbox key change,
  token masking, empty token label, missing provider_settings, add/remove keys

Uses unittest.mock.patch on AstrBot custom logger for reliable assertions.
2026-02-19 01:26:04 +08:00
zenfun
7e246477f0 fix(dashboard): graceful error handling for Neo skills when unconfigured
- Add _discover_bay_credentials() auto-discovery in _get_neo_client_config()
- Catch ValueError separately in _with_neo_client(), log at DEBUG instead of
  ERROR with full traceback — prevents log spam when visiting Skills page
  without Bay configured
2026-02-19 01:25:50 +08:00
Soulter
20d6ff4620 chore: bump version to 4.17.5 2026-02-18 22:04:43 +08:00
Chiu Chun-Hsien
a2b61e2ab8 refactor: extract Voice_messages_forbidden fallback into shared helper with typed BadRequest exception (#5204)
- Add _send_voice_with_fallback helper to deduplicate voice forbidden handling
- Catch telegram.error.BadRequest instead of bare Exception with string matching
- Add text field to Record component to preserve TTS source text
- Store original text in Record during TTS conversion for use as document caption
- Skip _send_chat_action when chat_id is empty to avoid unnecessary warnings
2026-02-18 21:45:19 +08:00
sanyekana
c6289d8f75 feat(core): add plugin error hook for custom error routing (#5192)
* feat(core): add plugin error hook for custom error routing

* fix(core): align plugin error suppression with event stop state
2026-02-18 21:38:27 +08:00
Soulter
567390e27c feat: add LINE support to multiple language README files 2026-02-18 21:35:27 +08:00
Soulter
0c0f8bf484 chore: ruff format 2026-02-18 18:22:06 +08:00
Soulter
ae0a9cb591 docs: update readme 2026-02-18 18:20:08 +08:00
Soulter
3f4d7255a0 feat: supports aihubmix 2026-02-18 18:11:13 +08:00
Soulter
b8d2499475 feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage (#5190)
* feat: add MarketPluginCard component and integrate random plugin feature in ExtensionPage

* feat: update random plugin selection logic to use pluginMarketData and refresh on relevant events
2026-02-18 17:29:04 +08:00
SnowNightt
8cb26d886f fix: 修复选择配置文件进入配置文件管理弹窗直接关闭弹窗显示的配置文件不正确 (#5174) 2026-02-18 16:33:18 +08:00
時壹
3ca8dd204f fix: prevent duplicate error message when all LLM providers fail (#5183) 2026-02-18 16:29:35 +08:00
RC-CHN
bc3e09f47b refactor(computer): split sandbox skill sync phases
separate sandbox skill syncing into distinct apply and scan steps
while keeping the legacy combined command for compatibility

improve observability by adding phase-based logs and richer shell
error details that include exit code, stderr, and stdout tail

reuse a shared python-exec command builder to reduce duplication
and keep command generation consistent
2026-02-18 13:35:17 +08:00
Soulter
3476afce41 feat: supports send markdown message in qqofficial (#5173)
* feat: supports send markdown message in qqofficial

closes: #1093 #918 #4180 #4264

* ruff format
2026-02-18 00:35:52 +08:00
Soulter
9b0e24ec49 chore: bump version to 4.17.4 2026-02-17 21:19:53 +08:00
Soulter
92d71fffe9 feat: add announcement section to WelcomePage and localize announcement title 2026-02-17 21:15:12 +08:00
Soulter
80c22f4f72 feat: add FAQ link to vertical sidebar and update navigation for localization 2026-02-17 21:01:29 +08:00
Soulter
6e22d266dd feat: implement search functionality in configuration components and update UI (#5168) 2026-02-17 20:47:24 +08:00
Soulter
4c285fb521 feat: add unsaved changes notice to configuration page and update messages 2026-02-17 20:32:25 +08:00
Helian Nuits
51c3521aaa ui(CronJobPage): fix action column buttons overlapping in CronJobPage (#5163)
- 修改前:操作列容器仅使用 `d-flex`,在页面宽度变窄时,子元素(开关和删除按钮)会因为宽度挤压而发生视觉重叠,甚至堆叠在一起。
- 修改后:
    1. 为容器添加了 `flex-nowrap`,强制禁止子元素换行。
    2. 设置了 `min-width: 140px`,确保该列拥有固定的保护空间,防止被其他长文本列挤压。
    3. 增加了 `gap: 12px` 间距,提升了操作辨识度并优化了点击体验。
2026-02-17 18:58:05 +08:00
Soulter
32112a3326 feat: enhance PersonaForm component with responsive design and improved styling (#5162)
fix: #5159
2026-02-17 18:46:52 +08:00
Soulter
f22221f781 fix: improve permission denied message for local execution in Python and shell tools 2026-02-17 18:02:41 +08:00
RC-CHN
707db768ea style: format code 2026-02-17 17:26:37 +08:00
RC-CHN
591803d407 refactor(skills): centralize neo promote and sync flow
extract shared promote/sync orchestration into `NeoSkillSyncManager` so
computer tools and dashboard routes use the same rollback and error logic

add a reusable neo tool base runner to remove duplicated admin checks and
try/catch handling across skill-related tools, keeping responses consistent

factor sync result serialization into a single helper and reuse it where
stable release sync output is returned
2026-02-17 17:20:42 +08:00
RC-CHN
b48919246d refactor(api): centralize neo client lifecycle in skills route
extract a shared `_with_neo_client` wrapper to handle neo client
setup, teardown, and error responses in one place.

reduce duplicated try/except and `BayClient` context boilerplate across
neo skills endpoints while preserving existing request validation and
response payloads.
2026-02-17 17:06:11 +08:00
RC-CHN
cf9a7235f7 fix(computer): return none for unsupported browser capability
set the base booter browser property to return None instead of
raising NotImplementedError so callers can handle missing browser
support through capability checks
2026-02-17 16:59:05 +08:00
RC-CHN
d62a6f107b fix(computer): mask bay api key in logs
Also add shipyard-neo-sdk dependency for neo support
2026-02-17 16:40:55 +08:00
Ruochen Pan
1a539830f8 Merge branch 'master' into feat/neo-skill-self-iteration 2026-02-17 16:23:14 +08:00
Soulter
4250d997b3 feat: enhance provider sources panel with styled menu and mobile support 2026-02-17 16:14:35 +08:00
Soulter
153d8cef6b feat: add NVIDIA provider template (#5157)
fixes: #5156
2026-02-17 16:08:35 +08:00
Soulter
c9cdf47603 chore: ruff format 2026-02-17 14:33:27 +08:00
Soulter
55ac878648 chore: bump version to 4.17.3 2026-02-17 14:09:10 +08:00
Soulter
60abddada3 fix: enhance handle_result to support event context and webchat image sending 2026-02-17 14:03:29 +08:00
Soulter
bbc583cc8d fix: enhance plugin metadata handling by injecting attributes before instantiation (#5155) 2026-02-17 14:01:31 +08:00
Soulter
7906030037 fix: 'Plain' object has no attribute 'text' when using python 3.14 (#5154) 2026-02-17 13:51:25 +08:00
エイカク
06b385697d fix(desktop): include runtime deps for builtin plugins in backend build (#5146) 2026-02-17 11:43:19 +09:00
Raven95676
059008a903 fix: prevent updates for AstrBot launched via launcher 2026-02-17 09:33:45 +08:00
zenfun
418913aa53 docs: add PR verification workflow to CONTRIBUTING.md
Document make pr-test-neo and make pr-test-full commands for local
CI-equivalent verification before submitting PRs.
2026-02-17 04:25:06 +08:00
zenfun
4b07aa2bc3 test(computer): add tests for credentials discovery and config logging
19 new tests in test_computer_config.py:
- TestDiscoverBayCredentials (9 tests): env priority, cwd fallback,
  missing file, empty key, malformed JSON, endpoint mismatch, slash normalization
- TestLogComputerConfigChanges (10 tests): runtime change, sandbox key change,
  token masking, empty token label, missing provider_settings, add/remove keys
2026-02-17 04:24:55 +08:00
zenfun
64d8daa67d feat(scripts): update start-with-neo.sh for auto-provisioned API key
- Generated config uses allow_anonymous: false (triggers auto-provision)
- Set BAY_DATA_DIR so credentials.json writes to pkgs/bay/
- Add read_bay_credentials() to extract auto-generated key after boot
- Display API key in config hints for easy AstrBot setup
2026-02-17 04:24:44 +08:00
zenfun
9d44947500 feat(dashboard): update Shipyard Neo config hints
- Endpoint hint: mention default port 8114
- Access Token hint: mention sk-bay-* format and credentials.json auto-discovery
- Updated in default.py, zh-CN, and en-US i18n files
2026-02-17 04:24:34 +08:00
zenfun
4043a10531 fix(computer): improve ShipyardNeoBooter error message
Include default endpoint URL (http://127.0.0.1:8114) and credentials.json
auto-discovery hint in the ValueError message when config is incomplete.
2026-02-17 04:24:24 +08:00
zenfun
7c8dac2fd5 feat(computer): add Bay credentials.json auto-discovery
When shipyard_neo_access_token is not configured, _discover_bay_credentials()
searches for Bay's credentials.json in:
1. BAY_DATA_DIR env var
2. Mono-repo relative path ../pkgs/bay/
3. Current working directory

Enables zero-config dev mode when Bay runs locally alongside AstrBot.
2026-02-17 04:24:12 -06:00
Soulter
97c9e95211 chore: ruff format 2026-02-17 02:31:38 +08:00
Soulter
a4be369e43 chore: bump version to 4.17.1 2026-02-17 02:30:13 +08:00
Soulter
bdaca78750 fix: add support for collecting data from builtin stars in electron pyinstaller build (#5145) 2026-02-17 02:27:07 +08:00
Soulter
6326d7e4ba fix: add MCP tools to function tool set in _plugin_tool_fix (#5144) 2026-02-17 02:19:36 +08:00
Soulter
a809a09e55 docs: Added instructions for deploying AstrBot using AstrBot Launcher. (#5136)
Added instructions for deploying AstrBot using AstrBot Launcher.
2026-02-16 17:06:56 +08:00
zenfun
963122b916 chore: update gitignore, Makefile, skills route, and test scaffolding 2026-02-16 02:38:01 +08:00
zenfun
aa3b012d60 feat: add Shipyard Neo quick-start script
Add scripts/start-with-neo.sh: one-click launcher that auto-generates
Bay config.yaml (anonymous mode, host_port), pulls Ship image, starts
Bay (port 8114) with health check, then starts AstrBot in foreground.
Ctrl+C stops both services. Supports BAY_PORT env var override.
2026-02-16 02:37:48 +08:00
zenfun
401dfb9ee2 feat(dashboard): log Computer/sandbox config changes on save
Add _log_computer_config_changes() to detect and log modifications to
computer_use_runtime and sandbox.* keys when saving config via Dashboard.
Sensitive fields (tokens/secrets) are masked in log output.
2026-02-16 02:37:24 +08:00
zenfun
1d81c52950 feat(computer): add INFO-level lifecycle logging to booter implementations
Add [Computer] prefixed INFO logs to:
- shipyard_neo.py: shutdown, upload_file, download_file, available
- shipyard.py: shutdown, upload_file, download_file, available
- boxlite.py: upload_file success path
- computer_client.py: sync_skills_to_active_sandboxes, _sync_skills_to_sandbox

Improves traceability of sandbox lifecycle events.
2026-02-16 02:37:14 +08:00
Soulter
52c4ef2d87 chore: bump version to 4.17.1 2026-02-15 23:45:34 +08:00
Soulter
52c31fabe2 fix: update retention logic in LogManager to handle backup count correctly 2026-02-15 23:42:12 +08:00
NayukiMeko
79e239ad97 fix: handle list format content from OpenAI-compatible APIs (#5128)
* fix: handle list format content from OpenAI-compatible APIs

Some LLM providers (e.g., GLM-4.5V via SiliconFlow) return content as
list[dict] format like [{'type': 'text', 'text': '...'}] instead of
plain string. This causes the raw list representation to be displayed
to users.

Changes:
- Add _normalize_content() helper to extract text from various content formats
- Use json.loads instead of ast.literal_eval for safer parsing
- Add size limit check (8KB) before attempting JSON parsing
- Only convert lists that match OpenAI content-part schema (has 'type': 'text')
  to avoid collapsing legitimate list-literal replies like ['foo', 'bar']
- Add strip parameter to preserve whitespace in streaming chunks
- Clean up orphan </think> tags that may leak from some models

Fixes #5124

* fix: improve content normalization safety

- Try json.loads first, fallback to ast.literal_eval for single-quoted
  Python literals to avoid corrupting apostrophes (e.g., "don't")
- Coerce text values to str to handle null or non-string text fields
2026-02-15 23:30:47 +08:00
Soulter
8abaf1015d chore: bump version to 4.17.0 2026-02-15 21:51:00 +08:00
Soulter
9a0c814fd4 feat: add SSL configuration options for WebUI and update related logging (#5117) 2026-02-15 17:43:36 +08:00
Soulter
c64e1b42a4 feat: replace colorlog with loguru for enhanced logging support (#5115) 2026-02-15 17:11:03 +08:00
Soulter
2d23c36067 feat: add Afdian support card to resources section in WelcomePage 2026-02-15 16:20:34 +08:00
Soulter
754144ad99 feat: add fallback chat model chain in tool loop runner (#5109)
* feat: implement fallback provider support for chat models and update configuration

* feat: enhance provider selection display with count and chips for selected providers

* feat: update fallback chat providers to use provider settings and add warning for non-list fallback models
2026-02-15 11:51:34 +08:00
Waterwzy
0faf109c2a feat: support hot reload after plugin load failure (#5043)
* add :Support hot reload after plugin load failure

* Apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix:reformat code

* fix:reformat code

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-02-13 18:37:20 +08:00
evpeople
7d1eff3ec4 fix #5089: add uv lock step in Dockerfile before export (#5091)
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-13 18:34:26 +08:00
Soulter
e295c470a5 fix: remove unnecessary frozen flag from requirements export in Dockerfile
fixes: #5089
2026-02-13 18:09:49 +08:00
Li-shi-ling
935168c024 fix-correct-FIRST_NOTICE.md-locale-path-resolution (#5083) (#5082)
* fix:修改配置文件目录

* fix:添加备选的FIRST_NOTICE.zh-CN.md用于兼容
2026-02-13 13:15:08 +08:00
Soulter
f44961d065 feat: add LINE platform support with adapter and configuration (#5085) 2026-02-13 13:01:48 +08:00
zenfun
40c7cf3901 feat(skills): merge sandbox built-ins with uploaded skill sync 2026-02-13 03:20:51 +08:00
Soulter
0c7a95ccd8 chore: bump version to 4.16.0 (#5074) 2026-02-12 22:55:42 +08:00
Soulter
09215bad57 fix: add config tabs and routing for normal and system configurations 2026-02-12 22:48:17 +08:00
エイカク
4ff07e3c74 fix: 完善转发引用解析与图片回退并支持配置化控制 (#5054)
* feat: support fallback image parsing for quoted messages

* fix: fallback parse quoted images when reply chain has placeholders

* style: format network utils with ruff

* test: expand quoted parser coverage and improve fallback diagnostics

* fix: fallback to text-only retry when image requests fail

* fix: tighten image fallback and resolve nested quoted forwards

* refactor: simplify quoted message extraction and dedupe images

* fix: harden quoted parsing and openai error candidates

* fix: harden quoted image ref normalization

* refactor: organize quoted parser settings and logging

* fix: cap quoted fallback images and avoid retry loops

* refactor: split quoted message parser into focused modules

* refactor: share onebot segment parsing logic

* refactor: unify quoted message parsing flow

* feat: move quoted parser tuning to provider settings

* fix: add missing i18n metadata for quoted parser settings

* chore: refine forwarded message setting labels
2026-02-12 23:42:29 +09:00
stevessr
473e01aadd feat: add i18n supports for custom platform adapters (#5045)
* Feat: 为插件提供的适配器的元数据&i18n提供数据通路

* chore: update docstrings with pull request references

Added references to pull request 5045 in docstrings.

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-12 21:49:12 +08:00
Soulter
cd5312ba77 fix: chunk err when using openrouter deepseek (#5069) 2026-02-12 19:26:12 +08:00
Soulter
d87bfb0d5d perf: 优化分段回复间隔时间的初始化逻辑 (#5068)
fixes: #5059
2026-02-12 19:18:23 +08:00
Soulter
d2de0ea5ad feat: QQ 官方机器人平台支持主动推送消息、私聊场景下支持接收文件 (#5066)
* feat: QQ 官方机器人平台支持主动推送消息、私聊场景下支持接收文件

* feat: enhance QQOfficialWebhook to remember session scenes for group, channel, and friend messages
2026-02-12 19:07:53 +08:00
xzj0898
4af064fd17 fix: 修复备份时缺失的人格文件夹映射 (#5042) 2026-02-12 16:40:45 +08:00
letr
8ab2b515f6 docs: sync and fix readme typo (#5055)
* docs: fix index typo

* docs: fix typo in README_en.md

- 移除英文README中意外出现的俄语,并替换为英语

* docs: fix html typo

- remove unused '</p>'

* docs: sync table with README

* docs: sync README header format

- keep the README header format consistent

* doc: sync key features

* style: format files

- Fix formatting issues from previous PR

* fix: correct md anchor link

* docs: correct typo in README_fr.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* docs: correct typo in README_zh-TW.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-02-12 16:37:25 +08:00
SnowNightt
51a1c0e375 fix: 修复更新日志、官方文档弹窗双滚动条问题 (#5060) 2026-02-12 16:36:05 +08:00
evpeople
30a0098b2a feat: add send_chat_action for Telegram platform adapter (#5037)
* feat: add send_chat_action for Telegram platform adapter

Add typing/upload indicator when sending messages via Telegram.
- Added _send_chat_action helper method for sending chat actions
- Send appropriate action (typing, upload_photo, upload_document, upload_voice)
  before sending different message types
- Support streaming mode with typing indicator
- Support supergroup with message_thread_id

* refactor(telegram): extract chat action helpers and add throttling

- Add ACTION_BY_TYPE mapping for message type to action priority
- Add _get_chat_action_for_chain() to determine action from message chain
- Add _send_media_with_action() for upload → send → restore typing pattern
- Add _ensure_typing() helper for typing status
- Add chat action throttling (0.5s) in streaming mode to avoid rate limits
- Update type annotation to ChatAction | str for better static checking

* feat(telegram): implement send_typing method for Telegram platform

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-12 14:46:06 +08:00
Soulter
e3cb9eb8af chore: ruff format 2026-02-12 13:56:33 +08:00
Soulter
b0de33c801 fix: provider extra param dialog key display error 2026-02-12 13:09:34 +08:00
letr
bcdd8c463c docs: clean and sync README (#5014)
* fix: close missing div in README

* fix: sync README_zh-TW with README

* fix: sync README

* fix: correct typo

correct url in README_en README_fr README_ru

* docs: sync README_en with README

* Update README_en.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-12 01:17:15 +08:00
Soulter
336e2a2c40 fix: update error logging message for connection failures 2026-02-12 01:14:49 +08:00
Limitless
338d8a6610 fix: close unawaited reset coroutine on early return (#5033)
When an OnLLMRequestEvent hook stops event propagation, the
reset_coro created by build_main_agent was never awaited, causing
a RuntimeWarning. Close the coroutine explicitly before returning.

Fixes #5032

Co-authored-by: Limitless2023 <limitless@users.noreply.github.com>
2026-02-12 01:07:13 +08:00
Soulter
9d93bda3fe feat: temporary file handling and introduce TempDirCleaner (#5026)
* feat: temporary file handling and introduce TempDirCleaner

- Updated various modules to use `get_astrbot_temp_path()` instead of `get_astrbot_data_path()` for temporary file storage.
- Renamed temporary files for better identification and organization.
- Introduced `TempDirCleaner` to manage the size of the temporary directory, ensuring it does not exceed a specified limit by deleting the oldest files.
- Added configuration option for maximum temporary directory size in the dashboard.
- Implemented tests for `TempDirCleaner` to verify cleanup functionality and size management.

* ruff
2026-02-12 01:04:48 +08:00
エイカク
a8dda20a30 fix: 提升打包版桌面端启动稳定性并优化插件依赖处理 (#5031)
* fix(desktop): rotate electron and backend logs

* refactor(desktop): centralize log rotation defaults and debug fs errors

* fix(desktop): harden rotation fs ops and buffer backend log writes

* refactor(desktop): extract buffered logger and reduce sync stat calls

* refactor(desktop): simplify rotation flow and harden logger config

* fix(desktop): make app logging async and flush-safe

* fix: harden app log path switching and debug-gated rotation errors

* fix: cap buffered log chunk size during path switch

* fix: avoid redundant plugin reinstall and upgrade electron

* fix: stop webchat tasks cleanly and bind packaged backend to localhost

* fix: unify platform shutdown and await webchat listener cleanup

* fix: improve startup logs for dashboard and onebot listeners

* fix: revert extra startup service logs

* fix: harden plugin import recovery and webchat listener cleanup

* fix: pin dashboard ci node version to 24.13.0

* fix: avoid duplicate webchat listener cleanup on terminate

* refactor: clarify platform task lifecycle management

* fix: continue platform shutdown when terminate fails
2026-02-12 01:04:04 +08:00
Soulter
cd7755fe07 feat: add first notice feature with multilingual support and UI integration 2026-02-12 00:00:53 +08:00
zenfun
afe292de35 fix: address neo skill review findings 2026-02-11 19:35:01 +08:00
エイカク
dc995af34b fix(desktop): 为 Electron 与后端日志增加按大小轮转 (#5029)
* fix(desktop): rotate electron and backend logs

* refactor(desktop): centralize log rotation defaults and debug fs errors

* fix(desktop): harden rotation fs ops and buffer backend log writes

* refactor(desktop): extract buffered logger and reduce sync stat calls

* refactor(desktop): simplify rotation flow and harden logger config

* fix(desktop): make app logging async and flush-safe

* fix: harden app log path switching and debug-gated rotation errors

* fix: cap buffered log chunk size during path switch
2026-02-11 20:17:57 +09:00
zenfun
d4dcc6430f chore: apply pre-commit formatting fixes for neo integration 2026-02-11 17:34:07 +08:00
zenfun
a8cc995633 feat(dashboard): add neo skills APIs and management UI 2026-02-11 17:14:55 +08:00
zenfun
73251db1da feat(skills): add neo lifecycle tools and stable sync manager 2026-02-11 17:14:47 +08:00
zenfun
d16398a0e8 feat(computer): add shipyard_neo booter runtime and sandbox config 2026-02-11 17:14:38 +08:00
LIghtJUNction
331ada02fd docs: add AUR installation method (#4879)
* docs: sync system package manager installation instructions to all languages

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update README.md

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix/typo

* refactor: update system package manager installation instructions for Arch Linux across multiple language README files

* feat: add installation command for AstrBot in multiple language README files

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-02-11 13:36:17 +08:00
Soulter
80e1231e9a feat: adding support for media and quoted message attachments for feishu (#5018) 2026-02-11 13:26:27 +08:00
エイカク
e61b29ec6a fix: harden plugin dependency loading in frozen app runtime (#5015)
* fix: compare plugin versions semantically in market updates

* fix: prioritize plugin site-packages for in-process pip

* fix: reload starlette from plugin target site-packages

* fix: harden plugin dependency import precedence in frozen runtime

* fix: improve plugin dependency conflict handling

* refactor: simplify plugin conflict checks and version utils

* fix: expand transitive plugin dependencies for conflict checks

* fix: recover conflicting plugin dependencies during module prefer

* fix: reuse renderer restart flow for tray backend restart

* fix: add recoverable plugin dependency conflict handling

* revert: remove plugin version comparison changes

* fix: add missing tray restart backend labels
2026-02-11 13:01:44 +09:00
Soulter
16d49d568b fix: add reminder for v4.14.8 users regarding manual redeployment due to a bug 2026-02-10 23:20:49 +08:00
Soulter
776e17062c chore: bump version to 4.15.0 (#5003) 2026-02-10 23:17:23 +08:00
エイカク
8fa8c14b0b fix: 修复app内重启异常,修复app内点击重启不能立刻提示重启,以及在后端就绪时及时刷新界面的问题 (#5013)
* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: avoid frozen restart crash from multiprocessing import

* fix: include missing frozen dependencies for windows backend

* fix: use execv for stable backend reboot args

* Revert "fix: use execv for stable backend reboot args"

This reverts commit 9cc27becff.

* Revert "fix: include missing frozen dependencies for windows backend"

This reverts commit 52554bea1f.

* Revert "fix: avoid frozen restart crash from multiprocessing import"

This reverts commit 10548645b0.

* fix: reset pyinstaller onefile env before reboot

* fix: unify electron restart path and tray-exit backend cleanup

* fix: stabilize desktop restart detection and frozen reboot args

* fix: make dashboard restart wait detection robust

* fix: revert dashboard restart waiting interaction tweaks

* fix: pass auth token for desktop graceful restart

* fix: avoid false failure during graceful restart wait

* fix: start restart waiting before electron restart call

* fix: harden restart waiting and reboot arg parsing

* fix: parse start_time as numeric timestamp

* fix: preserve windows frozen reboot argv quoting

* fix: align restart waiting with electron restart timing

* fix: tighten graceful restart and unmanaged kill safety
2026-02-10 22:21:04 +09:00
エイカク
64de474139 fix: 修复 Windows 打包版后端重启失败问题 (#5009)
* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage

* fix: avoid frozen restart crash from multiprocessing import

* fix: include missing frozen dependencies for windows backend

* fix: use execv for stable backend reboot args

* Revert "fix: use execv for stable backend reboot args"

This reverts commit 9cc27becff.

* Revert "fix: include missing frozen dependencies for windows backend"

This reverts commit 52554bea1f.

* Revert "fix: avoid frozen restart crash from multiprocessing import"

This reverts commit 10548645b0.

* fix: reset pyinstaller onefile env before reboot

* fix: unify electron restart path and tray-exit backend cleanup

* fix: stabilize desktop restart detection and frozen reboot args

* fix: make dashboard restart wait detection robust

* fix: revert dashboard restart waiting interaction tweaks

* fix: pass auth token for desktop graceful restart

* fix: avoid false failure during graceful restart wait

* fix: start restart waiting before electron restart call

* fix: harden restart waiting and reboot arg parsing

* fix: parse start_time as numeric timestamp
2026-02-10 21:33:06 +09:00
エイカク
d35771f97d fix: stabilize packaged runtime pip/ssl behavior and mac font fallback (#5007)
* fix: patch pip distlib finder for frozen electron runtime

* fix: use certifi CA bundle for runtime SSL requests

* fix: configure certifi CA before core imports

* fix: improve mac font fallback for dashboard text

* fix: harden frozen pip patch and unify TLS connector

* refactor: centralize dashboard CJK font fallback stacks

* perf: reuse TLS context and avoid repeated frozen pip patch

* refactor: bootstrap TLS setup before core imports

* fix: use async confirm dialog for provider deletions

* fix: replace native confirm dialogs in dashboard

- Add shared confirm helper in dashboard/src/utils/confirmDialog.ts for async dialog usage with safe fallback.

- Migrate provider, chat, config, session, platform, persona, MCP, backup, and knowledge-base delete/close confirmations to use the shared helper.

- Remove scattered inline confirm handling to keep behavior consistent and avoid native blocking dialog focus/caret issues in Electron.

* fix: capture runtime bootstrap logs after logger init

- Add bootstrap record buffer in runtime_bootstrap for early TLS patch logs before logger is ready.

- Flush buffered bootstrap logs to astrbot logger at process startup in main.py.

- Include concrete exception details for TLS bootstrap failures to improve diagnosis.

* fix: harden runtime bootstrap and unify confirm handling

- Simplify bootstrap log buffering and add a public initialize hook for non-main startup paths.

- Guard aiohttp TLS patching with feature/type checks and keep graceful fallback when internals are unavailable.

- Standardize dashboard confirmation flow via shared confirm helpers across composition and options API components.

* refactor: simplify runtime tls bootstrap and tighten confirm typing

* refactor: align ssl helper namespace and confirm usage
2026-02-10 16:42:43 +09:00
dependabot[bot]
7a4d20d329 chore(deps): bump the github-actions group with 2 updates (#5006)
Bumps the github-actions group with 2 updates: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `astral-sh/setup-uv` from 6 to 7
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v6...v7)

Updates `actions/download-artifact` from 6 to 7
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  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-02-10 11:10:26 +08:00
Li-shi-ling
aab095347f fix: 'HandoffTool' object has no attribute 'agent' (#5005)
* fix: 移动agent的位置到super().__init__之后

* add: 添加一行注释
2026-02-10 11:01:49 +08:00
エイカク
1addd5b2ab perf: 稳定源码与 Electron 打包环境下的 pip 安装行为,并修复非 Electron 环境下点击 WebUI 更新按钮时出现跳转对话框的问题 (#4996)
* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling

* fix: scope global data root to packaged electron runtime

* refactor: inline frozen runtime check for electron guard

* fix: prefer current interpreter for source pip installs

* fix: avoid resolving venv python symlink for pip

* refactor: share runtime environment detection utilities

* fix: improve error message when pip module is unavailable

* fix: raise ImportError when pip module is unavailable

* fix: preserve ImportError semantics for missing pip

* fix: 修复非electron app环境更新时仍然显示electron更新对话框的问题

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-09 23:12:18 +08:00
Soulter
da4bb6549c feat: enhance persona tool management and update UI localization for subagent orchestration (#4990)
* feat: enhance persona tool management and update UI localization for subagent orchestration

* fix: remove debug logging for final ProviderRequest in build_main_agent function
2026-02-09 22:38:05 +08:00
Soulter
7193454d50 feat: enhance WecomAIBotAdapter and WecomAIBotMessageEvent for improved streaming message handling (#5000)
fixes: #3965
2026-02-09 22:30:24 +08:00
Soulter
d204b92877 feat: 企业微信智能机器人支持主动消息推送以及发送视频、文件等消息类型支持 (#4999) 2026-02-09 22:16:44 +08:00
Soulter
04faf26140 feat: 企业微信应用 支持主动消息推送,并优化企微应用、微信公众号、微信客服音频相关的处理 (#4998) 2026-02-09 22:15:11 +08:00
鸦羽
67b81c279b fix: collect certifi data in desktop backend build (#4995) 2026-02-09 19:40:32 +09:00
エイカク
2afb08d8b2 fix: handle pip install execution in frozen runtime (#4985)
* fix: handle pip install execution in frozen runtime

* fix: harden pip subprocess fallback handling
2026-02-09 15:19:01 +08:00
Soulter
06b2c7cb16 feat: enhance Dingtalk adapter with active push message and image, video, audio message type (#4986) 2026-02-09 15:17:55 +08:00
Copilot
9c12803ddd feat: add delete button to persona management dialog (#4978)
* Initial plan

* feat: add delete button to persona management dialog

- Added delete button to PersonaForm dialog (only visible when editing)
- Implemented deletePersona method with confirmation dialog
- Connected delete event to PersonaManager for proper handling
- Button positioned on left side of dialog actions for clear separation
- Uses existing i18n translations for delete button and messages

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: use finally block to ensure saving state is reset

- Moved `this.saving = false` to finally block in deletePersona
- Ensures UI doesn't stay in saving state after errors
- Follows best practices for state management

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-09 11:59:28 +08:00
Soulter
ce65491d55 chore: update pydantic dependency version (#4980) 2026-02-09 11:59:05 +08:00
Soulter
b67adcf481 ci: change ghcr namespace 2026-02-09 11:51:56 +08:00
Soulter
1707d55c02 fix: prepare OpenSSL via vcpkg for Windows ARM64 2026-02-09 11:04:31 +08:00
LIghtJUNction
48c2d98dde 删除 bun.lock,让行数看起来没那么夸张 2026-02-09 00:22:46 +08:00
Dt8333
7dd95d8a59 chore: auto ann fix by ruff (#4903)
* chore: auto fix by ruff

* refactor: 统一修正返回类型注解为 None/bool 以匹配实现

* refactor: 将 _get_next_page 改为异步并移除多余的请求错误抛出

* refactor: 将 get_client 的返回类型改为 object

* style: 为 LarkMessageEvent 的相关方法添加返回类型注解 None

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-09 00:22:24 +08:00
LIghtJUNction
af09b5cb16 Update astrbot/dashboard/server.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-09 00:21:37 +08:00
Soulter
e1b71540c7 chore: bump version to 4.14.8 and bump faiss-cpu version up to date 2026-02-09 00:19:12 +08:00
Soulter
85e1764857 feat: refactor release workflow and add special update handling for electron app (#4969) 2026-02-08 23:56:30 +08:00
Soulter
0553f84d6c chore: bump version to 4.14.7 2026-02-08 23:20:34 +08:00
Soulter
3fd89808ee chore: update Python version requirements to 3.12 (#4963) 2026-02-08 23:13:51 +08:00
Soulter
96753821b7 feat: enhance package.json with resource filters and compression settings 2026-02-08 22:58:58 +08:00
鸦羽
eca3ede7b0 fix: dedupe preset messages (#4961) 2026-02-08 22:18:13 +08:00
エイカク
a7e580407c feat: supports electron app (#4952)
* feat: add desktop wrapper with frontend-only packaging

* docs: add desktop build docs and track dashboard lockfile

* fix: track desktop lockfile for npm ci

* fix: allow custom install directory for windows installer

* chore: migrate desktop workflow to pnpm

* fix(desktop): build AppImage only on Linux

* fix(desktop): harden packaged startup and backend bundling

* fix(desktop): adapt packaged restart and plugin dependency flow

* fix(desktop): prevent backend respawn race on quit

* fix(desktop): prefer pyproject version for desktop packaging

* fix(desktop): improve startup loading UX and reduce flicker

* ci: add desktop multi-platform release workflow

* ci: fix desktop release build and mac runner labels

* ci: disable electron-builder auto publish in desktop build

* ci: avoid electron-builder publish path in build matrix

* ci: normalize desktop release artifact names

* ci: exclude blockmap files from desktop release assets

* ci: prefix desktop release assets with AstrBot and purge blockmaps

* feat: add electron bridge types and expose backend control methods in preload script

* Update startup screen assets and styles

- Changed the icon from PNG to SVG format for better scalability.
- Updated the border color from #d0d0d0 to #eeeeee for a softer appearance.
- Adjusted the width of the startup screen from 460px to 360px for improved responsiveness.

* Update .gitignore to include package.json

* chore: remove desktop gitkeep ignore exceptions

* docs: update desktop troubleshooting for current runtime behavior

* refactor(desktop): modularize runtime and harden startup flow

---------

Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-08 21:49:54 +08:00
Soulter
8bd1565696 fix: correct height attribute to max-height for dialog component 2026-02-08 21:13:38 +08:00
Soulter
03e0949067 feat: add welcome feature with localized content and onboarding steps 2026-02-08 21:11:34 +08:00
DD斩首
dbe8e33c4b feat(telegram): 添加媒体组(相册)支持 / add media group (album) support (#4893)
* feat(telegram): 添加媒体组(相册)支持 / add media group (album) support

## 功能说明
支持 Telegram 的媒体组消息(相册),将多张图片/视频合并为一条消息处理,而不是分散成多条消息。

## 主要改动

### 1. 初始化媒体组缓存 (__init__)
- 添加 `media_group_cache` 字典存储待处理的媒体组消息
- 使用 2.5 秒超时收集媒体组消息(基于社区最佳实践)
- 最大等待时间 10 秒(防止永久等待)

### 2. 消息处理流程 (message_handler)
- 检测 `media_group_id` 判断是否为媒体组消息
- 媒体组消息走特殊处理流程,避免分散处理

### 3. 媒体组消息缓存 (handle_media_group_message)
- 缓存收到的媒体组消息
- 使用 APScheduler 实现防抖(debounce)机制
- 每收到新消息时重置超时计时器
- 超时后触发统一处理

### 4. 媒体组合并处理 (process_media_group)
- 从缓存中取出所有媒体项
- 使用第一条消息作为基础(保留文本、回复等信息)
- 依次添加所有图片、视频、文档到消息链
- 将合并后的消息发送到处理流程

## 技术方案论证

Telegram Bot API 在处理媒体组时的设计限制:
1. 将媒体组的每个消息作为独立的 update 发送
2. 每个 update 带有相同的 `media_group_id`
3. **不提供**组的总数、结束标志或一次性完整组的机制

因此,bot 必须自行收集消息,并通过硬编码超时(timeout/delay)等待可能延迟到达的消息。
这是目前唯一可靠的方案,被官方实现、主流框架和开发者社区广泛采用。

### 官方和社区证据:
- **Telegram Bot API 服务器实现(tdlib)**:明确指出缺少结束标志或总数信息
  https://github.com/tdlib/telegram-bot-api/issues/643

- **Telegram Bot API 服务器 issue**:讨论媒体组处理的不便性,推荐使用超时机制
  https://github.com/tdlib/telegram-bot-api/issues/339

- **Telegraf(Node.js 框架)**:专用媒体组中间件使用 timeout 控制等待时间
  https://github.com/DieTime/telegraf-media-group

- **StackOverflow 讨论**:无法一次性获取媒体组所有文件,必须手动收集
  https://stackoverflow.com/questions/50180048/telegram-api-get-all-uploaded-photos-by-media-group-id

- **python-telegram-bot 社区**:确认媒体组消息单独到达,需手动处理
  https://github.com/python-telegram-bot/python-telegram-bot/discussions/3143

- **Telegram Bot API 官方文档**:仅定义 `media_group_id` 为可选字段,不提供获取完整组的接口
  https://core.telegram.org/bots/api#message

## 实现细节
- 使用 2.5 秒超时收集媒体组消息(基于社区最佳实践)
- 最大等待时间 10 秒(防止永久等待)
- 采用防抖(debounce)机制:每收到新消息重置计时器
- 利用 APScheduler 实现延迟处理和任务调度

## 测试验证
-  发送 5 张图片相册,成功合并为一条消息
-  保留原始文本说明和回复信息
-  支持图片、视频、文档混合的媒体组
-  日志显示 Processing media group <media_group_id> with 5 items

## 代码变更
- 文件:astrbot/core/platform/sources/telegram/tg_adapter.py
- 新增代码:124 行
- 新增方法:handle_media_group_message(), process_media_group()

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor(telegram): 优化媒体组处理性能和可靠性

根据代码审查反馈改进:

1. 实现 media_group_max_wait 防止无限延迟
   - 跟踪媒体组创建时间,超过最大等待时间立即处理
   - 最坏情况下 10 秒内必定处理,防止消息持续到达导致无限延迟

2. 移除手动 job 查找优化性能
   - 删除 O(N) 的 get_jobs() 循环扫描
   - 依赖 replace_existing=True 自动替换任务

3. 重用 convert_message 减少代码重复
   - 统一所有媒体类型转换逻辑
   - 未来添加新媒体类型只需修改一处

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(telegram): handle missing message in media group processing and improve logging messages

---------

Co-authored-by: Ubuntu <ubuntu@localhost.localdomain>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-02-08 13:22:45 +08:00
Gao Jinzhe
952023db30 feat: 允许 LLM 预览工具返回的图片并自主决定是否发送 (#4895)
* feat: 允许 LLM 预览工具返回的图片并自主决定是否发送

* 复用 send_message_to_user 替代独立的图片发送工具

* feat: implement _HandleFunctionToolsResult class for improved tool response handling

* docs: add path handling guidelines to AGENTS.md

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-08 13:16:16 +08:00
Helian Nuits
4e0b5063c6 feat(ComponentPanel): implement permission management for dashboard (#4887)
* feat(backend): add permission update api

* feat(useCommandActions): add updatePermission action and translations

* feat(dashboard): implement permission editing ui

* style: fix import sorting in command.py

* refactor(backend): extract permission update logic to service

* feat(i18n): add success and failure messages for command updates

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-08 12:27:32 +08:00
搁浅
30d1d55e3c feat: add provider-souce-level proxy (#4949)
* feat: 添加 Provider 级别代理支持及请求失败日志

* refactor: simplify provider source configuration structure

* refactor: move env proxy fallback logic to log_connection_failure

* refactor: update client proxy handling and add terminate method for cleanup

* refactor: update no_proxy configuration to remove redundant subnet

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-08 12:22:01 +08:00
Soulter
1e9026d44c chore: bump version to 4.14.6 2026-02-08 10:43:25 +08:00
letr
e48950d260 fix: localize provider source config UI (#4933)
* fix: localize provider source ui

* feat: localize provider metadata keys

* chore: add provider metadata translations

* chore: format provider i18n changes

* fix: preserve metadata fields in i18n conversion

* fix: internationalize platform config and dialog

* fix: add Weixin official account platform icon

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-08 10:40:26 +08:00
LIghtJUNction
31f46045d7 修正/修正一个错误 2026-02-07 20:17:44 +08:00
LIghtJUNction
d6455d774b 修正/一个导入问题 2026-02-07 20:02:44 +08:00
LIghtJUNction
3e928b9659 修正/CI工作流反馈的一些问题 2026-02-07 19:54:54 +08:00
Soulter
5e5207da95 perf: optimize webchat and wecom ai queue lifecycle (#4941)
* perf: optimize webchat and wecom ai queue lifecycle

* perf: enhance webchat back queue management with conversation ID support
2026-02-07 14:03:33 +08:00
Soulter
def8b730b7 fix: correct spelling of 'temporary' in SharedPreferences class 2026-02-07 14:01:08 +08:00
Soulter
22a109c2ae feat: implement feishu / lark media file handling utilities for file, audio and video processing (#4938)
* feat: implement media file handling utilities for audio and video processing

* feat: refactor file upload handling for audio and video in LarkMessageEvent

* feat: add cleanup for failed audio and video conversion outputs in media_utils

* feat: add utility methods for sending messages and uploading files in LarkMessageEvent
2026-02-07 12:40:05 +08:00
Soulter
6416707e35 chore: bump version to 4.14.5 (#4930) 2026-02-07 00:55:16 +08:00
Soulter
4658998b85 fix: messages[x] assistant content must contain at least one part (#4928)
* fix: messages[x] assistant content must contain at least one part

fixes: #4876

* ruff format
2026-02-07 00:33:07 +08:00
can
d233fb8b1e feat: add bocha web search tool (#4902)
* add bocha web search tool

* Revert "add bocha web search tool"

This reverts commit 1b36d75a17.

* add bocha web search tool

* fix: correct temporary_cache spelling and update supported tools for web search

* ruff

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-06 21:43:42 +08:00
LIghtJUNction
df1299b192 移除自定义的一个协议 2026-02-06 12:38:55 +08:00
LIghtJUNction
15ee17724d Merge branch 'feat/optional-backend' of https://github.com/AstrBotDevs/AstrBot into feat/optional-backend 2026-02-06 12:37:58 +08:00
LIghtJUNction
437c186a66 类型标注 2026-02-06 12:37:41 +08:00
LIghtJUNction
3610a42ebf Merge branch 'master' into feat/optional-backend 2026-02-06 04:22:49 +08:00
LIghtJUNction
bf1bde79ec Update astrbot/core/utils/io.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-06 04:22:03 +08:00
LIghtJUNction
f309638192 Update astrbot/dashboard/server.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-06 04:21:40 +08:00
LIghtJUNction
6439e4e152 Update astrbot/cli/commands/cmd_run.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-06 04:21:02 +08:00
LIghtJUNction
4b1395b2c9 Update astrbot/dashboard/routes/route.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-06 04:19:41 +08:00
LIghtJUNction
1859206007 feat: 支持前后端分离部署与动态后端地址配置
后端:
- 支持通过 DASHBOARD_ENABLE 环境变量分离 WebUI 服务
- 修复 CORS 跨域预检请求(OPTIONS) 鉴权问题
- 优化 IPv6 地址过滤逻辑
- CLI 新增 --backend-only 模式支持

前端:
- 新增 API 地址动态配置与预设管理功能 (登录页/设置页)
- 修复 WebSocket/SSE 连接地址适配非同源环境
- 修复 TypeScript 配置报错
- 完善新增功能的国际化支持
2026-02-06 04:06:52 +08:00
LIghtJUNction
3b93429353 新增cors配置项 2026-02-06 04:01:30 +08:00
LIghtJUNction
d68ccfcc96 1.前端的后端配置页面新增新增按钮,允许新增后端,自由切换后端。2.一些必要的改进,比如astrbot init初始化时候询问是否下载前端,可选择不下载,使用--backend-only选项时候,不再提示要下载前端 2026-02-06 03:47:53 +08:00
LIghtJUNction
68b8a1a01c 将enable变量含义释为:是否启用集成前端,如果为False,保留后端能力,而不是后端也关闭了 2026-02-06 03:13:46 +08:00
LIghtJUNction
75ee46715a 支持ipv6并完善astrbot run子命令
* 默认host修改为::,同时新增两个环境变量DASHBOARD_HOST,DASHBOARD_ENABLE,和DASHBOARD_PORT对齐

* feat: systemd support (#4880)

* fix: pyright lint (#4874)

* feat: 将 MessageSession 的 platform_id 改为 init=False,实例化时无需传入

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* refactor: 将 isinstance 检查改为元组、将默认模型值设为空字符串、将类型注解改为 Any 并导入

* refactor: 为 _serialize_job 增加返回类型注解 dict

* fix: 使用 cast 获取百度 AIP 的 msg 并对 psutil_addr 引入 type: ignore

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* refactor: 引入 _AddrWithPort 协议并替换 conn.laddr 的 cast

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* fix: 在构建 AstrBotMessage 时对 ctx.channel 可能为 None 进行兜底处理

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

---------

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* fix: TypeError when MCP schema type is a list (#4867)

* Fix TypeError when MCP schema type is a list

Fixes crash in Gemini native tools with VRChat MCP.

* Refactor: avoid modifying schema in place per feedback

* Fix formatting and cleanup comments

* docs: update watashiwakoseinodesukara

Removed duplicate text and added a new image.

* 修复/跨平台一致性

* 琐事/类型标注和一些简单错误修正

* 修复/检查端口时候包含ipv6

* 修复/enable变量的赋值逻辑

---------

Co-authored-by: Dt8333 <25431943+Dt8333@users.noreply.github.com>
Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>
Co-authored-by: boushi1111 <95118141+boushi1111@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-06 02:46:16 +08:00
LIghtJUNction
a8cad50f27 新功能/可选的分离前后端 2026-02-06 02:38:58 +08:00
Soulter
fc2a67188f docs: update watashiwakoseinodesukara
Removed duplicate text and added a new image.
2026-02-05 23:08:14 +08:00
boushi1111
d69592aaa8 fix: TypeError when MCP schema type is a list (#4867)
* Fix TypeError when MCP schema type is a list

Fixes crash in Gemini native tools with VRChat MCP.

* Refactor: avoid modifying schema in place per feedback

* Fix formatting and cleanup comments
2026-02-05 22:51:29 +08:00
Dt8333
f3397f6f08 fix: pyright lint (#4874)
* feat: 将 MessageSession 的 platform_id 改为 init=False,实例化时无需传入

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* refactor: 将 isinstance 检查改为元组、将默认模型值设为空字符串、将类型注解改为 Any 并导入

* refactor: 为 _serialize_job 增加返回类型注解 dict

* fix: 使用 cast 获取百度 AIP 的 msg 并对 psutil_addr 引入 type: ignore

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* refactor: 引入 _AddrWithPort 协议并替换 conn.laddr 的 cast

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

* fix: 在构建 AstrBotMessage 时对 ctx.channel 可能为 None 进行兜底处理

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>

---------

Co-authored-by: aider (openai/gpt-5.2) <aider@aider.chat>
2026-02-05 21:54:12 +08:00
LIghtJUNction
be92e4f395 feat: systemd support (#4880) 2026-02-05 21:52:21 +08:00
Soulter
912e40e7f0 chore: delete unused file 2026-02-05 10:40:53 +08:00
Xican
2876c43387 fix: 修复特定提供商导致的定时任务执行失败的问题 (#4872)
* fix: 修复特定提供商导致的定时任务执行失败的问题

* ruff format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-05 10:14:31 +08:00
Soulter
464882f206 chore: bump version to 4.14.4 2026-02-04 23:21:08 +08:00
Soulter
6736fb85c2 fix: conversation token usage calculate wrongly and fix tool call infinitely (#4869) 2026-02-04 23:18:32 +08:00
Soulter
1f75255950 chore: bump version to 4.14.3 2026-02-04 20:31:19 +08:00
Soulter
a954e75547 fix: add apply_reset parameter to build_main_agent and handle coroutine reset in InternalAgentSubStage 2026-02-04 20:25:31 +08:00
advent259141
d2b9997620 chore: bump version to 4.14.2 2026-02-04 17:42:41 +08:00
Gao Jinzhe
36432c4361 fix: 修复插件热重载时平台适配器未清理导致注册冲突的问题 (#4859) 2026-02-04 15:06:03 +08:00
圣达生物多
36f0d1f0f9 feat: add debug hint to console page and localization files (#4852) 2026-02-04 15:02:15 +08:00
Anima-IGCenter
f65b268bb2 chore: create robots.txt (#4847) 2026-02-04 15:00:08 +08:00
Raven95676
fe06dfcca3 fix: update ruff version to 0.15.0 and add ASYNC240 to ignore list 2026-02-04 11:45:59 +08:00
Soulter
bc9043bc3f fix: update ruff exclude list to include tests directory 2026-02-04 10:08:48 +08:00
Soulter
430694aae9 chore: update readme 2026-02-04 10:05:35 +08:00
Soulter
c643e3c093 chore: ruff format 2026-02-03 23:40:23 +08:00
Soulter
ff46eef3b2 chore: bump version to 4.14.1 2026-02-03 23:35:21 +08:00
Soulter
a0c364aa81 fix: active reply function does not work caused by event.request_llm() outdated 2026-02-03 23:34:42 +08:00
Anima-IGCenter
0e0f923a49 chore(seo): prevent indexing with noindex, nofollow (#4844) 2026-02-03 23:19:25 +08:00
Soulter
f2d637b935 fix: downgrade monaco-editor to version 0.52.2 2026-02-03 22:12:29 +08:00
Soulter
96e61a4a92 chore: bump version to 4.14.0 2026-02-03 22:08:29 +08:00
香草味的纳西妲喵
e42c1b6da8 fix: add error handling to avoid ghost plugins (#4836)
* fix: add error handling to avoid ghost plugins

Add null checks to filter out incomplete plugin metadata objects that would appear as ghost plugins in the API response.

This fix ensures that plugins with all null key fields (name, author, desc, version, display_name) are not included in the plugin list response, preventing ghost plugins from appearing in the UI.

Issue: #4833

* fix: improve ghost plugin detection logic for better accuracy

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-02-03 20:40:47 +08:00
Soulter
387bba093e fix: missing 2 required positional arguments: 'filter1' and 'filter2' (#4840)
fixes: #4777
2026-02-03 20:37:18 +08:00
Soulter
123cf9cb11 docs: revise README.md for clarity and feature updates (#4839)
Updated project description and added details about deployment and features.
2026-02-03 20:24:10 +08:00
Soulter
93277ffac9 fix: improve skills bundle extraction process to prevent overwriting existing files 2026-02-03 16:54:53 +08:00
Soulter
c091053ea8 fix: skills bundle unzip failed in sandbox 2026-02-03 16:34:07 +08:00
Soulter
8b9f2f1e70 feat: enhance user experience with runtime hints and improved UI elements in skills management 2026-02-03 16:28:17 +08:00
Soulter
25ca7bd71e fix: add missing newline for code readability in _apply_local_env_tools function 2026-02-03 16:09:17 +08:00
Soulter
093b37e04b feat: add computer use runtime config and handling for skills execution (#4831)
* feat: add computer use runtime configuration and handling for skills execution

* fix: improve user notification for disabled Computer Use feature in skills execution
2026-02-03 16:08:15 +08:00
Soulter
a12e27f9ab feat: implement theme customization with primary and secondary color options 2026-02-03 14:41:48 +08:00
Soulter
ae6e0db053 perf: webui
Co-authored-by: IGCrystal <IGCrystal@wenturc.com>
2026-02-03 14:40:45 +08:00
SJ
cd6bef4d78 fix: MCP tools being filtered out when a specific plugin set is configured in the WebUI (#4825)
* fix: preserve MCP tools in _plugin_tool_fix filter

Tools without handler_module_path (such as MCP tools and built-in tools)
were being incorrectly skipped during plugin-based tool filtering.

This fix ensures that tools without plugin association are preserved,
as they should not be affected by plugin-level filtering logic.

* fix: retain MCP tools in _plugin_tool_fix function

---------

Co-authored-by: idiotsj <idiotsj@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-02-03 10:53:20 +08:00
Copilot
de1304dc6a feat: add edit button to persona selector dialog (#4826)
* Initial plan

* feat: add edit persona functionality in chatui selector dialog

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: address code review feedback - improve null checks and i18n consistency

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-02-03 10:32:20 +08:00
Soulter
f835f63542 feat: add trace settings management and UI for enabling/disabling trace logging (#4822)
* feat: add trace settings management and UI for enabling/disabling trace logging

* feat: enhance trace feature with internationalization support for hints and status messages

* fix: improve tool info extraction in run_agent function
2026-02-03 10:24:41 +08:00
Soulter
5deb045e47 fix: merge chatui pop-up prompt into chatui default persona and improve chatui persona handle (#4824)
* fix: merge chatui pop-up prompt into chatui default persona and improve chatui persona handle

* fix: update webchat persona handling to avoid default assignment for None
2026-02-03 01:29:21 +08:00
Soulter
42e84afd89 perf: improve cron job page 2026-02-02 14:13:17 +08:00
Soulter
a7ed6b8c76 fix: reasoning block style 2026-02-02 14:11:17 +08:00
Soulter
ee43b98ce6 fix: add missing comma in truncate_and_compress hint in config-metadata.json 2026-02-01 23:34:21 +08:00
Soulter
681b4747a6 feat: add proactive capability configuration with cron tools support 2026-02-01 23:33:45 +08:00
Soulter
a6da4ebe5e feat: add styles for embedded images and audio in MessagePartsRenderer 2026-02-01 23:29:08 +08:00
Soulter
e35a604b30 Merge pull request #4697 from advent259141/Astrbot_skill
feat: implemented proactive agents and subagents orchestrator
2026-02-01 22:57:47 +08:00
Soulter
45c9db258d feat: add support for resolving file paths from sandbox and downloading files if necessary 2026-02-01 22:30:22 +08:00
Soulter
382aaaf053 feat: i18n 2026-02-01 22:04:44 +08:00
Soulter
f66edc8d45 feat: implement CronJob system with support for one-time tasks and enhanced UI for task management 2026-02-01 22:04:30 +08:00
Soulter
3f8d8b5033 feat: integrate subagent orchestrator with configuration options for tool management 2026-02-01 20:43:08 +08:00
Soulter
bf587765de feat: enhance FileDownloadTool to confirm file removal and successful download 2026-02-01 18:13:23 +08:00
Soulter
313a6d8a24 fix: improve error handling for temporary file removal in FileDownloadTool 2026-02-01 18:12:40 +08:00
Soulter
2213fb1ebf feat: add proactive messaging support in CronJobPage and enhance file download tool with user notification option 2026-02-01 18:12:11 +08:00
Soulter
9bf63354be feat: enhance UI for SubAgent and CronJob management with beta indicators 2026-02-01 17:58:30 +08:00
Soulter
cd6cb1d60c chore: remove reminder 2026-02-01 17:50:29 +08:00
Soulter
193676012f feat: implement history persistence for agent interactions and enhance cron job permission handling 2026-02-01 17:42:08 +08:00
Soulter
bddf7b8623 feat: add proactive messaging support and enhance message handling in SendMessageToUserTool 2026-02-01 16:49:10 +08:00
Soulter
4c8c87d3fd feat: enhance cron job management and update UI terminology 2026-02-01 15:49:14 +08:00
Soulter
83288ca43e ruff format 2026-02-01 14:33:17 +08:00
Soulter
7f58a83833 Refactor cron job handling and enhance proactive agent capabilities
- Updated FunctionToolExecutor to improve background task handling and integrate new system prompts for proactive agents.
- Enhanced MainAgentBuildConfig with additional configuration options for tool management and context handling.
- Introduced new system prompts for proactive agents triggered by cron jobs and background tasks to improve user interaction.
- Refactored cron job management to utilize ProviderRequest for better context management and tool integration.
- Renamed cron job tools for clarity, changing "create_cron_job" to "create_future_task" and similar adjustments for consistency.
- Improved error handling and logging for cron job execution and agent responses.
- Added support for image captioning and persona management in agent requests.
2026-02-01 14:32:30 +08:00
Soulter
19651d24bb fix(skills): remove sandbox runtime handling from skill upload process (#4798) 2026-02-01 13:13:27 +08:00
Soulter
dba08edd0d style: enhance dialog titles with padding and text styles in MCP and Skills sections 2026-02-01 11:09:32 +08:00
letr
dc06bc943a fix(mcp): cannot rename MCP Server (#4766)
* fix(mcp): support renaming when editing MCP servers

When editing the MCP server configuration, you can now change the server name. The frontend will save the original name in edit mode, and the backend will recognize the rename operation through the oldName field.

* fix(mcp): fixed an issue where renaming the MCP server did not check for name conflicts

When renaming an MCP server, add a check to see if the target name already exists. If the name exists and it is a rename operation, return an error message to avoid overwriting the configuration.
2026-02-01 11:01:49 +08:00
Soulter
b48e6fb1b3 Merge remote-tracking branch 'origin/master' into Astrbot_skill 2026-02-01 00:46:05 +08:00
Soulter
0c5308a132 refactor: extract main agent 2026-02-01 00:43:41 +08:00
Soulter
339d98be35 chore: bump version to 4.13.2 (#4782) 2026-02-01 00:39:37 +08:00
Soulter
e8be624794 fix(context): append 'main' to module_part for handler module path (#4776) 2026-01-31 22:26:50 +08:00
Soulter
b2c6471ab0 fix: skill like tool (#4775) 2026-01-31 22:11:42 +08:00
Soulter
4ea865f017 feat: add cron job management tools and dashboard integration
- Implemented proactive cron job tools in InternalAgentSubStage for scheduling tasks.
- Created SendMessageToUserTool for sending messages to users based on cron job triggers.
- Added CreateActiveCronTool, DeleteCronJobTool, and ListCronJobsTool for cron job management.
- Introduced CronRoute for handling cron job API requests in the dashboard.
- Developed CronJobPage.vue for managing cron jobs in the dashboard UI.
- Updated SubAgentPage.vue to include persona selection for subagents.
2026-01-31 17:08:37 +08:00
sanyekana
106f352017 fix: Fixed a bug where the front end still displayed a success messag… (#4768)
* fix: Fixed a bug where the front end still displayed a success message when Skills upload failed.

* refactor(dashboard): unify API response handling in SkillsSection
2026-01-31 11:31:02 +08:00
Soulter
5b7805e8d7 feat: trace and log file config (#4747)
* feat: trace

* fix(log): increase log cache size from 200 to 500

* feat(logging): add file and trace logging configuration options
2026-01-31 00:05:54 +08:00
Soulter
831c2150d6 Merge remote-tracking branch 'origin/master' into Astrbot_skill 2026-01-29 23:46:21 +08:00
Soulter
a500f2edc8 chore: bump version to 4.13.1 2026-01-29 23:31:49 +08:00
Soulter
d27099f2da fix(skills): update SANDBOX_SKILLS_ROOT path to use relative directory 2026-01-29 23:25:56 +08:00
Helian Nuits
2aa0986295 fix(db): using lambda expression to ensure updated_at field (#4730)
* fix(db): 使用 lambda 表达式确保 updated_at 字段正确更新

updated_at 字段原先在 sa_column_kwargs["onupdate"] 中直接使用了 datetime.now(),导致时间戳仅在模块导入时被计算一次,之后不再变化,结果所有记录的更新时间都被设成了程序启动时间。

本次修改将时间戳生成逻辑封装进 lambda 表达式,使 SQLAlchemy 在每次更新记录时才惰性求值,从而保证时间戳实时更新。

* refactor(db): 根据建议引入 TimestampMixin 统一时间戳定义,提取 `created_at`/`updated_at` 至 [TimestampMixin]
2026-01-29 19:07:21 +08:00
Soulter
34c6ceb67c fix(docs): update feature description to include 'Skills' in README files 2026-01-29 17:22:48 +08:00
Soulter
906877cbe6 feat(i18n): add localized message for tool usage in chat 2026-01-29 16:29:44 +08:00
Soulter
609180022e feat(chat): refactor message rendering and introduce ToolCallItem component 2026-01-29 16:07:57 +08:00
Soulter
49c087a141 docs: replace demo banner in readme
Updated the image in the README file.
2026-01-29 12:17:11 +08:00
Soulter
70f12cd686 docs(readme): update language links and enhance feature descriptions 2026-01-29 12:09:38 +08:00
advent259141
738e69a8af add 3-mode selector and main tool mounting policy 2026-01-29 11:27:50 +08:00
Gao Jinzhe
60492d46ee Merge branch 'master' into Astrbot_skill 2026-01-29 10:57:30 +08:00
Soulter
ea82e00359 fix(changelog): clarify support for Anthropic Skills with usage reference 2026-01-29 00:54:39 +08:00
Soulter
928c557a25 fix: update markstream-vue and stream-monaco dependencies 2026-01-29 00:48:51 +08:00
Soulter
0500ee8e2b chore: bump version to 4.13.0 2026-01-29 00:21:58 +08:00
vmoranv
f92f0a3e5d feat(core): supports anthropic-skills-like tool call mode (#4681)
* feat(core): change llmtool to claude skills like func call

* feat: refactor tool execution logic in ToolLoopAgentRunner for improved clarity and efficiency

* feat(core): 添加工具调用模式配置选项

新增 tool_schema_mode 配置项,支持两种工具调用模式:
- skills_like:先发送工具名称和描述,再查询参数(两阶段)
- full:一次性发送完整工具模式

更新了默认配置、配置元数据定义以及代理子阶段处理逻辑,
添加了完整的工具调用提示语句,并在仪表板中提供了国际化支持。

* feat: 优化工具集获取逻辑,添加轻量和参数工具集返回方法

* refactor(runner): 重构工具模式处理逻辑到ToolLoopAgentRunner

- 将工具集激活逻辑提取到新的_build_active_tool_set方法中
- 实现工具模式配置功能,支持full和light模式的动态切换
- 移除InternalAgentSubStage中的工具模式应用逻辑,统一在runner中处理
- 添加_tool_schema_full_set和_tool_schema_param_set实例变量来管理工具集状态
- 修改工具查询逻辑以使用新的工具集管理方式

* fix: update default tool_schema_mode to 'full' in InternalAgentSubStage

* refactor: rename TOOL_CALL_PROMPT_FULL to TOOL_CALL_PROMPT_SKILLS_LIKE_MODE and update prompt logic

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-01-28 22:49:34 +08:00
Soulter
c1b764da04 fix: webui github proxy selector and bugs after uninstalling plugins (#4724)
fixes: #4709
2026-01-28 21:04:13 +08:00
Soulter
22bd8d6824 feat: support anthropic skills (#4715)
* feat: support anthropic skills

closes: #4687

* chore: ruff

* feat: implement skills management and selection in persona configuration

* feat: enhance skills management with local environment tools and permissions
2026-01-28 01:48:57 +08:00
xunxiing
a4fc92e803 feat: add file upload to plugin config (#4539)
Co-authored-by: Soulter <905617992@qq.com>
2026-01-27 14:56:19 +08:00
advent259141
053c4e989b 优化tool选择的下拉框:根据插件分组 2026-01-27 00:21:57 +08:00
advent259141
1bd8eae25a 按照comment进行一些小改动 2026-01-26 23:30:29 +08:00
Soulter
a41391f9f2 feat: resolve provider api keys from env (#4696) 2026-01-26 22:37:30 +08:00
advent259141
b3a1f4ca7d 再次修复格式 2026-01-26 22:36:25 +08:00
advent259141
c3e4a52e5f 修复格式 2026-01-26 22:31:18 +08:00
advent259141
3cf0880f98 修复bug,优化前端页面 2026-01-26 22:14:56 +08:00
Soulter
b04dad1fd2 docs: add AGENTS.md 2026-01-26 21:21:26 +08:00
advent259141
6d47663842 修复了一些已知问题 2026-01-26 17:22:20 +08:00
xunxiing
3765dd46f7 fix: gemini toolcall repetition call (#4686)
* 修复gemini toolcall 的名称导致的循环调用

* Apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* Refactor function response creation for tool role

Refactor function response handling for tool role to ensure proper ID injection.

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2026-01-26 17:14:58 +08:00
advent259141
6b39717695 增加subagent编排功能 2026-01-26 14:57:20 +08:00
Soulter
17d642efc9 fix: update configuration metadata hints for segmented reply settings 2026-01-25 14:28:07 +08:00
時壹
4839cc6119 feat: add configurable Dashboard API access log toggle (#4661)
* feat: add configurable Dashboard API access log toggle

* chore: remove Dashboard API access log configuration
2026-01-24 16:31:23 +08:00
搁浅
127e8c31c2 feat: add confirmation dialog for update all plugins button to prevent accidental clicks #4300 (#4658) 2026-01-24 16:08:47 +08:00
Soulter
1cf673154c chore: bump version to 4.12.4 2026-01-24 14:55:32 +08:00
Soulter
f7c228ede2 fix: markdown keyerror or unbound error in aiocqhttp adapter (#4656)
* fix: markdown keyerror or unbound error in aiocqhttp adapter

* fix: improve exception handling and logging in aiocqhttp adapter
2026-01-24 14:43:49 +08:00
Soulter
78617ec7ce fix: enhance provider selection error handling and logging (#4654) 2026-01-24 14:25:41 +08:00
Soulter
e5048bddeb chore: remove deprecated tool commands
closes: #4599
2026-01-23 20:00:59 +08:00
Soulter
eebe31f69d fix: update web_search_tavily handling for webchat platform (#4633)
* fix: update web_search_tavily handling for webchat platform

* chore: style consistent
2026-01-23 19:52:31 +08:00
Copilot
90b57eb5cb fix: provider selector button hidden by long model names (#4631)
* Initial plan

* Fix long model name overflow in ProviderSelector

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-01-23 19:42:12 +08:00
Soulter
2b2edf4852 fix: genie tts config 2026-01-23 19:00:57 +08:00
Soulter
a920e45f96 feat: AstrBot Live Chat Mode on ChatUI (#4534)
* feat: astr live

* chore: remove

* feat: metrics

* feat: enhance audio processing and metrics display in live mode

* feat: genie tts

* feat: enhance live mode audio processing and text handling

* feat: add metrics

* feat: eyes

* feat: nervous

* chore: update readme

Added '自动压缩对话' feature and updated features list.

* feat: skip saving head system messages in history (#4538)

* feat: skip saving the first system message in history

* fix: rename variable for clarity in system message handling

* fix: update logic to skip all system messages until the first non-system message

* fix: clarify logic for skipping initial system messages in conversation

* chore: bump version to 4.12.2

* docs: update 4.12.2 changelog

* refactor: update event types for LLM tool usage and response

* chore: bump version to 4.12.3

* fix: ensure embedding dimensions are returned as integers in providers (#4547)

* fix: ensure embedding dimensions are returned as integers in providers

* chore: ruff format

* perf: T2I template editor preview (#4574)

* feat: add file drag upload feature for ChatUI (#4583)

* feat(chat): add drag-drop upload and fix batch file upload

* style(chat): adjust drop overlay to only cover input container

* fix: streaming response for DingTalk (#4590)

closes: #4384

* #4384 钉钉消息回复卡片模板

* chore: ruff format

* chore: ruff format

---------

Co-authored-by: ManJiang <man.jiang@jg-robust.com>
Co-authored-by: Soulter <905617992@qq.com>

* feat: implement persona folder for advanced persona management (#4443)

* feat(db): add persona folder management for hierarchical organization

Implement hierarchical folder structure for organizing personas:
- Add PersonaFolder model with recursive parent-child relationships
- Add folder_id and sort_order fields to Persona model
- Implement CRUD operations for persona folders in database layer
- Add migration support for existing databases
- Extend PersonaManager with folder management methods
- Add dashboard API routes for folder operations

* feat(persona): add batch sort order update endpoint for personas and folders

Add new API endpoint POST /persona/reorder to batch update sort_order
for both personas and folders. This enables drag-and-drop reordering
in the dashboard UI.

Changes:
- Add abstract batch_update_sort_order method to BaseDatabase
- Implement batch_update_sort_order in SQLiteDatabase
- Add batch_update_sort_order to PersonaManager with cache refresh
- Add reorder_items route handler with input validation

* feat(persona): add folder_id and sort_order params to persona creation

Extend persona creation flow to support folder placement and ordering:
- Add folder_id and sort_order parameters to insert_persona in db layer
- Update PersonaManager.create_persona to accept and pass folder params
- Add get_folder_detail API endpoint for retrieving folder information
- Include folder_id and sort_order in persona creation response
- Add session flush/refresh to return complete persona object

* feat(dashboard): implement persona folder management UI

- Add folder management system with tree view and breadcrumbs
- Implement create, rename, delete, and move operations for folders
- Add drag-and-drop support for organizing personas and folders
- Create new PersonaManager component and Pinia store for state management
- Refactor PersonaPage to support hierarchical structure
- Update locale files with folder-related translations
- Handle empty parent_id correctly in backend route

* feat(dashboard): centralize folder expansion state in persona store

Move folder expansion logic from local component state to global Pinia
store to persist expansion state.
- Add `expandedFolderIds` state and toggle actions to `personaStore`
- Update `FolderTreeNode` to use store state instead of local data
- Automatically navigate to target folder after moving a persona

* feat(dashboard): add reusable folder management component library

Extract folder management UI into reusable base components and create
persona-specific wrapper components that integrate with personaStore.

- Add base folder components (tree, breadcrumb, card, dialogs) with
  customizable labels for i18n support
- Create useFolderManager composable for folder state management
- Implement drag-and-drop support for moving personas between folders
- Add persona-specific wrapper components connecting to personaStore
- Reorganize PersonaManager into views/persona directory structure
- Include comprehensive README documentation for component usage

* refactor(dashboard): remove legacy persona folder management components

Remove deprecated persona folder management Vue components that have been
superseded by the new reusable folder management component library.

Deleted components:
- CreateFolderDialog.vue
- FolderBreadcrumb.vue
- FolderCard.vue
- FolderTree.vue
- FolderTreeNode.vue
- MoveTargetNode.vue
- MoveToFolderDialog.vue
- PersonaCard.vue
- PersonaManager.vue

These components are replaced by the centralized folder management
implementation introduced in commit 3fbb3db2.

* fix(dashboard): add delayed skeleton loading to prevent UI flicker

Implement a 150ms delay before showing the skeleton loader in
PersonaManager to prevent visual flicker during fast loading operations.

- Add showSkeleton state with timer-based delay mechanism
- Use v-fade-transition for smooth skeleton visibility transitions
- Clean up timer on component unmount to prevent memory leaks
- Only display skeleton when loading exceeds threshold duration

* feat(dashboard): add generic folder item selector component for persona selection

Introduce BaseFolderItemSelector.vue as a reusable component for selecting
items within folder hierarchies. Refactor PersonaSelector to use this new
base component instead of its previous flat list implementation.

Changes:
- Add BaseFolderItemSelector with folder tree navigation and item selection
- Extend folder types with SelectableItem and FolderItemSelectorLabels
- Refactor PersonaSelector to leverage the new base component
- Add i18n translations for rootFolder and emptyFolder labels

* feat(persona): add tree-view display for persona list command

Add hierarchical folder tree output for the persona list command,
showing personas organized by folders with visual tree connectors.

- Add _build_tree_output method for recursive tree structure rendering
- Display folders with 📁 icon and personas with 👤 icon
- Show root-level personas separately from folder contents
- Include total persona count in output

* refactor(persona): simplify tree-view output with shorter indentation lines

Replace complex tree connector logic with simpler depth-based indentation
using "│ " prefix. Remove unnecessary parameters (prefix, is_last) and
computed variables (has_content, total_items, item_idx) in favor of a
cleaner depth-based approach.

* feat(dashboard): add duplicate persona ID validation in create form

Add frontend validation to prevent creating personas with duplicate IDs.
Load existing persona IDs when opening the create form and validate
against them in real-time.

- Add existingPersonaIds array and loadExistingPersonaIds method
- Add validation rule to check for duplicate persona IDs
- Add i18n messages for duplicate ID error (en-US and zh-CN)
- Fix minLength validation to require at least 1 character

* i18n(persona): add createButton translation key for folder dialog

Move create button label to folder-specific translation path
instead of using generic buttons.create key.

* feat(persona): show target folder name in persona creation dialog

Add visual feedback showing which folder a new persona will be created in.

- Add info alert in PersonaForm displaying the target folder name
- Pass currentFolderName prop from PersonaManager and PersonaSelector
- Add recursive findFolderName helper to resolve folder ID to name
- Add i18n translations for createInFolder and rootFolder labels

* style:format code

* fix: remove 'persistent' attribute from dialog components

---------

Co-authored-by: Soulter <905617992@qq.com>

* perf: live mode entry

* chore: remove japanese prompt

---------

Co-authored-by: Anima-IGCenter <cacheigcrystal2@gmail.com>
Co-authored-by: Clhikari <Clhikari@qq.com>
Co-authored-by: jiangman202506 <jiangman202506@163.com>
Co-authored-by: ManJiang <man.jiang@jg-robust.com>
Co-authored-by: Ruochen Pan <67079377+RC-CHN@users.noreply.github.com>
2026-01-22 16:24:40 +08:00
Ruochen Pan
8910ab3a47 feat: implement persona folder for advanced persona management (#4443)
* feat(db): add persona folder management for hierarchical organization

Implement hierarchical folder structure for organizing personas:
- Add PersonaFolder model with recursive parent-child relationships
- Add folder_id and sort_order fields to Persona model
- Implement CRUD operations for persona folders in database layer
- Add migration support for existing databases
- Extend PersonaManager with folder management methods
- Add dashboard API routes for folder operations

* feat(persona): add batch sort order update endpoint for personas and folders

Add new API endpoint POST /persona/reorder to batch update sort_order
for both personas and folders. This enables drag-and-drop reordering
in the dashboard UI.

Changes:
- Add abstract batch_update_sort_order method to BaseDatabase
- Implement batch_update_sort_order in SQLiteDatabase
- Add batch_update_sort_order to PersonaManager with cache refresh
- Add reorder_items route handler with input validation

* feat(persona): add folder_id and sort_order params to persona creation

Extend persona creation flow to support folder placement and ordering:
- Add folder_id and sort_order parameters to insert_persona in db layer
- Update PersonaManager.create_persona to accept and pass folder params
- Add get_folder_detail API endpoint for retrieving folder information
- Include folder_id and sort_order in persona creation response
- Add session flush/refresh to return complete persona object

* feat(dashboard): implement persona folder management UI

- Add folder management system with tree view and breadcrumbs
- Implement create, rename, delete, and move operations for folders
- Add drag-and-drop support for organizing personas and folders
- Create new PersonaManager component and Pinia store for state management
- Refactor PersonaPage to support hierarchical structure
- Update locale files with folder-related translations
- Handle empty parent_id correctly in backend route

* feat(dashboard): centralize folder expansion state in persona store

Move folder expansion logic from local component state to global Pinia
store to persist expansion state.
- Add `expandedFolderIds` state and toggle actions to `personaStore`
- Update `FolderTreeNode` to use store state instead of local data
- Automatically navigate to target folder after moving a persona

* feat(dashboard): add reusable folder management component library

Extract folder management UI into reusable base components and create
persona-specific wrapper components that integrate with personaStore.

- Add base folder components (tree, breadcrumb, card, dialogs) with
  customizable labels for i18n support
- Create useFolderManager composable for folder state management
- Implement drag-and-drop support for moving personas between folders
- Add persona-specific wrapper components connecting to personaStore
- Reorganize PersonaManager into views/persona directory structure
- Include comprehensive README documentation for component usage

* refactor(dashboard): remove legacy persona folder management components

Remove deprecated persona folder management Vue components that have been
superseded by the new reusable folder management component library.

Deleted components:
- CreateFolderDialog.vue
- FolderBreadcrumb.vue
- FolderCard.vue
- FolderTree.vue
- FolderTreeNode.vue
- MoveTargetNode.vue
- MoveToFolderDialog.vue
- PersonaCard.vue
- PersonaManager.vue

These components are replaced by the centralized folder management
implementation introduced in commit 3fbb3db2.

* fix(dashboard): add delayed skeleton loading to prevent UI flicker

Implement a 150ms delay before showing the skeleton loader in
PersonaManager to prevent visual flicker during fast loading operations.

- Add showSkeleton state with timer-based delay mechanism
- Use v-fade-transition for smooth skeleton visibility transitions
- Clean up timer on component unmount to prevent memory leaks
- Only display skeleton when loading exceeds threshold duration

* feat(dashboard): add generic folder item selector component for persona selection

Introduce BaseFolderItemSelector.vue as a reusable component for selecting
items within folder hierarchies. Refactor PersonaSelector to use this new
base component instead of its previous flat list implementation.

Changes:
- Add BaseFolderItemSelector with folder tree navigation and item selection
- Extend folder types with SelectableItem and FolderItemSelectorLabels
- Refactor PersonaSelector to leverage the new base component
- Add i18n translations for rootFolder and emptyFolder labels

* feat(persona): add tree-view display for persona list command

Add hierarchical folder tree output for the persona list command,
showing personas organized by folders with visual tree connectors.

- Add _build_tree_output method for recursive tree structure rendering
- Display folders with 📁 icon and personas with 👤 icon
- Show root-level personas separately from folder contents
- Include total persona count in output

* refactor(persona): simplify tree-view output with shorter indentation lines

Replace complex tree connector logic with simpler depth-based indentation
using "│ " prefix. Remove unnecessary parameters (prefix, is_last) and
computed variables (has_content, total_items, item_idx) in favor of a
cleaner depth-based approach.

* feat(dashboard): add duplicate persona ID validation in create form

Add frontend validation to prevent creating personas with duplicate IDs.
Load existing persona IDs when opening the create form and validate
against them in real-time.

- Add existingPersonaIds array and loadExistingPersonaIds method
- Add validation rule to check for duplicate persona IDs
- Add i18n messages for duplicate ID error (en-US and zh-CN)
- Fix minLength validation to require at least 1 character

* i18n(persona): add createButton translation key for folder dialog

Move create button label to folder-specific translation path
instead of using generic buttons.create key.

* feat(persona): show target folder name in persona creation dialog

Add visual feedback showing which folder a new persona will be created in.

- Add info alert in PersonaForm displaying the target folder name
- Pass currentFolderName prop from PersonaManager and PersonaSelector
- Add recursive findFolderName helper to resolve folder ID to name
- Add i18n translations for createInFolder and rootFolder labels

* style:format code

* fix: remove 'persistent' attribute from dialog components

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-01-21 13:05:33 +08:00
jiangman202506
c09bbfb8ac fix: streaming response for DingTalk (#4590)
closes: #4384

* #4384 钉钉消息回复卡片模板

* chore: ruff format

* chore: ruff format

---------

Co-authored-by: ManJiang <man.jiang@jg-robust.com>
Co-authored-by: Soulter <905617992@qq.com>
2026-01-21 12:48:45 +08:00
Clhikari
02909c62ab feat: add file drag upload feature for ChatUI (#4583)
* feat(chat): add drag-drop upload and fix batch file upload

* style(chat): adjust drop overlay to only cover input container
2026-01-21 12:37:18 +08:00
Anima-IGCenter
978d9cbb6a perf: T2I template editor preview (#4574) 2026-01-20 10:23:37 +08:00
Soulter
cb3825bb00 fix: ensure embedding dimensions are returned as integers in providers (#4547)
* fix: ensure embedding dimensions are returned as integers in providers

* chore: ruff format
2026-01-18 17:09:25 +08:00
Soulter
5f54becbe2 chore: bump version to 4.12.3 2026-01-17 19:11:05 +08:00
Soulter
317b6fa475 refactor: update event types for LLM tool usage and response 2026-01-17 19:09:49 +08:00
Soulter
8199c83072 docs: update 4.12.2 changelog 2026-01-17 18:12:08 +08:00
Soulter
776c9ebfdd chore: bump version to 4.12.2 2026-01-17 18:07:54 +08:00
Soulter
73fca5d1a2 fix: clarify logic for skipping initial system messages in conversation 2026-01-17 18:02:31 +08:00
Soulter
844773a735 feat: skip saving head system messages in history (#4538)
* feat: skip saving the first system message in history

* fix: rename variable for clarity in system message handling

* fix: update logic to skip all system messages until the first non-system message
2026-01-17 17:57:11 +08:00
Soulter
1a7e8456ab chore: update readme
Added '自动压缩对话' feature and updated features list.
2026-01-16 17:57:49 +08:00
Soulter
f6a189f118 feat: add event hooks for tool usage and response handling (#4516)
* feat: add event hooks for tool usage and response handling

* fix: update decorator for LLM tool response handling
2026-01-16 16:51:35 +08:00
Soulter
82e2e0d02f feat: add web search references feature with sidebar and extraction logic (#4515)
* feat: add web search references feature with sidebar and extraction logic

* fix: reorder import statements for consistency

* chore: remove log
2026-01-16 16:49:48 +08:00
Soulter
8771317a1e perf: chatui default persona (#4502) 2026-01-16 16:46:39 +08:00
Soulter
ebae70c514 chore: bump version to 4.12.1 2026-01-15 22:20:52 +08:00
Soulter
dbdb4f5185 fix: unique session not working (#4490)
* fix: unique session not working

* fix: correct session initialization and update unified_msg_origin setter

* fix: update session ID assignment in WakingCheckStage
2026-01-15 22:16:21 +08:00
Soulter
af2b3b3bfc fix: update stream-monaco dependency to version 0.0.15 2026-01-15 19:53:58 +08:00
Soulter
6497d9a46f fix: update stream-markdown dependency to version 0.0.13 2026-01-15 19:52:23 +08:00
Soulter
8f4a62a2cb chore: bump version to 4.12.0 2026-01-15 19:47:53 +08:00
Soulter
acbe83a2e2 chore: bump version to 4.12.0 2026-01-15 19:47:25 +08:00
Gao Jinzhe
e0f3fb3c3d Merge pull request #4194 from Luna-channel/feat/session-management
feat: add batch operation functionality for session management
2026-01-15 19:38:24 +08:00
Soulter
fef789e4d3 feat: add Docker Compose configuration for AstrBot and Shipyard services 2026-01-15 18:53:24 +08:00
Soulter
680b900c76 feat: implement iPython tool and reasoning blocks with enhanced UI components 2026-01-15 18:15:42 +08:00
Soulter
f797f132cf perf: refine tool call related prompts 2026-01-15 17:22:50 +08:00
Soulter
941ab6db84 chore: add requirement 2026-01-15 16:19:26 +08:00
Soulter
5eea508296 feat: astrbot agent sandbox env(improved code interpreter) (#4449)
* stage

* fix: update tool call logging to include tool call IDs and enhance sandbox ship creation parameters

* feat: file upload

* fix

* update

* fix: remove 'boxlite' option from booter and handle error in PythonTool execution

* feat: implement singleton pattern for ShipyardSandboxClient and add FileUploadTool for file uploads

* feat: sandbox

* fix

* beta

* uv lock

* remove

* chore: makes world better

* feat: implement localStorage persistence for showReservedPlugins state

* docs: refine EULA

* fix

* feat: add availability check for sandbox in Shipyard and base booters

* feat: add shipyard session configuration options and update related tools

* feat: add file download functionality and update shipyard SDK version

* fix: sending OpenAI-style image_url causes Anthropic 400 invalid tag error (#4444)

* feat: chatui project (#4477)

* feat: chatui-project

* fix: remove console log from getProjects function

* fix: title saving logic and update project sessions on changes

* docs: standardize Context class documentation formatting (#4436)

* docs: standardize Context class documentation formatting

- Unified all method docstrings to standard format
- Fixed mixed language and formatting issues
- Added complete parameter and return descriptions
- Enhanced developer experience for plugin creators
- Fixes #4429

* docs: fix Context class documentation issues per review

- Restored Sphinx directives for versionadded notes
- Fixed MessageSesion typo to MessageSession throughout file
- Added clarification for kwargs propagation in tool_loop_agent
- Unified deprecation marker format
- Fixes #4429

* Convert developer API comments to English

* chore: revise comments

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: handle empty output case in PythonTool execution

* fix: update description for command parameter in ExecuteShellTool

* refactor: remove unused file tools and update PythonTool output handling

* project list

* fix: ensure message stream order (#4487)

* feat: enhance iPython tool rendering with Shiki syntax highlighting

* bugfixes

* feat: add sandbox mode prompt for enhanced user guidance in executing commands

* chore: remove skills prompt

---------

Co-authored-by: 時壹 <137363396+KBVsent@users.noreply.github.com>
Co-authored-by: Li-shi-ling <114913764+Li-shi-ling@users.noreply.github.com>
2026-01-15 16:17:56 +08:00
時壹
9782d1bff8 fix:exclude disabled commands from platform command registration (#4485) 2026-01-15 14:04:15 +08:00
Soulter
0e3d224c12 fix: ensure message stream order (#4487) 2026-01-15 13:11:27 +08:00
Soulter
8aeb2229ce fix: chatui title (#4486) 2026-01-15 12:47:55 +08:00
Li-shi-ling
179f3e6426 docs: standardize Context class documentation formatting (#4436)
* docs: standardize Context class documentation formatting

- Unified all method docstrings to standard format
- Fixed mixed language and formatting issues
- Added complete parameter and return descriptions
- Enhanced developer experience for plugin creators
- Fixes #4429

* docs: fix Context class documentation issues per review

- Restored Sphinx directives for versionadded notes
- Fixed MessageSesion typo to MessageSession throughout file
- Added clarification for kwargs propagation in tool_loop_agent
- Unified deprecation marker format
- Fixes #4429

* Convert developer API comments to English

* chore: revise comments

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2026-01-14 23:46:27 +08:00
Soulter
561741d43d fix: title saving logic and update project sessions on changes 2026-01-14 20:51:54 +08:00
Soulter
63e8d0634f feat: chatui project (#4477)
* feat: chatui-project

* fix: remove console log from getProjects function
2026-01-14 19:15:48 +08:00
時壹
350667b60f fix: sending OpenAI-style image_url causes Anthropic 400 invalid tag error (#4444) 2026-01-14 10:50:56 +08:00
Soulter
6a86dae76e docs: refine EULA 2026-01-13 12:19:05 +08:00
Soulter
a7eca40fe7 feat: implement localStorage persistence for showReservedPlugins state 2026-01-13 02:23:31 +08:00
Soulter
ef28dc5001 chore: makes world better 2026-01-13 02:20:24 +08:00
Soulter
d29ac4023a fix: typo 2026-01-12 21:24:11 +08:00
Soulter
c2af2c6d5e chore: bump version to 4.11.4 2026-01-12 20:42:49 +08:00
Soulter
d9fb29d314 docs: add initial EULA for user agreement and compliance 2026-01-12 20:32:28 +08:00
Soulter
981421ded6 docs: update readme 2026-01-12 20:31:17 +08:00
Soulter
49ad22ca82 fix(i18n): refine default source label in English and Chinese locales 2026-01-12 20:05:21 +08:00
Soulter
858e245108 chore: remove default provider source displayed in webui 2026-01-12 19:51:18 +08:00
Soulter
6ac37ecd60 chore: bump version to 4.11.3 2026-01-12 19:35:41 +08:00
Soulter
2bbe010747 Sanitize invalid platform IDs on load (#4432) 2026-01-12 19:04:44 +08:00
Soulter
52bba9026a feat(safety): LLM healthy mode (#4431)
* feat(safety): implement LLM safety mode

* chore: ruff format
2026-01-12 18:33:34 +08:00
clown145
3416e8990c fix(webui): optimize markdown rendering and remove redundant code (#4415)
* fix(dashboard): optimize markdown rendering and remove redundant code

* style: format code and refactor ReadmeDialog for i18n/isolation

* fix: robust clipboard fallback for http context

* refactor: optimize markdown rendering and fix table styles in ReadmeDialog
2026-01-12 17:39:53 +08:00
時壹
eedb62a5a3 fix: detect image MIME type from binary data for Anthropic API (#4426) 2026-01-12 17:35:23 +08:00
Oscar Shaw
e8bd821e72 feat(log): append version number tag to WARN and ERROR level logs (#4388)
* feat(log): 在 WARN 和 ERROR 级别日志中追加版本号标签

* refactor(core): 简化日志版本标签过滤逻辑以包含 WARNING 及以上级别
2026-01-12 17:30:38 +08:00
NayukiMeko
131950b909 fix (#4297): fix list config being saved as [""] instead of [] after deletion (#4401)
* fix: 修复列表配置项删除后保存为['']而非[]的问题 (#4297)

* fix: 添加类型检查以处理非字符串列表项

* refactor: 移除 ExtensionPage 中重复的 cleanEmptyListItems

过滤逻辑已在 ListConfigItem.vue 源头处理,保存配置时无需再次过滤。
2026-01-11 18:53:15 +08:00
Futureppo
2e172804e3 feat(context): sannitize llm context by modalities (#4367)
* feat(context): 添加按模型能力清理历史上下文

* fix(config): 更新历史上下文清理提示信息

* chore: ruff format

* fix: simplify modality checks and sanitize context handling

* fix(config): disable context sanitization by modalities

* fix(agent): skip messages with empty roles in InternalAgentSubStage

* fix(agent): refine tool call handling in InternalAgentSubStage

---------

Co-authored-by: Soulter <905617992@qq.com>
2026-01-11 15:39:23 +08:00
Gao Jinzhe
2f3a3f354f fix: add image placeholder for non-vision models to fix no response in private chat (#4411)
* fix: 修复私聊中单独发送图片无响应的问题,为非视觉模型添加图片占位符

* ruffcheck

* 修复占位符被重复添加的问题

* 简化逻辑
2026-01-11 15:11:35 +08:00
letr
86e9b41dde fix(core): correct duplicate word in agent logger warning (#4390)
- Fix duplicate '没有' in logger warning message
- Improve punctuation and readability of tool response comments
2026-01-11 15:00:35 +08:00
Gao Jinzhe
8dfe43f22f fix(webui): add null check for plugin list in config to fix empty list issue (#4392) 2026-01-11 14:39:54 +08:00
stevessr
6c2f738940 fix: when session_id including ":" (#4380) 2026-01-11 14:33:44 +08:00
letr
c1102f2f5c fix(webui): fix unexpected expansion of all rows in tool table (#4366)
Corrected the property from `item-key` to `item-value` to align with
Vuetify 3 API. This ensures each row has a unique identifier for
the expansion state.
2026-01-11 14:27:07 +08:00
Li-shi-ling
9a91f2fb11 fix: ensure atomic creation of knowledge base with proper cleanup on failure (#4406)
* fix: ensure atomic creation of knowledge base with proper cleanup on failure

- Added pre-validation for embedding_provider_id parameter
- Added check for existing knowledge base with same name
- Implemented proper rollback mechanism when KBHelper initialization fails
- Uses same session for cleanup to ensure data consistency
- Fixes #4403

* fix: ensure atomic KB creation with session.flush() to remove race condition risks

* fix: ensure change the annotation back
2026-01-11 14:24:26 +08:00
Soulter
81309bc908 perf: enhance reply functionality to support selected text quoting (#4387)
* feat(chat): enhance reply functionality to support selected text quoting

* perf: improve ui

* feat(chat): add label for tools used in tool calls and update translations

* feat(chat): simplify reply handling by removing text truncation logic
2026-01-09 18:04:43 +08:00
Soulter
f003b83443 docs: update demo banner 2026-01-09 16:49:03 +08:00
Soulter
34921e91f0 chore: bump version to 4.11.2 2026-01-08 15:32:37 +08:00
Soulter
6c15592cbb feat(metrics): add metrics tracking for plugin installation events 2026-01-08 15:29:32 +08:00
letr
8c7a4b87d0 fix(webui): maintain international consistency of the 'repo' button (#4358) 2026-01-08 13:34:13 +08:00
Gao Jinzhe
8ff12e3972 fix: on_waiting_llm_request hook did not check message validity (#4349)
* fix:修复waitingllmrequest没有检查消息有效性的问题

* 进行ruff修复
2026-01-07 12:51:00 +08:00
Gao Jinzhe
eefa3f2f00 fix: conversation was still saved to the context after stop_event (#4345) 2026-01-07 12:48:13 +08:00
Oscar Shaw
479284a8dd feat(extension): plugin marketplace search supports matching display names. (#4332) 2026-01-06 12:54:11 +08:00
clown145
9322218880 feat: supports to display plugin CHANGELOG.md (#4337)
* feat: optimize plugin update changelog feature, refactor to reuse ReadmeDialog and support independent view entry

* fix: distinguish error state from empty state in ReadmeDialog
2026-01-06 12:53:14 +08:00
Soulter
399062f14d chore: remove wechatpadpro 2026-01-06 11:14:54 +08:00
Soulter
de82df3c33 chore: bump version to 4.11.1 2026-01-05 20:22:18 +08:00
Soulter
9896aebfb5 feat: enhance provider source configuration with custom hints and tooltips 2026-01-05 20:20:09 +08:00
Soulter
df7653eb99 fix: 部分情况下选择提供商出现”暂无可用提供商的问题“,即使实际上有 2026-01-05 20:01:54 +08:00
Soulter
8e7b44185d chore: bump version to 4.11.0 2026-01-05 18:05:12 +08:00
RC-CHN
ef1c66a92e feat(webui): enable Range request support for backup downloads (#4329) 2026-01-05 17:27:03 +08:00
Soulter
241f1c26d3 feat: context compress (#4322)
* feat: context compressor

Co-authored-by: kawayiYokami <289104862@qq.com>

* Add comprehensive tests for ContextManager and ContextTruncator

- Implemented a full test suite for ContextManager covering initialization, message processing, token-based compression, and error handling.
- Added tests for ContextTruncator focusing on message fixing, truncation by turns, dropping oldest turns, and halving.
- Ensured that both test suites validate edge cases and maintain expected behavior with various message types, including system and tool messages.

* feat: add MockProvider for LLM compression tests

* chore: remove lock

* ruff fix

* fix

* perf

* feat: enhance context compression with token tracking and logging

* feat: update logging for context compression trigger

* feat: implement context compression logic with dynamic threshold and token tracking

* fix: reorder import statements for consistency

* feat: add token_usage tracking to conversations and update related processing logic

---------

Co-authored-by: kawayiYokami <289104862@qq.com>
2026-01-05 17:26:10 +08:00
Soulter
3615b7dde2 fix: token usage is always 0 in anthropic source (#4328) 2026-01-05 17:06:12 +08:00
RC-CHN
9bcf9bf2a0 fix(dashboard): complete i18n support for shared components (#4327)
* fix(dashboard): complete i18n support for shared components

- Replace hardcoded Chinese strings with i18n translations in:
  - PluginSetSelector.vue
  - ProviderSelector.vue
  - PersonaSelector.vue
  - KnowledgeBaseSelector.vue
  - T2ITemplateEditor.vue
  - AstrBotConfigV4.vue
  - ConfigItemRenderer.vue
  - ProxySelector.vue
  - ListConfigItem.vue

- Add missing translations to locale files:
  - core/shared.json: personaSelector, t2iTemplateEditor
  - core/common.json: autoDetect
  - features/settings.json: network.proxySelector

- Change prop defaults from hardcoded Chinese to empty strings,
  allowing components to use i18n fallback translations

* fix(i18n): 修正插件选择器标签的翻译格式,添加冒号

* fix(deployment): 添加持久化 machine-id PVC 和初始化容器,优化资源限制
2026-01-05 09:45:28 +08:00
Gao Jinzhe
7f5cc7cf1a feat: add on_waiting_llm_request event hook (#4319)
* 加入on_waiting_llm_request钩子

* ruff check
2026-01-04 16:11:12 +08:00
Oscar Shaw
f26867c77d ci(stale): 增加 stale action 每次运行的操作限制 (#4256) 2026-01-04 11:20:03 +08:00
Soulter
a14d588b44 docs: add Matrix adapter to community maintained section in multiple languages 2026-01-04 10:15:16 +08:00
Soulter
e236402d92 chore: update platform adapter name for clarity 2026-01-04 10:12:25 +08:00
Soulter
454841de10 fix: database is locked error when invoking tts command (#4313)
* fix: database is locked error when invoking /tts command

fixes: #4311

* chore: rm pnpm lockfile

* perf: 减少操作数据库的次数
2026-01-03 19:12:39 +08:00
clown145
442b5403df feat(webui): supports force update plugins (#4293) 2026-01-03 15:30:50 +08:00
Soulter
9db7bf59b8 docs: add new community group contact 2026-01-03 00:48:55 +08:00
雪語
3622504021 fix: retry failed due to a mismatch in the msg.id data type of a WeChat Official Account (#4292)
问题描述:
- 控制台显示正常发送消息,但公众号未收到
- 处理时间 > 5秒的消息几乎总是失败(如 AI 图片生成)
- 短消息(<5秒)正常工作

根本原因:
msg.id 是整数类型,但字典 key 使用字符串类型,导致类型不匹配。
检查时整数无法匹配字符串 key,导致每次都创建新的 future,
微信重试时无法重用,最终导致响应失败。

修复内容:
将 msg.id 转换为字符串后再检查字典
  if str(msg.id) in self.wexin_event_workers:

影响范围:
- 修复了微信重试时无法正确重用 future 的问题
- AI 图片生成、长文本生成等耗时操作现在可以正常工作
- 仅影响微信公众号适配器,其他平台不受影响

Fixes #1679
2026-01-02 22:16:04 +08:00
Soulter
fc42db40ce chore: bump version to 4.10.6 2026-01-02 12:14:59 +08:00
Soulter
e413a002c1 perf: list view mode toggle with localStorage support in ExtensionPage (#4288)
closes: #4253
2026-01-02 11:59:41 +08:00
tjc66666666
6437d759a3 fix: reasoning content inject for openai api (#4284) 2026-01-02 01:09:28 +08:00
Soulter
c758b2d888 feat: use shell globbing to match umop config router (#4270)
* feat: use shell globbing to match umop config router

* rf

* fix: use fnmatchcase for case-sensitive matching in UmopConfigRouter
2025-12-31 23:10:12 +08:00
Soulter
510290fe0e chore: bump version to 4.10.5 2025-12-31 17:58:28 +08:00
Soulter
c61d62edb6 fix: handle null item-meta in ConfigItemRenderer (#4269)
fixes: #4268
2025-12-31 17:55:49 +08:00
Soulter
45bce6fe76 chore: bump version to 4.10.4 2025-12-31 12:50:37 +08:00
Soulter
f156adddf8 feat: enhance configuration editor with template schema support and UI improvements (#4267)
- Added support for template schemas in the configuration editor, allowing users to define and manage additional parameters like temperature, top_p, and max_tokens.
- Improved UI components in ProviderModelsPanel and ObjectEditor for better user interaction, including new configuration buttons and enhanced input handling.
- Updated localization files to include new configuration options.
2025-12-31 12:19:29 +08:00
Soulter
b5a4b80c36 perf: Add list item add button (#4259)
fixes: #4254
2025-12-30 15:27:17 +08:00
Soulter
792fb69d6d perf: allow zero chunk overlap in recursive chunker (#4258)
* Allow zero chunk overlap

* Validate recursive chunking bounds
2025-12-30 15:23:05 +08:00
Oscar Shaw
300a73ace0 fix(#4188): terminate the same plugin when install the plugin via file (#4250)
* fix(#4188): 从文件安装插件时先终止并解绑已存在的同名插件

* feat(star): 优化从文件安装插件的处理同名冲突逻辑,增加边缘检查
2025-12-30 13:43:44 +08:00
Oscar Shaw
a5b9de3695 Update stale.yml 2025-12-30 11:10:21 +08:00
fluidcat
90142bcafe fix: ensure close aiodocker.Docker() (#4251)
* fix: ensure close aiodocker.Docker()

* fix: code formatted
2025-12-30 00:24:29 +08:00
Misaka Mikoto
79d0487c03 feat: add template_list config type to support multiple repeated core/plugin config sets (#4208)
* feat: 添加模板列表配置支持,包含验证和编辑功能

* refactor(dashboard): extract ConfigItemRenderer to eliminate code duplication

- Create ConfigItemRenderer.vue to centralize rendering logic for various config types (string, int, bool, selectors, etc.)
- Refactor TemplateListEditor.vue to use the new renderer for entry fields
- Refactor AstrBotConfig.vue and AstrBotConfigV4.vue to simplify metadata-driven rendering
- Resolve circular dependency by decoupling TemplateListEditor from the base renderer

* ruff format

* refactor: improve config validation and fix unidirection data flow

- Frontend: Fix one-way data flow in TemplateListEditor.vue by cloning entries before applying defaults and emitting updates instead of in-place modification.
- Frontend: Remove unused TemplateListEditor import in ConfigItemRenderer.vue.
- Backend: Refactor validate_config in config.py by extracting _expect_type and _validate_template_list helpers to reduce nesting and complexity.
2025-12-30 00:16:24 +08:00
akuuma
4f15102e79 perf(satori): increase websocket max message size to 10MB (#4238)
* perf(satori): increase websocket max message size to 10MB

Add max_size parameter to websocket connection to handle larger messages
and prevent connection drops when receiving large payloads from Satori platform.

* chore: ruff format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2025-12-29 23:59:55 +08:00
Oscar Shaw
ef1feb639c fix(utils): optimize pip install output decoding for cross-platform encoding compatibility (#4249) 2025-12-29 23:54:11 +08:00
Oscar Shaw
1039a4f864 chore: update stale issue workflow to target only 'bug' labeled issues and adjust inactivity handling (#4252) 2025-12-29 23:49:40 +08:00
Soulter
66e2f49c11 perf: support extended thinking for Anthropic, DeepSeek reasoning mode, and Gemini text part thought signatures to improve multi-turn reasoning performance. (#4240)
* perf: support extended thinking for Anthropic, DeepSeek reasoning mode, and Gemini text part thought signatures to improve multi-turn reasoning performance.

* chore: remove verbose

* perf

* refactor: remove special tools handling for deepseek-reasoner model in openai source

* fix: improve error handling and logging in InternalAgentSubStage processing

* refactor: remove unused reasoning content from Gemini source processing

* refactor: enhance modality determination logic in useProviderSources

Co-authored-by: kawayiYokami <289104862@qq.com>
2025-12-29 14:22:30 +08:00
fluidcat
c5773fe63e feat: add JSON value for custom_extra_body (#4246)
* feat: add JSON value for custom_extra_body

* feat: add invalid format tip
2025-12-29 12:52:10 +08:00
NieiR
4e9ef48af2 fix: handle None values in _extract_usage to prevent TypeError (#4244)
* fix: handle None values in _extract_usage to prevent TypeError

Some LLM providers (especially API proxies) may return None for
prompt_tokens and completion_tokens in the usage response. This
causes a TypeError when attempting arithmetic operations.

Added null checks with fallback to 0 for both prompt_tokens and
completion_tokens before performing calculations.

* refactor: use explicit None check and reuse cached variable

- Use `is None` instead of `or 0` to avoid masking unexpected falsy values
- Reuse `cached` variable for `input_cached` to avoid redundant calculation

* ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-29 12:49:25 +08:00
RC-CHN
9eafd7b44a feat: add features for chunked upload and backup file management to the backup section (#4237)
* feat: 添加分片上传备份文件功能

* feat: 为上传备份文件添加异步并发以提升速度

* feat: 使用浏览器原生下载方式以显示进度条

* feat: 添加从已上传备份列表恢复的功能

* feat: 允许重命名备份文件

* feat: 在后端校验可用备份文件后在前端部分显示备份版本号,添加手动上传提示

* style: format code

* fix: 更新备份部分测试

* fix: 修复浏览器原生下载鉴权问题,通过url传参的方式完成认证

* feat(backup): 改进备份系统的分片上传和下载鉴权

- 修复浏览器原生下载鉴权问题,支持 URL 参数传递 token
- 修复上传会话过期判断,使用 last_activity 避免活跃上传被清理
- 延迟启动后台清理任务,避免 asyncio 事件循环问题
- 统一由后端计算 chunk_size 和 total_chunks,避免前后端不一致
- 更新 generate_unique_filename 文档注释与实际行为一致
- 更新测试用例以验证 origin 字段

修复问题:
- 浏览器下载时显示"需要授权"
- 大文件上传可能因会话过期失败
- __init__ 中 asyncio.create_task 可能失败

* style: format code
2025-12-29 12:30:59 +08:00
Soulter
fc61f7ad32 fix: unique session config cannot be applied in non-default astrbot config (#4232)
* fix: unique session config cannot be applied in non-default astrbot config

fixes: #4195

* perf: sesison id
2025-12-28 15:01:43 +08:00
simplify123
f51810997a fix: Xinference STT failed: INVALID (#4231)
* Update xinference_stt_provider.py

* chore: ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-28 14:42:06 +08:00
Soulter
fb4baf676f perf: add auto voice emotion for minimax tts (#4228)
* perf: add `auto` voice emotion for minimax tts

* ruff format
2025-12-28 00:34:44 +08:00
Oscar Shaw
71ad974c3c feat: two dashboard persistence optimizations (#4221)
* feat: persist console visibility state in local storage on PlatformPage

* feat: add persistence for sidebar opened items in local storage
2025-12-27 14:06:01 +08:00
Soulter
f0fff68947 fix: at sender users not working in dingtalk (#4219)
fixes: #4218
2025-12-27 11:26:39 +08:00
Soulter
3e3599835e chore: bump version to 4.10.3 2025-12-26 22:39:59 +08:00
Soulter
5255388e2d refactor: move builtin stars to astrbot package (#4209)
* refactor: move builtin stars to astrbot package

fixes: #4202

* chore: ruff format

* chore: remove print
2025-12-26 22:31:22 +08:00
Yokami
fbdd60b64c feat: add extra user content block support (#4189)
* feat: 多文本块功能

* FIX

* 传递链

* 重命名

* refactor: unify extra_user_content_parts type to ContentPart across providers and update related handling

* claude额外块支持图片模态

* 已经处理过了不用再处理

* feat: enhance image handling in extra content blocks for multiple providers

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-26 22:08:20 +08:00
Soulter
bd1b0a2836 perf: drop unnecessary none-value fields in tool call loop (#4213) 2025-12-26 21:12:34 +08:00
Soulter
19541d9d07 fix: ensure max_tokens is set and validate tool_calls type in ProviderAnthropic (#4212) 2025-12-26 21:01:05 +08:00
大饼鸡蛋
2a5d574394 fix: failed to initialize FishAudio TTS instance (#4200)
fixes: #4172

* fix: 修复 FishAudio 源的配置加载问题并增强请求鲁棒性

- Fix `KeyError: 'model'``: 适配新版配置结构。
- Add `timeout` support: 防止长文本生成时超时。
- Improve response handling: 使用更标准的 Header 检查方式。

* feat: 使用更安全的类型转换并优化错误信息打印
2025-12-26 20:50:45 +08:00
Soulter
f2924fbd1b chore: update readme 2025-12-26 18:04:56 +08:00
Gao Jinzhe
703e208947 fix: handle index out of range error when selecting provider (#4206) 2025-12-26 18:02:43 +08:00
NoctuUFO
9a5cc977c2 fix: fix log loss on SSE reconnect using Last-Event-ID (#4205)
* feat: implement last-event-id handing in log route

* perf: better log handling

* chore: ruff format

* perf: log

* Update ConsoleDisplayer.vue

* Update package.json

* Update ConsoleDisplayer.vue

* Update common.js

* chore: ruff format

* fix: ensure last_event_id is required for log replay

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-26 18:01:58 +08:00
RC-CHN
aa38fe776a feat: supports data backup (#4105)
* feat: 添加数据迁移功能

* test: 添加迁移相关测试

* feat: 备份插件及相关持久化目录

* fix: 修复版本号比较逻辑,添加相关测试

* fix: 清洗文件名,添加相关测试

* fix: 修复安全文件名测试用例断言

* refactor: 优化代码,为备份模块提取公用常量

* feat: 修改备份版本校验逻辑,允许强制小版本间导入

* fix: 修复备份创建时间读取,修复备份相关i18n

* refactor(backup): 使用 astrbot_path 统一管理备份目录路径

* fix(backup): 清理备份模块中未使用的导入

* refactor(backup): 统一备份路径与参数并移除未用附件目录

- 通过 astrbot_path 动态获取备份/知识库/数据相关路径
- 移除 exporter/importer 未使用的 attachments_dir/data_root 传参
- 更新备份路由与测试用例的构造参数

* fix(dashboard): alias mermaid to dist entry for Vite prebundle

* fix(backup): 放行start-time接口到白名单以处理备份导入后jwt token变化导致无法自动刷新webui的问题

* chore(backup): 统一配置路径以使用动态数据目录

* refactor(backup): 使用 VersionComparator 替代重复的版本比较函数

* style(backup test): format code

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-26 15:47:50 +08:00
Luna-channel
61dfb0f207 chore: remove unnecessary files and revert auto_release.yml 2025-12-25 15:04:47 +08:00
Luna-channel
6f9cb770be 修复格式问题 2025-12-25 14:40:33 +08:00
Luna-channel
f4e05e1352 2.0 2025-12-25 02:25:38 +08:00
Luna-channel
8af46ab804 稳定版 2025-12-25 01:44:24 +08:00
Luna-channel
9d32c4e720 自定义规则界面修改 2025-12-25 00:37:10 +08:00
Soulter
701399c00c docs: update readme xmas 2025-12-24 21:58:04 +08:00
Soulter
eaee98d4b8 chore: bump version to 4.10.2 2025-12-24 21:55:05 +08:00
Soulter
76c66000a7 chore: restrict psutil version <7.2.0 to avoid compatibility issues
fixes: #4176
2025-12-24 15:48:58 +08:00
Oscar Shaw
4b365143c0 feat: support for managing command aliases (#4170)
* feat(command): persist aliases on rename and apply to runtime filter

* feat(dashboard-api): support aliases in rename command endpoint

* feat(dashboard-ui): add alias editor to rename command dialog

* feat(dashboard-ui): enhance alias editor UI in rename dialog
2025-12-24 15:37:10 +08:00
Soulter
6e4e5011e2 chore: bump version to 4.10.1 2025-12-23 21:35:40 +08:00
Venus Yan
d853bfde84 perf: handle unsupported message types with logging in OneBot adapter (#4164)
* Handle unsupported message types with logging

解决else 分支中对未知消息类型毫无防御,直接索引ComponentTypes[t],导致新类型markdown类信息报错并炸掉事件管道,且对应群聊单群永久不响应插件;尝试支持markdown类型进行支持但未经过测试

* chore: ruff format

* chore: ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-23 21:31:32 +08:00
Soulter
a0e856f80f fix: provider source id contains slash will lead to 405 (#4162) 2025-12-22 20:28:20 +08:00
Oscar Shaw
8c94a0010c fix(core): improve error handling of command parser and sync (#4161) 2025-12-22 19:54:26 +08:00
Soulter
a44fdaaec0 chore: bump version to 4.10.0 2025-12-22 18:10:30 +08:00
Soulter
60105c76f5 feat: implement router loading progress indicator 2025-12-22 13:20:39 +08:00
Soulter
bcf87d3ce4 fix: update provider subtitle for clarity in English and Chinese locales
- Revised the subtitle in the provider feature localization files to provide a more detailed description of functionalities, including chat model configuration and third-party service integrations.
2025-12-22 13:13:42 +08:00
Soulter
4d7c8c8453 style: add active background color for provider source list item in dark theme 2025-12-22 12:59:55 +08:00
Soulter
a064a9115f fix: omit thinking params for gemini image generation models (#4151)
- Expanded model name checks to include specific Gemini 2.5 and 3 variants, ensuring correct configuration for thinking parameters based on the model used.
2025-12-22 00:09:30 +08:00
Soulter
6ef99e1553 feat: enhance ChatInput and ConversationSidebar dark theme 2025-12-21 21:19:54 +08:00
Soulter
c0dbe5cf65 chore: bump version to 4.10.0-alpha.2 2025-12-21 13:11:32 +08:00
Soulter
3598c51eff fix: enhance provider model menu and sidebar session selection handling (#4144)
- Updated `ProviderModelMenu.vue` to manage menu state and load provider configurations dynamically upon opening.
- Filtered provider configurations to exclude those with `enable` set to false.
- Improved session selection logic in `useSessions.ts` to ensure the currently selected session is highlighted and properly managed during navigation.
2025-12-21 13:05:15 +08:00
Soulter
b5cdb8f650 fix: improve error handling in tool execution to prevent infinite tool call loops (#4143)
* fix: improve error handling in tool execution to prevent infinite tool call loops

- Enhanced error handling in `call_local_llm_tool` to provide more informative exceptions for ValueError and TypeError, including detailed parameter information.
- Updated `ToolLoopAgentRunner` to yield appropriate messages for cases with no response or unsupported types, ensuring clearer communication to users.
- Improved logging and messaging consistency across tool execution processes.

* refactor: clean up unused router parameter in message retrieval functions

- Removed the unused `router` parameter from `getSessionMessages` and related function calls in `Chat.vue` and `useMessages.ts`.
- Commented out the `tool_calls` dictionary in `chat.py` for clarity, indicating it is not currently in use.

* fix: enhance exception handling in tool execution for clearer error reporting

- Improved exception handling in `call_local_llm_tool` by chaining exceptions for ValueError and TypeError, providing more context in error messages.
- Ensured that traceback information is preserved in raised exceptions for better debugging.
2025-12-21 12:57:54 +08:00
Yokami
fc5b520f9b perf(agent): add max step limit to prevent infinite tool call loops (#4110)
* perf(agent): add max step limit to prevent infinite tool call loops

* feat: implement max step limit handling in main agent runner

- Enhanced the agent runner to enforce a maximum step limit, logging a warning and forcing a final response when the limit is reached.
- Updated message handling to append a user prompt when the tool call limit is exceeded.
- Refactored tool response handling to yield appropriate messages based on the response type, including handling cases with no response or unsupported types.
- Improved conversation message formatting to ensure consistent output in the assistant's responses.

* chore: ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-21 12:30:43 +08:00
Soulter
904f56b32f fix: webui conversation traj data display error (#4142)
fixes: #4141
2025-12-20 23:29:40 +08:00
Soulter
2f15fd019c chore: bump version to v4.10.0-alpha.1 2025-12-20 16:35:54 +08:00
Soulter
82330b8d10 feat: add changelog functionality and dialog component (#4135)
* feat: add changelog functionality and dialog component

- Implemented new routes for fetching changelogs and available versions in StatRoute.
- Created ChangelogDialog.vue for displaying changelog content and version selection.
- Updated VerticalSidebar.vue to include a button for opening the changelog dialog.
- Enhanced localization files for English and Chinese to support new changelog features.
- Adjusted styles in VerticalHeader.vue for improved layout consistency.

* chore: ruff format
2025-12-20 16:33:12 +08:00
Soulter
3ee6af7027 feat: add route watcher for viewMode changes in VerticalHeader.vue
- Introduced a watcher to monitor changes in customizer.viewMode, automatically redirecting to the homepage when switching from 'chat' to 'bot' mode.
- Updated imports to include useRoute from vue-router for routing functionality.
- Adjusted button styles for improved layout consistency in bot mode.
2025-12-20 15:38:01 +08:00
Soulter
6e20ebe901 feat: add KaTeX and Mermaid and computation-friendly renderer support (#4118)
* feat: add KaTeX and Mermaid support for enhanced markdown rendering in MessageList.vue

closes: #3747
- Integrated @mdit/plugin-katex and katex for LaTeX rendering.
- Added markstream-vue for improved markdown rendering capabilities.
- Updated MessageList.vue to utilize MarkdownRender component for rendering markdown content.
- Enhanced UI for dark mode compatibility across various components.
- Introduced new styles for file links, reasoning blocks, and tool call cards to improve visual consistency.

* refactor: replace markdown-it with markstream-vue for improved markdown rendering

- Removed markdown-it and related configurations from ReadmeDialog.vue, VerticalHeader.vue, and ConversationPage.vue.
- Integrated markstream-vue for enhanced markdown rendering capabilities, including support for KaTeX and Mermaid.
- Updated components to utilize MarkdownRender for rendering markdown content, improving consistency and performance.

* chore: remove deprecated markdown-it and marked dependencies from pnpm-lock.yaml

- Cleaned up pnpm-lock.yaml by removing markdown-it and marked entries, streamlining the dependency list.
- This change follows the recent integration of markstream-vue for improved markdown rendering capabilities.

* chore: remove d3 dependency and update MessageList.vue for dark mode support

- Removed d3 from package.json and commented out its import in LongTermMemory.vue to clean up unused dependencies.
- Updated MessageList.vue to ensure consistent dark mode styling by passing the isDark prop to MarkdownRender components.

* feat: add loading indicator for message retrieval in Chat and MessageList components

- Introduced a loading overlay in Chat.vue and MessageList.vue to indicate when messages are being loaded.
- Added a new `isLoadingMessages` prop to manage loading state and enhance user experience during message retrieval.
- Updated styles to ensure the loading indicator is visually integrated with the existing UI.

* feat: add provider configuration dialog to chat sidebar

- Introduced a new `ProviderConfigDialog` component for managing provider settings.
- Added a menu item in the `ConversationSidebar` to open the provider configuration dialog.
- Updated English and Chinese localization files to include translations for the new provider configuration feature.

* feat: update dashboard components and styles for improved chat experience

- Replaced font in index.html to use 'Outfit' for a fresh look.
- Changed icon in ConversationSidebar.vue to 'mdi-creation' for better representation.
- Refactored MessageList.vue to streamline loading indicators and enhance styling consistency.
- Updated localization files to change 'Provider Configuration' to 'AI Configuration' for clarity.
- Introduced new styles for loading indicators and chat mode adjustments in FullLayout.vue.
- Added functionality for toggling between bot and chat modes in the header.
- Removed deprecated sidebar item for chat navigation.

* feat: xmas easter egg

* chore: remove pnpm lock file
2025-12-20 15:22:48 +08:00
Yokami
4d6150fd6d fix: handle quoted messages correctly to prevent breaking cache (#4112)
* fix: Handle quoted messages correctly as user context

This change ensures quoted messages, including text and image captions, are appended to the conversation history as a user message rather than being injected into the system prompt.

Fixes #3886

* 注入到req.prompt里
2025-12-20 11:03:27 +08:00
Soulter
544e52191b Merge pull request #4065 from AstrBotDevs/refactor/provider-source
refactor: SUPER AMAZING model provider refactor
2025-12-20 00:09:36 +08:00
Soulter
f2c2a6da4a chore: ruff format 2025-12-20 00:07:42 +08:00
Soulter
dd3df425ee feat: add warnings for missing provider IDs in manager and context
- Introduced logging warnings in ProviderManager and Context classes when a provider ID is not found, indicating potential issues due to ID modifications.
- Updated the ProviderPage.vue to advise against modifying provider IDs, highlighting possible configuration impacts.
2025-12-20 00:06:42 +08:00
Soulter
40b4a27a3d Merge remote-tracking branch 'origin/master' into refactor/provider-source 2025-12-19 15:48:42 +08:00
Soulter
9d991c7468 perf: enhance chat components with theme and fullscreen toggles (#4116)
* perf: enhance chat components with theme and fullscreen toggles

- Added theme and fullscreen toggle functionality to Chat.vue and ConversationSidebar.vue.
- Introduced a new StyledMenu component for improved dropdown menus.
- Updated MessageList.vue and ChatInput.vue for better mobile responsiveness and UI consistency.
- Enhanced language switcher integration in ConversationSidebar.vue.
- Added new settings translations in English and Chinese locales.

* fix: streamline conversation selection handling in Chat.vue

- Updated handleSelectConversation function to immediately set the current session ID and selected sessions, reducing the need for multiple clicks.
- Adjusted padding in ConversationSidebar.vue for improved layout consistency.
2025-12-19 11:18:01 +08:00
Soulter
ad6a8b5c94 Merge remote-tracking branch 'origin/master' into refactor/provider-source 2025-12-18 17:39:27 +08:00
Soulter
1b4bfcbd72 chore: ruff format 2025-12-18 17:37:12 +08:00
Soulter
9d3cc593a1 feat: supports thinking level of google gemini (#4104)
* feat: supports thinking level of google gemini

- Updated google-genai version to >=1.56.0 in pyproject.toml and requirements.txt.
- Changed model configuration from "gemini-1.5-flash" to "gemini-3-flash-preview" in default.py.
- Enhanced thinking configuration handling in gemini_source.py to support new parameters for Gemini 3 models.

* fix: standardize thinking level configuration in default.py and gemini_source.py

- Updated the thinking level values in default.py to uppercase for consistency.
- Enhanced gemini_source.py to validate the thinking level and default to "HIGH" if an invalid value is provided.
2025-12-18 17:37:11 +08:00
Soulter
f0dee35ba9 feat: enhance tool call handling and agent stats tracking and UI integration for tool calls render (#4101)
* feat: enhance tool call handling and UI integration for tool calls render

- Added support for tool call messages in the agent runner and webchat event handling.
- Implemented JSON message component for structured tool call data.
- Updated chat route to save tool call information in message history.
- Enhanced frontend to display tool call details in a collapsible format, including status and results.
- Introduced elapsed time tracking for ongoing tool calls in the chat interface.

* fix: improve message handling in agent run utility and tool loop runner

- Refactored message sending logic in `astr_agent_run_util.py` to use `msg_chain` directly for better clarity.
- Added a check in `tool_loop_agent_runner.py` to ensure `tool_call_result_blocks` is not empty before yielding the last tool call result, preventing potential errors.

* refactor: enhance message structure and UI for chat components

- Updated message handling in `MessageList.vue` to support structured message parts, including plain text, images, audio, and files.
- Improved the `Chat.vue` component styles for better visual consistency.
- Refactored message parsing logic in `useMessages.ts` to accommodate new message formats and ensure proper rendering of embedded content.
- Removed deprecated tool call handling from the message structure, streamlining the message display process.

* chore: ruff format

* feat: implement agent statistics tracking and display in chat

- Added `AgentStats` and `TokenUsage` data classes to track agent performance metrics.
- Enhanced `ToolLoopAgentRunner` to collect and update agent statistics during execution.
- Integrated agent statistics sending to webchat for real-time updates.
- Updated chat route to save and display agent statistics in message history.
- Improved frontend components to visualize agent statistics, including token usage and duration metrics.

* fix: improve message handling in Telegram event and agent run utility

- Updated message sending logic in `astr_agent_run_util.py` to send the correct message chain for tool calls.
- Enhanced `tg_event.py` to edit messages during streaming breaks, improving message management and user experience.
- Added error handling for message editing failures to ensure robustness.

* chore: ruff format
2025-12-18 17:36:45 +08:00
Soulter
4135bd84d5 refactor: update OneBot configuration and add platform logo (#4106)
- Renamed "QQ 个人号(OneBot v11)" to "OneBot v11" in the configuration.
- Added a new logo for OneBot in the dashboard assets.
- Updated platform icon retrieval logic to include the new OneBot logo.
2025-12-18 17:34:59 +08:00
Soulter
f6da614e5d fix: validation error for ToolCall.extra_content in specific upstream model providers (#4102)
* fix: validation error for ToolCall.extra_content in specific upstream model providers

* fix: handle missing extra_content gracefully in ToolCall serialization
2025-12-18 17:34:59 +08:00
Soulter
5f531c9be5 chore: ruff format 2025-12-18 17:17:17 +08:00
Soulter
94591d965b feat: supports thinking level of google gemini (#4104)
* feat: supports thinking level of google gemini

- Updated google-genai version to >=1.56.0 in pyproject.toml and requirements.txt.
- Changed model configuration from "gemini-1.5-flash" to "gemini-3-flash-preview" in default.py.
- Enhanced thinking configuration handling in gemini_source.py to support new parameters for Gemini 3 models.

* fix: standardize thinking level configuration in default.py and gemini_source.py

- Updated the thinking level values in default.py to uppercase for consistency.
- Enhanced gemini_source.py to validate the thinking level and default to "HIGH" if an invalid value is provided.
2025-12-18 17:15:01 +08:00
Soulter
8a0f865af1 feat: enhance tool call handling and agent stats tracking and UI integration for tool calls render (#4101)
* feat: enhance tool call handling and UI integration for tool calls render

- Added support for tool call messages in the agent runner and webchat event handling.
- Implemented JSON message component for structured tool call data.
- Updated chat route to save tool call information in message history.
- Enhanced frontend to display tool call details in a collapsible format, including status and results.
- Introduced elapsed time tracking for ongoing tool calls in the chat interface.

* fix: improve message handling in agent run utility and tool loop runner

- Refactored message sending logic in `astr_agent_run_util.py` to use `msg_chain` directly for better clarity.
- Added a check in `tool_loop_agent_runner.py` to ensure `tool_call_result_blocks` is not empty before yielding the last tool call result, preventing potential errors.

* refactor: enhance message structure and UI for chat components

- Updated message handling in `MessageList.vue` to support structured message parts, including plain text, images, audio, and files.
- Improved the `Chat.vue` component styles for better visual consistency.
- Refactored message parsing logic in `useMessages.ts` to accommodate new message formats and ensure proper rendering of embedded content.
- Removed deprecated tool call handling from the message structure, streamlining the message display process.

* chore: ruff format

* feat: implement agent statistics tracking and display in chat

- Added `AgentStats` and `TokenUsage` data classes to track agent performance metrics.
- Enhanced `ToolLoopAgentRunner` to collect and update agent statistics during execution.
- Integrated agent statistics sending to webchat for real-time updates.
- Updated chat route to save and display agent statistics in message history.
- Improved frontend components to visualize agent statistics, including token usage and duration metrics.

* fix: improve message handling in Telegram event and agent run utility

- Updated message sending logic in `astr_agent_run_util.py` to send the correct message chain for tool calls.
- Enhanced `tg_event.py` to edit messages during streaming breaks, improving message management and user experience.
- Added error handling for message editing failures to ensure robustness.

* chore: ruff format
2025-12-18 17:11:09 +08:00
Soulter
4aced976a8 refactor: update OneBot configuration and add platform logo (#4106)
- Renamed "QQ 个人号(OneBot v11)" to "OneBot v11" in the configuration.
- Added a new logo for OneBot in the dashboard assets.
- Updated platform icon retrieval logic to include the new OneBot logo.
2025-12-18 15:19:15 +08:00
Soulter
0299aa6e4c fix: validation error for ToolCall.extra_content in specific upstream model providers (#4102)
* fix: validation error for ToolCall.extra_content in specific upstream model providers

* fix: handle missing extra_content gracefully in ToolCall serialization
2025-12-18 11:55:49 +08:00
Soulter
e8b54a019e refactor: replace ProviderModelSelector with ProviderModelMenu for improved UI and functionality 2025-12-17 22:57:32 +08:00
Soulter
98ce796275 chore: remove copilot instruction 2025-12-17 17:21:33 +08:00
Soulter
b87dcf2275 refactor: improve provider source ID validation to prevent duplicates during configuration updates 2025-12-17 17:19:35 +08:00
Soulter
591a228431 refactor: enhance provider management with resource locking and CRUD operations 2025-12-17 17:08:52 +08:00
Soulter
f52f375154 refactor: update provider handling to use new config structure and improve template retrieval 2025-12-17 16:55:12 +08:00
Soulter
975c685a17 chore: ruff format 2025-12-17 16:32:38 +08:00
Soulter
6db80d36a8 fix: prevent platform ID modification during updates and ensure correct routing table handling 2025-12-17 16:16:50 +08:00
Soulter
4651bd2807 feat: implement provider deletion functionality and ensure unique provider IDs 2025-12-17 15:00:22 +08:00
Soulter
94ada3793e Merge remote-tracking branch 'origin/master' into refactor/provider-source 2025-12-17 13:33:23 +08:00
Soulter
fd05b0bf09 docs: update contributing guidelines to include code style and formatting instructions 2025-12-17 13:26:22 +08:00
Soulter
4d046f8490 delete: remove backup of ProviderPage.vue 2025-12-17 11:34:12 +08:00
Copilot
58e32b7b70 fix: inverted logic in segmented reply LLM-only filter (#4071)
* Initial plan

* Fix: Correct inverted logic in is_seg_reply_required for only_llm_result option

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2025-12-17 11:12:05 +08:00
Soulter
903dd0f9f7 feat: add manual model addition functionality and search capability in ProviderPage 2025-12-17 10:56:45 +08:00
Soulter
1acac0cac2 feat: enhance provider selection with a new drawer interface and localization updates 2025-12-17 10:39:16 +08:00
Oscar Shaw
80b89fd2ea feat: implements command management and improve webui feature structure (#3904)
move mcp management to plugin managemanet page

* feat: 新增命令配置数据库模型

* feat: 实现核心命令管理系统

* feat: 将命令管理集成到 Star 框架

* feat: 新增命令管理后台 API

* feat: 新增命令管理界面页面

* feat: 新增命令管理国际化支持

* test: 新增命令管理相关测试

* refactor(command): 移除指令重命名时的别名功能

* fix(command): 修正指令冲突检测逻辑

* fix(command): 排除已禁用指令的冲突检测

- 只有 `effective_command` 存在且 `enabled` 为 `True` 的指令才会被纳入冲突检测范围。

* feat(command): 优化指令冲突显示与提示

- 【功能】新增指令冲突警告提示,当检测到冲突时显示详细信息及解决方案。
- 【优化】调整指令列表排序逻辑,将冲突指令优先显示并分组。
- 【样式】为冲突指令行添加专属高亮样式,提升视觉识别度。
- 【国际化】更新英文和中文多语言文件,增加指令冲突警告相关的翻译文本。

* chore(command-page): 禁用命令表格部分列的排序功能

* style(command-page): 调整命令页面表格样式和图标大小

* refactor(command): 优化指令页面布局并更新冲突警告

- 【布局优化】重新组织指令管理页面布局,将筛选器移至顶部独立行
- 【信息展示】将搜索栏与总指令数、已禁用指令数合并显示,提升页面空间利用率
- 【视觉更新】更新指令冲突警告样式

* style: UI 细节

* refactor(command): 调整指令管理中的成员权限显示与筛选

  - 更新指令筛选逻辑,当选择“所有人”权限筛选时,将同时包含 `everyone` 和 `member` 权限的指令。

* feat(command-management): 新增指令层级管理与UI展示

- 【后端】
  - `CommandDescriptor` 新增 `parent_group_handler` 和 `sub_commands` 字段,支持指令层级结构定义。
  - `list_commands` 函数重构,实现指令的层级收集与构建,将子指令正确挂载到其父指令组下。
  - 新增 `_collect_all_descriptors` 和 `_find_parent_group_handler` 辅助函数,用于全面收集指令并定位父指令组。
  - `_build_descriptor` 优化指令类型判断逻辑,明确区分普通指令、指令组和子指令。
  - `_descriptor_to_dict` 递归处理子指令,确保 API 返回完整的指令层级数据。
- 【前端】
  - 指令管理页面 (`CommandPage.vue`) 增加指令类型筛选器,并支持指令组的展开/折叠功能。
  - 表格展示优化,为指令组和子指令添加不同的样式和缩进,提升层级结构的视觉可读性。
  - 指令详情对话框新增指令类型、所属指令组和子指令列表的展示。
  - 更新 `CommandItem` 接口,以适配后端提供的层级数据结构。
- 【i18n】
  - 新增指令类型(指令、指令组、子指令)的国际化文本。
  - 更新指令管理相关 UI 文本,包括表格头部、详情对话框字段和筛选器选项。

* style(command): 优化指令组子指令数量显示UI

* refactor(command): 修改指令列表排序逻辑

* style(command-page): 优化命令列表UI

* feat(command): 添加系统插件指令过滤与冲突处理

* refactor(command): 更新指令数展示逻辑

* style(command): 更新空状态描述

* feat(extension): 添加插件指令冲突检测与提示

- 在插件安装或启用后,自动检测并提示指令冲突。
- 当检测到指令冲突时,显示警告对话框,告知用户冲突数量及可能的影响。

* refactor(command): 移除指令表格内部加载指示器

* style(extension): 文案修改

* refactor(command): 模块化指令管理面板前端代码

* refactor(commandPanel): 重命名指令模块目录为 commandPanel

* style(commandPanel): 微调指令面板UI

* fix(command): 确保新命令配置的事务提交

* fix(sidebar): 补全新增侧边栏项后的侧边栏位追加逻辑

* refactor(commands): 重构/help指令以动态显示实际命令并补充部分命令描述

* style(builtin_commands): 补充命令描述

* refactor(commandPanel): 移除未使用的 filterState 常量

* perf(dashboard): 删除多余的CommandPage.vue文件(已被模块化引用)

* perf(command): 优化命令冲突计数逻辑

* perf(command): 优化指令管理辅助函数和配置绑定逻辑

* perf(db): 优化重构command相关数据库操作

* refactor(sidebar): 提取侧边栏项目解析逻辑到工具函数复用

* refactor: move mcp and command page to extension page

* refactor: remove unused imports in component panel

* fix: update terminology for handler management in extension localization

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-16 20:24:57 +08:00
Soulter
26f863ba81 Revert "fix: omit empty content field for the LLM request after tool calls ar…" (#4068)
This reverts commit f78a90218e.
2025-12-16 20:22:13 +08:00
sctop
f78a90218e fix: omit empty content field for the LLM request after tool calls are completed (#4008)
* fix: omit content field for the LLM request after tool calls are completed and content is empy string or none

* chore: ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-16 20:11:11 +08:00
Soulter
a3ecebd2aa fix: correct text accumulation logic in webchat (#4066) 2025-12-16 19:35:41 +08:00
Soulter
67c33b842d feat: add new provider icons and improve provider source handling
- Added icons for 'modelstack', 'tokenpony', and 'compshare' in providerUtils.js.
- Updated ProviderPage.vue to display the correct count of displayed provider sources.
- Enhanced the logic for displaying provider sources to include placeholders for unselected templates.
- Improved the display name for provider sources to show template keys for placeholders.
- Adjusted styles for better layout and overflow handling in provider source list and cards.
- Refactored source selection logic to handle placeholder sources correctly.
- Updated error handling in provider testing to provide clearer messages.
2025-12-16 16:11:56 +08:00
Soulter
5431c9f46e refactor: remove unused tab from AddNewProvider and disable button based on provider status in ProviderPage 2025-12-16 12:26:26 +08:00
Soulter
764b91a5f7 chore: ruff check 2025-12-16 12:21:14 +08:00
Soulter
c20c1b84bf feat: implement LLM metadata fetching and integrate into provider model selection 2025-12-16 12:19:40 +08:00
Soulter
fd66a0ac00 perf: better UI 2025-12-16 11:24:07 +08:00
Soulter
aaee283367 fix: type checking of AstrAgentContext 2025-12-16 10:09:57 +08:00
Soulter
4a5b7d1976 fix: type checking of contextwrapper 2025-12-16 09:59:56 +08:00
Sukafon
08244548ab fix: incorrect type assignment when the agent send an image (#4050) 2025-12-16 08:28:10 +08:00
dependabot[bot]
b486de6a98 chore(deps): bump actions/upload-artifact in the github-actions group (#4061)
Bumps the github-actions group with 1 update: [actions/upload-artifact](https://github.com/actions/upload-artifact).


Updates `actions/upload-artifact` from 5 to 6
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-16 08:24:03 +08:00
Soulter
e2f928a7e5 chore: bump version to 4.9.2 2025-12-15 16:58:32 +08:00
Soulter
b8e4068c75 feat: support key-value storage for plugins (#4048)
* feat: support key-value storage for plugins

* fix: remove unnecessary initialization method from Main class
2025-12-15 16:50:44 +08:00
Soulter
0916177a57 chore: bump version to 4.9.1 2025-12-15 16:07:10 +08:00
Soulter
02cd5e396b feat: add trigger probability setting for TTS and support to render slider in schema (#4047)
* feat: add trigger probability setting for TTS and support to render slider in schema

* chore: ruff format
2025-12-15 16:04:27 +08:00
Soulter
56673ad78f fix: prevent duplicate result content type after streaming finishes in RespondStage 2025-12-15 15:33:40 +08:00
Soulter
9a4d05e2b6 fix: remove unnecessary persistent attribute from ReadmeDialog and adjust dialog structure in ExtensionPage 2025-12-15 15:27:42 +08:00
Soulter
b2e9dab233 refactor: enhance layout and improve provider source management in ProviderPage 2025-12-15 15:15:17 +08:00
Soulter
45110200ea feat: update provider and provider source configuration handling 2025-12-15 12:31:29 +08:00
Soulter
c3f45449e8 docs: readme
wa ta shi wa ko sei no de su ka ra!
2025-12-15 11:47:21 +08:00
Copilot
65da469deb feat: add conversation export feature to JSONL for AI training (#4037)
* Initial plan

* Add conversation export functionality (backend and frontend)

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* Address code review feedback: move imports, simplify logic, improve i18n

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* Simplify frontend download logic: remove redundant Blob wrapper and complex filename parsing

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* fix: update conversation export filename format for consistency

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2025-12-14 21:44:12 +08:00
Soulter
16df64c405 fix: lark domain and log_level of Lark API client (#4038)
fixes: #4035
2025-12-14 21:31:17 +08:00
i0cLiceao
6b73b19e54 fix: support using GitHub Raw content as plugin source (#3975)
* Update plugin.py

* Update plugin.py

* Update plugin.py

* Update plugin.py
2025-12-14 18:23:29 +08:00
Soulter
a70088b799 Merge remote-tracking branch 'origin/master' into refactor/provider-source 2025-12-13 23:37:23 +08:00
Soulter
e7e97730af chore: bump version to 4.9.0 2025-12-13 18:49:07 +08:00
Soulter
467ca1eb5c fix: webui log output incompletely (#4029)
* fix: webui log output incompletely

* fix: improve SSE log parsing to handle partial data chunks

* fix: enhance log handling by implementing local cache and fetching history

* fix: log time handling to use epoch time
2025-12-13 18:46:16 +08:00
Soulter
bb45d9cb54 stage 2025-12-13 17:16:07 +08:00
RC-CHN
46528391c2 feat: add pre-chunk import strategy for knowledge base (#3973)
* feat: 添加文档导入功能及相关测试

* feat: 优化文档上传功能,支持从文件名推断文件类型,并增强文档切片验证

* feat: 添加文档导入功能的无效输入测试,验证 chunks 类型和内容的错误处理

* refactor: 重构文档上传和导入任务的状态管理,添加任务初始化、结果设置和进度更新方法
2025-12-12 23:15:11 +08:00
Soulter
8a0b7717cc feat: supports webhook mode for Lark platform (#4016)
* feat: add Lark platform support with unified webhook configuration

* fix: update token verification logic in LarkWebhookServer

* feat: implement event deduplication and cleanup for Lark webhook events
2025-12-12 22:12:13 +08:00
Copilot
3b81fb4985 fix: mobile dialog close button visibility (#4010)
* Initial plan

* Fix mobile dialog close button visibility by adding max-height and scrollable content

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2025-12-12 16:02:24 +08:00
Soulter
c09d57a820 refactor: improve UI layout and interaction for list item management (#4002)
* refactor: improve UI layout and interaction for list item management

* feat: enhance list configuration UI with batch import functionality

* feat: add internationalization support for list configuration UI
2025-12-11 18:55:56 +08:00
Soulter
ec408a2aff fix: lark message timestamp 2025-12-11 18:20:50 +08:00
Soulter
417179a6b9 ci: add smoke test 2025-12-11 10:44:15 +08:00
Soulter
fcd29445c7 refactor: remove unused current provider initialization in StarRequestSubStage 2025-12-11 10:36:33 +08:00
BiDuang
5f535001db fix: incorrect modalities enum of gemini api provider (#3993) 2025-12-10 20:27:51 +08:00
PaloMiku
750d245b16 docs: Update README with new Zread link and badges (#3992)
ZRead 是由智谱 AI 推出的 DeepWiki 类似平替品。
2025-12-10 20:22:56 +08:00
Dt8333
f624971613 chore: fix bunches of type checking errors (#3213)
* chore(core.utils): 🚨 修正错误Lint

* chore(core.provider): 🚨 修复基类错误Lint

* chore(core.utils): 补全session_get()的重载

* chore(core.provider): 🚨 修正实现错误Lint

* chore(core.platform): 🚨 修正platform基类和webchat的错误Lint

* chore(core.platform): 修正错误实现Lint

* fix(core.provider): 修复循环调用和错误assert

* chore(core.platform): 修复部分实现Lint

* chore(core.provider): 补充Dify.text_chat_stream的参数类型

* chore(core.pipeline): 🚨 修复错误Lint

* fix(core.slack): 补充遗漏导入

* chore(core.utils): 修复错误的session_get声明

* chore(core.platform): 移除Lark adapter import中的wildcard

* chore(core.db): 修复声明和部分逻辑

* chore(core.db): 添加typings,使faiss参数能被正确识别。

* chore(core): 修复声明

* chore(core): 修改声明

* chore: 补充faiss声明

* chore(dashboard): 修改实现,减少报错

* chore(package): 修改部分声明与实现,减少报错

* chore(core): 添加Handler的overload,以去除部分assert同时通过类型检查

* chore(core.pipeline): 修改Pipeline Scheduler的execute,将判断属性改为判断类型,通过静态类型检查

* chore(core.config): 添加类型标注,通过类型检查

* chore(core.message): 为File._download_file添加检查,通过类型检查

* fix: 将断言改为条件判断以实现优雅关闭的容错性

* refactor: 移除 discord 客户端中的 assert,改用 if None 判断并抛出异常

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: DiscordPlatformAdapter 对 self.client.user 为 None 做日志并返回,移除断言

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 增强 Lark 相关空值/异常检查并完善日志输出

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 将断言替换为条件检查并加入日志与错误处理

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* chore: 移除LLM生成的无用注释

* refactor: 使用 File.get_file 替换下载逻辑并移除 assert,提供默认 filename

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: Slack Socket 未初始化抛出运行时异常,图片 URL 判空改为非空判断

* refactor: 将 WeChatPadProAdapter 的断言改为空值判断并添加日志

* refactor: 使用 isinstance 替代断言实现类型判断,便于静态检查

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 去除cast,直接使用字段与字典访问,修正端口解析

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 使用 match-case 重构 ProviderManager 加载并通过类型检查抛出 TypeError

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: group_name_display 时若 group 对象为空则记录错误并返回

* fix: 将 _get_current_persona_id 的 assert 替换成 if guard 并返回 None

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 优化插件目录存在性检查及图片URL非空验证,更新JSON排序配置

* fix: 将 datetime_str 的 assert 替换为显式检查并抛出异常

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 移除 cast,改为运行时检查并在找不到调度器时跳过

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 移除 cast,改用 isinstance 检查 FaissVecDB 并警告

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 删除 typing.cast 导入,并在获取文件绝对路径前校验 file_

* refactor: 移除 typing.cast,简化内容安全检查调用

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 将 PlatformMetadata.id 设为必填并在注册时传入 id,移除 cast

* refactor: 移除 cast,改用 HasInitialize 与 isinstance 进行初始化

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 为 ProviderManager.initialize 增加ID类型判断,避免 None 导致 get 失败

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 为 OTTSProvider 与 AzureNativeProvider 引入 _client 与 client 属性改进上下文管理

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 为 Whisper 自托管源添加模型未初始化校验并直接调用 transcribe

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 移除未使用的 cast 导入并简化 platform_name 赋值

* refactor: 引入 cast 并对 id 使用 cast(str, ...) 提升类型安全

* fix: 将 _id_to_sid 返回改为 str,空值返回空串;对 id 与 message_id 使用 cast

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 重构 Discord 处理逻辑:强制 类型转换、优先斜杠指令并优化提及判断

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* fix: 统一对 id 获取执行 cast,并在微信消息解析失败时抛错

* Revert "fix: 去除cast,直接使用字段与字典访问,修正端口解析"

This reverts commit 1cbfdf9d1b.

* fix: 百炼 Rerank 会话关闭时返回空结果;初始化 request.prompt 避免空值拼接

* fix: 统一处理搜索结果链接为字符串,新增 _get_url 助手并适配 Bing/Sogo

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>

* refactor: 调整 call_handler 泛型、Discord 通道注解及 FishAudioTTS API 请求类型

* refactor: 使用 col(...) 替代列引用并对结果进行 CursorResult 强转

* chore: ruff format

---------

Co-authored-by: aider (openai/gemini-3-pro-high) <aider@aider.chat>
Co-authored-by: Soulter <905617992@qq.com>
2025-12-09 14:13:47 +08:00
Soulter
aa6d07afcc refactor: move all internal commands from astrbot plugin to default_command plugin (#3960)
* refactor: move all internal commands from astrbot plugin to default_command plugin

* ruff check

* feat: add config

* ruff check
2025-12-08 22:17:32 +08:00
Soulter
2c36649874 feat: add Agent Runner test prompt dialog in ProviderPage (#3968) 2025-12-08 21:46:47 +08:00
Soulter
c95735dcc0 docs: update readme 2025-12-08 12:05:57 +08:00
Soulter
03bb278f50 chore: ruff check 2025-12-08 11:00:43 +08:00
Soulter
a5e0974da3 chore: ruff format 2025-12-08 00:36:56 +08:00
vmoranv
f0fb447fbc feat: custom plugin api source manager (#3956)
* feat: custom plugin api source manager

* fix: rename plugin source file in a safer way

* chore: turned the way of saving plugin source to backend and refacted some components

* style: clean up whitespace and improve logging message formatting

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-08 00:32:50 +08:00
Soulter
37566182b0 feat: segment reply supports segmentation words (#3959)
* feat: segment reply supports segmentation words

* chore: ruff format

* feat: enhance segmented reply processing by refining word extraction logic

* ruff format
2025-12-08 00:27:17 +08:00
Soulter
e460b411da chore: remove dev version from webui (#3951)
* chore: remove dev version

* chore: remove development version references from header localization files
2025-12-07 15:23:30 +08:00
Soulter
e14ed804da chore: bump version to 4.8.0 2025-12-05 19:09:56 +08:00
Oscar Shaw
8e4e49df20 fix: not invoke on_llm_response hook when LLM request has error (#3871)
* fix: handle on_agent_done in error responses

- Introduced an LLMResponse for error messages to be processed by agent hooks, ensuring better error reporting and handling.

* fix: improve error logging in on_agent_done hook

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2025-12-05 16:13:46 +08:00
Oscar Shaw
5d856900ef perf: some UI/UX fixes, change Console to Platform Logs (#3873)
* refactor: 统一‘平台日志’文案

* perf: 优化自动滚动开关键操作逻辑

* perf: add tooltips to save and code editor buttons
2025-12-05 16:02:20 +08:00
Soulter
380a68b96c chore: add CONTRIBUTING.md 2025-12-05 15:59:18 +08:00
易推倒白毛
8879bd7e9d fix: add supports for Whisper with QQ amr audio file
* fix: Whisper API对QQ语音amr文件的支持

* Update whisper_api_source.py

* fix: cleanup temporary files in Whisper API

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-05 15:41:37 +08:00
RC-CHN
2cce09400f feat: add Kubernetes manifests for astrbot and napcat deployment with services and persistent storage (#3901)
* feat: add Kubernetes manifests for astrbot and napcat deployment with services and persistent storage

* chore: remove 11451 port

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-04 20:36:35 +08:00
Oscar Shaw
54d26dcd38 perf: integrate Pinia store for log cache management (#3852)
* perf: integrate Pinia store for log cache management

* perf: remove unused code
2025-12-04 14:26:05 +08:00
Soulter
205024f27a fix: correct SQL query syntax in SQLiteDatabase class 2025-12-04 12:51:22 +08:00
Soulter
efde994907 chore: revise badges and language links
Updated badge links and language options in README.
2025-12-03 17:21:09 +08:00
Soulter
8ca4f9cb74 feat: update README files for multilingual support and enhanced descriptions
- Added French, Russian, and Traditional Chinese README files to support a wider audience.
- Updated English and Japanese README files with improved descriptions of AstrBot's capabilities and features.
- Enhanced community section in all README files to include QQ, Telegram, and Discord group information.
- Adjusted plugin marketplace badge and key features list for clarity and consistency across languages.
2025-12-03 17:01:56 +08:00
Soulter
54e49b997b feat: enhance platform management with status tracking and error handling
- Introduced PlatformStatus enum to manage platform states (pending, running, error, stopped).
- Added error recording and retrieval functionality in the Platform class.
- Implemented a new method in PlatformManager to gather statistics for all platforms.
- Updated the dashboard to display platform statuses and error details, including a dialog for error insights.
- Enhanced localization for runtime statuses and error dialogs in both English and Chinese.
2025-12-03 16:48:57 +08:00
Soulter
5714944eef feat: unified platform webhook url (#3889)
* feat: unified platform webhook url

* chore: ruff format

* fix: 修复 Telegram 语音使用 Whisper API 报错 (#3884)

* Update whisper_api_source.py

* chore: ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>

* Update astrbot/dashboard/routes/platform.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: ruff format

* fix: update webhook dialog descriptions for clarity in English and Chinese locales

* fix: update webhook URL paths to include '/api' prefix for consistency across the application

---------

Co-authored-by: 易推倒白毛 <zhaixingbi@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-03 15:44:52 +08:00
Soulter
defc46b6c9 fix: remove unnecessary blocks in Slack reply message (#3897) 2025-12-03 13:59:41 +08:00
Soulter
4d819546b0 fix: handle message sending in QQOfficialMessageEvent class (#3894)
- Added a fallback to the `_post_send` method without parameters when the stream payload is not set, ensuring proper message handling in all scenarios.

fixes: #3893
2025-12-03 13:15:12 +08:00
易推倒白毛
8006981976 fix: 修复 Telegram 语音使用 Whisper API 报错 (#3884)
* Update whisper_api_source.py

* chore: ruff format

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-12-03 02:50:50 +08:00
Soulter
f7a716af43 refactor: message storage format of webchat, support reply and file message segment (#3845)
* refactor: message storage format of webchat

* refactor: update image and record handling in webchat event processing

* fix: thinking placeholder in webchat

* feat: supports file upload in webchat

* feat: supports to delete attachments when webchat session is deleted

* perf: improve performance of file downloading

* refactor: remove unused import in chat route

* feat: add message timestamp formatting and localization support in chat

* fix: handle missing filename in file upload for chat route

* feat: enhance file handling in chat and webchat, supporting video uploads and improved attachment management

* fix: update property name for embedded files in message handling

* fix: compute variable errors after uninstalling plugins

* feat: supported for reply message and standarlize the message param

* fix: ensure message actions are displayed for the last message in the list
2025-12-02 17:11:08 +08:00
Copilot
a708901e7f fix: fix dark mode white background in conversation preview dialog (#3881)
* Initial plan

* Fix dark mode background issue in conversation data preview

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>

* style: update conversation messages container background color and add debug log for dark mode detection

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2025-12-02 17:03:59 +08:00
Soulter
e9be8cf69f chore: bump version to 4.7.4 2025-12-01 18:42:07 +08:00
Soulter
31d53edb9d refactor: standardize provider test method implementation
- Updated the `test` method in all provider classes to remove return values and raise exceptions for failure cases, enhancing clarity and consistency.
- Adjusted related logic in the dashboard and command routes to align with the new `test` method behavior, simplifying error handling.
2025-12-01 18:37:08 +08:00
Soulter
2ba0460f19 feat: introduce file extract capability (#3870)
* feat: introduce file extract capability

powered by MoonshotAI

* fix: correct indentation in default configuration file

* fix: add error handling for file extract application in InternalAgentSubStage

* fix: update file name handling in InternalAgentSubStage to correctly associate file names with extracted content

* feat: add condition settings for local agent runner in default configuration

* fix: enhance file naming logic in File component and update prompt handling in InternalAgentSubStage
2025-12-01 18:12:39 +08:00
雪語
0e034f0fbd fix: aiocqhttp 适配器 NapCat 文件名获取为空 (#3853)
* aiocqhttp 适配器 NapCat 文件名获取为空

修复使用 NapCat 时,文件消息的 File.name 为空的问题。原代码硬编码 name="",导致下游插件无法获取文件名和扩展名

* Enhance file name retrieval from message data

Updated file name extraction logic to check multiple fields for better accuracy.
2025-12-01 13:36:19 +08:00
Soulter
2a7d03f9e1 fix: fit language and log AI responses more clearly (#3864)
* fix: fit language and log AI responses more clearly

* chore: ruff format
2025-12-01 13:24:52 +08:00
Soulter
72fac4b9f1 feat: implement unified provider availability testing across components (#3865)
- Added a `test` method to each provider class to standardize availability checks.
- Updated the dashboard and command routes to utilize the new `test` method for provider reachability verification, simplifying the logic and improving maintainability.
- Removed redundant reachability check logic from the command handler.
2025-12-01 13:17:20 +08:00
Soulter
38281ba2cf refactor: restore reachability check configuration in default settings and localization files 2025-12-01 00:38:30 +08:00
Soulter
21aa3174f4 fix: disable reachability check in default configuration 2025-12-01 00:16:11 +08:00
邹永赫
dcda871fc0 feat: provider availability reachability improvements (#3708) 2025-12-01 01:06:10 +09:00
Soulter
c13c51f499 fix: assistant message validation error when tool_call exists but content not exists (#3862)
* fix: assistant message validation error when tool_call exists but content not exists

* fix: enhance content validation in Message model to allow None for assistant role with tool_calls
2025-11-30 23:42:37 +08:00
Dt8333
a130db5cf4 fix: 将 Graceful shutdown 的异常改为 KeyboardInterrupt (#3855) 2025-11-30 20:31:17 +08:00
邹永赫
7faeb5cea8 Merge pull request #3850 from zouyonghe/feature/plugin-upgrade-all
增加升级所有插件按钮
2025-11-30 15:12:36 +09:00
ZouYonghe
8d3ff61e0d Format plugin route with ruff 2025-11-30 11:56:24 +08:00
ZouYonghe
4c03e82570 Fix plugin update JSON parsing and concurrency handling 2025-11-30 11:50:46 +08:00
ZouYonghe
e7e8664ab4 chore: tweak update all label 2025-11-30 11:18:30 +08:00
ZouYonghe
1dd1623e7d feat: batch update plugins via new api 2025-11-30 11:11:36 +08:00
ZouYonghe
80d8161d58 feat: add update all plugins action 2025-11-30 10:40:46 +08:00
Soulter
fc80d7d681 chore: bump version to 4.7.3 2025-11-30 00:42:49 +08:00
Soulter
c2f036b27c chore: bump vertion to 4.7.2 2025-11-30 00:33:07 +08:00
Soulter
4087bbb512 perf: set content attribute optional to AssistantMessageSegment for enhanced message handling
fixes: #3843
2025-11-30 00:32:00 +08:00
Soulter
e1c728582d chore: bump version to 4.7.2 2025-11-30 00:18:23 +08:00
Oscar Shaw
93c69a639a feat: 新增群聊模式下的专用图片转述模型配置 (#3822)
* feat: add image caption provider configuration for group chat

- Introduced `image_caption_provider_id` to allow separate configuration for group chat image understanding.
- Updated metadata and hints in English and Chinese for clarity on new settings.
- Adjusted logic in long term memory to utilize the new provider ID for image captioning.

* fix: format

* Fix logic for image caption and active reply settings

* Fix indentation and formatting in long_term_memory.py

* chore: ruff format

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2025-11-29 23:53:32 +08:00
Soulter
a7fdc98b29 fix: third party agent runner cannot run properly when using non-default config file
fix: #3815
2025-11-29 23:45:12 +08:00
Soulter
85b7f104df fix: remove unnecessary provider check (#3846)
fixes: #3815
2025-11-29 23:15:19 +08:00
Oscar Shaw
d76d1bd7fe perf: adjust padding for PlatformPage and ProviderPage log sections (#3825)
- Added bottom margin to log card for better spacing.
2025-11-29 19:15:35 +08:00
Soulter
df4412aa80 style: adjust bot-embedded-image max-width and remove hover effect for improved layout 2025-11-29 01:31:25 +08:00
Soulter
ab2c94e19a chore: comment out error logging in provider sources to reduce verbosity 2025-11-28 19:59:33 +08:00
Oscar Shaw
37cc4e2121 perf: console tag UI improve (#3816)
- Added yarn.lock to .gitignore to prevent tracking of Yarn lock files.
- Updated ConsoleDisplayer.vue to improve chip styling
2025-11-28 17:17:11 +08:00
Soulter
60dfdd0a66 chore: update astrbot cli version 2025-11-28 16:53:20 +08:00
Soulter
bb8b2cb194 chore: bump version to 4.7.1 2025-11-28 15:13:35 +08:00
Soulter
4e29684aa3 fix: add plugin set and knowledge bases selection in custom rules page (#3813)
fixes: #3806
2025-11-28 13:29:50 +08:00
Soulter
0e17e3553d chore: bump version to 4.7.0 2025-11-27 23:50:05 +08:00
Soulter
0a55060e89 fix: session controller in webchat 2025-11-27 22:32:35 +08:00
Soulter
77859c7daa feat: enhance provider status display in ProviderPage
- Added a tooltip to show detailed provider status, including availability and error messages.
- Refactored item details template to include status chips for better visual representation.
- Removed unused status section to streamline the UI.
2025-11-27 16:39:51 +08:00
Soulter
ba39c393a0 perf: enhance provider management with reload locking and logging (#3793)
- Introduced a reload lock to prevent concurrent reloads of providers.
- Added logging to indicate when a provider is disabled and when providers are being synchronized with the configuration.
- Refactored the reload method to improve clarity and maintainability.


Co-authored-by: anka <1350989414@qq.com>
2025-11-27 16:25:31 +08:00
Soulter
6a50d316d9 fix: mcp server cannot reload successfully after updating mcp server config (#3797)
fixes: #3780
2025-11-27 16:22:26 +08:00
Soulter
88c1d77f0b perf: add at message to group chat history (#3796)
* feat: enhance long-term memory message formatting

- Added support for 'At' message components in long-term memory, allowing for better representation of mentions in messages.

* chore: ruff check
2025-11-27 15:59:07 +08:00
Dt8333
758ce40cc1 chore: fix test (#3787) 2025-11-27 14:02:42 +08:00
Soulter
3e7bb80492 chore: ruff format 2025-11-27 14:01:25 +08:00
Soulter
75e95aa9ca fix: update session management icon in sidebar
- Changed the icon for the session management sidebar item from 'mdi-account-group' to 'mdi-pencil-ruler' for better representation.
2025-11-27 14:00:05 +08:00
Soulter
a389842e25 feat: update session management UI with information button and layout adjustments
- Added an information button linking to custom rules documentation.
- Adjusted layout for improved spacing and readability in the session management page.
- Minor refactoring of the data table component for better alignment.
2025-11-27 13:58:37 +08:00
Soulter
0f6a3c3f5a refactor: session management custom rules (#3792)
* refactor: umo custom rules

* feat(i18n): update session management translations and improve provider configuration handling

- Updated English and Chinese translations for session management, including "Unified Message Origin" and "Follow Config".
- Enhanced provider configuration options to include "Follow Config" as a selectable item.
- Removed unused clear buttons and refactored provider configuration saving logic to handle updates and deletions more efficiently.
2025-11-27 13:30:43 +08:00
Soulter
133f27422d feat: implement i18n of astrbot config (#3772)
* feat: implement i18n of astrbot config

* feat(config): update configuration metadata with i18n details and future deprecation notes
2025-11-26 16:40:58 +08:00
RC-CHN
abc6deb244 feat: add plugin logo placeholder (#3784) 2025-11-26 16:22:11 +08:00
teapot1de
06869b4597 docs: clarify segmented_reply words_count_threshold hint (#3779)
Update the configuration hint for `words_count_threshold` to explicitly state that it acts as a maximum limit for segmentation, preventing user confusion about it being a minimum trigger.
2025-11-26 16:15:09 +08:00
dependabot[bot]
d32cea9870 chore(deps): bump actions/checkout in the github-actions group (#3775)
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 5 to 6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-26 16:13:42 +08:00
Soulter
4b68100f16 feat(chat): add standalone chat component and integrate with config page for testing configurations (#3767)
* feat(chat): add standalone chat component and integrate with config page for testing configurations

* feat(chat): add error handling for message sending and session creation
2025-11-24 22:06:02 +08:00
Soulter
5c5515d462 fix: segmented reply regex error handling (#3771)
* fix: segmented reply regex error handling

closes: #3761

* fix: improve regex handling for segmented replies to support multiline input

* fix: update regex handling in ResultDecorateStage to use findall for segmented replies

* fix: update error logging message for segmented reply regex handling
2025-11-24 22:00:59 +08:00
Soulter
3932b8f982 Merge pull request #3760 from AstrBotDevs/feat/agent-runner
refactor: transfer dify, coze and alibaba dashscope from chat provider to agent runner
2025-11-24 15:33:20 +08:00
Soulter
82488ca900 feat(api): enhance file upload method to support mime type and file name 2025-11-24 15:30:49 +08:00
Soulter
29d9b9b2d6 feat(config): add condition for display_reasoning_text based on agent_runner_type 2025-11-24 15:10:17 +08:00
Soulter
02215e9b7b feat(config): update hint for agent_runner execution method to clarify third-party integration 2025-11-24 15:07:33 +08:00
Soulter
7160b7a18b fix: dify workflow streaming mode 2025-11-24 15:04:15 +08:00
Soulter
ea8dac837a feat(config): enhance hint for agent_runner execution method in configuration 2025-11-24 14:42:36 +08:00
Soulter
e2a7a028bd feat(migration): enhance migration process with error handling and agent runner config updates 2025-11-24 14:37:25 +08:00
Soulter
70db8d264b fix(config): disable auto_save_history option in configuration 2025-11-24 14:25:14 +08:00
Soulter
0518e6d487 feat(config): add hint for agent_runner execution method in configuration 2025-11-24 14:23:53 +08:00
Soulter
39eb367866 perf: improve file structure
- Implemented CozeAPIClient for file upload, image download, chat messaging, and context management.
- Developed DashscopeAgentRunner for handling requests to the Dashscope API with streaming support.
- Created DifyAgentRunner to manage interactions with the Dify API, including file uploads and workflow execution.
- Introduced DifyAPIClient for making asynchronous requests to the Dify API.
- Updated third-party agent imports to reflect new module structure.
2025-11-24 14:00:16 +08:00
Soulter
f1d51a22ad feat(dashscope_agent_runner): refactor request payload construction and enhance streaming response handling 2025-11-24 13:21:34 +08:00
Soulter
77fb554e8f feat(dashscope_agent_runner): implement streaming response handling and request payload construction 2025-11-24 13:09:57 +08:00
Soulter
91f8a0ae09 fix(provider_manager): use get method for provider_type check in load_provider 2025-11-24 10:57:13 +08:00
Soulter
370cda7cf0 feat(dify_api_client): add docstring for file_upload method 2025-11-24 10:53:50 +08:00
Soulter
66b3eed273 fix: correct typo in agent state transition log message 2025-11-24 00:03:22 +08:00
Soulter
99b061a143 fix: make session properties required in Session interface 2025-11-23 23:25:29 +08:00
Soulter
5f3c7ed673 feat(conversation): update agent runner type configuration path to provider_settings 2025-11-23 23:05:36 +08:00
Soulter
a6dc458212 feat(third-party-agent): implement streaming response handling and enhance agent execution flow 2025-11-23 23:03:56 +08:00
Soulter
520f521887 feat(provider): enhance agent runner provider selection with subtype filtering 2025-11-23 22:23:23 +08:00
Soulter
01427d9969 feat(config): add hint for non-built-in agent execution model configuration 2025-11-23 22:13:52 +08:00
Soulter
34c03ce983 Merge remote-tracking branch 'origin/master' into feat/agent-runner 2025-11-23 22:06:52 +08:00
Soulter
95e9da42d6 fix(webchat): webchat session cannot be deleted (#3759) 2025-11-23 22:03:07 +08:00
Soulter
1338cab61b feat: add configuration selector for session management and enhance session handling in chat components 2025-11-23 21:53:56 +08:00
Soulter
7ba98c1e91 feat: enhance provider display with grouped categorization and improved filtering 2025-11-23 21:06:16 +08:00
Soulter
9a5f507cbe feat: enable agent runner providers in configuration 2025-11-23 20:58:18 +08:00
Soulter
d560671d1f feat: agent runner config migration 2025-11-23 20:54:19 +08:00
Soulter
82c9cf4db6 chore: remove legacy coze and dashscope provider 2025-11-23 20:18:51 +08:00
Soulter
910ec6c695 feat: implement third party agent sub stage and refactor provider management
- Added `ThirdPartyAgentSubStage` to handle interactions with third-party agent runners (Dify, Coze, Dashscope).
- Refactored `star_request.py` to ensure consistent return types in the `process` method.
- Updated `stage.py` to initialize and utilize the new `AgentRequestSubStage`.
- Modified `ProviderManager` to skip loading agent runner providers.
- Removed `Dify` source implementation as it is now handled by the new agent runner structure.
- Enhanced `DifyAPIClient` to support file uploads via both file path and file data.
- Cleaned up shared preferences handling to simplify session preference retrieval.
- Updated dashboard configuration to reflect changes in agent runner provider selection.
- Refactored conversation commands to accommodate the new agent runner structure and remove direct dependencies on Dify.
- Adjusted main application logic to ensure compatibility with the new conversation management approach.
2025-11-23 20:18:51 +08:00
Soulter
766d6f2bec fix(conversation): update session configuration retrieval to use unified message origin 2025-11-23 20:18:51 +08:00
Soulter
9f39140987 fix(conversation): update session configuration retrieval to use unified message origin 2025-11-23 19:59:21 +08:00
Soulter
89716ef4da Merge remote-tracking branch 'origin/master' into feat/agent-runner 2025-11-23 14:48:08 +08:00
Soulter
3c4ea5a339 chore: bump version to 4.6.1 2025-11-23 13:58:53 +08:00
Soulter
601846a8c1 docs: refine readme 2025-11-22 18:57:08 +08:00
Soulter
85d66c1056 fix(migration): update migration_done key for webchat session tracking (#3746) 2025-11-22 18:51:00 +08:00
Dt8333
b89d3f663c fix(core.db): 修复升级后webchat未正确迁移的问题 (#3745)
不是所有人都叫Astrbot

#3722
2025-11-22 18:37:39 +08:00
Soulter
0260d430d1 Merge pull request #3706 from piexian/master 2025-11-22 01:11:35 +08:00
piexian
2e608cdc09 refactor(bailian_rerank): 修复误删除并优化top_n参数处理
- 移除不合理的知识库配置读取逻辑
- 添加os模块导入(用于读取环境变量)
- 抽取辅助函数:_build_payload()、_parse_results()、_log_usage()
- 添加自定义异常类:BailianRerankError、BailianAPIError、BailianNetworkError
- 使用.get()安全访问API响应字段,避免KeyError
- 使用raise ... from e保持异常链
2025-11-21 05:34:18 +08:00
piexian
234ce93dc1 refactor(bailian_rerank): 优化代码质量和错误处理
- 移除未使用的 os 导入
- 简化 API Key 验证逻辑
- 优化 top_n 参数处理,优先使用传入值
- 改进错误处理,使用 RuntimeError 替代通用 Exception
- 添加异常链保持原始错误上下文
2025-11-21 04:07:45 +08:00
Soulter
4e2154feb7 fix(ci): repository name must be lowercase 2025-11-20 23:46:34 +08:00
Soulter
604958898c chore: bump version to 4.6.0 2025-11-20 23:41:20 +08:00
Soulter
a093f5ad0a fix(dependencies): specify upper version limit for google-genai 2025-11-20 23:32:05 +08:00
Soulter
a7e9a7f30c fix(gemini): ensure extra_content is not empty before processing 2025-11-20 23:30:19 +08:00
Soulter
5d1e9de096 Merge pull request #3678 from AstrBotDevs/refactor/webchat-session
refactor: Implement WebChat session management and migration
2025-11-20 17:23:10 +08:00
Soulter
89da4eb747 Merge branch 'master' into refactor/webchat-session 2025-11-20 17:21:48 +08:00
Soulter
8899a1dee1 feat(chat): refactor chat component structure and add new features (#3701)
- Introduced `ConversationSidebar.vue` for improved conversation management and sidebar functionality.
- Enhanced `MessageList.vue` to handle loading states and improved message rendering.
- Created new composables: `useConversations`, `useMessages`, `useMediaHandling`, `useRecording` for better code organization and reusability.
- Added loading indicators and improved user experience during message processing.
- Ensured backward compatibility and maintained existing functionalities.
2025-11-20 17:19:45 +08:00
Soulter
384a687ec3 delete: remove useConversations composable 2025-11-20 17:15:47 +08:00
Soulter
70cfdd2f8b feat(chat): refactor chat component structure and add new features (#3701)
- Introduced `ConversationSidebar.vue` for improved conversation management and sidebar functionality.
- Enhanced `MessageList.vue` to handle loading states and improved message rendering.
- Created new composables: `useConversations`, `useMessages`, `useMediaHandling`, `useRecording` for better code organization and reusability.
- Added loading indicators and improved user experience during message processing.
- Ensured backward compatibility and maintained existing functionalities.
2025-11-20 17:15:04 +08:00
Soulter
bdbd2f009a delete: useConversations 2025-11-20 17:11:01 +08:00
Soulter
164e0d26e0 feat(chat): refactor chat component structure and add new features (#3701)
- Introduced `ConversationSidebar.vue` for improved conversation management and sidebar functionality.
- Enhanced `MessageList.vue` to handle loading states and improved message rendering.
- Created new composables: `useConversations`, `useMessages`, `useMediaHandling`, `useRecording` for better code organization and reusability.
- Added loading indicators and improved user experience during message processing.
- Ensured backward compatibility and maintained existing functionalities.
2025-11-20 17:10:36 +08:00
Soulter
cb087b5ff9 refactor: update timestamp handling in session management and chat components 2025-11-20 17:02:01 +08:00
Soulter
1d3928d145 refactor(sqlite): remove auto-generation of session_id in insert method 2025-11-20 16:33:57 +08:00
Soulter
6dc3d161e7 feat(chat): refactor chat component structure and add new features (#3701)
- Introduced `ConversationSidebar.vue` for improved conversation management and sidebar functionality.
- Enhanced `MessageList.vue` to handle loading states and improved message rendering.
- Created new composables: `useConversations`, `useMessages`, `useMediaHandling`, `useRecording` for better code organization and reusability.
- Added loading indicators and improved user experience during message processing.
- Ensured backward compatibility and maintained existing functionalities.
2025-11-20 16:30:05 +08:00
Soulter
e9805ba205 fix: anyio.ClosedResourceError when calling mcp tools (#3700)
* fix: anyio.ClosedResourceError when calling mcp tools

added reconnect mechanism

fixes: 3676

* fix(mcp_client): implement thread-safe reconnection using asyncio.Lock
2025-11-20 16:24:02 +08:00
Dt8333
d5280dcd88 fix(core.platform): 修复启用多个企业微信智能机器人适配器时消息混乱的问题 (#3693)
* fix(core.platform): 修复启用多个企业微信智能机器人适配器时消息混乱的问题

移除了全局的消息队列,改为每个适配器处理自己的队列。修改相关方法适应该更改。

#3673

* chore: apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-20 16:24:02 +08:00
Dt8333
67a9663eff fix(dashboard.i18n): complete the missing i18n keys(#3699)
#3679
2025-11-20 16:24:02 +08:00
Soulter
77dd89b8eb feat: add supports for gemini-3 series thought signature (#3698)
* feat: add supports for gemini-3 series thought signature

* feat: refactor tools_call_extra_content to use a dictionary for better structure
2025-11-20 16:24:02 +08:00
Soulter
8e511bf14b fix: build docker ci failed 2025-11-20 16:24:02 +08:00
Soulter
164a4226ea feat(chat): refactor chat component structure and add new features (#3701)
- Introduced `ConversationSidebar.vue` for improved conversation management and sidebar functionality.
- Enhanced `MessageList.vue` to handle loading states and improved message rendering.
- Created new composables: `useConversations`, `useMessages`, `useMediaHandling`, `useRecording` for better code organization and reusability.
- Added loading indicators and improved user experience during message processing.
- Ensured backward compatibility and maintained existing functionalities.
2025-11-20 16:07:09 +08:00
Soulter
6d6fefc435 fix: anyio.ClosedResourceError when calling mcp tools (#3700)
* fix: anyio.ClosedResourceError when calling mcp tools

added reconnect mechanism

fixes: 3676

* fix(mcp_client): implement thread-safe reconnection using asyncio.Lock
2025-11-20 16:01:22 +08:00
Soulter
aa59532287 refactor: implement migration for WebChat sessions by creating PlatformSession records from platform_message_history 2025-11-20 15:58:27 +08:00
piexian
2ada1deb9a 修复文档返回读取问题 2025-11-20 08:31:50 +08:00
piexian
788ceb9721 添加阿里百炼重排序模型 2025-11-20 08:05:42 +08:00
Dt8333
8488c9aeab fix(core.platform): 修复启用多个企业微信智能机器人适配器时消息混乱的问题 (#3693)
* fix(core.platform): 修复启用多个企业微信智能机器人适配器时消息混乱的问题

移除了全局的消息队列,改为每个适配器处理自己的队列。修改相关方法适应该更改。

#3673

* chore: apply suggestions from code review

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-19 21:44:38 +08:00
Dt8333
676f9fd4ff fix(dashboard.i18n): complete the missing i18n keys(#3699)
#3679
2025-11-19 21:36:34 +08:00
Soulter
1935ce4700 refactor: update session handling by replacing conversation_id with session_id in chat routes and components 2025-11-19 19:54:29 +08:00
Soulter
e760956353 refactor: enhance PlatformSession migration by adding display_name from Conversations and improve session item styling 2025-11-19 19:41:57 +08:00
Soulter
be3e5f3f8b refactor: update message history deletion logic to remove newer records based on offset 2025-11-19 19:41:25 +08:00
Soulter
cdf617feac refactor: optimize WebChat session migration by batch inserting records 2025-11-19 19:16:15 +08:00
Soulter
afb56cf707 feat: add supports for gemini-3 series thought signature (#3698)
* feat: add supports for gemini-3 series thought signature

* feat: refactor tools_call_extra_content to use a dictionary for better structure
2025-11-19 18:54:56 +08:00
Soulter
cd2556ab94 fix: build docker ci failed 2025-11-19 15:40:41 +08:00
Soulter
cf4a5d9ea4 refactor: change to platform session 2025-11-18 22:37:55 +08:00
Soulter
0747099cac fix: restore migration check for version 4.7 2025-11-18 22:07:43 +08:00
Soulter
323ec29b02 refactor: Implement WebChat session management and migration from version 4.6 to 4.7
- Added WebChatSession model for managing user sessions.
- Introduced methods for creating, retrieving, updating, and deleting WebChat sessions in the database.
- Updated core lifecycle to include migration from version 4.6 to 4.7, creating WebChat sessions from existing platform message history.
- Refactored chat routes to support new session-based architecture, replacing conversation-related endpoints with session endpoints.
- Updated frontend components to handle sessions instead of conversations, including session creation and management.
2025-11-18 22:04:26 +08:00
magisk317
ae81d70685 ci(docker-build): build nightly image everyday (#3120)
* ci: build test image on master pushes

* ci: split workflows for master test and release builds

* test ci

* test ci

* Update docker-image.yml

* test ci

Updated README to enhance deployment instructions.

* Make GHCR publishing optional in Docker workflow

* chore: Update DockerHub password secret in workflow

* Update .github/workflows/docker-image.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: rename job to build nightly image in workflow

* feat: schedule the nightly build at 0:00 am everyday, if have new commits

* fix: update build-nightly-image job to trigger only on schedule events

* Update fetch-depth and enable fetch-tag in workflows

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: LIghtJUNction <lightjunction.me@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
2025-11-18 10:47:58 +08:00
RC-CHN
270c89c12f feat: Add URL document parser for knowledge base (#3622)
* feat: 添加从 URL 上传文档的功能,支持进度回调和错误处理

* feat: 添加从 URL 上传文档的前端

* chore: 添加 URL 上传功能的警告提示,确保用户配置正确

* feat: 添加内容清洗功能,支持从 URL 上传文档时的清洗设置和服务提供商选择

* feat: 更新内容清洗系统提示,增强信息提取规则;添加 URL 上传功能的测试版标识

* style: format code

* perf: 优化上传设置,增强 URL 上传时的禁用逻辑和清洗提供商验证

* refactor:使用自带chunking模块

* refactor: 提取prompt到单独文件

* feat: 添加 Tavily API Key 配置对话框,增强网页搜索功能的配置体验

* fix: update URL hint and warning messages for clarity in knowledge base upload settings

* fix: 修复设置tavily_key的热重载问题

---------

Co-authored-by: Soulter <905617992@qq.com>
2025-11-17 19:05:14 +08:00
Soulter
c7a58252fe feat: supports knowledge base agentic search (#3667)
* feat: supports knowledge base agentic search

* fix: correct formatting of system prompt in knowledge base results
2025-11-17 17:29:18 +08:00
Soulter
47ad8c86e5 docs: update translations of README 2025-11-17 12:50:01 +08:00
Soulter
937e879e5e chore: revise the issue template
Updated the bug report template to include English translations for all fields and improved clarity.
2025-11-17 11:35:24 +08:00
Soulter
1ecf26eead chore: revice pr template
Removed unnecessary comments and streamlined the pull request template.
2025-11-17 11:27:48 +08:00
Soulter
adbb84530a chore: bump version to 4.5.8 2025-11-17 09:58:02 +08:00
piexian
6cf169f4f2 fix: ImageURLPart typo (#3665)
* 修复新版本更新对不上格式的问题

entities.py生成的格式:{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}}
ImageURLPart期望的格式:{"type": "image_url", "image_url": "data:image/jpeg;base64,..."}

* Revert "修复新版本更新对不上格式的问题"

This reverts commit 28b4791391.

* fix(core.agent): 修复ImageURLPart的声明,修复pydantic校验失败的问题。

---------

Co-authored-by: piexian <piexian@users.noreply.github.com>
Co-authored-by: Dt8333 <lb0016@foxmail.com>
2025-11-17 09:52:31 +08:00
Soulter
5ab9ea12c0 chore: bump verstion to 4.5.7 2025-11-16 14:01:25 +08:00
Soulter
fd9cb703db refactor: update ToolSet initialization to use Pydantic Field and clean up deprecated methods in Context 2025-11-16 12:13:11 +08:00
Soulter
388c1ab16d fix: ensure parameter properties are correctly handled in spec_to_func 2025-11-16 11:50:58 +08:00
Soulter
f867c2a271 feat: enhance parameter type handling in LLM tool registration with JSON schema support (#3655)
* feat: enhance parameter type handling in LLM tool registration with JSON schema support

* refactor: remove debug print statement from FunctionToolManager
2025-11-16 00:55:40 +08:00
Soulter
605bb2cb90 refactor: disable debug logging for chunk delta in OpenAI provider 2025-11-15 22:29:06 +08:00
Soulter
5ea15dde5a feat: enhance LLM handsoff tool execution with system prompt and run hooks 2025-11-15 22:26:13 +08:00
Soulter
3ca545c4c7 Merge pull request #3636 from AstrBotDevs/feat/context-llm-capability
refactor: better invoke the LLM / Agent capabilities
2025-11-15 21:41:42 +08:00
Soulter
e200835074 refactor: remove unused Message import and context_model initialization in LLMRequestSubStage 2025-11-15 21:36:54 +08:00
Soulter
3a90348353 Merge branch 'master' into feat/context-llm-capability 2025-11-15 21:34:54 +08:00
Soulter
5a11d8f0ee refactor: LLM response handling with reasoning content (#3632)
* refactor: LLM response handling with reasoning content

- Added a `show_reasoning` parameter to `run_agent` to control the display of reasoning content.
- Updated `LLMResponse` to include a `reasoning_content` field for storing reasoning text.
- Modified `WebChatMessageEvent` to handle and send reasoning content in streaming responses.
- Implemented reasoning extraction in various provider sources (e.g., OpenAI, Gemini).
- Updated the chat interface to display reasoning content in a collapsible format.
- Removed the deprecated `thinking_filter` package and its associated logic.
- Updated localization files to include new reasoning-related strings.

* feat: add Groq chat completion provider and associated configurations

* Update astrbot/core/provider/sources/gemini_source.py

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-15 21:31:03 +08:00
Soulter
824af5eeea fix: Provider.meta() error (#3647)
fixes: #3643
2025-11-15 21:30:05 +08:00
Dt8333
08ec787491 fix(core.platform): make DingTalk user-ID compliant with UMO (#3634) 2025-11-15 21:30:05 +08:00
Soulter
b062e83d54 refactor: remove redundant session lock management from message sending logic in RespondStage (#3645)
fixes: #3644

Co-authored-by: Dt8333 <lb0016@foxmail.com>
2025-11-15 21:30:05 +08:00
Soulter
17422ba9c3 feat: introduce messages field in agent RunContext 2025-11-15 21:15:20 +08:00
Soulter
6849af2bad refactor: LLM response handling with reasoning content (#3632)
* refactor: LLM response handling with reasoning content

- Added a `show_reasoning` parameter to `run_agent` to control the display of reasoning content.
- Updated `LLMResponse` to include a `reasoning_content` field for storing reasoning text.
- Modified `WebChatMessageEvent` to handle and send reasoning content in streaming responses.
- Implemented reasoning extraction in various provider sources (e.g., OpenAI, Gemini).
- Updated the chat interface to display reasoning content in a collapsible format.
- Removed the deprecated `thinking_filter` package and its associated logic.
- Updated localization files to include new reasoning-related strings.

* feat: add Groq chat completion provider and associated configurations

* Update astrbot/core/provider/sources/gemini_source.py

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-15 18:59:17 +08:00
Soulter
09c3da64f9 fix: Provider.meta() error (#3647)
fixes: #3643
2025-11-15 18:01:51 +08:00
Dt8333
2c8470e8ac fix(core.platform): make DingTalk user-ID compliant with UMO (#3634) 2025-11-15 17:31:03 +08:00
Soulter
c4ea3db73d refactor: remove redundant session lock management from message sending logic in RespondStage (#3645)
fixes: #3644

Co-authored-by: Dt8333 <lb0016@foxmail.com>
2025-11-15 16:39:49 +08:00
Soulter
89e79863f6 fix: ensure image_urls and system_prompt default to empty values in ProviderRequest 2025-11-14 22:45:55 +08:00
Soulter
d19945009f refactor: decople the agent impl part and introduce some helper context method to call llm 2025-11-14 19:17:24 +08:00
Soulter
c77256ee0e feat: add id field to ProviderMetaData and update provider manager to set provider ID 2025-11-14 12:35:30 +08:00
Soulter
7d823af627 refactor: update provider metadata handling and enhance ProviderMetaData structure 2025-11-13 19:53:23 +08:00
Soulter
3957861878 refactor: streamline llm processing logic (#3607)
* refactor: streamline llm processing logic

* perf: merge-nested-ifs

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* fix: ruff format

* refactor: remove unnecessary debug logs in FunctionToolExecutor and LLMRequestSubStage

---------

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-11-13 10:08:57 +08:00
Dt8333
6ac43c600e perf: improve streaming fallback strategy for streaming-unsupported platform (#3547)
* feat: 修改tool_loop_agent_runner,新增stream_to_general属性。

Co-authored-by: aider (openai/gemini-2.5-flash-preview) <aider@aider.chat>

* refactor: 优化text_chat_stream,直接yield完整信息

Co-authored-by: aider (openai/gemini-2.5-flash-preview) <aider@aider.chat>

* feat(core):  添加streaming_fallback选项,允许进行流式请求和非流式输出

添加了streaming_fallback配置,默认为false。在PlatformMetadata中新增字段用于标识是否支持真流式输出。在LLMRequest中添加判断是否启用Fallback。

#3431 #2793 #3014

* refactor(core): 将stream_to_general移出toolLoopAgentRunner

* refactor(core.platform): 修改metadata中的属性名称

* fix: update streaming provider settings descriptions and add conditions

* fix: update streaming configuration to use unsupported_streaming_strategy and adjust related logic

* fix: remove support_streaming_message flag from WecomAIBotAdapter registration

* fix: update hint for non-streaming platform handling in configuration

* fix(core.pipeline): Update astrbot/core/pipeline/process_stage/method/llm_request.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(core.pipeline): Update astrbot/core/pipeline/process_stage/method/llm_request.py

---------

Co-authored-by: aider (openai/gemini-2.5-flash-preview) <aider@aider.chat>
Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
Co-authored-by: Soulter <905617992@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-12 18:01:20 +08:00
RC-CHN
27af9ebb6b feat: changelog display improvement
* feat: 添加旧版本changelog的modal

* style: 调整发布说明对话框的样式,移除背景颜色
2025-11-12 14:54:03 +08:00
Soulter
b360c8446e feat: add default model selection chip in provider model selector 2025-11-10 13:04:28 +08:00
Soulter
6d00717655 feat: add streaming support with toggle in chat interface and adjust layout for mobile 2025-11-09 21:57:30 +08:00
Soulter
bb5f06498e perf: refine login page 2025-11-09 20:57:45 +08:00
Dt8333
aca5743ab6 feat: 为部分适配器添加缺失的 send_streaming 方法 (#3545)
为Wechatpadpro和discord添加缺失的方法。
2025-11-09 16:00:24 +08:00
Soulter
6903032f7e fix: improve knowledge base chip display with truncation and styling (#3582)
fixes: #3546
2025-11-09 15:30:41 +08:00
nazo
1ce0ff87bd feat: supports to add custom headers for openai providers (#3581)
* feat: OPENAI系支持自定义添加请求头

* chore: add custom headers and extra body to config for zhipu

---------

Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
2025-11-09 15:12:52 +08:00
Soulter
e39d6bae0b fix: update JSON submission link in plugin publish template 2025-11-09 15:06:40 +08:00
Raven95676
8028e9e9a6 chore: bump version to 4.5.6 2025-11-07 16:20:19 +08:00
Raven95676
817f20ea01 fix: pyproject 2025-11-07 16:18:42 +08:00
Raven95676
ad5579a2f4 chore: bump version to 4.5.5 2025-11-07 15:52:58 +08:00
Raven95676
81a689a79b fix: typo 2025-11-07 15:41:14 +08:00
Raven95676
1893dd8336 fix: dockefile 2025-11-07 15:41:03 +08:00
Soulter
021ca8175b chore: bump version to 4.5.4 2025-11-07 14:28:51 +08:00
Soulter
39d6207fe1 chore: remove dynamic version 2025-11-07 14:26:56 +08:00
Soulter
23ce687229 chore: fix dockerfile 2025-11-07 14:23:49 +08:00
鸦羽
3715312fd2 fix: update project description to English (#3516) 2025-11-07 01:13:32 +08:00
Soulter
8196922cac docs: simplify README 2025-11-06 15:22:43 +08:00
Soulter
8089ad91da perf: improve extension market ui 2025-11-06 13:57:46 +08:00
Soulter
61a68477d0 stage 2025-10-21 14:19:38 +08:00
Soulter
e74f626383 stage 2025-10-21 09:55:14 +08:00
Soulter
ef99f64291 feat(config): 添加 agent 运行器类型及相关配置支持 2025-10-21 00:47:04 +08:00
1304 changed files with 207426 additions and 27241 deletions

View File

@@ -1,6 +1,7 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# github actions
.git
.github/
.*ignore
# User-specific stuff
@@ -16,7 +17,7 @@ ENV/
.conda/
dashboard/
data/
changelogs/
tests/
.ruff_cache/
.astrbot
.astrbot
astrbot.lock

184
.env.example Normal file
View File

@@ -0,0 +1,184 @@
# ==========================================
# AstrBot Instance Configuration: ${INSTANCE_NAME}
# AstrBot 实例配置文件:${INSTANCE_NAME}
# ==========================================
# 将此文件复制为 .env 并根据需要修改。
# Copy this file to .env and modify as needed.
# 注意:在此处设置的变量将覆盖默认配置。
# Note: Variables set here override application defaults.
# ------------------------------------------
# 实例标识 / Instance Identity
# ------------------------------------------
# 实例名称(用于日志和服务名)
# Instance name (used in logs/service names)
INSTANCE_NAME="${INSTANCE_NAME}"
# ------------------------------------------
# 核心配置 / Core Configuration
# ------------------------------------------
# AstrBot 根目录路径
# AstrBot root directory path
# 默认 Default: 当前工作目录,桌面客户端为 ~/.astrbot服务器为 /var/lib/astrbot/<instance>/
# 示例 Example: /var/lib/astrbot/mybot
ASTRBOT_ROOT="${ASTRBOT_ROOT}"
# 日志等级
# Log level
# 可选值 Values: DEBUG, INFO, WARNING, ERROR, CRITICAL
# 默认 Default: INFO
# ASTRBOT_LOG_LEVEL=INFO
# 启用插件热重载(开发时有用)
# Enable plugin hot reload (useful for development)
# 可选值 Values: 0 (禁用 disabled), 1 (启用 enabled)
# 默认 Default: 0
# ASTRBOT_RELOAD=0
# 禁用匿名使用统计
# Disable anonymous usage statistics
# 可选值 Values: 0 (启用统计 enabled), 1 (禁用统计 disabled)
# 默认 Default: 0
ASTRBOT_DISABLE_METRICS=0
# 覆盖 Python 可执行文件路径(用于本地代码执行功能)
# Override Python executable path (for local code execution)
# 示例 Example: /usr/bin/python3, /home/user/.pyenv/shims/python
# PYTHON=/usr/bin/python3
# 启用演示模式(可能限制部分功能)
# Enable demo mode (may restrict certain features)
# 可选值 Values: True, False
# 默认 Default: False
# DEMO_MODE=False
# 启用测试模式(影响日志和部分行为)
# Enable testing mode (affects logging and behavior)
# 可选值 Values: True, False
# 默认 Default: False
# TESTING=False
# 标记:是否通过桌面客户端执行(主要用于内部)
# Flag: running via desktop client (internal use)
# 可选值 Values: 0, 1
# ASTRBOT_DESKTOP_CLIENT=0
# 标记:是否通过 systemd 服务执行
# Flag: running via systemd service
# 可选值 Values: 0, 1
ASTRBOT_SYSTEMD=1
# ------------------------------------------
# 管理面板配置 / Dashboard Configuration
# ------------------------------------------
# 启用或禁用 WebUI 管理面板
# Enable or disable WebUI dashboard
# 可选值 Values: True, False
# 默认 Default: True
ASTRBOT_DASHBOARD_ENABLE=True
# ------------------------------------------
# 国际化配置 / Internationalization Configuration
# ------------------------------------------
# CLI 界面语言
# CLI interface language
# 可选值 Values: zh (中文), en (英文)
# 默认 Default: zh (跟随系统 locale / follows system locale)
# ASTRBOT_CLI_LANG=zh
# TUI 界面语言
# TUI interface language
# 可选值 Values: zh (中文), en (英文)
# 默认 Default: zh
# ASTRBOT_TUI_LANG=zh
# ------------------------------------------
# 网络配置 / Network Configuration
# ------------------------------------------
# API 绑定主机
# API bind host
# 示例 Example: 0.0.0.0 (所有接口 all interfaces), 127.0.0.1 (仅本地 localhost only)
ASTRBOT_HOST="${ASTRBOT_HOST}"
# API 绑定端口
# API bind port
# 示例 Example: 3000, 6185, 8080
ASTRBOT_PORT="${ASTRBOT_PORT}"
# 是否为 API 启用 SSL/TLS
# Enable SSL/TLS for API
# 可选值 Values: true, false
# 默认 Default: false
ASTRBOT_SSL_ENABLE=false
# SSL 证书路径PEM 格式)
# SSL certificate path (PEM format)
# 示例 Example: /etc/astrbot/certs/myinstance/fullchain.pem
ASTRBOT_SSL_CERT=""
# SSL 私钥路径PEM 格式)
# SSL private key path (PEM format)
# 示例 Example: /etc/astrbot/certs/myinstance/privkey.pem
ASTRBOT_SSL_KEY=""
# SSL CA 证书链路径(可选,用于客户端验证)
# SSL CA certificates bundle (optional, for client verification)
# 示例 Example: /etc/ssl/certs/ca-certificates.crt
ASTRBOT_SSL_CA_CERTS=""
# ------------------------------------------
# 代理配置 / Proxy Configuration
# ------------------------------------------
# HTTP 代理地址
# HTTP proxy URL
# 示例 Example: http://127.0.0.1:7890, socks5://127.0.0.1:1080
# http_proxy=
# HTTPS 代理地址
# HTTPS proxy URL
# 示例 Example: http://127.0.0.1:7890, socks5://127.0.0.1:1080
# https_proxy=
# 不走代理的主机列表(逗号分隔)
# Hosts to bypass proxy (comma-separated)
# 示例 Example: localhost,127.0.0.1,192.168.0.0/16,.local
# no_proxy=localhost,127.0.0.1
# ------------------------------------------
# 第三方集成 / Third-party Integrations
# ------------------------------------------
# 阿里云 DashScope API 密钥(用于 Rerank 服务)
# Alibaba DashScope API Key (for Rerank service)
# 获取地址 Get from: https://dashscope.console.aliyun.com/
# 示例 Example: sk-xxxxxxxxxxxx
# DASHSCOPE_API_KEY=
# Coze 集成
# Coze integration
# 获取地址 Get from: https://www.coze.com/
# COZE_API_KEY=
# COZE_BOT_ID=
# 计算机控制相关的数据目录(用于截图/文件存储)
# Computer control data directory (for screenshots/file storage)
# 示例 Example: /var/lib/astrbot/bay_data
# BAY_DATA_DIR=
# ------------------------------------------
# 平台特定配置 / Platform-specific Configuration
# ------------------------------------------
# QQ 官方机器人测试模式开关
# QQ official bot test mode
# 可选值 Values: on, off
# 默认 Default: off
# TEST_MODE=off
# End of template / 模板结束

2
.envrc Normal file
View File

@@ -0,0 +1,2 @@
git pull
git status

View File

@@ -16,7 +16,7 @@ body:
请将插件信息填写到下方的 JSON 代码块中。其中 `tags`(插件标签)和 `social_link`(社交链接)选填。
不熟悉 JSON ?可以从 [此](https://plugins.astrbot.app/submit) 生成 JSON ,生成后记得复制粘贴过来.
不熟悉 JSON ?可以从 [此](https://plugins.astrbot.app) 右下角提交。
- type: textarea
id: plugin-info

View File

@@ -1,46 +1,44 @@
name: '🐛 报告 Bug'
name: '🐛 Report Bug / 报告 Bug'
title: '[Bug]'
description: 提交报告帮助我们改进。
description: Submit bug report to help us improve. / 提交报告帮助我们改进。
labels: [ 'bug' ]
body:
- type: markdown
attributes:
value: |
感谢您抽出时间报告问题!请准确解释您的问题。如果可能,请提供一个可复现的片段(这有助于更快地解决问题)。请注意,不详细 / 没有日志的 issue 会被直接关闭,谢谢理解。
Thank you for taking the time to report this issue! Please describe your problem accurately. If possible, please provide a reproducible snippet (this will help resolve the issue more quickly). Please note that issues that are not detailed or have no logs will be closed immediately. Thank you for your understanding. / 感谢您抽出时间报告问题!请准确解释您的问题。如果可能,请提供一个可复现的片段(这有助于更快地解决问题)。请注意,不详细 / 没有日志的 issue 会被直接关闭,谢谢理解。
- type: textarea
attributes:
label: 发生了什么
description: 描述你遇到的异常
label: What happened / 发生了什么
description: Description
placeholder: >
一个清晰且具体的描述这个异常是什么。请注意,不详细 / 没有日志的 issue 会被直接关闭,谢谢理解。
Please provide a clear and specific description of what this exception is. Please note that issues that are not detailed or have no logs will be closed immediately. Thank you for your understanding. / 一个清晰且具体的描述这个异常是什么。请注意,不详细 / 没有日志的 issue 会被直接关闭,谢谢理解。
validations:
required: true
- type: textarea
attributes:
label: 如何复现?
label: Reproduce / 如何复现?
description: >
复现该问题的步骤
The steps to reproduce the issue. / 复现该问题的步骤
placeholder: >
: 1. 打开 '...'
Example: 1. Open '...'
validations:
required: true
- type: textarea
attributes:
label: AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
description: >
请提供您的 AstrBot 版本和部署方式。
label: AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
placeholder: >
如: 3.1.8 Docker, 3.1.7 Windows启动器
Example: 4.5.7 Docker, 3.1.7 Windows Launcher
validations:
required: true
- type: dropdown
attributes:
label: 操作系统
label: OS
description: |
你在哪个操作系统上遇到了这个问题?
On which operating system did you encounter this problem? / 你在哪个操作系统上遇到了这个问题?
multiple: false
options:
- 'Windows'
@@ -53,30 +51,30 @@ body:
- type: textarea
attributes:
label: 报错日志
label: Logs / 报错日志
description: >
如报错日志、截图等。请提供完整的 Debug 级别的日志,不要介意它很长!请注意,不详细 / 没有日志的 issue 会被直接关闭,谢谢理解。
Please provide complete Debug-level logs, such as error logs and screenshots. Don't worry if they're long! Please note that issues with insufficient details or no logs will be closed immediately. Thank you for your understanding. / 如报错日志、截图等。请提供完整的 Debug 级别的日志,不要介意它很长!请注意,不详细 / 没有日志的 issue 会被直接关闭,谢谢理解。
placeholder: >
请提供完整的报错日志或截图。
Please provide a complete error log or screenshot. / 请提供完整的报错日志或截图。
validations:
required: true
- type: checkboxes
attributes:
label: 你愿意提交 PR 吗?
label: Are you willing to submit a PR? / 你愿意提交 PR 吗?
description: >
这不是必需的,但我们很乐意在贡献过程中为您提供指导特别是如果你已经很好地理解了如何实现修复。
This is not required, but we would be happy to provide guidance during the contribution process, especially if you already have a good understanding of how to implement the fix. / 这不是必需的,但我们很乐意在贡献过程中为您提供指导特别是如果你已经很好地理解了如何实现修复。
options:
- label: 是的,我愿意提交 PR!
- label: Yes!
- type: checkboxes
attributes:
label: Code of Conduct
options:
- label: >
我已阅读并同意遵守该项目的 [行为准则](https://docs.github.com/zh/site-policy/github-terms/github-community-code-of-conduct)。
I have read and agree to abide by the project's [Code of Conduct](https://docs.github.com/zh/site-policy/github-terms/github-community-code-of-conduct)。
required: true
- type: markdown
attributes:
value: "感谢您填写我们的表单!"
value: "Thank you for filling out our form! / 感谢您填写我们的表单!"

View File

@@ -1,42 +1,40 @@
name: '🎉 功能建议'
name: '🎉 Feature Request / 功能建议'
title: "[Feature]"
description: 提交建议帮助我们改进。
description: Submit a suggestion to help us improve. / 提交建议帮助我们改进。
labels: [ "enhancement" ]
body:
- type: markdown
attributes:
value: |
感谢您抽出时间提出新功能建议,请准确解释您的想法。
Thank you for taking the time to suggest a new feature! Please explain your idea clearly and accurately. / 感谢您抽出时间提出新功能建议,请准确解释您的想法。
- type: textarea
attributes:
label: 描述
description: 简短描述您的功能建议
label: Description / 描述
description: Please describe the feature you want to be added in detail. / 请详细描述您希望添加的功能。
- type: textarea
attributes:
label: 使用场景
description: 你想要发生什么?
placeholder: >
一个清晰且具体的描述这个功能的使用场景。
label: Use Case / 使用场景
description: Please describe the use case for this feature. / 请描述这个功能的使用场景。
- type: checkboxes
attributes:
label: 愿意提交PR吗?
label: Willing to Submit PR? / 是否愿意提交PR
description: >
这不是必的,但我们欢迎您的贡献。
This is not required, but if you are willing to submit a PR to implement this feature, it would be greatly appreciated! / 这不是必的,但如果您愿意提交 PR 来实现这个功能,我们将不胜感激!
options:
- label: 是的, 我愿意提交PR!
- label: Yes, I am willing to submit a PR. / 是的,我愿意提交 PR
- type: checkboxes
attributes:
label: Code of Conduct
options:
- label: >
我已阅读并同意遵守该项目的 [行为准则](https://docs.github.com/zh/site-policy/github-terms/github-community-code-of-conduct)
I have read and agree to abide by the project's [Code of Conduct](https://docs.github.com/zh/site-policy/github-terms/github-community-code-of-conduct). /
required: true
- type: markdown
attributes:
value: "感谢您填写我们的表单!"
value: "Thank you for filling out our form!"

View File

@@ -1,46 +1,34 @@
<!-- 如果有的话,请指定此 PR 旨在解决的 ISSUE 编号。 -->
<!-- If applicable, please specify the ISSUE number this PR aims to resolve. -->
fixes #XYZ
---
### Motivation / 动机
<!--请描述此项更改的动机:它解决了什么问题?(例如:修复了 XX 错误,添加了 YY 功能)-->
<!--Please describe the motivation for this change: What problem does it solve? (e.g., Fixes XX bug, adds YY feature)-->
<!--Please describe the motivation for this change: What problem does it solve? (e.g., Fixes XX issue, adds YY feature)-->
<!--请描述此项更改的动机:它解决了什么问题?(例如:修复了 XX issue添加了 YY 功能)-->
### Modifications / 改动点
<!--请总结你的改动:哪些核心文件被修改了?实现了什么功能?-->
<!--Please summarize your changes: What core files were modified? What functionality was implemented?-->
<!--请总结你的改动:哪些核心文件被修改了?实现了什么功能?-->
### Verification Steps / 验证步骤
<!--请为审查者 (Reviewer) 提供清晰、可复现的验证步骤例如1. 导航到... 2. 点击...)。-->
<!--Please provide clear and reproducible verification steps for the Reviewer (e.g., 1. Navigate to... 2. Click...).-->
- [x] This is NOT a breaking change. / 这不是一个破坏性变更。
<!-- If your changes is a breaking change, please uncheck the checkbox above -->
### Screenshots or Test Results / 运行截图或测试结果
<!--请粘贴截图、GIF 或测试日志,作为执行“验证步骤”的证据,证明此改动有效。-->
<!--Please paste screenshots, GIFs, or test logs here as evidence of executing the "Verification Steps" to prove this change is effective.-->
### Compatibility & Breaking Changes / 兼容性与破坏性变更
<!--请说明此变更的兼容性:哪些是破坏性变更?哪些地方做了向后兼容处理?是否提供了数据迁移方法?-->
<!--Please explain the compatibility of this change: What are the breaking changes? What backward-compatible measures were taken? Are data migration paths provided?-->
- [ ] 这是一个破坏性变更 (Breaking Change)。/ This is a breaking change.
- [ ] 这不是一个破坏性变更。/ This is NOT a breaking change.
<!--请粘贴截图、GIF 或测试日志,作为执行“验证步骤”的证据,证明此改动有效。-->
---
### Checklist / 检查清单
<!--如果分支被合并,您的代码将服务于数万名用户!在提交前,请核查一下几点内容。-->
<!--If merged, your code will serve tens of thousands of users! Please double-check the following items before submitting.-->
<!--如果分支被合并,您的代码将服务于数万名用户!在提交前,请核查一下几点内容。-->
- [ ] 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
- [ ] 👀 我的更改经过了良好的测试,**并已在上方提供了“验证步骤”和“运行截图”**。/ My changes have been well-tested, **and "Verification Steps" and "Screenshots" have been provided above**.
- [ ] 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 `requirements.txt``pyproject.toml` 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in `requirements.txt` and `pyproject.toml`.
- [ ] 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.
- [ ] 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
- [ ] 👀 My changes have been well-tested, **and "Verification Steps" and "Screenshots" have been provided above**.
/ 我的更改经过了良好的测试,**并已在上方提供了“验证步骤”和“运行截图”**。
- [ ] 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in `requirements.txt` and `pyproject.toml`.
/ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 `requirements.txt``pyproject.toml` 文件相应位置。
- [ ] 😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。

View File

@@ -15,7 +15,6 @@ Always reference these instructions first and fallback to search or bash command
### Running the Application
- Run main application: `uv run main.py` -- starts in ~3 seconds
- Application creates WebUI on http://localhost:6185 (default credentials: `astrbot`/`astrbot`)
- Application loads plugins automatically from `packages/` and `data/plugins/` directories
### Dashboard Build (Vue.js/Node.js)
- **Prerequisites**: Node.js 20+ and npm 10+ required
@@ -35,7 +34,7 @@ Always reference these instructions first and fallback to search or bash command
- **ALWAYS** run `uv run ruff check .` and `uv run ruff format .` before committing changes
### Plugin Development
- Plugins load from `packages/` (built-in) and `data/plugins/` (user-installed)
- Plugins load from `astrbot/builtin_stars/` (built-in) and `data/plugins/` (user-installed)
- Plugin system supports function tools and message handlers
- Key plugins: python_interpreter, web_searcher, astrbot, reminder, session_controller

View File

@@ -1,92 +0,0 @@
on:
push:
tags:
- 'v*'
workflow_dispatch:
name: Auto Release
jobs:
build-and-publish-to-github-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Dashboard Build
run: |
cd dashboard
npm install
npm run build
echo "COMMIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
echo ${{ github.ref_name }} > dist/assets/version
zip -r dist.zip dist
- name: Upload to Cloudflare R2
env:
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
R2_BUCKET_NAME: "astrbot"
R2_OBJECT_NAME: "astrbot-webui-latest.zip"
VERSION_TAG: ${{ github.ref_name }}
run: |
echo "Installing rclone..."
curl https://rclone.org/install.sh | sudo bash
echo "Configuring rclone remote..."
mkdir -p ~/.config/rclone
cat <<EOF > ~/.config/rclone/rclone.conf
[r2]
type = s3
provider = Cloudflare
access_key_id = $R2_ACCESS_KEY_ID
secret_access_key = $R2_SECRET_ACCESS_KEY
endpoint = https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
EOF
echo "Uploading dist.zip to R2 bucket: $R2_BUCKET_NAME/$R2_OBJECT_NAME"
mv dashboard/dist.zip dashboard/$R2_OBJECT_NAME
rclone copy dashboard/$R2_OBJECT_NAME r2:$R2_BUCKET_NAME --progress
mv dashboard/$R2_OBJECT_NAME dashboard/astrbot-webui-${VERSION_TAG}.zip
rclone copy dashboard/astrbot-webui-${VERSION_TAG}.zip r2:$R2_BUCKET_NAME --progress
mv dashboard/astrbot-webui-${VERSION_TAG}.zip dashboard/dist.zip
- name: Fetch Changelog
run: |
echo "changelog=changelogs/${{github.ref_name}}.md" >> "$GITHUB_ENV"
- name: Create GitHub Release
uses: ncipollo/release-action@v1
with:
bodyFile: ${{ env.changelog }}
artifacts: "dashboard/dist.zip"
build-and-publish-to-pypi:
# 构建并发布到 PyPI
runs-on: ubuntu-latest
needs: build-and-publish-to-github-release
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'
- name: Install uv
run: |
python -m pip install uv
- name: Build package
run: |
uv build
- name: Publish to PyPI
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
run: |
uv publish

43
.github/workflows/build-docs.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: release
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest # 运行环境
steps:
- name: checkout
uses: actions/checkout@v6
- name: nodejs installation
uses: actions/setup-node@v6
with:
node-version: "18"
- name: npm install
run: npm add -D vitepress
working-directory: './docs' # working-directory 指定 shell 命令运行目录
- name: npm run build
run: npm run docs:build
working-directory: './docs'
- name: scp
uses: appleboy/scp-action@v1.0.0
with:
host: ${{ secrets.HOST_NEKO }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORDNEKO }}
source: 'docs/.vitepress/dist/*'
target: '/tmp/'
- name: script
uses: appleboy/ssh-action@v1.2.5
with:
host: ${{ secrets.HOST_NEKO }}
username: ${{ secrets.USERNAME }}
password: ${{ secrets.PASSWORDNEKO }}
script: |
mkdir -p /root/docker_data/caddy/caddy_data/static_site/abv4/
rm -rf /root/docker_data/caddy/caddy_data/static_site/abv4/*
mv /tmp/docs/.vitepress/dist/* /root/docker_data/caddy/caddy_data/static_site/abv4/
rm -rf /tmp/docs/

View File

@@ -12,12 +12,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'
python-version: '3.12'
- name: Install UV
run: pip install uv

View File

@@ -56,7 +56,7 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -37,9 +37,10 @@ jobs:
mkdir -p data/temp
export TESTING=true
export ZHIPU_API_KEY=${{ secrets.OPENAI_API_KEY }}
pytest --cov=. -v -o log_cli=true -o log_level=DEBUG
pytest --cov=astrbot -v -o log_cli=true -o log_level=DEBUG
- name: Upload results to Codecov
if: github.repository == 'AstrBotDevs/AstrBot'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -8,15 +8,16 @@ on:
jobs:
build:
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 'latest'
node-version: '24.13.0'
- name: npm install, build
run: |
@@ -36,7 +37,7 @@ jobs:
zip -r dist.zip dist
- name: Archive production artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: dist-without-markdown
path: |
@@ -45,11 +46,11 @@ jobs:
- name: Create GitHub Release
if: github.event_name == 'push'
uses: ncipollo/release-action@v1
uses: ncipollo/release-action@v1.21.0
with:
tag: release-${{ github.sha }}
owner: AstrBotDevs
repo: astrbot-release-harbour
body: "Automated release from commit ${{ github.sha }}"
token: ${{ secrets.ASTRBOT_HARBOUR_TOKEN }}
artifacts: "dashboard/dist.zip"
artifacts: "dashboard/dist.zip"

View File

@@ -3,18 +3,125 @@ name: Docker Image CI/CD
on:
push:
tags:
- 'v*'
- "v*"
schedule:
# Run at 00:00 UTC every day
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
publish-docker:
build-nightly-image:
if: github.repository == 'AstrBotDevs/AstrBot' && github.event_name == 'schedule'
runs-on: ubuntu-latest
env:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
GHCR_OWNER: astrbotdevs
HAS_GHCR_TOKEN: ${{ secrets.GHCR_GITHUB_TOKEN != '' }}
steps:
- name: Pull The Codes
uses: actions/checkout@v5
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0 # Must be 0 so we can fetch tags
fetch-depth: 1
fetch-tag: true
- name: Check for new commits today
if: github.event_name == 'schedule'
id: check-commits
run: |
# Get commits from the last 24 hours
commits=$(git log --since="24 hours ago" --oneline)
if [ -z "$commits" ]; then
echo "No commits in the last 24 hours, skipping build"
echo "has_commits=false" >> $GITHUB_OUTPUT
else
echo "Found commits in the last 24 hours:"
echo "$commits"
echo "has_commits=true" >> $GITHUB_OUTPUT
fi
- name: Exit if no commits
if: github.event_name == 'schedule' && steps.check-commits.outputs.has_commits == 'false'
run: exit 0
- name: Build Dashboard
run: |
cd dashboard
npm install
npm run build
mkdir -p dist/assets
echo $(git rev-parse HEAD) > dist/assets/version
cd ..
mkdir -p data
cp -r dashboard/dist data/
- name: Determine test image tags
id: test-meta
run: |
short_sha=$(echo "${GITHUB_SHA}" | cut -c1-12)
build_date=$(date +%Y%m%d)
echo "short_sha=$short_sha" >> $GITHUB_OUTPUT
echo "build_date=$build_date" >> $GITHUB_OUTPUT
- name: Set QEMU
uses: docker/setup-qemu-action@v4.0.0
- name: Set Docker Buildx
uses: docker/setup-buildx-action@v4.0.0
- name: Log in to DockerHub
uses: docker/login-action@v4.0.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Login to GitHub Container Registry
if: env.HAS_GHCR_TOKEN == 'true'
uses: docker/login-action@v4.0.0
with:
registry: ghcr.io
username: ${{ env.GHCR_OWNER }}
password: ${{ secrets.GHCR_GITHUB_TOKEN }}
- name: Build nightly image tags list
id: test-tags
run: |
TAGS="${{ env.DOCKER_HUB_USERNAME }}/astrbot:nightly-latest
${{ env.DOCKER_HUB_USERNAME }}/astrbot:nightly-${{ steps.test-meta.outputs.build_date }}-${{ steps.test-meta.outputs.short_sha }}"
if [ "${{ env.HAS_GHCR_TOKEN }}" = "true" ]; then
TAGS="$TAGS
ghcr.io/${{ env.GHCR_OWNER }}/astrbot:nightly-latest
ghcr.io/${{ env.GHCR_OWNER }}/astrbot:nightly-${{ steps.test-meta.outputs.build_date }}-${{ steps.test-meta.outputs.short_sha }}"
fi
echo "tags<<EOF" >> $GITHUB_OUTPUT
echo "$TAGS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Build and Push Nightly Image
uses: docker/build-push-action@v7.0.0
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.test-tags.outputs.tags }}
- name: Post build notifications
run: echo "Test Docker image has been built and pushed successfully"
build-release-image:
if: github.repository == 'AstrBotDevs/AstrBot' && (github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')))
runs-on: ubuntu-latest
env:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
GHCR_OWNER: astrbotdevs
HAS_GHCR_TOKEN: ${{ secrets.GHCR_GITHUB_TOKEN != '' }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-tag: true
- name: Get latest tag (only on manual trigger)
id: get-latest-tag
@@ -27,21 +134,22 @@ jobs:
if: github.event_name == 'workflow_dispatch'
run: git checkout ${{ steps.get-latest-tag.outputs.latest_tag }}
- name: Check if version is pre-release
id: check-prerelease
- name: Compute release metadata
id: release-meta
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
version="${{ steps.get-latest-tag.outputs.latest_tag }}"
else
version="${{ github.ref_name }}"
version="${GITHUB_REF#refs/tags/}"
fi
if [[ "$version" == *"beta"* ]] || [[ "$version" == *"alpha"* ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "Version $version is a pre-release, will not push latest tag"
echo "Version $version marked as pre-release"
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "Version $version is a stable release, will push latest tag"
echo "Version $version marked as stable"
fi
echo "version=$version" >> $GITHUB_OUTPUT
- name: Build Dashboard
run: |
@@ -55,35 +163,36 @@ jobs:
cp -r dashboard/dist data/
- name: Set QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4.0.0
- name: Set Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4.0.0
- name: Log in to DockerHub
uses: docker/login-action@v3
uses: docker/login-action@v4.0.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
if: env.HAS_GHCR_TOKEN == 'true'
uses: docker/login-action@v4.0.0
with:
registry: ghcr.io
username: Soulter
username: ${{ env.GHCR_OWNER }}
password: ${{ secrets.GHCR_GITHUB_TOKEN }}
- name: Build and Push Docker to DockerHub and Github GHCR
uses: docker/build-push-action@v6
- name: Build and Push Release Image
uses: docker/build-push-action@v7.0.0
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ steps.check-prerelease.outputs.is_prerelease == 'false' && format('{0}/astrbot:latest', secrets.DOCKER_HUB_USERNAME) || '' }}
${{ secrets.DOCKER_HUB_USERNAME }}/astrbot:${{ github.event_name == 'workflow_dispatch' && steps.get-latest-tag.outputs.latest_tag || github.ref_name }}
${{ steps.check-prerelease.outputs.is_prerelease == 'false' && 'ghcr.io/soulter/astrbot:latest' || '' }}
ghcr.io/soulter/astrbot:${{ github.event_name == 'workflow_dispatch' && steps.get-latest-tag.outputs.latest_tag || github.ref_name }}
${{ steps.release-meta.outputs.is_prerelease == 'false' && format('{0}/astrbot:latest', env.DOCKER_HUB_USERNAME) || '' }}
${{ steps.release-meta.outputs.is_prerelease == 'false' && env.HAS_GHCR_TOKEN == 'true' && format('ghcr.io/{0}/astrbot:latest', env.GHCR_OWNER) || '' }}
${{ format('{0}/astrbot:{1}', env.DOCKER_HUB_USERNAME, steps.release-meta.outputs.version) }}
${{ env.HAS_GHCR_TOKEN == 'true' && format('ghcr.io/{0}/astrbot:{1}', env.GHCR_OWNER, steps.release-meta.outputs.version) || '' }}
- name: Post build notifications
run: echo "Docker image has been built and pushed successfully"
run: echo "Release Docker image has been built and pushed successfully"

54
.github/workflows/pr-title-check.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: PR Title Check
on:
pull_request_target:
types: [opened, edited, reopened, synchronize]
jobs:
title-format:
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-latest
permissions:
pull-requests: write
issues: write
steps:
- name: Validate PR title
uses: actions/github-script@v8
with:
script: |
const title = (context.payload.pull_request.title || "").trim();
// allow only:
// feat: xxx
// feat(scope): xxx
const pattern = /^(feat)(\([a-z0-9-]+\))?:\s.+$/i;
const isValid = pattern.test(title);
const isSameRepo =
context.payload.pull_request.head.repo.full_name === context.payload.repository.full_name;
if (!isValid) {
if (isSameRepo) {
try {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: [
"⚠️ PR title format check failed.",
"Required formats:",
"- `feat: xxx`",
"- `feat(scope): xxx`",
"Please update your PR title and push again."
].join("\n")
});
} catch (e) {
core.warning(`Failed to post PR title comment: ${e.message}`);
}
} else {
core.warning("Fork PR: comment permission is restricted; skip posting review comment.");
}
}
if (!isValid) {
core.setFailed("Invalid PR title. Expected format: feat: xxx or feat(scope): xxx.");
}

248
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,248 @@
name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
ref:
description: "Git ref to build (branch/tag/SHA)"
required: false
default: "master"
tag:
description: "Release tag to publish assets to (for example: v4.14.6)"
required: false
permissions:
contents: write
jobs:
build-dashboard:
name: Build Dashboard
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-24.04
env:
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.ref || github.ref }}
- name: Resolve tag
id: tag
shell: bash
run: |
if [ "${{ github.event_name }}" = "push" ]; then
tag="${GITHUB_REF_NAME}"
elif [ -n "${{ inputs.tag }}" ]; then
tag="${{ inputs.tag }}"
else
tag="$(git describe --tags --abbrev=0)"
fi
if [ -z "$tag" ]; then
echo "Failed to resolve tag." >&2
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Setup pnpm
uses: pnpm/action-setup@v5.0.0
with:
version: 10.28.2
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '24.13.0'
cache: "pnpm"
cache-dependency-path: dashboard/pnpm-lock.yaml
- name: Build dashboard dist
shell: bash
run: |
pnpm --dir dashboard install --frozen-lockfile
pnpm --dir dashboard run build
echo "${{ steps.tag.outputs.tag }}" > dashboard/dist/assets/version
cd dashboard
zip -r "AstrBot-${{ steps.tag.outputs.tag }}-dashboard.zip" dist
- name: Upload dashboard artifact
uses: actions/upload-artifact@v7
with:
name: Dashboard-${{ steps.tag.outputs.tag }}
if-no-files-found: error
path: dashboard/AstrBot-${{ steps.tag.outputs.tag }}-dashboard.zip
- name: Upload dashboard package to Cloudflare R2
if: ${{ env.R2_ACCOUNT_ID != '' && env.R2_ACCESS_KEY_ID != '' && env.R2_SECRET_ACCESS_KEY != '' }}
env:
R2_BUCKET_NAME: "astrbot"
R2_OBJECT_NAME: "astrbot-webui-latest.zip"
VERSION_TAG: ${{ steps.tag.outputs.tag }}
shell: bash
run: |
curl https://rclone.org/install.sh | sudo bash
mkdir -p ~/.config/rclone
cat <<EOF > ~/.config/rclone/rclone.conf
[r2]
type = s3
provider = Cloudflare
access_key_id = $R2_ACCESS_KEY_ID
secret_access_key = $R2_SECRET_ACCESS_KEY
endpoint = https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com
EOF
cp "dashboard/AstrBot-${VERSION_TAG}-dashboard.zip" "dashboard/${R2_OBJECT_NAME}"
rclone copy "dashboard/${R2_OBJECT_NAME}" "r2:${R2_BUCKET_NAME}" --progress
cp "dashboard/AstrBot-${VERSION_TAG}-dashboard.zip" "dashboard/astrbot-webui-${VERSION_TAG}.zip"
rclone copy "dashboard/astrbot-webui-${VERSION_TAG}.zip" "r2:${R2_BUCKET_NAME}" --progress
publish-release:
name: Publish GitHub Release
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-24.04
needs:
- build-dashboard
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.ref || github.ref }}
- name: Resolve tag
id: tag
shell: bash
run: |
if [ "${{ github.event_name }}" = "push" ]; then
tag="${GITHUB_REF_NAME}"
elif [ -n "${{ inputs.tag }}" ]; then
tag="${{ inputs.tag }}"
else
tag="$(git describe --tags --abbrev=0)"
fi
if [ -z "$tag" ]; then
echo "Failed to resolve tag." >&2
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Download dashboard artifact
uses: actions/download-artifact@v8
with:
name: Dashboard-${{ steps.tag.outputs.tag }}
path: release-assets
- name: Resolve release notes
id: notes
shell: bash
run: |
note_file="changelogs/${{ steps.tag.outputs.tag }}.md"
if [ ! -f "$note_file" ]; then
note_file="$(mktemp)"
echo "Release ${{ steps.tag.outputs.tag }}" > "$note_file"
fi
echo "file=$note_file" >> "$GITHUB_OUTPUT"
- name: Ensure release exists
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
tag="${{ steps.tag.outputs.tag }}"
if ! gh release view "$tag" >/dev/null 2>&1; then
gh release create "$tag" --title "$tag" --notes-file "${{ steps.notes.outputs.file }}"
fi
- name: Remove stale assets from release
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
tag="${{ steps.tag.outputs.tag }}"
while IFS= read -r asset; do
case "$asset" in
*.AppImage|*.dmg|*.zip|*.exe|*.blockmap)
gh release delete-asset "$tag" "$asset" -y || true
;;
esac
done < <(gh release view "$tag" --json assets --jq '.assets[].name')
- name: Upload assets to release
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
tag="${{ steps.tag.outputs.tag }}"
gh release upload "$tag" release-assets/* --clobber
publish-pypi:
name: Publish PyPI
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-24.04
needs:
- publish-release
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.ref || github.ref }}
- name: Resolve tag
id: tag
shell: bash
run: |
if [ "${{ github.event_name }}" = "push" ]; then
tag="${GITHUB_REF_NAME}"
elif [ -n "${{ inputs.tag }}" ]; then
tag="${{ inputs.tag }}"
else
tag="$(git describe --tags --abbrev=0)"
fi
if [ -z "$tag" ]; then
echo "Failed to resolve tag." >&2
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Download dashboard artifact
uses: actions/download-artifact@v8
with:
name: Dashboard-${{ steps.tag.outputs.tag }}
path: dashboard-artifact
- name: Unpack dashboard dist into package tree
shell: bash
run: |
mkdir -p astrbot/dashboard/dist
unzip -q "dashboard-artifact/AstrBot-${{ steps.tag.outputs.tag }}-dashboard.zip" -d dashboard-artifact/unpacked
cp -r dashboard-artifact/unpacked/dist/. astrbot/dashboard/dist/
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
- name: Install uv
shell: bash
run: python -m pip install uv
- name: Build package
shell: bash
# Dashboard assets are already in astrbot/dashboard/dist/;
# ASTRBOT_BUILD_DASHBOARD is intentionally unset so the hatch hook skips npm.
run: uv build
- name: Publish to PyPI
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
shell: bash
run: uv publish

61
.github/workflows/smoke_test.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: Smoke Test
on:
push:
branches:
- master
paths-ignore:
- "README*.md"
- "changelogs/**"
- "dashboard/**"
pull_request:
workflow_dispatch:
jobs:
smoke-test:
name: Run smoke tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install UV package manager
run: |
pip install uv
- name: Install dependencies
run: |
uv sync
timeout-minutes: 15
- name: Run smoke tests
run: |
uv run main.py &
# uv tool install -e . --force
# astrbot init -y
# astrbot run --backend-only &
APP_PID=$!
echo "Waiting for application to start..."
for i in {1..60}; do
if curl -f http://localhost:6185 > /dev/null 2>&1; then
echo "Application started successfully!"
kill $APP_PID
exit 0
fi
sleep 1
done
echo "Application failed to start within 30 seconds"
kill $APP_PID 2>/dev/null || true
exit 1
timeout-minutes: 2

View File

@@ -1,27 +1,65 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
# 本工作流用于标记并关闭长期不活跃的 Issue。
# 目前仅针对带 `bug` 标签的 Issue 生效,不会处理 PR。
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests
# 文档: https://github.com/actions/stale
name: Mark stale bug issues
on:
schedule:
- cron: '21 23 * * *'
# 每天 UTC 08:30 执行 (北京时间 16:30)
- cron: '30 8 * * *'
workflow_dispatch:
inputs:
dry-run:
description: '仅预览, 不实际执行 (Dry run mode)'
required: false
default: true
type: boolean
jobs:
stale:
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Stale issue message'
stale-pr-message: 'Stale pull request message'
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
operations-per-run: 200
# 只处理带 bug 标签的 Issue
any-of-labels: 'bug'
# 不处理 PR
days-before-pr-stale: -1
days-before-pr-close: -1
# 不活跃判定与关闭策略: 先标记 stale, 再延迟关闭
days-before-issue-stale: 60
days-before-issue-close: 30
stale-issue-label: 'stale'
stale-issue-message: |
This issue has been automatically marked as **stale** because it has not had any activity.
It will be closed in a certain period of time if no further activity occurs.
If this issue is still relevant, please leave a comment.
---
该 Issue 已较长时间无活动, 已被标记为 `stale`。
如无后续活动, 将在一段时间后自动关闭。
如仍需跟进, 请回复评论。
close-issue-message: |
This issue has been automatically closed due to inactivity.
If the problem still exists, feel free to reopen or create a new issue with updated information.
---
该 Issue 因长期无活动已自动关闭。
如问题仍存在, 欢迎补充复现信息并重新打开或新建 Issue。
remove-stale-when-updated: true
debug-only: ${{ github.event_name == 'workflow_dispatch' && inputs.dry-run }}

69
.github/workflows/sync-wiki.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
name: sync wiki
on:
workflow_dispatch:
push:
branches:
- master
paths:
- '.github/workflows/sync-wiki.yml'
- 'docs/scripts/sync_docs_to_wiki.py'
- 'docs/tests/test_sync_docs_to_wiki.py'
- 'docs/zh/**'
- 'docs/en/**'
concurrency:
group: sync-wiki-${{ github.ref }}
cancel-in-progress: true
jobs:
sync:
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Validate manual ref
if: github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/master'
run: |
echo "This workflow only publishes from refs/heads/master. Re-run it from the master branch."
exit 1
- name: Check out docs repository
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Run sync unit tests
working-directory: docs
run: python -m unittest discover -s tests -p 'test_sync_docs_to_wiki.py' -v
- name: Validate internal doc links
run: python docs/scripts/sync_docs_to_wiki.py --source-root docs --check-links-only
- name: Clone AstrBot wiki
env:
WIKI_TOKEN: ${{ secrets.ASTRBOT_WIKI_TOKEN }}
run: |
test -n "$WIKI_TOKEN"
git clone "https://x-access-token:${WIKI_TOKEN}@github.com/AstrBotDevs/AstrBot.wiki.git" wiki
- name: Generate wiki pages
run: python docs/scripts/sync_docs_to_wiki.py --source-root docs --wiki-root wiki
- name: Commit and push wiki changes
working-directory: wiki
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add .
if git diff --cached --quiet; then
echo "No wiki changes to push"
exit 0
fi
git commit -m "docs: sync wiki from AstrBot-1/docs"
git push

37
.github/workflows/unit_tests.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Unit Tests
on:
push:
branches:
- master
paths-ignore:
- 'README*.md'
- 'changelogs/**'
- 'dashboard/**'
pull_request:
workflow_dispatch:
jobs:
unit-tests:
name: Run pytest suite
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install uv
run: |
python -m pip install --upgrade pip
python -m pip install uv
- name: Run tests
run: |
chmod +x scripts/run_pytests_ci.sh
bash ./scripts/run_pytests_ci.sh ./tests

37
.gitignore vendored
View File

@@ -24,16 +24,20 @@ configs/session
configs/config.yaml
cmd_config.json
# Plugins and packages
# Plugins
addons/plugins
packages/python_interpreter/workplace
astrbot/builtin_stars/python_interpreter/workplace
tests/astrbot_plugin_openai
# Dashboard
dashboard/node_modules/
dashboard/dist/
.pnpm-store/
package-lock.json
package.json
yarn.lock
# Bundled dashboard dist (generated by hatch_build.py during pip wheel build)
astrbot/dashboard/dist/
# Operating System
**/.DS_Store
@@ -47,3 +51,30 @@ astrbot.lock
chroma
venv/*
pytest.ini
AGENTS.md
IFLOW.md
# genie_tts data
CharacterModels/
GenieData/
.agent/
.codex/
.claude/
.opencode/
.kilocode/
.serena
.worktrees/
.astrbot_sdk_testing/
.env
dashboard/warker.js
dashboard/bun.lock
.pua/
# Rust build artifacts
rust/target/
# Build outputs
dist/
*.whl
*.so

View File

@@ -6,20 +6,20 @@ ci:
autoupdate_schedule: weekly
autoupdate_commit_msg: ":balloon: pre-commit autoupdate"
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.14.1
hooks:
# Run the linter.
- id: ruff-check
types_or: [ python, pyi ]
args: [ --fix ]
# Run the formatter.
- id: ruff-format
types_or: [ python, pyi ]
- repo: https://github.com/asottile/pyupgrade
rev: v3.21.0
hooks:
- id: pyupgrade
args: [--py310-plus]
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.7
hooks:
# Run the linter.
- id: ruff-check
types_or: [python, pyi]
args: [--fix]
# Run the formatter.
- id: ruff-format
types_or: [python, pyi]
- repo: https://github.com/asottile/pyupgrade
rev: v3.21.2
hooks:
- id: pyupgrade
args: [--py312-plus]

View File

@@ -1 +1 @@
3.10
3.12

59
AGENTS.md Normal file
View File

@@ -0,0 +1,59 @@
## Setup commands
### Core
```
uv tool install -e . --force
astrbot init
astrbot run # start the bot
astrbot run --backend-only # start the backend only
```
Exposed an API server on `http://localhost:6185` by default.
### Dashboard(WebUI)
```
cd dashboard
bun install # First time only.
bun dev
```
Runs on `http://localhost:3000` by default.
## Dev environment tips
1. When modifying the WebUI, be sure to maintain componentization and clean code. Avoid duplicate code.
2. Do not add any report files such as xxx_SUMMARY.md.
3. After finishing, use `ruff format .` and `ruff check .` to format and check the code.
4. When committing, ensure to use conventional commits messages, such as `feat: add new agent for data analysis` or `fix: resolve bug in provider manager`.
5. Use English for all new comments.
6. For path handling, use `pathlib.Path` instead of string paths, and use `astrbot.core.utils.path_utils` to get the AstrBot data and temp directory.
7. Use Python 3.12+ type hinting syntax (e.g., `list[str]` over `List[str]`, `int | None` over `Optional[int]`). Avoid using `Any` and `cast()` - use proper TypedDict, dataclass, or Protocol instead. When encountering dict access issues (e.g., `msg.get("key")` where ty infers wrong type), define a TypedDict with `total=False` to explicitly declare allowed keys.
Good example:
```python
class MessageComponent(TypedDict, total=False):
type: str
text: str
path: str
```
Bad example (avoid):
```python
msg: Any = something
msg = cast(dict, msg)
```
8. When introducing new environment variables:
- Use the `ASTRBOT_` prefix for naming (e.g., `ASTRBOT_ENABLE_FEATURE`).
- Add the variable and description to `.env.example`.
- Update `astrbot/cli/commands/cmd_run.py`:
- Add to the module docstring under "Environment Variables Used in Project".
- Add to the `keys_to_print` list in the `run` function for debug output.
9. To check all available CLI commands and their usage recursively, run `astrbot help --all`.
10. uv sync --group dev && uv run pytest --cov=astrbot tests/
## PR instructions
1. Title format: use conventional commit messages
2. Use English to write PR title and descriptions.

180
CLAUDE.md Normal file
View File

@@ -0,0 +1,180 @@
# AstrBot - Claude Code Guidelines
AstrBot is an open-source, all-in-one Agentic personal and group chat assistant supporting multiple IM platforms (QQ, Telegram, Discord, etc.) and LLM providers.
## Project Overview
- **Main entry**: `astrbot/__main__.py` or via CLI `astrbot run`
- **CLI commands**: `astrbot/cli/commands/`
- **Core modules**: `astrbot/core/`
- **Platform adapters**: `astrbot/core/platform/sources/`
- **Star plugins**: `astrbot/builtin_stars/`
- **Dashboard**: `dashboard/` (Vue.js frontend)
## Development Setup
```bash
# Install dependencies
uv tool install -e . --force
# Initialize AstrBot
astrbot init
# Run development
astrbot run
# Backend only (no WebUI)
astrbot run --backend-only
# Dashboard frontend
cd dashboard && bun dev
# Run tests
uv sync --group dev && uv run pytest --cov=astrbot tests/
```
## Code Style
### Python
1. **Type hints required** - Use Python 3.12+ syntax:
- `list[str]` not `List[str]`
- `int | None` not `Optional[int]`
- Avoid `Any` when possible
2. **Path handling** - Always use `pathlib.Path`:
```python
from pathlib import Path
# Use astrbot.core.utils.path_utils for data/temp directories
from astrbot.core.utils.path_utils import get_astrbot_data_path
```
3. **Formatting** - Run before committing:
```bash
ruff format .
ruff check .
```
4. **Comments** - Use English for all comments and docstrings
5. **Imports** - Use absolute imports via `astrbot.` prefix
### Environment Variables
When adding new environment variables:
1. Use `ASTRBOT_` prefix: `ASTRBOT_ENABLE_FEATURE`
2. Add to `.env.example` with description
3. Update `astrbot/cli/commands/cmd_run.py`:
- Add to module docstring under "Environment Variables Used in Project"
- Add to `keys_to_print` list for debug output
## Architecture
### Core Components
- `astrbot/core/` - Core bot functionality
- `astrbot/core/platform/` - Platform adapter system
- `astrbot/core/agent/` - Agent execution logic
- `astrbot/core/star/` - Plugin/Star handler system
- `astrbot/core/pipeline/` - Message processing pipeline
- `astrbot/cli/` - Command-line interface
### Important Utilities
```python
from astrbot.core.utils.astrbot_path import (
get_astrbot_root, # AstrBot root directory
get_astrbot_data_path, # Data directory
get_astrbot_config_path, # Config directory
get_astrbot_plugin_path, # Plugin directory
get_astrbot_temp_path, # Temp directory
get_astrbot_skills_path, # Skills directory
)
```
### Platform Adapters
Platform adapters are in `astrbot/core/platform/sources/`:
- Each adapter extends base platform classes
- Use `@register_platform_adapter` decorator
- Events flow through `commit_event()` to message queue
### Star (Plugin) System
Stars are plugins in `astrbot/builtin_stars/`:
- Extend `Star` base class
- Use decorators for command handlers: `@star.on_command`, `@star.on_message`, etc.
- Access via `context` object
## Testing
1. Tests go in `tests/` directory
2. Use `pytest` with `pytest-asyncio`
3. Coverage target: `uv run pytest --cov=astrbot tests/`
4. Test files: `test_*.py` or `*_test.py`
## Git Conventions
### Commit Messages
Use conventional commits:
```
feat: add new feature
fix: resolve bug
docs: update documentation
refactor: restructure code
test: add tests
chore: maintenance tasks
```
### PR Guidelines
1. Title: conventional commit format
2. Description: English
3. Target branch: `dev`
4. Keep changes focused and atomic
## Project-Specific Guidelines
1. **No report files** - Do not add `xxx_SUMMARY.md` or similar
2. **Componentization** - Maintain clean code, avoid duplication in WebUI
3. **Backward compatibility** - When deprecating, add warnings
4. **CLI help** - Run `astrbot help --all` to see all commands
## File Organization
```
astrbot/
├── __main__.py # Main entry point
├── __init__.py # Package init, exports
├── cli/ # CLI commands
│ └── commands/ # Individual command modules
├── core/ # Core functionality
│ ├── agent/ # Agent execution
│ ├── platform/ # Platform adapters
│ ├── pipeline/ # Message processing
│ ├── star/ # Plugin system
│ └── config/ # Configuration
├── builtin_stars/ # Built-in plugins
├── dashboard/ # Vue.js frontend
└── utils/ # Utilities
```
## Common Tasks
### Adding a new platform adapter
1. Create adapter in `astrbot/core/platform/sources/`
2. Extend `Platform` base class
3. Use `@register_platform_adapter` decorator
4. Implement required methods: `run()`, `convert_message()`, `meta()`
### Adding a new command
1. Add to appropriate module in `cli/commands/`
2. Register with `@click.command()`
3. Update `astrbot/cli/__main__.py` to add command
### Adding a new Star handler
1. Create in `astrbot/builtin_stars/` or as plugin
2. Extend `Star` class
3. Use decorators: `@star.on_command()`, `@star.on_schedule()`, etc.

142
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,142 @@
# CONTRIBUTING
## 贡献指南
首先,感谢您花时间做出贡献!❤️
所有类型的贡献都受到鼓励和重视。有关不同的帮助方式和处理方式的详细信息,请参阅[目录](#目录)。在做出贡献之前,请确保阅读相关部分。这将使我们维护人员的工作变得更加容易,并为所有参与者带来顺畅的体验。社区期待您的贡献。🎉
### 目录
- [报告问题](#报告问题)
- [提交代码更改](#提交代码更改)
### 报告问题
如果您在使用 AstrBot 时遇到任何问题,请按照以下步骤报告:
1. **检查现有问题**:在提交新问题之前,请先检查 [Issues](https://github.com/AstrBotDevs/AstrBot/issues) 中是否已经存在类似的问题。
2. **创建新问题**:如果没有类似的问题,请创建一个新问题。请确保提供以下信息:
- 问题的简要描述
- 重现问题的步骤
- 预期结果和实际结果
- 相关日志或错误消息
### 提交代码更改
#### 分支命名
我们使用 `fix/` 前缀来修复错误,使用 `feat/` 前缀来添加新功能。对于 `fix/` 分支,请使用简短的描述,或者直接使用 Issue 编号。例如:`fix/1234` 或者 `fix/1234-login-typo`。对于 `feat/` 分支,请使用简短的描述,例如:`feat/add-user-profile`
#### PR 描述
- 请使用英文描述您的 PR。
- 标题请使用 `fix: `, `feat: `, `docs: `, `style: `, `refactor: `, `test: `, `chore: ` 等语义化前缀,并简要描述更改内容。如:`fix: correct login page typo`
#### 代码规范
##### Core
我们使用 Ruff 作为代码格式化和静态分析工具。在提交代码之前,请运行以下命令以确保代码符合规范:
```bash
ruff format .
ruff check .
```
如果您使用 VSCode可以安装 `Ruff` 插件。
##### PR 功能完整性验证(推荐)
如果您希望在本地做一套接近 CI 的完整验证,可使用:
```bash
make pr-test-neo
```
该命令会执行:
- `uv sync --group dev`
- `ruff format --check .``ruff check .`
- Neo 相关关键测试
- `main.py` 启动 smoke test检测 `http://localhost:6185`
需要全量验证时可使用:
```bash
make pr-test-full
```
如果只想快速重复执行(跳过依赖同步和 dashboard 构建):
```bash
make pr-test-full-fast
```
## Contributing Guide
First off, thanks for taking the time to contribute! ❤️
All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
### Table of Contents
- [Reporting Issues](#reporting-issues)
- [Pull Requests](#pull-requests)
### Reporting Issues
If you encounter any issues while using AstrBot, please follow these steps to report them:
1. **Check Existing Issues**: Before submitting a new issue, please check if a similar issue already exists in the [Issues](https://github.com/AstrBotDevs/AstrBot/issues) section of the repository.
2. **Create a New Issue**: If no similar issue exists, please create a new issue. Make sure to provide the following information:
- A brief description of the issue
- Steps to reproduce the issue
- Expected and actual results
- Relevant logs or error messages
### Pull Requests
#### Branch Naming
We use the `fix/` prefix for bug fixes and the `feat/` prefix for new features. For `fix/` branches, please use a short description or directly use the Issue number, e.g., `fix/1234` or `fix/1234-login-typo`. For `feat/` branches, please use a short description, e.g., `feat/add-user-profile`.
#### PR Description
- Please use English to describe your PR.
- Use semantic prefixes like `fix: `, `feat: `, `docs: `, `style: `, `refactor: `, `test: `, `chore: ` in the title, followed by a brief description of the changes, e.g., `fix: correct login page typo`.
#### Code Style
##### Core
We use Ruff as our code formatter and static analysis tool. Before submitting your code, please run the following commands to ensure your code adheres to the style guidelines:
```bash
ruff format .
ruff check .
```
##### PR completeness checks (recommended)
To run a local validation flow close to CI, use:
```bash
make pr-test-neo
```
This command runs:
- `uv sync --group dev`
- `ruff format --check .` and `ruff check .`
- Neo-related critical tests
- a startup smoke test against `http://localhost:6185`
For full validation, use:
```bash
make pr-test-full
```
For faster repeated runs (skip dependency sync and dashboard build), use:
```bash
make pr-test-full-fast
```

View File

@@ -1,4 +1,4 @@
FROM python:3.11-slim
FROM python:3.12-slim
WORKDIR /AstrBot
COPY . /AstrBot/
@@ -15,18 +15,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
gnupg \
git \
&& curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
apt-get install -y --no-install-recommends nodejs && \
echo "3.11" > .python-version && \
rm -rf /var/lib/apt/lists/*
RUN python -m pip install --no-cache-dir uv && \
uv pip install socksio pilk --no-cache-dir --system
RUN python -m pip install uv \
&& echo "3.12" > .python-version \
&& uv lock \
&& uv export --format requirements.txt --output-file requirements.txt --frozen \
&& uv pip install -r requirements.txt --no-cache-dir --system \
&& uv pip install socksio uv pilk --no-cache-dir --system
EXPOSE 6185
EXPOSE 6186
CMD ["uv", "run", "main.py"]
CMD ["python", "main.py"]

View File

@@ -1,40 +0,0 @@
FROM python:3.11-slim
WORKDIR /AstrBot
COPY . /AstrBot/
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
build-essential \
python3-dev \
libffi-dev \
libssl-dev \
curl \
unzip \
ca-certificates \
bash \
git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV NVM_DIR="/root/.nvm" \
NODE_VERSION=22
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash && \
. "$NVM_DIR/nvm.sh" && \
nvm install $NODE_VERSION && \
nvm use $NODE_VERSION && \
nvm alias default $NODE_VERSION && \
node -v && npm -v && \
echo "3.11" > .python-version
ENV PATH="$NVM_DIR/versions/node/v$(node -v | cut -d 'v' -f 2)/bin:$PATH"
RUN python -m pip install --no-cache-dir uv
# 安装项目依赖(根据指南,使用 uv sync
RUN uv sync --no-cache
EXPOSE 6185
EXPOSE 6186
CMD ["uv", "run", "main.py"]

244
EULA.md Normal file
View File

@@ -0,0 +1,244 @@
# 最终用户许可协议EULA
> 我们热爱开源软件,并始终致力于为所有用户提供健康、安全、可靠的使用体验。 ❤️
For English edition, please refer to the section below the Chinese version.
**最后更新:** 2026-01-12
感谢您使用 **AstrBot**
在使用本项目之前,请仔细阅读以下声明内容。
**您一旦安装、运行或使用本项目,即表示您已阅读、理解并同意本声明中的全部内容。**
## 1. 项目性质
AstrBot 是一个遵循 **GNU Affero General Public License v3AGPLv3** 协议发布的**免费开源软件项目**。
* 截至目前AstrBot 项目未开展任何形式的商业化服务AstrBot 团队也未通过本项目向用户提供任何收费服务。若您因使用 AstrBot 被要求付费,请务必提高警惕,谨防诈骗行为。
* AstrBot 的代码实现未对任何第三方系统进行逆向工程、破解、反编译或绕过安全机制等行为。AstrBot 仅使用并支持各即时通讯IM平台官方公开提供的机器人接入接口、开放平台能力或相关通信协议进行集成与通信。
## 2. 无担保声明
AstrBot 按“**现状as is**”提供,不附带任何形式的明示或暗示担保。
AstrBot 团队不对以下内容作出任何保证:
* 系统本身的安全性、可靠性或稳定性;
* 任何第三方插件的安全性、正确性或可信度;
* 任何第三方 AI 模型或外部服务 API 的可用性、质量、准确性或安全性;
* 本软件对任何特定用途的适用性。
**您使用本软件所产生的一切风险均由您自行承担。**
## 3. 第三方插件与服务
* AstrBot 支持第三方插件及外部 AI 服务接入;
* AstrBot 团队**不对任何第三方插件、扩展或服务进行审计、控制、背书或担保**
* 因使用第三方插件或服务所产生的任何风险、损失、数据泄露或法律后果,均由用户自行承担。
* 第三方插件指代的是非 AstrBot 自带的插件AstrBot 自带的插件指代的是插件实现代码已经包含在 AstrBotDevs/AstrBot 代码库中的插件。插件市场中的插件都是第三方插件。
## 4. 使用与内容限制
您同意不会将 AstrBot 用于以下行为:
* 输入、生成、传播或处理任何违法、极端、暴力、色情、仇恨、辱骂或其他有害内容;
* 从事违反您所在国家或地区法律法规,或任何适用国际法律的行为;
* 试图绕过、关闭、削弱或破坏本系统内置的安全机制或内容限制。
* 任何侵犯他人合法权益、损害他人和自己身心健康、涉及个人隐私、个人信息等敏感内容的内容。
## 5. 项目用途说明
AstrBot 是一个**工具型对话与 Agent 系统**,在**安全、健康、友善**的前提下提供有限的人性化交互能力。
项目的主要目标是:
* 提供 Agent 能力与自动化辅助;
* 帮助用户提升工作、学习和信息处理效率;
* 在合理范围内提供友好的人机交互体验。
* 辅助用户成长,提供有益于用户身心健康的内容。
## 6. 安全措施说明
AstrBot 团队**已尽合理努力在技术和策略层面设置安全与内容约束机制**,以引导系统输出健康、友善、安全的内容。
但请理解:
* 世界上任何的系统均无法保证完全无误、绝对安全或无法被滥用;
* 用户仍有责任自行合理配置、监督并正确使用本系统。
如果您要关闭 AstrBot 默认启用的“健康模式”,请在 cmd_config.json 中将 `provider_settings.llm_safety_mode` 设置为 `False`。但请注意关闭健康模式不是推荐的使用方式可能导致系统输出不安全或不适当的内容。关闭该功能所产生的任何风险与后果均由用户自行承担AstrBot 团队不对此承担任何责任。
## 7. 心理健康提示
如果您在使用本项目过程中因系统输出内容而感到心理不适、情绪困扰,
或您本身正处于心理压力较大、情绪不稳定、焦虑、抑郁等状态并因此使用本项目,
请优先考虑寻求来自专业人士的帮助,例如心理咨询师、心理医生或当地心理援助机构。
如遇紧急情况(例如存在自伤或他伤风险),请立即联系当地的紧急救助电话或专业机构。
## 8. 统计信息与隐私说明
AstrBot 可能会收集有限的匿名统计信息,用于了解系统使用情况、发现问题以及持续改进项目。
所收集的统计信息仅包括与系统运行和功能使用相关的基础技术指标,例如功能使用频率、错误信息等。
AstrBot **不会收集、上传或存储您的对话内容、消息正文、输入文本,或任何能够识别您个人身份的敏感信息**
您可以手动关闭此项功能,通过在系统环境变量中设置 `ASTRBOT_DISABLE_METRICS=1` 来禁用匿名统计信息收集。
## 9. 责任限制
在法律允许的最大范围内AstrBot 团队不对因以下原因导致的任何直接或间接损失承担责任,包括但不限于:
* 使用或无法使用本软件;
* 使用第三方插件或服务;
* 系统生成的内容或输出;
* 数据丢失、服务中断或安全事件。
## 10. 条款的接受
您一旦安装、运行、修改或使用 AstrBot即确认
* 您已阅读并理解本声明内容;
* 您同意并接受上述所有条款;
* 您对自身使用行为承担全部责任。
如您不同意本声明的任何内容,请勿使用本项目。
## 11. 许可与版权
AstrBot 的源代码、文档及相关内容受版权法及相关法律保护。
在遵守本声明及 AGPLv3 协议的前提下AstrBot 授予您一项非独占、不可转让、不可再许可的许可,用于下载、安装、运行、修改和分发本软件。
除非法律另有规定或本声明另有明确说明AstrBot 团队保留本项目的所有未明确授予的权利。
## 12. 适用法律
本声明的解释与适用应遵循您所在地或项目发布地适用的法律法规。
如本声明的任何条款被认定为无效或不可执行,其余条款仍然有效。
---
# EULA
> We love open-source software and are always committed to providing all users with a healthy, safe, and reliable experience. ❤️
**Last updated:** January 12, 2026
Thank you for using **AstrBot**.
Please read the following notice carefully before using this project.
**By installing, running, or using this project, you acknowledge that you have read, understood, and agreed to all the terms stated below.**
## 1. Nature of the Project
AstrBot is a **free and open-source software project** released under the **GNU Affero General Public License v3 (AGPLv3)**.
* AstrBot does not constitute any form of commercial service;
* The AstrBot Team does not provide any paid services through this project;
* AstrBots implementation does not involve reverse engineering, cracking, decompilation, or circumvention of security mechanisms of any third-party systems. AstrBot only uses and supports officially published bot integration interfaces, open platform capabilities, or related communication protocols provided by instant messaging (IM) platforms for integration and communication.
## 2. No Warranty
AstrBot is provided **“as is”**, without any express or implied warranties.
The AstrBot Team makes no guarantees regarding:
* The security, reliability, or stability of the system;
* The security, correctness, or trustworthiness of any third-party plugins;
* The availability, quality, accuracy, or safety of any third-party AI model APIs or external services;
* The fitness of the software for any particular purpose.
**All risks arising from the use of this software are borne solely by the user.**
## 3. Third-Party Plugins and Services
* AstrBot supports third-party plugins and external AI services;
* The AstrBot Team does **not audit, control, endorse, or guarantee** any third-party plugins, extensions, or services;
* Any risks, losses, data leaks, or legal consequences arising from the use of third-party plugins or services are solely the responsibility of the user;
* “Third-party plugins” refer to plugins that are not built into AstrBot. Built-in plugins are those whose implementation code is included in the AstrBotDevs/AstrBot repository. All plugins available in the plugin marketplace are third-party plugins.
## 4. Usage and Content Restrictions
You agree not to use AstrBot for any of the following activities:
* Inputting, generating, distributing, or processing any illegal, extremist, violent, pornographic, hateful, abusive, or otherwise harmful content;
* Engaging in activities that violate the laws or regulations of your country or region, or any applicable international laws;
* Attempting to bypass, disable, weaken, or undermine the built-in safety mechanisms or content restrictions of the system;
* Any activities that infringe upon the legitimate rights and interests of others, harm the physical or mental well-being of yourself or others, or involve personal privacy or sensitive personal information.
## 5. Intended Use
AstrBot is a **tool-oriented conversational and agent system** that provides limited human-like interaction capabilities under the principles of **safety, health, and friendliness**.
The primary goals of the project are to:
* Provide agent capabilities and automation assistance;
* Help users improve efficiency in work, study, and information processing;
* Offer a friendly humancomputer interaction experience within reasonable boundaries;
* Support user growth and provide content beneficial to users physical and mental well-being.
## 6. Safety Measures
The AstrBot Team has made **reasonable efforts** at both technical and policy levels to implement safety and content restriction mechanisms, guiding the system to produce healthy, friendly, and safe outputs.
However, please understand that:
* No system in the world can be guaranteed to be completely error-free, absolutely secure, or immune to misuse;
* Users remain responsible for properly configuring, supervising, and using the system.
If you wish to disable AstrBots default “Safety Mode,” please set `provider_settings.llm_safety_mode` to `False` in `cmd_config.json`. However, please note that disabling Safety Mode is not recommended and may lead to unsafe or inappropriate outputs. Any risks or consequences arising from disabling this feature are solely borne by the user, and the AstrBot Team assumes no responsibility.
## 7. Mental Health Notice
If you experience psychological discomfort or emotional distress due to system outputs during use,
or if you are experiencing significant psychological stress, emotional instability, anxiety, or depression and are using this project for such reasons,
please prioritize seeking help from qualified professionals, such as psychologists, psychiatrists, or local mental health support services.
In case of emergency (for example, if there is a risk of self-harm or harm to others), please immediately contact your local emergency number or professional crisis support services.
## 8. Metrics and Privacy
AstrBot may collect a limited amount of anonymous usage statistics to understand system usage, identify issues, and continuously improve the project.
Collected metrics are limited to basic technical indicators related to system operation and feature usage, such as feature usage frequency and error information.
AstrBot **does not collect, upload, or store your conversation content, message bodies, input text, or any personally identifiable or sensitive information**.
You may manually disable this feature by setting the environment variable `ASTRBOT_DISABLE_METRICS=1` to turn off anonymous metrics collection.
## 9. Limitation of Liability
To the maximum extent permitted by law, the AstrBot Team shall not be liable for any direct or indirect losses arising from, including but not limited to:
* The use or inability to use this software;
* The use of third-party plugins or services;
* Generated content or system outputs;
* Data loss, service interruptions, or security incidents.
## 10. Acceptance of Terms
By installing, running, modifying, or using AstrBot, you confirm that:
* You have read and understood this Notice;
* You agree to and accept all the terms stated above;
* You assume full responsibility for your use of the software.
If you do not agree with any part of this Notice, please do not use this project.
## 11. License and Copyright
The source code, documentation, and related materials of AstrBot are protected by copyright laws and applicable regulations.
Subject to compliance with this Notice and the AGPLv3 license, AstrBot grants you a non-exclusive, non-transferable, non-sublicensable license to download, install, run, modify, and distribute this software.
Unless otherwise required by law or expressly stated in this Notice, the AstrBot Team reserves all rights not expressly granted.
## 12. Governing Law
The interpretation and application of this Notice shall be governed by the laws and regulations applicable in your jurisdiction or the jurisdiction where the project is released.
If any provision of this Notice is held to be invalid or unenforceable, the remaining provisions shall remain in full force and effect.

14
FIRST_NOTICE.en-US.md Normal file
View File

@@ -0,0 +1,14 @@
## Welcome to AstrBot
🌟 Thank you for using AstrBot!
AstrBot is an Agentic AI assistant for personal and group chats, with support for multiple IM platforms and a wide range of built-in features. We hope it brings you an efficient and enjoyable experience. ❤️
Important notice:
AstrBot is a **free and open-source software project** protected by the AGPLv3 license. You can find the full source code and related resources on our [**official website**](https://astrbot.app) and [**GitHub**](https://github.com/astrbotdevs/astrbot).
As of now, AstrBot has **no commercial services of any kind**, and the official team **will never charge users any fees** under any name.
If anyone asks you to pay while using AstrBot, **you are likely being scammed**. Please request a refund immediately and report it to us by email.
📮 Official email: [community@astrbot.app](mailto:community@astrbot.app)

14
FIRST_NOTICE.md Normal file
View File

@@ -0,0 +1,14 @@
## 欢迎使用 AstrBot
🌟 感谢您使用 AstrBot
AstrBot 是一款可接入多种 IM 平台的 Agentic AI 个人 / 群聊助手,内置多项强大功能,希望能为您带来高效、愉快的使用体验。❤️
我们想特别说明:
AstrBot 是受 AGPLv3 开源协议保护的**免费开源软件项目**,您可以在[**官方网站**](https://astrbot.app)、[**GitHub**](https://github.com/astrbotdevs/astrbot) 上找到 AstrBot 的全部源代码及相关资源。
截至目前AstrBot 项目**未开展任何形式的商业化服务**,官方**不会以任何名义向用户收取费用**。
如果您在使用 AstrBot 的过程中被要求付费,**表明您已经遭遇诈骗行为**。请立即向相关方申请退款,并及时通过邮件向我们反馈。
📮 官方邮箱:[community@astrbot.app](mailto:community@astrbot.app)

41
Makefile Normal file
View File

@@ -0,0 +1,41 @@
.PHONY: worktree worktree-add worktree-rm pr-test-neo pr-test-full pr-test-full-fast
WORKTREE_DIR ?= ../astrbot_worktree
BRANCH ?= $(word 2,$(MAKECMDGOALS))
BASE ?= $(word 3,$(MAKECMDGOALS))
BASE ?= master
worktree:
@echo "Usage:"
@echo " make worktree-add <branch> [base-branch]"
@echo " make worktree-rm <branch>"
worktree-add:
ifeq ($(strip $(BRANCH)),)
$(error Branch name required. Usage: make worktree-add <branch> [base-branch])
endif
@mkdir -p $(WORKTREE_DIR)
git worktree add $(WORKTREE_DIR)/$(BRANCH) -b $(BRANCH) $(BASE)
worktree-rm:
ifeq ($(strip $(BRANCH)),)
$(error Branch name required. Usage: make worktree-rm <branch>)
endif
@if [ -d "$(WORKTREE_DIR)/$(BRANCH)" ]; then \
git worktree remove $(WORKTREE_DIR)/$(BRANCH); \
else \
echo "Worktree $(WORKTREE_DIR)/$(BRANCH) not found."; \
fi
pr-test-neo:
./scripts/pr_test_env.sh --profile neo
pr-test-full:
./scripts/pr_test_env.sh --profile full
pr-test-full-fast:
./scripts/pr_test_env.sh --profile full --skip-sync --no-dashboard
# Swallow extra args (branch/base) so make doesn't treat them as targets
%:
@true

378
README.md
View File

@@ -1,236 +1,294 @@
![AstrBot-Logo-Simplified](https://github.com/user-attachments/assets/ffd99b6b-3272-4682-beaa-6fe74250f7d9)
</p>
<div align="center">
<br>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh-TW.md">繁體中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ja.md">日本語</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_fr.md">Français</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ru.md">Русский</a>
<div>
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=1" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=2" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br>
<div>
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?style=for-the-badge&color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg?style=for-the-badge&color=76bad9" alt="python">
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?style=for-the-badge&color=76bad9"/></a>
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=wtbaNx7EioxeaqS9z7RQWVXPIxg2zYr7&jump_from=webapi&authKey=vlqnv/AV2DbJEvGIcxdlNSpfxVy+8vVqijgreRdnVKOaydpc+YSw4MctmEbr0k5"><img alt="QQ_community" src="https://img.shields.io/badge/QQ群-775869627-purple?style=for-the-badge&color=76bad9"></a>
<a href="https://t.me/+hAsD2Ebl5as3NmY1"><img alt="Telegram_community" src="https://img.shields.io/badge/Telegram-AstrBot-purple?style=for-the-badge&color=76bad9"></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%E4%B8%AA&style=for-the-badge&label=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%9C%BA&cacheSeconds=3600">
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://deepwiki.com/badge.svg" href="https://deepwiki.com/AstrBotDevs/AstrBot">
<a href="https://zread.ai/AstrBotDevs/AstrBot" target="_blank"><img src="https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTk0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff" alt="zread"/></a>
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?color=76bad9"/></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%20Plugins&label=Marketplace&cacheSeconds=3600">
<img src="https://gitcode.com/Soulter/AstrBot/star/badge.svg" href="https://gitcode.com/Soulter/AstrBot">
</div>
<br>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_en.md">English</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ja.md">日本語</a>
<a href="https://astrbot.app/">文档</a>
<a href="https://astrbot.app/">Home</a>
<a href="https://astrbot.app/">Docs</a>
<a href="https://blog.astrbot.app/">Blog</a>
<a href="https://astrbot.featurebase.app/roadmap">路线图</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">问题提交</a>
<a href="https://astrbot.featurebase.app/roadmap">Roadmap</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">Issue Tracker</a>
<a href="mailto:community@astrbot.app">Email Support</a>
</div>
AstrBot 是一个开源的一站式 Agent 聊天机器人平台及开发框架。
AstrBot is an open-source, all-in-one Agentic personal and group chat assistant that can be deployed on dozens of mainstream instant messaging platforms such as QQ, Telegram, WeCom, Lark, DingTalk, Slack, and more. It also features a built-in lightweight ChatUI similar to OpenWebUI, creating a reliable and scalable conversational AI infrastructure for individuals, developers, and teams. Whether it's a personal AI companion, smart customer service, automated assistant, or enterprise knowledge base, AstrBot enables you to quickly build AI applications within the workflow of your instant messaging platforms.
## 主要功能
![landingpage](https://github.com/user-attachments/assets/45fc5699-cddf-4e21-af35-13040706f6c0)
1. **大模型对话**。支持接入多种大模型服务。支持多模态、工具调用、MCP、原生知识库、人设等功能。
2. **多消息平台支持**。支持接入 QQ、企业微信、微信公众号、飞书、Telegram、钉钉、Discord、KOOK 等平台。支持速率限制、白名单、百度内容审核。
3. **Agent**。完善适配的 Agentic 能力。支持多轮工具调用、内置沙盒代码执行器、网页搜索等功能。
4. **插件扩展**。深度优化的插件机制,支持[开发插件](https://astrbot.app/dev/plugin.html)扩展功能,社区插件生态丰富。
5. **WebUI**。可视化配置和管理机器人,功能齐全。
## Key Features
## 部署方式
1. 💯 Free & Open Source.
2. ✨ Large Language Model (LLM) dialogue, Multimodal, Agent, MCP, Skills, Knowledge Base, Persona settings, automatic dialogue compression.
3. 🤖 Supports integration with agent platforms such as Dify, Alibaba Bailian, Coze, etc.
4. 🌐 Multi-platform support: QQ, WeCom, Lark, DingTalk, WeChat Official Account, Telegram, Slack, and [more](#supported-message-platforms).
5. 📦 Plugin extension: 1000+ plugins available for one-click installation.
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html): Isolated environment for safely executing any code, calling Shell commands, and reusing session-level resources.
7. 💻 WebUI support.
8. 🌈 Web ChatUI support: Built-in proxy sandbox, web search, etc. within ChatUI.
9. 🌐 Internationalization (i18n) support.
#### Docker 部署(推荐 🥳)
<br>
推荐使用 Docker / Docker Compose 方式部署 AstrBot。
<table align="center">
<tr align="center">
<th>💙 Roleplay & Companionship</th>
<th>✨ Proactive Agent</th>
<th>🚀 General Agentic Capabilities</th>
<th>🧩 1000+ Community Plugins</th>
</tr>
<tr>
<td align="center"><p align="center"><img width="984" height="1746" alt="99b587c5d35eea09d84f33e6cf6cfd4f" src="https://github.com/user-attachments/assets/89196061-3290-458d-b51f-afa178049f84" /></p></td>
<td align="center"><p align="center"><img width="976" height="1612" alt="c449acd838c41d0915cc08a3824025b1" src="https://github.com/user-attachments/assets/f75368b4-e022-41dc-a9e0-131c3e73e32e" /></p></td>
<td align="center"><p align="center"><img width="974" height="1732" alt="image" src="https://github.com/user-attachments/assets/e22a3968-87d7-4708-a7cd-e7f198c7c32e" /></p></td>
<td align="center"><p align="center"><img width="976" height="1734" alt="image" src="https://github.com/user-attachments/assets/0952b395-6b4a-432a-8a50-c294b7f89750" /></p></td>
</tr>
</table>
请参阅官方文档 [使用 Docker 部署 AstrBot](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot) 。
## Quick Start
#### 宝塔面板部署
### One-Click Deployment
AstrBot 与宝塔面板合作,已上架至宝塔面板。
For users who want to experience AstrBot quickly, are familiar with the command line, and can install the `uv` environment themselves, we recommend using `uv` for one-click deployment ⚡️.
请参阅官方文档 [宝塔面板部署](https://astrbot.app/deploy/astrbot/btpanel.html) 。
```bash
uv tool install astrbot
astrbot init # Execute this command only for the first time to initialize the environment
astrbot run # astrbot run --backend-only starts only the backend service
#### 1Panel 部署
# Install development version (more fixes and new features, but less stable; suitable for developers)
uv tool install git+https://github.com/AstrBotDevs/AstrBot@dev
```
AstrBot 已由 1Panel 官方上架至 1Panel 面板。
> Requires [uv](https://docs.astral.sh/uv/) installed.
请参阅官方文档 [1Panel 部署](https://astrbot.app/deploy/astrbot/1panel.html) 。
> [!NOTE]
> For macOS users: Due to macOS security checks, the first execution of the `astrbot` command may take a longer time (about 10-20 seconds).
#### 在 雨云 上部署
Update `astrbot`:
AstrBot 已由雨云官方上架至云应用平台,可一键部署。
```bash
uv tool upgrade astrbot
```
### Docker Deployment
For users familiar with containers who prefer a more stable deployment suitable for production environments, we recommend using Docker / Docker Compose to deploy AstrBot.
Please refer to the official documentation [Deploy AstrBot with Docker](https://astrbot.app/deploy/astrbot/docker.html).
### Deploy on RainYun
For users who want to deploy AstrBot with one click and do not want to manage servers themselves, we recommend RainYun's one-click cloud deployment service ☁️:
[![Deploy on RainYun](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-en.svg)](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
#### 在 Replit 上部署
### Desktop Client Deployment
社区贡献的部署方式。
For users who wish to use AstrBot on the desktop with ChatUI as the main interface, we recommend using the AstrBot App.
Go to [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) to download and install; this method is intended for desktop use and is not recommended for server scenarios.
### Launcher Deployment
Also for desktop, users who want quick deployment and isolated environments for multiple instances can use the AstrBot Launcher.
Go to [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) to download and install.
### Deploy on Replit
Replit deployment is maintained by the community, suitable for online demos and lightweight trials.
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
#### Windows 一键安装器部署
### AUR
请参阅官方文档 [使用 Windows 一键安装器部署 AstrBot](https://astrbot.app/deploy/astrbot/windows.html) 。
The AUR method is for Arch Linux users who wish to install AstrBot via the system package manager.
#### CasaOS 部署
社区贡献的部署方式。
请参阅官方文档 [CasaOS 部署](https://astrbot.app/deploy/astrbot/casaos.html) 。
#### 手动部署
首先安装 uv
Execute the following command in the terminal to install the `astrbot-git` package. You can start using it after installation completes.
```bash
pip install uv
yay -S astrbot-git
```
通过 Git Clone 安装 AstrBot
**More Deployment Methods**
```bash
git clone https://github.com/AstrBotDevs/AstrBot && cd AstrBot
uv run main.py
```
If you need panel-based or highly customized deployment, you can refer to [BT Panel](https://astrbot.app/deploy/astrbot/btpanel.html) (BT Panel App Store), [1Panel](https://astrbot.app/deploy/astrbot/1panel.html) (1Panel App Store), [CasaOS](https://astrbot.app/deploy/astrbot/casaos.html) (NAS / Home Server visual deployment), and [Manual Deployment](https://astrbot.app/deploy/astrbot/cli.html) (Full custom installation based on source code and `uv`).
或者请参阅官方文档 [通过源码部署 AstrBot](https://astrbot.app/deploy/astrbot/cli.html) 。
## Supported Message Platforms
## 🌍 社区
Connect AstrBot to your favorite chat platforms.
### QQ 群组
| Platform | Maintainer |
|---------|---------------|
| **QQ** | Official |
| **OneBot v11** | Official |
| **Telegram** | Official |
| **WeCom App & Bot** | Official |
| **WeChat Customer Service & Official Account** | Official |
| **Lark (Feishu)** | Official |
| **DingTalk** | Official |
| **Slack** | Official |
| **Discord** | Official |
| **LINE** | Official |
| **Satori** | Official |
| **Misskey** | Official |
| **Whatsapp (Coming Soon)** | Official |
| [**Matrix**](https://github.com/stevessr/astrbot_plugin_matrix_adapter) | Community |
| [**KOOK**](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | Community |
| [**VoceChat**](https://github.com/HikariFroya/astrbot_plugin_vocechat) | Community |
- 1 群322154837
- 3 群630166526
- 5 群822130018
- 6 群753075035
- 开发者群975206796
## Supported Model Providers
### Telegram 群组
| Provider | Type |
|---------|---------------|
| Custom | Any OpenAI API compatible service |
| OpenAI | LLM |
| Anthropic | LLM |
| Google Gemini | LLM |
| Moonshot AI | LLM |
| Zhipu AI | LLM |
| DeepSeek | LLM |
| Ollama (Local) | LLM |
| LM Studio (Local) | LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM (API Gateway, supports all models) |
| [Compshare](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM (API Gateway, supports all models) |
| [SiliconFlow](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM (API Gateway, supports all models) |
| [PPIO](https://ppio.com/user/register?invited_by=AIOONE) | LLM (API Gateway, supports all models) |
| [302.AI](https://share.302.ai/rr1M3l) | LLM (API Gateway, supports all models)|
| [TokenPony](https://www.tokenpony.cn/3YPyf) | LLM (API Gateway, supports all models)|
| ModelScope | LLM |
| OneAPI | LLM |
| Dify | LLMOps Platform |
| Alibaba Bailian | LLMOps Platform |
| Coze | LLMOps Platform |
| OpenAI Whisper | Speech-to-Text |
| SenseVoice | Speech-to-Text |
| OpenAI TTS | Text-to-Speech |
| Gemini TTS | Text-to-Speech |
| GPT-Sovits-Inference | Text-to-Speech |
| GPT-Sovits | Text-to-Speech |
| FishAudio | Text-to-Speech |
| Edge TTS | Text-to-Speech |
| Alibaba Bailian TTS | Text-to-Speech |
| Azure TTS | Text-to-Speech |
| Minimax TTS | Text-to-Speech |
| Volcano Engine TTS | Text-to-Speech |
<a href="https://t.me/+hAsD2Ebl5as3NmY1"><img alt="Telegram_community" src="https://img.shields.io/badge/Telegram-AstrBot-purple?style=for-the-badge&color=76bad9"></a>
## ❤️ Sponsors
### Discord 群组
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
<a href="https://discord.gg/hAVk6tgV36"><img alt="Discord_community" src="https://img.shields.io/badge/Discord-AstrBot-purple?style=for-the-badge&color=76bad9"></a>
## ⚡ 消息平台支持情况
## ❤️ Contribution
**官方维护**
Welcome any Issues/Pull Requests! Just submit your changes to this project :)
| 平台 | 支持性 |
| -------- | ------- |
| QQ(官方平台) | ✔ |
| QQ(OneBot) | ✔ |
| Telegram | ✔ |
| 企微应用 | ✔ |
| 企微智能机器人 | ✔ |
| 微信客服 | ✔ |
| 微信公众号 | ✔ |
| 飞书 | ✔ |
| 钉钉 | ✔ |
| Slack | ✔ |
| Discord | ✔ |
| Satori | ✔ |
| Misskey | ✔ |
| Whatsapp | 将支持 |
| LINE | 将支持 |
### How to Contribute
**社区维护**
You can contribute by viewing issues or helping to review PRs (Pull Requests). Any issues or PRs are welcome to promote community contribution. Of course, these are just suggestions; you can contribute in any way. For new feature additions, please discuss via Issue first.
It is recommended to merge functional PRs into the `dev` branch, which will be merged into the main branch and released as a new version after testing.
To reduce conflicts, we suggest:
1. Create your working branch based on the `dev` branch, avoid working directly on the `main` branch.
2. When submitting a PR, select the `dev` branch as the target.
3. Regularly sync the `dev` branch to your local environment; use `git pull` frequently.
| 平台 | 支持性 |
| -------- | ------- |
| [KOOK](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | ✔ |
| [VoceChat](https://github.com/HikariFroya/astrbot_plugin_vocechat) | ✔ |
| [Bilibili 私信](https://github.com/Hina-Chat/astrbot_plugin_bilibili_adapter) | ✔ |
| [wxauto](https://github.com/luosheng520qaq/wxauto-repost-onebotv11) | ✔ |
### Development Environment
## ⚡ 提供商支持情况
**大模型服务**
| 名称 | 支持性 | 备注 |
| -------- | ------- | ------- |
| OpenAI | ✔ | 支持任何兼容 OpenAI API 的服务 |
| Anthropic | ✔ | |
| Google Gemini | ✔ | |
| Moonshot AI | ✔ | |
| 智谱 AI | ✔ | |
| DeepSeek | ✔ | |
| Ollama | ✔ | 本地部署 DeepSeek 等开源语言模型 |
| LM Studio | ✔ | 本地部署 DeepSeek 等开源语言模型 |
| [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | ✔ | |
| [302.AI](https://share.302.ai/rr1M3l) | ✔ | |
| [小马算力](https://www.tokenpony.cn/3YPyf) | ✔ | |
| 硅基流动 | ✔ | |
| PPIO 派欧云 | ✔ | |
| ModelScope | ✔ | |
| OneAPI | ✔ | |
| Dify | ✔ | |
| 阿里云百炼应用 | ✔ | |
| Coze | ✔ | |
**语音转文本服务**
| 名称 | 支持性 | 备注 |
| -------- | ------- | ------- |
| Whisper | ✔ | 支持 API、本地部署 |
| SenseVoice | ✔ | 本地部署 |
**文本转语音服务**
| 名称 | 支持性 | 备注 |
| -------- | ------- | ------- |
| OpenAI TTS | ✔ | |
| Gemini TTS | ✔ | |
| GSVI | ✔ | GPT-Sovits-Inference |
| GPT-SoVITs | ✔ | GPT-Sovits |
| FishAudio | ✔ | |
| Edge TTS | ✔ | Edge 浏览器的免费 TTS |
| 阿里云百炼 TTS | ✔ | |
| Azure TTS | ✔ | |
| Minimax TTS | ✔ | |
| 火山引擎 TTS | ✔ | |
## ❤️ 贡献
欢迎任何 Issues/Pull Requests只需要将你的更改提交到此项目 )
### 如何贡献
你可以通过查看问题或帮助审核 PR拉取请求来贡献。任何问题或 PR 都欢迎参与,以促进社区贡献。当然,这些只是建议,你可以以任何方式进行贡献。对于新功能的添加,请先通过 Issue 讨论。
### 开发环境
AstrBot 使用 `ruff` 进行代码格式化和检查。
AstrBot uses `ruff` for code formatting and checking.
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
git switch dev # Switch to dev branch
pip install pre-commit # or uv tool install pre-commit
pre-commit install
```
We recommend using `uv` for local installation and testing:
```bash
uv tool install -e . --force
astrbot init
astrbot run
```
Frontend Debugging:
```bash
astrbot run --backend-only
cd dashboard
bun install # or pnpm, etc.
bun dev
```
### QQ Groups
- Group 9: 1076659624 (New)
- Group 10: 1078079676 (New)
- Group 1: 322154837
- Group 3: 630166526
- Group 5: 822130018
- Group 6: 753075035
- Group 7: 743746109
- Group 8: 1030353265
- Developer Group (Casual): 975206796
- Developer Group (Official): 1039761811
### Discord Channel
- [Discord](https://discord.gg/hAVk6tgV36)
## ❤️ Special Thanks
特别感谢所有 Contributors 和插件开发者对 AstrBot 的贡献 ❤️
Special thanks to all Contributors and plugin developers for their contributions to AstrBot ❤️
<a href="https://github.com/AstrBotDevs/AstrBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot" />
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot&max=200&columns=14" />
</a>
此外,本项目的诞生离不开以下开源项目的帮助:
In addition, the birth of this project cannot be separated from the help of the following open-source projects:
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - 伟大的猫猫框架
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - Great Cat Framework
Open Source Project Friendly Links:
- [NoneBot2](https://github.com/nonebot/nonebot2) - Excellent Python Asynchronous ChatBot Framework
- [Koishi](https://github.com/koishijs/koishi) - Excellent Node.js ChatBot Framework
- [MaiBot](https://github.com/Mai-with-u/MaiBot) - Excellent Anthropomorphic AI ChatBot
- [nekro-agent](https://github.com/KroMiose/nekro-agent) - Excellent Agent ChatBot
- [LangBot](https://github.com/langbot-app/LangBot) - Excellent Multi-platform AI ChatBot
- [ChatLuna](https://github.com/ChatLunaLab/chatluna) - Excellent Multi-platform AI ChatBot Koishi Plugin
- [Operit AI](https://github.com/AAswordman/Operit) - Excellent AI Assistant Android APP
## ⭐ Star History
> [!TIP]
> 如果本项目对您的生活 / 工作产生了帮助,或者您关注本项目的未来发展,请给项目 Star这是我们维护这个开源项目的动力 <3
> [!TIP]
> If this project helps your life/work, or you are concerned about the future development of this project, please Star the project. This is our motivation to maintain this open-source project <3
<div align="center">
@@ -238,6 +296,12 @@ pre-commit install
</div>
</details>
<div align="center">
_Companionship and capability should never be opposites. We hope to create a robot that can both understand emotions, provide companionship, and reliably complete tasks._
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>

View File

@@ -1,182 +0,0 @@
<p align="center">
![6e1279651f16d7fdf4727558b72bbaf1](https://github.com/user-attachments/assets/ead4c551-fc3c-48f7-a6f7-afbfdb820512)
</p>
<div align="center">
_✨ Easy-to-use Multi-platform LLM Chatbot & Development Framework ✨_
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/AstrBotDevs/AstrBot)](https://github.com/AstrBotDevs/AstrBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot"/></a>
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=wtbaNx7EioxeaqS9z7RQWVXPIxg2zYr7&jump_from=webapi&authKey=vlqnv/AV2DbJEvGIcxdlNSpfxVy+8vVqijgreRdnVKOaydpc+YSw4MctmEbr0k5"><img alt="Static Badge" src="https://img.shields.io/badge/QQ群-630166526-purple"></a>
[![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e)
![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B6%88%E6%81%AF%E4%B8%8A%E8%A1%8C%E9%87%8F&cacheSeconds=3600)
[![codecov](https://codecov.io/gh/AstrBotDevs/AstrBot/graph/badge.svg?token=FF3P5967B8)](https://codecov.io/gh/AstrBotDevs/AstrBot)
<a href="https://astrbot.app/">Documentation</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">Issue Tracking</a>
</div>
AstrBot is a loosely coupled, asynchronous chatbot and development framework that supports multi-platform deployment, featuring an easy-to-use plugin system and comprehensive Large Language Model (LLM) integration capabilities.
## ✨ Key Features
1. **LLM Conversations** - Supports various LLMs including OpenAI API, Google Gemini, Llama, Deepseek, ChatGLM, etc. Enables local model deployment via Ollama/LLMTuner. Features multi-turn dialogues, personality contexts, multimodal capabilities (image understanding), and speech-to-text (Whisper).
2. **Multi-platform Integration** - Supports QQ (OneBot), QQ Channels, WeChat (Gewechat), Feishu, and Telegram. Planned support for DingTalk, Discord, WhatsApp, and Xiaomi Smart Speakers. Includes rate limiting, whitelisting, keyword filtering, and Baidu content moderation.
3. **Agent Capabilities** - Native support for code execution, natural language TODO lists, web search. Integrates with [Dify Platform](https://dify.ai/) for easy access to Dify assistants/knowledge bases/workflows.
4. **Plugin System** - Optimized plugin mechanism with minimal development effort. Supports multiple installed plugins.
5. **Web Dashboard** - Visual configuration management, plugin controls, logging, and WebChat interface for direct LLM interaction.
6. **High Stability & Modularity** - Event bus and pipeline architecture ensures high modularization and loose coupling.
> [!TIP]
> Dashboard Demo: [https://demo.astrbot.app/](https://demo.astrbot.app/)
> Username: `astrbot`, Password: `astrbot` (LLM not configured for chat page)
## ✨ Deployment
#### Docker Deployment
See docs: [Deploy with Docker](https://astrbot.app/deploy/astrbot/docker.html#docker-deployment)
#### Windows Installer
Requires Python (>3.10). See docs: [Windows Installer Guide](https://astrbot.app/deploy/astrbot/windows.html)
#### Replit Deployment
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
#### CasaOS Deployment
Community-contributed method.
See docs: [CasaOS Deployment](https://astrbot.app/deploy/astrbot/casaos.html)
#### Manual Deployment
See docs: [Source Code Deployment](https://astrbot.app/deploy/astrbot/cli.html)
## ⚡ Platform Support
| Platform | Status | Details | Message Types |
| -------------------------------------------------------------- | ------ | ------------------- | ------------------- |
| QQ (Official Bot) | ✔ | Private/Group chats | Text, Images |
| QQ (OneBot) | ✔ | Private/Group chats | Text, Images, Voice |
| WeChat (Personal) | ✔ | Private/Group chats | Text, Images, Voice |
| [Telegram](https://github.com/AstrBotDevs/AstrBot_plugin_telegram) | ✔ | Private/Group chats | Text, Images |
| [WeChat Work](https://github.com/AstrBotDevs/AstrBot_plugin_wecom) | ✔ | Private chats | Text, Images, Voice |
| Feishu | ✔ | Group chats | Text, Images |
| WeChat Open Platform | 🚧 | Planned | - |
| Discord | 🚧 | Planned | - |
| WhatsApp | 🚧 | Planned | - |
| Xiaomi Speakers | 🚧 | Planned | - |
## Provider Support Status
| Name | Support | Type | Notes |
|---------------------------|---------|------------------------|-----------------------------------------------------------------------|
| OpenAI API | ✔ | Text Generation | Supports all OpenAI API-compatible services including DeepSeek, Google Gemini, GLM, Moonshot, Alibaba Cloud Bailian, Silicon Flow, xAI, etc. |
| Claude API | ✔ | Text Generation | |
| Google Gemini API | ✔ | Text Generation | |
| Dify | ✔ | LLMOps | |
| DashScope (Alibaba Cloud) | ✔ | LLMOps | |
| Ollama | ✔ | Model Loader | Local deployment for open-source LLMs (DeepSeek, Llama, etc.) |
| LM Studio | ✔ | Model Loader | Local deployment for open-source LLMs (DeepSeek, Llama, etc.) |
| LLMTuner | ✔ | Model Loader | Local loading of fine-tuned models (e.g. LoRA) |
| OneAPI | ✔ | LLM Distribution | |
| Whisper | ✔ | Speech-to-Text | Supports API and local deployment |
| SenseVoice | ✔ | Speech-to-Text | Local deployment |
| OpenAI TTS API | ✔ | Text-to-Speech | |
| Fishaudio | ✔ | Text-to-Speech | Project involving GPT-Sovits author |
# 🦌 Roadmap
> [!TIP]
> Suggestions welcome via Issues <3
- [ ] Ensure feature parity across all platform adapters
- [ ] Optimize plugin APIs
- [ ] Add default TTS services (e.g., GPT-Sovits)
- [ ] Enhance chat features with persistent memory
- [ ] i18n Planning
## ❤️ Contributions
All Issues/PRs welcome! Simply submit your changes to this project :)
For major features, please discuss via Issues first.
## 🌟 Support
- Star this project!
- Support via [Afdian](https://afdian.com/a/soulter)
- WeChat support: [QR Code](https://drive.soulter.top/f/pYfA/d903f4fa49a496fda3f16d2be9e023b5.png)
## ✨ Demos
> [!NOTE]
> Code executor file I/O currently tested with Napcat(QQ)/Lagrange(QQ)
<div align='center'>
<img src="https://github.com/user-attachments/assets/4ee688d9-467d-45c8-99d6-368f9a8a92d8" width="600">
_✨ Docker-based Sandboxed Code Executor (Beta) ✨_
<img src="https://github.com/user-attachments/assets/0378f407-6079-4f64-ae4c-e97ab20611d2" height=500>
_✨ Multimodal Input, Web Search, Text-to-Image ✨_
<img src="https://github.com/user-attachments/assets/8ec12797-e70f-460a-959e-48eca39ca2bb" height=100>
_✨ Natural Language TODO Lists ✨_
<img src="https://github.com/user-attachments/assets/e137a9e1-340a-4bf2-bb2b-771132780735" height=150>
<img src="https://github.com/user-attachments/assets/480f5e82-cf6a-4955-a869-0d73137aa6e1" height=150>
_✨ Plugin System Showcase ✨_
<img src="https://github.com/user-attachments/assets/592a8630-14c7-4e06-b496-9c0386e4f36c" width=600>
_✨ Web Dashboard ✨_
![webchat](https://drive.soulter.top/f/vlsA/ezgif-5-fb044b2542.gif)
_✨ Built-in Web Chat Interface ✨_
</div>
## ⭐ Star History
> [!TIP]
> If this project helps you, please give it a star <3
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=AstrBotDevs/AstrBot&type=Date)](https://star-history.com/#AstrBotDevs/AstrBot&Date)
</div>
## Disclaimer
1. Licensed under `AGPL-v3`.
2. WeChat integration uses [Gewechat](https://github.com/Devo919/Gewechat). Use at your own risk with non-critical accounts.
3. Users must comply with local laws and regulations.
<!-- ## ✨ ATRI [Beta]
Available as plugin: [astrbot_plugin_atri](https://github.com/AstrBotDevs/AstrBot_plugin_atri)
1. Qwen1.5-7B-Chat Lora model fine-tuned with ATRI character data
2. Long-term memory
3. Meme understanding & responses
4. TTS integration
-->
_私は、高性能ですから!_

304
README_fr.md Normal file
View File

@@ -0,0 +1,304 @@
![AstrBot-Logo-Simplified](https://github.com/user-attachments/assets/ffd99b6b-3272-4682-beaa-6fe74250f7d9)
<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README.md">English</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh-TW.md">繁體中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ja.md">日本語</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ru.md">Русский</a>
<div>
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=2" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br>
<div>
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://deepwiki.com/badge.svg" href="https://deepwiki.com/AstrBotDevs/AstrBot">
<a href="https://zread.ai/AstrBotDevs/AstrBot" target="_blank"><img src="https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTk4IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff" alt="zread"/></a>
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?color=76bad9"/></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%20Plugins&label=Marketplace&cacheSeconds=3600">
<img src="https://gitcode.com/Soulter/AstrBot/star/badge.svg" href="https://gitcode.com/Soulter/AstrBot">
</div>
<br>
<a href="https://astrbot.app/">Accueil</a>
<a href="https://astrbot.app/">Documentation</a>
<a href="https://blog.astrbot.app/">Blog</a>
<a href="https://astrbot.featurebase.app/roadmap">Feuille de route</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">Signaler un problème</a>
<a href="mailto:community@astrbot.app">Email</a>
</div>
AstrBot est un assistant de chat personnel et de groupe Agentic tout-en-un et open-source, qui peut être déployé sur des dizaines de logiciels de messagerie instantanée grand public tels que QQ, Telegram, WeCom (WeChat Entreprise), Lark (Feishu), DingTalk, Slack, etc. Il intègre également une interface de chat légère similaire à OpenWebUI, créant ainsi une infrastructure conversationnelle intelligente fiable et extensible pour les particuliers, les développeurs et les équipes. Qu'il s'agisse d'un compagnon IA personnel, d'un service client intelligent, d'un assistant automatisé ou d'une base de connaissances d'entreprise, AstrBot vous permet de construire rapidement des applications IA au sein du flux de travail de vos plateformes de messagerie instantanée.
![landingpage](https://github.com/user-attachments/assets/45fc5699-cddf-4e21-af35-13040706f6c0)
## Fonctionnalités Principales
1. 💯 Gratuit & Open Source.
2. ✨ Dialogue avec de grands modèles d'IA (LLM), multimodal, Agent, MCP, Compétences (Skills), base de connaissances, définition de persona, compression automatique des dialogues.
3. 🤖 Prend en charge l'intégration avec des plateformes d'agents comme Dify, Alibaba Bailian, Coze, etc.
4. 🌐 Multiplateforme, prend en charge QQ, WeCom, Lark, DingTalk, Compte Officiel WeChat, Telegram, Slack et [plus encore](#plateformes-de-messagerie-prises-en-charge).
5. 📦 Extension par plugins, plus de 1000 plugins disponibles pour une installation en un clic.
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html) : environnement isolé pour exécuter n'importe quel code, appeler le Shell et réutiliser les ressources au niveau de la session en toute sécurité.
7. 💻 Support WebUI.
8. 🌈 Support Web ChatUI, avec sandbox de proxy intégré, recherche web, etc.
9. 🌐 Support de l'internationalisation (i18n).
<br>
<table align="center">
<tr align="center">
<th>💙 Jeu de rôle & Accompagnement émotionnel</th>
<th>✨ Agent Proactif</th>
<th>🚀 Capacités Agentic Génériques</th>
<th>🧩 1000+ Plugins Communautaires</th>
</tr>
<tr>
<td align="center"><p align="center"><img width="984" height="1746" alt="99b587c5d35eea09d84f33e6cf6cfd4f" src="https://github.com/user-attachments/assets/89196061-3290-458d-b51f-afa178049f84" /></p></td>
<td align="center"><p align="center"><img width="976" height="1612" alt="c449acd838c41d0915cc08a3824025b1" src="https://github.com/user-attachments/assets/f75368b4-e022-41dc-a9e0-131c3e73e32e" /></p></td>
<td align="center"><p align="center"><img width="974" height="1732" alt="image" src="https://github.com/user-attachments/assets/e22a3968-87d7-4708-a7cd-e7f198c7c32e" /></p></td>
<td align="center"><p align="center"><img width="976" height="1734" alt="image" src="https://github.com/user-attachments/assets/0952b395-6b4a-432a-8a50-c294b7f89750" /></p></td>
</tr>
</table>
## Démarrage Rapide
### Déploiement en un clic
Pour les utilisateurs qui souhaitent essayer AstrBot rapidement, qui sont familiers avec la ligne de commande et capables d'installer l'environnement `uv` par eux-mêmes, nous recommandons la méthode de déploiement en un clic avec `uv` ⚡️.
```bash
uv tool install astrbot
astrbot init # Exécutez cette commande uniquement la première fois pour initialiser l'environnement
astrbot run # astrbot run --backend-only démarre uniquement le service backend
# Installer la version de développement (plus de correctifs, nouvelles fonctionnalités, mais moins stable, adapté aux développeurs)
uv tool install git+https://github.com/AstrBotDevs/AstrBot@dev
```
> Nécessite l'installation de [uv](https://docs.astral.sh/uv/).
> [!NOTE]
> Pour les utilisateurs de macOS : en raison des contrôles de sécurité de macOS, la première exécution de la commande `astrbot` peut prendre un certain temps (environ 10-20 secondes).
Mettre à jour `astrbot` :
```bash
uv tool upgrade astrbot
```
### Déploiement Docker
Pour les utilisateurs familiers avec les conteneurs et souhaitant une méthode de déploiement plus stable et adaptée aux environnements de production, nous recommandons d'utiliser Docker / Docker Compose pour déployer AstrBot.
Veuillez vous référer à la documentation officielle [Déployer AstrBot avec Docker](https://astrbot.app/deploy/astrbot/docker.html).
### Déploiement sur RainYun
Pour les utilisateurs souhaitant déployer AstrBot en un clic sans gérer de serveur, nous recommandons le service de déploiement cloud en un clic de RainYun ☁️ :
[![Deploy on RainYun](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-en.svg)](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### Déploiement Client Bureau
Pour les utilisateurs souhaitant utiliser AstrBot sur ordinateur de bureau et utiliser principalement ChatUI comme point d'entrée, nous recommandons l'application AstrBot App.
Rendez-vous sur [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) pour télécharger et installer ; cette méthode est destinée à un usage bureautique et n'est pas recommandée pour les scénarios serveur.
### Déploiement Launcher
Également pour une utilisation sur bureau, pour les utilisateurs souhaitant un déploiement rapide et une isolation de l'environnement pour plusieurs instances, nous recommandons AstrBot Launcher.
Rendez-vous sur [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) pour télécharger et installer.
### Déploiement sur Replit
Le déploiement sur Replit est maintenu par la communauté et convient aux démonstrations en ligne et aux scénarios d'essai légers.
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
La méthode AUR est destinée aux utilisateurs d'Arch Linux souhaitant installer AstrBot via le gestionnaire de paquets du système.
Exécutez la commande ci-dessous dans le terminal pour installer le paquet `astrbot-git`. Une fois l'installation terminée, vous pouvez le lancer.
```bash
yay -S astrbot-git
```
**Plus de méthodes de déploiement**
Si vous avez besoin d'un déploiement via panneau de contrôle ou hautement personnalisé, vous pouvez consulter [BT Panel](https://astrbot.app/deploy/astrbot/btpanel.html) (installation via le magasin d'applications BT Panel), [1Panel](https://astrbot.app/deploy/astrbot/1panel.html) (installation via le magasin d'applications 1Panel), [CasaOS](https://astrbot.app/deploy/astrbot/casaos.html) (déploiement visuel pour NAS / serveur domestique) et [Déploiement Manuel](https://astrbot.app/deploy/astrbot/cli.html) (installation personnalisée complète basée sur le code source et `uv`).
## Plateformes de Messagerie Prises en Charge
Connectez AstrBot à vos plateformes de chat préférées.
| Plateforme | Mainteneur |
|---------|---------------|
| **QQ** | Officiel |
| **OneBot v11** | Officiel |
| **Telegram** | Officiel |
| **WeCom (App & Smart Bot)** | Officiel |
| **WeChat (Service Client & Compte Officiel)** | Officiel |
| **Lark (Feishu)** | Officiel |
| **DingTalk** | Officiel |
| **Slack** | Officiel |
| **Discord** | Officiel |
| **LINE** | Officiel |
| **Satori** | Officiel |
| **Misskey** | Officiel |
| **Whatsapp (Bientôt)** | Officiel |
| [**Matrix**](https://github.com/stevessr/astrbot_plugin_matrix_adapter) | Communauté |
| [**KOOK**](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | Communauté |
| [**VoceChat**](https://github.com/HikariFroya/astrbot_plugin_vocechat) | Communauté |
## Fournisseurs de Modèles Pris en Charge
| Fournisseur | Type |
|---------|---------------|
| Personnalisé | Tout service compatible avec l'API OpenAI |
| OpenAI | LLM |
| Anthropic | LLM |
| Google Gemini | LLM |
| Moonshot AI | LLM |
| Zhipu AI | LLM |
| DeepSeek | LLM |
| Ollama (Local) | LLM |
| LM Studio (Local) | LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM (Passerelle API, supporte tous les modèles) |
| [Uyun AI](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM (Passerelle API, supporte tous les modèles) |
| [SiliconFlow](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM (Passerelle API, supporte tous les modèles) |
| [PPIO](https://ppio.com/user/register?invited_by=AIOONE) | LLM (Passerelle API, supporte tous les modèles) |
| [302.AI](https://share.302.ai/rr1M3l) | LLM (Passerelle API, supporte tous les modèles)|
| [TokenPony](https://www.tokenpony.cn/3YPyf) | LLM (Passerelle API, supporte tous les modèles)|
| ModelScope | LLM |
| OneAPI | LLM |
| Dify | Plateforme LLMOps |
| Alibaba Bailian | Plateforme LLMOps |
| Coze | Plateforme LLMOps |
| OpenAI Whisper | Synthèse vocale (Speech-to-Text) |
| SenseVoice | Synthèse vocale (Speech-to-Text) |
| OpenAI TTS | Synthèse vocale (Text-to-Speech) |
| Gemini TTS | Synthèse vocale (Text-to-Speech) |
| GPT-Sovits-Inference | Synthèse vocale (Text-to-Speech) |
| GPT-Sovits | Synthèse vocale (Text-to-Speech) |
| FishAudio | Synthèse vocale (Text-to-Speech) |
| Edge TTS | Synthèse vocale (Text-to-Speech) |
| Alibaba Bailian TTS | Synthèse vocale (Text-to-Speech) |
| Azure TTS | Synthèse vocale (Text-to-Speech) |
| Minimax TTS | Synthèse vocale (Text-to-Speech) |
| Volcengine TTS | Synthèse vocale (Text-to-Speech) |
## ❤️ Sponsors
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
## ❤️ Contribution
Les Issues et Pull Requests sont les bienvenus ! Soumettez simplement vos modifications à ce projet :)
### Comment Contribuer
Vous pouvez contribuer en examinant les problèmes ou en aidant à réviser les PR (Pull Requests). Tout problème ou PR est le bienvenu pour promouvoir la contribution communautaire. Bien sûr, ce ne sont que des suggestions, vous pouvez contribuer de n'importe quelle manière. Pour l'ajout de nouvelles fonctionnalités, veuillez d'abord en discuter via une Issue.
Il est recommandé de fusionner les PR fonctionnels dans la branche `dev`, qui sera fusionnée dans la branche principale et publiée en tant que nouvelle version après test des modifications.
Pour réduire les conflits, nous suggérons :
1. Créez votre branche de travail basée sur la branche `dev`, évitez de travailler directement sur la branche `main`.
2. Lors de la soumission d'une PR, sélectionnez la branche `dev` comme cible.
3. Synchronisez régulièrement la branche `dev` en local, utilisez souvent `git pull`.
### Environnement de Développement
AstrBot utilise `ruff` pour le formatage et la vérification du code.
```bash
git clone https://github.com/AstrBotDevs/AstrBot
git switch dev # Basculer vers la branche de développement
pip install pre-commit # ou uv tool install pre-commit
pre-commit install
```
Il est recommandé d'utiliser `uv` pour l'installation locale et les tests.
```bash
uv tool install -e . --force
astrbot init
astrbot run
```
Débogage frontend
```bash
astrbot run --backend-only
cd dashboard
bun install # ou pnpm, etc.
bun dev
```
### Groupes QQ
- Groupe 9 : 1076659624 (Nouveau)
- Groupe 10 : 1078079676 (Nouveau)
- Groupe 1 : 322154837
- Groupe 3 : 630166526
- Groupe 5 : 822130018
- Groupe 6 : 753075035
- Groupe 7 : 743746109
- Groupe 8 : 1030353265
- Groupe Développeurs (Discussion libre) : 975206796
- Groupe Développeurs (Officiel) : 1039761811
### Canal Discord
- [Discord](https://discord.gg/hAVk6tgV36)
## ❤️ Remerciements Spéciaux
Un grand merci à tous les Contributeurs et développeurs de plugins pour leur contribution à AstrBot ❤️
<a href="https://github.com/AstrBotDevs/AstrBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot&max=200&columns=14" />
</a>
De plus, la naissance de ce projet n'aurait pas été possible sans l'aide des projets open source suivants :
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - Le grand framework félin
Liens amicaux vers des projets open source :
- [NoneBot2](https://github.com/nonebot/nonebot2) - Excellent framework de ChatBot asynchrone en Python
- [Koishi](https://github.com/koishijs/koishi) - Excellent framework de ChatBot en Node.js
- [MaiBot](https://github.com/Mai-with-u/MaiBot) - Excellent ChatBot IA anthropomorphe
- [nekro-agent](https://github.com/KroMiose/nekro-agent) - Excellent ChatBot Agent
- [LangBot](https://github.com/langbot-app/LangBot) - Excellent ChatBot IA multiplateforme
- [ChatLuna](https://github.com/ChatLunaLab/chatluna) - Excellent plugin Koishi de ChatBot IA multiplateforme
- [Operit AI](https://github.com/AAswordman/Operit) - Excellente application Android d'assistant intelligent IA
## ⭐ Historique des Étoiles
> [!TIP]
> Si ce projet vous a été utile dans votre vie ou votre travail, ou si vous vous intéressez à son développement futur, merci de lui donner une Étoile. C'est notre motivation pour maintenir ce projet open source <3
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=astrbotdevs/astrbot&type=Date)](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_La compagnie et la compétence ne devraient jamais être opposées. Nous espérons créer un robot capable à la fois de comprendre les émotions, d'offrir de la compagnie et d'accomplir des tâches de manière fiable._
_私は、高性能ですから!_ (Je suis performant !)
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>

View File

@@ -1,167 +1,304 @@
<p align="center">
![6e1279651f16d7fdf4727558b72bbaf1](https://github.com/user-attachments/assets/ead4c551-fc3c-48f7-a6f7-afbfdb820512)
</p>
![AstrBot-Logo-Simplified](https://github.com/user-attachments/assets/ffd99b6b-3272-4682-beaa-6fe74250f7d9)
<div align="center">
_✨ 簡単に使えるマルチプラットフォーム LLM チャットボットおよび開発フレームワーク ✨_
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README.md">English</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh-TW.md">繁體中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_fr.md">Français</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ru.md">Русский</a>
<div>
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/AstrBotDevs/AstrBot)](https://github.com/AstrBotDevs/AstrBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg"/></a>
<img alt="Static Badge" src="https://img.shields.io/badge/QQ群-630166526-purple">
[![wakatime](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e.svg)](https://wakatime.com/badge/user/915e5316-99c6-4563-a483-ef186cf000c9/project/018e705a-a1a7-409a-a849-3013485e6c8e)
![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fstats&query=v&label=7%E6%97%A5%E6%B6%88%E6%81%AF%E4%B8%8A%E8%A1%8C%E9%87%8F&cacheSeconds=3600)
[![codecov](https://codecov.io/gh/AstrBotDevs/AstrBot/graph/badge.svg?token=FF3P5967B8)](https://codecov.io/gh/AstrBotDevs/AstrBot)
<a href="https://astrbot.app/">ドキュメントを見る</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">問題を報告する</a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=2" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
AstrBot は、疎結合、非同期、複数のメッセージプラットフォームに対応したデプロイ、使いやすいプラグインシステム、および包括的な大規模言語モデルLLM接続機能を備えたチャットボットおよび開発フレームワークです。
<br>
## ✨ 主な機能
<div>
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://deepwiki.com/badge.svg" href="https://deepwiki.com/AstrBotDevs/AstrBot">
<a href="https://zread.ai/AstrBotDevs/AstrBot" target="_blank"><img src="https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff" alt="zread"/></a>
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?color=76bad9"/></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%E5%80%8B&label=%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%82%A2&cacheSeconds=3600">
<img src="https://gitcode.com/Soulter/AstrBot/star/badge.svg" href="https://gitcode.com/Soulter/AstrBot">
</div>
1. **大規模言語モデルの対話**。OpenAI API、Google Gemini、Llama、Deepseek、ChatGLM など、さまざまな大規模言語モデルをサポートし、Ollama、LLMTuner を介してローカルにデプロイされた大規模モデルをサポートします。多輪対話、人格シナリオ、多モーダル機能を備え、画像理解、音声からテキストへの変換Whisperをサポートします。
2. **複数のメッセージプラットフォームの接続**。QQOneBot、QQ チャンネル、Feishu、Telegram への接続をサポートします。今後、DingTalk、Discord、WhatsApp、Xiaoai 音響をサポートする予定です。レート制限、ホワイトリスト、キーワードフィルタリング、Baidu コンテンツ監査をサポートします。
3. **エージェント**。一部のエージェント機能をネイティブにサポートし、コードエグゼキューター、自然言語タスク、ウェブ検索などを提供します。[Dify プラットフォーム](https://dify.ai/)と連携し、Dify スマートアシスタント、ナレッジベース、Dify ワークフローを簡単に接続できます。
4. **プラグインの拡張**。深く最適化されたプラグインメカニズムを備え、[プラグインの開発](https://astrbot.app/dev/plugin.html)をサポートし、機能を拡張できます。複数のプラグインのインストールをサポートします。
5. **ビジュアル管理パネル**。設定の視覚的な変更、プラグイン管理、ログの表示などをサポートし、設定の難易度を低減します。WebChat を統合し、パネル上で大規模モデルと対話できます。
6. **高い安定性と高いモジュール性**。イベントバスとパイプラインに基づくアーキテクチャ設計により、高度にモジュール化され、低結合です。
<br>
> [!TIP]
> 管理パネルのオンラインデモを体験する: [https://demo.astrbot.app/](https://demo.astrbot.app/)
>
> ユーザー名: `astrbot`, パスワード: `astrbot`。LLM が設定されていないため、チャットページで大規模モデルを使用することはできません。(デモのログインパスワードを変更しないでください 😭)
<a href="https://astrbot.app/">ホーム</a>
<a href="https://astrbot.app/">ドキュメント</a>
<a href="https://blog.astrbot.app/">ブログ</a>
<a href="https://astrbot.featurebase.app/roadmap">ロードマップ</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">課題の提出</a>
<a href="mailto:community@astrbot.app">Email</a>
## ✨ 使用方法
</div>
#### Docker デプロイ
AstrBotは、オープンソースのオールインワンAgentic個人およびグループチャットアシスタントです。QQ、Telegram、WeCom企業微信、Lark飛書、DingTalk釘釘、Slackなど、数十種類の主要なインスタントメッセージングソフトウェアに導入できます。さらに、OpenWebUIに似た軽量のChatUIも組み込まれており、個人、開発者、チーム向けに信頼性が高く拡張可能な会話型AIインフラストラクチャを提供します。個人のAIパートナー、インテリジェントなカスタマーサービス、自動化アシスタント、または企業のナレッジベースであっても、AstrBotはインスタントメッセージングプラットフォームのワークフロー内でAIアプリケーションを迅速に構築することを可能にします。
公式ドキュメント [Docker を使用して AstrBot をデプロイする](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot) を参照してください。
![landingpage](https://github.com/user-attachments/assets/45fc5699-cddf-4e21-af35-13040706f6c0)
#### Windows ワンクリックインストーラーのデプロイ
## 主な機能
コンピュータに Python>3.10)がインストールされている必要があります。公式ドキュメント [Windows ワンクリックインストーラーを使用して AstrBot をデプロイする](https://astrbot.app/deploy/astrbot/windows.html) を参照してください
1. 💯 無料 & オープンソース
2. ✨ AI大規模モデル対話、マルチモーダル、エージェント、MCP、スキル、ナレッジベース、人格設定、対話の自動圧縮。
3. 🤖 Dify、Alibaba Bailian阿里雲百煉、Cozeなどのエージェントプラットフォームとの連携をサポート。
4. 🌐 マルチプラットフォーム対応QQ、WeCom、Lark、DingTalk、WeChat公式アカウント、Telegram、Slack、その他[多数](#対応メッセージングプラットフォーム)。
5. 📦 プラグイン拡張1000以上のプラグインがワンクリックでインストール可能。
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html):隔離された環境で、あらゆるコードの安全な実行、シェル呼び出し、セッションレベルのリソース再利用が可能。
7. 💻 WebUIサポート。
8. 🌈 Web ChatUIサポートChatUIにはプロキシサンドボックス、Web検索などが組み込まれています。
9. 🌐 国際化i18nサポート。
#### Replit デプロイ
<br>
<table align="center">
<tr align="center">
<th>💙 ロールプレイ & 感情的な付き添い</th>
<th>✨ 能動的エージェント</th>
<th>🚀 汎用Agentic能力</th>
<th>🧩 1000+ コミュニティプラグイン</th>
</tr>
<tr>
<td align="center"><p align="center"><img width="984" height="1746" alt="99b587c5d35eea09d84f33e6cf6cfd4f" src="https://github.com/user-attachments/assets/89196061-3290-458d-b51f-afa178049f84" /></p></td>
<td align="center"><p align="center"><img width="976" height="1612" alt="c449acd838c41d0915cc08a3824025b1" src="https://github.com/user-attachments/assets/f75368b4-e022-41dc-a9e0-131c3e73e32e" /></p></td>
<td align="center"><p align="center"><img width="974" height="1732" alt="image" src="https://github.com/user-attachments/assets/e22a3968-87d7-4708-a7cd-e7f198c7c32e" /></p></td>
<td align="center"><p align="center"><img width="976" height="1734" alt="image" src="https://github.com/user-attachments/assets/0952b395-6b4a-432a-8a50-c294b7f89750" /></p></td>
</tr>
</table>
## クイックスタート
### ワンクリックデプロイ
AstrBotをすぐに試してみたい方で、コマンドラインに慣れており、`uv`環境を自分でインストールできる方には、`uv`を使用したワンクリックデプロイをお勧めします⚡️。
```bash
uv tool install astrbot
astrbot init # 初回のみ環境初期化のために実行
astrbot run # astrbot run --backend-only バックエンドサービスのみ起動
# 開発版のインストール(修正や新機能が多いですが、不安定な場合があります。開発者向け)
uv tool install git+https://github.com/AstrBotDevs/AstrBot@dev
```
> [uv](https://docs.astral.sh/uv/)のインストールが必要です。
> [!NOTE]
> macOSユーザーの場合macOSのセキュリティチェックにより、`astrbot`コマンドの初回実行に時間がかかる場合があります約10〜20秒
`astrbot`の更新:
```bash
uv tool upgrade astrbot
```
### Dockerデプロイ
コンテナに精通しており、より安定的で本番環境に適したデプロイ方法を好むユーザーには、Docker / Docker Composeを使用したAstrBotのデプロイをお勧めします。
公式ドキュメントの[Dockerを使用してAstrBotをデプロイする](https://astrbot.app/deploy/astrbot/docker.html)を参照してください。
### RainYun雨云でのデプロイ
サーバーを自分で管理せずにAstrBotをワンクリックでデプロイしたいユーザーには、RainYunのワンクリッククラウドデプロイサービスをお勧めします☁
[![Deploy on RainYun](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-en.svg)](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### デスクトップクライアントデプロイ
デスクトップでAstrBotを使用し、主にChatUIを入り口として使用したいユーザーには、AstrBot Appをお勧めします。
[AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop)にアクセスしてダウンロードおよびインストールしてください。この方法はデスクトップ利用向けであり、サーバーシナリオには推奨されません。
### ランチャーデプロイ
同じくデスクトップ向けで、迅速にデプロイし、環境を分離して複数起動したいユーザーには、AstrBot Launcherをお勧めします。
[AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher)にアクセスしてダウンロードおよびインストールしてください。
### Replitでのデプロイ
Replitデプロイはコミュニティによって維持されており、オンラインデモや軽量な試用シナリオに適しています。
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
#### CasaOS デプロイ
### AUR
コミュニティが提供するデプロイ方法です。
AUR方式はArch Linuxユーザー向けで、システムパッケージマネージャーを通じてAstrBotをインストールしたい場合に適しています。
公式ドキュメント [ソースコードを使用して AstrBot をデプロイする](https://astrbot.app/deploy/astrbot/casaos.html) を参照してください
ターミナルで以下のコマンドを実行して`astrbot-git`パッケージをインストールすると、起動して使用できます
#### 手動デプロイ
```bash
yay -S astrbot-git
```
公式ドキュメント [ソースコードを使用して AstrBot をデプロイする](https://astrbot.app/deploy/astrbot/cli.html) を参照してください。
**その他のデプロイ方法**
## ⚡ メッセージプラットフォームのサポート状況
パネル化や高度なカスタマイズデプロイが必要な場合は、[BT Panel宝塔パネル](https://astrbot.app/deploy/astrbot/btpanel.html)BT Panelアプリストアインストール、[1Panel](https://astrbot.app/deploy/astrbot/1panel.html)1Panelアプリストアインストール、[CasaOS](https://astrbot.app/deploy/astrbot/casaos.html)NAS / ホームサーバーの視覚的デプロイ)、および[手動デプロイ](https://astrbot.app/deploy/astrbot/cli.html)(ソースコードと`uv`に基づく完全なカスタムインストール)を参照してください。
| プラットフォーム | サポート状況 | 詳細 | メッセージタイプ |
| -------- | ------- | ------- | ------ |
| QQ(公式ロボットインターフェース) | ✔ | プライベートチャット、グループチャット、QQ チャンネルプライベートチャット、グループチャット | テキスト、画像 |
| QQ(OneBot) | ✔ | プライベートチャット、グループチャット | テキスト、画像、音声 |
| WeChat(個人アカウント) | ✔ | WeChat 個人アカウントのプライベートチャット、グループチャット | テキスト、画像、音声 |
| [Telegram](https://github.com/Soulter/astrbot_plugin_telegram) | ✔ | プライベートチャット、グループチャット | テキスト、画像 |
| [WeChat(企業 WeChat)](https://github.com/Soulter/astrbot_plugin_wecom) | ✔ | プライベートチャット | テキスト、画像、音声 |
| Feishu | ✔ | グループチャット | テキスト、画像 |
| WeChat 対話オープンプラットフォーム | 🚧 | 計画中 | - |
| Discord | 🚧 | 計画中 | - |
| WhatsApp | 🚧 | 計画中 | - |
| Xiaoai 音響 | 🚧 | 計画中 | - |
## 対応メッセージングプラットフォーム
# 🦌 今後のロードマップ
AstrBotを普段使用しているチャットプラットフォームに接続しましょう。
> [!TIP]
> Issue でさらに多くの提案を歓迎します <3
| プラットフォーム | 管理者 |
|---------|---------------|
| **QQ** | 公式管理 |
| **OneBot v11** | 公式管理 |
| **Telegram** | 公式管理 |
| **WeComアプリ & WeComボット** | 公式管理 |
| **WeChatカスタマーサービス & WeChat公式アカウント** | 公式管理 |
| **Lark (飛書)** | 公式管理 |
| **DingTalk (釘釘)** | 公式管理 |
| **Slack** | 公式管理 |
| **Discord** | 公式管理 |
| **LINE** | 公式管理 |
| **Satori** | 公式管理 |
| **Misskey** | 公式管理 |
| **Whatsapp (対応予定)** | 公式管理 |
| [**Matrix**](https://github.com/stevessr/astrbot_plugin_matrix_adapter) | コミュニティ管理 |
| [**KOOK**](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | コミュニティ管理 |
| [**VoceChat**](https://github.com/HikariFroya/astrbot_plugin_vocechat) | コミュニティ管理 |
## 対応モデルプロバイダー
| プロバイダー | タイプ |
|---------|---------------|
| カスタム | OpenAI API互換の任意のサービス |
| OpenAI | LLM |
| Anthropic | LLM |
| Google Gemini | LLM |
| Moonshot AI | LLM |
| Zhipu AI (智譜AI) | LLM |
| DeepSeek | LLM |
| Ollama (ローカル) | LLM |
| LM Studio (ローカル) | LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM (APIゲートウェイ, 全モデル対応) |
| [Uyun AI (優雲智算)](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM (APIゲートウェイ, 全モデル対応) |
| [SiliconFlow (硅基流動)](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM (APIゲートウェイ, 全モデル対応) |
| [PPIO](https://ppio.com/user/register?invited_by=AIOONE) | LLM (APIゲートウェイ, 全モデル対応) |
| [302.AI](https://share.302.ai/rr1M3l) | LLM (APIゲートウェイ, 全モデル対応)|
| [TokenPony (小馬算力)](https://www.tokenpony.cn/3YPyf) | LLM (APIゲートウェイ, 全モデル対応)|
| ModelScope | LLM |
| OneAPI | LLM |
| Dify | LLMOpsプラットフォーム |
| Alibaba Bailian (阿里雲百煉) | LLMOpsプラットフォーム |
| Coze | LLMOpsプラットフォーム |
| OpenAI Whisper | 音声認識 (STT) |
| SenseVoice | 音声認識 (STT) |
| OpenAI TTS | 音声合成 (TTS) |
| Gemini TTS | 音声合成 (TTS) |
| GPT-Sovits-Inference | 音声合成 (TTS) |
| GPT-Sovits | 音声合成 (TTS) |
| FishAudio | 音声合成 (TTS) |
| Edge TTS | 音声合成 (TTS) |
| Alibaba Bailian TTS | 音声合成 (TTS) |
| Azure TTS | 音声合成 (TTS) |
| Minimax TTS | 音声合成 (TTS) |
| Volcengine TTS (火山エンジン) | 音声合成 (TTS) |
## ❤️ Sponsors
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
- [ ] 現在のすべてのプラットフォームアダプターの機能の一貫性を確保し、改善する
- [ ] プラグインインターフェースの最適化
- [ ] GPT-Sovits などの TTS サービスをデフォルトでサポート
- [ ] "チャット強化" 部分を完成させ、永続的な記憶をサポート
- [ ] i18n の計画
## ❤️ 貢献
IssuePull Request を歓迎します!このプロジェクトに変更を加えるだけです :)
IssuePull Requestは大歓迎です!変更をこのプロジェクトに送信してください :)
新機能の追加については、まず Issue で議論してください。
### 貢献方法
## 🌟 サポート
問題の確認やPRプルリクエストのレビューを通じて貢献できます。コミュニティの貢献を促進するために、あらゆる問題やPRへの参加を歓迎します。もちろん、これらは提案に過ぎず、どのような方法で貢献しても構いません。新機能の追加については、まずIssueで議論してください。
機能的なPRは`dev`ブランチにマージすることをお勧めします。テスト修正後にメインブランチにマージされ、新しいバージョンとしてリリースされます。
コンフリクトを減らすために、以下のことを推奨します:
1. 作業ブランチは`dev`ブランチに基づいて作成し、`main`ブランチで直接作業することは避けてください。
2. PRを送信する際は、ターゲットブランチとして`dev`ブランチを選択してください。
3. 定期的に`dev`ブランチをローカルに同期し、`git pull`を頻繁に使用してください。
- このプロジェクトに Star を付けてください!
- [愛発電](https://afdian.com/a/soulter)で私をサポートしてください!
- [WeChat](https://drive.soulter.top/f/pYfA/d903f4fa49a496fda3f16d2be9e023b5.png)で私をサポートしてください~
### 開発環境
## ✨ デモ
AstrBotはコードのフォーマットとチェックに`ruff`を使用しています。
> [!NOTE]
> コードエグゼキューターのファイル入力/出力は現在 Napcat(QQ)、Lagrange(QQ) でのみテストされています
```bash
git clone https://github.com/AstrBotDevs/AstrBot
git switch dev # 開発ブランチに切り替え
pip install pre-commit # または uv tool install pre-commit
pre-commit install
```
ローカルでのインストールとテストには`uv`の使用をお勧めします。
```bash
uv tool install -e . --force
astrbot init
astrbot run
```
フロントエンドのデバッグ
```bash
astrbot run --backend-only
cd dashboard
bun install # または pnpm など
bun dev
```
<div align='center'>
### QQグループ
<img src="https://github.com/user-attachments/assets/4ee688d9-467d-45c8-99d6-368f9a8a92d8" width="600">
- 9群: 1076659624 (新)
- 10群: 1078079676 (新)
- 1群322154837
- 3群630166526
- 5群822130018
- 6群753075035
- 7群743746109
- 8群1030353265
- 開発者群雑談975206796
- 開発者群公式1039761811
_✨ Docker ベースのサンドボックス化されたコードエグゼキューター(ベータテスト中)✨_
### Discordチャンネル
<img src="https://github.com/user-attachments/assets/0378f407-6079-4f64-ae4c-e97ab20611d2" height=500>
- [Discord](https://discord.gg/hAVk6tgV36)
_✨ 多モーダル、ウェブ検索、長文の画像変換(設定可能)✨_
## ❤️ Special Thanks
<img src="https://github.com/user-attachments/assets/8ec12797-e70f-460a-959e-48eca39ca2bb" height=100>
AstrBotに貢献してくださったすべてのコントリビューターとプラグイン開発者に感謝します ❤️
_✨ 自然言語タスク ✨_
<a href="https://github.com/AstrBotDevs/AstrBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot&max=200&columns=14" />
</a>
<img src="https://github.com/user-attachments/assets/e137a9e1-340a-4bf2-bb2b-771132780735" height=150>
<img src="https://github.com/user-attachments/assets/480f5e82-cf6a-4955-a869-0d73137aa6e1" height=150>
さらに、このプロジェクトの誕生は、以下のオープンソースプロジェクトの助けなしにはあり得ませんでした:
_✨ プラグインシステム - 一部のプラグインの展示 ✨_
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - 偉大な猫フレームワーク
<img src="https://github.com/user-attachments/assets/592a8630-14c7-4e06-b496-9c0386e4f36c" width="600">
オープンソースプロジェクトのフレンドリーリンク:
_✨ 管理パネル ✨_
![webchat](https://drive.soulter.top/f/vlsA/ezgif-5-fb044b2542.gif)
_✨ 内蔵 Web Chat、オンラインでボットと対話 ✨_
</div>
- [NoneBot2](https://github.com/nonebot/nonebot2) - 優れたPython非同期チャットボットフレームワーク
- [Koishi](https://github.com/koishijs/koishi) - 優れたNode.jsチャットボットフレームワーク
- [MaiBot](https://github.com/Mai-with-u/MaiBot) - 優れた擬人化AIチャットボット
- [nekro-agent](https://github.com/KroMiose/nekro-agent) - 優れたエージェントチャットボット
- [LangBot](https://github.com/langbot-app/LangBot) - 優れたマルチプラットフォームAIチャットボット
- [ChatLuna](https://github.com/ChatLunaLab/chatluna) - 優れたマルチプラットフォームAIチャットボットKoishiプラグイン
- [Operit AI](https://github.com/AAswordman/Operit) - 優れたAIインテリジェントアシスタントAndroidアプリ
## ⭐ Star History
> [!TIP]
> このプロジェクトがあなたの生活や仕事に役立った場合、またはこのプロジェクトの将来の発展に関心がある場合は、プロジェクトに Star を付けてください。これはこのオープンソースプロジェクトを維持するためのモチベーションです <3
> もしこのプロジェクトがあなたの生活や仕事の助けになったなら、あるいはこのプロジェクトの将来の発展に関心があるなら、プロジェクトにStarを付けてください。これは私たちがこのオープンソースプロジェクトを維持するための原動力となります <3
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=soulter/astrbot&type=Date)](https://star-history.com/#soulter/astrbot&Date)
[![Star History Chart](https://api.star-history.com/svg?repos=astrbotdevs/astrbot&type=Date)](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
## スポンサー
<div align="center">
[<img src="https://api.gitsponsors.com/api/badge/img?id=575865240" height="20">](https://api.gitsponsors.com/api/badge/link?p=XEpbdGxlitw/RbcwiTX93UMzNK/jgDYC8NiSzamIPMoKvG2lBFmyXhSS/b0hFoWlBBMX2L5X5CxTDsUdyvcIEHTOfnkXz47UNOZvMwyt5CzbYpq0SEzsSV1OJF1cCo90qC/ZyYKYOWedal3MhZ3ikw==)
## 免責事項
1. このプロジェクトは `AGPL-v3` オープンソースライセンスの下で保護されています。
2. このプロジェクトを使用する際は、現地の法律および規制を遵守してください。
<!-- ## ✨ ATRI [ベータテスト]
この機能はプラグインとしてロードされます。プラグインリポジトリのアドレス:[astrbot_plugin_atri](https://github.com/Soulter/astrbot_plugin_atri)
1. 《ATRI ~ My Dear Moments》の主人公 ATRI のキャラクターセリフを微調整データセットとして使用した `Qwen1.5-7B-Chat Lora` 微調整モデル。
2. 長期記憶
3. ミームの理解と返信
4. TTS
-->
_付き添いと能力は決して対立するものであってはなりません。私たちが創造したいのは、感情を理解し、寄り添いながらも、確実に仕事を遂行できるロボットです。_
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>

304
README_ru.md Normal file
View File

@@ -0,0 +1,304 @@
![AstrBot-Logo-Simplified](https://github.com/user-attachments/assets/ffd99b6b-3272-4682-beaa-6fe74250f7d9)
<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README.md">English</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh-TW.md">繁體中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ja.md">日本語</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_fr.md">Français</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a>
<div>
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=2" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br>
<div>
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://deepwiki.com/badge.svg" href="https://deepwiki.com/AstrBotDevs/AstrBot">
<a href="https://zread.ai/AstrBotDevs/AstrBot" target="_blank"><img src="https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff" alt="zread"/></a>
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?color=76bad9"/></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%20Plugins&label=%D0%9C%D0%B0%D1%80%D0%BA%D0%B5%D1%82%D0%BF%D0%BB%D0%B5%D0%B9%D1%81&cacheSeconds=3600">
<img src="https://gitcode.com/Soulter/AstrBot/star/badge.svg" href="https://gitcode.com/Soulter/AstrBot">
</div>
<br>
<a href="https://astrbot.app/">Главная</a>
<a href="https://astrbot.app/">Документация</a>
<a href="https://blog.astrbot.app/">Блог</a>
<a href="https://astrbot.featurebase.app/roadmap">Roadmap</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">Сообщить о проблеме</a>
<a href="mailto:community@astrbot.app">Email</a>
</div>
AstrBot — это универсальный агентский помощник для личных и групповых чатов с открытым исходным кодом. Он может быть развернут в десятках популярных мессенджеров, таких как QQ, Telegram, WeCom (Enterprise WeChat), Lark (Feishu), DingTalk, Slack и других. Кроме того, он имеет встроенный легковесный веб-интерфейс чата (ChatUI), похожий на OpenWebUI, создавая надежную и масштабируемую диалоговую интеллектуальную инфраструктуру для частных лиц, разработчиков и команд. Будь то личный AI-компаньон, интеллектуальная служба поддержки, автоматизированный помощник или корпоративная база знаний, AstrBot позволяет быстро создавать AI-приложения в рабочем процессе ваших платформ обмена мгновенными сообщениями.
![landingpage](https://github.com/user-attachments/assets/45fc5699-cddf-4e21-af35-13040706f6c0)
## Основные возможности
1. 💯 Бесплатно и с открытым исходным кодом.
2. ✨ Поддержка диалога с большими языковыми моделями (LLM), мультимодальность, Агенты, MCP, Навыки (Skills), База знаний, Персонализация, автоматическое сжатие диалога.
3. 🤖 Поддержка интеграции с платформами агентов, такими как Dify, Alibaba Bailian, Coze и др.
4. 🌐 Мультиплатформенность: поддержка QQ, WeCom, Lark, DingTalk, WeChat Official Account, Telegram, Slack и [других](#поддерживаемые-платформы-сообщений).
5. 📦 Расширение плагинами: доступно более 1000 плагинов для установки в один клик.
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html): Изолированная среда для безопасного выполнения любого кода, вызова Shell и повторного использования ресурсов на уровне сессии.
7. 💻 Поддержка WebUI.
8. 🌈 Поддержка Web ChatUI: встроенная прокси-песочница, веб-поиск и многое другое внутри ChatUI.
9. 🌐 Поддержка интернационализации (i18n).
<br>
<table align="center">
<tr align="center">
<th>💙 Ролевые игры и Эмоциональное общение</th>
<th>✨ Проактивный Агент</th>
<th>🚀 Общие агентские возможности</th>
<th>🧩 1000+ Плагинов сообщества</th>
</tr>
<tr>
<td align="center"><p align="center"><img width="984" height="1746" alt="99b587c5d35eea09d84f33e6cf6cfd4f" src="https://github.com/user-attachments/assets/89196061-3290-458d-b51f-afa178049f84" /></p></td>
<td align="center"><p align="center"><img width="976" height="1612" alt="c449acd838c41d0915cc08a3824025b1" src="https://github.com/user-attachments/assets/f75368b4-e022-41dc-a9e0-131c3e73e32e" /></p></td>
<td align="center"><p align="center"><img width="974" height="1732" alt="image" src="https://github.com/user-attachments/assets/e22a3968-87d7-4708-a7cd-e7f198c7c32e" /></p></td>
<td align="center"><p align="center"><img width="976" height="1734" alt="image" src="https://github.com/user-attachments/assets/0952b395-6b4a-432a-8a50-c294b7f89750" /></p></td>
</tr>
</table>
## Быстрый старт
### Развертывание в один клик
Для пользователей, которые хотят быстро протестировать AstrBot, знакомы с командной строкой и могут самостоятельно установить среду `uv`, мы рекомендуем метод развертывания в один клик с помощью `uv` ⚡️.
```bash
uv tool install astrbot
astrbot init # Выполните эту команду только в первый раз для инициализации среды
astrbot run # astrbot run --backend-only запускает только бэкенд сервис
# Установка версии для разработчиков (больше исправлений и новых функций, но менее стабильна; подходит для разработчиков)
uv tool install git+https://github.com/AstrBotDevs/AstrBot@dev
```
> Требуется установленный [uv](https://docs.astral.sh/uv/).
> [!NOTE]
> Для пользователей macOS: Из-за проверок безопасности macOS первый запуск команды `astrbot` может занять длительное время (около 10-20 секунд).
Обновление `astrbot`:
```bash
uv tool upgrade astrbot
```
### Развертывание через Docker
Для пользователей, знакомых с контейнерами и предпочитающих более стабильный метод развертывания, подходящий для производственных сред, мы рекомендуем использовать Docker / Docker Compose для развертывания AstrBot.
Пожалуйста, обратитесь к официальной документации [Развертывание AstrBot с помощью Docker](https://astrbot.app/deploy/astrbot/docker.html).
### Развертывание на RainYun
Для пользователей, которые хотят развернуть AstrBot в один клик и не хотят самостоятельно управлять серверами, мы рекомендуем облачный сервис развертывания в один клик от RainYun ☁️:
[![Deploy on RainYun](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-en.svg)](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### Развертывание настольного клиента
Для пользователей, желающих использовать AstrBot на рабочем столе и использовать ChatUI в качестве основного интерфейса, мы рекомендуем приложение AstrBot App.
Перейдите на [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) для загрузки и установки; этот метод предназначен для использования на рабочем столе и не рекомендуется для серверных сценариев.
### Развертывание через лаунчер
Также для настольных компьютеров, для пользователей, которым требуется быстрое развертывание и изоляция среды для нескольких экземпляров, мы рекомендуем AstrBot Launcher.
Перейдите на [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) для загрузки и установки.
### Развертывание на Replit
Развертывание на Replit поддерживается сообществом и подходит для онлайн-демонстраций и легких тестовых сценариев.
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
Метод AUR предназначен для пользователей Arch Linux, желающих установить AstrBot через системный менеджер пакетов.
Выполните приведенную ниже команду в терминале, чтобы установить пакет `astrbot-git`. После завершения установки вы сможете запустить его.
```bash
yay -S astrbot-git
```
**Другие методы развертывания**
Если вам требуется панельное управление или более кастомизированное развертывание, вы можете обратиться к [BT Panel](https://astrbot.app/deploy/astrbot/btpanel.html) (установка через магазин приложений BT Panel), [1Panel](https://astrbot.app/deploy/astrbot/1panel.html) (установка через магазин приложений 1Panel), [CasaOS](https://astrbot.app/deploy/astrbot/casaos.html) (визуальное развертывание для NAS / домашнего сервера) и [Ручное развертывание](https://astrbot.app/deploy/astrbot/cli.html) (полная пользовательская установка на основе исходного кода и `uv`).
## Поддерживаемые платформы сообщений
Подключите AstrBot к вашим любимым платформам чата.
| Платформа | Поддержка |
|---------|---------------|
| **QQ** | Официальная |
| **OneBot v11** | Официальная |
| **Telegram** | Официальная |
| **WeCom (Приложение & Смарт-бот)** | Официальная |
| **WeChat (Служба поддержки & Официальный аккаунт)** | Официальная |
| **Lark (Feishu)** | Официальная |
| **DingTalk** | Официальная |
| **Slack** | Официальная |
| **Discord** | Официальная |
| **LINE** | Официальная |
| **Satori** | Официальная |
| **Misskey** | Официальная |
| **Whatsapp (Скоро)** | Официальная |
| [**Matrix**](https://github.com/stevessr/astrbot_plugin_matrix_adapter) | Сообщество |
| [**KOOK**](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | Сообщество |
| [**VoceChat**](https://github.com/HikariFroya/astrbot_plugin_vocechat) | Сообщество |
## Поддерживаемые провайдеры моделей
| Провайдер | Тип |
|---------|---------------|
| Пользовательский | Любой сервис, совместимый с OpenAI API |
| OpenAI | LLM |
| Anthropic | LLM |
| Google Gemini | LLM |
| Moonshot AI | LLM |
| Zhipu AI | LLM |
| DeepSeek | LLM |
| Ollama (Локально) | LLM |
| LM Studio (Локально) | LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM (API шлюз, поддерживает все модели) |
| [Uyun AI](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM (API шлюз, поддерживает все модели) |
| [SiliconFlow](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM (API шлюз, поддерживает все модели) |
| [PPIO](https://ppio.com/user/register?invited_by=AIOONE) | LLM (API шлюз, поддерживает все модели) |
| [302.AI](https://share.302.ai/rr1M3l) | LLM (API шлюз, поддерживает все модели)|
| [TokenPony](https://www.tokenpony.cn/3YPyf) | LLM (API шлюз, поддерживает все модели)|
| ModelScope | LLM |
| OneAPI | LLM |
| Dify | Платформа LLMOps |
| Alibaba Bailian | Платформа LLMOps |
| Coze | Платформа LLMOps |
| OpenAI Whisper | Распознавание речи (STT) |
| SenseVoice | Распознавание речи (STT) |
| OpenAI TTS | Синтез речи (TTS) |
| Gemini TTS | Синтез речи (TTS) |
| GPT-Sovits-Inference | Синтез речи (TTS) |
| GPT-Sovits | Синтез речи (TTS) |
| FishAudio | Синтез речи (TTS) |
| Edge TTS | Синтез речи (TTS) |
| Alibaba Bailian TTS | Синтез речи (TTS) |
| Azure TTS | Синтез речи (TTS) |
| Minimax TTS | Синтез речи (TTS) |
| Volcengine TTS | Синтез речи (TTS) |
## ❤️ Sponsors
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
## ❤️ Вклад в проект
Мы приветствуем любые Issues и Pull Requests! Просто отправьте свои изменения в этот проект :)
### Как внести вклад
Вы можете внести свой вклад, просматривая проблемы (Issues) или помогая проверять PR (Pull Requests). Любая проблема или PR приветствуются для поощрения участия сообщества. Конечно, это всего лишь предложения, вы можете внести свой вклад любым способом. Для добавления новых функций, пожалуйста, сначала обсудите это через Issue.
Рекомендуется объединять функциональные PR в ветку `dev`, которая будет объединена с основной веткой (`main`) и выпущена как новая версия после тестирования изменений.
Для уменьшения конфликтов мы рекомендуем:
1. Создавайте рабочую ветку на основе ветки `dev`, избегайте работы напрямую в ветке `main`.
2. При отправке PR выбирайте ветку `dev` в качестве целевой.
3. Регулярно синхронизируйте ветку `dev` с локальной средой, чаще используйте `git pull`.
### Среда разработки
AstrBot использует `ruff` для форматирования и проверки кода.
```bash
git clone https://github.com/AstrBotDevs/AstrBot
git switch dev # Переключиться на ветку разработки
pip install pre-commit # или uv tool install pre-commit
pre-commit install
```
Рекомендуется использовать `uv` для локальной установки и тестирования:
```bash
uv tool install -e . --force
astrbot init
astrbot run
```
Отладка фронтенда:
```bash
astrbot run --backend-only
cd dashboard
bun install # или pnpm и т.д.
bun dev
```
### Группы QQ
- Группа 9: 1076659624 (Новая)
- Группа 10: 1078079676 (Новая)
- Группа 1: 322154837
- Группа 3: 630166526
- Группа 5: 822130018
- Группа 6: 753075035
- Группа 7: 743746109
- Группа 8: 1030353265
- Группа разработчиков (Неформальное общение): 975206796
- Группа разработчиков (Официальная): 1039761811
### Канал Discord
- [Discord](https://discord.gg/hAVk6tgV36)
## ❤️ Особая благодарность
Особая благодарность всем контрибьюторам и разработчикам плагинов за их вклад в AstrBot ❤️
<a href="https://github.com/AstrBotDevs/AstrBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot&max=200&columns=14" />
</a>
Кроме того, рождение этого проекта было бы невозможным без помощи следующих проектов с открытым исходным кодом:
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - Великий кошачий фреймворк
Дружественные ссылки на проекты с открытым исходным кодом:
- [NoneBot2](https://github.com/nonebot/nonebot2) - Отличный асинхронный фреймворк ChatBot на Python
- [Koishi](https://github.com/koishijs/koishi) - Отличный фреймворк ChatBot на Node.js
- [MaiBot](https://github.com/Mai-with-u/MaiBot) - Отличный антропоморфный AI ChatBot
- [nekro-agent](https://github.com/KroMiose/nekro-agent) - Отличный агентский ChatBot
- [LangBot](https://github.com/langbot-app/LangBot) - Отличный мультиплатформенный AI ChatBot
- [ChatLuna](https://github.com/ChatLunaLab/chatluna) - Отличный плагин мультиплатформенного AI ChatBot для Koishi
- [Operit AI](https://github.com/AAswordman/Operit) - Отличное Android-приложение интеллектуального AI-помощника
## ⭐ История звезд
> [!TIP]
> Если этот проект помог вам в жизни или работе, или если вы заинтересованы в будущем развитии этого проекта, пожалуйста, поставьте проекту звезду (Star). Это наша мотивация поддерживать этот проект с открытым исходным кодом <3
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=astrbotdevs/astrbot&type=Date)](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_Компаньонство и способности никогда не должны быть противоположностями. Мы надеемся создать робота, который сможет одновременно понимать эмоции, быть компаньоном и надежно выполнять работу._
_私は、高性能ですから!_ (Я высокопроизводительный!)
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>

304
README_zh-TW.md Normal file
View File

@@ -0,0 +1,304 @@
![AstrBot-Logo-Simplified](https://github.com/user-attachments/assets/ffd99b6b-3272-4682-beaa-6fe74250f7d9)
<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README.md">English</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ja.md">日本語</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_fr.md">Français</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ru.md">Русский</a>
<div>
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=2" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br>
<div>
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://deepwiki.com/badge.svg" href="https://deepwiki.com/AstrBotDevs/AstrBot">
<a href="https://zread.ai/AstrBotDevs/AstrBot" target="_blank"><img src="https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff" alt="zread"/></a>
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?color=76bad9"/></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%E5%80%8B&label=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%A0%B4&cacheSeconds=3600">
<img src="https://gitcode.com/Soulter/AstrBot/star/badge.svg" href="https://gitcode.com/Soulter/AstrBot">
</div>
<br>
<a href="https://astrbot.app/">首頁</a>
<a href="https://astrbot.app/">文檔</a>
<a href="https://blog.astrbot.app/">博客</a>
<a href="https://astrbot.featurebase.app/roadmap">路線圖</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">問題提交</a>
<a href="mailto:community@astrbot.app">Email</a>
</div>
AstrBot 是一個開源的一站式 Agentic 個人和群聊助手,可在 QQ、Telegram、企業微信、飛書、釘钉、Slack 等數十款主流即時通訊軟件上部署,此外還內置類似 OpenWebUI 的輕量化 ChatUI為個人、開發者和團隊打造可靠、可擴展的對話式智能基礎設施。無論是個人 AI 夥伴、智能客服、自動化助手還是企業知識庫AstrBot 都能在你的即時通訊軟件平台的工作流中快速構建 AI 應用。
![landingpage](https://github.com/user-attachments/assets/45fc5699-cddf-4e21-af35-13040706f6c0)
## 主要功能
1. 💯 免費 & 開源。
2. ✨ AI 大模型對話多模態AgentMCPSkills知識庫人格設定自動壓縮對話。
3. 🤖 支持接入 Dify、阿里雲百煉、Coze 等智能體平台。
4. 🌐 多平台,支持 QQ、企業微信、飛書、釘釘、微信公眾號、Telegram、Slack 以及[更多](#支持的消息平台)。
5. 📦 插件擴展,已有 1000+ 個插件可一鍵安裝。
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html) 隔離化環境,安全地執行任何代碼、調用 Shell、會話級資源複用。
7. 💻 WebUI 支持。
8. 🌈 Web ChatUI 支持ChatUI 內置代理沙盒、網頁搜索等。
9. 🌐 國際化i18n支持。
<br>
<table align="center">
<tr align="center">
<th>💙 角色扮演 & 情感陪伴</th>
<th>✨ 主動式 Agent</th>
<th>🚀 通用 Agentic 能力</th>
<th>🧩 1000+ 社區插件</th>
</tr>
<tr>
<td align="center"><p align="center"><img width="984" height="1746" alt="99b587c5d35eea09d84f33e6cf6cfd4f" src="https://github.com/user-attachments/assets/89196061-3290-458d-b51f-afa178049f84" /></p></td>
<td align="center"><p align="center"><img width="976" height="1612" alt="c449acd838c41d0915cc08a3824025b1" src="https://github.com/user-attachments/assets/f75368b4-e022-41dc-a9e0-131c3e73e32e" /></p></td>
<td align="center"><p align="center"><img width="974" height="1732" alt="image" src="https://github.com/user-attachments/assets/e22a3968-87d7-4708-a7cd-e7f198c7c32e" /></p></td>
<td align="center"><p align="center"><img width="976" height="1734" alt="image" src="https://github.com/user-attachments/assets/0952b395-6b4a-432a-8a50-c294b7f89750" /></p></td>
</tr>
</table>
## 快速開始
### 一鍵部署
對於想快速體驗 AstrBot、且熟悉命令行並能夠自行安裝 `uv` 環境的用戶,我們推薦使用 `uv` 一鍵部署方式 ⚡️。
```bash
uv tool install astrbot
astrbot init # 僅首次執行此命令以初始化環境
astrbot run # astrbot run --backend-only 僅啟動後端服務
# 安裝開發版本(更多修復,新功能,但不夠穩定,適合開發者)
uv tool install git+https://github.com/AstrBotDevs/AstrBot@dev
```
> 需要安裝 [uv](https://docs.astral.sh/uv/)。
> [!NOTE]
> 對於 macOS 用戶:由於 macOS 安全檢查,首次運行 `astrbot` 命令可能需要較長時間(約 10-20 秒)。
更新 `astrbot`
```bash
uv tool upgrade astrbot
```
### Docker 部署
對於熟悉容器、希望獲得更穩定且更適合生產環境部署方式的用戶,我們推薦使用 Docker / Docker Compose 部署 AstrBot。
請參考官方文檔 [使用 Docker 部署 AstrBot](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot)。
### 在 雨雲 上部署
對於希望一鍵部署 AstrBot 且不想自行管理服務器的用戶,我們推薦使用雨雲的一鍵雲部署服務 ☁️:
[![Deploy on RainYun](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-en.svg)](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### 桌面客戶端部署
對於希望在桌面端使用 AstrBot、並以 ChatUI 為主要入口的用戶,我們推薦使用 AstrBot App。
前往 [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) 下載並安裝;該方式面向桌面使用,不推薦服務器場景。
### 啟動器部署
同樣在桌面端,希望快速部署並實現環境隔離多開的用戶,我們推薦使用 AstrBot Launcher。
前往 [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) 下載並安裝。
### 在 Replit 上部署
Replit 部署由社區維護,適合在線演示和輕量試用場景。
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
AUR 方式面向 Arch Linux 用戶,適合希望通過系統包管理器安裝 AstrBot 的場景。
在終端執行下方命令安裝 `astrbot-git` 包,安裝完成後即可啟動使用。
```bash
yay -S astrbot-git
```
**更多部署方式**
若你需要面板化或更高自定義部署,可參考 [寶塔面板](https://astrbot.app/deploy/astrbot/btpanel.html)BT Panel 應用商店安裝)、[1Panel](https://astrbot.app/deploy/astrbot/1panel.html)1Panel 應用商店安裝)、[CasaOS](https://astrbot.app/deploy/astrbot/casaos.html)NAS / 家庭服務器可視化部署)和 [手動部署](https://astrbot.app/deploy/astrbot/cli.html)(基於源碼與 `uv` 的完整自定義安裝)。
## 支持的消息平台
將 AstrBot 連接到你常用的聊天平台。
| 平台 | 維護方 |
|---------|---------------|
| **QQ** | 官方維護 |
| **OneBot v11** | 官方維護 |
| **Telegram** | 官方維護 |
| **企微應用 & 企微智能機器人** | 官方維護 |
| **微信客服 & 微信公眾號** | 官方維護 |
| **飛書** | 官方維護 |
| **釘釘** | 官方維護 |
| **Slack** | 官方維護 |
| **Discord** | 官方維護 |
| **LINE** | 官方維護 |
| **Satori** | 官方維護 |
| **Misskey** | 官方維護 |
| **Whatsapp (將支持)** | 官方維護 |
| [**Matrix**](https://github.com/stevessr/astrbot_plugin_matrix_adapter) | 社區維護 |
| [**KOOK**](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | 社區維護 |
| [**VoceChat**](https://github.com/HikariFroya/astrbot_plugin_vocechat) | 社區維護 |
## 支持的模型提供商
| 提供商 | 類型 |
|---------|---------------|
| 自定義 | 任何 OpenAI API 兼容的服務 |
| OpenAI | LLM |
| Anthropic | LLM |
| Google Gemini | LLM |
| Moonshot AI | LLM |
| 智譜 AI | LLM |
| DeepSeek | LLM |
| Ollama (本地部署) | LLM |
| LM Studio (本地部署) | LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM (API 網關, 支持所有模型) |
| [優雲智算](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM (API 網關, 支持所有模型) |
| [硅基流動](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM (API 網關, 支持所有模型) |
| [PPIO 派歐雲](https://ppio.com/user/register?invited_by=AIOONE) | LLM (API 網關, 支持所有模型) |
| [302.AI](https://share.302.ai/rr1M3l) | LLM (API 網關, 支持所有模型)|
| [小馬算力](https://www.tokenpony.cn/3YPyf) | LLM (API 網關, 支持所有模型)|
| ModelScope | LLM |
| OneAPI | LLM |
| Dify | LLMOps 平台 |
| 阿里雲百煉應用 | LLMOps 平台 |
| Coze | LLMOps 平台 |
| OpenAI Whisper | 語音轉文本 |
| SenseVoice | 語音轉文本 |
| OpenAI TTS | 文本轉語音 |
| Gemini TTS | 文本轉語音 |
| GPT-Sovits-Inference | 文本轉語音 |
| GPT-Sovits | 文本轉語音 |
| FishAudio | 文本轉語音 |
| Edge TTS | 文本轉語音 |
| 阿里雲百煉 TTS | 文本轉語音 |
| Azure TTS | 文本轉語音 |
| Minimax TTS | 文本轉語音 |
| 火山引擎 TTS | 文本轉語音 |
## ❤️ Sponsors
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
## ❤️ 貢獻
歡迎任何 Issues/Pull Requests只需要將你的更改提交到此項目 :)
### 如何貢獻
你可以通過查看問題或幫助審核 PR拉取請求來貢獻。任何問題或 PR 都歡迎參與,以促進社區貢獻。當然,這些只是建議,你可以以任何方式進行貢獻。對於新功能的添加,請先通過 Issue 討論。
建議將功能性PR合併至dev分支將在測試修改後合併到主分支並發布新版本。
為了減少衝突,建議如下:
1. 工作分支最好基於 `dev` 分支創建,避免直接在 `main` 分支上工作。
2. 提交 PR 時,選擇 `dev` 分支作為目標分支。
3. 定期同步 `dev` 分支到本地多使用git pull。
### 開發環境
AstrBot 使用 `ruff` 進行代碼格式化和檢查。
```bash
git clone https://github.com/AstrBotDevs/AstrBot
git switch dev # 切換到開發分支
pip install pre-commit # 或者uv tool install pre-commit
pre-commit install
```
推薦使用uv本地安裝進行測試
```bash
uv tool install -e . --force
astrbot init
astrbot run
```
調試前端
```bash
astrbot run --backend-only
cd dashboard
bun install # 或者pnpm 等
bun dev
```
### QQ 群組
- 9 群: 1076659624 (新)
- 10 群: 1078079676 (新)
- 1 群322154837
- 3 群630166526
- 5 群822130018
- 6 群753075035
- 7 群743746109
- 8 群1030353265
- 開發者群偏閒聊吹水975206796
- 開發者群正式1039761811
### Discord 頻道
- [Discord](https://discord.gg/hAVk6tgV36)
## ❤️ Special Thanks
特別感謝所有 Contributors 和插件開發者對 AstrBot 的貢獻 ❤️
<a href="https://github.com/AstrBotDevs/AstrBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot&max=200&columns=14" />
</a>
此外,本項目的誕生離不開以下開源項目的幫助:
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - 偉大的貓貓框架
開源項目友情鏈接:
- [NoneBot2](https://github.com/nonebot/nonebot2) - 優秀的 Python 異步 ChatBot 框架
- [Koishi](https://github.com/koishijs/koishi) - 優秀的 Node.js ChatBot 框架
- [MaiBot](https://github.com/Mai-with-u/MaiBot) - 優秀的擬人化 AI ChatBot
- [nekro-agent](https://github.com/KroMiose/nekro-agent) - 優秀的 Agent ChatBot
- [LangBot](https://github.com/langbot-app/LangBot) - 優秀的多平台 AI ChatBot
- [ChatLuna](https://github.com/ChatLunaLab/chatluna) - 優秀的多平台 AI ChatBot Koishi 插件
- [Operit AI](https://github.com/AAswordman/Operit) - 優秀的 AI 智能助手 Android APP
## ⭐ Star History
> [!TIP]
> 如果本項目對您的生活 / 工作產生了幫助,或者您關注本項目的未來發展,請給項目 Star這是我們維護這個開源項目的動力 <3
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=astrbotdevs/astrbot&type=Date)](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_陪伴與能力從來不應該是對立面。我們希望創造的是一個既能理解情緒、給予陪伴,也能可靠完成工作的機器人。_
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>

304
README_zh.md Normal file
View File

@@ -0,0 +1,304 @@
![AstrBot-Logo-Simplified](https://github.com/user-attachments/assets/ffd99b6b-3272-4682-beaa-6fe74250f7d9)
<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README.md">English</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh-TW.md">繁體中文</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ja.md">日本語</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_fr.md">Français</a>
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ru.md">Русский</a>
<div>
<a href="https://trendshift.io/repositories/12875" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12875" alt="Soulter%2FAstrBot | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
<a href="https://hellogithub.com/repository/AstrBotDevs/AstrBot" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=d127d50cd5e54c5382328acc3bb25483&claim_uid=ZO9by7qCXgSd6Lp&t=2" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</div>
<br>
<div>
<img src="https://img.shields.io/github/v/release/AstrBotDevs/AstrBot?color=76bad9" href="https://github.com/AstrBotDevs/AstrBot/releases/latest">
<img src="https://img.shields.io/badge/python-3.10+-blue.svg" alt="python">
<img src="https://deepwiki.com/badge.svg" href="https://deepwiki.com/AstrBotDevs/AstrBot">
<a href="https://zread.ai/AstrBotDevs/AstrBot" target="_blank"><img src="https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff" alt="zread"/></a>
<a href="https://hub.docker.com/r/soulter/astrbot"><img alt="Docker pull" src="https://img.shields.io/docker/pulls/soulter/astrbot.svg?color=76bad9"/></a>
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.soulter.top%2Fastrbot%2Fplugin-num&query=%24.result&suffix=%E4%B8%AA&label=%E6%8F%92%E4%BB%B6%E5%B8%82%E5%9C%BA&cacheSeconds=3600">
<img src="https://gitcode.com/Soulter/AstrBot/star/badge.svg" href="https://gitcode.com/Soulter/AstrBot">
</div>
<br>
<a href="https://astrbot.app/">主页</a>
<a href="https://astrbot.app/">文档</a>
<a href="https://blog.astrbot.app/">博客</a>
<a href="https://astrbot.featurebase.app/roadmap">路线图</a>
<a href="https://github.com/AstrBotDevs/AstrBot/issues">问题提交</a>
<a href="mailto:community@astrbot.app">Email</a>
</div>
AstrBot 是一个开源的一站式 Agentic 个人和群聊助手,可在 QQ、Telegram、企业微信、飞书、钉钉、Slack、等数十款主流即时通讯软件上部署此外还内置类似 OpenWebUI 的轻量化 ChatUI为个人、开发者和团队打造可靠、可扩展的对话式智能基础设施。无论是个人 AI 伙伴、智能客服、自动化助手还是企业知识库AstrBot 都能在你的即时通讯软件平台的工作流中快速构建 AI 应用。
![landingpage](https://github.com/user-attachments/assets/45fc5699-cddf-4e21-af35-13040706f6c0)
## 主要功能
1. 💯 免费 & 开源。
2. ✨ AI 大模型对话多模态AgentMCPSkills知识库人格设定自动压缩对话。
3. 🤖 支持接入 Dify、阿里云百炼、Coze 等智能体平台。
4. 🌐 多平台,支持 QQ、企业微信、飞书、钉钉、微信公众号、Telegram、Slack 以及[更多](#支持的消息平台)。
5. 📦 插件扩展,已有 1000+ 个插件可一键安装。
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html) 隔离化环境,安全地执行任何代码、调用 Shell、会话级资源复用。
7. 💻 WebUI 支持。
8. 🌈 Web ChatUI 支持ChatUI 内置代理沙盒、网页搜索等。
9. 🌐 国际化i18n支持。
<br>
<table align="center">
<tr align="center">
<th>💙 角色扮演 & 情感陪伴</th>
<th>✨ 主动式 Agent</th>
<th>🚀 通用 Agentic 能力</th>
<th>🧩 1000+ 社区插件</th>
</tr>
<tr>
<td align="center"><p align="center"><img width="984" height="1746" alt="99b587c5d35eea09d84f33e6cf6cfd4f" src="https://github.com/user-attachments/assets/89196061-3290-458d-b51f-afa178049f84" /></p></td>
<td align="center"><p align="center"><img width="976" height="1612" alt="c449acd838c41d0915cc08a3824025b1" src="https://github.com/user-attachments/assets/f75368b4-e022-41dc-a9e0-131c3e73e32e" /></p></td>
<td align="center"><p align="center"><img width="974" height="1732" alt="image" src="https://github.com/user-attachments/assets/e22a3968-87d7-4708-a7cd-e7f198c7c32e" /></p></td>
<td align="center"><p align="center"><img width="976" height="1734" alt="image" src="https://github.com/user-attachments/assets/0952b395-6b4a-432a-8a50-c294b7f89750" /></p></td>
</tr>
</table>
## 快速开始
### 一键部署
对于想快速体验 AstrBot、且熟悉命令行并能够自行安装 `uv` 环境的用户,我们推荐使用 `uv` 一键部署方式 ⚡️。
```bash
uv tool install astrbot
astrbot init # 仅首次执行此命令以初始化环境
astrbot run # astrbot run --backend-only 仅启动后端服务
# 安装开发版本(更多修复,新功能,但不够稳定,适合开发者)
uv tool install git+https://github.com/AstrBotDevs/AstrBot@dev
```
> 需要安装 [uv](https://docs.astral.sh/uv/)。
> [!NOTE]
> 对于 macOS 用户:由于 macOS 安全检查,首次运行 `astrbot` 命令可能需要较长时间(约 10-20 秒)。
更新 `astrbot`
```bash
uv tool upgrade astrbot
```
### Docker 部署
对于熟悉容器、希望获得更稳定且更适合生产环境部署方式的用户,我们推荐使用 Docker / Docker Compose 部署 AstrBot。
请参考官方文档 [使用 Docker 部署 AstrBot](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot)。
### 在 雨云 上部署
对于希望一键部署 AstrBot 且不想自行管理服务器的用户,我们推荐使用雨云的一键云部署服务 ☁️:
[![Deploy on RainYun](https://rainyun-apps.cn-nb1.rains3.com/materials/deploy-on-rainyun-en.svg)](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### 桌面客户端部署
对于希望在桌面端使用 AstrBot、并以 ChatUI 为主要入口的用户,我们推荐使用 AstrBot App。
前往 [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) 下载并安装;该方式面向桌面使用,不推荐服务器场景。
### 启动器部署
同样在桌面端,希望快速部署并实现环境隔离多开的用户,我们推荐使用 AstrBot Launcher。
前往 [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) 下载并安装。
### 在 Replit 上部署
Replit 部署由社区维护,适合在线演示和轻量试用场景。
[![Run on Repl.it](https://repl.it/badge/github/AstrBotDevs/AstrBot)](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
AUR 方式面向 Arch Linux 用户,适合希望通过系统包管理器安装 AstrBot 的场景。
在终端执行下方命令安装 `astrbot-git` 包,安装完成后即可启动使用。
```bash
yay -S astrbot-git
```
**更多部署方式**
若你需要面板化或更高自定义部署,可参考 [宝塔面板](https://astrbot.app/deploy/astrbot/btpanel.html)BT Panel 应用商店安装)、[1Panel](https://astrbot.app/deploy/astrbot/1panel.html)1Panel 应用商店安装)、[CasaOS](https://astrbot.app/deploy/astrbot/casaos.html)NAS / 家庭服务器可视化部署)和 [手动部署](https://astrbot.app/deploy/astrbot/cli.html)(基于源码与 `uv` 的完整自定义安装)。
## 支持的消息平台
将 AstrBot 连接到你常用的聊天平台。
| 平台 | 维护方 |
|---------|---------------|
| **QQ** | 官方维护 |
| **OneBot v11** | 官方维护 |
| **Telegram** | 官方维护 |
| **企微应用 & 企微智能机器人** | 官方维护 |
| **微信客服 & 微信公众号** | 官方维护 |
| **飞书** | 官方维护 |
| **钉钉** | 官方维护 |
| **Slack** | 官方维护 |
| **Discord** | 官方维护 |
| **LINE** | 官方维护 |
| **Satori** | 官方维护 |
| **Misskey** | 官方维护 |
| **Whatsapp (将支持)** | 官方维护 |
| [**Matrix**](https://github.com/stevessr/astrbot_plugin_matrix_adapter) | 社区维护 |
| [**KOOK**](https://github.com/wuyan1003/astrbot_plugin_kook_adapter) | 社区维护 |
| [**VoceChat**](https://github.com/HikariFroya/astrbot_plugin_vocechat) | 社区维护 |
## 支持的模型提供商
| 提供商 | 类型 |
|---------|---------------|
| 自定义 | 任何 OpenAI API 兼容的服务 |
| OpenAI | LLM |
| Anthropic | LLM |
| Google Gemini | LLM |
| Moonshot AI | LLM |
| 智谱 AI | LLM |
| DeepSeek | LLM |
| Ollama (本地部署) | LLM |
| LM Studio (本地部署) | LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM (API 网关, 支持所有模型) |
| [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM (API 网关, 支持所有模型) |
| [硅基流动](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM (API 网关, 支持所有模型) |
| [PPIO 派欧云](https://ppio.com/user/register?invited_by=AIOONE) | LLM (API 网关, 支持所有模型) |
| [302.AI](https://share.302.ai/rr1M3l) | LLM (API 网关, 支持所有模型)|
| [小马算力](https://www.tokenpony.cn/3YPyf) | LLM (API 网关, 支持所有模型)|
| ModelScope | LLM |
| OneAPI | LLM |
| Dify | LLMOps 平台 |
| 阿里云百炼应用 | LLMOps 平台 |
| Coze | LLMOps 平台 |
| OpenAI Whisper | 语音转文本 |
| SenseVoice | 语音转文本 |
| OpenAI TTS | 文本转语音 |
| Gemini TTS | 文本转语音 |
| GPT-Sovits-Inference | 文本转语音 |
| GPT-Sovits | 文本转语音 |
| FishAudio | 文本转语音 |
| Edge TTS | 文本转语音 |
| 阿里云百炼 TTS | 文本转语音 |
| Azure TTS | 文本转语音 |
| Minimax TTS | 文本转语音 |
| 火山引擎 TTS | 文本转语音 |
## ❤️ Sponsors
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
## ❤️ 贡献
欢迎任何 Issues/Pull Requests只需要将你的更改提交到此项目 :)
### 如何贡献
你可以通过查看问题或帮助审核 PR拉取请求来贡献。任何问题或 PR 都欢迎参与,以促进社区贡献。当然,这些只是建议,你可以以任何方式进行贡献。对于新功能的添加,请先通过 Issue 讨论。
建议将功能性PR合并至dev分支将在测试修改后合并到主分支并发布新版本。
为了减少冲突,建议如下:
1. 工作分支最好基于 `dev` 分支创建,避免直接在 `main` 分支上工作。
2. 提交 PR 时,选择 `dev` 分支作为目标分支。
3. 定期同步 `dev` 分支到本地多使用git pull。
### 开发环境
AstrBot 使用 `ruff` 进行代码格式化和检查。
```bash
git clone https://github.com/AstrBotDevs/AstrBot
git switch dev # 切换到开发分支
pip install pre-commit # 或者uv tool install pre-commit
pre-commit install
```
推荐使用uv本地安装进行测试
```bash
uv tool install -e . --force
astrbot init
astrbot run
```
调试前端
```bash
astrbot run --backend-only
cd dashboard
bun install # 或者pnpm 等
bun dev
```
### QQ 群组
- 9 群: 1076659624 (新)
- 10 群: 1078079676 (新)
- 1 群322154837
- 3 群630166526
- 5 群822130018
- 6 群753075035
- 7 群743746109
- 8 群1030353265
- 开发者群偏闲聊吹水975206796
- 开发者群正式1039761811
### Discord 频道
- [Discord](https://discord.gg/hAVk6tgV36)
## ❤️ Special Thanks
特别感谢所有 Contributors 和插件开发者对 AstrBot 的贡献 ❤️
<a href="https://github.com/AstrBotDevs/AstrBot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=AstrBotDevs/AstrBot&max=200&columns=14" />
</a>
此外,本项目的诞生离不开以下开源项目的帮助:
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - 伟大的猫猫框架
开源项目友情链接:
- [NoneBot2](https://github.com/nonebot/nonebot2) - 优秀的 Python 异步 ChatBot 框架
- [Koishi](https://github.com/koishijs/koishi) - 优秀的 Node.js ChatBot 框架
- [MaiBot](https://github.com/Mai-with-u/MaiBot) - 优秀的拟人化 AI ChatBot
- [nekro-agent](https://github.com/KroMiose/nekro-agent) - 优秀的 Agent ChatBot
- [LangBot](https://github.com/langbot-app/LangBot) - 优秀的多平台 AI ChatBot
- [ChatLuna](https://github.com/ChatLunaLab/chatluna) - 优秀的多平台 AI ChatBot Koishi 插件
- [Operit AI](https://github.com/AAswordman/Operit) - 优秀的 AI 智能助手 Android APP
## ⭐ Star History
> [!TIP]
> 如果本项目对您的生活 / 工作产生了帮助,或者您关注本项目的未来发展,请给项目 Star这是我们维护这个开源项目的动力 <3
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=astrbotdevs/astrbot&type=Date)](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_陪伴与能力从来不应该是对立面。我们希望创造的是一个既能理解情绪、给予陪伴,也能可靠完成工作的机器人。_
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>

View File

@@ -1,3 +1,16 @@
from .core.log import LogManager
from __future__ import annotations
logger = LogManager.GetLogger(log_name="astrbot")
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from .core import logger as logger
__all__ = ["logger"]
def __getattr__(name: str) -> Any:
if name == "logger":
from .core import logger
return logger
raise AttributeError(name)

151
astrbot/__main__.py Normal file
View File

@@ -0,0 +1,151 @@
import argparse
import asyncio
import mimetypes
import os
import sys
from pathlib import Path
import anyio
from astrbot.core import LogBroker, LogManager, db_helper, logger
from astrbot.core.config.default import VERSION
from astrbot.core.initial_loader import InitialLoader
from astrbot.core.utils.astrbot_path import (
get_astrbot_config_path,
get_astrbot_data_path,
get_astrbot_knowledge_base_path,
get_astrbot_plugin_path,
get_astrbot_root,
get_astrbot_site_packages_path,
get_astrbot_skills_path,
get_astrbot_temp_path,
)
from astrbot.core.utils.io import (
download_dashboard,
get_dashboard_version,
)
from astrbot.runtime_bootstrap import initialize_runtime_bootstrap
initialize_runtime_bootstrap()
# 将父目录添加到 sys.path
sys.path.append(Path(__file__).parent.as_posix())
logo_tmpl = r"""
___ _______.___________..______ .______ ______ .___________.
/ \ / | || _ \ | _ \ / __ \ | |
/ ^ \ | (----`---| |----`| |_) | | |_) | | | | | `---| |----`
/ /_\ \ \ \ | | | / | _ < | | | | | |
/ _____ \ .----) | | | | |\ \----.| |_) | | `--' | | |
/__/ \__\ |_______/ |__| | _| `._____||______/ \______/ |__|
"""
def check_env() -> None:
# Python version check: require 3.12 or 3.13
if not (sys.version_info.major == 3 and sys.version_info.minor in (12, 13)):
sys.exit(1)
astrbot_root = get_astrbot_root()
if astrbot_root not in sys.path:
sys.path.insert(0, astrbot_root)
site_packages_path = get_astrbot_site_packages_path()
if site_packages_path not in sys.path:
sys.path.insert(0, site_packages_path)
os.makedirs(get_astrbot_config_path(), exist_ok=True)
os.makedirs(get_astrbot_plugin_path(), exist_ok=True)
os.makedirs(get_astrbot_temp_path(), exist_ok=True)
os.makedirs(get_astrbot_knowledge_base_path(), exist_ok=True)
os.makedirs(get_astrbot_skills_path(), exist_ok=True)
os.makedirs(site_packages_path, exist_ok=True)
# 针对问题 #181 的临时解决方案
mimetypes.add_type("text/javascript", ".js")
mimetypes.add_type("text/javascript", ".mjs")
mimetypes.add_type("application/json", ".json")
async def check_dashboard_files(webui_dir: str | None = None):
"""下载管理面板文件"""
# 指定webui目录
if webui_dir:
if await anyio.Path(webui_dir).exists():
logger.info(f"使用指定的 WebUI 目录: {webui_dir}")
return webui_dir
logger.warning(f"指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。")
data_dist_path = os.path.join(get_astrbot_data_path(), "dist")
if await anyio.Path(data_dist_path).exists():
v = await get_dashboard_version()
if v is not None:
# 存在文件
if v == f"v{VERSION}":
logger.info("WebUI 版本已是最新。")
else:
logger.warning(
f"检测到 WebUI 版本 ({v}) 与当前 AstrBot 版本 (v{VERSION}) 不符。",
)
return data_dist_path
logger.info(
"开始下载管理面板文件...高峰期(晚上)可能导致较慢的速度。如多次下载失败,请前往 https://github.com/AstrBotDevs/AstrBot/releases/latest 下载 dist.zip,并将其中的 dist 文件夹解压至 data 目录下。",
)
try:
await download_dashboard(version=f"v{VERSION}", latest=False)
except Exception as e:
logger.warning(
f"下载指定版本(v{VERSION})的管理面板文件失败: {e},尝试下载最新版本。"
)
try:
await download_dashboard(latest=True)
except Exception as e:
logger.critical(f"下载管理面板文件失败: {e}")
return None
logger.info("管理面板下载完成。")
return data_dist_path
async def main_async(webui_dir_arg: str | None, log_broker: LogBroker) -> None:
"""主异步入口"""
# 检查仪表板文件
webui_dir = await check_dashboard_files(webui_dir_arg)
if webui_dir is None:
logger.warning(
"管理面板文件检查失败,WebUI 功能将不可用。"
"请检查网络连接或手动指定 --webui-dir 参数。"
)
db = db_helper
# 打印 logo
logger.info(logo_tmpl)
core_lifecycle = InitialLoader(db, log_broker)
core_lifecycle.webui_dir = webui_dir
await core_lifecycle.start()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="AstrBot")
parser.add_argument(
"--webui-dir",
type=str,
help="指定 WebUI 静态文件目录路径",
default=None,
)
args = parser.parse_args()
check_env()
# 启动日志代理
log_broker = LogBroker()
LogManager.set_queue_handler(logger, log_broker)
# 只使用一次 asyncio.run()
asyncio.run(main_async(args.webui_dir, log_broker))

View File

@@ -0,0 +1,5 @@
"""
Astbot内部实现
外部模块请勿导入
"""

View File

@@ -0,0 +1,57 @@
"""
ABP (AstrBot Protocol) client - in-process star communication.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any
class BaseAstrbotAbpClient(ABC):
"""
ABP client: in-process star (plugin) communication.
Stars register themselves; client delegates calls to registered instances.
Subclass must implement:
- connect() -> None
- register_star(name, instance) -> None
- unregister_star(name) -> None
- call_star_tool(star, tool, args) -> Any
- shutdown() -> None
"""
@property
@abstractmethod
def connected(self) -> bool: ...
@abstractmethod
async def connect(self) -> None:
"""Lightweight: just sets connected=True."""
...
@abstractmethod
def register_star(self, star_name: str, star_instance: Any) -> None:
"""Add star to internal registry."""
...
@abstractmethod
def unregister_star(self, star_name: str) -> None:
"""Remove star from registry (idempotent)."""
...
@abstractmethod
async def call_star_tool(
self,
star_name: str,
tool_name: str,
arguments: dict[str, Any],
) -> Any:
"""Delegate to star_instance.call_tool(tool_name, arguments)."""
...
@abstractmethod
async def shutdown(self) -> None:
"""Set connected=False, cancel pending requests."""
...

View File

@@ -0,0 +1,66 @@
"""
ACP (AstrBot Communication Protocol) client.
Transport: TCP | Unix Socket
Messages: JSON with Content-Length header
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Any
class BaseAstrbotAcpClient(ABC):
"""
ACP client: connects to ACP servers via TCP or Unix socket.
Subclass must implement:
- connect() -> None
- connect_to_server(host, port) -> None
- connect_to_unix_socket(path) -> None
- call_tool(server, tool, args) -> Any
- send_notification(method, params) -> None
- shutdown() -> None
"""
@property
@abstractmethod
def connected(self) -> bool: ...
@abstractmethod
async def connect(self) -> None: ...
@abstractmethod
async def connect_to_server(self, host: str, port: int) -> None:
"""Connect via TCP."""
...
@abstractmethod
async def connect_to_unix_socket(self, socket_path: str) -> None:
"""Connect via Unix domain socket."""
...
@abstractmethod
async def call_tool(
self,
server_name: str,
tool_name: str,
arguments: dict[str, Any],
) -> Any:
"""Call tool on server, return result."""
...
@abstractmethod
async def send_notification(
self,
method: str,
params: dict[str, Any],
) -> None:
"""Send one-way notification."""
...
@abstractmethod
async def shutdown(self) -> None:
"""Close connection, cancel pending requests."""
...

View File

@@ -0,0 +1,68 @@
"""
ACP (AstrBot Communication Protocol) server.
Transport: TCP listening socket
Messages: JSON with Content-Length header
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from collections.abc import Callable
from typing import Any
class BaseAstrbotAcpServer(ABC):
"""
ACP server: listens for client connections, exposes tools.
Subclass must implement:
- start(host, port) -> None
- register_tool(name, handler) -> None
- register_notification_handler(name, handler) -> None
- broadcast_notification(method, params) -> None
- shutdown() -> None
"""
@property
@abstractmethod
def running(self) -> bool:
"""True if server is accepting connections."""
...
@abstractmethod
async def start(self, host: str = "127.0.0.1", port: int = 8765) -> None:
"""Bind and listen. Block until shutdown."""
...
@abstractmethod
def register_tool(
self,
name: str,
handler: Callable[..., Any],
) -> None:
"""Register async tool handler (receives params dict, returns result)."""
...
@abstractmethod
def register_notification_handler(
self,
name: str,
handler: Callable[..., Any],
) -> None:
"""Register async notification handler (receives params dict)."""
...
@abstractmethod
async def broadcast_notification(
self,
method: str,
params: dict[str, Any],
) -> None:
"""Send notification to all connected clients."""
...
@abstractmethod
async def shutdown(self) -> None:
"""Stop accepting, close all client connections."""
...

View File

@@ -0,0 +1,73 @@
"""
AstrBot Gateway - HTTP/WebSocket API server.
Built on FastAPI, provides:
- HTTP REST API (stats, inspector, config)
- WebSocket for real-time events
- Static file serving (dashboard)
- Authentication (JWT/API key)
"""
from __future__ import annotations
from abc import ABC, abstractmethod
class BaseAstrbotGateway(ABC):
"""
Gateway: HTTP/WebSocket server built on FastAPI.
┌─────────────────────────────────────────────────────────┐
│ FastAPI App │
├─────────────────────────────────────────────────────────┤
│ REST Endpoints WebSocket │
│ ├─ GET /api/stats ├─ /ws (connection manager)│
│ ├─ GET /api/inspector/* │ │
│ ├─ GET /api/memory/* │ │
│ └─ ... │ │
│ │
│ Middleware: CORS, Auth, Logging │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────┐
│ Orchestrator │
│ (owns protocol clients)│
└─────────────────────────┘
Routes (typical):
GET / → Dashboard static files
GET /api/stats → System statistics
GET /api/inspector/stars → List registered stars
WS /ws → WebSocket for real-time events
serve() Lifecycle:
1. Create FastAPI app
2. Register routes
3. Start WebSocket manager
4. Bind to host:port
5. Run ASGI server (uvicorn/hypercorn)
6. Block until shutdown
7. Close all connections
Subclass must implement:
- serve(): start server, block until shutdown
"""
@abstractmethod
async def serve(self) -> None:
"""
Start gateway server - blocks until shutdown.
Should:
1. Create FastAPI app with routes
2. Configure CORS, auth middleware
3. Start WebSocket connection manager
4. Bind to ASTRBOT_PORT (default 6185)
5. Run ASGI server
6. Handle graceful shutdown on SIGTERM/SIGINT
Raises:
OSError: address already in use
"""
...

View File

@@ -0,0 +1,352 @@
"""
AstrBot Orchestrator - core runtime lifecycle manager.
Architecture
============
┌─────────────────────────────────────────────────────┐
│ Orchestrator │
│ (owns lifecycle of all protocol clients + stars) │
└─────────────────────────────────────────────────────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ LSP │ │ MCP │ │ ACP │
│ Client │ │ Client │ │ Client │
└─────────┘ └─────────┘ └─────────┘
│ │ │
▼ ▼ ▼
LSP Servers MCP Servers ACP Services
┌─────────────────────────────────────────────────────┐
│ ABP Client │
│ (in-process star registry) │
└─────────────────────────────────────────────────────┘
┌─────────┐
│ Stars │
│(Plugins) │
└─────────┘
Lifecycle State Machine
=======================
States:
┌─────────┐
│ INIT │───► orchestrator created, clients not initialized
└────┬────┘
│ start()
┌─────────┐
│ RUNNING │◄─── run_loop() executing
└────┬────┘
│ shutdown()
┌──────────┐
│ SHUTDOWN │─── all clients closed, ready for GC
└──────────┘
Transitions:
INIT + start() ──► RUNNING
RUNNING + shutdown() ──► SHUTDOWN
For each protocol client, the orchestrator:
1. Creates instance in __init__
2. Calls connect() to initialize
3. Calls protocol-specific setup (connect_to_server, etc)
4. Manages via run_loop() heartbeat
5. Calls shutdown() on final cleanup
Star Registration Flow
=====================
orchestrator.register_star("my-star", MyStar())
┌───────────────────┐
│ ABP Client │
│ .register_star() │
└───────────────────┘
┌───────────────────┐
│ Internal dict │
{"my-star": obj} │
└───────────────────┘
Message Routing (conceptual)
===========================
External Tool Call
┌──────────────┐ list_tools() ┌──────────────┐
│ MCP Client │────────────────────►│ MCP Server │
└──────────────┘◄────────────────────└──────────────┘
│ tool result
┌──────────────┐ call_tool() ┌──────────────┐
│ ABP │────────────────────►│ Star │
│ Client │◄────────────────────└──────────────┘
└──────────────┘ tool result
Return to caller
run_loop() Responsibilities
===========================
while running:
│─ check LSP server health (ping/heartbeat)
│─ check MCP session status (reconnect if needed)
│─ check ACP client connections
│─ process any pending star notifications
│─ sleep(SLEEP_INTERVAL)
Shutdown Sequence
==================
shutdown()
├─ set _running = False
├─ LSP.shutdown()
│ └─ send "shutdown" request
│ └─ terminate subprocess
├─ ACP.shutdown()
│ └─ close TCP/Unix connections
├─ ABP.shutdown()
│ └─ cancel pending requests
└─ MCP.cleanup()
└─ close all sessions
└─ cleanup subprocesses
Exception Handling
==================
Each protocol client should:
- Catch connection errors
- Attempt reconnection with exponential backoff
- Log errors but don't crash run_loop
- Raise on irrecoverable failures
The orchestrator run_loop should:
- Catch CancelledError on shutdown
- Catch Exception and log (don't crash)
- Ensure cleanup runs in finally block
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from astrbot._internal.protocols.abp.client import AstrbotAbpClient
from astrbot._internal.protocols.acp.client import AstrbotAcpClient
from astrbot._internal.protocols.lsp.client import AstrbotLspClient
from astrbot._internal.protocols.mcp.client import McpClient
#: Default heartbeat interval for run_loop()
DEFAULT_SLEEP_INTERVAL: float = 5.0
class BaseAstrbotOrchestrator(ABC):
"""
Core runtime: owns lifecycle of all protocol clients and stars.
┌────────────────────────────────────────────────────────────┐
│ Protocol Clients (always present, never None after init) │
├────────────────────────────────────────────────────────────┤
│ lsp: Language Server Protocol │
│ Purpose: code completion, diagnostics, hover, etc │
│ Transport: stdio subprocess │
│ │
│ mcp: Model Context Protocol │
│ Purpose: external tool access │
│ Transport: stdio | SSE | HTTP │
│ │
│ acp: AstrBot Communication Protocol │
│ Purpose: inter-service communication │
│ Transport: TCP | Unix Socket │
│ │
│ abp: AstrBot Protocol │
│ Purpose: in-process star (plugin) communication │
│ Transport: direct method calls │
└────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ Star Registry │
├────────────────────────────────────────────────────────────┤
│ _stars: dict[str, Any] │
│ Stars are plugins registered by name │
│ ABP client delegates calls to registered stars │
└────────────────────────────────────────────────────────────┘
Subclass must implement:
- __init__(): create all protocol client instances
- run_loop(): main event loop (block until shutdown)
- register_star(name, instance): add to registry + ABP
- unregister_star(name): remove from registry + ABP
- shutdown(): clean up all clients
"""
#: LSP client for language intelligence
lsp: AstrbotLspClient
#: MCP client for external tools
mcp: McpClient
#: ACP client for inter-service communication
acp: AstrbotAcpClient
#: ABP client for in-process star communication
abp: AstrbotAbpClient
def __init__(self) -> None:
"""
Initialize orchestrator and all protocol clients.
After __init__, all clients exist but are not connected.
Call start() or run_loop() to begin operation.
Example:
class MyOrchestrator(BaseAstrbotOrchestrator):
def __init__(self):
self.lsp = AstrbotLspClient()
self.mcp = McpClient()
self.acp = AstrbotAcpClient()
self.abp = AstrbotAbpClient()
self._stars: dict[str, Any] = {}
self._running = False
"""
self._stars: dict[str, Any] = {}
self._running: bool = False
@property
def running(self) -> bool:
"""True if run_loop() is executing."""
return self._running
@abstractmethod
async def start(self) -> None:
"""
Initialize all protocol clients.
Called once before run_loop(). Should:
1. Call lsp.connect()
2. Call mcp.connect()
3. Call acp.connect()
4. Call abp.connect()
5. Set _running = True
Raises:
Exception: if any client fails to initialize
"""
...
@abstractmethod
async def run_loop(self) -> None:
"""
Main event loop - blocks until shutdown.
Execution:
self._running = True
try:
while self._running:
await self._heartbeat()
await anyio.sleep(DEFAULT_SLEEP_INTERVAL)
except asyncio.CancelledError:
pass # shutdown requested
finally:
self._running = False
_heartbeat() responsibilities:
- Check LSP server health (optional ping)
- Check MCP session status, reconnect if needed
- Check ACP connections
- Process any pending star notifications
Raises:
asyncio.CancelledError: when shutdown() called
Note:
Subclass defines _heartbeat() for periodic tasks.
This method only handles the loop control.
"""
...
@abstractmethod
async def register_star(self, name: str, star_instance: Any) -> None:
"""
Register a star (plugin) with the orchestrator.
Args:
name: Unique identifier for the star
instance: Star plugin instance (must have .call_tool() method)
Does:
self._stars[name] = star_instance
self.abp.register_star(name, star_instance)
Raises:
ValueError: if name already registered
"""
...
@abstractmethod
async def unregister_star(self, name: str) -> None:
"""
Unregister a star (plugin) from the orchestrator.
Args:
name: Identifier of star to remove
Does:
del self._stars[name]
self.abp.unregister_star(name)
Note:
Idempotent - does nothing if name not found.
"""
...
@abstractmethod
async def get_star(self, name: str) -> Any | None:
"""Get registered star by name. Returns None if not found."""
...
@abstractmethod
async def list_stars(self) -> list[str]:
"""Return list of registered star names."""
...
@abstractmethod
async def shutdown(self) -> None:
"""
Graceful shutdown of orchestrator and all clients.
Execution order:
1. self._running = False (stop run_loop)
2. await lsp.shutdown()
3. await acp.shutdown()
4. await abp.shutdown()
5. await mcp.cleanup()
Does NOT unregister stars - caller should do that first.
After shutdown, orchestrator is ready for garbage collection.
"""
...

View File

@@ -0,0 +1,114 @@
"""
LSP (Language Server Protocol) client.
Transport: stdio subprocess
Messages: JSON-RPC 2.0 with Content-Length header
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
pass
class LspMessage:
"""JSON-RPC 2.0 message."""
jsonrpc: str = "2.0"
id: int | str | None = None
method: str | None = None
params: dict[str, Any] | None = None
result: Any = None
error: dict[str, Any] | None = None
class LspRequest(LspMessage):
"""Outgoing request."""
def __init__(self, method: str, params: dict[str, Any] | None = None) -> None:
self.id = id(self)
self.method = method
self.params = params
class LspResponse(LspMessage):
"""Incoming response."""
class LspNotification(LspMessage):
"""Incoming notification (no id)."""
class BaseAstrbotLspClient(ABC):
"""
LSP client: connects to LSP servers via stdio subprocess.
Subclass must implement:
- connect() -> None
- connect_to_server(command, workspace_uri) -> None
- send_request(method, params) -> dict
- send_notification(method, params) -> None
- shutdown() -> None
"""
@property
@abstractmethod
def connected(self) -> bool:
"""True if connected to an LSP server."""
...
@abstractmethod
async def connect(self) -> None:
self._connected = False
...
@abstractmethod
async def connect_to_server(
self,
command: list[str],
workspace_uri: str,
) -> None:
"""
Start LSP server subprocess and complete handshake.
Steps:
1. Spawn subprocess with stdin/stdout pipes
2. Send initialize request
3. Wait for response
4. Send initialized notification
"""
...
@abstractmethod
async def send_request(
self,
method: str,
params: dict[str, Any] | None = None,
) -> Any:
"""
Send JSON-RPC request and return result.
Raises:
RuntimeError: not connected
Exception: server returned error
"""
...
@abstractmethod
async def send_notification(
self,
method: str,
params: dict[str, Any] | None = None,
) -> None:
"""
Send JSON-RPC notification (no response expected).
"""
...
@abstractmethod
async def shutdown(self) -> None:
"""Send shutdown, terminate subprocess, cleanup."""
...

View File

@@ -0,0 +1,95 @@
"""
MCP (Model Context Protocol) client.
Transport: stdio | SSE | streamable_http
Messages: JSON-RPC 2.0
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any, Literal, TypedDict
if TYPE_CHECKING:
pass
class McpServerConfig(TypedDict, total=False):
"""MCP server configuration."""
# Stdio transport
command: str
args: list[str]
env: dict[str, str]
cwd: str
# HTTP transport
url: str
headers: dict[str, str]
transport: Literal["sse", "streamable_http"]
class McpToolInfo(TypedDict):
"""MCP tool descriptor."""
name: str
description: str
inputSchema: dict[str, Any]
class BaseAstrbotMcpClient(ABC):
"""
MCP client: connects to MCP servers for external tools.
Subclass must implement:
- connect() -> None
- connect_to_server(config, name) -> None
- list_tools() -> list[McpToolInfo]
- call_tool(name, args, timeout) -> CallToolResult
- cleanup() -> None
"""
session: Any # mcp.ClientSession
@property
@abstractmethod
def connected(self) -> bool: ...
@abstractmethod
async def connect(self) -> None:
"""Initialize client session."""
...
@abstractmethod
async def connect_to_server(
self,
config: McpServerConfig,
name: str,
) -> None:
"""
Connect to MCP server.
Stdio: {"command": "python", "args": ["server.py"], "env": {...}}
HTTP: {"url": "https://...", "transport": "sse"}
"""
...
@abstractmethod
async def list_tools(self) -> list[McpToolInfo]:
"""Call tools/list and return tools."""
...
@abstractmethod
async def call_tool(
self,
name: str,
arguments: dict[str, Any],
read_timeout_seconds: int = 60,
) -> Any:
"""Call tools/call with reconnection support."""
...
@abstractmethod
async def cleanup(self) -> None:
"""Close all server connections."""
...

View File

@@ -0,0 +1,6 @@
"""Gateway module - FastAPI server for the dashboard backend."""
from .server import AstrbotGateway
from .ws_manager import WebSocketManager
__all__ = ["AstrbotGateway", "WebSocketManager"]

View File

@@ -0,0 +1,4 @@
"""
依赖注入
"""

View File

@@ -0,0 +1,248 @@
"""
AstrBot Gateway - FastAPI server for the dashboard backend.
Provides REST API endpoints and WebSocket connections for the frontend dashboard.
The gateway acts as the communication bridge between the dashboard and the orchestrator.
"""
from __future__ import annotations
import json
from contextlib import asynccontextmanager
from typing import TYPE_CHECKING, Any, cast
from astrbot import logger
from astrbot._internal.abc.base_astrbot_gateway import BaseAstrbotGateway
from astrbot._internal.abc.base_astrbot_orchestrator import BaseAstrbotOrchestrator
from astrbot._internal.geteway.ws_manager import WebSocketManager
if TYPE_CHECKING:
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
else:
try:
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
except ImportError:
logger.warning("FastAPI not installed, gateway unavailable.")
FastAPI = cast(Any, None)
WebSocket = cast(Any, None)
WebSocketDisconnect = cast(Any, None)
CORSMiddleware = cast(Any, None)
log = logger
class AstrbotGateway(BaseAstrbotGateway):
"""
FastAPI-based gateway server for AstrBot.
Handles:
- REST API endpoints for configuration and stats
- WebSocket connections for real-time communication
- CORS middleware for dashboard access
"""
def __init__(self, orchestrator: BaseAstrbotOrchestrator) -> None:
self.orchestrator = orchestrator
self.ws_manager = WebSocketManager()
self._app: FastAPI | None = None
self._host = "0.0.0.0"
self._port = 8765
async def serve(self) -> None:
"""
Start the gateway server.
Creates and runs a FastAPI application with WebSocket support.
"""
if FastAPI is None:
raise RuntimeError("FastAPI is not installed")
log.info(f"Starting AstrBot Gateway on {self._host}:{self._port}")
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
log.info("Gateway server started.")
yield
# Shutdown
await self.ws_manager.broadcast({"type": "server_shutdown"})
log.info("Gateway server stopped.")
self._app = FastAPI(
title="AstrBot Gateway",
description="Backend API for AstrBot dashboard",
version="1.0.0",
lifespan=lifespan,
)
# CORS middleware
self._app.add_middleware(
cast(Any, CORSMiddleware),
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
self._setup_routes()
# Run with uvicorn
import uvicorn
config = uvicorn.Config(
self._app,
host=self._host,
port=self._port,
log_level="info",
)
server = uvicorn.Server(config)
await server.serve()
def _setup_routes(self) -> None:
"""Set up API routes."""
if self._app is None:
return
from fastapi import APIRouter
# Health check
@self._app.get("/health")
async def health():
return {"status": "ok"}
# WebSocket endpoint
@self._app.websocket("/ws")
async def websocket_endpoint(ws: WebSocket):
await self.ws_manager.connect(ws)
try:
while True:
data = await ws.receive_text()
try:
message = json.loads(data)
response = await self._handle_ws_message(message)
if response:
await ws.send_json(response)
except json.JSONDecodeError:
await ws.send_json({"error": "Invalid JSON"})
except WebSocketDisconnect:
self.ws_manager.disconnect(ws)
# Stats router
stats_router = APIRouter(prefix="/api/stats", tags=["stats"])
@stats_router.get("/overview")
async def get_overview():
return await self._get_stats_overview()
self._app.include_router(stats_router)
# Inspector router
inspector_router = APIRouter(prefix="/api/inspector", tags=["inspector"])
@inspector_router.get("/stars")
async def list_stars():
return await self._list_stars()
@inspector_router.get("/stars/{star_name}")
async def get_star(star_name: str):
return await self._get_star_detail(star_name)
self._app.include_router(inspector_router)
# Memory router
memory_router = APIRouter(prefix="/api/memory", tags=["memory"])
@memory_router.get("/")
async def get_memory():
return await self._get_memory_info()
self._app.include_router(memory_router)
async def _handle_ws_message(
self, message: dict[str, Any]
) -> dict[str, Any] | None:
"""
Handle an incoming WebSocket message.
Args:
message: Parsed JSON message from the client
Returns:
Response message to send back, or None for no response
"""
msg_type = message.get("type")
data = message.get("data", {})
if msg_type == "ping":
return {"type": "pong", "data": {}}
if msg_type == "call_tool":
return await self._handle_call_tool(data)
if msg_type == "get_stars":
return {"type": "stars_list", "data": await self._list_stars()}
return {
"type": "error",
"data": {"message": f"Unknown message type: {msg_type}"},
}
async def _handle_call_tool(self, data: dict[str, Any]) -> dict[str, Any]:
"""Handle a tool call request via WebSocket."""
star_name = data.get("star")
tool_name = data.get("tool")
arguments = data.get("arguments", {})
if not star_name or not tool_name:
return {
"type": "tool_result",
"data": {"error": "Missing star or tool name"},
}
try:
result = await self.orchestrator.abp.call_star_tool(
star_name, tool_name, arguments
)
return {"type": "tool_result", "data": {"result": result}}
except Exception as e:
return {"type": "tool_result", "data": {"error": str(e)}}
async def _get_stats_overview(self) -> dict[str, Any]:
"""Get overview statistics."""
return {
"stars_count": len(self.orchestrator.abp._stars),
"lsp_connected": self.orchestrator.lsp._connected,
"mcp_sessions": getattr(self.orchestrator.mcp, "session", None) is not None,
"acp_clients": len(getattr(self.orchestrator.acp, "_clients", [])),
}
async def _list_stars(self) -> list[dict[str, Any]]:
"""List all registered stars."""
stars = []
for name in self.orchestrator.abp._stars:
stars.append({"name": name, "status": "active"})
return stars
async def _get_star_detail(self, star_name: str) -> dict[str, Any]:
"""Get details of a specific star."""
star = self.orchestrator.abp._stars.get(star_name)
if not star:
return {"error": f"Star '{star_name}' not found"}
return {"name": star_name, "status": "active"}
async def _get_memory_info(self) -> dict[str, Any]:
"""Get memory usage information."""
import gc
gc.collect()
return {
"gc_objects": len(gc.get_objects()),
"python_memory": "N/A", # Would need psutil for actual values
}
def set_listen_address(self, host: str, port: int) -> None:
"""Set the listen address for the gateway server."""
self._host = host
self._port = port

View File

@@ -0,0 +1,103 @@
"""
WebSocket connection manager for the AstrBot gateway.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, cast
import anyio
from astrbot import logger
if TYPE_CHECKING:
from fastapi import WebSocket
else:
try:
from fastapi import WebSocket
except ImportError:
logger.warning("FastAPI not installed, WebSocketManager unavailable.")
WebSocket = cast(Any, None)
log = logger
class WebSocketManager:
"""
Manages all active WebSocket connections.
Provides connection/disconnection handling and broadcast capabilities.
"""
def __init__(self) -> None:
self._connections: set[WebSocket] = set()
self._lock = anyio.Lock()
async def connect(self, websocket: WebSocket) -> None:
"""Accept and register a new WebSocket connection."""
await websocket.accept()
async with self._lock:
self._connections.add(websocket)
log.debug(f"WebSocket connected. Total: {len(self._connections)}")
async def disconnect(self, websocket: WebSocket) -> None:
"""Remove a WebSocket connection."""
async with self._lock:
self._connections.discard(websocket)
log.debug(f"WebSocket disconnected. Total: {len(self._connections)}")
async def send_json(self, websocket: WebSocket, data: dict[str, Any]) -> None:
"""
Send JSON data to a specific WebSocket.
Args:
websocket: Target WebSocket connection
data: Data to send (must be JSON-serializable)
"""
try:
await websocket.send_json(data)
except Exception as e:
log.warning(f"Failed to send to WebSocket: {e}")
await self.disconnect(websocket)
async def broadcast(self, data: dict[str, Any]) -> None:
"""
Broadcast JSON data to all connected WebSockets.
Args:
data: Data to broadcast (must be JSON-serializable)
"""
async with self._lock:
connections = list(self._connections)
for conn in connections:
try:
await conn.send_json(data)
except Exception as e:
log.warning(f"Failed to broadcast to WebSocket: {e}")
async with self._lock:
self._connections.discard(conn)
async def send_to(
self, websocket: WebSocket, message: str | dict[str, Any]
) -> None:
"""
Send a message to a specific WebSocket.
Args:
websocket: Target WebSocket connection
message: Message to send (string or dict)
"""
try:
if isinstance(message, str):
await websocket.send_text(message)
else:
await websocket.send_json(message)
except Exception as e:
log.warning(f"Failed to send to WebSocket: {e}")
await self.disconnect(websocket)
@property
def connection_count(self) -> int:
"""Return the number of active connections."""
return len(self._connections)

View File

@@ -0,0 +1,5 @@
"""ABP module - AstrBot Protocol client implementation (built-in plugin protocol)."""
from .client import AstrbotAbpClient
__all__ = ["AstrbotAbpClient"]

View File

@@ -0,0 +1,93 @@
"""
ABP (AstrBot Protocol) client implementation.
ABP is the built-in plugin protocol where the orchestrator acts as client
connecting to internal stars (plugins) embedded in the runtime.
"""
from __future__ import annotations
from typing import Any
from astrbot import logger
from astrbot._internal.abc.abp.base_astrbot_abp_client import BaseAstrbotAbpClient
log = logger
class AstrbotAbpClient(BaseAstrbotAbpClient):
"""
ABP client for communicating with internal stars (built-in plugins).
The orchestrator acts as the client, sending requests to and receiving
notifications from stars running within the same process.
"""
def __init__(self) -> None:
self._connected = False
self._stars: dict[str, Any] = {}
# Use a simple dict for pending requests; we avoid asyncio.Future here.
self._pending_requests: dict[str, Any] = {}
self._request_id = 0
@property
def connected(self) -> bool:
"""True if connected to stars registry."""
return self._connected
async def connect(self) -> None:
"""Connect to internal stars registry."""
log.debug("ABP client connecting to internal stars...")
self._connected = True
log.info("ABP client connected to internal stars registry.")
async def call_star_tool(
self, star_name: str, tool_name: str, arguments: dict[str, Any]
) -> Any:
"""
Call a tool on a registered star.
Args:
star_name: Name of the star (plugin)
tool_name: Name of the tool to call
arguments: Tool arguments
Returns:
Tool call result
"""
if not self._connected:
raise RuntimeError("ABP client is not connected")
star = self._stars.get(star_name)
if not star:
raise ValueError(f"Star '{star_name}' not found")
request_id = f"{self._request_id}"
self._request_id += 1
# No asyncio.Future used; store a placeholder entry for tracking if needed.
self._pending_requests[request_id] = None
try:
# Call the star's tool handler
result = await star.call_tool(tool_name, arguments)
return result
finally:
self._pending_requests.pop(request_id, None)
def register_star(self, star_name: str, star_instance: Any) -> None:
"""Register a star (plugin) with the ABP client."""
self._stars[star_name] = star_instance
log.debug(f"Star '{star_name}' registered with ABP client.")
def unregister_star(self, star_name: str) -> None:
"""Unregister a star from the ABP client."""
self._stars.pop(star_name, None)
log.debug(f"Star '{star_name}' unregistered from ABP client.")
async def shutdown(self) -> None:
"""Shutdown the ABP client connection."""
self._connected = False
# Clear any pending requests (no asyncio futures used in this implementation)
self._pending_requests.clear()
log.info("ABP client shut down.")

View File

@@ -0,0 +1,6 @@
"""ACP module - AstrBot Communication Protocol client and server implementations."""
from .client import AstrbotAcpClient
from .server import AstrbotAcpServer
__all__ = ["AstrbotAcpClient", "AstrbotAcpServer"]

View File

@@ -0,0 +1,220 @@
"""
ACP (AstrBot Communication Protocol) client implementation.
ACP is a client-server protocol for inter-service communication,
similar to MCP but designed specifically for AstrBot's architecture.
"""
from __future__ import annotations
import asyncio
import json
from typing import Any
from astrbot import logger
from astrbot._internal.abc.acp.base_astrbot_acp_client import BaseAstrbotAcpClient
log = logger
class AstrbotAcpClient(BaseAstrbotAcpClient):
"""
ACP client for communicating with ACP servers.
The orchestrator acts as an ACP client, connecting to external
ACP-compatible services.
"""
def __init__(self) -> None:
self._connected = False
self._reader: asyncio.StreamReader | None = None
self._writer: asyncio.StreamWriter | None = None
self._server_url: str | None = None
self._pending_requests: dict[str, asyncio.Future[dict[str, Any]]] = {}
self._request_id = 0
self._reader_task: asyncio.Task[None] | None = None
@property
def connected(self) -> bool:
"""True if connected to an ACP server."""
return self._connected
async def connect(self) -> None:
"""
Connect to configured ACP servers.
ACP servers can be accessed via TCP (host:port) or Unix socket.
"""
log.debug("ACP client connecting...")
# TODO: Load ACP server configurations
self._connected = True
log.info("ACP client initialized.")
async def connect_to_server(self, host: str, port: int) -> None:
"""
Connect to an ACP server via TCP.
Args:
host: Server hostname or IP
port: Server port
"""
self._server_url = f"{host}:{port}"
self._reader, self._writer = await asyncio.open_connection(host, port)
self._connected = True
# Start reading responses
self._reader_task = asyncio.create_task(self._read_messages())
log.info(f"ACP client connected to {self._server_url}")
async def connect_to_unix_socket(self, socket_path: str) -> None:
"""
Connect to an ACP server via Unix socket.
Args:
socket_path: Path to the Unix socket
"""
self._server_url = f"unix://{socket_path}"
self._reader, self._writer = await asyncio.open_unix_connection(socket_path)
self._connected = True
self._reader_task = asyncio.create_task(self._read_messages())
log.info(f"ACP client connected to {self._server_url}")
async def _read_messages(self) -> None:
"""Background task to read ACP messages."""
if not self._reader:
return
buffer = b""
while self._connected:
try:
data = await self._reader.read(4096)
if not data:
break
buffer += data
while True:
header_end = buffer.find(b"\n")
if header_end == -1:
break
try:
header = json.loads(buffer[:header_end].decode("utf-8"))
except json.JSONDecodeError:
buffer = buffer[header_end + 1 :]
continue
content_length = header.get("content-length", 0)
if (
content_length == 0
or len(buffer) < header_end + 1 + content_length
):
break
content = buffer[header_end + 1 : header_end + 1 + content_length]
buffer = buffer[header_end + 1 + content_length :]
message = json.loads(content.decode("utf-8"))
if "id" in message:
request_id = str(message["id"])
future = self._pending_requests.pop(request_id, None)
if future and not future.done():
if "error" in message:
future.set_exception(Exception(str(message["error"])))
else:
future.set_result(message.get("result", {}))
else:
await self._handle_notification(message)
except Exception as e:
if self._connected:
log.error(f"ACP read error: {e}")
break
async def _handle_notification(self, notification: dict[str, Any]) -> None:
"""Handle incoming ACP notifications."""
method = notification.get("method", "")
log.debug(f"ACP notification: {method}")
async def call_tool(
self, server_name: str, tool_name: str, arguments: dict[str, Any]
) -> Any:
"""
Call a tool on an ACP server.
Args:
server_name: Name of the ACP server
tool_name: Name of the tool to call
arguments: Tool arguments
Returns:
Tool call result
"""
if not self._connected:
raise RuntimeError("ACP client is not connected")
request_id = str(self._request_id)
self._request_id += 1
message = {
"jsonrpc": "2.0",
"id": request_id,
"method": f"{server_name}/{tool_name}",
"params": arguments,
}
future: asyncio.Future[dict[str, Any]] = asyncio.Future()
self._pending_requests[request_id] = future
await self._send_message(message)
return await future
async def _send_message(self, message: dict[str, Any]) -> None:
"""Send an ACP message."""
if not self._writer:
raise RuntimeError("ACP client not connected")
content = json.dumps(message)
header = json.dumps({"content-length": len(content)}) + "\n"
self._writer.write((header + content).encode())
await self._writer.drain()
async def send_notification(
self, method: str, params: dict[str, Any] | None = None
) -> None:
"""Send a one-way notification to the server."""
message = {
"jsonrpc": "2.0",
"method": method,
"params": params or {},
}
await self._send_message(message)
async def shutdown(self) -> None:
"""Shutdown the ACP client connection."""
self._connected = False
if self._reader_task:
self._reader_task.cancel()
try:
await self._reader_task
except asyncio.CancelledError:
pass
if self._writer:
self._writer.close()
try:
await self._writer.wait_closed()
except Exception:
pass
for future in self._pending_requests.values():
if not future.done():
future.cancel()
self._pending_requests.clear()
log.info("ACP client shut down.")

View File

@@ -0,0 +1,223 @@
"""
ACP (AstrBot Communication Protocol) server implementation.
ACP servers listen for connections from ACP clients and provide
services/tools to the orchestrator.
"""
from __future__ import annotations
import asyncio
import json
from collections.abc import Callable
from typing import Any
from astrbot import logger
from astrbot._internal.abc.acp.base_astrbot_acp_server import BaseAstrbotAcpServer
log = logger
class AstrbotAcpServer(BaseAstrbotAcpServer):
"""
ACP server for accepting connections from ACP clients.
ACP servers expose tools/notifications that can be called by clients.
"""
def __init__(self) -> None:
self._running = False
self._host: str = "127.0.0.1"
self._port: int = 8765
self._server: asyncio.Server | None = None
self._clients: set[tuple[asyncio.StreamReader, asyncio.StreamWriter]] = set()
self._tool_handlers: dict[str, Callable[..., Any]] = {}
self._notification_handlers: dict[str, Callable[..., Any]] = {}
def register_tool(self, name: str, handler: Callable[..., Any]) -> None:
"""
Register a tool handler.
Args:
name: Tool name
handler: Async callable that handles tool calls
"""
self._tool_handlers[name] = handler
log.debug(f"ACP server registered tool: {name}")
def register_notification_handler(
self, name: str, handler: Callable[..., Any]
) -> None:
"""
Register a notification handler.
Args:
name: Notification method name
handler: Async callable that handles notifications
"""
self._notification_handlers[name] = handler
log.debug(f"ACP server registered notification handler: {name}")
async def start(self, host: str = "127.0.0.1", port: int = 8765) -> None:
"""
Start the ACP server.
Args:
host: Host to bind to
port: Port to listen on
"""
self._host = host
self._port = port
self._server = await asyncio.start_server(
self._handle_client,
host=host,
port=port,
)
self._running = True
log.info(f"ACP server listening on {host}:{port}")
async def _handle_client(
self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
) -> None:
"""Handle an incoming ACP client connection."""
addr = writer.get_extra_info("peername")
log.debug(f"ACP client connected: {addr}")
self._clients.add((reader, writer))
buffer = b""
try:
while self._running:
try:
data = await reader.read(4096)
if not data:
break
buffer += data
while True:
header_end = buffer.find(b"\n")
if header_end == -1:
break
try:
header = json.loads(buffer[:header_end].decode("utf-8"))
except json.JSONDecodeError:
buffer = buffer[header_end + 1 :]
continue
content_length = header.get("content-length", 0)
if (
content_length == 0
or len(buffer) < header_end + 1 + content_length
):
break
content = buffer[
header_end + 1 : header_end + 1 + content_length
]
buffer = buffer[header_end + 1 + content_length :]
message = json.loads(content.decode("utf-8"))
response = await self._handle_message(message)
if response:
content = json.dumps(response)
resp_header = (
json.dumps({"content-length": len(content)}) + "\n"
)
writer.write(resp_header.encode() + content.encode())
await writer.drain()
except Exception as e:
log.error(f"ACP client error ({addr}): {e}")
break
finally:
self._clients.discard((reader, writer))
writer.close()
try:
await writer.wait_closed()
except Exception:
pass
log.debug(f"ACP client disconnected: {addr}")
async def _handle_message(self, message: dict[str, Any]) -> dict[str, Any] | None:
"""Handle an incoming ACP message."""
method = message.get("method", "")
msg_id = message.get("id")
params = message.get("params", {})
# Check if it's a notification (no id) or request (has id)
if msg_id is None:
# Notification
handler = self._notification_handlers.get(method)
if handler:
try:
await handler(params)
except Exception as e:
log.error(f"ACP notification handler error ({method}): {e}")
return None
# Request
result = None
error = None
handler = self._tool_handlers.get(method)
if handler:
try:
result = await handler(params)
except Exception as e:
error = str(e)
log.error(f"ACP tool handler error ({method}): {e}")
else:
error = f"Unknown method: {method}"
response: dict[str, Any] = {"jsonrpc": "2.0", "id": msg_id}
if error:
response["error"] = {"code": -32601, "message": error}
else:
response["result"] = result
return response
async def broadcast_notification(self, method: str, params: dict[str, Any]) -> None:
"""
Broadcast a notification to all connected clients.
Args:
method: Notification method name
params: Notification parameters
"""
message = {
"jsonrpc": "2.0",
"method": method,
"params": params,
}
content = json.dumps(message)
header = json.dumps({"content-length": len(content)}) + "\n"
data = header.encode() + content.encode()
for reader, writer in list(self._clients):
try:
writer.write(data)
await writer.drain()
except Exception as e:
log.warning(f"Failed to broadcast to client: {e}")
async def shutdown(self) -> None:
"""Shutdown the ACP server."""
self._running = False
if self._server:
self._server.close()
await self._server.wait_closed()
self._server = None
for reader, writer in list(self._clients):
writer.close()
try:
await writer.wait_closed()
except Exception:
pass
self._clients.clear()
log.info("ACP server shut down.")

View File

@@ -0,0 +1,5 @@
"""LSP module - Language Server Protocol client implementation."""
from .client import AstrbotLspClient
__all__ = ["AstrbotLspClient"]

View File

@@ -0,0 +1,243 @@
"""
LSP (Language Server Protocol) client implementation.
The orchestrator acts as an LSP client, connecting to LSP servers
that provide language intelligence features (completions, diagnostics, etc.).
"""
from __future__ import annotations
import json
from typing import Any
import anyio
from anyio.abc import ByteReceiveStream, ByteSendStream, Process
from astrbot import logger
from astrbot._internal.abc.lsp.base_astrbot_lsp_client import BaseAstrbotLspClient
log = logger
class AstrbotLspClient(BaseAstrbotLspClient):
"""
LSP client for communicating with LSP servers.
Implements the Microsoft Language Server Protocol for connecting to
external language intelligence services.
"""
def __init__(self) -> None:
self._connected = False
self._reader: ByteReceiveStream | None = None
self._writer: ByteSendStream | None = None
self._server_process: Process | None = None
self._pending_requests: dict[int, Any] = {}
self._request_id = 0
self._server_command: list[str] | None = None
# anyio TaskGroup handle for background readers
self._task_group: Any | None = None
@property
def connected(self) -> bool:
"""True if connected to an LSP server."""
return self._connected
async def connect(self) -> None:
"""
Connect to configured LSP servers.
LSP servers are typically stdio-based subprocesses. This method
establishes the communication channel.
"""
log.debug("LSP client connecting...")
# TODO: Load LSP server configurations and start subprocesses
# For now, mark as connected in idle mode
self._connected = True
log.info("LSP client initialized.")
async def connect_to_server(self, command: list[str], workspace_uri: str) -> None:
"""
Connect to an LSP server subprocess.
Args:
command: Command line to start the LSP server (e.g., ["python", "lsp_server.py"])
workspace_uri: Root URI of the workspace to serve
"""
log.debug(f"Starting LSP server: {' '.join(command)}")
self._server_process = await anyio.open_process(
command,
stdin=-1,
stdout=-1,
stderr=-1,
)
self._reader = self._server_process.stdout
self._writer = self._server_process.stdin
self._server_command = command
self._connected = True
# Start reading responses in background using anyio TaskGroup
# Create and enter a TaskGroup so the reader runs until we close it at shutdown.
self._task_group = anyio.create_task_group()
await self._task_group.__aenter__()
self._task_group.start_soon(self._read_responses)
# Send initialize request
await self.send_request(
"initialize",
{
"processId": None,
"rootUri": workspace_uri,
"capabilities": {},
},
)
# Send initialized notification
await self.send_notification("initialized", {})
log.info(f"LSP client connected to server: {command[0]}")
async def send_request(
self, method: str, params: dict[str, Any] | None = None
) -> Any:
"""Send an LSP request and wait for response."""
if not self._writer:
raise RuntimeError("LSP client not connected")
request_id = self._request_id
self._request_id += 1
message = {
"jsonrpc": "2.0",
"id": request_id,
"method": method,
"params": params or {},
}
# Use anyio.Event for request/response matching
response_event: anyio.Event = anyio.Event()
response_holder: dict[str, Any] = {}
async def set_response(response: dict[str, Any]) -> None:
response_holder["response"] = response
response_event.set()
self._pending_requests[request_id] = set_response
content = json.dumps(message)
headers = f"Content-Length: {len(content)}\r\n\r\n"
await self._writer.send((headers + content).encode())
# Wait for response with timeout
with anyio.move_on_after(30):
await response_event.wait()
if "response" in response_holder:
return response_holder["response"]
raise TimeoutError(f"LSP request {method} timed out")
async def send_notification(
self, method: str, params: dict[str, Any] | None = None
) -> None:
"""Send an LSP notification (no response expected)."""
if not self._writer:
raise RuntimeError("LSP client not connected")
message = {
"jsonrpc": "2.0",
"method": method,
"params": params or {},
}
content = json.dumps(message)
headers = f"Content-Length: {len(content)}\r\n\r\n"
await self._writer.send((headers + content).encode())
async def _read_responses(self) -> None:
"""Background task to read LSP responses."""
if not self._reader:
return
buffer = b""
try:
while self._connected:
try:
data = await self._reader.receive()
if not data:
break
buffer += data
while True:
# Parse Content-Length header
header_end = buffer.find(b"\r\n\r\n")
if header_end == -1:
break
header = buffer[:header_end].decode("utf-8")
content_length = 0
for line in header.split("\r\n"):
if line.startswith("Content-Length:"):
content_length = int(line.split(":")[1].strip())
if content_length == 0:
break
total_length = header_end + 4 + content_length
if len(buffer) < total_length:
break
content = buffer[header_end + 4 : total_length]
buffer = buffer[total_length:]
response = json.loads(content.decode("utf-8"))
# Handle response vs notification
if "id" in response:
request_id = response["id"]
handler = self._pending_requests.pop(request_id, None)
if handler:
await handler(response)
else:
# Notification (e.g., window/logMessage)
await self._handle_notification(response)
except anyio.EndOfStream:
break
except anyio.get_cancelled_exc_class():
# Task was cancelled via the TaskGroup cancel/exit during shutdown
pass
async def _handle_notification(self, notification: dict[str, Any]) -> None:
"""Handle incoming LSP notifications."""
method = notification.get("method", "")
log.debug(f"LSP notification: {method}")
async def shutdown(self) -> None:
"""Shutdown the LSP client."""
self._connected = False
if self._task_group:
try:
# Exit the TaskGroup, which cancels background tasks started within it
await self._task_group.__aexit__(None, None, None)
except anyio.get_cancelled_exc_class():
pass
self._task_group = None
if self._server_process:
try:
await self.send_notification("shutdown", {})
except Exception:
pass
self._server_process.terminate()
try:
with anyio.move_on_after(5):
await self._server_process.wait()
except Exception:
self._server_process.kill()
self._server_process = None
self._pending_requests.clear()
log.info("LSP client shut down.")

View File

@@ -0,0 +1,63 @@
"""MCP module - Model Context Protocol client and tool implementations.
This module provides MCP client functionality and MCP tool wrappers.
"""
import asyncio
from dataclasses import dataclass
from .client import McpClient
from .config import (
DEFAULT_MCP_CONFIG,
get_mcp_config_path,
load_mcp_config,
save_mcp_config,
)
from .tool import MCPTool
# Exceptions
class MCPInitError(Exception):
"""Base exception for MCP initialization failures."""
class MCPInitTimeoutError(asyncio.TimeoutError, MCPInitError):
"""Raised when MCP client initialization exceeds the configured timeout."""
class MCPAllServicesFailedError(MCPInitError):
"""Raised when all configured MCP services fail to initialize."""
class MCPShutdownTimeoutError(asyncio.TimeoutError):
"""Raised when MCP shutdown exceeds the configured timeout."""
def __init__(self, names: list[str], timeout: float) -> None:
self.names = names
self.timeout = timeout
message = f"MCP 服务关闭超时({timeout:g} 秒):{', '.join(names)}"
super().__init__(message)
@dataclass
class MCPInitSummary:
"""Summary of MCP initialization results."""
total: int
success: int
failed: list[str]
__all__ = [
"DEFAULT_MCP_CONFIG",
"MCPAllServicesFailedError",
"MCPInitError",
"MCPInitSummary",
"MCPInitTimeoutError",
"MCPShutdownTimeoutError",
"MCPTool",
"McpClient",
"get_mcp_config_path",
"load_mcp_config",
"save_mcp_config",
]

View File

@@ -0,0 +1,486 @@
"""MCP client implementation."""
import asyncio
import logging
import os
import sys
from contextlib import AsyncExitStack
from datetime import timedelta
from typing import Any, cast
from tenacity import (
before_sleep_log,
retry,
retry_if_exception_type,
stop_after_attempt,
wait_exponential,
)
from astrbot._internal.abc.mcp.base_astrbot_mcp_client import (
BaseAstrbotMcpClient,
McpServerConfig,
McpToolInfo,
)
from astrbot.core.utils.log_pipe import LogPipe
logger = logging.getLogger("astrbot")
try:
import anyio
import mcp
from mcp.client.sse import sse_client
except (ModuleNotFoundError, ImportError):
logger.warning(
"Warning: Missing 'mcp' dependency, MCP services will be unavailable."
)
try:
from mcp.client.streamable_http import streamablehttp_client
except (ModuleNotFoundError, ImportError):
logger.warning(
"Warning: Missing 'mcp' dependency or MCP library version too old, Streamable HTTP connection unavailable.",
)
class TenacityLogger:
"""Wraps a logging.Logger to satisfy tenacity's LoggerProtocol."""
__slots__ = ("_logger",)
_logger: logging.Logger
def __init__(self, logger: logging.Logger) -> None:
self._logger = logger
def log(
self,
level: int,
msg: str,
/,
*args: Any,
**kwargs: Any,
) -> None:
self._logger.log(level, msg, *args, **kwargs)
def _prepare_config(config: dict) -> dict:
"""Prepare configuration, handle nested format."""
if config.get("mcpServers"):
first_key = next(iter(config["mcpServers"]))
config = config["mcpServers"][first_key]
config.pop("active", None)
return config
def _prepare_stdio_env(config: dict) -> dict:
"""Preserve Windows executable resolution for stdio subprocesses."""
if sys.platform != "win32":
return config
pathext = os.environ.get("PATHEXT")
if not pathext:
return config
prepared = config.copy()
env = dict(prepared.get("env") or {})
env.setdefault("PATHEXT", pathext)
prepared["env"] = env
return prepared
async def _quick_test_mcp_connection(config: dict) -> tuple[bool, str]:
"""Quick test MCP server connectivity."""
import aiohttp
cfg = _prepare_config(config.copy())
url = cfg["url"]
headers = cfg.get("headers", {})
timeout = cfg.get("timeout", 10)
try:
if "transport" in cfg:
transport_type = cfg["transport"]
elif "type" in cfg:
transport_type = cfg["type"]
else:
raise Exception("MCP connection config missing transport or type field")
async with aiohttp.ClientSession() as session:
if transport_type == "streamable_http":
test_payload = {
"jsonrpc": "2.0",
"method": "initialize",
"id": 0,
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "test-client", "version": "1.2.3"},
},
}
async with session.post(
url,
headers={
**headers,
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
json=test_payload,
timeout=aiohttp.ClientTimeout(total=timeout),
) as response:
if response.status == 200:
return True, ""
return False, f"HTTP {response.status}: {response.reason}"
else:
async with session.get(
url,
headers={
**headers,
"Accept": "application/json, text/event-stream",
},
timeout=aiohttp.ClientTimeout(total=timeout),
) as response:
if response.status == 200:
return True, ""
return False, f"HTTP {response.status}: {response.reason}"
except asyncio.TimeoutError:
return False, f"Connection timeout: {timeout} seconds"
except Exception as e:
return False, f"{e!s}"
class McpClient(BaseAstrbotMcpClient):
def __init__(self) -> None:
# Initialize session and client objects
self.session: mcp.ClientSession | None = None
self.exit_stack = AsyncExitStack()
self._old_exit_stacks: list[AsyncExitStack] = [] # Track old stacks for cleanup
self.name: str | None = None
self.active: bool = True
self.tools: list[mcp.Tool] = []
self.server_errlogs: list[str] = []
self.running_event = anyio.Event()
self.process_pid: int | None = None
# Store connection config for reconnection
self._mcp_server_config: McpServerConfig | None = None
self._server_name: str | None = None
self._reconnect_lock = anyio.Lock() # Lock for thread-safe reconnection
self._reconnecting: bool = False # For logging and debugging
async def connect(self) -> None:
"""Initialize the MCP client connection.
Note: Actual server connections are made via connect_to_server().
This method prepares the client for use.
"""
# MCP client is initialized on-demand via connect_to_server
# This is a no-op stub to satisfy BaseAstrbotMcpClient
logger.debug("MCP client initialized.")
@property
def connected(self) -> bool:
"""True if MCP client has an active session."""
return self.session is not None
async def list_tools(self) -> list[McpToolInfo]:
"""List all tools from connected MCP servers."""
if not self.session:
return []
result = await self.list_tools_and_save()
tools = [
{
"name": tool.name,
"description": tool.description or "",
"inputSchema": tool.inputSchema,
}
for tool in result.tools
]
return cast(list[McpToolInfo], tools)
async def call_tool(
self,
name: str,
arguments: dict[str, Any],
read_timeout_seconds: int = 60,
) -> Any:
"""Call a tool on the MCP server with reconnection support."""
return await self.call_tool_with_reconnect(
tool_name=name,
arguments=arguments,
read_timeout_seconds=timedelta(seconds=read_timeout_seconds),
)
@staticmethod
def _extract_stdio_process_pid(streams_context: object) -> int | None:
"""Best-effort extraction for stdio subprocess PID used by lease cleanup.
TODO(refactor): replace this async-generator frame introspection with a
stable MCP library hook once the upstream transport exposes process PID.
"""
generator = getattr(streams_context, "gen", None)
frame = getattr(generator, "ag_frame", None)
if frame is None:
return None
process = frame.f_locals.get("process")
pid = getattr(process, "pid", None)
try:
return int(pid) if pid is not None else None
except (TypeError, ValueError):
return None
async def connect_to_server(self, config: McpServerConfig, name: str) -> None:
"""Connect to MCP server
If `url` parameter exists:
1. When transport is specified as `streamable_http`, use Streamable HTTP connection.
2. When transport is specified as `sse`, use SSE connection.
3. If not specified, default to SSE connection to MCP service.
Args:
config: Configuration for the MCP server. See https://modelcontextprotocol.io/quickstart/server
"""
# Store config for reconnection
self._mcp_server_config = config
self._server_name = name
self.process_pid = None
cfg = _prepare_config(dict(config))
def logging_callback(
msg: str | mcp.types.LoggingMessageNotificationParams,
) -> None:
# Handle MCP service error logs
if isinstance(msg, mcp.types.LoggingMessageNotificationParams):
if msg.level in ("warning", "error", "critical", "alert", "emergency"):
log_msg = f"[{msg.level.upper()}] {msg.data!s}"
self.server_errlogs.append(log_msg)
if "url" in cfg:
success, error_msg = await _quick_test_mcp_connection(cfg)
if not success:
raise Exception(error_msg)
if "transport" in cfg:
transport_type = cfg["transport"]
elif "type" in cfg:
transport_type = cfg["type"]
else:
raise Exception("MCP connection config missing transport or type field")
if transport_type != "streamable_http":
# SSE transport method
self._streams_context = sse_client(
url=cfg["url"],
headers=cfg.get("headers", {}),
timeout=cfg.get("timeout", 5),
sse_read_timeout=cfg.get("sse_read_timeout", 60 * 5),
)
streams = await self.exit_stack.enter_async_context(
self._streams_context,
)
# Create a new client session
read_timeout = timedelta(seconds=cfg.get("session_read_timeout", 60))
self.session = await self.exit_stack.enter_async_context(
mcp.ClientSession(
*streams,
read_timeout_seconds=read_timeout,
logging_callback=cast(Any, logging_callback),
),
)
else:
timeout = timedelta(seconds=cfg.get("timeout", 30))
sse_read_timeout = timedelta(
seconds=cfg.get("sse_read_timeout", 60 * 5),
)
self._streams_context = streamablehttp_client(
url=cfg["url"],
headers=cfg.get("headers", {}),
timeout=timeout,
sse_read_timeout=sse_read_timeout,
terminate_on_close=cfg.get("terminate_on_close", True),
)
read_s, write_s, _ = await self.exit_stack.enter_async_context(
self._streams_context,
)
# Create a new client session
read_timeout = timedelta(seconds=cfg.get("session_read_timeout", 60))
self.session = await self.exit_stack.enter_async_context(
mcp.ClientSession(
read_stream=read_s,
write_stream=write_s,
read_timeout_seconds=read_timeout,
logging_callback=logging_callback, # type: ignore
),
)
else:
cfg = _prepare_stdio_env(cfg)
server_params = mcp.StdioServerParameters(
**cfg,
)
def callback(msg: str | mcp.types.LoggingMessageNotificationParams) -> None:
# Handle MCP service error logs
if isinstance(msg, mcp.types.LoggingMessageNotificationParams):
if msg.level in (
"warning",
"error",
"critical",
"alert",
"emergency",
):
log_msg = f"[{msg.level.upper()}] {msg.data!s}"
self.server_errlogs.append(log_msg)
stdio_transport = await self.exit_stack.enter_async_context(
mcp.stdio_client(
server_params,
errlog=cast(
Any,
LogPipe(
level=logging.INFO,
logger=logger,
identifier=f"MCPServer-{name}",
callback=callback,
),
),
),
)
self.process_pid = self._extract_stdio_process_pid(stdio_transport)
# Create a new client session
self.session = await self.exit_stack.enter_async_context(
mcp.ClientSession(*stdio_transport),
)
await self.session.initialize()
async def list_tools_and_save(self) -> mcp.ListToolsResult:
"""List all tools from the server and save them to self.tools"""
if not self.session:
raise Exception("MCP Client is not initialized")
response = await self.session.list_tools()
self.tools = response.tools
return response
async def _reconnect(self) -> None:
"""Reconnect to the MCP server using the stored configuration.
Uses asyncio.Lock to ensure thread-safe reconnection in concurrent environments.
Raises:
Exception: raised when reconnection fails
"""
async with self._reconnect_lock:
# Check if already reconnecting (useful for logging)
if self._reconnecting:
logger.debug(
f"MCP Client {self._server_name} is already reconnecting, skipping"
)
return
if not self._mcp_server_config or not self._server_name:
raise Exception("Cannot reconnect: missing connection configuration")
self._reconnecting = True
try:
logger.info(
f"Attempting to reconnect to MCP server {self._server_name}..."
)
# Save old exit_stack for later cleanup (don't close it now to avoid cancel scope issues)
if self.exit_stack:
self._old_exit_stacks.append(self.exit_stack)
# Mark old session as invalid
self.session = None
# Create new exit stack for new connection
self.exit_stack = AsyncExitStack()
# Reconnect using stored config
await self.connect_to_server(self._mcp_server_config, self._server_name)
await self.list_tools_and_save()
logger.info(
f"Successfully reconnected to MCP server {self._server_name}"
)
except Exception as e:
logger.error(
f"Failed to reconnect to MCP server {self._server_name}: {e}"
)
raise
finally:
self._reconnecting = False
async def call_tool_with_reconnect(
self,
tool_name: str,
arguments: dict,
read_timeout_seconds: timedelta,
) -> mcp.types.CallToolResult:
"""Call MCP tool with automatic reconnection on failure, max 2 retries.
Args:
tool_name: tool name
arguments: tool arguments
read_timeout_seconds: read timeout
Returns:
MCP tool call result
Raises:
ValueError: MCP session is not available
anyio.ClosedResourceError: raised after reconnection failure
"""
@retry(
retry=retry_if_exception_type(anyio.ClosedResourceError),
stop=stop_after_attempt(2),
wait=wait_exponential(multiplier=1, min=1, max=3),
before_sleep=before_sleep_log(TenacityLogger(logger), logging.WARNING),
reraise=True,
)
async def _call_with_retry():
if not self.session:
raise ValueError("MCP session is not available for MCP function tools.")
try:
return await self.session.call_tool(
name=tool_name,
arguments=arguments,
read_timeout_seconds=read_timeout_seconds,
)
except anyio.ClosedResourceError:
logger.warning(
f"MCP tool {tool_name} call failed (ClosedResourceError), attempting to reconnect..."
)
# Attempt to reconnect
await self._reconnect()
# Reraise the exception to trigger tenacity retry
raise
return await _call_with_retry()
async def cleanup(self) -> None:
"""Clean up resources including old exit stacks from reconnections"""
# Close current exit stack
try:
await self.exit_stack.aclose()
except Exception as e:
logger.debug(f"Error closing current exit stack: {e}")
# Don't close old exit stacks as they may be in different task contexts
# They will be garbage collected naturally
# Just clear the list to release references
self._old_exit_stacks.clear()
# Set running_event first to unblock any waiting tasks
self.running_event.set()
self.process_pid = None

View File

@@ -0,0 +1,55 @@
"""MCP configuration management."""
import json
import os
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
DEFAULT_MCP_CONFIG = {"mcpServers": {}}
def get_mcp_config_path() -> str:
"""Get the path to the MCP configuration file."""
data_dir = get_astrbot_data_path()
return os.path.join(data_dir, "mcp_server.json")
def load_mcp_config() -> dict:
"""Load MCP configuration from file.
Returns:
MCP configuration dict. If file doesn't exist, returns default config.
"""
config_path = get_mcp_config_path()
if not os.path.exists(config_path):
# Create default config if not exists
os.makedirs(os.path.dirname(config_path), exist_ok=True)
with open(config_path, "w", encoding="utf-8") as f:
json.dump(DEFAULT_MCP_CONFIG, f, ensure_ascii=False, indent=4)
return DEFAULT_MCP_CONFIG
try:
with open(config_path, encoding="utf-8") as f:
return json.load(f)
except Exception:
return DEFAULT_MCP_CONFIG
def save_mcp_config(config: dict) -> bool:
"""Save MCP configuration to file.
Args:
config: MCP configuration dict to save.
Returns:
True if successful, False otherwise.
"""
config_path = get_mcp_config_path()
try:
with open(config_path, "w", encoding="utf-8") as f:
json.dump(config, f, ensure_ascii=False, indent=4)
return True
except Exception:
return False

View File

@@ -0,0 +1,45 @@
"""MCP tool wrapper."""
from datetime import timedelta
from typing import TYPE_CHECKING, Any
try:
import mcp
except (ModuleNotFoundError, ImportError):
mcp = None # type: ignore
from astrbot._internal.tools.base import FunctionTool
if TYPE_CHECKING:
from astrbot._internal.protocols.mcp.client import McpClient
class MCPTool(FunctionTool):
"""A function tool that calls an MCP service."""
def __init__(
self,
mcp_tool: "mcp.types.Tool",
mcp_client: "McpClient",
mcp_server_name: str,
**kwargs: Any,
) -> None:
super().__init__(
name=mcp_tool.name,
description=mcp_tool.description or "",
parameters=mcp_tool.inputSchema,
)
self.mcp_tool = mcp_tool
self.mcp_client = mcp_client
self.mcp_server_name = mcp_server_name
self.source = "mcp"
async def call(self, **kwargs: Any) -> Any:
"""Call the MCP tool with the given arguments."""
# Note: For actual usage, context.tool_call_timeout is needed
# but for simplicity we use a default timeout here
return await self.mcp_client.call_tool_with_reconnect(
tool_name=self.mcp_tool.name,
arguments=kwargs,
read_timeout_seconds=timedelta(seconds=60),
)

View File

@@ -0,0 +1,3 @@
from astrbot._internal.runtime.__main__ import bootstrap
__all__ = ["bootstrap"]

View File

@@ -0,0 +1,24 @@
from __future__ import annotations
import anyio
from astrbot._internal.abc.base_astrbot_gateway import BaseAstrbotGateway
from astrbot._internal.abc.base_astrbot_orchestrator import BaseAstrbotOrchestrator
from astrbot._internal.geteway.server import AstrbotGateway
from astrbot._internal.runtime.orchestrator import AstrbotOrchestrator
async def bootstrap():
orchestrator: BaseAstrbotOrchestrator = AstrbotOrchestrator()
gw: BaseAstrbotGateway = AstrbotGateway(orchestrator)
# anyio 的结构化并发
async with anyio.create_task_group() as tg:
tg.start_soon(orchestrator.lsp.connect) # 启动 LSP client
tg.start_soon(orchestrator.mcp.connect) # 启动 MCP client
tg.start_soon(orchestrator.acp.connect) # 启动 ACP client
tg.start_soon(orchestrator.abp.connect) # 启动 ABP client
await anyio.sleep(0.5)
tg.start_soon(orchestrator.run_loop) # 启动编排器循环
tg.start_soon(gw.serve) # 面板后端服务

View File

@@ -0,0 +1,164 @@
"""
AstrBot Orchestrator - core runtime that coordinates all protocol clients.
The orchestrator manages the lifecycle of LSP, MCP, ACP, and ABP clients,
and runs the main event loop that dispatches messages between components.
"""
from __future__ import annotations
from typing import Any
import anyio
from astrbot import logger
from astrbot._internal.abc.base_astrbot_orchestrator import BaseAstrbotOrchestrator
from astrbot._internal.protocols.abp.client import AstrbotAbpClient
from astrbot._internal.protocols.acp.client import AstrbotAcpClient
from astrbot._internal.protocols.lsp.client import AstrbotLspClient
from astrbot._internal.protocols.mcp.client import McpClient
from astrbot._internal.stars import RuntimeStatusStar
log = logger
class AstrbotOrchestrator(BaseAstrbotOrchestrator):
"""
Core runtime orchestrator for AstrBot.
Manages:
- LSP client: Language Server Protocol for editor integrations
- MCP client: Model Context Protocol for external tool servers
- ACP client: AstrBot Communication Protocol for inter-service communication
- ABP client: AstrBot Protocol for built-in star (plugin) communication
"""
def __init__(self) -> None:
# Initialize protocol clients (use concrete types for full method access)
self.lsp = AstrbotLspClient()
self.mcp = McpClient()
self.acp = AstrbotAcpClient()
self.abp = AstrbotAbpClient()
self._running = False
self._stars: dict[str, Any] = {}
self._message_count: int = 0
self._last_activity_timestamp: float | None = None
# Auto-register RuntimeStatusStar
self._runtime_status_star = RuntimeStatusStar()
self._runtime_status_star.set_orchestrator(self)
self._stars["runtime-status-star"] = self._runtime_status_star
self.abp.register_star("runtime-status-star", self._runtime_status_star)
log.debug("AstrbotOrchestrator initialized.")
async def start(self) -> None:
"""
Initialize all protocol clients.
Calls connect() on all protocol clients to prepare them for use.
"""
log.info("Starting AstrbotOrchestrator...")
await self.lsp.connect()
await self.mcp.connect()
await self.acp.connect()
await self.abp.connect()
self._running = True
log.info("AstrbotOrchestrator started.")
async def run_loop(self) -> None:
"""
Main orchestrator event loop.
This loop runs continuously, handling:
- Periodic health checks of protocol clients
- Message routing between protocols
- Star (plugin) lifecycle management
"""
self._running = True
log.info("AstrbotOrchestrator run loop started.")
stop_event = anyio.Event()
def set_stop() -> None:
stop_event.set()
# Store the callback for cleanup
self._stop_callback = set_stop
try:
while self._running:
# TODO: Periodic tasks:
# - Check LSP server health
# - Check MCP session status
# - Check ACP client connections
# - Process any pending star notifications
# Wait for 5 seconds or until shutdown is called
with anyio.move_on_after(5):
await stop_event.wait()
except anyio.get_cancelled_exc_class():
log.info("Orchestrator run loop cancelled.")
finally:
self._running = False
self._stop_callback = None
log.info("AstrbotOrchestrator run loop stopped.")
async def register_star(self, name: str, star_instance: Any) -> None:
"""
Register a star (plugin) with the orchestrator.
Args:
name: Unique name for the star
star_instance: Star plugin instance
"""
self._stars[name] = star_instance
self.abp.register_star(name, star_instance)
log.info(f"Star '{name}' registered.")
async def unregister_star(self, name: str) -> None:
"""
Unregister a star (plugin) from the orchestrator.
Args:
name: Name of the star to unregister
"""
self._stars.pop(name, None)
self.abp.unregister_star(name)
log.info(f"Star '{name}' unregistered.")
async def get_star(self, name: str) -> Any | None:
"""Get a registered star by name."""
return self._stars.get(name)
async def list_stars(self) -> list[str]:
"""List all registered star names."""
return list(self._stars.keys())
def record_activity(self) -> None:
"""Record a message activity for stats tracking."""
self._message_count += 1
import time
self._last_activity_timestamp = time.time()
async def shutdown(self) -> None:
"""
Shutdown the orchestrator and all protocol clients.
"""
log.info("Shutting down AstrbotOrchestrator...")
self._running = False
# Shutdown all protocol clients
await self.lsp.shutdown()
await self.acp.shutdown()
await self.abp.shutdown()
# MCP cleanup
await self.mcp.cleanup()
log.info("AstrbotOrchestrator shut down.")

View File

@@ -0,0 +1,18 @@
import sys
try:
from ._core import cli as _cli
def cli():
if len(sys.argv) == 1:
sys.argv.append("--help")
return _cli()
except ImportError:
from click import echo
def cli():
echo("""
AstrBot CLI(rust) is not available.
Developer: maturin dev
User: uv run astrbot-rs
""")

View File

@@ -0,0 +1,16 @@
from typing import Any
class AstrbotOrchestrator:
def start(self) -> None: ...
def stop(self) -> None: ...
def is_running(self) -> bool: ...
def register_star(self, name: str, handler: str) -> None: ...
def unregister_star(self, name: str) -> None: ...
def list_stars(self) -> list[str]: ...
def record_activity(self) -> None: ...
def get_stats(self) -> dict[str, Any]: ...
def set_protocol_connected(self, protocol: str, connected: bool) -> None: ...
def get_protocol_status(self, protocol: str) -> dict[str, Any] | None: ...
def get_orchestrator() -> AstrbotOrchestrator: ...
def cli() -> None: ...

View File

@@ -0,0 +1,13 @@
"""Internal skills module - re-exports from core.skills.skill_manager."""
from astrbot.core.skills.skill_manager import (
SkillInfo,
SkillManager,
build_skills_prompt,
)
__all__ = [
"SkillInfo",
"SkillManager",
"build_skills_prompt",
]

View File

@@ -0,0 +1,7 @@
"""
Stars (built-in plugins) for AstrBot runtime.
"""
from astrbot._internal.stars.runtime_status_star import RuntimeStatusStar
__all__ = ["RuntimeStatusStar"]

View File

@@ -0,0 +1,127 @@
"""
RuntimeStatusStar - ABP plugin that exposes core runtime internal state.
This star provides tools for querying:
- Runtime status (running state, uptime)
- Protocol client status (LSP, MCP, ACP, ABP)
- Registered stars registry
- Message counts and metrics
"""
from __future__ import annotations
import time
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any
@dataclass
class RuntimeStatusStar:
"""
ABP star that exposes core runtime internal state as callable tools.
Tools provided:
- get_runtime_status: Returns running state and uptime
- get_protocol_status: Returns LSP, MCP, ACP, ABP status
- get_star_registry: Returns registered star names
- get_stats: Returns message counts and metrics
"""
name: str = "runtime-status-star"
description: str = "ABP plugin that exposes core runtime internal state"
_start_time: float = field(default_factory=time.time, init=False)
_orchestrator: Any = field(default=None, init=False)
def set_orchestrator(self, orchestrator: Any) -> None:
"""Set the orchestrator reference for status queries."""
self._orchestrator = orchestrator
async def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> Any:
"""
Handle tool calls from ABP client.
Args:
tool_name: Name of the tool to call
arguments: Tool arguments
Returns:
Tool result
"""
if tool_name == "get_runtime_status":
return self._get_runtime_status()
elif tool_name == "get_protocol_status":
return await self._get_protocol_status()
elif tool_name == "get_star_registry":
return await self._get_star_registry()
elif tool_name == "get_stats":
return self._get_stats()
else:
raise ValueError(f"Unknown tool: {tool_name}")
def _get_runtime_status(self) -> dict[str, Any]:
"""Get overall runtime state."""
running = (
getattr(self._orchestrator, "running", False)
if self._orchestrator
else False
)
uptime_seconds = time.time() - self._start_time
return {
"running": running,
"uptime_seconds": uptime_seconds,
}
async def _get_protocol_status(self) -> dict[str, Any]:
"""Get status of each protocol client."""
if not self._orchestrator:
return {
"lsp": {"connected": False, "name": "lsp-client"},
"mcp": {"connected": False, "name": "mcp-client"},
"acp": {"connected": False, "name": "acp-client"},
"abp": {"connected": False, "name": "abp-client"},
}
return {
"lsp": {
"connected": getattr(self._orchestrator.lsp, "connected", False),
"name": "lsp-client",
},
"mcp": {
"connected": getattr(self._orchestrator.mcp, "connected", False),
"name": "mcp-client",
},
"acp": {
"connected": getattr(self._orchestrator.acp, "connected", False),
"name": "acp-client",
},
"abp": {
"connected": getattr(self._orchestrator.abp, "connected", False),
"name": "abp-client",
},
}
async def _get_star_registry(self) -> dict[str, Any]:
"""Get list of registered stars."""
if not self._orchestrator:
return {"stars": []}
stars = await self._orchestrator.list_stars()
return {"stars": stars}
def _get_stats(self) -> dict[str, Any]:
"""Get message counts and metrics."""
result: dict[str, Any] = {
"uptime_seconds": time.time() - self._start_time,
}
if self._orchestrator:
result["total_messages"] = getattr(self._orchestrator, "_message_count", 0)
last_ts = getattr(self._orchestrator, "_last_activity_timestamp", None)
if last_ts is not None:
result["last_activity"] = datetime.fromtimestamp(
last_ts, tz=timezone.utc
).isoformat()
else:
result["last_activity"] = None
return result

View File

@@ -0,0 +1,5 @@
"""Internal tools module for AstrBot runtime."""
from .base import FunctionTool, ToolSet
__all__ = ["FunctionTool", "ToolSet"]

View File

@@ -0,0 +1,332 @@
"""Base tool classes for AstrBot internal runtime.
This module provides the FunctionTool base class used by MCP tools
in the new internal architecture.
"""
import copy
from collections.abc import AsyncGenerator, Awaitable, Callable, Iterator
from dataclasses import dataclass, field
from typing import Any
from pydantic import model_validator
ParametersType = dict[str, Any]
@dataclass
class ToolSchema:
"""A class representing the schema of a tool for function calling."""
name: str
"""The name of the tool."""
description: str
"""The description of the tool."""
parameters: ParametersType = field(default_factory=dict)
"""The parameters of the tool, in JSON Schema format."""
@model_validator(mode="after")
def validate_parameters(self) -> "ToolSchema":
"""Validate the parameters JSON schema."""
import jsonschema
jsonschema.validate(
self.parameters, jsonschema.Draft202012Validator.META_SCHEMA
)
return self
@dataclass
class FunctionTool(ToolSchema):
"""A callable tool, for function calling."""
handler: Callable[..., Awaitable[str | None] | AsyncGenerator[Any, None]] | None = (
None
)
"""a callable that implements the tool's functionality. It should be an async function."""
handler_module_path: str | None = None
"""
The module path of the handler function. This is empty when the origin is mcp.
This field must be retained, as the handler will be wrapped in functools.partial during initialization,
causing the handler's __module__ to be functools
"""
active: bool = True
"""
Whether the tool is active. This field is a special field for AstrBot.
You can ignore it when integrating with other frameworks.
"""
is_background_task: bool = False
"""
Declare this tool as a background task. Background tasks return immediately
with a task identifier while the real work continues asynchronously.
"""
source: str = "mcp"
"""
Origin of this tool: 'plugin' (from star plugins), 'internal' (AstrBot built-in),
or 'mcp' (from MCP servers). Used by WebUI for display grouping.
"""
def __repr__(self) -> str:
return f"FuncTool(name={self.name}, parameters={self.parameters}, description={self.description})"
async def call(self, **kwargs: Any) -> Any:
"""Run the tool with the given arguments. The handler field has priority."""
raise NotImplementedError(
"FunctionTool.call() must be implemented by subclasses or set a handler."
)
class ToolSet:
"""
A collection of FunctionTools grouped under a namespace.
ToolSets allow organizing related tools together. The LLM sees tools
as "namespace/tool_name" when calling.
"""
def __init__(self, namespace: str, tools: list[FunctionTool] | None = None) -> None:
self.namespace = namespace
self._tools: dict[str, FunctionTool] = {}
if tools:
for tool in tools:
self.add(tool)
def add(self, tool: FunctionTool) -> None:
"""Add a tool to the set."""
self._tools[tool.name] = tool
def add_tool(self, tool: FunctionTool) -> None:
"""Add a tool to the set (alias for add())."""
self.add(tool)
def remove(self, name: str) -> FunctionTool | None:
"""Remove and return a tool by name."""
return self._tools.pop(name, None)
def remove_tool(self, name: str) -> None:
"""Remove a tool by its name."""
self._tools.pop(name, None)
def get(self, name: str) -> FunctionTool | None:
"""Get a tool by name."""
return self._tools.get(name)
def get_tool(self, name: str) -> FunctionTool | None:
"""Get a tool by name (alias for get)."""
return self.get(name)
def list_tools(self) -> list[FunctionTool]:
"""List all tools in this set."""
return list(self._tools.values())
def __iter__(self) -> Iterator[FunctionTool]:
return iter(self._tools.values())
def __len__(self) -> int:
return len(self._tools)
def __bool__(self) -> bool:
return bool(self._tools)
def __repr__(self) -> str:
return f"ToolSet(namespace={self.namespace!r}, tools={self.list_tools()!r})"
def __str__(self) -> str:
return f"ToolSet({self.namespace}, {len(self)} tools)"
def names(self) -> list[str]:
"""Get names of all tools in this set."""
return [tool.name for tool in self.tools]
def empty(self) -> bool:
"""Check if the tool set is empty."""
return len(self) == 0
def merge(self, other: "ToolSet") -> None:
"""Merge another ToolSet into this one."""
for tool in other.tools:
self.add(tool)
def normalize(self) -> None:
"""Sort tools by name for deterministic serialization."""
self._tools = dict(sorted(self._tools.items(), key=lambda x: x[0]))
def get_light_tool_set(self) -> "ToolSet":
"""Return a light tool set with only name/description."""
light_tools = []
for tool in self.tools:
if hasattr(tool, "active") and not tool.active:
continue
light_tools.append(
FunctionTool(
name=tool.name,
description=tool.description,
parameters={"type": "object", "properties": {}},
handler=None,
)
)
return ToolSet("default", light_tools)
def get_param_only_tool_set(self) -> "ToolSet":
"""Return a tool set with name/parameters only (no description)."""
param_tools = []
for tool in self.tools:
if hasattr(tool, "active") and not tool.active:
continue
params = (
copy.deepcopy(tool.parameters)
if tool.parameters
else {"type": "object", "properties": {}}
)
param_tools.append(
FunctionTool(
name=tool.name,
description="",
parameters=params,
handler=None,
)
)
return ToolSet("default", param_tools)
@property
def tools(self) -> list[FunctionTool]:
"""List all tools in this set."""
return list(self._tools.values())
def openai_schema(
self, omit_empty_parameter_field: bool = False
) -> list[dict[str, Any]]:
"""Convert tools to OpenAI API function calling schema format."""
result: list[dict[str, Any]] = []
for tool in self._tools.values():
func_def: dict[str, Any] = {
"type": "function",
"function": {"name": tool.name},
}
if tool.description:
func_def["function"]["description"] = tool.description
if tool.parameters is not None:
if (
tool.parameters.get("properties")
) or not omit_empty_parameter_field:
func_def["function"]["parameters"] = tool.parameters
result.append(func_def)
return result
def anthropic_schema(self) -> list[dict]:
"""Convert tools to Anthropic API format."""
result = []
for tool in self.tools:
input_schema: dict[str, Any] = {"type": "object"}
if tool.parameters:
input_schema["properties"] = tool.parameters.get("properties", {})
input_schema["required"] = tool.parameters.get("required", [])
tool_def: dict[str, Any] = {"name": tool.name, "input_schema": input_schema}
if tool.description:
tool_def["description"] = tool.description
result.append(tool_def)
return result
def google_schema(self) -> dict:
"""Convert tools to Google GenAI API format."""
def convert_schema(schema: dict) -> dict:
supported_types = {
"string",
"number",
"integer",
"boolean",
"array",
"object",
"null",
}
supported_formats = {
"string": {"enum", "date-time"},
"integer": {"int32", "int64"},
"number": {"float", "double"},
}
if "anyOf" in schema:
return {"anyOf": [convert_schema(s) for s in schema["anyOf"]]}
result = {}
origin_type = schema.get("type")
target_type = origin_type
if isinstance(origin_type, list):
target_type = next((t for t in origin_type if t != "null"), "string")
if target_type in supported_types:
result["type"] = target_type
if "format" in schema and schema["format"] in supported_formats.get(result["type"], set()):
result["format"] = schema["format"]
else:
result["type"] = "null"
support_fields = {
"title",
"description",
"enum",
"minimum",
"maximum",
"maxItems",
"minItems",
"nullable",
"required",
}
result.update({k: schema[k] for k in support_fields if k in schema})
if "properties" in schema:
properties = {}
for key, value in schema["properties"].items():
prop_value = convert_schema(value)
if "default" in prop_value:
del prop_value["default"]
if "additionalProperties" in prop_value:
del prop_value["additionalProperties"]
properties[key] = prop_value
if properties:
result["properties"] = properties
if target_type == "array":
items_schema = schema.get("items")
if isinstance(items_schema, dict):
result["items"] = convert_schema(items_schema)
else:
result["items"] = {"type": "string"}
return result
tools_list = []
for tool in self.tools:
d: dict[str, Any] = {"name": tool.name}
if tool.description:
d["description"] = tool.description
if tool.parameters:
d["parameters"] = convert_schema(tool.parameters)
tools_list.append(d)
declarations: dict[str, Any] = {}
if tools_list:
declarations["function_declarations"] = tools_list
return declarations
def get_func_desc_openai_style(self, omit_empty_parameter_field: bool = False):
"""Get tools in OpenAI function calling style (deprecated)."""
return self.openai_schema(omit_empty_parameter_field)
def get_func_desc_anthropic_style(self):
"""Get tools in Anthropic style (deprecated)."""
return self.anthropic_schema()
def get_func_desc_google_genai_style(self):
"""Get tools in Google GenAI style (deprecated)."""
return self.google_schema()

View File

@@ -0,0 +1,48 @@
"""
Builtin tools for AstrBot - re-exports from core.tools for backward compatibility.
This module re-exports the builtin tools (cron, send_message, kb_query) from
the deprecated core.tools module for backward compatibility.
TODO: These tools should be fully migrated to _internal and core.tools
should be removed once all consumers update their imports.
"""
from __future__ import annotations
# Re-export cron tools
from astrbot.core.tools.cron_tools import (
CREATE_CRON_JOB_TOOL,
DELETE_CRON_JOB_TOOL,
LIST_CRON_JOBS_TOOL,
CreateActiveCronTool,
DeleteCronJobTool,
ListCronJobsTool,
)
# Re-export knowledge_base_query tool
from astrbot.core.tools.kb_query import (
KNOWLEDGE_BASE_QUERY_TOOL,
KnowledgeBaseQueryTool,
)
# Re-export send_message tool
from astrbot.core.tools.send_message import (
SEND_MESSAGE_TO_USER_TOOL,
SendMessageToUserTool,
)
__all__ = [
# Cron tools
"CREATE_CRON_JOB_TOOL",
"DELETE_CRON_JOB_TOOL",
"KNOWLEDGE_BASE_QUERY_TOOL",
"LIST_CRON_JOBS_TOOL",
"SEND_MESSAGE_TO_USER_TOOL",
# Classes
"CreateActiveCronTool",
"DeleteCronJobTool",
"KnowledgeBaseQueryTool",
"ListCronJobsTool",
"SendMessageToUserTool",
]

View File

@@ -0,0 +1,278 @@
"""Tools registry for AstrBot internal runtime."""
from __future__ import annotations
from typing import Any
# Re-export from base
from astrbot._internal.tools.base import FunctionTool, ToolSet
__all__ = [
"DEFAULT_MCP_CONFIG",
"ENABLE_MCP_TIMEOUT_ENV",
"FuncCall",
"FunctionTool",
"FunctionToolManager",
"MCPAllServicesFailedError",
"MCPInitError",
"MCPInitSummary",
"MCPInitTimeoutError",
"MCPShutdownTimeoutError",
"ToolSet",
]
# MCP config constants (re-exported from protocols)
try:
from astrbot._internal.protocols.mcp import (
DEFAULT_MCP_CONFIG,
MCPAllServicesFailedError,
MCPInitError,
MCPInitSummary,
MCPInitTimeoutError,
MCPShutdownTimeoutError,
)
except ImportError:
DEFAULT_MCP_CONFIG: dict[str, Any] = {}
MCPAllServicesFailedError: type[Exception] = Exception
MCPInitError: type[Exception] = Exception
MCPInitSummary: type[dict] = dict
MCPInitTimeoutError: type[TimeoutError] = TimeoutError
MCPShutdownTimeoutError: type[TimeoutError] = TimeoutError
ENABLE_MCP_TIMEOUT_ENV = "ASTRBOT_MCP_TIMEOUT_ENABLED"
MCP_INIT_TIMEOUT_ENV = "ASTRBOT_MCP_INIT_TIMEOUT"
class FunctionToolManager:
"""Central registry for all function tools."""
def __init__(self) -> None:
self._func_list: list[FunctionTool] = []
@property
def func_list(self) -> list[FunctionTool]:
"""Get the list of function tools."""
return self._func_list
@func_list.setter
def func_list(self, value: list[FunctionTool]) -> None:
"""Set the list of function tools."""
self._func_list = value
def add(self, tool: FunctionTool) -> None:
"""Add a tool to the registry."""
self._func_list.append(tool)
def remove(self, name: str) -> bool:
"""Remove a tool by name. Returns True if found."""
for i, f in enumerate(self._func_list):
if f.name == name:
self._func_list.pop(i)
return True
return False
def get_func(self, name: str) -> FunctionTool | None:
"""Get a tool by name. Returns the last active tool if multiple match."""
last_match: FunctionTool | None = None
for f in reversed(self._func_list):
if f.name == name:
if getattr(f, "active", True):
return f
if last_match is None:
last_match = f
return last_match
def get_full_tool_set(self) -> ToolSet:
"""Return a ToolSet with all active tools, deduplicated by name."""
seen: dict[str, FunctionTool] = {}
for tool in reversed(self._func_list):
if tool.name not in seen and getattr(tool, "active", True):
seen[tool.name] = tool
return ToolSet("default", list(seen.values()))
def register_internal_tools(self) -> None:
"""Register built-in computer tools (shell, python, browser, neo)."""
# Import here to avoid circular imports
from astrbot.core.computer.computer_tool_provider import get_all_tools
for tool in get_all_tools():
if self.get_func(tool.name) is None:
self.add(tool)
# MCP-related stub methods for base class compatibility
async def enable_mcp_server(
self, name: str, config: dict[str, Any], init_timeout: int = 30
) -> None:
"""Enable an MCP server (stub)."""
pass
async def disable_mcp_server(
self, name: str = "", timeout: int = 10, shutdown_timeout: int = 10
) -> None:
"""Disable an MCP server (stub)."""
pass
async def init_mcp_clients(self) -> None:
"""Initialize MCP clients (stub)."""
pass
async def test_mcp_server_connection(
self, config: dict[str, Any]
) -> tuple[bool, str]:
"""Test MCP server connection (stub)."""
return False, "Not implemented"
async def sync_modelscope_mcp_servers(self) -> None:
"""Sync ModelScope MCP servers (stub)."""
pass
def load_mcp_config(self) -> dict[str, Any]:
"""Load MCP configuration (stub)."""
return {"mcpServers": {}}
def save_mcp_config(self, config: dict[str, Any]) -> bool:
"""Save MCP configuration (stub)."""
return True
def activate_llm_tool(self, name: str) -> bool:
"""Activate an LLM tool (stub)."""
return True
def deactivate_llm_tool(self, name: str) -> bool:
"""Deactivate an LLM tool (stub)."""
return True
@property
def mcp_client_dict(self) -> dict[str, Any]:
"""Return dict of MCP clients (stub)."""
return {}
@property
def mcp_server_runtime_view(self) -> dict[str, Any]:
"""Return runtime view of MCP servers (stub)."""
return {}
class FuncCall(FunctionToolManager):
"""Alias for FunctionToolManager for backward compatibility."""
def __init__(self) -> None:
super().__init__()
self._mcp_server_runtime_view: dict[str, Any] = {}
self._mcp_client_dict: dict[str, Any] = {}
@property
def mcp_server_runtime_view(self) -> dict[str, Any]:
"""Return runtime view of MCP servers."""
return self._mcp_server_runtime_view
@property
def mcp_client_dict(self) -> dict[str, Any]:
"""Return dict of MCP clients (for backward compatibility)."""
return self._mcp_client_dict
async def init_mcp_clients(self) -> None:
"""Initialize MCP clients (stub implementation)."""
pass
def add_func(
self,
name: str,
func_args: list[dict[str, Any]],
desc: str,
handler: Any,
) -> None:
"""Add a function tool (deprecated, use add() instead)."""
params: dict[str, Any] = {
"type": "object",
"properties": {},
}
for param in func_args:
params["properties"][param["name"]] = {
"type": param.get("type", "string"),
"description": param.get("description", ""),
}
func = FunctionTool(
name=name,
parameters=params,
description=desc,
handler=handler,
)
self.add(func)
def remove_func(self, name: str) -> None:
"""Remove a function tool by name (deprecated, use remove() instead)."""
self.remove(name)
def get_func(self, name: str) -> FunctionTool | None:
"""Get a function tool by name."""
return super().get_func(name)
def names(self) -> list[str]:
"""Get all tool names."""
return [f.name for f in self.func_list]
def remove_tool(self, name: str) -> None:
"""Remove a tool by its name (alias for remove)."""
self.remove(name)
def get_func_desc_openai_style(
self, omit_empty_parameter_field: bool = False
) -> list[dict[str, Any]]:
"""Get tools in OpenAI style (deprecated, use get_full_tool_set().openai_schema())."""
tool_set = self.get_full_tool_set()
return tool_set.openai_schema(omit_empty_parameter_field)
async def enable_mcp_server(
self, name: str, config: dict[str, Any], init_timeout: int = 30
) -> None:
"""Enable an MCP server (stub implementation)."""
pass
async def disable_mcp_server(
self, name: str = "", timeout: int = 10, shutdown_timeout: int = 10
) -> None:
"""Disable an MCP server (stub implementation)."""
pass
def load_mcp_config(self) -> dict[str, Any]:
"""Load MCP configuration (stub implementation)."""
return {"mcpServers": {}}
def save_mcp_config(self, config: dict[str, Any]) -> bool:
"""Save MCP configuration (stub implementation)."""
return True
def activate_llm_tool(self, name: str) -> bool:
"""Activate an LLM tool (stub implementation)."""
return True
def deactivate_llm_tool(self, name: str) -> bool:
"""Deactivate an LLM tool (stub implementation)."""
return True
async def test_mcp_server_connection(
self, config: dict[str, Any]
) -> tuple[bool, str]:
"""Test MCP server connection (stub implementation)."""
# Import the actual test function if available
try:
from astrbot._internal.protocols.mcp.client import (
_quick_test_mcp_connection,
)
success, message = await _quick_test_mcp_connection(config)
if not success:
raise Exception(message)
return success, message
except Exception as e:
raise Exception(f"MCP connection test failed: {e!s}") from e
async def sync_modelscope_mcp_servers(self) -> None:
"""Sync ModelScope MCP servers (stub implementation)."""
pass
def get_full_tool_set(self) -> ToolSet:
"""Return a ToolSet with all active tools."""
return ToolSet("default", [t for t in self.func_list if t.active])

View File

@@ -1,19 +1,64 @@
"""
AstrBot Public API.
This package exposes the public interface for extending and integrating with
AstrBot. All exports from this module are guaranteed to be stable across
minor version updates.
Modules:
tools: Tool registration and management API
mcp: Model Context Protocol server and tool API
skills: Skill management and conversion API
"""
from astrbot import logger
# Tool API
from astrbot._internal.tools.base import FunctionTool, ToolSet
# MCP API
from astrbot.api.mcp import (
MCPClient,
MCPTool,
get_mcp_servers,
register_mcp_server,
unregister_mcp_server,
)
# Skills API
from astrbot.api.skills import (
SkillInfo,
SkillManager,
get_skill_manager,
skill_to_tool,
)
# Tools API (public interface)
from astrbot.api.tools import ToolRegistry, get_registry, tool
from astrbot.core import html_renderer, sp
from astrbot.core.agent.tool import FunctionTool, ToolSet
from astrbot.core.agent.tool_executor import BaseFunctionToolExecutor
from astrbot.core.config.astrbot_config import AstrBotConfig
from astrbot.core.star.register import register_agent as agent
from astrbot.core.star.register import register_llm_tool as llm_tool
__all__ = [
"AstrBotConfig",
"BaseFunctionToolExecutor",
"FunctionTool",
"MCPClient",
"MCPTool",
"SkillInfo",
"SkillManager",
"ToolRegistry",
"ToolSet",
"agent",
"get_mcp_servers",
"get_registry",
"get_skill_manager",
"html_renderer",
"llm_tool",
"logger",
"register_mcp_server",
"skill_to_tool",
"sp",
"tool",
"unregister_mcp_server",
]

View File

@@ -29,14 +29,15 @@ from astrbot.core.star.filter.platform_adapter_type import (
PlatformAdapterType,
)
from astrbot.core.star.register import (
register_star as register, # 注册插件Star
register_star as register, # 注册插件(Star)
)
from astrbot.core.star import Context, Star
from astrbot.core.star.config import *
# provider
from astrbot.core.provider import Provider, Personality, ProviderMetaData
from astrbot.core.provider import Provider, ProviderMetaData
from astrbot.core.db.po import Personality
# platform
from astrbot.core.platform import (

View File

@@ -20,7 +20,17 @@ from astrbot.core.star.register import (
)
from astrbot.core.star.register import register_on_llm_request as on_llm_request
from astrbot.core.star.register import register_on_llm_response as on_llm_response
from astrbot.core.star.register import (
register_on_llm_tool_respond as on_llm_tool_respond,
)
from astrbot.core.star.register import register_on_platform_loaded as on_platform_loaded
from astrbot.core.star.register import register_on_plugin_error as on_plugin_error
from astrbot.core.star.register import register_on_plugin_loaded as on_plugin_loaded
from astrbot.core.star.register import register_on_plugin_unloaded as on_plugin_unloaded
from astrbot.core.star.register import register_on_using_llm_tool as on_using_llm_tool
from astrbot.core.star.register import (
register_on_waiting_llm_request as on_waiting_llm_request,
)
from astrbot.core.star.register import register_permission_type as permission_type
from astrbot.core.star.register import (
register_platform_adapter_type as platform_adapter_type,
@@ -45,7 +55,13 @@ __all__ = [
"on_decorating_result",
"on_llm_request",
"on_llm_response",
"on_llm_tool_respond",
"on_platform_loaded",
"on_plugin_error",
"on_plugin_loaded",
"on_plugin_unloaded",
"on_using_llm_tool",
"on_waiting_llm_request",
"permission_type",
"platform_adapter_type",
"regex",

98
astrbot/api/mcp.py Normal file
View File

@@ -0,0 +1,98 @@
"""
MCP (Model Context Protocol) Public API for AstrBot.
This module provides a simple, stable interface for MCP server management,
delegating to the _internal package.
Example:
from astrbot.api.mcp import get_mcp_servers, register_mcp_server
# List connected servers
servers = get_mcp_servers()
# Register stdio MCP server
await register_mcp_server(
name="weather",
command="uv",
args=["tool", "run", "weather-mcp"],
)
# Register SSE server
await register_mcp_server(
name="fileserver",
url="http://localhost:8080/sse",
transport="sse",
)
"""
from __future__ import annotations
from typing import Any
# Import from _internal package (the canonical source)
# TODO: fix path - should be protocols.mcp.client
from astrbot._internal.protocols.mcp.client import McpClient as MCPClient
from astrbot._internal.protocols.mcp.tool import MCPTool
__all__ = [
"MCPClient",
"MCPTool",
"get_mcp_servers",
"register_mcp_server",
"unregister_mcp_server",
]
def get_mcp_servers() -> dict[str, MCPClient]:
"""Get all connected MCP servers."""
from astrbot.core.provider.register import llm_tools as func_tool_manager
manager = func_tool_manager
return dict(manager.mcp_client_dict)
async def register_mcp_server(
name: str,
command: str | None = None,
args: list[str] | None = None,
url: str | None = None,
transport: str | None = None,
**kwargs: Any,
) -> None:
"""Register and connect to an MCP server.
Args:
name: Unique name for this server
command: Command to run (for stdio transport)
args: Command arguments
url: URL (for SSE/Streamable HTTP transports)
transport: "sse", "streamable_http", or None for stdio
Example - Stdio:
await register_mcp_server(name="weather", command="uv",
args=["tool", "run", "weather-mcp"])
"""
from astrbot.core.provider.register import llm_tools as func_tool_manager
manager = func_tool_manager
config: dict[str, Any] = {}
if command is not None:
config["command"] = command
if args is not None:
config["args"] = args
if url is not None:
config["url"] = url
if transport is not None:
config["transport"] = transport
config.update(kwargs)
await manager.enable_mcp_server(name=name, config=config)
async def unregister_mcp_server(name: str) -> None:
"""Disconnect and remove an MCP server."""
from astrbot.core.provider.register import llm_tools as func_tool_manager
manager = func_tool_manager
await manager.disable_mcp_server(name=name)

View File

@@ -1,4 +1,5 @@
from astrbot.core.provider import Personality, Provider, STTProvider
from astrbot.core.db.po import Personality
from astrbot.core.provider import Provider, STTProvider
from astrbot.core.provider.entities import (
LLMResponse,
ProviderMetaData,

58
astrbot/api/skills.py Normal file
View File

@@ -0,0 +1,58 @@
"""
Skills Public API for AstrBot.
This module provides a simple, stable interface for skill management,
delegating to the _internal package.
Two skill types:
1. Prompt-based: SKILL.md files injected into system prompt
2. Tool-based: Skills with input_schema converted to FunctionTool
Example:
from astrbot.api.skills import get_skill_manager, skill_to_tool
# List skills
mgr = get_skill_manager()
skills = mgr.list_skills()
# Convert tool-based skill to FunctionTool
tool_skills = [s for s in skills if s.input_schema]
if tool_skills:
func_tool = skill_to_tool(tool_skills[0])
"""
from __future__ import annotations
from astrbot._internal.tools.base import FunctionTool
# Import from _internal package (the canonical source)
# TODO: fix path - should be core.skills.skill_manager
from astrbot.core.skills.skill_manager import SkillInfo, SkillManager
__all__ = ["SkillInfo", "SkillManager", "get_skill_manager", "skill_to_tool"]
def get_skill_manager() -> SkillManager:
"""Get the global SkillManager instance."""
return SkillManager()
def skill_to_tool(skill: SkillInfo) -> FunctionTool | None:
"""Convert a tool-based skill (with input_schema) to a FunctionTool.
Args:
skill: A SkillInfo instance with an input_schema
Returns:
A FunctionTool, or None if the skill has no input_schema
"""
if not skill.input_schema:
return None
return FunctionTool(
name=f"skill_{skill.name}",
description=skill.description or f"Skill: {skill.name}",
parameters=skill.input_schema,
handler=None,
source="skill",
)

View File

@@ -1,7 +1,7 @@
from astrbot.core.star import Context, Star, StarTools
from astrbot.core.star.config import *
from astrbot.core.star.register import (
register_star as register, # 注册插件Star
register_star as register, # 注册插件(Star)
)
__all__ = ["Context", "Star", "StarTools", "register"]

120
astrbot/api/tools.py Normal file
View File

@@ -0,0 +1,120 @@
"""
Tools Public API for AstrBot.
This module provides a simple, stable interface for tool registration
and management. All implementations are delegated to the _internal package.
Example:
from astrbot.api.tools import tool, get_registry
@tool(name="weather", description="Get weather", parameters={...})
async def get_weather(city: str) -> str:
return f"Weather in {city} is sunny"
registry = get_registry()
tools = registry.list_tools()
"""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from functools import wraps
from typing import Any
# Import from _internal package (the canonical source)
from astrbot._internal.tools.base import FunctionTool, ToolSet
from astrbot._internal.tools.registry import FunctionToolManager
__all__ = ["FunctionTool", "ToolRegistry", "ToolSet", "get_registry", "tool"]
class ToolRegistry:
"""Wrapper around FunctionToolManager for simplified tool registration.
This class provides a user-friendly interface for registering and
managing tools, delegating to the internal FunctionToolManager.
"""
_instance: ToolRegistry | None = None
def __init__(self) -> None:
# Import here to avoid circular imports
from astrbot.core.provider.register import llm_tools as func_tool_manager
self._manager: FunctionToolManager = func_tool_manager
@classmethod
def get_instance(cls) -> ToolRegistry:
"""Get the singleton ToolRegistry instance."""
if cls._instance is None:
cls._instance = cls()
return cls._instance
def register(self, tool: FunctionTool) -> None:
"""Register a FunctionTool."""
self._manager.func_list.append(tool)
def unregister(self, name: str) -> bool:
"""Unregister a tool by name. Returns True if found and removed."""
for i, f in enumerate(self._manager.func_list):
if f.name == name:
self._manager.func_list.pop(i)
return True
return False
def list_tools(self) -> list[FunctionTool]:
"""List all registered tools."""
return self._manager.func_list.copy()
def get_tool(self, name: str) -> FunctionTool | None:
"""Get a tool by name."""
return self._manager.get_func(name)
def get_registry() -> ToolRegistry:
"""Get the global ToolRegistry instance."""
return ToolRegistry.get_instance()
def tool(
name: str,
description: str,
parameters: dict[str, Any] | None = None,
) -> Callable[
[Callable[..., Awaitable[str | None]]], Callable[..., Awaitable[str | None]]
]:
"""Decorator to register an async function as a tool.
Args:
name: Tool name (used by LLM to invoke it)
description: What the tool does
parameters: JSON Schema for parameters (optional)
Example:
@tool(name="weather", description="Get weather for a city", parameters={...})
async def get_weather(city: str) -> str:
return f"The weather in {city} is sunny"
"""
if parameters is None:
parameters = {"type": "object", "properties": {}}
def decorator(
func: Callable[..., Awaitable[str | None]],
) -> Callable[..., Awaitable[str | None]]:
func_tool = FunctionTool(
name=name,
description=description,
parameters=parameters,
handler=func,
handler_module_path=getattr(func, "__module__", ""),
source="api",
)
get_registry().register(func_tool)
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> str | None:
return await func(*args, **kwargs)
return wrapper
return decorator

View File

@@ -6,9 +6,9 @@ from collections import defaultdict
from astrbot import logger
from astrbot.api import star
from astrbot.api.event import AstrMessageEvent
from astrbot.api.message_components import Image, Plain
from astrbot.api.message_components import At, Image, Plain
from astrbot.api.platform import MessageType
from astrbot.api.provider import Provider, ProviderRequest
from astrbot.api.provider import LLMResponse, Provider, ProviderRequest
from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
"""
@@ -17,7 +17,7 @@ from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
class LongTermMemory:
def __init__(self, acm: AstrBotConfigManager, context: star.Context):
def __init__(self, acm: AstrBotConfigManager, context: star.Context) -> None:
self.acm = acm
self.context = context
self.session_chats = defaultdict(list)
@@ -30,16 +30,13 @@ class LongTermMemory:
except BaseException as e:
logger.error(e)
max_cnt = 300
image_caption = (
True
if cfg["provider_settings"]["default_image_caption_provider_id"]
and cfg["provider_ltm_settings"]["image_caption"]
else False
)
image_caption_prompt = cfg["provider_settings"]["image_caption_prompt"]
image_caption_provider_id = cfg["provider_settings"][
"default_image_caption_provider_id"
]
image_caption_provider_id = cfg["provider_ltm_settings"].get(
"image_caption_provider_id"
)
image_caption = cfg["provider_ltm_settings"]["image_caption"] and bool(
image_caption_provider_id
)
active_reply = cfg["provider_ltm_settings"]["active_reply"]
enable_active_reply = active_reply.get("enable", False)
ar_method = active_reply["method"]
@@ -79,7 +76,7 @@ class LongTermMemory:
if not provider:
raise Exception(f"没有找到 ID 为 {image_caption_provider_id} 的提供商")
if not isinstance(provider, Provider):
raise Exception(f"提供商类型错误({type(provider)})无法获取图片描述")
raise Exception(f"提供商类型错误({type(provider)}),无法获取图片描述")
response = await provider.text_chat(
prompt=image_caption_prompt,
session_id=uuid.uuid4().hex,
@@ -114,7 +111,7 @@ class LongTermMemory:
return False
async def handle_message(self, event: AstrMessageEvent):
async def handle_message(self, event: AstrMessageEvent) -> None:
"""仅支持群聊"""
if event.get_message_type() == MessageType.GROUP_MESSAGE:
datetime_str = datetime.datetime.now().strftime("%H:%M:%S")
@@ -142,6 +139,8 @@ class LongTermMemory:
logger.error(f"获取图片描述失败: {e}")
else:
parts.append(" [Image]")
elif isinstance(comp, At):
parts.append(f" [At: {comp.name}]")
final_message = "".join(parts)
logger.debug(f"ltm | {event.unified_msg_origin} | {final_message}")
@@ -149,8 +148,8 @@ class LongTermMemory:
if len(self.session_chats[event.unified_msg_origin]) > cfg["max_cnt"]:
self.session_chats[event.unified_msg_origin].pop(0)
async def on_req_llm(self, event: AstrMessageEvent, req: ProviderRequest):
"""当触发 LLM 请求前调用此方法修改 req"""
async def on_req_llm(self, event: AstrMessageEvent, req: ProviderRequest) -> None:
"""当触发 LLM 请求前,调用此方法修改 req"""
if event.unified_msg_origin not in self.session_chats:
return
@@ -159,22 +158,30 @@ class LongTermMemory:
cfg = self.cfg(event)
if cfg["enable_active_reply"]:
prompt = req.prompt
req.prompt = f"You are now in a chatroom. The chat history is as follows:\n{chats_str}"
req.prompt += f"\nNow, a new message is coming: `{prompt}`. Please react to it. Only output your response and do not output any other information."
req.contexts = [] # 清空上下文当使用了主动回复所有聊天记录都在一个prompt中。
req.prompt = (
f"You are now in a chatroom. The chat history is as follows:\n{chats_str}"
f"\nNow, a new message is coming: `{prompt}`. "
"Please react to it. Only output your response and do not output any other information. "
"You MUST use the SAME language as the chatroom is using."
)
req.contexts = [] # 清空上下文,当使用了主动回复,所有聊天记录都在一个prompt中。
else:
req.system_prompt += (
"You are now in a chatroom. The chat history is as follows: \n"
)
req.system_prompt += chats_str
async def after_req_llm(self, event: AstrMessageEvent):
async def after_req_llm(
self, event: AstrMessageEvent, llm_resp: LLMResponse
) -> None:
if event.unified_msg_origin not in self.session_chats:
return
if event.get_result() and event.get_result().is_llm_result():
final_message = f"[You/{datetime.datetime.now().strftime('%H:%M:%S')}]: {event.get_result().get_plain_text()}"
logger.debug(f"ltm | {event.unified_msg_origin} | {final_message}")
if llm_resp.completion_text:
final_message = f"[You/{datetime.datetime.now().strftime('%H:%M:%S')}]: {llm_resp.completion_text}"
logger.debug(
f"Recorded AI response: {event.unified_msg_origin} | {final_message}"
)
self.session_chats[event.unified_msg_origin].append(final_message)
cfg = self.cfg(event)
if len(self.session_chats[event.unified_msg_origin]) > cfg["max_cnt"]:

View File

@@ -0,0 +1,118 @@
import traceback
from astrbot.api import star
from astrbot.api.event import AstrMessageEvent, filter
from astrbot.api.message_components import Image, Plain
from astrbot.api.provider import LLMResponse, ProviderRequest
from astrbot.core import logger
from .long_term_memory import LongTermMemory
class Main(star.Star):
def __init__(self, context: star.Context) -> None:
self.context = context
self.ltm = None
try:
self.ltm = LongTermMemory(self.context.astrbot_config_mgr, self.context)
except BaseException as e:
logger.error(f"聊天增强 err: {e}")
def ltm_enabled(self, event: AstrMessageEvent):
ltmse = self.context.get_config(umo=event.unified_msg_origin)[
"provider_ltm_settings"
]
return ltmse["group_icl_enable"] or ltmse["active_reply"]["enable"]
@filter.platform_adapter_type(filter.PlatformAdapterType.ALL)
async def on_message(self, event: AstrMessageEvent):
"""群聊记忆增强"""
has_image_or_plain = False
for comp in event.message_obj.message:
if isinstance(comp, Plain) or isinstance(comp, Image):
has_image_or_plain = True
break
if self.ltm_enabled(event) and self.ltm and has_image_or_plain:
need_active = await self.ltm.need_active_reply(event)
group_icl_enable = self.context.get_config()["provider_ltm_settings"][
"group_icl_enable"
]
if group_icl_enable:
"""记录对话"""
try:
await self.ltm.handle_message(event)
except BaseException as e:
logger.error(e)
if need_active:
"""主动回复"""
provider = self.context.get_using_provider(event.unified_msg_origin)
if not provider:
logger.error("未找到任何 LLM 提供商。请先配置。无法主动回复")
return
try:
conv = None
session_curr_cid = await self.context.conversation_manager.get_curr_conversation_id(
event.unified_msg_origin,
)
if not session_curr_cid:
logger.error(
"当前未处于对话状态,无法主动回复,请确保 平台设置->会话隔离(unique_session) 未开启,并使用 /switch 序号 切换或者 /new 创建一个会话。",
)
return
conv = await self.context.conversation_manager.get_conversation(
event.unified_msg_origin,
session_curr_cid,
)
prompt = event.message_str
if not conv:
logger.error("未找到对话,无法主动回复")
return
yield event.request_llm(
prompt=prompt,
session_id=event.session_id,
conversation=conv,
)
except BaseException as e:
logger.error(traceback.format_exc())
logger.error(f"主动回复失败: {e}")
@filter.on_llm_request()
async def decorate_llm_req(
self, event: AstrMessageEvent, req: ProviderRequest
) -> None:
"""在请求 LLM 前注入人格信息、Identifier、时间、回复内容等 System Prompt"""
if self.ltm and self.ltm_enabled(event):
try:
await self.ltm.on_req_llm(event, req)
except BaseException as e:
logger.error(f"ltm: {e}")
@filter.on_llm_response()
async def record_llm_resp_to_ltm(
self, event: AstrMessageEvent, resp: LLMResponse
) -> None:
"""在 LLM 响应后记录对话"""
if self.ltm and self.ltm_enabled(event):
try:
await self.ltm.after_req_llm(event, resp)
except Exception as e:
logger.error(f"ltm: {e}")
@filter.after_message_sent()
async def after_message_sent(self, event: AstrMessageEvent) -> None:
"""消息发送后处理"""
if self.ltm and self.ltm_enabled(event):
try:
clean_session = event.get_extra("_clean_ltm_session", False)
if clean_session:
await self.ltm.remove_session(event)
except Exception as e:
logger.error(f"ltm: {e}")

View File

@@ -0,0 +1,4 @@
name: astrbot
desc: AstrBot 自带插件,包含人格注入、思考内容注入、群聊上下文感知等功能的实现,禁用后将无法使用这些功能。
author: Soulter
version: 4.1.0

View File

@@ -11,7 +11,6 @@ from .provider import ProviderCommands
from .setunset import SetUnsetCommands
from .sid import SIDCommand
from .t2i import T2ICommand
from .tool import ToolCommands
from .tts import TTSCommand
__all__ = [
@@ -27,5 +26,4 @@ __all__ = [
"SetUnsetCommands",
"T2ICommand",
"TTSCommand",
"ToolCommands",
]

View File

@@ -5,60 +5,60 @@ from astrbot.core.utils.io import download_dashboard
class AdminCommands:
def __init__(self, context: star.Context):
def __init__(self, context: star.Context) -> None:
self.context = context
async def op(self, event: AstrMessageEvent, admin_id: str = ""):
"""授权管理员op <admin_id>"""
async def op(self, event: AstrMessageEvent, admin_id: str = "") -> None:
"""授权管理员op <admin_id>"""
if not admin_id:
event.set_result(
MessageEventResult().message(
"使用方法: /op <id> 授权管理员/deop <id> 取消管理员可通过 /sid 获取 ID",
"使用方法: /op <id> 授权管理员;/deop <id> 取消管理员可通过 /sid 获取 ID",
),
)
return
self.context.get_config()["admins_id"].append(str(admin_id))
self.context.get_config().save_config()
event.set_result(MessageEventResult().message("授权成功"))
event.set_result(MessageEventResult().message("授权成功"))
async def deop(self, event: AstrMessageEvent, admin_id: str = ""):
"""取消授权管理员deop <admin_id>"""
async def deop(self, event: AstrMessageEvent, admin_id: str = "") -> None:
"""取消授权管理员deop <admin_id>"""
if not admin_id:
event.set_result(
MessageEventResult().message(
"使用方法: /deop <id> 取消管理员可通过 /sid 获取 ID",
"使用方法: /deop <id> 取消管理员可通过 /sid 获取 ID",
),
)
return
try:
self.context.get_config()["admins_id"].remove(str(admin_id))
self.context.get_config().save_config()
event.set_result(MessageEventResult().message("取消授权成功"))
event.set_result(MessageEventResult().message("取消授权成功"))
except ValueError:
event.set_result(
MessageEventResult().message("此用户 ID 不在管理员名单内"),
MessageEventResult().message("此用户 ID 不在管理员名单内"),
)
async def wl(self, event: AstrMessageEvent, sid: str = ""):
"""添加白名单wl <sid>"""
async def wl(self, event: AstrMessageEvent, sid: str = "") -> None:
"""添加白名单wl <sid>"""
if not sid:
event.set_result(
MessageEventResult().message(
"使用方法: /wl <id> 添加白名单/dwl <id> 删除白名单可通过 /sid 获取 ID",
"使用方法: /wl <id> 添加白名单;/dwl <id> 删除白名单可通过 /sid 获取 ID",
),
)
return
cfg = self.context.get_config(umo=event.unified_msg_origin)
cfg["platform_settings"]["id_whitelist"].append(str(sid))
cfg.save_config()
event.set_result(MessageEventResult().message("添加白名单成功"))
event.set_result(MessageEventResult().message("添加白名单成功"))
async def dwl(self, event: AstrMessageEvent, sid: str = ""):
"""删除白名单dwl <sid>"""
async def dwl(self, event: AstrMessageEvent, sid: str = "") -> None:
"""删除白名单dwl <sid>"""
if not sid:
event.set_result(
MessageEventResult().message(
"使用方法: /dwl <id> 删除白名单可通过 /sid 获取 ID",
"使用方法: /dwl <id> 删除白名单可通过 /sid 获取 ID",
),
)
return
@@ -66,11 +66,12 @@ class AdminCommands:
cfg = self.context.get_config(umo=event.unified_msg_origin)
cfg["platform_settings"]["id_whitelist"].remove(str(sid))
cfg.save_config()
event.set_result(MessageEventResult().message("删除白名单成功"))
event.set_result(MessageEventResult().message("删除白名单成功"))
except ValueError:
event.set_result(MessageEventResult().message("此 SID 不在白名单内"))
event.set_result(MessageEventResult().message("此 SID 不在白名单内"))
async def update_dashboard(self, event: AstrMessageEvent):
async def update_dashboard(self, event: AstrMessageEvent) -> None:
"""更新管理面板"""
await event.send(MessageChain().message("正在尝试更新管理面板..."))
await download_dashboard(version=f"v{VERSION}", latest=False)
await event.send(MessageChain().message("管理面板更新完成"))
await event.send(MessageChain().message("管理面板更新完成"))

View File

@@ -11,14 +11,14 @@ from .utils.rst_scene import RstScene
class AlterCmdCommands(CommandParserMixin):
def __init__(self, context: star.Context):
def __init__(self, context: star.Context) -> None:
self.context = context
async def update_reset_permission(self, scene_key: str, perm_type: str):
async def update_reset_permission(self, scene_key: str, perm_type: str) -> None:
"""更新reset命令在特定场景下的权限设置"""
from astrbot.api import sp
alter_cmd_cfg = await sp.global_get("alter_cmd", {})
alter_cmd_cfg = await sp.global_get("alter_cmd", {}) or {}
plugin_cfg = alter_cmd_cfg.get("astrbot", {})
reset_cfg = plugin_cfg.get("reset", {})
reset_cfg[scene_key] = perm_type
@@ -26,12 +26,12 @@ class AlterCmdCommands(CommandParserMixin):
alter_cmd_cfg["astrbot"] = plugin_cfg
await sp.global_put("alter_cmd", alter_cmd_cfg)
async def alter_cmd(self, event: AstrMessageEvent):
async def alter_cmd(self, event: AstrMessageEvent) -> None:
token = self.parse_commands(event.message_str)
if token.len < 3:
await event.send(
MessageChain().message(
"该指令用于设置指令或指令组的权限\n"
"该指令用于设置指令或指令组的权限\n"
"格式: /alter_cmd <cmd_name> <admin/member>\n"
"例1: /alter_cmd c1 admin 将 c1 设为管理员指令\n"
"例2: /alter_cmd g1 c1 admin 将 g1 指令组的 c1 子指令设为管理员指令\n"
@@ -47,7 +47,7 @@ class AlterCmdCommands(CommandParserMixin):
if cmd_name == "reset" and cmd_type == "config":
from astrbot.api import sp
alter_cmd_cfg = await sp.global_get("alter_cmd", {})
alter_cmd_cfg = await sp.global_get("alter_cmd", {}) or {}
plugin_ = alter_cmd_cfg.get("astrbot", {})
reset_cfg = plugin_.get("reset", {})
@@ -56,11 +56,11 @@ class AlterCmdCommands(CommandParserMixin):
private = reset_cfg.get("private", "member")
config_menu = f"""reset命令权限细粒度配置
当前配置
当前配置:
1. 群聊+会话隔离开: {group_unique_on}
2. 群聊+会话隔离关: {group_unique_off}
3. 私聊: {private}
修改指令格式
修改指令格式:
/alter_cmd reset scene <场景编号> <admin/member>
例如: /alter_cmd reset scene 2 member"""
await event.send(MessageChain().message(config_menu))
@@ -82,7 +82,7 @@ class AlterCmdCommands(CommandParserMixin):
if perm_type not in ["admin", "member"]:
await event.send(
MessageChain().message("权限类型错误只能是 admin 或 member"),
MessageChain().message("权限类型错误,只能是 admin 或 member"),
)
return
@@ -101,7 +101,7 @@ class AlterCmdCommands(CommandParserMixin):
if cmd_type not in ["admin", "member"]:
await event.send(
MessageChain().message("指令类型错误可选类型有 admin, member"),
MessageChain().message("指令类型错误,可选类型有 admin, member"),
)
return
@@ -131,7 +131,7 @@ class AlterCmdCommands(CommandParserMixin):
from astrbot.api import sp
alter_cmd_cfg = await sp.global_get("alter_cmd", {})
alter_cmd_cfg = await sp.global_get("alter_cmd", {}) or {}
plugin_ = alter_cmd_cfg.get(found_plugin.name, {})
cfg = plugin_.get(found_command.handler_name, {})
cfg["permission"] = cmd_type
@@ -168,6 +168,6 @@ class AlterCmdCommands(CommandParserMixin):
cmd_group_str = "指令组" if cmd_group else "指令"
await event.send(
MessageChain().message(
f"已将{cmd_name}{cmd_group_str} 的权限级别调整为 {cmd_type}",
f"已将{cmd_name}{cmd_group_str} 的权限级别调整为 {cmd_type}",
),
)

View File

@@ -1,20 +1,29 @@
import datetime
from astrbot.api import logger, sp, star
from astrbot.api import sp, star
from astrbot.api.event import AstrMessageEvent, MessageEventResult
from astrbot.core.platform.astr_message_event import MessageSesion
from astrbot.core.agent.runners.deerflow.constants import (
DEERFLOW_PROVIDER_TYPE,
DEERFLOW_THREAD_ID_KEY,
)
from astrbot.core.platform.astr_message_event import MessageSession
from astrbot.core.platform.message_type import MessageType
from astrbot.core.provider.sources.coze_source import ProviderCoze
from astrbot.core.provider.sources.dify_source import ProviderDify
from astrbot.core.utils.active_event_registry import active_event_registry
from ..long_term_memory import LongTermMemory
from .utils.rst_scene import RstScene
THIRD_PARTY_AGENT_RUNNER_KEY = {
"dify": "dify_conversation_id",
"coze": "coze_conversation_id",
"dashscope": "dashscope_conversation_id",
DEERFLOW_PROVIDER_TYPE: DEERFLOW_THREAD_ID_KEY,
}
THIRD_PARTY_AGENT_RUNNER_STR = ", ".join(THIRD_PARTY_AGENT_RUNNER_KEY.keys())
class ConversationCommands:
def __init__(self, context: star.Context, ltm: LongTermMemory | None = None):
def __init__(self, context: star.Context) -> None:
self.context = context
self.ltm = ltm
async def _get_current_persona_id(self, session_id):
curr = await self.context.conversation_manager.get_curr_conversation_id(
@@ -26,26 +35,20 @@ class ConversationCommands:
session_id,
curr,
)
if not conv:
return None
return conv.persona_id
def ltm_enabled(self, event: AstrMessageEvent):
if not self.ltm:
return False
ltmse = self.context.get_config(umo=event.unified_msg_origin)[
"provider_ltm_settings"
]
return ltmse["group_icl_enable"] or ltmse["active_reply"]["enable"]
async def reset(self, message: AstrMessageEvent):
async def reset(self, message: AstrMessageEvent) -> None:
"""重置 LLM 会话"""
is_unique_session = self.context.get_config()["platform_settings"][
"unique_session"
]
umo = message.unified_msg_origin
cfg = self.context.get_config(umo=message.unified_msg_origin)
is_unique_session = cfg["platform_settings"]["unique_session"]
is_group = bool(message.get_group_id())
scene = RstScene.get_scene(is_group, is_unique_session)
alter_cmd_cfg = await sp.get_async("global", "global", "alter_cmd", {})
alter_cmd_cfg = await sp.get_async("global", "global", "alter_cmd", {}) or {}
plugin_config = alter_cmd_cfg.get("astrbot", {})
reset_cfg = plugin_config.get("reset", {})
@@ -57,61 +60,82 @@ class ConversationCommands:
if required_perm == "admin" and message.role != "admin":
message.set_result(
MessageEventResult().message(
f"{scene.name}场景下reset命令需要管理员权限"
f"您 (ID {message.get_sender_id()}) 不是管理员无法执行此操作",
f"{scene.name}场景下,reset命令需要管理员权限,"
f"您 (ID {message.get_sender_id()}) 不是管理员,无法执行此操作",
),
)
return
if not self.context.get_using_provider(message.unified_msg_origin):
agent_runner_type = cfg["provider_settings"]["agent_runner_type"]
if agent_runner_type in THIRD_PARTY_AGENT_RUNNER_KEY:
active_event_registry.stop_all(umo, exclude=message)
await sp.remove_async(
scope="umo",
scope_id=umo,
key=THIRD_PARTY_AGENT_RUNNER_KEY[agent_runner_type],
)
message.set_result(MessageEventResult().message("重置对话成功。"))
return
if not self.context.get_using_provider(umo):
message.set_result(
MessageEventResult().message("未找到任何 LLM 提供商请先配置"),
MessageEventResult().message("未找到任何 LLM 提供商请先配置"),
)
return
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type in ["dify", "coze"]:
assert isinstance(provider, (ProviderDify, ProviderCoze)), (
"provider type is not dify or coze"
)
await provider.forget(message.unified_msg_origin)
message.set_result(
MessageEventResult().message(
"已重置当前 Dify / Coze 会话,新聊天将更换到新的会话。",
),
)
return
cid = await self.context.conversation_manager.get_curr_conversation_id(
message.unified_msg_origin,
)
cid = await self.context.conversation_manager.get_curr_conversation_id(umo)
if not cid:
message.set_result(
MessageEventResult().message(
"当前未处于对话状态请 /switch 切换或者 /new 创建",
"当前未处于对话状态,请 /switch 切换或者 /new 创建",
),
)
return
active_event_registry.stop_all(umo, exclude=message)
await self.context.conversation_manager.update_conversation(
message.unified_msg_origin,
umo,
cid,
[],
)
ret = "清除会话 LLM 聊天历史成功"
if self.ltm and self.ltm_enabled(message):
cnt = await self.ltm.remove_session(event=message)
ret += f"\n聊天增强: 已清除 {cnt} 条聊天记录。"
ret = "清除聊天历史成功!"
message.set_extra("_clean_ltm_session", True)
message.set_result(MessageEventResult().message(ret))
async def his(self, message: AstrMessageEvent, page: int = 1):
async def stop(self, message: AstrMessageEvent) -> None:
"""停止当前会话正在运行的 Agent"""
cfg = self.context.get_config(umo=message.unified_msg_origin)
agent_runner_type = cfg["provider_settings"]["agent_runner_type"]
umo = message.unified_msg_origin
if agent_runner_type in THIRD_PARTY_AGENT_RUNNER_KEY:
stopped_count = active_event_registry.stop_all(umo, exclude=message)
else:
stopped_count = active_event_registry.request_agent_stop_all(
umo,
exclude=message,
)
if stopped_count > 0:
message.set_result(
MessageEventResult().message(
f"已请求停止 {stopped_count} 个运行中的任务。"
)
)
return
message.set_result(MessageEventResult().message("当前会话没有运行中的任务。"))
async def his(self, message: AstrMessageEvent, page: int = 1) -> None:
"""查看对话记录"""
if not self.context.get_using_provider(message.unified_msg_origin):
message.set_result(
MessageEventResult().message("未找到任何 LLM 提供商请先配置"),
MessageEventResult().message("未找到任何 LLM 提供商请先配置"),
)
return
@@ -142,7 +166,7 @@ class ConversationCommands:
history = "".join(parts)
ret = (
f"当前对话历史记录"
f"当前对话历史记录:"
f"{history or '无历史记录'}\n\n"
f"{page} 页 | 共 {total_pages}\n"
f"*输入 /history 2 跳转到第 2 页"
@@ -150,31 +174,16 @@ class ConversationCommands:
message.set_result(MessageEventResult().message(ret).use_t2i(False))
async def convs(self, message: AstrMessageEvent, page: int = 1):
async def convs(self, message: AstrMessageEvent, page: int = 1) -> None:
"""查看对话列表"""
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type == "dify":
"""原有的Dify处理逻辑保持不变"""
parts = ["Dify 对话列表:\n"]
assert isinstance(provider, ProviderDify)
data = await provider.api_client.get_chat_convs(message.unified_msg_origin)
idx = 1
for conv in data["data"]:
ts_h = datetime.datetime.fromtimestamp(conv["updated_at"]).strftime(
"%m-%d %H:%M",
)
parts.append(
f"{idx}. {conv['name']}({conv['id'][:4]})\n 上次更新:{ts_h}\n"
)
idx += 1
if idx == 1:
parts.append("没有找到任何对话。")
dify_cid = provider.conversation_ids.get(message.unified_msg_origin, None)
parts.append(
f"\n\n用户: {message.unified_msg_origin}\n当前对话: {dify_cid}\n使用 /switch <序号> 切换对话。"
cfg = self.context.get_config(umo=message.unified_msg_origin)
agent_runner_type = cfg["provider_settings"]["agent_runner_type"]
if agent_runner_type in THIRD_PARTY_AGENT_RUNNER_KEY:
message.set_result(
MessageEventResult().message(
f"{THIRD_PARTY_AGENT_RUNNER_STR} 对话列表功能暂不支持。",
),
)
ret = "".join(parts)
message.set_result(MessageEventResult().message(ret))
return
size_per_page = 6
@@ -191,7 +200,7 @@ class ConversationCommands:
end_idx = start_idx + size_per_page
conversations_paged = conversations_all[start_idx:end_idx]
parts = ["对话列表\n---\n"]
parts = ["对话列表:\n---\n"]
"""全局序号从当前页的第一个开始"""
global_index = start_idx + 1
@@ -202,16 +211,33 @@ class ConversationCommands:
_titles[conv.cid] = title
"""遍历分页后的对话生成列表显示"""
provider_settings = cfg.get("provider_settings", {})
platform_name = message.get_platform_name()
for conv in conversations_paged:
persona_id = conv.persona_id
if not persona_id or persona_id == "[%None]":
persona = await self.context.persona_manager.get_default_persona_v3(
umo=message.unified_msg_origin,
)
persona_id = persona["name"]
(
persona_id,
_,
force_applied_persona_id,
_,
) = await self.context.persona_manager.resolve_selected_persona(
umo=message.unified_msg_origin,
conversation_persona_id=conv.persona_id,
platform_name=platform_name,
provider_settings=provider_settings,
)
if persona_id == "[%None]":
persona_name = ""
elif persona_id:
persona_name = persona_id
else:
persona_name = ""
if force_applied_persona_id:
persona_name = f"{persona_name} (自定义规则)"
title = _titles.get(conv.cid, "新对话")
parts.append(
f"{global_index}. {title}({conv.cid[:4]})\n 人格情景: {persona_id}\n 上次更新: {datetime.datetime.fromtimestamp(conv.updated_at).strftime('%m-%d %H:%M')}\n"
f"{global_index}. {title}({conv.cid[:4]})\n 人格情景: {persona_name}\n 上次更新: {datetime.datetime.fromtimestamp(conv.updated_at).strftime('%m-%d %H:%M')}\n"
)
global_index += 1
@@ -227,9 +253,8 @@ class ConversationCommands:
else:
ret += "\n当前对话: 无"
unique_session = self.context.get_config()["platform_settings"][
"unique_session"
]
cfg = self.context.get_config(umo=message.unified_msg_origin)
unique_session = cfg["platform_settings"]["unique_session"]
if unique_session:
ret += "\n会话隔离粒度: 个人"
else:
@@ -241,19 +266,21 @@ class ConversationCommands:
message.set_result(MessageEventResult().message(ret).use_t2i(False))
return
async def new_conv(self, message: AstrMessageEvent):
async def new_conv(self, message: AstrMessageEvent) -> None:
"""创建新对话"""
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type in ["dify", "coze"]:
assert isinstance(provider, (ProviderDify, ProviderCoze)), (
"provider type is not dify or coze"
)
await provider.forget(message.unified_msg_origin)
message.set_result(
MessageEventResult().message("成功,下次聊天将是新对话。"),
cfg = self.context.get_config(umo=message.unified_msg_origin)
agent_runner_type = cfg["provider_settings"]["agent_runner_type"]
if agent_runner_type in THIRD_PARTY_AGENT_RUNNER_KEY:
active_event_registry.stop_all(message.unified_msg_origin, exclude=message)
await sp.remove_async(
scope="umo",
scope_id=message.unified_msg_origin,
key=THIRD_PARTY_AGENT_RUNNER_KEY[agent_runner_type],
)
message.set_result(MessageEventResult().message("已创建新对话。"))
return
active_event_registry.stop_all(message.unified_msg_origin, exclude=message)
cpersona = await self._get_current_persona_id(message.unified_msg_origin)
cid = await self.context.conversation_manager.new_conversation(
message.unified_msg_origin,
@@ -261,32 +288,17 @@ class ConversationCommands:
persona_id=cpersona,
)
# 长期记忆
if self.ltm and self.ltm_enabled(message):
try:
await self.ltm.remove_session(event=message)
except Exception as e:
logger.error(f"清理聊天增强记录失败: {e}")
message.set_extra("_clean_ltm_session", True)
message.set_result(
MessageEventResult().message(f"切换到新对话: 新对话({cid[:4]})"),
MessageEventResult().message(f"切换到新对话: 新对话({cid[:4]})"),
)
async def groupnew_conv(self, message: AstrMessageEvent, sid: str = ""):
async def groupnew_conv(self, message: AstrMessageEvent, sid: str = "") -> None:
"""创建新群聊对话"""
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type in ["dify", "coze"]:
assert isinstance(provider, (ProviderDify, ProviderCoze)), (
"provider type is not dify or coze"
)
await provider.forget(message.unified_msg_origin)
message.set_result(
MessageEventResult().message("成功,下次聊天将是新对话。"),
)
return
if sid:
session = str(
MessageSesion(
MessageSession(
platform_name=message.platform_meta.id,
message_type=MessageType("GroupMessage"),
session_id=sid,
@@ -301,55 +313,30 @@ class ConversationCommands:
)
message.set_result(
MessageEventResult().message(
f"群聊 {session} 已切换到新对话: 新对话({cid[:4]})",
f"群聊 {session} 已切换到新对话: 新对话({cid[:4]})",
),
)
else:
message.set_result(
MessageEventResult().message("请输入群聊 ID/groupnew 群聊ID"),
MessageEventResult().message("请输入群聊 ID/groupnew 群聊ID"),
)
async def switch_conv(
self,
message: AstrMessageEvent,
index: int | None = None,
):
) -> None:
"""通过 /ls 前面的序号切换对话"""
if not isinstance(index, int):
message.set_result(
MessageEventResult().message("类型错误请输入数字对话序号"),
MessageEventResult().message("类型错误,请输入数字对话序号"),
)
return
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type == "dify":
assert isinstance(provider, ProviderDify), "provider type is not dify"
data = await provider.api_client.get_chat_convs(message.unified_msg_origin)
if not data["data"]:
message.set_result(MessageEventResult().message("未找到任何对话。"))
return
selected_conv = None
if index is not None:
try:
selected_conv = data["data"][index - 1]
except IndexError:
message.set_result(
MessageEventResult().message("对话序号错误,请使用 /ls 查看"),
)
return
else:
selected_conv = data["data"][0]
ret = (
f"Dify 切换到对话: {selected_conv['name']}({selected_conv['id'][:4]})。"
)
provider.conversation_ids[message.unified_msg_origin] = selected_conv["id"]
message.set_result(MessageEventResult().message(ret))
return
if index is None:
message.set_result(
MessageEventResult().message(
"请输入对话序号/switch 对话序号/ls 查看对话 /new 新建对话",
"请输入对话序号/switch 对话序号/ls 查看对话 /new 新建对话",
),
)
return
@@ -358,7 +345,7 @@ class ConversationCommands:
)
if index > len(conversations) or index < 1:
message.set_result(
MessageEventResult().message("对话序号错误请使用 /ls 查看"),
MessageEventResult().message("对话序号错误,请使用 /ls 查看"),
)
else:
conversation = conversations[index - 1]
@@ -369,85 +356,65 @@ class ConversationCommands:
)
message.set_result(
MessageEventResult().message(
f"切换到对话: {title}({conversation.cid[:4]})",
f"切换到对话: {title}({conversation.cid[:4]})",
),
)
async def rename_conv(self, message: AstrMessageEvent, new_name: str = ""):
async def rename_conv(self, message: AstrMessageEvent, new_name: str = "") -> None:
"""重命名对话"""
if not new_name:
message.set_result(MessageEventResult().message("请输入新的对话名称"))
message.set_result(MessageEventResult().message("请输入新的对话名称"))
return
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type == "dify":
assert isinstance(provider, ProviderDify)
cid = provider.conversation_ids.get(message.unified_msg_origin, None)
if not cid:
message.set_result(MessageEventResult().message("未找到当前对话。"))
return
await provider.api_client.rename(cid, new_name, message.unified_msg_origin)
message.set_result(MessageEventResult().message("重命名对话成功。"))
return
await self.context.conversation_manager.update_conversation_title(
message.unified_msg_origin,
new_name,
)
message.set_result(MessageEventResult().message("重命名对话成功"))
message.set_result(MessageEventResult().message("重命名对话成功"))
async def del_conv(self, message: AstrMessageEvent):
async def del_conv(self, message: AstrMessageEvent) -> None:
"""删除当前对话"""
is_unique_session = self.context.get_config()["platform_settings"][
"unique_session"
]
umo = message.unified_msg_origin
cfg = self.context.get_config(umo=umo)
is_unique_session = cfg["platform_settings"]["unique_session"]
if message.get_group_id() and not is_unique_session and message.role != "admin":
# 群聊没开独立会话发送人不是管理员
# 群聊,没开独立会话,发送人不是管理员
message.set_result(
MessageEventResult().message(
f"会话处于群聊并且未开启独立会话并且您 (ID {message.get_sender_id()}) 不是管理员因此没有权限删除当前对话",
f"会话处于群聊,并且未开启独立会话,并且您 (ID {message.get_sender_id()}) 不是管理员,因此没有权限删除当前对话",
),
)
return
provider = self.context.get_using_provider(message.unified_msg_origin)
if provider and provider.meta().type == "dify":
assert isinstance(provider, ProviderDify)
dify_cid = provider.conversation_ids.pop(message.unified_msg_origin, None)
if dify_cid:
await provider.api_client.delete_chat_conv(
message.unified_msg_origin,
dify_cid,
)
message.set_result(
MessageEventResult().message(
"删除当前对话成功。不再处于对话状态,使用 /switch 序号 切换到其他对话或 /new 创建。",
),
agent_runner_type = cfg["provider_settings"]["agent_runner_type"]
if agent_runner_type in THIRD_PARTY_AGENT_RUNNER_KEY:
active_event_registry.stop_all(umo, exclude=message)
await sp.remove_async(
scope="umo",
scope_id=umo,
key=THIRD_PARTY_AGENT_RUNNER_KEY[agent_runner_type],
)
message.set_result(MessageEventResult().message("重置对话成功。"))
return
session_curr_cid = (
await self.context.conversation_manager.get_curr_conversation_id(
message.unified_msg_origin,
)
await self.context.conversation_manager.get_curr_conversation_id(umo)
)
if not session_curr_cid:
message.set_result(
MessageEventResult().message(
"当前未处于对话状态请 /switch 序号 切换或 /new 创建",
"当前未处于对话状态,请 /switch 序号 切换或 /new 创建",
),
)
return
active_event_registry.stop_all(umo, exclude=message)
await self.context.conversation_manager.delete_conversation(
message.unified_msg_origin,
umo,
session_curr_cid,
)
ret = "删除当前对话成功不再处于对话状态使用 /switch 序号 切换到其他对话或 /new 创建"
if self.ltm and self.ltm_enabled(message):
cnt = await self.ltm.remove_session(event=message)
ret += f"\n聊天增强: 已清除 {cnt} 条聊天记录。"
ret = "删除当前对话成功不再处于对话状态,使用 /switch 序号 切换到其他对话或 /new 创建"
message.set_extra("_clean_ltm_session", True)
message.set_result(MessageEventResult().message(ret))

View File

@@ -0,0 +1,88 @@
import aiohttp
from astrbot.api import star
from astrbot.api.event import AstrMessageEvent, MessageEventResult
from astrbot.core.config.default import VERSION
from astrbot.core.star import command_management
from astrbot.core.utils.io import get_dashboard_version
class HelpCommand:
def __init__(self, context: star.Context) -> None:
self.context = context
async def _query_astrbot_notice(self):
try:
async with aiohttp.ClientSession(trust_env=True) as session:
async with session.get(
"https://astrbot.app/notice.json",
timeout=2,
) as resp:
return (await resp.json())["notice"]
except BaseException:
return ""
async def _build_reserved_command_lines(self) -> list[str]:
"""
使用实时指令配置生成内置指令清单,确保重命名/禁用后与实际生效状态保持一致。
"""
try:
commands = await command_management.list_commands()
except BaseException:
return []
lines: list[str] = []
hidden_commands = {"set", "unset", "websearch"}
def walk(items: list[dict], indent: int = 0) -> None:
for item in items:
if not item.get("reserved") or not item.get("enabled"):
continue
# 仅展示顶级指令或指令组
if item.get("type") == "sub_command":
continue
if item.get("parent_signature"):
continue
effective = (
item.get("effective_command")
or item.get("original_command")
or item.get("handler_name")
)
if not effective:
continue
if effective in hidden_commands:
continue
description = item.get("description") or ""
desc_text = f" - {description}" if description else ""
indent_prefix = " " * indent
lines.append(f"{indent_prefix}/{effective}{desc_text}")
walk(commands)
return lines
async def help(self, event: AstrMessageEvent) -> None:
"""查看帮助"""
notice = ""
try:
notice = await self._query_astrbot_notice()
except BaseException:
pass
dashboard_version = await get_dashboard_version()
command_lines = await self._build_reserved_command_lines()
commands_section = (
"\n".join(command_lines) if command_lines else "暂无启用的内置指令"
)
msg_parts = [
f"AstrBot v{VERSION}(WebUI: {dashboard_version})",
"内置指令:",
commands_section,
]
if notice:
msg_parts.append(notice)
msg = "\n".join(msg_parts)
event.set_result(MessageEventResult().message(msg).use_t2i(False))

View File

@@ -3,10 +3,10 @@ from astrbot.api.event import AstrMessageEvent, MessageChain
class LLMCommands:
def __init__(self, context: star.Context):
def __init__(self, context: star.Context) -> None:
self.context = context
async def llm(self, event: AstrMessageEvent):
async def llm(self, event: AstrMessageEvent) -> None:
"""开启/关闭 LLM"""
cfg = self.context.get_config(umo=event.unified_msg_origin)
enable = cfg["provider_settings"].get("enable", True)
@@ -17,4 +17,4 @@ class LLMCommands:
cfg["provider_settings"]["enable"] = True
status = "开启"
cfg.save_config()
await event.send(MessageChain().message(f"{status} LLM 聊天功能"))
await event.send(MessageChain().message(f"{status} LLM 聊天功能"))

View File

@@ -0,0 +1,214 @@
import builtins
from typing import TYPE_CHECKING
from astrbot.api import star
from astrbot.api.event import AstrMessageEvent, MessageEventResult
if TYPE_CHECKING:
from astrbot.core.db.po import Persona
class PersonaCommands:
def __init__(self, context: star.Context) -> None:
self.context = context
def _build_tree_output(
self,
folder_tree: list[dict],
all_personas: list["Persona"],
depth: int = 0,
) -> list[str]:
"""递归构建树状输出,使用短线条表示层级"""
lines: list[str] = []
# 使用短线条作为缩进前缀,每层只用 "" 加一个空格
prefix = " " * depth
for folder in folder_tree:
# 输出文件夹
lines.append(f"{prefix}├ 📁 {folder['name']}/")
# 获取该文件夹下的人格
folder_personas = [
p for p in all_personas if p.folder_id == folder["folder_id"]
]
child_prefix = " " * (depth + 1)
# 输出该文件夹下的人格
for persona in folder_personas:
lines.append(f"{child_prefix}├ 👤 {persona.persona_id}")
# 递归处理子文件夹
children = folder.get("children", [])
if children:
lines.extend(
self._build_tree_output(
children,
all_personas,
depth + 1,
)
)
return lines
async def persona(self, message: AstrMessageEvent) -> None:
parts = message.message_str.split(" ")
umo = message.unified_msg_origin
curr_persona_name = ""
cid = await self.context.conversation_manager.get_curr_conversation_id(umo)
default_persona = await self.context.persona_manager.get_default_persona_v3(
umo=umo,
)
force_applied_persona_id = None
curr_cid_title = ""
if cid:
conv = await self.context.conversation_manager.get_conversation(
unified_msg_origin=umo,
conversation_id=cid,
create_if_not_exists=True,
)
if conv is None:
message.set_result(
MessageEventResult().message(
"当前对话不存在,请先使用 /new 新建一个对话。",
),
)
return
provider_settings = self.context.get_config(umo=umo).get(
"provider_settings",
{},
)
(
persona_id,
_,
force_applied_persona_id,
_,
) = await self.context.persona_manager.resolve_selected_persona(
umo=umo,
conversation_persona_id=conv.persona_id,
platform_name=message.get_platform_name(),
provider_settings=provider_settings,
)
if persona_id == "[%None]":
curr_persona_name = ""
elif persona_id:
curr_persona_name = persona_id
if force_applied_persona_id:
curr_persona_name = f"{curr_persona_name} (自定义规则)"
curr_cid_title = conv.title if conv.title else "新对话"
curr_cid_title += f"({cid[:4]})"
if len(parts) == 1:
message.set_result(
MessageEventResult()
.message(
f"""[Persona]
- 人格情景列表: `/persona list`
- 设置人格情景: `/persona 人格`
- 人格情景详细信息: `/persona view 人格`
- 取消人格: `/persona unset`
默认人格情景: {default_persona["name"]}
当前对话 {curr_cid_title} 的人格情景: {curr_persona_name}
配置人格情景请前往管理面板-配置页
""",
)
.use_t2i(False),
)
elif parts[1] == "list":
# 获取文件夹树和所有人格
folder_tree = await self.context.persona_manager.get_folder_tree()
all_personas = self.context.persona_manager.personas
lines = ["📂 人格列表:\n"]
# 构建树状输出
tree_lines = self._build_tree_output(folder_tree, all_personas)
lines.extend(tree_lines)
# 输出根目录下的人格(没有文件夹的)
root_personas = [p for p in all_personas if p.folder_id is None]
if root_personas:
if tree_lines: # 如果有文件夹内容,加个空行
lines.append("")
for persona in root_personas:
lines.append(f"👤 {persona.persona_id}")
# 统计信息
total_count = len(all_personas)
lines.append(f"\n{total_count} 个人格")
lines.append("\n*使用 `/persona <人格名>` 设置人格")
lines.append("*使用 `/persona view <人格名>` 查看详细信息")
msg = "\n".join(lines)
message.set_result(MessageEventResult().message(msg).use_t2i(False))
elif parts[1] == "view":
if len(parts) == 2:
message.set_result(MessageEventResult().message("请输入人格情景名"))
return
ps = parts[2].strip()
if persona := next(
builtins.filter(
lambda persona: persona["name"] == ps,
self.context.provider_manager.personas,
),
None,
):
msg = f"人格{ps}的详细信息:\n"
msg += f"{persona['prompt']}\n"
else:
msg = f"人格{ps}不存在"
message.set_result(MessageEventResult().message(msg))
elif parts[1] == "unset":
if not cid:
message.set_result(
MessageEventResult().message("当前没有对话,无法取消人格。"),
)
return
await self.context.conversation_manager.update_conversation_persona_id(
message.unified_msg_origin,
"[%None]",
)
message.set_result(MessageEventResult().message("取消人格成功。"))
else:
ps = "".join(parts[1:]).strip()
if not cid:
message.set_result(
MessageEventResult().message(
"当前没有对话,请先开始对话或使用 /new 创建一个对话。",
),
)
return
if persona := next(
builtins.filter(
lambda persona: persona["name"] == ps,
self.context.provider_manager.personas,
),
None,
):
await self.context.conversation_manager.update_conversation_persona_id(
message.unified_msg_origin,
ps,
)
force_warn_msg = ""
if force_applied_persona_id:
force_warn_msg = "提醒:由于自定义规则,您现在切换的人格将不会生效。"
message.set_result(
MessageEventResult().message(
f"设置成功。如果您正在切换到不同的人格,请注意使用 /reset 来清空上下文,防止原人格对话影响现人格。{force_warn_msg}",
),
)
else:
message.set_result(
MessageEventResult().message(
"不存在该人格情景。使用 /persona list 查看所有。",
),
)

View File

@@ -4,16 +4,15 @@ from astrbot.core import DEMO_MODE, logger
from astrbot.core.star.filter.command import CommandFilter
from astrbot.core.star.filter.command_group import CommandGroupFilter
from astrbot.core.star.star_handler import StarHandlerMetadata, star_handlers_registry
from astrbot.core.star.star_manager import PluginManager
class PluginCommands:
def __init__(self, context: star.Context):
def __init__(self, context: star.Context) -> None:
self.context = context
async def plugin_ls(self, event: AstrMessageEvent):
"""获取已经安装的插件列表"""
parts = ["已加载的插件\n"]
async def plugin_ls(self, event: AstrMessageEvent) -> None:
"""获取已经安装的插件列表"""
parts = ["已加载的插件:\n"]
for plugin in self.context.get_all_stars():
line = f"- `{plugin.name}` By {plugin.author}: {plugin.desc}"
if not plugin.activated:
@@ -21,72 +20,78 @@ class PluginCommands:
parts.append(line + "\n")
if len(parts) == 1:
plugin_list_info = "没有加载任何插件"
plugin_list_info = "没有加载任何插件"
else:
plugin_list_info = "".join(parts)
plugin_list_info += "\n使用 /plugin help <插件名> 查看插件帮助和加载的指令\n使用 /plugin on/off <插件名> 启用或者禁用插件"
plugin_list_info += "\n使用 /plugin help <插件名> 查看插件帮助和加载的指令\n使用 /plugin on/off <插件名> 启用或者禁用插件"
event.set_result(
MessageEventResult().message(f"{plugin_list_info}").use_t2i(False),
)
async def plugin_off(self, event: AstrMessageEvent, plugin_name: str = ""):
async def plugin_off(self, event: AstrMessageEvent, plugin_name: str = "") -> None:
"""禁用插件"""
if DEMO_MODE:
event.set_result(MessageEventResult().message("演示模式下无法禁用插件"))
event.set_result(MessageEventResult().message("演示模式下无法禁用插件"))
return
if not plugin_name:
event.set_result(
MessageEventResult().message("/plugin off <插件名> 禁用插件"),
MessageEventResult().message("/plugin off <插件名> 禁用插件"),
)
return
await self.context._star_manager.turn_off_plugin(plugin_name) # type: ignore
event.set_result(MessageEventResult().message(f"插件 {plugin_name} 已禁用。"))
if self.context._star_manager is None:
event.set_result(MessageEventResult().message("插件管理器未初始化。"))
return
await self.context._star_manager.turn_off_plugin(plugin_name)
event.set_result(MessageEventResult().message(f"插件 {plugin_name} 已禁用。"))
async def plugin_on(self, event: AstrMessageEvent, plugin_name: str = ""):
async def plugin_on(self, event: AstrMessageEvent, plugin_name: str = "") -> None:
"""启用插件"""
if DEMO_MODE:
event.set_result(MessageEventResult().message("演示模式下无法启用插件"))
event.set_result(MessageEventResult().message("演示模式下无法启用插件"))
return
if not plugin_name:
event.set_result(
MessageEventResult().message("/plugin on <插件名> 启用插件"),
MessageEventResult().message("/plugin on <插件名> 启用插件"),
)
return
await self.context._star_manager.turn_on_plugin(plugin_name) # type: ignore
event.set_result(MessageEventResult().message(f"插件 {plugin_name} 已启用。"))
if self.context._star_manager is None:
event.set_result(MessageEventResult().message("插件管理器未初始化。"))
return
await self.context._star_manager.turn_on_plugin(plugin_name)
event.set_result(MessageEventResult().message(f"插件 {plugin_name} 已启用。"))
async def plugin_get(self, event: AstrMessageEvent, plugin_repo: str = ""):
async def plugin_get(self, event: AstrMessageEvent, plugin_repo: str = "") -> None:
"""安装插件"""
if DEMO_MODE:
event.set_result(MessageEventResult().message("演示模式下无法安装插件"))
event.set_result(MessageEventResult().message("演示模式下无法安装插件"))
return
if not plugin_repo:
event.set_result(
MessageEventResult().message("/plugin get <插件仓库地址> 安装插件"),
)
return
logger.info(f"准备从 {plugin_repo} 安装插件")
logger.info(f"准备从 {plugin_repo} 安装插件")
if self.context._star_manager:
star_mgr: PluginManager = self.context._star_manager
star_mgr = self.context._star_manager
try:
await star_mgr.install_plugin(plugin_repo) # type: ignore
event.set_result(MessageEventResult().message("安装插件成功"))
await star_mgr.install_plugin(plugin_repo)
event.set_result(MessageEventResult().message("安装插件成功"))
except Exception as e:
logger.error(f"安装插件失败: {e}")
event.set_result(MessageEventResult().message(f"安装插件失败: {e}"))
return
async def plugin_help(self, event: AstrMessageEvent, plugin_name: str = ""):
async def plugin_help(self, event: AstrMessageEvent, plugin_name: str = "") -> None:
"""获取插件帮助"""
if not plugin_name:
event.set_result(
MessageEventResult().message("/plugin help <插件名> 查看插件信息"),
MessageEventResult().message("/plugin help <插件名> 查看插件信息"),
)
return
plugin = self.context.get_registered_star(plugin_name)
if plugin is None:
event.set_result(MessageEventResult().message("未找到此插件"))
event.set_result(MessageEventResult().message("未找到此插件"))
return
help_msg = ""
help_msg += f"\n\n✨ 作者: {plugin.author}\n✨ 版本: {plugin.version}"
@@ -106,15 +111,15 @@ class PluginCommands:
command_names.append(filter_.group_name)
if len(command_handlers) > 0:
parts = ["\n\n🔧 指令列表\n"]
parts = ["\n\n🔧 指令列表:\n"]
for i in range(len(command_handlers)):
line = f"- {command_names[i]}"
if command_handlers[i].desc:
line += f": {command_handlers[i].desc}"
parts.append(line + "\n")
parts.append("\nTip: 指令的触发需要添加唤醒前缀默认为 /")
parts.append("\nTip: 指令的触发需要添加唤醒前缀,默认为 /")
help_msg += "".join(parts)
ret = f"🧩 插件 {plugin_name} 帮助信息\n" + help_msg
ret += "更多帮助信息请查看插件仓库 README"
ret = f"🧩 插件 {plugin_name} 帮助信息:\n" + help_msg
ret += "更多帮助信息请查看插件仓库 README"
event.set_result(MessageEventResult().message(ret).use_t2i(False))

View File

@@ -0,0 +1,736 @@
from __future__ import annotations
import asyncio
import time
from collections.abc import Sequence
from dataclasses import dataclass
from typing import TYPE_CHECKING
from astrbot import logger
from astrbot.api import star
from astrbot.api.event import AstrMessageEvent, MessageEventResult
from astrbot.core.provider.entities import ProviderType
from astrbot.core.utils.error_redaction import safe_error
if TYPE_CHECKING:
from astrbot.core.provider.provider import Provider
MODEL_LIST_CACHE_TTL_SECONDS_DEFAULT = 30.0
MODEL_LOOKUP_MAX_CONCURRENCY_DEFAULT = 4
MODEL_LOOKUP_MAX_CONCURRENCY_UPPER_BOUND = 16
MODEL_LIST_CACHE_TTL_KEY = "model_list_cache_ttl_seconds"
MODEL_LOOKUP_MAX_CONCURRENCY_KEY = "model_lookup_max_concurrency"
MODEL_CACHE_MAX_ENTRIES = 512
@dataclass(frozen=True)
class _ModelLookupConfig:
umo: str | None
cache_ttl_seconds: float
max_concurrency: int
class _ModelCache:
def __init__(self) -> None:
self._store: dict[tuple[str, str | None], tuple[float, list[str]]] = {}
def get(self, provider_id: str, umo: str | None, ttl: float) -> list[str] | None:
if ttl <= 0:
return None
entry = self._store.get((provider_id, umo))
if not entry:
return None
timestamp, models = entry
if time.monotonic() - timestamp > ttl:
self._store.pop((provider_id, umo), None)
return None
return models
def set(
self, provider_id: str, umo: str | None, models: list[str], ttl: float
) -> None:
if ttl <= 0:
return
self._store[(provider_id, umo)] = (time.monotonic(), list(models))
self._evict_if_needed()
def _evict_if_needed(self) -> None:
if len(self._store) <= MODEL_CACHE_MAX_ENTRIES:
return
# Drop oldest entries first when cache grows too large.
overflow = len(self._store) - MODEL_CACHE_MAX_ENTRIES
for key, _ in sorted(
self._store.items(),
key=lambda item: item[1][0],
)[:overflow]:
self._store.pop(key, None)
def invalidate(
self, provider_id: str | None = None, *, umo: str | None = None
) -> None:
if provider_id is None:
self._store.clear()
return
if umo is not None:
self._store.pop((provider_id, umo), None)
return
stale_keys = [
cache_key for cache_key in self._store if cache_key[0] == provider_id
]
for cache_key in stale_keys:
self._store.pop(cache_key, None)
class ProviderCommands:
def __init__(self, context: star.Context) -> None:
self.context = context
self._model_cache = _ModelCache()
self._register_provider_change_hook()
def _register_provider_change_hook(self) -> None:
set_change_callback = getattr(
self.context.provider_manager,
"set_provider_change_callback",
None,
)
if callable(set_change_callback):
set_change_callback(self._on_provider_manager_changed)
return
register_change_hook = getattr(
self.context.provider_manager,
"register_provider_change_hook",
None,
)
if callable(register_change_hook):
register_change_hook(self._on_provider_manager_changed)
def invalidate_provider_models_cache(
self, provider_id: str | None = None, *, umo: str | None = None
) -> None:
"""Public hook for cache invalidation on external provider config changes."""
self._model_cache.invalidate(provider_id, umo=umo)
def _on_provider_manager_changed(
self,
provider_id: str,
provider_type: ProviderType,
umo: str | None,
) -> None:
if provider_type == ProviderType.CHAT_COMPLETION:
self.invalidate_provider_models_cache(provider_id, umo=umo)
def _get_provider_settings(self, umo: str | None) -> dict:
if not umo:
return {}
try:
return self.context.get_config(umo).get("provider_settings", {}) or {}
except Exception as e:
logger.debug(
"读取 provider_settings 失败,使用默认值: %s",
safe_error("", e),
)
return {}
def _get_model_cache_ttl(self, umo: str | None) -> float:
settings = self._get_provider_settings(umo)
raw = settings.get(
MODEL_LIST_CACHE_TTL_KEY,
MODEL_LIST_CACHE_TTL_SECONDS_DEFAULT,
)
try:
return max(float(raw), 0.0)
except Exception as e:
logger.debug(
"读取 %s 失败,回退默认值 %r: %s",
MODEL_LIST_CACHE_TTL_KEY,
MODEL_LIST_CACHE_TTL_SECONDS_DEFAULT,
safe_error("", e),
)
return MODEL_LIST_CACHE_TTL_SECONDS_DEFAULT
def _get_model_lookup_concurrency(self, umo: str | None) -> int:
settings = self._get_provider_settings(umo)
raw = settings.get(
MODEL_LOOKUP_MAX_CONCURRENCY_KEY,
MODEL_LOOKUP_MAX_CONCURRENCY_DEFAULT,
)
try:
value = int(raw)
except Exception as e:
logger.debug(
"读取 %s 失败,回退默认值 %r: %s",
MODEL_LOOKUP_MAX_CONCURRENCY_KEY,
MODEL_LOOKUP_MAX_CONCURRENCY_DEFAULT,
safe_error("", e),
)
value = MODEL_LOOKUP_MAX_CONCURRENCY_DEFAULT
return min(max(value, 1), MODEL_LOOKUP_MAX_CONCURRENCY_UPPER_BOUND)
def _get_model_lookup_config(self, umo: str | None) -> _ModelLookupConfig:
return _ModelLookupConfig(
umo=umo,
cache_ttl_seconds=self._get_model_cache_ttl(umo),
max_concurrency=self._get_model_lookup_concurrency(umo),
)
def _resolve_model_name(
self,
model_name: str,
models: Sequence[str],
) -> str | None:
"""Resolve model name with precedence:
exact > case-insensitive > provider-qualified suffix.
"""
requested = model_name.strip()
if not requested:
return None
requested_norm = requested.casefold()
# exact / case-insensitive match
for candidate in models:
if candidate == requested or candidate.casefold() == requested_norm:
return candidate
# provider-qualified suffix match:
# e.g. candidate `openai/gpt-4o` should match requested `gpt-4o`.
for candidate in models:
cand_norm = candidate.casefold()
if cand_norm.endswith(f"/{requested_norm}") or cand_norm.endswith(
f":{requested_norm}"
):
return candidate
return None
def _apply_model(
self, prov: Provider, model_name: str, *, umo: str | None = None
) -> str:
prov.set_model(model_name)
self.invalidate_provider_models_cache(prov.meta().id, umo=umo)
return f"切换模型成功。当前提供商: [{prov.meta().id}] 当前模型: [{prov.get_model()}]"
async def _get_provider_models(
self,
provider: Provider,
*,
config: _ModelLookupConfig,
use_cache: bool = True,
) -> list[str]:
provider_id = provider.meta().id
ttl_seconds = config.cache_ttl_seconds
umo = config.umo
if use_cache:
cached = self._model_cache.get(provider_id, umo, ttl_seconds)
if cached is not None:
return cached
models = list(await provider.get_models())
if use_cache:
self._model_cache.set(provider_id, umo, models, ttl_seconds)
return models
async def _get_models_or_reply_error(
self,
message: AstrMessageEvent,
prov: Provider,
config: _ModelLookupConfig,
*,
error_prefix: str,
disable_t2i: bool = False,
warning_log: str | None = None,
) -> list[str] | None:
try:
return await self._get_provider_models(prov, config=config)
except asyncio.CancelledError:
raise
except Exception as e:
if warning_log is not None:
logger.warning(
warning_log,
prov.meta().id,
safe_error("", e),
)
result = MessageEventResult().message(safe_error(error_prefix, e))
if disable_t2i:
result = result.use_t2i(False)
message.set_result(result)
return None
def _log_reachability_failure(
self,
provider,
provider_capability_type: ProviderType | None,
err_code: str,
err_reason: str,
) -> None:
"""记录不可达原因到日志。"""
meta = provider.meta()
logger.warning(
"Provider reachability check failed: id=%s type=%s code=%s reason=%s",
meta.id,
provider_capability_type.name if provider_capability_type else "unknown",
err_code,
err_reason,
)
async def _test_provider_capability(self, provider):
"""测试单个 provider 的可用性"""
meta = provider.meta()
provider_capability_type = meta.provider_type
try:
await provider.test()
return True, None, None
except Exception as e:
err_code = "TEST_FAILED"
err_reason = safe_error("", e)
self._log_reachability_failure(
provider, provider_capability_type, err_code, err_reason
)
return False, err_code, err_reason
async def _find_provider_for_model(
self,
model_name: str,
*,
exclude_provider_id: str | None = None,
config: _ModelLookupConfig,
use_cache: bool = True,
) -> tuple[Provider | None, str | None]:
all_providers = []
for provider in self.context.get_all_providers():
provider_meta = provider.meta()
if provider_meta.provider_type != ProviderType.CHAT_COMPLETION:
continue
if (
exclude_provider_id is not None
and provider_meta.id == exclude_provider_id
):
continue
all_providers.append(provider)
if not all_providers:
return None, None
semaphore = asyncio.Semaphore(config.max_concurrency)
async def fetch_models(
provider: Provider,
) -> tuple[Provider, list[str] | None, str | None]:
async with semaphore:
try:
models = await self._get_provider_models(
provider,
config=config,
use_cache=use_cache,
)
return provider, models, None
except asyncio.CancelledError:
raise
except Exception as e:
err = safe_error("", e)
logger.debug(
"跨提供商查找模型 %s 获取 %s 模型列表失败: %s",
model_name,
provider.meta().id,
err,
)
return provider, None, err
results = await asyncio.gather(
*(fetch_models(provider) for provider in all_providers)
)
failed_provider_errors: list[tuple[str, str]] = []
for provider, models, err in results:
if err is not None:
failed_provider_errors.append((provider.meta().id, err))
continue
if models is None:
continue
matched_model_name = self._resolve_model_name(model_name, models)
if matched_model_name is not None:
return provider, matched_model_name
if failed_provider_errors and len(failed_provider_errors) == len(all_providers):
failed_ids = ",".join(
provider_id for provider_id, _ in failed_provider_errors
)
logger.error(
"跨提供商查找模型 %s 时,所有 %d 个提供商的 get_models() 均失败: %s。请检查配置或网络",
model_name,
len(all_providers),
failed_ids,
)
elif failed_provider_errors:
logger.debug(
"跨提供商查找模型 %s 时有 %d 个提供商获取模型失败: %s",
model_name,
len(failed_provider_errors),
",".join(
f"{provider_id}({error})"
for provider_id, error in failed_provider_errors
),
)
return None, None
async def provider(
self,
event: AstrMessageEvent,
idx: str | int | None = None,
idx2: int | None = None,
) -> None:
"""查看或者切换 LLM Provider"""
umo = event.unified_msg_origin
cfg = self.context.get_config(umo).get("provider_settings", {})
reachability_check_enabled = cfg.get("reachability_check", True)
if idx is None:
parts = ["## 载入的 LLM 提供商\n"]
# 获取所有类型的提供商
llms = list(self.context.get_all_providers())
ttss = self.context.get_all_tts_providers()
stts = self.context.get_all_stt_providers()
# 构造待检测列表: [(provider, type_label), ...]
all_providers = []
all_providers.extend([(p, "llm") for p in llms])
all_providers.extend([(p, "tts") for p in ttss])
all_providers.extend([(p, "stt") for p in stts])
# 并发测试连通性
if reachability_check_enabled:
if all_providers:
await event.send(
MessageEventResult().message(
"正在进行提供商可达性测试,请稍候..."
)
)
check_results = await asyncio.gather(
*[self._test_provider_capability(p) for p, _ in all_providers],
return_exceptions=True,
)
else:
# 用 None 表示未检测
check_results = [None for _ in all_providers]
# 整合结果
display_data = []
for (p, p_type), reachable in zip(all_providers, check_results):
meta = p.meta()
id_ = meta.id
error_code = None
if isinstance(reachable, asyncio.CancelledError):
raise reachable
if isinstance(reachable, Exception):
# 异常情况下兜底处理,避免单个 provider 导致列表失败
self._log_reachability_failure(
p,
None,
reachable.__class__.__name__,
safe_error("", reachable),
)
reachable_flag = False
error_code = reachable.__class__.__name__
elif isinstance(reachable, tuple):
reachable_flag, error_code, _ = reachable
else:
reachable_flag = reachable
# 根据类型构建显示名称
if p_type == "llm":
info = f"{id_} ({meta.model})"
else:
info = f"{id_}"
# 确定状态标记
if reachable_flag is True:
mark = ""
elif reachable_flag is False:
if error_code:
mark = f" ❌(错误码: {error_code})"
else:
mark = ""
else:
mark = "" # 不支持检测时不显示标记
display_data.append(
{
"type": p_type,
"info": info,
"mark": mark,
"provider": p,
}
)
# 分组输出
# 1. LLM
llm_data = [d for d in display_data if d["type"] == "llm"]
for i, d in enumerate(llm_data):
line = f"{i + 1}. {d['info']}{d['mark']}"
provider_using = self.context.get_using_provider(umo=umo)
if (
provider_using
and provider_using.meta().id == d["provider"].meta().id
):
line += " (当前使用)"
parts.append(line + "\n")
# 2. TTS
tts_data = [d for d in display_data if d["type"] == "tts"]
if tts_data:
parts.append("\n## 载入的 TTS 提供商\n")
for i, d in enumerate(tts_data):
line = f"{i + 1}. {d['info']}{d['mark']}"
tts_using = self.context.get_using_tts_provider(umo=umo)
if tts_using and tts_using.meta().id == d["provider"].meta().id:
line += " (当前使用)"
parts.append(line + "\n")
# 3. STT
stt_data = [d for d in display_data if d["type"] == "stt"]
if stt_data:
parts.append("\n## 载入的 STT 提供商\n")
for i, d in enumerate(stt_data):
line = f"{i + 1}. {d['info']}{d['mark']}"
stt_using = self.context.get_using_stt_provider(umo=umo)
if stt_using and stt_using.meta().id == d["provider"].meta().id:
line += " (当前使用)"
parts.append(line + "\n")
parts.append("\n使用 /provider <序号> 切换 LLM 提供商。")
ret = "".join(parts)
if ttss:
ret += "\n使用 /provider tts <序号> 切换 TTS 提供商。"
if stts:
ret += "\n使用 /provider stt <序号> 切换 STT 提供商。"
if not reachability_check_enabled:
ret += "\n已跳过提供商可达性检测,如需检测请在配置文件中开启。"
event.set_result(MessageEventResult().message(ret))
elif idx == "tts":
if idx2 is None:
event.set_result(MessageEventResult().message("请输入序号。"))
return
if idx2 > len(self.context.get_all_tts_providers()) or idx2 < 1:
event.set_result(MessageEventResult().message("无效的提供商序号。"))
return
provider = self.context.get_all_tts_providers()[idx2 - 1]
id_ = provider.meta().id
await self.context.provider_manager.set_provider(
provider_id=id_,
provider_type=ProviderType.TEXT_TO_SPEECH,
umo=umo,
)
event.set_result(MessageEventResult().message(f"成功切换到 {id_}"))
elif idx == "stt":
if idx2 is None:
event.set_result(MessageEventResult().message("请输入序号。"))
return
if idx2 > len(self.context.get_all_stt_providers()) or idx2 < 1:
event.set_result(MessageEventResult().message("无效的提供商序号。"))
return
provider = self.context.get_all_stt_providers()[idx2 - 1]
id_ = provider.meta().id
await self.context.provider_manager.set_provider(
provider_id=id_,
provider_type=ProviderType.SPEECH_TO_TEXT,
umo=umo,
)
event.set_result(MessageEventResult().message(f"成功切换到 {id_}"))
elif isinstance(idx, int):
if idx > len(self.context.get_all_providers()) or idx < 1:
event.set_result(MessageEventResult().message("无效的提供商序号。"))
return
provider = self.context.get_all_providers()[idx - 1]
id_ = provider.meta().id
await self.context.provider_manager.set_provider(
provider_id=id_,
provider_type=ProviderType.CHAT_COMPLETION,
umo=umo,
)
event.set_result(MessageEventResult().message(f"成功切换到 {id_}"))
else:
event.set_result(MessageEventResult().message("无效的参数。"))
async def _switch_model_by_name(
self, message: AstrMessageEvent, model_name: str, prov: Provider
) -> None:
model_name = model_name.strip()
if not model_name:
message.set_result(MessageEventResult().message("模型名不能为空。"))
return
umo = message.unified_msg_origin
config = self._get_model_lookup_config(umo)
curr_provider_id = prov.meta().id
models = await self._get_models_or_reply_error(
message,
prov,
config,
error_prefix="获取当前提供商模型列表失败: ",
warning_log="获取当前提供商 %s 模型列表失败,停止跨提供商查找: %s",
)
if models is None:
return
matched_model_name = self._resolve_model_name(model_name, models)
if matched_model_name is not None:
message.set_result(
MessageEventResult().message(
self._apply_model(prov, matched_model_name, umo=umo)
),
)
return
target_prov, matched_target_model_name = await self._find_provider_for_model(
model_name,
exclude_provider_id=curr_provider_id,
config=config,
)
if target_prov is None or matched_target_model_name is None:
message.set_result(
MessageEventResult().message(
f"模型 [{model_name}] 未在任何已配置的提供商中找到,或所有提供商模型列表获取失败,请检查配置或网络后重试。",
),
)
return
target_id = target_prov.meta().id
try:
await self.context.provider_manager.set_provider(
provider_id=target_id,
provider_type=ProviderType.CHAT_COMPLETION,
umo=umo,
)
self._apply_model(target_prov, matched_target_model_name, umo=umo)
message.set_result(
MessageEventResult().message(
f"检测到模型 [{matched_target_model_name}] 属于提供商 [{target_id}],已自动切换提供商并设置模型。",
),
)
except asyncio.CancelledError:
raise
except Exception as e:
message.set_result(
MessageEventResult().message(
safe_error("跨提供商切换并设置模型失败: ", e)
),
)
async def model_ls(
self,
message: AstrMessageEvent,
idx_or_name: int | str | None = None,
) -> None:
"""查看或者切换模型"""
prov = self.context.get_using_provider(message.unified_msg_origin)
if not prov:
message.set_result(
MessageEventResult().message("未找到任何 LLM 提供商。请先配置。"),
)
return
config = self._get_model_lookup_config(message.unified_msg_origin)
if idx_or_name is None:
models = await self._get_models_or_reply_error(
message,
prov,
config,
error_prefix="获取模型列表失败: ",
disable_t2i=True,
)
if models is None:
return
parts = ["下面列出了此模型提供商可用模型:"]
for i, model in enumerate(models, 1):
parts.append(f"\n{i}. {model}")
curr_model = prov.get_model() or ""
parts.append(f"\n当前模型: [{curr_model}]")
parts.append(
"\nTips: 使用 /model <模型名/编号> 切换模型。输入模型名时可自动跨提供商查找并切换;跨提供商也可使用 /provider 切换。"
)
ret = "".join(parts)
message.set_result(MessageEventResult().message(ret).use_t2i(False))
elif isinstance(idx_or_name, int):
models = await self._get_models_or_reply_error(
message,
prov,
config,
error_prefix="获取模型列表失败: ",
)
if models is None:
return
if idx_or_name > len(models) or idx_or_name < 1:
message.set_result(MessageEventResult().message("模型序号错误。"))
else:
try:
new_model = models[idx_or_name - 1]
message.set_result(
MessageEventResult().message(
self._apply_model(
prov,
new_model,
umo=message.unified_msg_origin,
)
),
)
except Exception as e:
message.set_result(
MessageEventResult().message(
safe_error("切换模型未知错误: ", e)
),
)
return
else:
await self._switch_model_by_name(message, idx_or_name, prov)
async def key(self, message: AstrMessageEvent, index: int | None = None) -> None:
prov = self.context.get_using_provider(message.unified_msg_origin)
if not prov:
message.set_result(
MessageEventResult().message("未找到任何 LLM 提供商。请先配置。"),
)
return
if index is None:
keys_data = prov.get_keys()
curr_key = prov.get_current_key()
parts = ["Key:"]
for i, k in enumerate(keys_data, 1):
parts.append(f"\n{i}. {k[:8]}")
parts.append(f"\n当前 Key: {curr_key[:8]}")
parts.append("\n当前模型: " + prov.get_model())
parts.append("\n使用 /key <idx> 切换 Key。")
ret = "".join(parts)
message.set_result(MessageEventResult().message(ret).use_t2i(False))
else:
keys_data = prov.get_keys()
if index > len(keys_data) or index < 1:
message.set_result(MessageEventResult().message("Key 序号错误。"))
else:
try:
new_key = keys_data[index - 1]
prov.set_key(new_key)
self.invalidate_provider_models_cache(
prov.meta().id,
umo=message.unified_msg_origin,
)
message.set_result(MessageEventResult().message("切换 Key 成功。"))
except Exception as e:
message.set_result(
MessageEventResult().message(
safe_error("切换 Key 未知错误: ", e)
),
)
return

Some files were not shown because too many files have changed in this diff Show More