Showing preview only (7,575K chars total). Download the full file or copy to clipboard to get everything.
Repository: AstrBotDevs/AstrBot
Branch: master
Commit: 39131d2e12bd
Files: 1231
Total size: 7.0 MB
Directory structure:
gitextract_qqwyrvoh/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── PLUGIN_PUBLISH.yml
│ │ ├── bug-report.yml
│ │ └── feature-request.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── auto_assign.yml
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-docs.yml
│ ├── code-format.yml
│ ├── codeql.yml
│ ├── coverage_test.yml
│ ├── dashboard_ci.yml
│ ├── docker-image.yml
│ ├── pr-title-check.yml
│ ├── release.yml
│ ├── smoke_test.yml
│ ├── stale.yml
│ └── sync-wiki.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── EULA.md
├── FIRST_NOTICE.en-US.md
├── FIRST_NOTICE.md
├── LICENSE
├── Makefile
├── README.md
├── README_fr.md
├── README_ja.md
├── README_ru.md
├── README_zh-TW.md
├── README_zh.md
├── astrbot/
│ ├── __init__.py
│ ├── api/
│ │ ├── __init__.py
│ │ ├── all.py
│ │ ├── event/
│ │ │ ├── __init__.py
│ │ │ └── filter/
│ │ │ └── __init__.py
│ │ ├── message_components.py
│ │ ├── platform/
│ │ │ └── __init__.py
│ │ ├── provider/
│ │ │ └── __init__.py
│ │ ├── star/
│ │ │ └── __init__.py
│ │ └── util/
│ │ └── __init__.py
│ ├── builtin_stars/
│ │ ├── astrbot/
│ │ │ ├── long_term_memory.py
│ │ │ ├── main.py
│ │ │ └── metadata.yaml
│ │ ├── builtin_commands/
│ │ │ ├── commands/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── admin.py
│ │ │ │ ├── alter_cmd.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── help.py
│ │ │ │ ├── llm.py
│ │ │ │ ├── persona.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── provider.py
│ │ │ │ ├── setunset.py
│ │ │ │ ├── sid.py
│ │ │ │ ├── t2i.py
│ │ │ │ ├── tts.py
│ │ │ │ └── utils/
│ │ │ │ └── rst_scene.py
│ │ │ ├── main.py
│ │ │ └── metadata.yaml
│ │ ├── session_controller/
│ │ │ ├── main.py
│ │ │ └── metadata.yaml
│ │ └── web_searcher/
│ │ ├── engines/
│ │ │ ├── __init__.py
│ │ │ ├── bing.py
│ │ │ └── sogo.py
│ │ ├── main.py
│ │ └── metadata.yaml
│ ├── cli/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── commands/
│ │ │ ├── __init__.py
│ │ │ ├── cmd_conf.py
│ │ │ ├── cmd_init.py
│ │ │ ├── cmd_plug.py
│ │ │ └── cmd_run.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── basic.py
│ │ ├── plugin.py
│ │ └── version_comparator.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── agent/
│ │ │ ├── agent.py
│ │ │ ├── context/
│ │ │ │ ├── compressor.py
│ │ │ │ ├── config.py
│ │ │ │ ├── manager.py
│ │ │ │ ├── token_counter.py
│ │ │ │ └── truncator.py
│ │ │ ├── handoff.py
│ │ │ ├── hooks.py
│ │ │ ├── mcp_client.py
│ │ │ ├── message.py
│ │ │ ├── response.py
│ │ │ ├── run_context.py
│ │ │ ├── runners/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── coze/
│ │ │ │ │ ├── coze_agent_runner.py
│ │ │ │ │ └── coze_api_client.py
│ │ │ │ ├── dashscope/
│ │ │ │ │ └── dashscope_agent_runner.py
│ │ │ │ ├── deerflow/
│ │ │ │ │ ├── constants.py
│ │ │ │ │ ├── deerflow_agent_runner.py
│ │ │ │ │ ├── deerflow_api_client.py
│ │ │ │ │ ├── deerflow_content_mapper.py
│ │ │ │ │ └── deerflow_stream_utils.py
│ │ │ │ ├── dify/
│ │ │ │ │ ├── dify_agent_runner.py
│ │ │ │ │ └── dify_api_client.py
│ │ │ │ └── tool_loop_agent_runner.py
│ │ │ ├── tool.py
│ │ │ ├── tool_executor.py
│ │ │ └── tool_image_cache.py
│ │ ├── astr_agent_context.py
│ │ ├── astr_agent_hooks.py
│ │ ├── astr_agent_run_util.py
│ │ ├── astr_agent_tool_exec.py
│ │ ├── astr_main_agent.py
│ │ ├── astr_main_agent_resources.py
│ │ ├── astrbot_config_mgr.py
│ │ ├── backup/
│ │ │ ├── __init__.py
│ │ │ ├── constants.py
│ │ │ ├── exporter.py
│ │ │ └── importer.py
│ │ ├── computer/
│ │ │ ├── booters/
│ │ │ │ ├── base.py
│ │ │ │ ├── bay_manager.py
│ │ │ │ ├── boxlite.py
│ │ │ │ ├── local.py
│ │ │ │ ├── shipyard.py
│ │ │ │ └── shipyard_neo.py
│ │ │ ├── computer_client.py
│ │ │ ├── olayer/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── browser.py
│ │ │ │ ├── filesystem.py
│ │ │ │ ├── python.py
│ │ │ │ └── shell.py
│ │ │ └── tools/
│ │ │ ├── __init__.py
│ │ │ ├── browser.py
│ │ │ ├── fs.py
│ │ │ ├── neo_skills.py
│ │ │ ├── permissions.py
│ │ │ ├── python.py
│ │ │ └── shell.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ ├── astrbot_config.py
│ │ │ ├── default.py
│ │ │ └── i18n_utils.py
│ │ ├── conversation_mgr.py
│ │ ├── core_lifecycle.py
│ │ ├── cron/
│ │ │ ├── __init__.py
│ │ │ ├── events.py
│ │ │ └── manager.py
│ │ ├── db/
│ │ │ ├── __init__.py
│ │ │ ├── migration/
│ │ │ │ ├── helper.py
│ │ │ │ ├── migra_3_to_4.py
│ │ │ │ ├── migra_45_to_46.py
│ │ │ │ ├── migra_token_usage.py
│ │ │ │ ├── migra_webchat_session.py
│ │ │ │ ├── shared_preferences_v3.py
│ │ │ │ └── sqlite_v3.py
│ │ │ ├── po.py
│ │ │ ├── sqlite.py
│ │ │ └── vec_db/
│ │ │ ├── base.py
│ │ │ └── faiss_impl/
│ │ │ ├── __init__.py
│ │ │ ├── document_storage.py
│ │ │ ├── embedding_storage.py
│ │ │ ├── sqlite_init.sql
│ │ │ └── vec_db.py
│ │ ├── event_bus.py
│ │ ├── exceptions.py
│ │ ├── file_token_service.py
│ │ ├── initial_loader.py
│ │ ├── knowledge_base/
│ │ │ ├── chunking/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── fixed_size.py
│ │ │ │ └── recursive.py
│ │ │ ├── kb_db_sqlite.py
│ │ │ ├── kb_helper.py
│ │ │ ├── kb_mgr.py
│ │ │ ├── models.py
│ │ │ ├── parsers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── markitdown_parser.py
│ │ │ │ ├── pdf_parser.py
│ │ │ │ ├── text_parser.py
│ │ │ │ ├── url_parser.py
│ │ │ │ └── util.py
│ │ │ ├── prompts.py
│ │ │ └── retrieval/
│ │ │ ├── __init__.py
│ │ │ ├── hit_stopwords.txt
│ │ │ ├── manager.py
│ │ │ ├── rank_fusion.py
│ │ │ └── sparse_retriever.py
│ │ ├── log.py
│ │ ├── message/
│ │ │ ├── components.py
│ │ │ └── message_event_result.py
│ │ ├── persona_error_reply.py
│ │ ├── persona_mgr.py
│ │ ├── pipeline/
│ │ │ ├── __init__.py
│ │ │ ├── bootstrap.py
│ │ │ ├── content_safety_check/
│ │ │ │ ├── stage.py
│ │ │ │ └── strategies/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── baidu_aip.py
│ │ │ │ ├── keywords.py
│ │ │ │ └── strategy.py
│ │ │ ├── context.py
│ │ │ ├── context_utils.py
│ │ │ ├── preprocess_stage/
│ │ │ │ └── stage.py
│ │ │ ├── process_stage/
│ │ │ │ ├── follow_up.py
│ │ │ │ ├── method/
│ │ │ │ │ ├── agent_request.py
│ │ │ │ │ ├── agent_sub_stages/
│ │ │ │ │ │ ├── internal.py
│ │ │ │ │ │ └── third_party.py
│ │ │ │ │ └── star_request.py
│ │ │ │ └── stage.py
│ │ │ ├── rate_limit_check/
│ │ │ │ └── stage.py
│ │ │ ├── respond/
│ │ │ │ └── stage.py
│ │ │ ├── result_decorate/
│ │ │ │ └── stage.py
│ │ │ ├── scheduler.py
│ │ │ ├── session_status_check/
│ │ │ │ └── stage.py
│ │ │ ├── stage.py
│ │ │ ├── stage_order.py
│ │ │ ├── waking_check/
│ │ │ │ └── stage.py
│ │ │ └── whitelist_check/
│ │ │ └── stage.py
│ │ ├── platform/
│ │ │ ├── __init__.py
│ │ │ ├── astr_message_event.py
│ │ │ ├── astrbot_message.py
│ │ │ ├── manager.py
│ │ │ ├── message_session.py
│ │ │ ├── message_type.py
│ │ │ ├── platform.py
│ │ │ ├── platform_metadata.py
│ │ │ ├── register.py
│ │ │ └── sources/
│ │ │ ├── aiocqhttp/
│ │ │ │ ├── aiocqhttp_message_event.py
│ │ │ │ └── aiocqhttp_platform_adapter.py
│ │ │ ├── dingtalk/
│ │ │ │ ├── dingtalk_adapter.py
│ │ │ │ └── dingtalk_event.py
│ │ │ ├── discord/
│ │ │ │ ├── client.py
│ │ │ │ ├── components.py
│ │ │ │ ├── discord_platform_adapter.py
│ │ │ │ └── discord_platform_event.py
│ │ │ ├── kook/
│ │ │ │ ├── kook_adapter.py
│ │ │ │ ├── kook_client.py
│ │ │ │ ├── kook_config.py
│ │ │ │ ├── kook_event.py
│ │ │ │ └── kook_types.py
│ │ │ ├── lark/
│ │ │ │ ├── lark_adapter.py
│ │ │ │ ├── lark_event.py
│ │ │ │ └── server.py
│ │ │ ├── line/
│ │ │ │ ├── line_adapter.py
│ │ │ │ ├── line_api.py
│ │ │ │ └── line_event.py
│ │ │ ├── misskey/
│ │ │ │ ├── misskey_adapter.py
│ │ │ │ ├── misskey_api.py
│ │ │ │ ├── misskey_event.py
│ │ │ │ └── misskey_utils.py
│ │ │ ├── qqofficial/
│ │ │ │ ├── qqofficial_message_event.py
│ │ │ │ └── qqofficial_platform_adapter.py
│ │ │ ├── qqofficial_webhook/
│ │ │ │ ├── qo_webhook_adapter.py
│ │ │ │ ├── qo_webhook_event.py
│ │ │ │ └── qo_webhook_server.py
│ │ │ ├── satori/
│ │ │ │ ├── satori_adapter.py
│ │ │ │ └── satori_event.py
│ │ │ ├── slack/
│ │ │ │ ├── client.py
│ │ │ │ ├── slack_adapter.py
│ │ │ │ └── slack_event.py
│ │ │ ├── telegram/
│ │ │ │ ├── tg_adapter.py
│ │ │ │ └── tg_event.py
│ │ │ ├── webchat/
│ │ │ │ ├── message_parts_helper.py
│ │ │ │ ├── webchat_adapter.py
│ │ │ │ ├── webchat_event.py
│ │ │ │ └── webchat_queue_mgr.py
│ │ │ ├── wecom/
│ │ │ │ ├── wecom_adapter.py
│ │ │ │ ├── wecom_event.py
│ │ │ │ ├── wecom_kf.py
│ │ │ │ └── wecom_kf_message.py
│ │ │ ├── wecom_ai_bot/
│ │ │ │ ├── WXBizJsonMsgCrypt.py
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ierror.py
│ │ │ │ ├── wecomai_adapter.py
│ │ │ │ ├── wecomai_api.py
│ │ │ │ ├── wecomai_event.py
│ │ │ │ ├── wecomai_long_connection.py
│ │ │ │ ├── wecomai_queue_mgr.py
│ │ │ │ ├── wecomai_server.py
│ │ │ │ ├── wecomai_utils.py
│ │ │ │ └── wecomai_webhook.py
│ │ │ └── weixin_official_account/
│ │ │ ├── weixin_offacc_adapter.py
│ │ │ └── weixin_offacc_event.py
│ │ ├── platform_message_history_mgr.py
│ │ ├── provider/
│ │ │ ├── __init__.py
│ │ │ ├── entites.py
│ │ │ ├── entities.py
│ │ │ ├── func_tool_manager.py
│ │ │ ├── manager.py
│ │ │ ├── provider.py
│ │ │ ├── register.py
│ │ │ └── sources/
│ │ │ ├── anthropic_source.py
│ │ │ ├── azure_tts_source.py
│ │ │ ├── bailian_rerank_source.py
│ │ │ ├── dashscope_tts.py
│ │ │ ├── edge_tts_source.py
│ │ │ ├── fishaudio_tts_api_source.py
│ │ │ ├── gemini_embedding_source.py
│ │ │ ├── gemini_source.py
│ │ │ ├── gemini_tts_source.py
│ │ │ ├── genie_tts.py
│ │ │ ├── groq_source.py
│ │ │ ├── gsv_selfhosted_source.py
│ │ │ ├── gsvi_tts_source.py
│ │ │ ├── kimi_code_source.py
│ │ │ ├── minimax_tts_api_source.py
│ │ │ ├── oai_aihubmix_source.py
│ │ │ ├── openai_embedding_source.py
│ │ │ ├── openai_source.py
│ │ │ ├── openai_tts_api_source.py
│ │ │ ├── openrouter_source.py
│ │ │ ├── sensevoice_selfhosted_source.py
│ │ │ ├── vllm_rerank_source.py
│ │ │ ├── volcengine_tts.py
│ │ │ ├── whisper_api_source.py
│ │ │ ├── whisper_selfhosted_source.py
│ │ │ ├── xai_source.py
│ │ │ ├── xinference_rerank_source.py
│ │ │ ├── xinference_stt_provider.py
│ │ │ └── zhipu_source.py
│ │ ├── sentinels.py
│ │ ├── skills/
│ │ │ ├── __init__.py
│ │ │ ├── neo_skill_sync.py
│ │ │ └── skill_manager.py
│ │ ├── star/
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── command_management.py
│ │ │ ├── config.py
│ │ │ ├── context.py
│ │ │ ├── error_messages.py
│ │ │ ├── filter/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── command.py
│ │ │ │ ├── command_group.py
│ │ │ │ ├── custom_filter.py
│ │ │ │ ├── event_message_type.py
│ │ │ │ ├── permission.py
│ │ │ │ ├── platform_adapter_type.py
│ │ │ │ └── regex.py
│ │ │ ├── register/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── star.py
│ │ │ │ └── star_handler.py
│ │ │ ├── session_llm_manager.py
│ │ │ ├── session_plugin_manager.py
│ │ │ ├── star.py
│ │ │ ├── star_handler.py
│ │ │ ├── star_manager.py
│ │ │ ├── star_tools.py
│ │ │ └── updator.py
│ │ ├── subagent_orchestrator.py
│ │ ├── tools/
│ │ │ └── cron_tools.py
│ │ ├── umop_config_router.py
│ │ ├── updator.py
│ │ ├── utils/
│ │ │ ├── active_event_registry.py
│ │ │ ├── astrbot_path.py
│ │ │ ├── command_parser.py
│ │ │ ├── config_number.py
│ │ │ ├── core_constraints.py
│ │ │ ├── datetime_utils.py
│ │ │ ├── error_redaction.py
│ │ │ ├── file_extract.py
│ │ │ ├── history_saver.py
│ │ │ ├── http_ssl.py
│ │ │ ├── image_ref_utils.py
│ │ │ ├── io.py
│ │ │ ├── llm_metadata.py
│ │ │ ├── log_pipe.py
│ │ │ ├── media_utils.py
│ │ │ ├── metrics.py
│ │ │ ├── migra_helper.py
│ │ │ ├── network_utils.py
│ │ │ ├── path_util.py
│ │ │ ├── pip_installer.py
│ │ │ ├── plugin_kv_store.py
│ │ │ ├── quoted_message/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── chain_parser.py
│ │ │ │ ├── extractor.py
│ │ │ │ ├── image_refs.py
│ │ │ │ ├── image_resolver.py
│ │ │ │ ├── onebot_client.py
│ │ │ │ └── settings.py
│ │ │ ├── quoted_message_parser.py
│ │ │ ├── requirements_utils.py
│ │ │ ├── runtime_env.py
│ │ │ ├── session_lock.py
│ │ │ ├── session_waiter.py
│ │ │ ├── shared_preferences.py
│ │ │ ├── string_utils.py
│ │ │ ├── t2i/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── local_strategy.py
│ │ │ │ ├── network_strategy.py
│ │ │ │ ├── renderer.py
│ │ │ │ ├── template/
│ │ │ │ │ ├── astrbot_powershell.html
│ │ │ │ │ └── base.html
│ │ │ │ └── template_manager.py
│ │ │ ├── temp_dir_cleaner.py
│ │ │ ├── tencent_record_helper.py
│ │ │ ├── trace.py
│ │ │ ├── version_comparator.py
│ │ │ └── webhook_utils.py
│ │ └── zip_updator.py
│ ├── dashboard/
│ │ ├── routes/
│ │ │ ├── __init__.py
│ │ │ ├── api_key.py
│ │ │ ├── auth.py
│ │ │ ├── backup.py
│ │ │ ├── chat.py
│ │ │ ├── chatui_project.py
│ │ │ ├── command.py
│ │ │ ├── config.py
│ │ │ ├── conversation.py
│ │ │ ├── cron.py
│ │ │ ├── file.py
│ │ │ ├── knowledge_base.py
│ │ │ ├── live_chat.py
│ │ │ ├── log.py
│ │ │ ├── open_api.py
│ │ │ ├── persona.py
│ │ │ ├── platform.py
│ │ │ ├── plugin.py
│ │ │ ├── route.py
│ │ │ ├── session_management.py
│ │ │ ├── skills.py
│ │ │ ├── stat.py
│ │ │ ├── static_file.py
│ │ │ ├── subagent.py
│ │ │ ├── t2i.py
│ │ │ ├── tools.py
│ │ │ ├── update.py
│ │ │ └── util.py
│ │ ├── server.py
│ │ └── utils.py
│ └── utils/
│ ├── __init__.py
│ └── http_ssl_common.py
├── changelogs/
│ ├── v3.4.0.md
│ ├── v3.4.1.md
│ ├── v3.4.10.md
│ ├── v3.4.11.md
│ ├── v3.4.12.md
│ ├── v3.4.13.md
│ ├── v3.4.14.md
│ ├── v3.4.15.md
│ ├── v3.4.16.md
│ ├── v3.4.17.md
│ ├── v3.4.18.md
│ ├── v3.4.19.md
│ ├── v3.4.20.md
│ ├── v3.4.21.md
│ ├── v3.4.22.md
│ ├── v3.4.23.md
│ ├── v3.4.24.md
│ ├── v3.4.25.md
│ ├── v3.4.26.md
│ ├── v3.4.27.md
│ ├── v3.4.28.md
│ ├── v3.4.29.md
│ ├── v3.4.3.md
│ ├── v3.4.30.md
│ ├── v3.4.31.md
│ ├── v3.4.32.md
│ ├── v3.4.33.md
│ ├── v3.4.35.md
│ ├── v3.4.36.md
│ ├── v3.4.37.md
│ ├── v3.4.38.md
│ ├── v3.4.39.md
│ ├── v3.4.4.md
│ ├── v3.4.5.md
│ ├── v3.4.6.md
│ ├── v3.4.7.md
│ ├── v3.4.8.md
│ ├── v3.4.9.md
│ ├── v3.5.0.md
│ ├── v3.5.1.md
│ ├── v3.5.10.md
│ ├── v3.5.11.md
│ ├── v3.5.12.md
│ ├── v3.5.13.md
│ ├── v3.5.14.md
│ ├── v3.5.15.md
│ ├── v3.5.16.md
│ ├── v3.5.17.md
│ ├── v3.5.18.md
│ ├── v3.5.19.md
│ ├── v3.5.2.md
│ ├── v3.5.20.md
│ ├── v3.5.21.md
│ ├── v3.5.22.md
│ ├── v3.5.23.md
│ ├── v3.5.24.md
│ ├── v3.5.25.md
│ ├── v3.5.26.md
│ ├── v3.5.27.md
│ ├── v3.5.3.1.md
│ ├── v3.5.3.2.md
│ ├── v3.5.3.md
│ ├── v3.5.4.md
│ ├── v3.5.5.md
│ ├── v3.5.6.md
│ ├── v3.5.7.md
│ ├── v3.5.8.md
│ ├── v3.5.9.md
│ ├── v4.0.0-beta.3.md
│ ├── v4.0.0-beta.4.md
│ ├── v4.0.0-beta.5.md
│ ├── v4.0.0.md
│ ├── v4.1.0.md
│ ├── v4.1.1.md
│ ├── v4.1.2.md
│ ├── v4.1.3.md
│ ├── v4.1.4.md
│ ├── v4.1.5.md
│ ├── v4.1.6.md
│ ├── v4.1.7.md
│ ├── v4.10.0-alpha.1.md
│ ├── v4.10.0-alpha.2.md
│ ├── v4.10.0.md
│ ├── v4.10.1.md
│ ├── v4.10.2.md
│ ├── v4.10.3.md
│ ├── v4.10.4.md
│ ├── v4.10.5.md
│ ├── v4.10.6.md
│ ├── v4.11.0.md
│ ├── v4.11.1.md
│ ├── v4.11.2.md
│ ├── v4.11.3.md
│ ├── v4.11.4.md
│ ├── v4.12.0.md
│ ├── v4.12.1.md
│ ├── v4.12.2.md
│ ├── v4.12.3.md
│ ├── v4.12.4.md
│ ├── v4.13.0.md
│ ├── v4.13.1.md
│ ├── v4.13.2.md
│ ├── v4.14.0.md
│ ├── v4.14.1.md
│ ├── v4.14.2.md
│ ├── v4.14.3.md
│ ├── v4.14.4.md
│ ├── v4.14.5.md
│ ├── v4.14.6.md
│ ├── v4.14.7.md
│ ├── v4.14.8.md
│ ├── v4.15.0.md
│ ├── v4.16.0.md
│ ├── v4.17.0.md
│ ├── v4.17.1.md
│ ├── v4.17.2.md
│ ├── v4.17.3.md
│ ├── v4.17.4.md
│ ├── v4.17.5.md
│ ├── v4.17.6.md
│ ├── v4.18.0.md
│ ├── v4.18.1.md
│ ├── v4.18.2.md
│ ├── v4.18.3.md
│ ├── v4.19.2.md
│ ├── v4.19.3.md
│ ├── v4.19.4.md
│ ├── v4.19.5.md
│ ├── v4.2.0.md
│ ├── v4.2.1.md
│ ├── v4.20.0.md
│ ├── v4.20.1.md
│ ├── v4.3.0.md
│ ├── v4.3.1.md
│ ├── v4.3.2.md
│ ├── v4.3.3.md
│ ├── v4.3.5.md
│ ├── v4.5.0.md
│ ├── v4.5.1.md
│ ├── v4.5.2.md
│ ├── v4.5.3.md
│ ├── v4.5.4.md
│ ├── v4.5.5.md
│ ├── v4.5.6.md
│ ├── v4.5.7.md
│ ├── v4.5.8.md
│ ├── v4.6.0.md
│ ├── v4.6.1.md
│ ├── v4.7.0.md
│ ├── v4.7.1.md
│ ├── v4.7.3.md
│ ├── v4.7.4.md
│ ├── v4.8.0.md
│ ├── v4.9.0.md
│ ├── v4.9.1.md
│ └── v4.9.2.md
├── compose-with-shipyard.yml
├── compose.yml
├── dashboard/
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── env.d.ts
│ ├── index.html
│ ├── package.json
│ ├── public/
│ │ ├── _redirects
│ │ └── robots.txt
│ ├── scripts/
│ │ └── subset-mdi-font.mjs
│ ├── src/
│ │ ├── App.vue
│ │ ├── assets/
│ │ │ └── mdi-subset/
│ │ │ └── materialdesignicons-subset.css
│ │ ├── components/
│ │ │ ├── ConfirmDialog.vue
│ │ │ ├── chat/
│ │ │ │ ├── Chat.vue
│ │ │ │ ├── ChatInput.vue
│ │ │ │ ├── ConfigSelector.vue
│ │ │ │ ├── ConversationSidebar.vue
│ │ │ │ ├── LiveMode.vue
│ │ │ │ ├── LiveOrb.vue
│ │ │ │ ├── MessageList.vue
│ │ │ │ ├── ProjectDialog.vue
│ │ │ │ ├── ProjectList.vue
│ │ │ │ ├── ProjectView.vue
│ │ │ │ ├── ProviderConfigDialog.vue
│ │ │ │ ├── ProviderModelMenu.vue
│ │ │ │ ├── StandaloneChat.vue
│ │ │ │ ├── WelcomeView.vue
│ │ │ │ └── message_list_comps/
│ │ │ │ ├── ActionRef.vue
│ │ │ │ ├── IPythonToolBlock.vue
│ │ │ │ ├── MessagePartsRenderer.vue
│ │ │ │ ├── ReasoningBlock.vue
│ │ │ │ ├── RefNode.vue
│ │ │ │ ├── RefsSidebar.vue
│ │ │ │ ├── ToolCallCard.vue
│ │ │ │ └── ToolCallItem.vue
│ │ │ ├── config/
│ │ │ │ ├── AstrBotCoreConfigWrapper.vue
│ │ │ │ └── UnsavedChangesConfirmDialog.vue
│ │ │ ├── extension/
│ │ │ │ ├── MarketPluginCard.vue
│ │ │ │ ├── McpServersSection.vue
│ │ │ │ ├── PluginSortControl.vue
│ │ │ │ ├── SkillsSection.vue
│ │ │ │ └── componentPanel/
│ │ │ │ ├── components/
│ │ │ │ │ ├── CommandFilters.vue
│ │ │ │ │ ├── CommandTable.vue
│ │ │ │ │ ├── DetailsDialog.vue
│ │ │ │ │ ├── RenameDialog.vue
│ │ │ │ │ └── ToolTable.vue
│ │ │ │ ├── composables/
│ │ │ │ │ ├── useCommandActions.ts
│ │ │ │ │ ├── useCommandFilters.ts
│ │ │ │ │ └── useComponentData.ts
│ │ │ │ ├── index.vue
│ │ │ │ └── types.ts
│ │ │ ├── folder/
│ │ │ │ ├── BaseCreateFolderDialog.vue
│ │ │ │ ├── BaseFolderBreadcrumb.vue
│ │ │ │ ├── BaseFolderCard.vue
│ │ │ │ ├── BaseFolderItemSelector.vue
│ │ │ │ ├── BaseFolderTree.vue
│ │ │ │ ├── BaseFolderTreeNode.vue
│ │ │ │ ├── BaseMoveTargetNode.vue
│ │ │ │ ├── BaseMoveToFolderDialog.vue
│ │ │ │ ├── README.md
│ │ │ │ ├── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── useFolderManager.ts
│ │ │ ├── platform/
│ │ │ │ └── AddNewPlatform.vue
│ │ │ ├── provider/
│ │ │ │ ├── AddNewProvider.vue
│ │ │ │ ├── ProviderModelsPanel.vue
│ │ │ │ └── ProviderSourcesPanel.vue
│ │ │ └── shared/
│ │ │ ├── AstrBotConfig.vue
│ │ │ ├── AstrBotConfigV4.vue
│ │ │ ├── BackupDialog.vue
│ │ │ ├── ChangelogDialog.vue
│ │ │ ├── ConfigItemRenderer.vue
│ │ │ ├── ConsoleDisplayer.vue
│ │ │ ├── ExtensionCard.vue
│ │ │ ├── FileConfigItem.vue
│ │ │ ├── ItemCard.vue
│ │ │ ├── ItemCardGrid.vue
│ │ │ ├── KnowledgeBaseSelector.vue
│ │ │ ├── LanguageSwitcher.vue
│ │ │ ├── ListConfigItem.vue
│ │ │ ├── Logo.vue
│ │ │ ├── MigrationDialog.vue
│ │ │ ├── ObjectEditor.vue
│ │ │ ├── PersonaForm.vue
│ │ │ ├── PersonaQuickPreview.vue
│ │ │ ├── PersonaSelector.vue
│ │ │ ├── PluginPlatformChip.vue
│ │ │ ├── PluginSetSelector.vue
│ │ │ ├── ProviderSelector.vue
│ │ │ ├── ProxySelector.vue
│ │ │ ├── ReadmeDialog.vue
│ │ │ ├── SidebarCustomizer.vue
│ │ │ ├── StyledMenu.vue
│ │ │ ├── T2ITemplateEditor.vue
│ │ │ ├── TemplateListEditor.vue
│ │ │ ├── TraceDisplayer.vue
│ │ │ ├── UninstallConfirmDialog.vue
│ │ │ └── WaitingForRestart.vue
│ │ ├── composables/
│ │ │ ├── useConversations.ts
│ │ │ ├── useMediaHandling.ts
│ │ │ ├── useMessages.ts
│ │ │ ├── useProjects.ts
│ │ │ ├── useProviderSources.ts
│ │ │ ├── useRecording.ts
│ │ │ ├── useSessions.ts
│ │ │ └── useVADRecording.ts
│ │ ├── config.ts
│ │ ├── i18n/
│ │ │ ├── composables.ts
│ │ │ ├── loader.ts
│ │ │ ├── locales/
│ │ │ │ ├── en-US/
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── actions.json
│ │ │ │ │ │ ├── common.json
│ │ │ │ │ │ ├── header.json
│ │ │ │ │ │ ├── navigation.json
│ │ │ │ │ │ ├── shared.json
│ │ │ │ │ │ └── status.json
│ │ │ │ │ ├── features/
│ │ │ │ │ │ ├── about.json
│ │ │ │ │ │ ├── alkaid/
│ │ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ │ ├── knowledge-base.json
│ │ │ │ │ │ │ └── memory.json
│ │ │ │ │ │ ├── auth.json
│ │ │ │ │ │ ├── chart.json
│ │ │ │ │ │ ├── chat.json
│ │ │ │ │ │ ├── command.json
│ │ │ │ │ │ ├── config-metadata.json
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── console.json
│ │ │ │ │ │ ├── conversation.json
│ │ │ │ │ │ ├── cron.json
│ │ │ │ │ │ ├── dashboard.json
│ │ │ │ │ │ ├── extension.json
│ │ │ │ │ │ ├── knowledge-base/
│ │ │ │ │ │ │ ├── detail.json
│ │ │ │ │ │ │ ├── document.json
│ │ │ │ │ │ │ └── index.json
│ │ │ │ │ │ ├── migration.json
│ │ │ │ │ │ ├── persona.json
│ │ │ │ │ │ ├── platform.json
│ │ │ │ │ │ ├── provider.json
│ │ │ │ │ │ ├── session-management.json
│ │ │ │ │ │ ├── settings.json
│ │ │ │ │ │ ├── subagent.json
│ │ │ │ │ │ ├── tool-use.json
│ │ │ │ │ │ ├── trace.json
│ │ │ │ │ │ └── welcome.json
│ │ │ │ │ └── messages/
│ │ │ │ │ ├── errors.json
│ │ │ │ │ ├── success.json
│ │ │ │ │ └── validation.json
│ │ │ │ ├── ru-RU/
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── actions.json
│ │ │ │ │ │ ├── common.json
│ │ │ │ │ │ ├── header.json
│ │ │ │ │ │ ├── navigation.json
│ │ │ │ │ │ ├── shared.json
│ │ │ │ │ │ └── status.json
│ │ │ │ │ ├── features/
│ │ │ │ │ │ ├── about.json
│ │ │ │ │ │ ├── alkaid/
│ │ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ │ ├── knowledge-base.json
│ │ │ │ │ │ │ └── memory.json
│ │ │ │ │ │ ├── auth.json
│ │ │ │ │ │ ├── chart.json
│ │ │ │ │ │ ├── chat.json
│ │ │ │ │ │ ├── command.json
│ │ │ │ │ │ ├── config-metadata.json
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── console.json
│ │ │ │ │ │ ├── conversation.json
│ │ │ │ │ │ ├── cron.json
│ │ │ │ │ │ ├── dashboard.json
│ │ │ │ │ │ ├── extension.json
│ │ │ │ │ │ ├── knowledge-base/
│ │ │ │ │ │ │ ├── detail.json
│ │ │ │ │ │ │ ├── document.json
│ │ │ │ │ │ │ └── index.json
│ │ │ │ │ │ ├── migration.json
│ │ │ │ │ │ ├── persona.json
│ │ │ │ │ │ ├── platform.json
│ │ │ │ │ │ ├── provider.json
│ │ │ │ │ │ ├── session-management.json
│ │ │ │ │ │ ├── settings.json
│ │ │ │ │ │ ├── subagent.json
│ │ │ │ │ │ ├── tool-use.json
│ │ │ │ │ │ ├── trace.json
│ │ │ │ │ │ └── welcome.json
│ │ │ │ │ └── messages/
│ │ │ │ │ ├── errors.json
│ │ │ │ │ ├── success.json
│ │ │ │ │ └── validation.json
│ │ │ │ └── zh-CN/
│ │ │ │ ├── core/
│ │ │ │ │ ├── actions.json
│ │ │ │ │ ├── common.json
│ │ │ │ │ ├── header.json
│ │ │ │ │ ├── navigation.json
│ │ │ │ │ ├── shared.json
│ │ │ │ │ └── status.json
│ │ │ │ ├── features/
│ │ │ │ │ ├── about.json
│ │ │ │ │ ├── alkaid/
│ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ ├── knowledge-base.json
│ │ │ │ │ │ └── memory.json
│ │ │ │ │ ├── auth.json
│ │ │ │ │ ├── chart.json
│ │ │ │ │ ├── chat.json
│ │ │ │ │ ├── command.json
│ │ │ │ │ ├── config-metadata.json
│ │ │ │ │ ├── config.json
│ │ │ │ │ ├── console.json
│ │ │ │ │ ├── conversation.json
│ │ │ │ │ ├── cron.json
│ │ │ │ │ ├── dashboard.json
│ │ │ │ │ ├── extension.json
│ │ │ │ │ ├── knowledge-base/
│ │ │ │ │ │ ├── detail.json
│ │ │ │ │ │ ├── document.json
│ │ │ │ │ │ └── index.json
│ │ │ │ │ ├── migration.json
│ │ │ │ │ ├── persona.json
│ │ │ │ │ ├── platform.json
│ │ │ │ │ ├── provider.json
│ │ │ │ │ ├── session-management.json
│ │ │ │ │ ├── settings.json
│ │ │ │ │ ├── subagent.json
│ │ │ │ │ ├── tool-use.json
│ │ │ │ │ ├── trace.json
│ │ │ │ │ └── welcome.json
│ │ │ │ └── messages/
│ │ │ │ ├── errors.json
│ │ │ │ ├── success.json
│ │ │ │ └── validation.json
│ │ │ ├── tools/
│ │ │ │ └── index.ts
│ │ │ ├── translations.ts
│ │ │ ├── types.ts
│ │ │ └── validator.ts
│ │ ├── layouts/
│ │ │ ├── blank/
│ │ │ │ └── BlankLayout.vue
│ │ │ └── full/
│ │ │ ├── FullLayout.vue
│ │ │ ├── vertical-header/
│ │ │ │ └── VerticalHeader.vue
│ │ │ └── vertical-sidebar/
│ │ │ ├── NavItem.vue
│ │ │ ├── VerticalSidebar.vue
│ │ │ └── sidebarItem.ts
│ │ ├── main.ts
│ │ ├── plugins/
│ │ │ ├── confirmPlugin.ts
│ │ │ └── vuetify.ts
│ │ ├── router/
│ │ │ ├── AuthRoutes.ts
│ │ │ ├── ChatBoxRoutes.ts
│ │ │ ├── MainRoutes.ts
│ │ │ ├── index.ts
│ │ │ └── routeConstants.mjs
│ │ ├── scss/
│ │ │ ├── _override.scss
│ │ │ ├── _variables.scss
│ │ │ ├── components/
│ │ │ │ ├── _VButtons.scss
│ │ │ │ ├── _VCard.scss
│ │ │ │ ├── _VField.scss
│ │ │ │ ├── _VInput.scss
│ │ │ │ ├── _VNavigationDrawer.scss
│ │ │ │ ├── _VScrollbar.scss
│ │ │ │ ├── _VShadow.scss
│ │ │ │ ├── _VTabs.scss
│ │ │ │ └── _VTextField.scss
│ │ │ ├── layout/
│ │ │ │ ├── _container.scss
│ │ │ │ └── _sidebar.scss
│ │ │ ├── pages/
│ │ │ │ └── _dashboards.scss
│ │ │ └── style.scss
│ │ ├── stores/
│ │ │ ├── auth.ts
│ │ │ ├── common.js
│ │ │ ├── customizer.ts
│ │ │ ├── personaStore.ts
│ │ │ ├── routerLoading.ts
│ │ │ └── toast.js
│ │ ├── theme/
│ │ │ ├── DarkTheme.ts
│ │ │ └── LightTheme.ts
│ │ ├── types/
│ │ │ ├── confirm.d.ts
│ │ │ ├── desktop-bridge.d.ts
│ │ │ ├── themeTypes/
│ │ │ │ └── ThemeType.ts
│ │ │ ├── vue3-print-nb.d.ts
│ │ │ └── vue_tabler_icon.d.ts
│ │ ├── utils/
│ │ │ ├── chatConfigBinding.ts
│ │ │ ├── confirmDialog.ts
│ │ │ ├── desktopRuntime.ts
│ │ │ ├── errorUtils.js
│ │ │ ├── hashRouteTabs.mjs
│ │ │ ├── inputValue.ts
│ │ │ ├── platformUtils.js
│ │ │ ├── pluginSearch.js
│ │ │ ├── providerUtils.js
│ │ │ ├── restartAstrBot.ts
│ │ │ ├── routerReadiness.mjs
│ │ │ ├── sidebarCustomization.js
│ │ │ └── toast.js
│ │ └── views/
│ │ ├── AboutPage.vue
│ │ ├── AlkaidPage.vue
│ │ ├── ChatBoxPage.vue
│ │ ├── ChatPage.vue
│ │ ├── ConfigPage.vue
│ │ ├── ConsolePage.vue
│ │ ├── ConversationPage.vue
│ │ ├── CronJobPage.vue
│ │ ├── ExtensionPage.vue
│ │ ├── PersonaPage.vue
│ │ ├── PlatformPage.vue
│ │ ├── ProviderPage.vue
│ │ ├── SessionManagementPage.vue
│ │ ├── Settings.vue
│ │ ├── SubAgentPage.vue
│ │ ├── TracePage.vue
│ │ ├── WelcomePage.vue
│ │ ├── alkaid/
│ │ │ ├── KnowledgeBase.vue
│ │ │ ├── LongTermMemory.vue
│ │ │ └── Other.vue
│ │ ├── authentication/
│ │ │ ├── auth/
│ │ │ │ └── LoginPage.vue
│ │ │ └── authForms/
│ │ │ └── AuthLogin.vue
│ │ ├── dashboards/
│ │ │ └── default/
│ │ │ ├── DefaultDashboard.vue
│ │ │ └── components/
│ │ │ ├── MemoryUsage.vue
│ │ │ ├── MessageStat.vue
│ │ │ ├── OnlinePlatform.vue
│ │ │ ├── OnlineTime.vue
│ │ │ ├── PlatformStat.vue
│ │ │ ├── RunningTime.vue
│ │ │ └── TotalMessage.vue
│ │ ├── extension/
│ │ │ ├── InstalledPluginsTab.vue
│ │ │ ├── MarketPluginsTab.vue
│ │ │ └── useExtensionPage.js
│ │ ├── knowledge-base/
│ │ │ ├── DocumentDetail.vue
│ │ │ ├── KBDetail.vue
│ │ │ ├── KBList.vue
│ │ │ ├── components/
│ │ │ │ ├── DocumentsTab.vue
│ │ │ │ ├── RetrievalTab.vue
│ │ │ │ ├── SettingsTab.vue
│ │ │ │ └── TavilyKeyDialog.vue
│ │ │ └── index.vue
│ │ └── persona/
│ │ ├── CreateFolderDialog.vue
│ │ ├── FolderBreadcrumb.vue
│ │ ├── FolderCard.vue
│ │ ├── FolderTree.vue
│ │ ├── FolderTreeNode.vue
│ │ ├── MoveTargetNode.vue
│ │ ├── MoveToFolderDialog.vue
│ │ ├── PersonaCard.vue
│ │ ├── PersonaManager.vue
│ │ └── index.ts
│ ├── tests/
│ │ ├── hashRouteTabs.test.mjs
│ │ ├── routerReadiness.test.mjs
│ │ └── subsetMdiFont.test.mjs
│ ├── tsconfig.json
│ ├── tsconfig.vite-config.json
│ └── vite.config.ts
├── docs/
│ ├── .gitignore
│ ├── .vitepress/
│ │ ├── config/
│ │ │ └── head.ts
│ │ ├── config.mjs
│ │ └── theme/
│ │ ├── components/
│ │ │ ├── ArticleShare.vue
│ │ │ ├── HomeFeaturesAfter.vue
│ │ │ ├── Layout.vue
│ │ │ ├── NotFound.vue
│ │ │ └── SectionTabs.vue
│ │ ├── index.js
│ │ └── styles/
│ │ ├── custom-block.css
│ │ ├── font.css
│ │ └── style.css
│ ├── README.md
│ ├── en/
│ │ ├── community.md
│ │ ├── config/
│ │ │ └── model-config.md
│ │ ├── deploy/
│ │ │ ├── astrbot/
│ │ │ │ ├── 1panel.md
│ │ │ │ ├── btpanel.md
│ │ │ │ ├── casaos.md
│ │ │ │ ├── cli.md
│ │ │ │ ├── community-deployment.md
│ │ │ │ ├── compshare.md
│ │ │ │ ├── docker.md
│ │ │ │ ├── kubernetes.md
│ │ │ │ ├── launcher.md
│ │ │ │ ├── other-deployments.md
│ │ │ │ ├── package.md
│ │ │ │ └── sys-pm.md
│ │ │ └── when-deployed.md
│ │ ├── dev/
│ │ │ ├── astrbot-config.md
│ │ │ ├── openapi.md
│ │ │ ├── plugin-platform-adapter.md
│ │ │ ├── plugin.md
│ │ │ └── star/
│ │ │ ├── guides/
│ │ │ │ ├── ai.md
│ │ │ │ ├── env.md
│ │ │ │ ├── html-to-pic.md
│ │ │ │ ├── listen-message-event.md
│ │ │ │ ├── plugin-config.md
│ │ │ │ ├── send-message.md
│ │ │ │ ├── session-control.md
│ │ │ │ ├── simple.md
│ │ │ │ └── storage.md
│ │ │ ├── plugin-new.md
│ │ │ └── plugin-publish.md
│ │ ├── faq.md
│ │ ├── index.md
│ │ ├── ospp/
│ │ │ └── 2025.md
│ │ ├── others/
│ │ │ └── self-host-t2i.md
│ │ ├── platform/
│ │ │ ├── aiocqhttp.md
│ │ │ ├── dingtalk.md
│ │ │ ├── discord.md
│ │ │ ├── kook.md
│ │ │ ├── lark.md
│ │ │ ├── line.md
│ │ │ ├── matrix.md
│ │ │ ├── misskey.md
│ │ │ ├── qqofficial/
│ │ │ │ ├── webhook.md
│ │ │ │ └── websockets.md
│ │ │ ├── qqofficial.md
│ │ │ ├── satori/
│ │ │ │ ├── guide.md
│ │ │ │ └── server-satori.md
│ │ │ ├── slack.md
│ │ │ ├── start.md
│ │ │ ├── telegram.md
│ │ │ ├── vocechat.md
│ │ │ ├── wecom.md
│ │ │ ├── wecom_ai_bot.md
│ │ │ └── weixin-official-account.md
│ │ ├── providers/
│ │ │ ├── 302ai.md
│ │ │ ├── agent-runners/
│ │ │ │ ├── astrbot-agent-runner.md
│ │ │ │ ├── coze.md
│ │ │ │ ├── dashscope.md
│ │ │ │ ├── deerflow.md
│ │ │ │ └── dify.md
│ │ │ ├── agent-runners.md
│ │ │ ├── aihubmix.md
│ │ │ ├── coze.md
│ │ │ ├── dashscope.md
│ │ │ ├── dify.md
│ │ │ ├── llm.md
│ │ │ ├── newapi.md
│ │ │ ├── ppio.md
│ │ │ ├── provider-lmstudio.md
│ │ │ ├── provider-ollama.md
│ │ │ ├── siliconflow.md
│ │ │ ├── start.md
│ │ │ └── tokenpony.md
│ │ ├── use/
│ │ │ ├── agent-runner.md
│ │ │ ├── astrbot-agent-sandbox.md
│ │ │ ├── astrbot-sandbox.md
│ │ │ ├── code-interpreter.md
│ │ │ ├── command.md
│ │ │ ├── context-compress.md
│ │ │ ├── custom-rules.md
│ │ │ ├── function-calling.md
│ │ │ ├── knowledge-base.md
│ │ │ ├── mcp.md
│ │ │ ├── plugin.md
│ │ │ ├── proactive-agent.md
│ │ │ ├── skills.md
│ │ │ ├── subagent.md
│ │ │ ├── unified-webhook.md
│ │ │ ├── websearch.md
│ │ │ └── webui.md
│ │ └── what-is-astrbot.md
│ ├── package.json
│ ├── public/
│ │ ├── openapi.json
│ │ └── scalar.html
│ ├── scripts/
│ │ ├── sync_docs_to_wiki.py
│ │ ├── upload-doc-images-to-r2.sh
│ │ ├── upload_doc_images_to_r2.py
│ │ └── usage.md
│ ├── tests/
│ │ └── test_sync_docs_to_wiki.py
│ ├── vercel.json
│ └── zh/
│ ├── community.md
│ ├── deploy/
│ │ ├── astrbot/
│ │ │ ├── 1panel.md
│ │ │ ├── btpanel.md
│ │ │ ├── casaos.md
│ │ │ ├── cli.md
│ │ │ ├── community-deployment.md
│ │ │ ├── compshare.md
│ │ │ ├── desktop.md
│ │ │ ├── docker.md
│ │ │ ├── kubernetes.md
│ │ │ ├── launcher.md
│ │ │ ├── other-deployments.md
│ │ │ ├── package.md
│ │ │ ├── rainyun.md
│ │ │ └── sys-pm.md
│ │ └── when-deployed.md
│ ├── dev/
│ │ ├── astrbot-config.md
│ │ ├── openapi.md
│ │ ├── plugin-platform-adapter.md
│ │ ├── plugin.md
│ │ └── star/
│ │ ├── guides/
│ │ │ ├── ai.md
│ │ │ ├── env.md
│ │ │ ├── html-to-pic.md
│ │ │ ├── listen-message-event.md
│ │ │ ├── other.md
│ │ │ ├── plugin-config.md
│ │ │ ├── send-message.md
│ │ │ ├── session-control.md
│ │ │ ├── simple.md
│ │ │ └── storage.md
│ │ ├── plugin-new.md
│ │ ├── plugin-publish.md
│ │ └── plugin.md
│ ├── faq.md
│ ├── index.md
│ ├── ospp/
│ │ └── 2025.md
│ ├── others/
│ │ ├── github-proxy.md
│ │ ├── ipv6.md
│ │ └── self-host-t2i.md
│ ├── platform/
│ │ ├── aiocqhttp.md
│ │ ├── dingtalk.md
│ │ ├── discord.md
│ │ ├── kook.md
│ │ ├── lark.md
│ │ ├── line.md
│ │ ├── matrix.md
│ │ ├── misskey.md
│ │ ├── qqofficial/
│ │ │ ├── webhook.md
│ │ │ └── websockets.md
│ │ ├── qqofficial.md
│ │ ├── satori/
│ │ │ ├── guide.md
│ │ │ └── server-satori.md
│ │ ├── slack.md
│ │ ├── start.md
│ │ ├── telegram.md
│ │ ├── vocechat.md
│ │ ├── wecom.md
│ │ ├── wecom_ai_bot.md
│ │ └── weixin-official-account.md
│ ├── providers/
│ │ ├── 302ai.md
│ │ ├── agent-runners/
│ │ │ ├── astrbot-agent-runner.md
│ │ │ ├── coze.md
│ │ │ ├── dashscope.md
│ │ │ ├── deerflow.md
│ │ │ └── dify.md
│ │ ├── agent-runners.md
│ │ ├── aihubmix.md
│ │ ├── coze.md
│ │ ├── dashscope.md
│ │ ├── dify.md
│ │ ├── llm.md
│ │ ├── newapi.md
│ │ ├── ppio.md
│ │ ├── provider-lmstudio.md
│ │ ├── provider-ollama.md
│ │ ├── siliconflow.md
│ │ ├── start.md
│ │ └── tokenpony.md
│ ├── use/
│ │ ├── agent-runner.md
│ │ ├── astrbot-agent-sandbox.md
│ │ ├── code-interpreter.md
│ │ ├── command.md
│ │ ├── context-compress.md
│ │ ├── custom-rules.md
│ │ ├── function-calling.md
│ │ ├── knowledge-base-old.md
│ │ ├── knowledge-base.md
│ │ ├── mcp.md
│ │ ├── plugin.md
│ │ ├── proactive-agent.md
│ │ ├── skills.md
│ │ ├── subagent.md
│ │ ├── unified-webhook.md
│ │ ├── websearch.md
│ │ └── webui.md
│ └── what-is-astrbot.md
├── k8s/
│ ├── astrbot/
│ │ ├── 00-namespace.yaml
│ │ ├── 01-pvc.yaml
│ │ ├── 02-deployment.yaml
│ │ ├── 03-service-nodeport.yaml
│ │ └── 04-service-loadbalancer.yaml
│ └── astrbot_with_napcat/
│ ├── 00-namespace.yaml
│ ├── 01-pvc.yaml
│ ├── 02-deployment.yaml
│ ├── 03-service-nodeport.yaml
│ └── 04-service-loadbalancer.yaml
├── main.py
├── openapi.json
├── openspec/
│ └── config.yaml
├── pyproject.toml
├── requirements.txt
├── runtime_bootstrap.py
├── scripts/
│ ├── astrbot.service
│ ├── hatch_build.py
│ ├── pr_test_env.sh
│ └── start-with-neo.sh
├── tests/
│ ├── agent/
│ │ ├── test_context_manager.py
│ │ ├── test_token_counter.py
│ │ └── test_truncator.py
│ ├── conftest.py
│ ├── fixtures/
│ │ ├── __init__.py
│ │ ├── configs/
│ │ │ └── test_cmd_config.json
│ │ ├── helpers.py
│ │ ├── messages/
│ │ │ └── test_messages.json
│ │ ├── mocks/
│ │ │ ├── __init__.py
│ │ │ ├── aiocqhttp.py
│ │ │ ├── discord.py
│ │ │ └── telegram.py
│ │ └── plugins/
│ │ ├── fixture_plugin.py
│ │ └── metadata.yaml
│ ├── test_anthropic_kimi_code_provider.py
│ ├── test_api_key_open_api.py
│ ├── test_backup.py
│ ├── test_chat_route.py
│ ├── test_computer_config.py
│ ├── test_computer_skill_sync.py
│ ├── test_dashboard.py
│ ├── test_kb_import.py
│ ├── test_kook/
│ │ ├── .gitignore
│ │ ├── data/
│ │ │ ├── kook_card_data.json
│ │ │ ├── kook_ws_event_group_message.json
│ │ │ ├── kook_ws_event_hello.json
│ │ │ ├── kook_ws_event_message_with_card_1.json
│ │ │ ├── kook_ws_event_message_with_card_2.json
│ │ │ ├── kook_ws_event_ping.json
│ │ │ ├── kook_ws_event_pong.json
│ │ │ ├── kook_ws_event_private_message.json
│ │ │ ├── kook_ws_event_private_system_message.json
│ │ │ ├── kook_ws_event_reconnect_err.json
│ │ │ ├── kook_ws_event_resume.json
│ │ │ └── kook_ws_event_resume_ack.json
│ │ ├── shared.py
│ │ ├── test_kook_event.py
│ │ └── test_kook_types.py
│ ├── test_local_shell_component.py
│ ├── test_main.py
│ ├── test_neo_skill_sync.py
│ ├── test_neo_skill_tools.py
│ ├── test_openai_source.py
│ ├── test_pip_helper_modules.py
│ ├── test_pip_installer.py
│ ├── test_plugin_manager.py
│ ├── test_profile_aware_tools.py
│ ├── test_quoted_message_parser.py
│ ├── test_runtime_env.py
│ ├── test_security_fixes.py
│ ├── test_skill_manager_sandbox_cache.py
│ ├── test_skill_metadata_enrichment.py
│ ├── test_smoke.py
│ ├── test_temp_dir_cleaner.py
│ ├── test_tool_loop_agent_runner.py
│ └── unit/
│ ├── test_aiocqhttp_poke.py
│ ├── test_astr_agent_tool_exec.py
│ ├── test_astr_main_agent.py
│ ├── test_astr_message_event.py
│ ├── test_astrbot_message.py
│ ├── test_computer.py
│ ├── test_config.py
│ ├── test_core_lifecycle.py
│ ├── test_cron_manager.py
│ ├── test_cron_tools.py
│ ├── test_event_bus.py
│ ├── test_python_tools.py
│ ├── test_session_lock.py
│ ├── test_star_base.py
│ └── test_subagent_orchestrator.py
└── typings/
└── faiss/
└── __init__.pyi
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
# 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
.idea/
# Byte-compiled / optimized / DLL files
__pycache__/
# Environments
.env
.venv
env/
venv*/
ENV/
.conda/
dashboard/
data/
tests/
.ruff_cache/
.astrbot
astrbot.lock
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: astrbot
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: ['https://afdian.com/a/astrbot_team']
================================================
FILE: .github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml
================================================
name: 🥳 发布插件
description: 提交插件到插件市场
title: "[Plugin] 插件名"
labels: ["plugin-publish"]
assignees: []
body:
- type: markdown
attributes:
value: |
欢迎发布插件到插件市场!
- type: markdown
attributes:
value: |
## 插件基本信息
请将插件信息填写到下方的 JSON 代码块中。其中 `tags`(插件标签)和 `social_link`(社交链接)选填。
不熟悉 JSON ?可以从 [此站](https://plugins.astrbot.app) 右下角提交。
- type: textarea
id: plugin-info
attributes:
label: 插件信息
description: 请在下方代码块中填写您的插件信息,确保反引号包裹了JSON
value: |
```json
{
"name": "插件名,请以 astrbot_plugin_ 开头",
"display_name": "用于展示的插件名,方便人类阅读",
"desc": "插件的简短介绍",
"author": "作者名",
"repo": "插件仓库链接",
"tags": [],
"social_link": "",
}
```
validations:
required: true
- type: markdown
attributes:
value: |
## 检查
- type: checkboxes
id: checks
attributes:
label: 插件检查清单
description: 请确认以下所有项目
options:
- label: 我的插件经过完整的测试
required: true
- label: 我的插件不包含恶意代码
required: true
- label: 我已阅读并同意遵守该项目的 [行为准则](https://docs.github.com/zh/site-policy/github-terms/github-community-code-of-conduct)。
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: '🐛 Report Bug / 报告 Bug'
title: '[Bug]'
description: Submit bug report to help us improve. / 提交报告帮助我们改进。
labels: [ 'bug' ]
body:
- type: markdown
attributes:
value: |
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: What happened / 发生了什么
description: Description
placeholder: >
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: Reproduce / 如何复现?
description: >
The steps to reproduce the issue. / 复现该问题的步骤
placeholder: >
Example: 1. Open '...'
validations:
required: true
- type: textarea
attributes:
label: AstrBot version, deployment method (e.g., Windows Docker Desktop deployment), provider used, and messaging platform used. / AstrBot 版本、部署方式(如 Windows Docker Desktop 部署)、使用的提供商、使用的消息平台适配器
placeholder: >
Example: 4.5.7 Docker, 3.1.7 Windows Launcher
validations:
required: true
- type: dropdown
attributes:
label: OS
description: |
On which operating system did you encounter this problem? / 你在哪个操作系统上遇到了这个问题?
multiple: false
options:
- 'Windows'
- 'macOS'
- 'Linux'
- 'Other'
- 'Not sure'
validations:
required: true
- type: textarea
attributes:
label: Logs / 报错日志
description: >
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: 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: Yes!
- type: checkboxes
attributes:
label: Code of Conduct
options:
- label: >
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: "Thank you for filling out our form! / 感谢您填写我们的表单!"
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yml
================================================
name: '🎉 Feature Request / 功能建议'
title: "[Feature]"
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 / 描述
description: Please describe the feature you want to be added in detail. / 请详细描述您希望添加的功能。
- type: textarea
attributes:
label: Use Case / 使用场景
description: Please describe the use case for this feature. / 请描述这个功能的使用场景。
- type: checkboxes
attributes:
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: Yes, I am willing to submit a PR. / 是的,我愿意提交 PR。
- type: checkboxes
attributes:
label: Code of Conduct
options:
- label: >
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: "Thank you for filling out our form!"
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!--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?-->
<!--请总结你的改动:哪些核心文件被修改了?实现了什么功能?-->
- [x] This is NOT a breaking change. / 这不是一个破坏性变更。
<!-- If your changes is a breaking change, please uncheck the checkbox above -->
### Screenshots or Test Results / 运行截图或测试结果
<!--Please paste screenshots, GIFs, or test logs here as evidence of executing the "Verification Steps" to prove this change is effective.-->
<!--请粘贴截图、GIF 或测试日志,作为执行“验证步骤”的证据,证明此改动有效。-->
---
### Checklist / 检查清单
<!--If merged, your code will serve tens of thousands of users! Please double-check the following items before submitting.-->
<!--如果分支被合并,您的代码将服务于数万名用户!在提交前,请核查一下几点内容。-->
- [ ] 😊 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.
/ 我的更改没有引入恶意代码。
================================================
FILE: .github/auto_assign.yml
================================================
# Set to true to add reviewers to pull requests
addReviewers: true
# Set to true to add assignees to pull requests
addAssignees: false
# A list of reviewers to be added to pull requests (GitHub user name)
reviewers:
- Soulter
- Raven95676
- Larch-C
- anka-afk
- advent259141
- Fridemn
- LIghtJUNction
# - zouyonghe
# A number of reviewers added to the pull request
# Set 0 to add all the reviewers (default: 0)
numberOfReviewers: 2
# A list of assignees, overrides reviewers if set
# assignees:
# - assigneeA
# A number of assignees to add to the pull request
# Set to 0 to add all of the assignees.
# Uses numberOfReviewers if unset.
# numberOfAssignees: 2
# A list of keywords to be skipped the process that add reviewers if pull requests include it
skipKeywords:
- wip
- draft
# A list of users to be skipped by both the add reviewers and add assignees processes
# skipUsers:
# - dependabot[bot]
================================================
FILE: .github/copilot-instructions.md
================================================
# AstrBot Development Instructions
AstrBot is a multi-platform LLM chatbot and development framework written in Python with a Vue.js dashboard. It supports multiple messaging platforms (QQ, Telegram, Discord, etc.) and various LLM providers (OpenAI, Anthropic, Google Gemini, etc.).
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
## Working Effectively
### Bootstrap and Install Dependencies
- **Python 3.10+ required** - Check `.python-version` file
- Install UV package manager: `pip install uv`
- Install project dependencies: `uv sync` -- takes 6-7 minutes. NEVER CANCEL. Set timeout to 10+ minutes.
- Create required directories: `mkdir -p data/plugins data/config data/temp`
### 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`)
### Dashboard Build (Vue.js/Node.js)
- **Prerequisites**: Node.js 20+ and npm 10+ required
- Navigate to dashboard: `cd dashboard`
- Install dashboard dependencies: `npm install` -- takes 2-3 minutes. NEVER CANCEL. Set timeout to 5+ minutes.
- Build dashboard: `npm run build` -- takes 25-30 seconds. NEVER CANCEL.
- Dashboard creates optimized production build in `dashboard/dist/`
### Testing
- Do not generate test files for now.
### Code Quality and Linting
- Install ruff linter: `uv add --dev ruff`
- Check code style: `uv run ruff check .` -- takes <1 second
- Check formatting: `uv run ruff format --check .` -- takes <1 second
- Fix formatting: `uv run ruff format .`
- **ALWAYS** run `uv run ruff check .` and `uv run ruff format .` before committing changes
### Plugin Development
- 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
### Common Issues and Workarounds
- **Dashboard download fails**: Known issue with "division by zero" error - application still works
- **Import errors in tests**: Ensure `uv run` is used to run tests in proper environment
=- **Build timeouts**: Always set appropriate timeouts (10+ minutes for uv sync, 5+ minutes for npm install)
## CI/CD Integration
- GitHub Actions workflows in `.github/workflows/`
- Docker builds supported via `Dockerfile`
- Pre-commit hooks enforce ruff formatting and linting
## Docker Support
- Primary deployment method: `docker run soulter/astrbot:latest`
- Compose file available: `compose.yml`
- Exposes ports: 6185 (WebUI), 6195 (WeChat), 6199 (QQ), etc.
- Volume mount required: `./data:/AstrBot/data`
## Multi-language Support
- Documentation in Chinese (README.md), English (README_en.md), Japanese (README_ja.md)
- UI supports internationalization
- Default language is Chinese
Remember: This is a production chatbot framework with real users. Always test thoroughly and ensure changes don't break existing functionality.
================================================
FILE: .github/dependabot.yml
================================================
# Keep GitHub Actions up to date with GitHub's Dependabot...
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
version: 2
updates:
- package-ecosystem: github-actions
directory: /
groups:
github-actions:
patterns:
- "*" # Group all Actions updates into a single larger pull request
schedule:
interval: weekly
================================================
FILE: .github/workflows/build-docs.yml
================================================
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/
================================================
FILE: .github/workflows/code-format.yml
================================================
name: Code Format Check
on:
pull_request:
branches: [ master ]
push:
branches: [ master ]
jobs:
format-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install UV
run: pip install uv
- name: Install dependencies
run: uv sync
- name: Check code formatting with ruff
run: |
uv run ruff format --check .
- name: Check code style with ruff
run: |
uv run ruff check .
================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: '21 15 * * 5'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: python
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# 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@v6
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"
================================================
FILE: .github/workflows/coverage_test.yml
================================================
name: Run tests and upload coverage
on:
push:
branches:
- master
paths-ignore:
- 'README.md'
- 'changelogs/**'
- 'dashboard/**'
pull_request:
workflow_dispatch:
jobs:
test:
name: Run tests and collect coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v6
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-asyncio pytest-cov
pip install --editable .
- name: Run tests
run: |
mkdir -p data/plugins
mkdir -p data/config
mkdir -p data/temp
export TESTING=true
export ZHIPU_API_KEY=${{ secrets.OPENAI_API_KEY }}
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 }}
================================================
FILE: .github/workflows/dashboard_ci.yml
================================================
name: AstrBot Dashboard CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
if: github.repository == 'AstrBotDevs/AstrBot'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '24.13.0'
- name: npm install, build
run: |
cd dashboard
npm install pnpm -g
pnpm install
pnpm i --save-dev @types/markdown-it
pnpm run build
- name: Inject Commit SHA
id: get_sha
run: |
echo "COMMIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
mkdir -p dashboard/dist/assets
echo $COMMIT_SHA > dashboard/dist/assets/version
cd dashboard
zip -r dist.zip dist
- name: Archive production artifacts
uses: actions/upload-artifact@v7
with:
name: dist-without-markdown
path: |
dashboard/dist
!dist/**/*.md
- name: Create GitHub Release
if: github.event_name == 'push'
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"
================================================
FILE: .github/workflows/docker-image.yml
================================================
name: Docker Image CI/CD
on:
push:
tags:
- "v*"
schedule:
# Run at 00:00 UTC every day
- cron: "0 0 * * *"
workflow_dispatch:
jobs:
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: Checkout
uses: actions/checkout@v6
with:
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
if: github.event_name == 'workflow_dispatch'
run: |
tag=$(git describe --tags --abbrev=0)
echo "latest_tag=$tag" >> $GITHUB_OUTPUT
- name: Checkout to latest tag (only on manual trigger)
if: github.event_name == 'workflow_dispatch'
run: git checkout ${{ steps.get-latest-tag.outputs.latest_tag }}
- name: Compute release metadata
id: release-meta
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
version="${{ steps.get-latest-tag.outputs.latest_tag }}"
else
version="${GITHUB_REF#refs/tags/}"
fi
if [[ "$version" == *"beta"* ]] || [[ "$version" == *"alpha"* ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "Version $version marked as pre-release"
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "Version $version marked as stable"
fi
echo "version=$version" >> $GITHUB_OUTPUT
- 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: 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 and Push Release Image
uses: docker/build-push-action@v7.0.0
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ 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 "Release Docker image has been built and pushed successfully"
================================================
FILE: .github/workflows/pr-title-check.yml
================================================
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.");
}
================================================
FILE: .github/workflows/release.yml
================================================
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@v4.4.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
================================================
FILE: .github/workflows/smoke_test.yml
================================================
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 &
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
================================================
FILE: .github/workflows/stale.yml
================================================
# 本工作流用于标记并关闭长期不活跃的 Issue。
# 目前仅针对带 `bug` 标签的 Issue 生效,不会处理 PR。
#
# 文档: https://github.com/actions/stale
name: Mark stale bug issues
on:
schedule:
# 每天 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
steps:
- 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 }}
================================================
FILE: .github/workflows/sync-wiki.yml
================================================
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
================================================
FILE: .gitignore
================================================
# Python related
__pycache__
.mypy_cache
.venv*
.conda/
uv.lock
.coverage
# IDE and editors
.vscode
.idea
# Logs and temporary files
botpy.log
logs/
temp
cookies.json
# Data files
data_v2.db
data_v3.db
data
configs/session
configs/config.yaml
cmd_config.json
# Plugins
addons/plugins
astrbot/builtin_stars/python_interpreter/workplace
tests/astrbot_plugin_openai
# Dashboard
dashboard/node_modules/
dashboard/dist/
.pnpm-store/
package-lock.json
yarn.lock
# Bundled dashboard dist (generated by hatch_build.py during pip wheel build)
astrbot/dashboard/dist/
# Operating System
**/.DS_Store
.DS_Store
# AstrBot specific
.astrbot
astrbot.lock
# Other
chroma
venv/*
pytest.ini
AGENTS.md
IFLOW.md
# genie_tts data
CharacterModels/
GenieData/
.agent/
.codex/
.opencode/
.kilocode/
.worktrees/
================================================
FILE: .pre-commit-config.yaml
================================================
default_install_hook_types: [pre-commit, prepare-commit-msg]
ci:
autofix_commit_msg: ":balloon: auto fixes by pre-commit hooks"
autofix_prs: true
autoupdate_branch: master
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]
================================================
FILE: .python-version
================================================
3.12
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
SoulterL@outlook.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# 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
```
================================================
FILE: Dockerfile
================================================
FROM python:3.12-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 \
ca-certificates \
bash \
ffmpeg \
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 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
CMD ["python", "main.py"]
================================================
FILE: EULA.md
================================================
# 最终用户许可协议(EULA)
> 我们热爱开源软件,并始终致力于为所有用户提供健康、安全、可靠的使用体验。 ❤️
For English edition, please refer to the section below the Chinese version.
**最后更新:** 2026-01-12
感谢您使用 **AstrBot**。
在使用本项目之前,请仔细阅读以下声明内容。
**您一旦安装、运行或使用本项目,即表示您已阅读、理解并同意本声明中的全部内容。**
## 1. 项目性质
AstrBot 是一个遵循 **GNU Affero General Public License v3(AGPLv3)** 协议发布的**免费开源软件项目**。
* 截至目前,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;
* AstrBot’s 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 human–computer 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 AstrBot’s 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.
================================================
FILE: FIRST_NOTICE.en-US.md
================================================
## 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)
================================================
FILE: FIRST_NOTICE.md
================================================
## 欢迎使用 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)
================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
AstrBot is a llm-powered chatbot and develop framework.
Copyright (C) 2022-2099 Soulter
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
================================================
FILE: Makefile
================================================
.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
================================================
FILE: README.md
================================================

<div align="center">
<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>
<br>
<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="Featured|HelloGitHub" 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=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/">Documentation</a> |
<a href="https://blog.astrbot.app/">Blog</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 is an open-source all-in-one Agent chatbot platform that integrates with mainstream instant messaging apps. It provides reliable and scalable conversational AI infrastructure for individuals, developers, and teams. Whether you're building a personal AI companion, intelligent customer service, automation assistant, or enterprise knowledge base, AstrBot enables you to quickly build production-ready AI applications within your IM platform workflows.

## Key Features
1. 💯 Free & Open Source.
2. ✨ AI LLM Conversations, Multimodal, Agent, MCP, Skills, Knowledge Base, Persona Settings, Auto Context Compression.
3. 🤖 Supports integration with Dify, Alibaba Cloud Bailian, Coze, and other agent platforms.
4. 🌐 Multi-Platform: QQ, WeChat Work, Feishu, DingTalk, WeChat Official Accounts, Telegram, Slack, and [more](#supported-messaging-platforms).
5. 📦 Plugin Extensions with 1000+ plugins available for one-click installation.
6. 🛡️ [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html) for isolated, safe execution of code, shell calls, and session-level resource reuse.
7. 💻 WebUI Support.
8. 🌈 Web ChatUI Support with built-in agent sandbox and web search.
9. 🌐 Internationalization (i18n) Support.
<br>
<table align="center">
<tr align="center">
<th>💙 Role-playing & Emotional 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>
## Quick Start
### One-Click Deployment
For users who want to quickly experience AstrBot, are familiar with command-line usage, and can install a `uv` environment on their own, we recommend the `uv` one-click deployment method ⚡️:
```bash
uv tool install astrbot
astrbot init # Only execute this command for the first time to initialize the environment
astrbot run
```
> Requires [uv](https://docs.astral.sh/uv/) to be installed.
> [!NOTE]
> For macOS user: due to macOS security checks, the first run of the `astrbot` command may take longer (about 10-20s).
Update `astrbot`:
```bash
uv tool upgrade astrbot
```
### Docker Deployment
For users familiar with containers and looking for a more stable, production-ready deployment method, we recommend deploying AstrBot with Docker / Docker Compose.
Please refer to the official documentation: [Deploy AstrBot with Docker](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot).
### Deploy on RainYun
For users who want one-click deployment and do not want to manage servers themselves, we recommend RainYun's one-click cloud deployment service ☁️:
[](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### Desktop Application Deployment
For users who want to use AstrBot on desktop and mainly use ChatUI, we recommend AstrBot App.
Visit [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) to download and install; this method is designed for desktop usage and is not recommended for server scenarios.
### Launcher Deployment
For desktop users who also want fast deployment and isolated multi-instance usage, we recommend AstrBot Launcher.
Visit [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) to download and install.
### Deploy on Replit
Replit deployment is maintained by the community and is suitable for online demos and lightweight trials.
[](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
AUR deployment targets Arch Linux users who prefer installing AstrBot through the system package workflow.
Run the command below to install `astrbot-git`, then start AstrBot in your local environment.
```bash
yay -S astrbot-git
```
**More deployment methods**
If you need panel-based management or deeper customization, see [BT-Panel Deployment](https://astrbot.app/deploy/astrbot/btpanel.html) for BT Panel app-store setup, [1Panel Deployment](https://astrbot.app/deploy/astrbot/1panel.html) for 1Panel app-market deployment, [CasaOS Deployment](https://astrbot.app/deploy/astrbot/casaos.html) for NAS/home-server visual deployment, and [Manual Deployment](https://astrbot.app/deploy/astrbot/cli.html) for fully custom source-based installation with `uv`.
## Supported Messaging Platforms
Connect AstrBot to your favorite chat platform.
| Platform | Maintainer |
|---------|---------------|
| QQ | Official |
| OneBot v11 protocol implementation | Official |
| Telegram | Official |
| Wecom & Wecom AI Bot | Official |
| WeChat Official Accounts | Official |
| Feishu (Lark) | 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 |
## Supported Model Services
| Service | Type |
|---------|---------------|
| OpenAI and Compatible Services | LLM Services |
| Anthropic | LLM Services |
| Google Gemini | LLM Services |
| Moonshot AI | LLM Services |
| Zhipu AI | LLM Services |
| DeepSeek | LLM Services |
| Ollama (Self-hosted) | LLM Services |
| LM Studio (Self-hosted) | LLM Services |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | LLM Services (API Gateway, supports all models) |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | LLM Services |
| [302.AI](https://share.302.ai/rr1M3l) | LLM Services |
| [TokenPony](https://www.tokenpony.cn/3YPyf) | LLM Services |
| [SiliconFlow](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | LLM Services |
| [PPIO Cloud](https://ppio.com/user/register?invited_by=AIOONE) | LLM Services |
| ModelScope | LLM Services |
| OneAPI | LLM Services |
| Dify | LLMOps Platforms |
| Alibaba Cloud Bailian Applications | LLMOps Platforms |
| Coze | LLMOps Platforms |
| OpenAI Whisper | Speech-to-Text Services |
| SenseVoice | Speech-to-Text Services |
| OpenAI TTS | Text-to-Speech Services |
| Gemini TTS | Text-to-Speech Services |
| GPT-Sovits-Inference | Text-to-Speech Services |
| GPT-Sovits | Text-to-Speech Services |
| FishAudio | Text-to-Speech Services |
| Edge TTS | Text-to-Speech Services |
| Alibaba Cloud Bailian TTS | Text-to-Speech Services |
| Azure TTS | Text-to-Speech Services |
| Minimax TTS | Text-to-Speech Services |
| Volcano Engine TTS | Text-to-Speech Services |
## ❤️ Sponsors
<p align="center">
<img alt="sponsors" src="https://sponsors.astrbot.app/?v=1">
</p>
## ❤️ Contributing
Issues and Pull Requests are always welcome! Feel free to submit your changes to this project :)
### How to Contribute
You can contribute by reviewing issues or helping with pull request reviews. Any issues or PRs are welcome to encourage community participation. Of course, these are just suggestions—you can contribute in any way you like. For adding new features, please discuss through an Issue first.
### Development Environment
AstrBot uses `ruff` for code formatting and linting.
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
pre-commit install
```
## 🌍 Community
### 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(Chit-chat): 975206796
- Developer Group(Formal): 1039761811
### Discord Server
<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>
## ❤️ Special Thanks
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&max=200&columns=14" />
</a>
Additionally, the birth of this project would not have been possible without the help of the following open-source projects:
- [NapNeko/NapCatQQ](https://github.com/NapNeko/NapCatQQ) - The amazing cat framework
## ⭐ Star History
> [!TIP]
> If this project has helped you in your life or work, or if you're interested in its future development, please give the project a Star. It's the driving force behind maintaining this open-source project <3
<div align="center">
[](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_Companionship and capability should never be at odds. What we aim to create is a robot that can understand emotions, provide genuine companionship, and reliably accomplish tasks._
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>
================================================
FILE: README_fr.md
================================================

<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a> |
<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_ru.md">Русский</a>
<br>
<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="Featured|HelloGitHub" 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%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFZIiBmaWxsPSIjZmZmIi8%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=%20&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/">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 Support</a>
</div>
AstrBot est une plateforme de chatbot Agent tout-en-un open source qui s'intègre aux principales applications de messagerie instantanée. Elle fournit une infrastructure d'IA conversationnelle fiable et évolutive pour les particuliers, les développeurs et les équipes. Que vous construisiez un compagnon IA personnel, un service client intelligent, un assistant d'automatisation ou une base de connaissances d'entreprise, AstrBot vous permet de créer rapidement des applications d'IA prêtes pour la production dans les flux de travail de votre plateforme de messagerie.

## Fonctionnalités principales
1. 💯 Gratuit & Open Source.
2. ✨ Dialogue avec de grands modèles d'IA, multimodal, Agent, MCP, Skills, Base de connaissances, Paramétrage de personnalité, compression automatique des dialogues.
3. 🤖 Prise en charge de l'accès aux plateformes d'Agents telles que Dify, Alibaba Cloud Bailian, Coze, etc.
4. 🌐 Multiplateforme : supporte QQ, WeChat Enterprise, Feishu, DingTalk, Comptes officiels WeChat, Telegram, Slack et [plus encore](#plateformes-de-messagerie-prises-en-charge).
5. 📦 Extension par plugins, avec plus de 1000 plugins déjà disponibles pour une installation en un clic.
6. 🛡️ Environnement isolé [Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html) : exécution sécurisée de code, appels Shell et réutilisation des ressources au niveau de la session.
7. 💻 Support WebUI.
8. 🌈 Support Web ChatUI, avec sandbox d'agent intégrée, recherche web, etc.
9. 🌐 Support de l'internationalisation (i18n).
<br>
<table align="center">
<tr align="center">
<th>💙 Jeux de rôle & Accompagnement émotionnel</th>
<th>✨ Agent proactif</th>
<th>🚀 Capacités agentiques générales</th>
<th>🧩 1000+ Plugins de communauté</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 veulent découvrir AstrBot rapidement, qui sont familiers avec la ligne de commande et peuvent installer eux-mêmes l'environnement `uv`, 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
```
> [uv](https://docs.astral.sh/uv/) doit être installé.
> [!NOTE]
> Pour les utilisateurs macOS : en raison des vérifications de sécurité de macOS, la première exécution de la commande `astrbot` peut prendre plus de temps (environ 10-20s).
Mettre à jour `astrbot` :
```bash
uv tool upgrade astrbot
```
### Déploiement Docker
Pour les utilisateurs familiers avec les conteneurs et qui souhaitent une méthode plus stable et adaptée à la production, nous recommandons de déployer AstrBot avec Docker / Docker Compose.
Veuillez consulter la documentation officielle [Déployer AstrBot avec Docker](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot).
### Déployer sur RainYun
Pour les utilisateurs qui souhaitent déployer AstrBot en un clic sans gérer le serveur eux-mêmes, nous recommandons le service de déploiement cloud en un clic de RainYun ☁️ :
[](https://app.rainyun.com/apps/rca/store/5994?ref=NjU1ODg0)
### Déploiement de l'application de bureau
Pour les utilisateurs qui veulent utiliser AstrBot sur desktop et passer principalement par ChatUI, nous recommandons AstrBot App.
Accédez à [AstrBot-desktop](https://github.com/AstrBotDevs/AstrBot-desktop) pour télécharger et installer l'application ; cette méthode est conçue pour un usage desktop et n'est pas recommandée pour les scénarios serveur.
### Déploiement avec le lanceur
Également sur desktop, pour les utilisateurs qui souhaitent un déploiement rapide avec isolation d'environnement et multi-instances, nous recommandons AstrBot Launcher.
Accédez à [AstrBot Launcher](https://github.com/Raven95676/astrbot-launcher) pour télécharger et installer.
### Déployer sur Replit
Le déploiement sur Replit est maintenu par la communauté et convient aux démonstrations en ligne et aux essais légers.
[](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
Le mode AUR s'adresse aux utilisateurs Arch Linux qui préfèrent installer AstrBot via le gestionnaire de paquets système.
Exécutez la commande ci-dessous pour installer `astrbot-git`, puis lancez AstrBot localement.
```bash
yay -S astrbot-git
```
**Autres méthodes de déploiement**
Si vous avez besoin d'une gestion par panneau ou d'une personnalisation plus poussée, consultez [Déploiement BT-Panel](https://astrbot.app/deploy/astrbot/btpanel.html) pour une installation via BT Panel, [Déploiement 1Panel](https://astrbot.app/deploy/astrbot/1panel.html) pour le marketplace 1Panel, [Déploiement CasaOS](https://astrbot.app/deploy/astrbot/casaos.html) pour un déploiement visuel sur NAS/serveur domestique, et [Déploiement manuel](https://astrbot.app/deploy/astrbot/cli.html) pour une installation complète depuis les sources avec `uv`.
## Plateformes de messagerie prises en charge
Connectez AstrBot à vos plateformes de chat préférées.
| Plateforme | Maintenance |
|---------|---------------|
| QQ | Officielle |
| Implémentation du protocole OneBot v11 | Officielle |
| Telegram | Officielle |
| Application WeChat Work & Bot intelligent WeChat Work | Officielle |
| Service client WeChat & Comptes officiels WeChat | Officielle |
| Feishu (Lark) | Officielle |
| DingTalk | Officielle |
| Slack | Officielle |
| Discord | Officielle |
| LINE | Officielle |
| Satori | Officielle |
| Misskey | Officielle |
| WhatsApp (Bientôt disponible) | Officielle |
| [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é |
## Services de modèles pris en charge
| Service | Type |
|---------|---------------|
| OpenAI et services compatibles | Services LLM |
| Anthropic | Services LLM |
| Google Gemini | Services LLM |
| Moonshot AI | Services LLM |
| Zhipu AI | Services LLM |
| DeepSeek | Services LLM |
| Ollama (Auto-hébergé) | Services LLM |
| LM Studio (Auto-hébergé) | Services LLM |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | Services LLM (Passerelle API, prend en charge tous les modèles) |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | Services LLM |
| [302.AI](https://share.302.ai/rr1M3l) | Services LLM |
| [TokenPony](https://www.tokenpony.cn/3YPyf) | Services LLM |
| [SiliconFlow](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | Services LLM |
| [PPIO Cloud](https://ppio.com/user/register?invited_by=AIOONE) | Services LLM |
| ModelScope | Services LLM |
| OneAPI | Services LLM |
| Dify | Plateformes LLMOps |
| Applications Alibaba Cloud Bailian | Plateformes LLMOps |
| Coze | Plateformes LLMOps |
| OpenAI Whisper | Services de reconnaissance vocale |
| SenseVoice | Services de reconnaissance vocale |
| OpenAI TTS | Services de synthèse vocale |
| Gemini TTS | Services de synthèse vocale |
| GPT-Sovits-Inference | Services de synthèse vocale |
| GPT-Sovits | Services de synthèse vocale |
| FishAudio | Services de synthèse vocale |
| Edge TTS | Services de synthèse vocale |
| Alibaba Cloud Bailian TTS | Services de synthèse vocale |
| Azure TTS | Services de synthèse vocale |
| Minimax TTS | Services de synthèse vocale |
| Volcano Engine TTS | Services de synthèse vocale |
## ❤️ Contribuer
Les Issues et Pull Requests sont toujours les bienvenues ! N'hésitez pas à soumettre vos modifications à ce projet :)
### Comment contribuer
Vous pouvez contribuer en examinant les issues ou en aidant à la revue des pull requests. Toutes les issues ou PRs sont les bienvenues pour encourager la participation de la communauté. Bien sûr, ce ne sont que des suggestions - vous pouvez contribuer de la manière que vous souhaitez. Pour l'ajout de nouvelles fonctionnalités, veuillez d'abord en discuter via une Issue.
### Environnement de développement
AstrBot utilise `ruff` pour le formatage et le linting du code.
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
pre-commit install
```
## 🌍 Communauté
### Groupes QQ
- Groupe 1 : 322154837
- Groupe 3 : 630166526
- Groupe 5 : 822130018
- Groupe 6 : 753075035
- Groupe développeurs : 975206796
- Groupe développeurs (officiel) : 1039761811
### Serveur Discord
<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>
## ❤️ Remerciements spéciaux
Un grand merci à tous les contributeurs et développeurs de plugins pour leurs contributions à 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) - L'incroyable framework chat
## ⭐ Historique des étoiles
> [!TIP]
> Si ce projet vous a aidé dans votre vie ou votre travail, ou si vous êtes intéressé par son développement futur, veuillez donner une étoile au projet. C'est la force motrice derrière la maintenance de ce projet open source <3
<div align="center">
[](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_La compagnie et la capacité ne devraient jamais être des opposés. Nous souhaitons créer un robot capable à la fois de comprendre les émotions, d'offrir de la présence, et d'accomplir des tâches de manière fiable._
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>
================================================
FILE: README_ja.md
================================================

<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a> |
<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_fr.md">Français</a> |
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_ru.md">Русский</a>
<br>
<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="Featured|HelloGitHub" 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%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFZIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0LjYxNTZDNS4zMTUwMiAxNC4zOTk5IDUuNjAxNTYgMTQuMTEzNCA1LjYwMTU2IDEzLjc1OTlWMTEuMDM5OUM1LjYwMTU2IDEwLjY4NjQgNS4zMTUwMiAxMC4zOTk5IDQuOTYxNTYgMTAuMzk5OVoiIGZpbGw9IiNmZmYiLz4KPHBhdGggZD0iTTEzLjc1ODQgMS42MDAxSDExLjAzODRDMTAuNjg1IDEuNjAwMSAxMC4zOTg0IDEuODg2NjQgMTAuMzk4NCAyLjI0MDFWNC45NjAxQzEwLjM5ODQgNS4zMTM1NiAxMC42ODUgNS42MDAxIDExLjAzODQgNS42MDAxSDEzLjc1ODRDMTQuMTExOSA1LjYwMDEgMTQuMzk4NCA1LjMxMzU2IDE0LjM5ODQgNC45NjAxVjIuMjQwMUMxNC4zOTg0IDEuODg2NjQgMTQuMTExOSAxLjYwMDEgMTMuNzU4NCAxLjYwMDFZIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDRMNCAxMlpFIiBmaWxsPSIjZmZmIi8%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=%20&label=%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%83%9E%E3%83%BC%E3%82%B1%E3%83%83%E3%83%88&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://blog.astrbot.app/">Blog</a> |
<a href="https://astrbot.featurebase.app/roadmap">ロードマップ</a> |
<a href="https://github.com/AstrBotDevs/AstrBot/issues">Issue</a>
<a href="mailto:community@astrbot.app">Email Support</a>
</div>
AstrBot は、主要なインスタントメッセージングアプリと統合できるオープンソースのオールインワン Agent チャットボットプラットフォームです。個人、開発者、チームに信頼性が高くスケーラブルな会話型 AI インフラストラクチャを提供します。パーソナル AI コンパニオン、インテリジェントカスタマーサービス、オートメーションアシスタント、エンタープライズナレッジベースなど、AstrBot を使用すると、IM プラットフォームのワークフロー内で本番環境対応の AI アプリケーションを迅速に構築できます。

## 主な機能
1. 💯 無料 & オープンソース。
2. ✨ AI大規模言語モデル対話、マルチモーダル、Agent、MCP、Skills、ナレッジベース、ペルソナ設定、対話の自動圧縮。
3. 🤖 Dify、Alibaba Cloud Bailian(百煉)、Coze などのAgentプラットフォームへの接続をサポート。
4. 🌐 マルチプラットフォーム:QQ、企業微信(WeCom)、飛書(Lark)、釘釘(DingTalk)、WeChat公式アカウント、Telegram、Slack、[その他](#サポートされているメッセージプラットフォーム)に対応。
5. 📦 プラグイン拡張:1000を超える既存プラグインをワンクリックでインストール可能。
6. 🛡️ 隔離環境[Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html):コードの安全な実行、Shell呼び出し、セッションレベルのリソース再利用。
7. 💻 WebUI 対応。
8. 🌈 Web ChatUI 対応:ChatUI内にAgent Sandboxやウェブ検索などを内蔵。
9. 🌐 多言語対応(i18n)。
<br>
<table align="center">
<tr align="center">
<th>💙 ロールプレイ & 感情的な対話</th>
<th>✨ プロアクティブ・エージェント (Proactive Agent)</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
```
> [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 をワンクリックでデプロイしたく、サーバーを自分で管理したくないユーザーには、雨云のワンクリッククラウドデプロイサービスをおすすめします ☁️:
[](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 デプロイはコミュニティ提供の方式で、オンラインデモや軽量な試用に向いています。
[](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
AUR 方式は Arch Linux ユーザー向けで、システムのパッケージ運用に合わせて AstrBot を導入したい場合に適しています。
次のコマンドで `astrbot-git` をインストールし、ローカル環境で AstrBot を起動してください。
```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 | 公式 |
| WeChat Work アプリケーション & WeChat Work インテリジェントボット | 公式 |
| WeChat カスタマーサービス & WeChat 公式アカウント | 公式 |
| Feishu (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 および互換サービス | 大規模言語モデルサービス |
| Anthropic | 大規模言語モデルサービス |
| Google Gemini | 大規模言語モデルサービス |
| Moonshot AI | 大規模言語モデルサービス |
| 智谱 AI | 大規模言語モデルサービス |
| DeepSeek | 大規模言語モデルサービス |
| Ollama (セルフホスト) | 大規模言語モデルサービス |
| LM Studio (セルフホスト) | 大規模言語モデルサービス |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | 大規模言語モデルサービス(APIゲートウェイ、全モデル対応) |
| [優云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | 大規模言語モデルサービス |
| [302.AI](https://share.302.ai/rr1M3l) | 大規模言語モデルサービス |
| [小馬算力](https://www.tokenpony.cn/3YPyf) | 大規模言語モデルサービス |
| [硅基流動](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | 大規模言語モデルサービス |
| [PPIO 派欧云](https://ppio.com/user/register?invited_by=AIOONE) | 大規模言語モデルサービス |
| ModelScope | 大規模言語モデルサービス |
| OneAPI | 大規模言語モデルサービス |
| Dify | LLMOps プラットフォーム |
| Alibaba Cloud 百炼アプリケーション | LLMOps プラットフォーム |
| Coze | LLMOps プラットフォーム |
| OpenAI Whisper | 音声認識サービス |
| SenseVoice | 音声認識サービス |
| OpenAI TTS | 音声合成サービス |
| Gemini TTS | 音声合成サービス |
| GPT-Sovits-Inference | 音声合成サービス |
| GPT-Sovits | 音声合成サービス |
| FishAudio | 音声合成サービス |
| Edge TTS | 音声合成サービス |
| Alibaba Cloud 百炼 TTS | 音声合成サービス |
| Azure TTS | 音声合成サービス |
| Minimax TTS | 音声合成サービス |
| Volcano Engine TTS | 音声合成サービス |
## ❤️ コントリビューション
Issue や Pull Request は大歓迎です!このプロジェクトに変更を送信してください :)
### コントリビュート方法
Issue を確認したり、PR(プルリクエスト)のレビューを手伝うことで貢献できます。どんな Issue や PR への参加も歓迎され、コミュニティ貢献を促進します。もちろん、これらは提案に過ぎず、どんな方法でも貢献できます。新機能の追加については、まず Issue で議論してください。
### 開発環境
AstrBot はコードのフォーマットとチェックに `ruff` を使用しています。
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
pre-commit install
```
## 🌍 コミュニティ
### QQ グループ
- 1群: 322154837
- 3群: 630166526
- 5群: 822130018
- 6群: 753075035
- 開発者群: 975206796
- 開発者群(正式): 1039761811
### Discord サーバー
<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>
## ❤️ Special Thanks
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) - 素晴らしい猫猫フレームワーク
## ⭐ Star History
> [!TIP]
> このプロジェクトがあなたの生活や仕事に役立ったり、このプロジェクトの今後の発展に関心がある場合は、プロジェクトに Star をください。これがこのオープンソースプロジェクトを維持する原動力です <3
<div align="center">
[](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_共感力と能力は決して対立するものではありません。私たちが目指すのは、感情を理解し、心の支えとなるだけでなく、確実に仕事をこなせるロボットの創造です。_
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>
================================================
FILE: README_ru.md
================================================

<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a> |
<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>
<br>
<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="Featured|HelloGitHub" 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%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFZIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjczODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%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=%20&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://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 Support</a>
</div>
AstrBot — это универсальная платформа Agent-чатботов с открытым исходным кодом, которая интегрируется с основными приложениями для обмена мгновенными сообщениями. Она предоставляет надёжную и масштабируемую инфраструктуру разговорного ИИ для частных лиц, разработчиков и команд. Будь то персональный ИИ-компаньон, интеллектуальная служба поддержки, автоматизированный помощник или корпоративная база знаний — AstrBot позволяет быстро создавать готовые к использованию ИИ-приложения в рабочих процессах вашей платформы обмена сообщениями.

## Основные возможности
1. 💯 Бесплатно & Открытый исходный код.
2. ✨ Диалоги с ИИ-моделями, мультимодальность, Agent, MCP, Skills, База знаний, Настройка личности, автоматическое сжатие диалогов.
3. 🤖 Поддержка интеграции с платформами Agents, такими как Dify, Alibaba Cloud Bailian, Coze и др.
4. 🌐 Мультиплатформенность: поддержка QQ, WeChat для предприятий, Feishu, DingTalk, публичных аккаунтов WeChat, Telegram, Slack и [других](#Поддерживаемые-платформы-обмена-сообщениями).
5. 📦 Расширение плагинами: доступно более 1000 плагинов для установки в один клик.
6. 🛡️ Изолированная среда[Agent Sandbox](https://docs.astrbot.app/use/astrbot-agent-sandbox.html): безопасное выполнение любого кода, вызов Shell, повторное использование ресурсов на уровне сессии.
7. 💻 Поддержка WebUI.
8. 🌈 Поддержка Web ChatUI: встроенная песочница агента, веб-поиск и др.
9. 🌐 Поддержка интернационализации (i18n).
<br>
<table align="center">
<tr align="center">
<th>💙 Ролевые игры & Эмоциональная поддержка</th>
<th>✨ Проактивный Агент (Agent)</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
```
> Требуется установленный [uv](https://docs.astral.sh/uv/).
> [!NOTE]
> Для пользователей macOS: из-за проверок безопасности macOS первый запуск команды `astrbot` может занять больше времени (около 10-20 секунд).
Обновить `astrbot`:
```bash
uv tool upgrade astrbot
```
### Развёртывание Docker
Для пользователей, знакомых с контейнерами и которым нужен более стабильный и подходящий для production способ, мы рекомендуем разворачивать AstrBot через Docker / Docker Compose.
См. официальную документацию [Развёртывание AstrBot с Docker](https://astrbot.app/deploy/astrbot/docker.html#%E4%BD%BF%E7%94%A8-docker-%E9%83%A8%E7%BD%B2-astrbot).
### Развёртывание на RainYun
Для пользователей, которые хотят развернуть AstrBot в один клик и не хотят самостоятельно управлять сервером, мы рекомендуем облачный сервис развёртывания в один клик от RainYun ☁️:
[](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 поддерживается сообществом и подходит для онлайн-демо и лёгких тестовых запусков.
[](https://repl.it/github/AstrBotDevs/AstrBot)
### AUR
AUR-вариант предназначен для пользователей Arch Linux, которым удобна установка через системный менеджер пакетов.
Выполните команду ниже для установки `astrbot-git`, затем запустите AstrBot локально.
```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 | Официальная |
| Приложение WeChat Work и интеллектуальный бот WeChat Work | Официальная |
| Служба поддержки WeChat и официальные аккаунты WeChat | Официальная |
| Feishu (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 и совместимые сервисы | Сервисы 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-шлюз, поддерживает все модели) |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | Сервисы LLM |
| [302.AI](https://share.302.ai/rr1M3l) | Сервисы LLM |
| [TokenPony](https://www.tokenpony.cn/3YPyf) | Сервисы LLM |
| [SiliconFlow](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | Сервисы LLM |
| [PPIO Cloud](https://ppio.com/user/register?invited_by=AIOONE) | Сервисы LLM |
| ModelScope | Сервисы LLM |
| OneAPI | Сервисы LLM |
| Dify | Платформы LLMOps |
| Приложения Alibaba Cloud Bailian | Платформы LLMOps |
| Coze | Платформы LLMOps |
| OpenAI Whisper | Сервисы распознавания речи |
| SenseVoice | Сервисы распознавания речи |
| OpenAI TTS | Сервисы синтеза речи |
| Gemini TTS | Сервисы синтеза речи |
| GPT-Sovits-Inference | Сервисы синтеза речи |
| GPT-Sovits | Сервисы синтеза речи |
| FishAudio | Сервисы синтеза речи |
| Edge TTS | Сервисы синтеза речи |
| Alibaba Cloud Bailian TTS | Сервисы синтеза речи |
| Azure TTS | Сервисы синтеза речи |
| Minimax TTS | Сервисы синтеза речи |
| Volcano Engine TTS | Сервисы синтеза речи |
## ❤️ Вклад в проект
Issues и Pull Request всегда приветствуются! Не стесняйтесь отправлять свои изменения в этот проект :)
### Как внести вклад
Вы можете внести вклад, просматривая issues или помогая с ревью pull request. Любые issues или PR приветствуются для поощрения участия сообщества. Конечно, это лишь предложения — вы можете вносить вклад любым удобным для вас способом. Для добавления новых функций сначала обсудите это через Issue.
### Среда разработки
AstrBot использует `ruff` для форматирования и линтинга кода.
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
pre-commit install
```
## 🌍 Сообщество
### Группы QQ
- Группа 1: 322154837
- Группа 3: 630166526
- Группа 5: 822130018
- Группа 6: 753075035
- Группа разработчиков: 975206796
- Группа разработчиков (официальная): 1039761811
### Сервер Discord
<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>
## ❤️ Особая благодарность
Особая благодарность всем контрибьюторам и разработчикам плагинов за их вклад в 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) - Замечательный кошачий фреймворк
## ⭐ История звёзд
> [!TIP]
> Если этот проект помог вам в жизни или работе, или если вас интересует его будущее развитие, пожалуйста, поставьте проекту звезду. Это движущая сила поддержки этого проекта с открытым исходным кодом <3
<div align="center">
[](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_Сопровождение и способности никогда не должны быть противоположностями. Мы стремимся создать робота, который сможет как понимать эмоции, оказывать душевную поддержку, так и надёжно выполнять работу._
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>
================================================
FILE: README_zh-TW.md
================================================

<div align="center">
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README_zh.md">简体中文</a> |
<a href="https://github.com/AstrBotDevs/AstrBot/blob/master/README.md">English</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>
<br>
<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="Featured|HelloGitHub" 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://blog.astrbot.app/">Blog</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 是一個開源的一站式 Agent 聊天機器人平台,可接入主流即時通訊軟體,為個人、開發者和團隊打造可靠、可擴展的對話式智慧基礎設施。無論是個人 AI 夥伴、智慧客服、自動化助手,還是企業知識庫,AstrBot 都能在您的即時通訊軟體平台的工作流程中快速構建生產可用的 AI 應用程式。

## 主要功能
1. 💯 免費 & 開源。
2. ✨ AI 大模型對話,多模態,Agent,MCP,Skills,知識庫,人格設定,自動壓縮對話。
3. 🤖 支援接入 Dify、阿里雲百煉、Coze 等智慧體 (Agent) 平台。
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 內置代理沙盒 (Agent Sandbox)、網頁搜尋等。
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
```
> 需要安裝 [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 且不想自行管理伺服器的使用者,我們推薦使用雨雲的一鍵雲端部署服務 ☁️:
[](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 部署由社群維護,適合線上示範與輕量試用情境。
[](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 及相容服務 | 大型模型服務 |
| Anthropic | 大型模型服務 |
| Google Gemini | 大型模型服務 |
| Moonshot AI | 大型模型服務 |
| 智譜 AI | 大型模型服務 |
| DeepSeek | 大型模型服務 |
| Ollama(本機部署) | 大型模型服務 |
| LM Studio(本機部署) | 大型模型服務 |
| [AIHubMix](https://aihubmix.com/?aff=4bfH) | 大型模型服務(API 閘道,支援所有模型) |
| [優雲智算](https://www.compshare.cn/?ytag=GPU_YY-gh_astrbot&referral_code=FV7DcGowN4hB5UuXKgpE74) | 大型模型服務 |
| [302.AI](https://share.302.ai/rr1M3l) | 大型模型服務 |
| [小馬算力](https://www.tokenpony.cn/3YPyf) | 大型模型服務 |
| [矽基流動](https://docs.siliconflow.cn/cn/usercases/use-siliconcloud-in-astrbot) | 大型模型服務 |
| [PPIO 派歐雲](https://ppio.com/user/register?invited_by=AIOONE) | 大型模型服務 |
| ModelScope | 大型模型服務 |
| OneAPI | 大型模型服務 |
| 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 | 文字轉語音服務 |
## ❤️ 貢獻
歡迎任何 Issues/Pull Requests!只需要將您的變更提交到此專案 :)
### 如何貢獻
您可以透過檢視問題或協助審核 PR(拉取請求)來貢獻。任何問題或 PR 都歡迎參與,以促進社群貢獻。當然,這些只是建議,您可以以任何方式進行貢獻。對於新功能的新增,請先透過 Issue 討論。
### 開發環境
AstrBot 使用 `ruff` 進行程式碼格式化和檢查。
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
pre-commit install
```
## 🌍 社群
### QQ 群組
- 9 群: 1076659624 (新)
- 10 群: 1078079676 (新)
- 1 群:322154837
- 3 群:630166526
- 5 群:822130018
- 6 群:753075035
- 7 群:743746109
- 8 群:1030353265
- 開發者群(闲聊吹水):975206796
- 開發者群(正式):1039761811
### Discord 群組
<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>
## ❤️ 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) - 偉大的貓貓框架
## ⭐ Star History
> [!TIP]
> 如果本專案對您的生活 / 工作產生了幫助,或者您關注本專案的未來發展,請給專案 Star,這是我們維護這個開源專案的動力 <3
<div align="center">
[](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_陪伴與能力從來不應該是對立面。我們希望創造的是一個既能理解情緒、給予陪伴,也能可靠完成工作的機器人。_
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>
================================================
FILE: README_zh.md
================================================

<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="Featured|HelloGitHub" 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 应用。

## 主要功能
1. 💯 免费 & 开源。
2. ✨ AI 大模型对话,多模态,Agent,MCP,Skills,知识库,人格设定,自动压缩对话。
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
```
> 需要安装 [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 且不想自行管理服务器的用户,我们推荐使用雨云的一键云部署服务 ☁️:
[](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 部署由社区维护,适合在线演示和轻量试用场景。
[](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 | 文本转语音 |
## ❤️ 贡献
欢迎任何 Issues/Pull Requests!只需要将你的更改提交到此项目 :)
### 如何贡献
你可以通过查看问题或帮助审核 PR(拉取请求)来贡献。任何问题或 PR 都欢迎参与,以促进社区贡献。当然,这些只是建议,你可以以任何方式进行贡献。对于新功能的添加,请先通过 Issue 讨论。
### 开发环境
AstrBot 使用 `ruff` 进行代码格式化和检查。
```bash
git clone https://github.com/AstrBotDevs/AstrBot
pip install pre-commit
pre-commit install
```
## 🌍 社区
### 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">
[](https://star-history.com/#astrbotdevs/astrbot&Date)
</div>
<div align="center">
_陪伴与能力从来不应该是对立面。我们希望创造的是一个既能理解情绪、给予陪伴,也能可靠完成工作的机器人。_
_私は、高性能ですから!_
<img src="https://files.astrbot.app/watashiwa-koseino-desukara.gif" width="100"/>
</div>
================================================
FILE: astrbot/__init__.py
================================================
from .core.log import LogManager
logger = LogManager.GetLogger(log_name="astrbot")
================================================
FILE: astrbot/api/__init__.py
================================================
from astrbot import logger
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",
"ToolSet",
"agent",
"html_renderer",
"llm_tool",
"logger",
"sp",
]
================================================
FILE: astrbot/api/all.py
================================================
from astrbot.core.config.astrbot_config import AstrBotConfig
from astrbot import logger
from astrbot.core import html_renderer
from astrbot.core.star.register import register_llm_tool as llm_tool
# event
from astrbot.core.message.message_event_result import (
MessageEventResult,
MessageChain,
CommandResult,
EventResultType,
)
from astrbot.core.platform import AstrMessageEvent
# star register
from astrbot.core.star.register import (
register_command as command,
register_command_group as command_group,
register_event_message_type as event_message_type,
register_regex as regex,
register_platform_adapter_type as platform_adapter_type,
)
from astrbot.core.star.filter.event_message_type import (
EventMessageTypeFilter,
EventMessageType,
)
from astrbot.core.star.filter.platform_adapter_type import (
PlatformAdapterTypeFilter,
PlatformAdapterType,
)
from astrbot.core.star.register import (
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, ProviderMetaData
from astrbot.core.db.po import Personality
# platform
from astrbot.core.platform import (
AstrMessageEvent,
Platform,
AstrBotMessage,
MessageMember,
MessageType,
PlatformMetadata,
)
from astrbot.core.platform.register import register_platform_adapter
from .message_components import *
================================================
FILE: astrbot/api/event/__init__.py
================================================
from astrbot.core.message.message_event_result import (
CommandResult,
EventResultType,
MessageChain,
MessageEventResult,
ResultContentType,
)
from astrbot.core.platform import AstrMessageEvent
__all__ = [
"AstrMessageEvent",
"CommandResult",
"EventResultType",
"MessageChain",
"MessageEventResult",
"ResultContentType",
]
================================================
FILE: astrbot/api/event/filter/__init__.py
================================================
from astrbot.core.star.filter.custom_filter import CustomFilter
from astrbot.core.star.filter.event_message_type import (
EventMessageType,
EventMessageTypeFilter,
)
from astrbot.core.star.filter.permission import PermissionType, PermissionTypeFilter
from astrbot.core.star.filter.platform_adapter_type import (
PlatformAdapterType,
PlatformAdapterTypeFilter,
)
from astrbot.core.star.register import register_after_message_sent as after_message_sent
from astrbot.core.star.register import register_command as command
from astrbot.core.star.register import register_command_group as command_group
from astrbot.core.star.register import register_custom_filter as custom_filter
from astrbot.core.star.register import register_event_message_type as event_message_type
from astrbot.core.star.register import register_llm_tool as llm_tool
from astrbot.core.star.register import register_on_astrbot_loaded as on_astrbot_loaded
from astrbot.core.star.register import (
register_on_decorating_result as on_decorating_result,
)
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,
)
from astrbot.core.star.register import register_regex as regex
__all__ = [
"CustomFilter",
"EventMessageType",
"EventMessageTypeFilter",
"PermissionType",
"PermissionTypeFilter",
"PlatformAdapterType",
"PlatformAdapterTypeFilter",
"after_message_sent",
"command",
"command_group",
"custom_filter",
"event_message_type",
"llm_tool",
"on_astrbot_loaded",
"on_decorating_result",
"on_llm_request",
"on_llm_response",
"on_plugin_error",
"on_plugin_loaded",
"on_plugin_unloaded",
"on_platform_loaded",
"on_waiting_llm_request",
"permission_type",
"platform_adapter_type",
"regex",
"on_using_llm_tool",
"on_llm_tool_respond",
]
================================================
FILE: astrbot/api/message_components.py
================================================
from astrbot.core.message.components import *
================================================
FILE: astrbot/api/platform/__init__.py
================================================
from astrbot.core.message.components import *
from astrbot.core.platform import (
AstrBotMessage,
AstrMessageEvent,
Group,
MessageMember,
MessageType,
Platform,
PlatformMetadata,
)
from astrbot.core.platform.register import register_platform_adapter
__all__ = [
"AstrBotMessage",
"AstrMessageEvent",
"Group",
"MessageMember",
"MessageType",
"Platform",
"PlatformMetadata",
"register_platform_adapter",
]
================================================
FILE: astrbot/api/provider/__init__.py
================================================
from astrbot.core.db.po import Personality
from astrbot.core.provider import Provider, STTProvider
from astrbot.core.provider.entities import (
LLMResponse,
ProviderMetaData,
ProviderRequest,
ProviderType,
)
__all__ = [
"LLMResponse",
"Personality",
"Provider",
"ProviderMetaData",
"ProviderRequest",
"ProviderType",
"STTProvider",
]
================================================
FILE: astrbot/api/star/__init__.py
================================================
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)
)
__all__ = ["Context", "Star", "StarTools", "register"]
================================================
FILE: astrbot/api/util/__init__.py
================================================
from astrbot.core.utils.session_waiter import (
SessionController,
SessionWaiter,
session_waiter,
)
__all__ = ["SessionController", "SessionWaiter", "session_waiter"]
================================================
FILE: astrbot/builtin_stars/astrbot/long_term_memory.py
================================================
import datetime
import random
import uuid
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 At, Image, Plain
from astrbot.api.platform import MessageType
from astrbot.api.provider import LLMResponse, Provider, ProviderRequest
from astrbot.core.astrbot_config_mgr import AstrBotConfigManager
"""
聊天记忆增强
"""
class LongTermMemory:
def __init__(self, acm: AstrBotConfigManager, context: star.Context) -> None:
self.acm = acm
self.context = context
self.session_chats = defaultdict(list)
"""记录群成员的群聊记录"""
def cfg(self, event: AstrMessageEvent):
cfg = self.context.get_config(umo=event.unified_msg_origin)
try:
max_cnt = int(cfg["provider_ltm_settings"]["group_message_max_cnt"])
except BaseException as e:
logger.error(e)
max_cnt = 300
image_caption_prompt = cfg["provider_settings"]["image_caption_prompt"]
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"]
ar_possibility = active_reply["possibility_reply"]
ar_prompt = active_reply.get("prompt", "")
ar_whitelist = active_reply.get("whitelist", [])
ret = {
"max_cnt": max_cnt,
"image_caption": image_caption,
"image_caption_prompt": image_caption_prompt,
"image_caption_provider_id": image_caption_provider_id,
"enable_active_reply": enable_active_reply,
"ar_method": ar_method,
"ar_possibility": ar_possibility,
"ar_prompt": ar_prompt,
"ar_whitelist": ar_whitelist,
}
return ret
async def remove_session(self, event: AstrMessageEvent) -> int:
cnt = 0
if event.unified_msg_origin in self.session_chats:
cnt = len(self.session_chats[event.unified_msg_origin])
del self.session_chats[event.unified_msg_origin]
return cnt
async def get_image_caption(
self,
image_url: str,
image_caption_provider_id: str,
image_caption_prompt: str,
) -> str:
if not image_caption_provider_id:
provider = self.context.get_using_provider()
else:
provider = self.context.get_provider_by_id(image_caption_provider_id)
if not provider:
raise Exception(f"没有找到 ID 为 {image_caption_provider_id} 的提供商")
if not isinstance(provider, Provider):
raise Exception(f"提供商类型错误({type(provider)}),无法获取图片描述")
response = await provider.text_chat(
prompt=image_caption_prompt,
session_id=uuid.uuid4().hex,
image_urls=[image_url],
persist=False,
)
return response.completion_text
async def need_active_reply(self, event: AstrMessageEvent) -> bool:
cfg = self.cfg(event)
if not cfg["enable_active_reply"]:
return False
if event.get_message_type() != MessageType.GROUP_MESSAGE:
return False
if event.is_at_or_wake_command:
# if the message is a command, let it pass
return False
if cfg["ar_whitelist"] and (
event.unified_msg_origin not in cfg["ar_whitelist"]
and (
event.get_group_id() and event.get_group_id() not in cfg["ar_whitelist"]
)
):
return False
match cfg["ar_method"]:
case "possibility_reply":
trig = random.random() < cfg["ar_possibility"]
return trig
return False
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")
parts = [f"[{event.message_obj.sender.nickname}/{datetime_str}]: "]
cfg = self.cfg(event)
for comp in event.get_messages():
if isinstance(comp, Plain):
parts.append(f" {comp.text}")
elif isinstance(comp, Image):
if cfg["image_caption"]:
try:
url = comp.url if comp.url else comp.file
if not url:
raise Exception("图片 URL 为空")
caption = await self.get_image_caption(
url,
cfg["image_caption_provider_id"],
cfg["image_caption_prompt"],
)
parts.append(f" [Image: {caption}]")
except Exception as e:
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}")
self.session_chats[event.unified_msg_origin].append(final_message)
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) -> None:
"""当触发 LLM 请求前,调用此方法修改 req"""
if event.unified_msg_origin not in self.session_chats:
return
chats_str = "\n---\n".join(self.session_chats[event.unified_msg_origin])
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}"
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, llm_resp: LLMResponse
) -> None:
if event.unified_msg_origin not in self.session_chats:
return
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"]:
self.session_chats[event.unified_msg_origin].pop(0)
================================================
FILE: astrbot/builtin_stars/astrbot/main.py
================================================
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(
gitextract_qqwyrvoh/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── PLUGIN_PUBLISH.yml
│ │ ├── bug-report.yml
│ │ └── feature-request.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── auto_assign.yml
│ ├── copilot-instructions.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build-docs.yml
│ ├── code-format.yml
│ ├── codeql.yml
│ ├── coverage_test.yml
│ ├── dashboard_ci.yml
│ ├── docker-image.yml
│ ├── pr-title-check.yml
│ ├── release.yml
│ ├── smoke_test.yml
│ ├── stale.yml
│ └── sync-wiki.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── EULA.md
├── FIRST_NOTICE.en-US.md
├── FIRST_NOTICE.md
├── LICENSE
├── Makefile
├── README.md
├── README_fr.md
├── README_ja.md
├── README_ru.md
├── README_zh-TW.md
├── README_zh.md
├── astrbot/
│ ├── __init__.py
│ ├── api/
│ │ ├── __init__.py
│ │ ├── all.py
│ │ ├── event/
│ │ │ ├── __init__.py
│ │ │ └── filter/
│ │ │ └── __init__.py
│ │ ├── message_components.py
│ │ ├── platform/
│ │ │ └── __init__.py
│ │ ├── provider/
│ │ │ └── __init__.py
│ │ ├── star/
│ │ │ └── __init__.py
│ │ └── util/
│ │ └── __init__.py
│ ├── builtin_stars/
│ │ ├── astrbot/
│ │ │ ├── long_term_memory.py
│ │ │ ├── main.py
│ │ │ └── metadata.yaml
│ │ ├── builtin_commands/
│ │ │ ├── commands/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── admin.py
│ │ │ │ ├── alter_cmd.py
│ │ │ │ ├── conversation.py
│ │ │ │ ├── help.py
│ │ │ │ ├── llm.py
│ │ │ │ ├── persona.py
│ │ │ │ ├── plugin.py
│ │ │ │ ├── provider.py
│ │ │ │ ├── setunset.py
│ │ │ │ ├── sid.py
│ │ │ │ ├── t2i.py
│ │ │ │ ├── tts.py
│ │ │ │ └── utils/
│ │ │ │ └── rst_scene.py
│ │ │ ├── main.py
│ │ │ └── metadata.yaml
│ │ ├── session_controller/
│ │ │ ├── main.py
│ │ │ └── metadata.yaml
│ │ └── web_searcher/
│ │ ├── engines/
│ │ │ ├── __init__.py
│ │ │ ├── bing.py
│ │ │ └── sogo.py
│ │ ├── main.py
│ │ └── metadata.yaml
│ ├── cli/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── commands/
│ │ │ ├── __init__.py
│ │ │ ├── cmd_conf.py
│ │ │ ├── cmd_init.py
│ │ │ ├── cmd_plug.py
│ │ │ └── cmd_run.py
│ │ └── utils/
│ │ ├── __init__.py
│ │ ├── basic.py
│ │ ├── plugin.py
│ │ └── version_comparator.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── agent/
│ │ │ ├── agent.py
│ │ │ ├── context/
│ │ │ │ ├── compressor.py
│ │ │ │ ├── config.py
│ │ │ │ ├── manager.py
│ │ │ │ ├── token_counter.py
│ │ │ │ └── truncator.py
│ │ │ ├── handoff.py
│ │ │ ├── hooks.py
│ │ │ ├── mcp_client.py
│ │ │ ├── message.py
│ │ │ ├── response.py
│ │ │ ├── run_context.py
│ │ │ ├── runners/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── coze/
│ │ │ │ │ ├── coze_agent_runner.py
│ │ │ │ │ └── coze_api_client.py
│ │ │ │ ├── dashscope/
│ │ │ │ │ └── dashscope_agent_runner.py
│ │ │ │ ├── deerflow/
│ │ │ │ │ ├── constants.py
│ │ │ │ │ ├── deerflow_agent_runner.py
│ │ │ │ │ ├── deerflow_api_client.py
│ │ │ │ │ ├── deerflow_content_mapper.py
│ │ │ │ │ └── deerflow_stream_utils.py
│ │ │ │ ├── dify/
│ │ │ │ │ ├── dify_agent_runner.py
│ │ │ │ │ └── dify_api_client.py
│ │ │ │ └── tool_loop_agent_runner.py
│ │ │ ├── tool.py
│ │ │ ├── tool_executor.py
│ │ │ └── tool_image_cache.py
│ │ ├── astr_agent_context.py
│ │ ├── astr_agent_hooks.py
│ │ ├── astr_agent_run_util.py
│ │ ├── astr_agent_tool_exec.py
│ │ ├── astr_main_agent.py
│ │ ├── astr_main_agent_resources.py
│ │ ├── astrbot_config_mgr.py
│ │ ├── backup/
│ │ │ ├── __init__.py
│ │ │ ├── constants.py
│ │ │ ├── exporter.py
│ │ │ └── importer.py
│ │ ├── computer/
│ │ │ ├── booters/
│ │ │ │ ├── base.py
│ │ │ │ ├── bay_manager.py
│ │ │ │ ├── boxlite.py
│ │ │ │ ├── local.py
│ │ │ │ ├── shipyard.py
│ │ │ │ └── shipyard_neo.py
│ │ │ ├── computer_client.py
│ │ │ ├── olayer/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── browser.py
│ │ │ │ ├── filesystem.py
│ │ │ │ ├── python.py
│ │ │ │ └── shell.py
│ │ │ └── tools/
│ │ │ ├── __init__.py
│ │ │ ├── browser.py
│ │ │ ├── fs.py
│ │ │ ├── neo_skills.py
│ │ │ ├── permissions.py
│ │ │ ├── python.py
│ │ │ └── shell.py
│ │ ├── config/
│ │ │ ├── __init__.py
│ │ │ ├── astrbot_config.py
│ │ │ ├── default.py
│ │ │ └── i18n_utils.py
│ │ ├── conversation_mgr.py
│ │ ├── core_lifecycle.py
│ │ ├── cron/
│ │ │ ├── __init__.py
│ │ │ ├── events.py
│ │ │ └── manager.py
│ │ ├── db/
│ │ │ ├── __init__.py
│ │ │ ├── migration/
│ │ │ │ ├── helper.py
│ │ │ │ ├── migra_3_to_4.py
│ │ │ │ ├── migra_45_to_46.py
│ │ │ │ ├── migra_token_usage.py
│ │ │ │ ├── migra_webchat_session.py
│ │ │ │ ├── shared_preferences_v3.py
│ │ │ │ └── sqlite_v3.py
│ │ │ ├── po.py
│ │ │ ├── sqlite.py
│ │ │ └── vec_db/
│ │ │ ├── base.py
│ │ │ └── faiss_impl/
│ │ │ ├── __init__.py
│ │ │ ├── document_storage.py
│ │ │ ├── embedding_storage.py
│ │ │ ├── sqlite_init.sql
│ │ │ └── vec_db.py
│ │ ├── event_bus.py
│ │ ├── exceptions.py
│ │ ├── file_token_service.py
│ │ ├── initial_loader.py
│ │ ├── knowledge_base/
│ │ │ ├── chunking/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── fixed_size.py
│ │ │ │ └── recursive.py
│ │ │ ├── kb_db_sqlite.py
│ │ │ ├── kb_helper.py
│ │ │ ├── kb_mgr.py
│ │ │ ├── models.py
│ │ │ ├── parsers/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── base.py
│ │ │ │ ├── markitdown_parser.py
│ │ │ │ ├── pdf_parser.py
│ │ │ │ ├── text_parser.py
│ │ │ │ ├── url_parser.py
│ │ │ │ └── util.py
│ │ │ ├── prompts.py
│ │ │ └── retrieval/
│ │ │ ├── __init__.py
│ │ │ ├── hit_stopwords.txt
│ │ │ ├── manager.py
│ │ │ ├── rank_fusion.py
│ │ │ └── sparse_retriever.py
│ │ ├── log.py
│ │ ├── message/
│ │ │ ├── components.py
│ │ │ └── message_event_result.py
│ │ ├── persona_error_reply.py
│ │ ├── persona_mgr.py
│ │ ├── pipeline/
│ │ │ ├── __init__.py
│ │ │ ├── bootstrap.py
│ │ │ ├── content_safety_check/
│ │ │ │ ├── stage.py
│ │ │ │ └── strategies/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── baidu_aip.py
│ │ │ │ ├── keywords.py
│ │ │ │ └── strategy.py
│ │ │ ├── context.py
│ │ │ ├── context_utils.py
│ │ │ ├── preprocess_stage/
│ │ │ │ └── stage.py
│ │ │ ├── process_stage/
│ │ │ │ ├── follow_up.py
│ │ │ │ ├── method/
│ │ │ │ │ ├── agent_request.py
│ │ │ │ │ ├── agent_sub_stages/
│ │ │ │ │ │ ├── internal.py
│ │ │ │ │ │ └── third_party.py
│ │ │ │ │ └── star_request.py
│ │ │ │ └── stage.py
│ │ │ ├── rate_limit_check/
│ │ │ │ └── stage.py
│ │ │ ├── respond/
│ │ │ │ └── stage.py
│ │ │ ├── result_decorate/
│ │ │ │ └── stage.py
│ │ │ ├── scheduler.py
│ │ │ ├── session_status_check/
│ │ │ │ └── stage.py
│ │ │ ├── stage.py
│ │ │ ├── stage_order.py
│ │ │ ├── waking_check/
│ │ │ │ └── stage.py
│ │ │ └── whitelist_check/
│ │ │ └── stage.py
│ │ ├── platform/
│ │ │ ├── __init__.py
│ │ │ ├── astr_message_event.py
│ │ │ ├── astrbot_message.py
│ │ │ ├── manager.py
│ │ │ ├── message_session.py
│ │ │ ├── message_type.py
│ │ │ ├── platform.py
│ │ │ ├── platform_metadata.py
│ │ │ ├── register.py
│ │ │ └── sources/
│ │ │ ├── aiocqhttp/
│ │ │ │ ├── aiocqhttp_message_event.py
│ │ │ │ └── aiocqhttp_platform_adapter.py
│ │ │ ├── dingtalk/
│ │ │ │ ├── dingtalk_adapter.py
│ │ │ │ └── dingtalk_event.py
│ │ │ ├── discord/
│ │ │ │ ├── client.py
│ │ │ │ ├── components.py
│ │ │ │ ├── discord_platform_adapter.py
│ │ │ │ └── discord_platform_event.py
│ │ │ ├── kook/
│ │ │ │ ├── kook_adapter.py
│ │ │ │ ├── kook_client.py
│ │ │ │ ├── kook_config.py
│ │ │ │ ├── kook_event.py
│ │ │ │ └── kook_types.py
│ │ │ ├── lark/
│ │ │ │ ├── lark_adapter.py
│ │ │ │ ├── lark_event.py
│ │ │ │ └── server.py
│ │ │ ├── line/
│ │ │ │ ├── line_adapter.py
│ │ │ │ ├── line_api.py
│ │ │ │ └── line_event.py
│ │ │ ├── misskey/
│ │ │ │ ├── misskey_adapter.py
│ │ │ │ ├── misskey_api.py
│ │ │ │ ├── misskey_event.py
│ │ │ │ └── misskey_utils.py
│ │ │ ├── qqofficial/
│ │ │ │ ├── qqofficial_message_event.py
│ │ │ │ └── qqofficial_platform_adapter.py
│ │ │ ├── qqofficial_webhook/
│ │ │ │ ├── qo_webhook_adapter.py
│ │ │ │ ├── qo_webhook_event.py
│ │ │ │ └── qo_webhook_server.py
│ │ │ ├── satori/
│ │ │ │ ├── satori_adapter.py
│ │ │ │ └── satori_event.py
│ │ │ ├── slack/
│ │ │ │ ├── client.py
│ │ │ │ ├── slack_adapter.py
│ │ │ │ └── slack_event.py
│ │ │ ├── telegram/
│ │ │ │ ├── tg_adapter.py
│ │ │ │ └── tg_event.py
│ │ │ ├── webchat/
│ │ │ │ ├── message_parts_helper.py
│ │ │ │ ├── webchat_adapter.py
│ │ │ │ ├── webchat_event.py
│ │ │ │ └── webchat_queue_mgr.py
│ │ │ ├── wecom/
│ │ │ │ ├── wecom_adapter.py
│ │ │ │ ├── wecom_event.py
│ │ │ │ ├── wecom_kf.py
│ │ │ │ └── wecom_kf_message.py
│ │ │ ├── wecom_ai_bot/
│ │ │ │ ├── WXBizJsonMsgCrypt.py
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ierror.py
│ │ │ │ ├── wecomai_adapter.py
│ │ │ │ ├── wecomai_api.py
│ │ │ │ ├── wecomai_event.py
│ │ │ │ ├── wecomai_long_connection.py
│ │ │ │ ├── wecomai_queue_mgr.py
│ │ │ │ ├── wecomai_server.py
│ │ │ │ ├── wecomai_utils.py
│ │ │ │ └── wecomai_webhook.py
│ │ │ └── weixin_official_account/
│ │ │ ├── weixin_offacc_adapter.py
│ │ │ └── weixin_offacc_event.py
│ │ ├── platform_message_history_mgr.py
│ │ ├── provider/
│ │ │ ├── __init__.py
│ │ │ ├── entites.py
│ │ │ ├── entities.py
│ │ │ ├── func_tool_manager.py
│ │ │ ├── manager.py
│ │ │ ├── provider.py
│ │ │ ├── register.py
│ │ │ └── sources/
│ │ │ ├── anthropic_source.py
│ │ │ ├── azure_tts_source.py
│ │ │ ├── bailian_rerank_source.py
│ │ │ ├── dashscope_tts.py
│ │ │ ├── edge_tts_source.py
│ │ │ ├── fishaudio_tts_api_source.py
│ │ │ ├── gemini_embedding_source.py
│ │ │ ├── gemini_source.py
│ │ │ ├── gemini_tts_source.py
│ │ │ ├── genie_tts.py
│ │ │ ├── groq_source.py
│ │ │ ├── gsv_selfhosted_source.py
│ │ │ ├── gsvi_tts_source.py
│ │ │ ├── kimi_code_source.py
│ │ │ ├── minimax_tts_api_source.py
│ │ │ ├── oai_aihubmix_source.py
│ │ │ ├── openai_embedding_source.py
│ │ │ ├── openai_source.py
│ │ │ ├── openai_tts_api_source.py
│ │ │ ├── openrouter_source.py
│ │ │ ├── sensevoice_selfhosted_source.py
│ │ │ ├── vllm_rerank_source.py
│ │ │ ├── volcengine_tts.py
│ │ │ ├── whisper_api_source.py
│ │ │ ├── whisper_selfhosted_source.py
│ │ │ ├── xai_source.py
│ │ │ ├── xinference_rerank_source.py
│ │ │ ├── xinference_stt_provider.py
│ │ │ └── zhipu_source.py
│ │ ├── sentinels.py
│ │ ├── skills/
│ │ │ ├── __init__.py
│ │ │ ├── neo_skill_sync.py
│ │ │ └── skill_manager.py
│ │ ├── star/
│ │ │ ├── README.md
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── command_management.py
│ │ │ ├── config.py
│ │ │ ├── context.py
│ │ │ ├── error_messages.py
│ │ │ ├── filter/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── command.py
│ │ │ │ ├── command_group.py
│ │ │ │ ├── custom_filter.py
│ │ │ │ ├── event_message_type.py
│ │ │ │ ├── permission.py
│ │ │ │ ├── platform_adapter_type.py
│ │ │ │ └── regex.py
│ │ │ ├── register/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── star.py
│ │ │ │ └── star_handler.py
│ │ │ ├── session_llm_manager.py
│ │ │ ├── session_plugin_manager.py
│ │ │ ├── star.py
│ │ │ ├── star_handler.py
│ │ │ ├── star_manager.py
│ │ │ ├── star_tools.py
│ │ │ └── updator.py
│ │ ├── subagent_orchestrator.py
│ │ ├── tools/
│ │ │ └── cron_tools.py
│ │ ├── umop_config_router.py
│ │ ├── updator.py
│ │ ├── utils/
│ │ │ ├── active_event_registry.py
│ │ │ ├── astrbot_path.py
│ │ │ ├── command_parser.py
│ │ │ ├── config_number.py
│ │ │ ├── core_constraints.py
│ │ │ ├── datetime_utils.py
│ │ │ ├── error_redaction.py
│ │ │ ├── file_extract.py
│ │ │ ├── history_saver.py
│ │ │ ├── http_ssl.py
│ │ │ ├── image_ref_utils.py
│ │ │ ├── io.py
│ │ │ ├── llm_metadata.py
│ │ │ ├── log_pipe.py
│ │ │ ├── media_utils.py
│ │ │ ├── metrics.py
│ │ │ ├── migra_helper.py
│ │ │ ├── network_utils.py
│ │ │ ├── path_util.py
│ │ │ ├── pip_installer.py
│ │ │ ├── plugin_kv_store.py
│ │ │ ├── quoted_message/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── chain_parser.py
│ │ │ │ ├── extractor.py
│ │ │ │ ├── image_refs.py
│ │ │ │ ├── image_resolver.py
│ │ │ │ ├── onebot_client.py
│ │ │ │ └── settings.py
│ │ │ ├── quoted_message_parser.py
│ │ │ ├── requirements_utils.py
│ │ │ ├── runtime_env.py
│ │ │ ├── session_lock.py
│ │ │ ├── session_waiter.py
│ │ │ ├── shared_preferences.py
│ │ │ ├── string_utils.py
│ │ │ ├── t2i/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── local_strategy.py
│ │ │ │ ├── network_strategy.py
│ │ │ │ ├── renderer.py
│ │ │ │ ├── template/
│ │ │ │ │ ├── astrbot_powershell.html
│ │ │ │ │ └── base.html
│ │ │ │ └── template_manager.py
│ │ │ ├── temp_dir_cleaner.py
│ │ │ ├── tencent_record_helper.py
│ │ │ ├── trace.py
│ │ │ ├── version_comparator.py
│ │ │ └── webhook_utils.py
│ │ └── zip_updator.py
│ ├── dashboard/
│ │ ├── routes/
│ │ │ ├── __init__.py
│ │ │ ├── api_key.py
│ │ │ ├── auth.py
│ │ │ ├── backup.py
│ │ │ ├── chat.py
│ │ │ ├── chatui_project.py
│ │ │ ├── command.py
│ │ │ ├── config.py
│ │ │ ├── conversation.py
│ │ │ ├── cron.py
│ │ │ ├── file.py
│ │ │ ├── knowledge_base.py
│ │ │ ├── live_chat.py
│ │ │ ├── log.py
│ │ │ ├── open_api.py
│ │ │ ├── persona.py
│ │ │ ├── platform.py
│ │ │ ├── plugin.py
│ │ │ ├── route.py
│ │ │ ├── session_management.py
│ │ │ ├── skills.py
│ │ │ ├── stat.py
│ │ │ ├── static_file.py
│ │ │ ├── subagent.py
│ │ │ ├── t2i.py
│ │ │ ├── tools.py
│ │ │ ├── update.py
│ │ │ └── util.py
│ │ ├── server.py
│ │ └── utils.py
│ └── utils/
│ ├── __init__.py
│ └── http_ssl_common.py
├── changelogs/
│ ├── v3.4.0.md
│ ├── v3.4.1.md
│ ├── v3.4.10.md
│ ├── v3.4.11.md
│ ├── v3.4.12.md
│ ├── v3.4.13.md
│ ├── v3.4.14.md
│ ├── v3.4.15.md
│ ├── v3.4.16.md
│ ├── v3.4.17.md
│ ├── v3.4.18.md
│ ├── v3.4.19.md
│ ├── v3.4.20.md
│ ├── v3.4.21.md
│ ├── v3.4.22.md
│ ├── v3.4.23.md
│ ├── v3.4.24.md
│ ├── v3.4.25.md
│ ├── v3.4.26.md
│ ├── v3.4.27.md
│ ├── v3.4.28.md
│ ├── v3.4.29.md
│ ├── v3.4.3.md
│ ├── v3.4.30.md
│ ├── v3.4.31.md
│ ├── v3.4.32.md
│ ├── v3.4.33.md
│ ├── v3.4.35.md
│ ├── v3.4.36.md
│ ├── v3.4.37.md
│ ├── v3.4.38.md
│ ├── v3.4.39.md
│ ├── v3.4.4.md
│ ├── v3.4.5.md
│ ├── v3.4.6.md
│ ├── v3.4.7.md
│ ├── v3.4.8.md
│ ├── v3.4.9.md
│ ├── v3.5.0.md
│ ├── v3.5.1.md
│ ├── v3.5.10.md
│ ├── v3.5.11.md
│ ├── v3.5.12.md
│ ├── v3.5.13.md
│ ├── v3.5.14.md
│ ├── v3.5.15.md
│ ├── v3.5.16.md
│ ├── v3.5.17.md
│ ├── v3.5.18.md
│ ├── v3.5.19.md
│ ├── v3.5.2.md
│ ├── v3.5.20.md
│ ├── v3.5.21.md
│ ├── v3.5.22.md
│ ├── v3.5.23.md
│ ├── v3.5.24.md
│ ├── v3.5.25.md
│ ├── v3.5.26.md
│ ├── v3.5.27.md
│ ├── v3.5.3.1.md
│ ├── v3.5.3.2.md
│ ├── v3.5.3.md
│ ├── v3.5.4.md
│ ├── v3.5.5.md
│ ├── v3.5.6.md
│ ├── v3.5.7.md
│ ├── v3.5.8.md
│ ├── v3.5.9.md
│ ├── v4.0.0-beta.3.md
│ ├── v4.0.0-beta.4.md
│ ├── v4.0.0-beta.5.md
│ ├── v4.0.0.md
│ ├── v4.1.0.md
│ ├── v4.1.1.md
│ ├── v4.1.2.md
│ ├── v4.1.3.md
│ ├── v4.1.4.md
│ ├── v4.1.5.md
│ ├── v4.1.6.md
│ ├── v4.1.7.md
│ ├── v4.10.0-alpha.1.md
│ ├── v4.10.0-alpha.2.md
│ ├── v4.10.0.md
│ ├── v4.10.1.md
│ ├── v4.10.2.md
│ ├── v4.10.3.md
│ ├── v4.10.4.md
│ ├── v4.10.5.md
│ ├── v4.10.6.md
│ ├── v4.11.0.md
│ ├── v4.11.1.md
│ ├── v4.11.2.md
│ ├── v4.11.3.md
│ ├── v4.11.4.md
│ ├── v4.12.0.md
│ ├── v4.12.1.md
│ ├── v4.12.2.md
│ ├── v4.12.3.md
│ ├── v4.12.4.md
│ ├── v4.13.0.md
│ ├── v4.13.1.md
│ ├── v4.13.2.md
│ ├── v4.14.0.md
│ ├── v4.14.1.md
│ ├── v4.14.2.md
│ ├── v4.14.3.md
│ ├── v4.14.4.md
│ ├── v4.14.5.md
│ ├── v4.14.6.md
│ ├── v4.14.7.md
│ ├── v4.14.8.md
│ ├── v4.15.0.md
│ ├── v4.16.0.md
│ ├── v4.17.0.md
│ ├── v4.17.1.md
│ ├── v4.17.2.md
│ ├── v4.17.3.md
│ ├── v4.17.4.md
│ ├── v4.17.5.md
│ ├── v4.17.6.md
│ ├── v4.18.0.md
│ ├── v4.18.1.md
│ ├── v4.18.2.md
│ ├── v4.18.3.md
│ ├── v4.19.2.md
│ ├── v4.19.3.md
│ ├── v4.19.4.md
│ ├── v4.19.5.md
│ ├── v4.2.0.md
│ ├── v4.2.1.md
│ ├── v4.20.0.md
│ ├── v4.20.1.md
│ ├── v4.3.0.md
│ ├── v4.3.1.md
│ ├── v4.3.2.md
│ ├── v4.3.3.md
│ ├── v4.3.5.md
│ ├── v4.5.0.md
│ ├── v4.5.1.md
│ ├── v4.5.2.md
│ ├── v4.5.3.md
│ ├── v4.5.4.md
│ ├── v4.5.5.md
│ ├── v4.5.6.md
│ ├── v4.5.7.md
│ ├── v4.5.8.md
│ ├── v4.6.0.md
│ ├── v4.6.1.md
│ ├── v4.7.0.md
│ ├── v4.7.1.md
│ ├── v4.7.3.md
│ ├── v4.7.4.md
│ ├── v4.8.0.md
│ ├── v4.9.0.md
│ ├── v4.9.1.md
│ └── v4.9.2.md
├── compose-with-shipyard.yml
├── compose.yml
├── dashboard/
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── env.d.ts
│ ├── index.html
│ ├── package.json
│ ├── public/
│ │ ├── _redirects
│ │ └── robots.txt
│ ├── scripts/
│ │ └── subset-mdi-font.mjs
│ ├── src/
│ │ ├── App.vue
│ │ ├── assets/
│ │ │ └── mdi-subset/
│ │ │ └── materialdesignicons-subset.css
│ │ ├── components/
│ │ │ ├── ConfirmDialog.vue
│ │ │ ├── chat/
│ │ │ │ ├── Chat.vue
│ │ │ │ ├── ChatInput.vue
│ │ │ │ ├── ConfigSelector.vue
│ │ │ │ ├── ConversationSidebar.vue
│ │ │ │ ├── LiveMode.vue
│ │ │ │ ├── LiveOrb.vue
│ │ │ │ ├── MessageList.vue
│ │ │ │ ├── ProjectDialog.vue
│ │ │ │ ├── ProjectList.vue
│ │ │ │ ├── ProjectView.vue
│ │ │ │ ├── ProviderConfigDialog.vue
│ │ │ │ ├── ProviderModelMenu.vue
│ │ │ │ ├── StandaloneChat.vue
│ │ │ │ ├── WelcomeView.vue
│ │ │ │ └── message_list_comps/
│ │ │ │ ├── ActionRef.vue
│ │ │ │ ├── IPythonToolBlock.vue
│ │ │ │ ├── MessagePartsRenderer.vue
│ │ │ │ ├── ReasoningBlock.vue
│ │ │ │ ├── RefNode.vue
│ │ │ │ ├── RefsSidebar.vue
│ │ │ │ ├── ToolCallCard.vue
│ │ │ │ └── ToolCallItem.vue
│ │ │ ├── config/
│ │ │ │ ├── AstrBotCoreConfigWrapper.vue
│ │ │ │ └── UnsavedChangesConfirmDialog.vue
│ │ │ ├── extension/
│ │ │ │ ├── MarketPluginCard.vue
│ │ │ │ ├── McpServersSection.vue
│ │ │ │ ├── PluginSortControl.vue
│ │ │ │ ├── SkillsSection.vue
│ │ │ │ └── componentPanel/
│ │ │ │ ├── components/
│ │ │ │ │ ├── CommandFilters.vue
│ │ │ │ │ ├── CommandTable.vue
│ │ │ │ │ ├── DetailsDialog.vue
│ │ │ │ │ ├── RenameDialog.vue
│ │ │ │ │ └── ToolTable.vue
│ │ │ │ ├── composables/
│ │ │ │ │ ├── useCommandActions.ts
│ │ │ │ │ ├── useCommandFilters.ts
│ │ │ │ │ └── useComponentData.ts
│ │ │ │ ├── index.vue
│ │ │ │ └── types.ts
│ │ │ ├── folder/
│ │ │ │ ├── BaseCreateFolderDialog.vue
│ │ │ │ ├── BaseFolderBreadcrumb.vue
│ │ │ │ ├── BaseFolderCard.vue
│ │ │ │ ├── BaseFolderItemSelector.vue
│ │ │ │ ├── BaseFolderTree.vue
│ │ │ │ ├── BaseFolderTreeNode.vue
│ │ │ │ ├── BaseMoveTargetNode.vue
│ │ │ │ ├── BaseMoveToFolderDialog.vue
│ │ │ │ ├── README.md
│ │ │ │ ├── index.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── useFolderManager.ts
│ │ │ ├── platform/
│ │ │ │ └── AddNewPlatform.vue
│ │ │ ├── provider/
│ │ │ │ ├── AddNewProvider.vue
│ │ │ │ ├── ProviderModelsPanel.vue
│ │ │ │ └── ProviderSourcesPanel.vue
│ │ │ └── shared/
│ │ │ ├── AstrBotConfig.vue
│ │ │ ├── AstrBotConfigV4.vue
│ │ │ ├── BackupDialog.vue
│ │ │ ├── ChangelogDialog.vue
│ │ │ ├── ConfigItemRenderer.vue
│ │ │ ├── ConsoleDisplayer.vue
│ │ │ ├── ExtensionCard.vue
│ │ │ ├── FileConfigItem.vue
│ │ │ ├── ItemCard.vue
│ │ │ ├── ItemCardGrid.vue
│ │ │ ├── KnowledgeBaseSelector.vue
│ │ │ ├── LanguageSwitcher.vue
│ │ │ ├── ListConfigItem.vue
│ │ │ ├── Logo.vue
│ │ │ ├── MigrationDialog.vue
│ │ │ ├── ObjectEditor.vue
│ │ │ ├── PersonaForm.vue
│ │ │ ├── PersonaQuickPreview.vue
│ │ │ ├── PersonaSelector.vue
│ │ │ ├── PluginPlatformChip.vue
│ │ │ ├── PluginSetSelector.vue
│ │ │ ├── ProviderSelector.vue
│ │ │ ├── ProxySelector.vue
│ │ │ ├── ReadmeDialog.vue
│ │ │ ├── SidebarCustomizer.vue
│ │ │ ├── StyledMenu.vue
│ │ │ ├── T2ITemplateEditor.vue
│ │ │ ├── TemplateListEditor.vue
│ │ │ ├── TraceDisplayer.vue
│ │ │ ├── UninstallConfirmDialog.vue
│ │ │ └── WaitingForRestart.vue
│ │ ├── composables/
│ │ │ ├── useConversations.ts
│ │ │ ├── useMediaHandling.ts
│ │ │ ├── useMessages.ts
│ │ │ ├── useProjects.ts
│ │ │ ├── useProviderSources.ts
│ │ │ ├── useRecording.ts
│ │ │ ├── useSessions.ts
│ │ │ └── useVADRecording.ts
│ │ ├── config.ts
│ │ ├── i18n/
│ │ │ ├── composables.ts
│ │ │ ├── loader.ts
│ │ │ ├── locales/
│ │ │ │ ├── en-US/
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── actions.json
│ │ │ │ │ │ ├── common.json
│ │ │ │ │ │ ├── header.json
│ │ │ │ │ │ ├── navigation.json
│ │ │ │ │ │ ├── shared.json
│ │ │ │ │ │ └── status.json
│ │ │ │ │ ├── features/
│ │ │ │ │ │ ├── about.json
│ │ │ │ │ │ ├── alkaid/
│ │ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ │ ├── knowledge-base.json
│ │ │ │ │ │ │ └── memory.json
│ │ │ │ │ │ ├── auth.json
│ │ │ │ │ │ ├── chart.json
│ │ │ │ │ │ ├── chat.json
│ │ │ │ │ │ ├── command.json
│ │ │ │ │ │ ├── config-metadata.json
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── console.json
│ │ │ │ │ │ ├── conversation.json
│ │ │ │ │ │ ├── cron.json
│ │ │ │ │ │ ├── dashboard.json
│ │ │ │ │ │ ├── extension.json
│ │ │ │ │ │ ├── knowledge-base/
│ │ │ │ │ │ │ ├── detail.json
│ │ │ │ │ │ │ ├── document.json
│ │ │ │ │ │ │ └── index.json
│ │ │ │ │ │ ├── migration.json
│ │ │ │ │ │ ├── persona.json
│ │ │ │ │ │ ├── platform.json
│ │ │ │ │ │ ├── provider.json
│ │ │ │ │ │ ├── session-management.json
│ │ │ │ │ │ ├── settings.json
│ │ │ │ │ │ ├── subagent.json
│ │ │ │ │ │ ├── tool-use.json
│ │ │ │ │ │ ├── trace.json
│ │ │ │ │ │ └── welcome.json
│ │ │ │ │ └── messages/
│ │ │ │ │ ├── errors.json
│ │ │ │ │ ├── success.json
│ │ │ │ │ └── validation.json
│ │ │ │ ├── ru-RU/
│ │ │ │ │ ├── core/
│ │ │ │ │ │ ├── actions.json
│ │ │ │ │ │ ├── common.json
│ │ │ │ │ │ ├── header.json
│ │ │ │ │ │ ├── navigation.json
│ │ │ │ │ │ ├── shared.json
│ │ │ │ │ │ └── status.json
│ │ │ │ │ ├── features/
│ │ │ │ │ │ ├── about.json
│ │ │ │ │ │ ├── alkaid/
│ │ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ │ ├── knowledge-base.json
│ │ │ │ │ │ │ └── memory.json
│ │ │ │ │ │ ├── auth.json
│ │ │ │ │ │ ├── chart.json
│ │ │ │ │ │ ├── chat.json
│ │ │ │ │ │ ├── command.json
│ │ │ │ │ │ ├── config-metadata.json
│ │ │ │ │ │ ├── config.json
│ │ │ │ │ │ ├── console.json
│ │ │ │ │ │ ├── conversation.json
│ │ │ │ │ │ ├── cron.json
│ │ │ │ │ │ ├── dashboard.json
│ │ │ │ │ │ ├── extension.json
│ │ │ │ │ │ ├── knowledge-base/
│ │ │ │ │ │ │ ├── detail.json
│ │ │ │ │ │ │ ├── document.json
│ │ │ │ │ │ │ └── index.json
│ │ │ │ │ │ ├── migration.json
│ │ │ │ │ │ ├── persona.json
│ │ │ │ │ │ ├── platform.json
│ │ │ │ │ │ ├── provider.json
│ │ │ │ │ │ ├── session-management.json
│ │ │ │ │ │ ├── settings.json
│ │ │ │ │ │ ├── subagent.json
│ │ │ │ │ │ ├── tool-use.json
│ │ │ │ │ │ ├── trace.json
│ │ │ │ │ │ └── welcome.json
│ │ │ │ │ └── messages/
│ │ │ │ │ ├── errors.json
│ │ │ │ │ ├── success.json
│ │ │ │ │ └── validation.json
│ │ │ │ └── zh-CN/
│ │ │ │ ├── core/
│ │ │ │ │ ├── actions.json
│ │ │ │ │ ├── common.json
│ │ │ │ │ ├── header.json
│ │ │ │ │ ├── navigation.json
│ │ │ │ │ ├── shared.json
│ │ │ │ │ └── status.json
│ │ │ │ ├── features/
│ │ │ │ │ ├── about.json
│ │ │ │ │ ├── alkaid/
│ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ ├── knowledge-base.json
│ │ │ │ │ │ └── memory.json
│ │ │ │ │ ├── auth.json
│ │ │ │ │ ├── chart.json
│ │ │ │ │ ├── chat.json
│ │ │ │ │ ├── command.json
│ │ │ │ │ ├── config-metadata.json
│ │ │ │ │ ├── config.json
│ │ │ │ │ ├── console.json
│ │ │ │ │ ├── conversation.json
│ │ │ │ │ ├── cron.json
│ │ │ │ │ ├── dashboard.json
│ │ │ │ │ ├── extension.json
│ │ │ │ │ ├── knowledge-base/
│ │ │ │ │ │ ├── detail.json
│ │ │ │ │ │ ├── document.json
│ │ │ │ │ │ └── index.json
│ │ │ │ │ ├── migration.json
│ │ │ │ │ ├── persona.json
│ │ │ │ │ ├── platform.json
│ │ │ │ │ ├── provider.json
│ │ │ │ │ ├── session-management.json
│ │ │ │ │ ├── settings.json
│ │ │ │ │ ├── subagent.json
│ │ │ │ │ ├── tool-use.json
│ │ │ │ │ ├── trace.json
│ │ │ │ │ └── welcome.json
│ │ │ │ └── messages/
│ │ │ │ ├── errors.json
│ │ │ │ ├── success.json
│ │ │ │ └── validation.json
│ │ │ ├── tools/
│ │ │ │ └── index.ts
│ │ │ ├── translations.ts
│ │ │ ├── types.ts
│ │ │ └── validator.ts
│ │ ├── layouts/
│ │ │ ├── blank/
│ │ │ │ └── BlankLayout.vue
│ │ │ └── full/
│ │ │ ├── FullLayout.vue
│ │ │ ├── vertical-header/
│ │ │ │ └── VerticalHeader.vue
│ │ │ └── vertical-sidebar/
│ │ │ ├── NavItem.vue
│ │ │ ├── VerticalSidebar.vue
│ │ │ └── sidebarItem.ts
│ │ ├── main.ts
│ │ ├── plugins/
│ │ │ ├── confirmPlugin.ts
│ │ │ └── vuetify.ts
│ │ ├── router/
│ │ │ ├── AuthRoutes.ts
│ │ │ ├── ChatBoxRoutes.ts
│ │ │ ├── MainRoutes.ts
│ │ │ ├── index.ts
│ │ │ └── routeConstants.mjs
│ │ ├── scss/
│ │ │ ├── _override.scss
│ │ │ ├── _variables.scss
│ │ │ ├── components/
│ │ │ │ ├── _VButtons.scss
│ │ │ │ ├── _VCard.scss
│ │ │ │ ├── _VField.scss
│ │ │ │ ├── _VInput.scss
│ │ │ │ ├── _VNavigationDrawer.scss
│ │ │ │ ├── _VScrollbar.scss
│ │ │ │ ├── _VShadow.scss
│ │ │ │ ├── _VTabs.scss
│ │ │ │ └── _VTextField.scss
│ │ │ ├── layout/
│ │ │ │ ├── _container.scss
│ │ │ │ └── _sidebar.scss
│ │ │ ├── pages/
│ │ │ │ └── _dashboards.scss
│ │ │ └── style.scss
│ │ ├── stores/
│ │ │ ├── auth.ts
│ │ │ ├── common.js
│ │ │ ├── customizer.ts
│ │ │ ├── personaStore.ts
│ │ │ ├── routerLoading.ts
│ │ │ └── toast.js
│ │ ├── theme/
│ │ │ ├── DarkTheme.ts
│ │ │ └── LightTheme.ts
│ │ ├── types/
│ │ │ ├── confirm.d.ts
│ │ │ ├── desktop-bridge.d.ts
│ │ │ ├── themeTypes/
│ │ │ │ └── ThemeType.ts
│ │ │ ├── vue3-print-nb.d.ts
│ │ │ └── vue_tabler_icon.d.ts
│ │ ├── utils/
│ │ │ ├── chatConfigBinding.ts
│ │ │ ├── confirmDialog.ts
│ │ │ ├── desktopRuntime.ts
│ │ │ ├── errorUtils.js
│ │ │ ├── hashRouteTabs.mjs
│ │ │ ├── inputValue.ts
│ │ │ ├── platformUtils.js
│ │ │ ├── pluginSearch.js
│ │ │ ├── providerUtils.js
│ │ │ ├── restartAstrBot.ts
│ │ │ ├── routerReadiness.mjs
│ │ │ ├── sidebarCustomization.js
│ │ │ └── toast.js
│ │ └── views/
│ │ ├── AboutPage.vue
│ │ ├── AlkaidPage.vue
│ │ ├── ChatBoxPage.vue
│ │ ├── ChatPage.vue
│ │ ├── ConfigPage.vue
│ │ ├── ConsolePage.vue
│ │ ├── ConversationPage.vue
│ │ ├── CronJobPage.vue
│ │ ├── ExtensionPage.vue
│ │ ├── PersonaPage.vue
│ │ ├── PlatformPage.vue
│ │ ├── ProviderPage.vue
│ │ ├── SessionManagementPage.vue
│ │ ├── Settings.vue
│ │ ├── SubAgentPage.vue
│ │ ├── TracePage.vue
│ │ ├── WelcomePage.vue
│ │ ├── alkaid/
│ │ │ ├── KnowledgeBase.vue
│ │ │ ├── LongTermMemory.vue
│ │ │ └── Other.vue
│ │ ├── authentication/
│ │ │ ├── auth/
│ │ │ │ └── LoginPage.vue
│ │ │ └── authForms/
│ │ │ └── AuthLogin.vue
│ │ ├── dashboards/
│ │ │ └── default/
│ │ │ ├── DefaultDashboard.vue
│ │ │ └── components/
│ │ │ ├── MemoryUsage.vue
│ │ │ ├── MessageStat.vue
│ │ │ ├── OnlinePlatform.vue
│ │ │ ├── OnlineTime.vue
│ │ │ ├── PlatformStat.vue
│ │ │ ├── RunningTime.vue
│ │ │ └── TotalMessage.vue
│ │ ├── extension/
│ │ │ ├── InstalledPluginsTab.vue
│ │ │ ├── MarketPluginsTab.vue
│ │ │ └── useExtensionPage.js
│ │ ├── knowledge-base/
│ │ │ ├── DocumentDetail.vue
│ │ │ ├── KBDetail.vue
│ │ │ ├── KBList.vue
│ │ │ ├── components/
│ │ │ │ ├── DocumentsTab.vue
│ │ │ │ ├── RetrievalTab.vue
│ │ │ │ ├── SettingsTab.vue
│ │ │ │ └── TavilyKeyDialog.vue
│ │ │ └── index.vue
│ │ └── persona/
│ │ ├── CreateFolderDialog.vue
│ │ ├── FolderBreadcrumb.vue
│ │ ├── FolderCard.vue
│ │ ├── FolderTree.vue
│ │ ├── FolderTreeNode.vue
│ │ ├── MoveTargetNode.vue
│ │ ├── MoveToFolderDialog.vue
│ │ ├── PersonaCard.vue
│ │ ├── PersonaManager.vue
│ │ └── index.ts
│ ├── tests/
│ │ ├── hashRouteTabs.test.mjs
│ │ ├── routerReadiness.test.mjs
│ │ └── subsetMdiFont.test.mjs
│ ├── tsconfig.json
│ ├── tsconfig.vite-config.json
│ └── vite.config.ts
├── docs/
│ ├── .gitignore
│ ├── .vitepress/
│ │ ├── config/
│ │ │ └── head.ts
│ │ ├── config.mjs
│ │ └── theme/
│ │ ├── components/
│ │ │ ├── ArticleShare.vue
│ │ │ ├── HomeFeaturesAfter.vue
│ │ │ ├── Layout.vue
│ │ │ ├── NotFound.vue
│ │ │ └── SectionTabs.vue
│ │ ├── index.js
│ │ └── styles/
│ │ ├── custom-block.css
│ │ ├── font.css
│ │ └── style.css
│ ├── README.md
│ ├── en/
│ │ ├── community.md
│ │ ├── config/
│ │ │ └── model-config.md
│ │ ├── deploy/
│ │ │ ├── astrbot/
│ │ │ │ ├── 1panel.md
│ │ │ │ ├── btpanel.md
│ │ │ │ ├── casaos.md
│ │ │ │ ├── cli.md
│ │ │ │ ├── community-deployment.md
│ │ │ │ ├── compshare.md
│ │ │ │ ├── docker.md
│ │ │ │ ├── kubernetes.md
│ │ │ │ ├── launcher.md
│ │ │ │ ├── other-deployments.md
│ │ │ │ ├── package.md
│ │ │ │ └── sys-pm.md
│ │ │ └── when-deployed.md
│ │ ├── dev/
│ │ │ ├── astrbot-config.md
│ │ │ ├── openapi.md
│ │ │ ├── plugin-platform-adapter.md
│ │ │ ├── plugin.md
│ │ │ └── star/
│ │ │ ├── guides/
│ │ │ │ ├── ai.md
│ │ │ │ ├── env.md
│ │ │ │ ├── html-to-pic.md
│ │ │ │ ├── listen-message-event.md
│ │ │ │ ├── plugin-config.md
│ │ │ │ ├── send-message.md
│ │ │ │ ├── session-control.md
│ │ │ │ ├── simple.md
│ │ │ │ └── storage.md
│ │ │ ├── plugin-new.md
│ │ │ └── plugin-publish.md
│ │ ├── faq.md
│ │ ├── index.md
│ │ ├── ospp/
│ │ │ └── 2025.md
│ │ ├── others/
│ │ │ └── self-host-t2i.md
│ │ ├── platform/
│ │ │ ├── aiocqhttp.md
│ │ │ ├── dingtalk.md
│ │ │ ├── discord.md
│ │ │ ├── kook.md
│ │ │ ├── lark.md
│ │ │ ├── line.md
│ │ │ ├── matrix.md
│ │ │ ├── misskey.md
│ │ │ ├── qqofficial/
│ │ │ │ ├── webhook.md
│ │ │ │ └── websockets.md
│ │ │ ├── qqofficial.md
│ │ │ ├── satori/
│ │ │ │ ├── guide.md
│ │ │ │ └── server-satori.md
│ │ │ ├── slack.md
│ │ │ ├── start.md
│ │ │ ├── telegram.md
│ │ │ ├── vocechat.md
│ │ │ ├── wecom.md
│ │ │ ├── wecom_ai_bot.md
│ │ │ └── weixin-official-account.md
│ │ ├── providers/
│ │ │ ├── 302ai.md
│ │ │ ├── agent-runners/
│ │ │ │ ├── astrbot-agent-runner.md
│ │ │ │ ├── coze.md
│ │ │ │ ├── dashscope.md
│ │ │ │ ├── deerflow.md
│ │ │ │ └── dify.md
│ │ │ ├── agent-runners.md
│ │ │ ├── aihubmix.md
│ │ │ ├── coze.md
│ │ │ ├── dashscope.md
│ │ │ ├── dify.md
│ │ │ ├── llm.md
│ │ │ ├── newapi.md
│ │ │ ├── ppio.md
│ │ │ ├── provider-lmstudio.md
│ │ │ ├── provider-ollama.md
│ │ │ ├── siliconflow.md
│ │ │ ├── start.md
│ │ │ └── tokenpony.md
│ │ ├── use/
│ │ │ ├── agent-runner.md
│ │ │ ├── astrbot-agent-sandbox.md
│ │ │ ├── astrbot-sandbox.md
│ │ │ ├── code-interpreter.md
│ │ │ ├── command.md
│ │ │ ├── context-compress.md
│ │ │ ├── custom-rules.md
│ │ │ ├── function-calling.md
│ │ │ ├── knowledge-base.md
│ │ │ ├── mcp.md
│ │ │ ├── plugin.md
│ │ │ ├── proactive-agent.md
│ │ │ ├── skills.md
│ │ │ ├── subagent.md
│ │ │ ├── unified-webhook.md
│ │ │ ├── websearch.md
│ │ │ └── webui.md
│ │ └── what-is-astrbot.md
│ ├── package.json
│ ├── public/
│ │ ├── openapi.json
│ │ └── scalar.html
│ ├── scripts/
│ │ ├── sync_docs_to_wiki.py
│ │ ├── upload-doc-images-to-r2.sh
│ │ ├── upload_doc_images_to_r2.py
│ │ └── usage.md
│ ├── tests/
│ │ └── test_sync_docs_to_wiki.py
│ ├── vercel.json
│ └── zh/
│ ├── community.md
│ ├── deploy/
│ │ ├── astrbot/
│ │ │ ├── 1panel.md
│ │ │ ├── btpanel.md
│ │ │ ├── casaos.md
│ │ │ ├── cli.md
│ │ │ ├── community-deployment.md
│ │ │ ├── compshare.md
│ │ │ ├── desktop.md
│ │ │ ├── docker.md
│ │ │ ├── kubernetes.md
│ │ │ ├── launcher.md
│ │ │ ├── other-deployments.md
│ │ │ ├── package.md
│ │ │ ├── rainyun.md
│ │ │ └── sys-pm.md
│ │ └── when-deployed.md
│ ├── dev/
│ │ ├── astrbot-config.md
│ │ ├── openapi.md
│ │ ├── plugin-platform-adapter.md
│ │ ├── plugin.md
│ │ └── star/
│ │ ├── guides/
│ │ │ ├── ai.md
│ │ │ ├── env.md
│ │ │ ├── html-to-pic.md
│ │ │ ├── listen-message-event.md
│ │ │ ├── other.md
│ │ │ ├── plugin-config.md
│ │ │ ├── send-message.md
│ │ │ ├── session-control.md
│ │ │ ├── simple.md
│ │ │ └── storage.md
│ │ ├── plugin-new.md
│ │ ├── plugin-publish.md
│ │ └── plugin.md
│ ├── faq.md
│ ├── index.md
│ ├── ospp/
│ │ └── 2025.md
│ ├── others/
│ │ ├── github-proxy.md
│ │ ├── ipv6.md
│ │ └── self-host-t2i.md
│ ├── platform/
│ │ ├── aiocqhttp.md
│ │ ├── dingtalk.md
│ │ ├── discord.md
│ │ ├── kook.md
│ │ ├── lark.md
│ │ ├── line.md
│ │ ├── matrix.md
│ │ ├── misskey.md
│ │ ├── qqofficial/
│ │ │ ├── webhook.md
│ │ │ └── websockets.md
│ │ ├── qqofficial.md
│ │ ├── satori/
│ │ │ ├── guide.md
│ │ │ └── server-satori.md
│ │ ├── slack.md
│ │ ├── start.md
│ │ ├── telegram.md
│ │ ├── vocechat.md
│ │ ├── wecom.md
│ │ ├── wecom_ai_bot.md
│ │ └── weixin-official-account.md
│ ├── providers/
│ │ ├── 302ai.md
│ │ ├── agent-runners/
│ │ │ ├── astrbot-agent-runner.md
│ │ │ ├── coze.md
│ │ │ ├── dashscope.md
│ │ │ ├── deerflow.md
│ │ │ └── dify.md
│ │ ├── agent-runners.md
│ │ ├── aihubmix.md
│ │ ├── coze.md
│ │ ├── dashscope.md
│ │ ├── dify.md
│ │ ├── llm.md
│ │ ├── newapi.md
│ │ ├── ppio.md
│ │ ├── provider-lmstudio.md
│ │ ├── provider-ollama.md
│ │ ├── siliconflow.md
│ │ ├── start.md
│ │ └── tokenpony.md
│ ├── use/
│ │ ├── agent-runner.md
│ │ ├── astrbot-agent-sandbox.md
│ │ ├── code-interpreter.md
│ │ ├── command.md
│ │ ├── context-compress.md
│ │ ├── custom-rules.md
│ │ ├── function-calling.md
│ │ ├── knowledge-base-old.md
│ │ ├── knowledge-base.md
│ │ ├── mcp.md
│ │ ├── plugin.md
│ │ ├── proactive-agent.md
│ │ ├── skills.md
│ │ ├── subagent.md
│ │ ├── unified-webhook.md
│ │ ├── websearch.md
│ │ └── webui.md
│ └── what-is-astrbot.md
├── k8s/
│ ├── astrbot/
│ │ ├── 00-namespace.yaml
│ │ ├── 01-pvc.yaml
│ │ ├── 02-deployment.yaml
│ │ ├── 03-service-nodeport.yaml
│ │ └── 04-service-loadbalancer.yaml
│ └── astrbot_with_napcat/
│ ├── 00-namespace.yaml
│ ├── 01-pvc.yaml
│ ├── 02-deployment.yaml
│ ├── 03-service-nodeport.yaml
│ └── 04-service-loadbalancer.yaml
├── main.py
├── openapi.json
├── openspec/
│ └── config.yaml
├── pyproject.toml
├── requirements.txt
├── runtime_bootstrap.py
├── scripts/
│ ├── astrbot.service
│ ├── hatch_build.py
│ ├── pr_test_env.sh
│ └── start-with-neo.sh
├── tests/
│ ├── agent/
│ │ ├── test_context_manager.py
│ │ ├── test_token_counter.py
│ │ └── test_truncator.py
│ ├── conftest.py
│ ├── fixtures/
│ │ ├── __init__.py
│ │ ├── configs/
│ │ │ └── test_cmd_config.json
│ │ ├── helpers.py
│ │ ├── messages/
│ │ │ └── test_messages.json
│ │ ├── mocks/
│ │ │ ├── __init__.py
│ │ │ ├── aiocqhttp.py
│ │ │ ├── discord.py
│ │ │ └── telegram.py
│ │ └── plugins/
│ │ ├── fixture_plugin.py
│ │ └── metadata.yaml
│ ├── test_anthropic_kimi_code_provider.py
│ ├── test_api_key_open_api.py
│ ├── test_backup.py
│ ├── test_chat_route.py
│ ├── test_computer_config.py
│ ├── test_computer_skill_sync.py
│ ├── test_dashboard.py
│ ├── test_kb_import.py
│ ├── test_kook/
│ │ ├── .gitignore
│ │ ├── data/
│ │ │ ├── kook_card_data.json
│ │ │ ├── kook_ws_event_group_message.json
│ │ │ ├── kook_ws_event_hello.json
│ │ │ ├── kook_ws_event_message_with_card_1.json
│ │ │ ├── kook_ws_event_message_with_card_2.json
│ │ │ ├── kook_ws_event_ping.json
│ │ │ ├── kook_ws_event_pong.json
│ │ │ ├── kook_ws_event_private_message.json
│ │ │ ├── kook_ws_event_private_system_message.json
│ │ │ ├── kook_ws_event_reconnect_err.json
│ │ │ ├── kook_ws_event_resume.json
│ │ │ └── kook_ws_event_resume_ack.json
│ │ ├── shared.py
│ │ ├── test_kook_event.py
│ │ └── test_kook_types.py
│ ├── test_local_shell_component.py
│ ├── test_main.py
│ ├── test_neo_skill_sync.py
│ ├── test_neo_skill_tools.py
│ ├── test_openai_source.py
│ ├── test_pip_helper_modules.py
│ ├── test_pip_installer.py
│ ├── test_plugin_manager.py
│ ├── test_profile_aware_tools.py
│ ├── test_quoted_message_parser.py
│ ├── test_runtime_env.py
│ ├── test_security_fixes.py
│ ├── test_skill_manager_sandbox_cache.py
│ ├── test_skill_metadata_enrichment.py
│ ├── test_smoke.py
│ ├── test_temp_dir_cleaner.py
│ ├── test_tool_loop_agent_runner.py
│ └── unit/
│ ├── test_aiocqhttp_poke.py
│ ├── test_astr_agent_tool_exec.py
│ ├── test_astr_main_agent.py
│ ├── test_astr_message_event.py
│ ├── test_astrbot_message.py
│ ├── test_computer.py
│ ├── test_config.py
│ ├── test_core_lifecycle.py
│ ├── test_cron_manager.py
│ ├── test_cron_tools.py
│ ├── test_event_bus.py
│ ├── test_python_tools.py
│ ├── test_session_lock.py
│ ├── test_star_base.py
│ └── test_subagent_orchestrator.py
└── typings/
└── faiss/
└── __init__.pyi
Showing preview only (496K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (5411 symbols across 463 files)
FILE: astrbot/builtin_stars/astrbot/long_term_memory.py
class LongTermMemory (line 19) | class LongTermMemory:
method __init__ (line 20) | def __init__(self, acm: AstrBotConfigManager, context: star.Context) -...
method cfg (line 26) | def cfg(self, event: AstrMessageEvent):
method remove_session (line 59) | async def remove_session(self, event: AstrMessageEvent) -> int:
method get_image_caption (line 66) | async def get_image_caption(
method need_active_reply (line 88) | async def need_active_reply(self, event: AstrMessageEvent) -> bool:
method handle_message (line 114) | async def handle_message(self, event: AstrMessageEvent) -> None:
method on_req_llm (line 151) | async def on_req_llm(self, event: AstrMessageEvent, req: ProviderReque...
method after_req_llm (line 174) | async def after_req_llm(
FILE: astrbot/builtin_stars/astrbot/main.py
class Main (line 12) | class Main(star.Star):
method __init__ (line 13) | def __init__(self, context: star.Context) -> None:
method ltm_enabled (line 21) | def ltm_enabled(self, event: AstrMessageEvent):
method on_message (line 28) | async def on_message(self, event: AstrMessageEvent):
method decorate_llm_req (line 88) | async def decorate_llm_req(
method record_llm_resp_to_ltm (line 99) | async def record_llm_resp_to_ltm(
method after_message_sent (line 110) | async def after_message_sent(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/admin.py
class AdminCommands (line 7) | class AdminCommands:
method __init__ (line 8) | def __init__(self, context: star.Context) -> None:
method op (line 11) | async def op(self, event: AstrMessageEvent, admin_id: str = "") -> None:
method deop (line 24) | async def deop(self, event: AstrMessageEvent, admin_id: str = "") -> N...
method wl (line 42) | async def wl(self, event: AstrMessageEvent, sid: str = "") -> None:
method dwl (line 56) | async def dwl(self, event: AstrMessageEvent, sid: str = "") -> None:
method update_dashboard (line 73) | async def update_dashboard(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/alter_cmd.py
class AlterCmdCommands (line 13) | class AlterCmdCommands(CommandParserMixin):
method __init__ (line 14) | def __init__(self, context: star.Context) -> None:
method update_reset_permission (line 17) | async def update_reset_permission(self, scene_key: str, perm_type: str...
method alter_cmd (line 29) | async def alter_cmd(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/conversation.py
class ConversationCommands (line 24) | class ConversationCommands:
method __init__ (line 25) | def __init__(self, context: star.Context) -> None:
method _get_current_persona_id (line 28) | async def _get_current_persona_id(self, session_id):
method reset (line 42) | async def reset(self, message: AstrMessageEvent) -> None:
method stop (line 110) | async def stop(self, message: AstrMessageEvent) -> None:
method his (line 134) | async def his(self, message: AstrMessageEvent, page: int = 1) -> None:
method convs (line 177) | async def convs(self, message: AstrMessageEvent, page: int = 1) -> None:
method new_conv (line 269) | async def new_conv(self, message: AstrMessageEvent) -> None:
method groupnew_conv (line 297) | async def groupnew_conv(self, message: AstrMessageEvent, sid: str = ""...
method switch_conv (line 324) | async def switch_conv(
method rename_conv (line 363) | async def rename_conv(self, message: AstrMessageEvent, new_name: str =...
method del_conv (line 374) | async def del_conv(self, message: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/help.py
class HelpCommand (line 10) | class HelpCommand:
method __init__ (line 11) | def __init__(self, context: star.Context) -> None:
method _query_astrbot_notice (line 14) | async def _query_astrbot_notice(self):
method _build_reserved_command_lines (line 25) | async def _build_reserved_command_lines(self) -> list[str]:
method help (line 65) | async def help(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/llm.py
class LLMCommands (line 5) | class LLMCommands:
method __init__ (line 6) | def __init__(self, context: star.Context) -> None:
method llm (line 9) | async def llm(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/persona.py
class PersonaCommands (line 11) | class PersonaCommands:
method __init__ (line 12) | def __init__(self, context: star.Context) -> None:
method _build_tree_output (line 15) | def _build_tree_output(
method persona (line 53) | async def persona(self, message: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/plugin.py
class PluginCommands (line 10) | class PluginCommands:
method __init__ (line 11) | def __init__(self, context: star.Context) -> None:
method plugin_ls (line 14) | async def plugin_ls(self, event: AstrMessageEvent) -> None:
method plugin_off (line 33) | async def plugin_off(self, event: AstrMessageEvent, plugin_name: str =...
method plugin_on (line 46) | async def plugin_on(self, event: AstrMessageEvent, plugin_name: str = ...
method plugin_get (line 59) | async def plugin_get(self, event: AstrMessageEvent, plugin_repo: str =...
method plugin_help (line 80) | async def plugin_help(self, event: AstrMessageEvent, plugin_name: str ...
FILE: astrbot/builtin_stars/builtin_commands/commands/provider.py
class _ModelLookupConfig (line 28) | class _ModelLookupConfig:
class _ModelCache (line 34) | class _ModelCache:
method __init__ (line 35) | def __init__(self) -> None:
method get (line 38) | def get(self, provider_id: str, umo: str | None, ttl: float) -> list[s...
method set (line 50) | def set(
method _evict_if_needed (line 58) | def _evict_if_needed(self) -> None:
method invalidate (line 69) | def invalidate(
class ProviderCommands (line 85) | class ProviderCommands:
method __init__ (line 86) | def __init__(self, context: star.Context) -> None:
method _register_provider_change_hook (line 91) | def _register_provider_change_hook(self) -> None:
method invalidate_provider_models_cache (line 108) | def invalidate_provider_models_cache(
method _on_provider_manager_changed (line 114) | def _on_provider_manager_changed(
method _get_provider_settings (line 123) | def _get_provider_settings(self, umo: str | None) -> dict:
method _get_model_cache_ttl (line 135) | def _get_model_cache_ttl(self, umo: str | None) -> float:
method _get_model_lookup_concurrency (line 152) | def _get_model_lookup_concurrency(self, umo: str | None) -> int:
method _get_model_lookup_config (line 170) | def _get_model_lookup_config(self, umo: str | None) -> _ModelLookupCon...
method _resolve_model_name (line 177) | def _resolve_model_name(
method _apply_model (line 207) | def _apply_model(
method _get_provider_models (line 214) | async def _get_provider_models(
method _get_models_or_reply_error (line 234) | async def _get_models_or_reply_error(
method _log_reachability_failure (line 261) | def _log_reachability_failure(
method _test_provider_capability (line 278) | async def _test_provider_capability(self, provider):
method _find_provider_for_model (line 294) | async def _find_provider_for_model(
method provider (line 378) | async def provider(
method _switch_model_by_name (line 560) | async def _switch_model_by_name(
method model_ls (line 627) | async def model_ls(
method key (line 696) | async def key(self, message: AstrMessageEvent, index: int | None = Non...
FILE: astrbot/builtin_stars/builtin_commands/commands/setunset.py
class SetUnsetCommands (line 5) | class SetUnsetCommands:
method __init__ (line 6) | def __init__(self, context: star.Context) -> None:
method set_variable (line 9) | async def set_variable(self, event: AstrMessageEvent, key: str, value:...
method unset_variable (line 22) | async def unset_variable(self, event: AstrMessageEvent, key: str) -> N...
FILE: astrbot/builtin_stars/builtin_commands/commands/sid.py
class SIDCommand (line 7) | class SIDCommand:
method __init__ (line 10) | def __init__(self, context: star.Context) -> None:
method sid (line 13) | async def sid(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/t2i.py
class T2ICommand (line 7) | class T2ICommand:
method __init__ (line 10) | def __init__(self, context: star.Context) -> None:
method t2i (line 13) | async def t2i(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/tts.py
class TTSCommand (line 8) | class TTSCommand:
method __init__ (line 11) | def __init__(self, context: star.Context) -> None:
method tts (line 14) | async def tts(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/builtin_commands/commands/utils/rst_scene.py
class RstScene (line 4) | class RstScene(Enum):
method key (line 10) | def key(self) -> str:
method name (line 14) | def name(self) -> str:
method from_index (line 18) | def from_index(cls, index: int) -> "RstScene":
method get_scene (line 23) | def get_scene(cls, is_group: bool, is_unique_session: bool) -> "RstSce...
FILE: astrbot/builtin_stars/builtin_commands/main.py
class Main (line 20) | class Main(star.Star):
method __init__ (line 21) | def __init__(self, context: star.Context) -> None:
method help (line 38) | async def help(self, event: AstrMessageEvent) -> None:
method llm (line 44) | async def llm(self, event: AstrMessageEvent) -> None:
method plugin (line 49) | def plugin(self) -> None:
method plugin_ls (line 53) | async def plugin_ls(self, event: AstrMessageEvent) -> None:
method plugin_off (line 59) | async def plugin_off(self, event: AstrMessageEvent, plugin_name: str =...
method plugin_on (line 65) | async def plugin_on(self, event: AstrMessageEvent, plugin_name: str = ...
method plugin_get (line 71) | async def plugin_get(self, event: AstrMessageEvent, plugin_repo: str =...
method plugin_help (line 76) | async def plugin_help(self, event: AstrMessageEvent, plugin_name: str ...
method t2i (line 81) | async def t2i(self, event: AstrMessageEvent) -> None:
method tts (line 86) | async def tts(self, event: AstrMessageEvent) -> None:
method sid (line 91) | async def sid(self, event: AstrMessageEvent) -> None:
method op (line 97) | async def op(self, event: AstrMessageEvent, admin_id: str = "") -> None:
method deop (line 103) | async def deop(self, event: AstrMessageEvent, admin_id: str) -> None:
method wl (line 109) | async def wl(self, event: AstrMessageEvent, sid: str = "") -> None:
method dwl (line 115) | async def dwl(self, event: AstrMessageEvent, sid: str) -> None:
method provider (line 121) | async def provider(
method reset (line 131) | async def reset(self, message: AstrMessageEvent) -> None:
method stop (line 136) | async def stop(self, message: AstrMessageEvent) -> None:
method model_ls (line 142) | async def model_ls(
method his (line 151) | async def his(self, message: AstrMessageEvent, page: int = 1) -> None:
method convs (line 156) | async def convs(self, message: AstrMessageEvent, page: int = 1) -> None:
method new_conv (line 161) | async def new_conv(self, message: AstrMessageEvent) -> None:
method groupnew_conv (line 167) | async def groupnew_conv(self, message: AstrMessageEvent, sid: str) -> ...
method switch_conv (line 172) | async def switch_conv(
method rename_conv (line 179) | async def rename_conv(self, message: AstrMessageEvent, new_name: str) ...
method del_conv (line 184) | async def del_conv(self, message: AstrMessageEvent) -> None:
method key (line 190) | async def key(self, message: AstrMessageEvent, index: int | None = Non...
method persona (line 196) | async def persona(self, message: AstrMessageEvent) -> None:
method update_dashboard (line 202) | async def update_dashboard(self, event: AstrMessageEvent) -> None:
method set_variable (line 207) | async def set_variable(self, event: AstrMessageEvent, key: str, value:...
method unset_variable (line 211) | async def unset_variable(self, event: AstrMessageEvent, key: str) -> N...
method alter_cmd (line 216) | async def alter_cmd(self, event: AstrMessageEvent) -> None:
FILE: astrbot/builtin_stars/session_controller/main.py
class Main (line 17) | class Main(Star):
method __init__ (line 20) | def __init__(self, context: Context) -> None:
method handle_session_control_agent (line 24) | async def handle_session_control_agent(self, event: AstrMessageEvent) ...
method handle_empty_mention (line 33) | async def handle_empty_mention(self, event: AstrMessageEvent):
FILE: astrbot/builtin_stars/web_searcher/engines/__init__.py
class SearchResult (line 31) | class SearchResult:
method __str__ (line 37) | def __str__(self) -> str:
class SearchEngine (line 41) | class SearchEngine:
method __init__ (line 44) | def __init__(self) -> None:
method _set_selector (line 49) | def _set_selector(self, selector: str) -> str:
method _get_next_page (line 52) | async def _get_next_page(self, query: str) -> str:
method _get_html (line 55) | async def _get_html(self, url: str, data: dict | None = None) -> str:
method tidy_text (line 83) | def tidy_text(self, text: str) -> str:
method _get_url (line 87) | def _get_url(self, tag: Tag) -> str:
method search (line 90) | async def search(self, query: str, num_results: int) -> list[SearchRes...
FILE: astrbot/builtin_stars/web_searcher/engines/bing.py
class Bing (line 4) | class Bing(SearchEngine):
method __init__ (line 5) | def __init__(self) -> None:
method _set_selector (line 10) | def _set_selector(self, selector: str):
method _get_next_page (line 20) | async def _get_next_page(self, query) -> str:
FILE: astrbot/builtin_stars/web_searcher/engines/sogo.py
class Sogo (line 10) | class Sogo(SearchEngine):
method __init__ (line 11) | def __init__(self) -> None:
method _set_selector (line 16) | def _set_selector(self, selector: str):
method _get_next_page (line 26) | async def _get_next_page(self, query) -> str:
method _get_url (line 30) | def _get_url(self, tag: Tag) -> str:
method search (line 33) | async def search(self, query: str, num_results: int) -> list[SearchRes...
method _parse_url (line 41) | async def _parse_url(self, url) -> str:
FILE: astrbot/builtin_stars/web_searcher/main.py
class Main (line 20) | class Main(star.Star):
method __init__ (line 29) | def __init__(self, context: star.Context) -> None:
method _tidy_text (line 64) | async def _tidy_text(self, text: str) -> str:
method _get_from_url (line 68) | async def _get_from_url(self, url: str) -> str:
method _process_search_result (line 81) | async def _process_search_result(
method _web_search_default (line 104) | async def _web_search_default(
method _get_tavily_key (line 126) | async def _get_tavily_key(self, cfg: AstrBotConfig) -> str:
method _web_search_tavily (line 137) | async def _web_search_tavily(
method _extract_tavily (line 172) | async def _extract_tavily(self, cfg: AstrBotConfig, payload: dict) -> ...
method search_from_search_engine (line 200) | async def search_from_search_engine(
method ensure_baidu_ai_search_mcp (line 238) | async def ensure_baidu_ai_search_mcp(self, umo: str | None = None) -> ...
method fetch_website_content (line 264) | async def fetch_website_content(self, event: AstrMessageEvent, url: st...
method search_from_tavily (line 275) | async def search_from_tavily(
method tavily_extract_web_page (line 351) | async def tavily_extract_web_page(
method _get_bocha_key (line 386) | async def _get_bocha_key(self, cfg: AstrBotConfig) -> str:
method _web_search_bocha (line 397) | async def _web_search_bocha(
method search_from_bocha (line 434) | async def search_from_bocha(
method edit_web_search_tools (line 541) | async def edit_web_search_tools(
FILE: astrbot/cli/__main__.py
function cli (line 22) | def cli() -> None:
function help (line 31) | def help(command_name: str | None) -> None:
FILE: astrbot/cli/commands/cmd_conf.py
function _validate_log_level (line 12) | def _validate_log_level(value: str) -> str:
function _validate_dashboard_port (line 22) | def _validate_dashboard_port(value: str) -> int:
function _validate_dashboard_username (line 33) | def _validate_dashboard_username(value: str) -> str:
function _validate_dashboard_password (line 40) | def _validate_dashboard_password(value: str) -> str:
function _validate_timezone (line 47) | def _validate_timezone(value: str) -> str:
function _validate_callback_api_base (line 58) | def _validate_callback_api_base(value: str) -> str:
function _load_config (line 78) | def _load_config() -> dict[str, Any]:
function _save_config (line 101) | def _save_config(config: dict[str, Any]) -> None:
function _set_nested_item (line 111) | def _set_nested_item(obj: dict[str, Any], path: str, value: Any) -> None:
function _get_nested_item (line 125) | def _get_nested_item(obj: dict[str, Any], path: str) -> Any:
function conf (line 134) | def conf() -> None:
function set_config (line 156) | def set_config(key: str, value: str) -> None:
function get_config (line 185) | def get_config(key: str | None = None) -> None:
FILE: astrbot/cli/commands/cmd_init.py
function initialize_astrbot (line 10) | async def initialize_astrbot(astrbot_root: Path) -> None:
function init (line 38) | def init() -> None:
FILE: astrbot/cli/commands/cmd_plug.py
function plug (line 18) | def plug() -> None:
function _get_data_path (line 22) | def _get_data_path() -> Path:
function display_plugins (line 31) | def display_plugins(plugins, title=None, color=None) -> None:
function new (line 50) | def new(name: str) -> None:
function list (line 107) | def list(all: bool) -> None:
function install (line 148) | def install(name: str, proxy: str | None) -> None:
function remove (line 171) | def remove(name: str) -> None:
function update (line 196) | def update(name: str, proxy: str | None) -> None:
function search (line 236) | def search(query: str) -> None:
FILE: astrbot/cli/commands/cmd_run.py
function run_astrbot (line 13) | async def run_astrbot(astrbot_root: Path) -> None:
function run (line 32) | def run(reload: bool, port: str) -> None:
FILE: astrbot/cli/utils/basic.py
function check_astrbot_root (line 9) | def check_astrbot_root(path: str | Path) -> bool:
function get_astrbot_root (line 20) | def get_astrbot_root() -> Path:
function check_dashboard (line 25) | async def check_dashboard(astrbot_root: Path) -> None:
FILE: astrbot/cli/utils/plugin.py
class PluginStatus (line 15) | class PluginStatus(str, Enum):
function get_git_repo (line 22) | def get_git_repo(url: str, target_path: Path, proxy: str | None = None) ...
function load_yaml_metadata (line 86) | def load_yaml_metadata(plugin_dir: Path) -> dict:
function build_plug_list (line 105) | def build_plug_list(plugins_dir: Path) -> list:
function manage_plugin (line 193) | def manage_plugin(
FILE: astrbot/cli/utils/version_comparator.py
class VersionComparator (line 6) | class VersionComparator:
method compare_version (line 8) | def compare_version(v1: str, v2: str) -> int:
method _split_prerelease (line 80) | def _split_prerelease(prerelease):
FILE: astrbot/core/agent/agent.py
class Agent (line 10) | class Agent(Generic[TContext]):
FILE: astrbot/core/agent/context/compressor.py
class ContextCompressor (line 22) | class ContextCompressor(Protocol):
method should_compress (line 28) | def should_compress(
method __call__ (line 43) | async def __call__(self, messages: list[Message]) -> list[Message]:
class TruncateByTurnsCompressor (line 55) | class TruncateByTurnsCompressor:
method __init__ (line 60) | def __init__(
method should_compress (line 72) | def should_compress(
method __call__ (line 90) | async def __call__(self, messages: list[Message]) -> list[Message]:
function split_history (line 99) | def split_history(
class LLMSummaryCompressor (line 146) | class LLMSummaryCompressor:
method __init__ (line 151) | def __init__(
method should_compress (line 178) | def should_compress(
method __call__ (line 196) | async def __call__(self, messages: list[Message]) -> list[Message]:
FILE: astrbot/core/agent/context/config.py
class ContextConfig (line 12) | class ContextConfig:
FILE: astrbot/core/agent/context/manager.py
class ContextManager (line 10) | class ContextManager:
method __init__ (line 13) | def __init__(
method process (line 44) | async def process(
method _run_compression (line 82) | async def _run_compression(
FILE: astrbot/core/agent/context/token_counter.py
class TokenCounter (line 8) | class TokenCounter(Protocol):
method count_tokens (line 14) | def count_tokens(
class EstimateTokenCounter (line 38) | class EstimateTokenCounter:
method count_tokens (line 46) | def count_tokens(
method _estimate_tokens (line 75) | def _estimate_tokens(self, text: str) -> int:
FILE: astrbot/core/agent/context/truncator.py
class ContextTruncator (line 4) | class ContextTruncator:
method _has_tool_calls (line 7) | def _has_tool_calls(self, message: Message) -> bool:
method _split_system_rest (line 16) | def _split_system_rest(
method _ensure_user_message (line 32) | def _ensure_user_message(
method fix_messages (line 51) | def fix_messages(self, messages: list[Message]) -> list[Message]:
method truncate_by_turns (line 100) | def truncate_by_turns(
method truncate_by_dropping_oldest_turns (line 146) | def truncate_by_dropping_oldest_turns(
method truncate_by_halving (line 175) | def truncate_by_halving(
FILE: astrbot/core/agent/handoff.py
class HandoffTool (line 8) | class HandoffTool(FunctionTool, Generic[TContext]):
method __init__ (line 11) | def __init__(
method default_parameters (line 39) | def default_parameters(self) -> dict:
method default_description (line 63) | def default_description(self, agent_name: str | None) -> str:
FILE: astrbot/core/agent/hooks.py
class BaseAgentRunHooks (line 11) | class BaseAgentRunHooks(Generic[TContext]):
method on_agent_begin (line 12) | async def on_agent_begin(self, run_context: ContextWrapper[TContext]) ...
method on_tool_start (line 13) | async def on_tool_start(
method on_tool_end (line 19) | async def on_tool_end(
method on_agent_done (line 26) | async def on_agent_done(
FILE: astrbot/core/agent/mcp_client.py
function _prepare_config (line 39) | def _prepare_config(config: dict) -> dict:
function _quick_test_mcp_connection (line 48) | async def _quick_test_mcp_connection(config: dict) -> tuple[bool, str]:
class MCPClient (line 110) | class MCPClient:
method __init__ (line 111) | def __init__(self) -> None:
method connect_to_server (line 129) | async def connect_to_server(self, mcp_server_config: dict, name: str) ...
method list_tools_and_save (line 252) | async def list_tools_and_save(self) -> mcp.ListToolsResult:
method _reconnect (line 260) | async def _reconnect(self) -> None:
method call_tool_with_reconnect (line 310) | async def call_tool_with_reconnect(
method cleanup (line 359) | async def cleanup(self) -> None:
class MCPTool (line 376) | class MCPTool(FunctionTool, Generic[TContext]):
method __init__ (line 379) | def __init__(
method call (line 391) | async def call(
FILE: astrbot/core/agent/message.py
class ContentPart (line 16) | class ContentPart(BaseModel):
method __init_subclass__ (line 23) | def __init_subclass__(cls, **kwargs: Any) -> None:
method __get_pydantic_core_schema__ (line 35) | def __get_pydantic_core_schema__(
class TextPart (line 62) | class TextPart(ContentPart):
class ThinkPart (line 72) | class ThinkPart(ContentPart):
method merge_in_place (line 83) | def merge_in_place(self, other: Any) -> bool:
class ImageURLPart (line 94) | class ImageURLPart(ContentPart):
class ImageURL (line 100) | class ImageURL(BaseModel):
class AudioURLPart (line 110) | class AudioURLPart(ContentPart):
class AudioURL (line 116) | class AudioURL(BaseModel):
class ToolCall (line 126) | class ToolCall(BaseModel):
class FunctionBody (line 140) | class FunctionBody(BaseModel):
method serialize (line 154) | def serialize(self, handler):
class ToolCallPart (line 161) | class ToolCallPart(BaseModel):
class Message (line 168) | class Message(BaseModel):
method check_content_required (line 190) | def check_content_required(self):
method serialize (line 203) | def serialize(self, handler):
class AssistantMessageSegment (line 212) | class AssistantMessageSegment(Message):
class ToolCallMessageSegment (line 218) | class ToolCallMessageSegment(Message):
class UserMessageSegment (line 224) | class UserMessageSegment(Message):
class SystemMessageSegment (line 230) | class SystemMessageSegment(Message):
FILE: astrbot/core/agent/response.py
class AgentResponseData (line 8) | class AgentResponseData(T.TypedDict):
class AgentResponse (line 13) | class AgentResponse:
class AgentStats (line 19) | class AgentStats:
method duration (line 26) | def duration(self) -> float:
method to_dict (line 29) | def to_dict(self) -> dict:
FILE: astrbot/core/agent/run_context.py
class ContextWrapper (line 13) | class ContextWrapper(Generic[TContext]):
FILE: astrbot/core/agent/runners/base.py
class AgentState (line 13) | class AgentState(Enum):
class BaseAgentRunner (line 22) | class BaseAgentRunner(T.Generic[TContext]):
method reset (line 24) | async def reset(
method step (line 36) | async def step(self) -> T.AsyncGenerator[AgentResponse, None]:
method step_until_done (line 41) | async def step_until_done(
method done (line 48) | def done(self) -> bool:
method get_final_llm_resp (line 55) | def get_final_llm_resp(self) -> LLMResponse | None:
method _transition_state (line 61) | def _transition_state(self, new_state: AgentState) -> None:
FILE: astrbot/core/agent/runners/coze/coze_agent_runner.py
class CozeAgentRunner (line 27) | class CozeAgentRunner(BaseAgentRunner[TContext]):
method reset (line 31) | async def reset(
method step (line 73) | async def step(self):
method step_until_done (line 109) | async def step_until_done(
method _execute_coze_request (line 116) | async def _execute_coze_request(self):
method _download_and_upload_image (line 326) | async def _download_and_upload_image(
method done (line 361) | def done(self) -> bool:
method get_final_llm_resp (line 366) | def get_final_llm_resp(self) -> LLMResponse | None:
FILE: astrbot/core/agent/runners/coze/coze_api_client.py
class CozeAPIClient (line 12) | class CozeAPIClient:
method __init__ (line 13) | def __init__(self, api_key: str, api_base: str = "https://api.coze.cn"...
method _ensure_session (line 18) | async def _ensure_session(self):
method upload_file (line 44) | async def upload_file(
method download_image (line 100) | async def download_image(self, image_url: str) -> bytes:
method chat_messages (line 123) | async def chat_messages(
method clear_context (line 211) | async def clear_context(self, conversation_id: str):
method get_message_list (line 244) | async def get_message_list(
method close (line 280) | async def close(self) -> None:
function test_coze_api_client (line 291) | async def test_coze_api_client() -> None:
FILE: astrbot/core/agent/runners/dashscope/dashscope_agent_runner.py
class DashscopeAgentRunner (line 31) | class DashscopeAgentRunner(BaseAgentRunner[TContext]):
method reset (line 35) | async def reset(
method has_rag_options (line 70) | def has_rag_options(self) -> bool:
method step (line 85) | async def step(self):
method step_until_done (line 119) | async def step_until_done(
method _consume_sync_generator (line 126) | def _consume_sync_generator(
method _process_stream_chunk (line 147) | async def _process_stream_chunk(
method _format_doc_references (line 200) | def _format_doc_references(self, doc_references: list) -> str:
method _build_request_payload (line 219) | async def _build_request_payload(
method _handle_streaming_response (line 280) | async def _handle_streaming_response(
method _execute_dashscope_request (line 369) | async def _execute_dashscope_request(self):
method done (line 397) | def done(self) -> bool:
method get_final_llm_resp (line 402) | def get_final_llm_resp(self) -> LLMResponse | None:
FILE: astrbot/core/agent/runners/deerflow/deerflow_agent_runner.py
class DeerFlowAgentRunner (line 49) | class DeerFlowAgentRunner(BaseAgentRunner[TContext]):
class _RunnerConfig (line 55) | class _RunnerConfig:
class _StreamState (line 70) | class _StreamState:
class _FinalResult (line 85) | class _FinalResult:
method _format_exception (line 89) | def _format_exception(self, err: Exception) -> str:
method close (line 111) | async def close(self) -> None:
method _notify_agent_done_hook (line 124) | async def _notify_agent_done_hook(self) -> None:
method _finish_with_result (line 132) | async def _finish_with_result(
method _finish_with_error (line 146) | async def _finish_with_error(self, err_msg: str) -> AgentResponse:
method _parse_runner_config (line 163) | def _parse_runner_config(self, provider_config: dict) -> _RunnerConfig:
method _load_config_and_client (line 212) | async def _load_config_and_client(self, provider_config: dict) -> None:
method reset (line 262) | async def reset(
method step (line 280) | async def step(self):
method step_until_done (line 306) | async def step_until_done(
method _extract_new_messages_from_values (line 323) | def _extract_new_messages_from_values(
method _fingerprint_message (line 354) | def _fingerprint_message(self, message: dict[str, T.Any]) -> str:
method _remember_seen_message_id (line 361) | def _remember_seen_message_id(self, state: _StreamState, msg_id: str) ...
method _ensure_thread_id (line 371) | async def _ensure_thread_id(self, session_id: str) -> str:
method _build_messages (line 396) | def _build_messages(
method _build_runtime_context (line 413) | def _build_runtime_context(self, thread_id: str) -> dict[str, T.Any]:
method _build_payload (line 426) | def _build_payload(
method _update_text_and_maybe_stream (line 446) | def _update_text_and_maybe_stream(
method _handle_values_event (line 488) | def _handle_values_event(
method _handle_message_event (line 539) | def _handle_message_event(
method _build_final_result (line 560) | def _build_final_result(self, state: _StreamState) -> _FinalResult:
method _emit_non_plain_components_at_end (line 605) | def _emit_non_plain_components_at_end(
method _execute_deerflow_request (line 623) | async def _execute_deerflow_request(self):
method done (line 687) | def done(self) -> bool:
method get_final_llm_resp (line 692) | def get_final_llm_resp(self) -> LLMResponse | None:
FILE: astrbot/core/agent/runners/deerflow/deerflow_api_client.py
function _normalize_sse_newlines (line 13) | def _normalize_sse_newlines(text: str) -> str:
function _parse_sse_data_lines (line 18) | def _parse_sse_data_lines(data_lines: list[str]) -> Any:
function _parse_sse_block (line 41) | def _parse_sse_block(block: str) -> dict[str, Any] | None:
function _stream_sse (line 58) | async def _stream_sse(resp: ClientResponse) -> AsyncGenerator[dict[str, ...
class DeerFlowAPIClient (line 98) | class DeerFlowAPIClient:
method __init__ (line 105) | def __init__(
method _get_session (line 124) | def _get_session(self) -> ClientSession:
method __aenter__ (line 131) | async def __aenter__(self) -> "DeerFlowAPIClient":
method __aexit__ (line 134) | async def __aexit__(
method create_thread (line 142) | async def create_thread(self, timeout: float = 20) -> dict[str, Any]:
method stream_run (line 160) | async def stream_run(
method close (line 209) | async def close(self) -> None:
method __del__ (line 233) | def __del__(self) -> None:
method is_closed (line 244) | def is_closed(self) -> bool:
FILE: astrbot/core/agent/runners/deerflow/deerflow_content_mapper.py
function is_likely_base64_image (line 12) | def is_likely_base64_image(value: str) -> bool:
function build_user_content (line 30) | def build_user_content(prompt: str, image_urls: list[str]) -> Any:
function image_component_from_url (line 97) | def image_component_from_url(url: Any) -> Comp.Image | None:
function append_components_from_content (line 130) | def append_components_from_content(
function build_chain_from_ai_content (line 178) | def build_chain_from_ai_content(
FILE: astrbot/core/agent/runners/deerflow/deerflow_stream_utils.py
function extract_text (line 5) | def extract_text(content: T.Any) -> str:
function extract_messages_from_values_data (line 30) | def extract_messages_from_values_data(data: T.Any) -> list[T.Any]:
function is_ai_message (line 47) | def is_ai_message(message: dict[str, T.Any]) -> bool:
function extract_latest_ai_text (line 62) | def extract_latest_ai_text(messages: Iterable[T.Any]) -> str:
function extract_latest_ai_message (line 80) | def extract_latest_ai_message(messages: Iterable[T.Any]) -> dict[str, T....
function is_clarification_tool_message (line 94) | def is_clarification_tool_message(message: dict[str, T.Any]) -> bool:
function extract_latest_clarification_text (line 100) | def extract_latest_clarification_text(messages: Iterable[T.Any]) -> str:
function get_message_id (line 116) | def get_message_id(message: T.Any) -> str:
function extract_event_message_obj (line 123) | def extract_event_message_obj(data: T.Any) -> dict[str, T.Any] | None:
function extract_ai_delta_from_event_data (line 133) | def extract_ai_delta_from_event_data(data: T.Any) -> str:
function extract_clarification_from_event_data (line 145) | def extract_clarification_from_event_data(data: T.Any) -> str:
function _iter_custom_event_items (line 154) | def _iter_custom_event_items(data: T.Any) -> list[dict[str, T.Any]]:
function extract_task_failures_from_custom_event (line 169) | def extract_task_failures_from_custom_event(data: T.Any) -> list[str]:
function build_task_failure_summary (line 189) | def build_task_failure_summary(failures: list[str]) -> str:
FILE: astrbot/core/agent/runners/dify/dify_agent_runner.py
class DifyAgentRunner (line 28) | class DifyAgentRunner(BaseAgentRunner[TContext]):
method reset (line 32) | async def reset(
method step (line 66) | async def step(self):
method step_until_done (line 102) | async def step_until_done(
method _execute_dify_request (line 109) | async def _execute_dify_request(self):
method parse_dify_result (line 282) | async def parse_dify_result(self, chunk: dict | str) -> MessageChain:
method done (line 330) | def done(self) -> bool:
method get_final_llm_resp (line 335) | def get_final_llm_resp(self) -> LLMResponse | None:
FILE: astrbot/core/agent/runners/dify/dify_api_client.py
function _stream_sse (line 11) | async def _stream_sse(resp: ClientResponse) -> AsyncGenerator[dict, None]:
class DifyAPIClient (line 33) | class DifyAPIClient:
method __init__ (line 34) | def __init__(self, api_key: str, api_base: str = "https://api.dify.ai/...
method chat_messages (line 42) | async def chat_messages(
method workflow_run (line 73) | async def workflow_run(
method file_upload (line 102) | async def file_upload(
method close (line 158) | async def close(self) -> None:
method get_chat_convs (line 161) | async def get_chat_convs(self, user: str, limit: int = 20):
method delete_chat_conv (line 171) | async def delete_chat_conv(self, user: str, conversation_id: str):
method rename (line 180) | async def rename(
FILE: astrbot/core/agent/runners/tool_loop_agent_runner.py
class _HandleFunctionToolsResult (line 54) | class _HandleFunctionToolsResult:
method from_message_chain (line 61) | def from_message_chain(cls, chain: MessageChain) -> "_HandleFunctionTo...
method from_tool_call_result_blocks (line 65) | def from_tool_call_result_blocks(
method from_cached_image (line 71) | def from_cached_image(cls, image: T.Any) -> "_HandleFunctionToolsResult":
class FollowUpTicket (line 76) | class FollowUpTicket:
class ToolLoopAgentRunner (line 83) | class ToolLoopAgentRunner(BaseAgentRunner[TContext]):
method _get_persona_custom_error_message (line 84) | def _get_persona_custom_error_message(self) -> str | None:
method reset (line 90) | async def reset(
method _iter_llm_responses (line 202) | async def _iter_llm_responses(
method _iter_llm_responses_with_fallback (line 222) | async def _iter_llm_responses_with_fallback(
method _simple_print_message_role (line 293) | def _simple_print_message_role(self, tag: str = ""):
method follow_up (line 299) | def follow_up(
method _resolve_unconsumed_follow_ups (line 315) | def _resolve_unconsumed_follow_ups(self) -> None:
method _consume_follow_up_notice (line 323) | def _consume_follow_up_notice(self) -> str:
method _merge_follow_up_notice (line 342) | def _merge_follow_up_notice(self, content: str) -> str:
method step (line 349) | async def step(self):
method step_until_done (line 621) | async def step_until_done(
method _handle_function_tools (line 650) | async def _handle_function_tools(
method _build_tool_requery_context (line 889) | def _build_tool_requery_context(
method _build_tool_subset (line 912) | def _build_tool_subset(self, tool_set: ToolSet, tool_names: list[str])...
method _resolve_tool_exec (line 921) | async def _resolve_tool_exec(
method done (line 954) | def done(self) -> bool:
method request_stop (line 958) | def request_stop(self) -> None:
method was_aborted (line 961) | def was_aborted(self) -> bool:
method get_final_llm_resp (line 964) | def get_final_llm_resp(self) -> LLMResponse | None:
FILE: astrbot/core/agent/tool.py
class ToolSchema (line 20) | class ToolSchema:
method validate_parameters (line 33) | def validate_parameters(self) -> "ToolSchema":
class FunctionTool (line 41) | class FunctionTool(ToolSchema, Generic[TContext]):
method __repr__ (line 67) | def __repr__(self) -> str:
method call (line 70) | async def call(self, context: ContextWrapper[TContext], **kwargs) -> T...
class ToolSet (line 78) | class ToolSet:
method empty (line 87) | def empty(self) -> bool:
method add_tool (line 91) | def add_tool(self, tool: FunctionTool) -> None:
method remove_tool (line 100) | def remove_tool(self, name: str) -> None:
method get_tool (line 104) | def get_tool(self, name: str) -> FunctionTool | None:
method get_light_tool_set (line 111) | def get_light_tool_set(self) -> "ToolSet":
method get_param_only_tool_set (line 131) | def get_param_only_tool_set(self) -> "ToolSet":
method add_func (line 153) | def add_func(
method remove_func (line 179) | def remove_func(self, name: str) -> None:
method get_func (line 184) | def get_func(self, name: str) -> FunctionTool | None:
method func_list (line 189) | def func_list(self) -> list[FunctionTool]:
method openai_schema (line 193) | def openai_schema(self, omit_empty_parameter_field: bool = False) -> l...
method anthropic_schema (line 210) | def anthropic_schema(self) -> list[dict]:
method google_schema (line 224) | def google_schema(self) -> dict:
method get_func_desc_openai_style (line 316) | def get_func_desc_openai_style(self, omit_empty_parameter_field: bool ...
method get_func_desc_anthropic_style (line 320) | def get_func_desc_anthropic_style(self):
method get_func_desc_google_genai_style (line 324) | def get_func_desc_google_genai_style(self):
method names (line 327) | def names(self) -> list[str]:
method merge (line 331) | def merge(self, other: "ToolSet") -> None:
method __len__ (line 336) | def __len__(self) -> int:
method __bool__ (line 339) | def __bool__(self) -> bool:
method __iter__ (line 342) | def __iter__(self):
method __repr__ (line 345) | def __repr__(self) -> str:
method __str__ (line 348) | def __str__(self) -> str:
FILE: astrbot/core/agent/tool_executor.py
class BaseFunctionToolExecutor (line 10) | class BaseFunctionToolExecutor(Generic[TContext]):
method execute (line 12) | async def execute(
FILE: astrbot/core/agent/tool_image_cache.py
class CachedImage (line 17) | class CachedImage:
class ToolImageCache (line 32) | class ToolImageCache:
method __new__ (line 43) | def __new__(cls) -> "ToolImageCache":
method __init__ (line 49) | def __init__(self) -> None:
method _get_file_extension (line 57) | def _get_file_extension(self, mime_type: str) -> str:
method save_image (line 70) | def save_image(
method get_image_base64_by_path (line 111) | def get_image_base64_by_path(
method cleanup_expired (line 135) | def cleanup_expired(self) -> int:
FILE: astrbot/core/astr_agent_context.py
class AstrAgentContext (line 10) | class AstrAgentContext:
FILE: astrbot/core/astr_agent_hooks.py
class MainAgentHooks (line 14) | class MainAgentHooks(BaseAgentRunHooks[AstrAgentContext]):
method on_agent_done (line 15) | async def on_agent_done(self, run_context, llm_response) -> None:
method on_tool_start (line 29) | async def on_tool_start(
method on_tool_end (line 42) | async def on_tool_end(
class EmptyAgentHooks (line 84) | class EmptyAgentHooks(BaseAgentRunHooks[AstrAgentContext]):
FILE: astrbot/core/astr_agent_run_util.py
function _should_stop_agent (line 26) | def _should_stop_agent(astr_event) -> bool:
function _truncate_tool_result (line 30) | def _truncate_tool_result(text: str, limit: int = 70) -> str:
function _extract_chain_json_data (line 40) | def _extract_chain_json_data(msg_chain: MessageChain) -> dict | None:
function _record_tool_call_name (line 49) | def _record_tool_call_name(
function _build_tool_call_status_message (line 61) | def _build_tool_call_status_message(tool_info: dict | None) -> str:
function _build_tool_result_status_message (line 67) | def _build_tool_result_status_message(
function run_agent (line 90) | async def run_agent(
function _watch_agent_stop_signal (line 271) | async def _watch_agent_stop_signal(agent_runner: AgentRunner, astr_event...
function run_live_agent (line 279) | async def run_live_agent(
function _run_agent_feeder (line 421) | async def _run_agent_feeder(
function _safe_tts_stream_wrapper (line 482) | async def _safe_tts_stream_wrapper(
function _simulated_stream_tts (line 496) | async def _simulated_stream_tts(
FILE: astrbot/core/astr_agent_tool_exec.py
class FunctionToolExecutor (line 46) | class FunctionToolExecutor(BaseFunctionToolExecutor[AstrAgentContext]):
method _collect_image_urls_from_args (line 48) | def _collect_image_urls_from_args(cls, image_urls_raw: T.Any) -> list[...
method _collect_image_urls_from_message (line 67) | async def _collect_image_urls_from_message(
method _collect_handoff_image_urls (line 92) | async def _collect_handoff_image_urls(
method execute (line 121) | async def execute(cls, tool, run_context, **tool_args):
method _get_runtime_computer_tools (line 180) | def _get_runtime_computer_tools(cls, runtime: str) -> dict[str, Functi...
method _build_handoff_toolset (line 196) | def _build_handoff_toolset(
method _execute_handoff (line 239) | async def _execute_handoff(
method _execute_handoff_background (line 313) | async def _execute_handoff_background(
method _do_handoff_background (line 356) | async def _do_handoff_background(
method _execute_background (line 403) | async def _execute_background(
method _wake_main_agent_for_background_result (line 443) | async def _wake_main_agent_for_background_result(
method _execute_local (line 552) | async def _execute_local(
method _execute_mcp (line 636) | async def _execute_mcp(
function call_local_llm_tool (line 648) | async def call_local_llm_tool(
FILE: astrbot/core/astr_main_agent.py
class MainAgentBuildConfig (line 86) | class MainAgentBuildConfig:
class MainAgentBuildResult (line 144) | class MainAgentBuildResult:
function _select_provider (line 151) | def _select_provider(
function _get_session_conv (line 173) | async def _get_session_conv(
function _apply_kb (line 190) | async def _apply_kb(
function _apply_file_extract (line 219) | async def _apply_file_extract(
function _apply_prompt_prefix (line 268) | def _apply_prompt_prefix(req: ProviderRequest, cfg: dict) -> None:
function _apply_local_env_tools (line 278) | def _apply_local_env_tools(req: ProviderRequest) -> None:
function _build_local_mode_prompt (line 286) | def _build_local_mode_prompt() -> str:
function _ensure_persona_and_skills (line 301) | async def _ensure_persona_and_skills(
function _request_img_caption (line 447) | async def _request_img_caption(
function _ensure_img_caption (line 475) | async def _ensure_img_caption(
function _append_quoted_image_attachment (line 497) | def _append_quoted_image_attachment(req: ProviderRequest, image_path: st...
function _get_quoted_message_parser_settings (line 503) | def _get_quoted_message_parser_settings(
function _process_quote_message (line 514) | async def _process_quote_message(
function _append_system_reminders (line 576) | def _append_system_reminders(
function _decorate_llm_request (line 620) | async def _decorate_llm_request(
function _modalities_fix (line 660) | def _modalities_fix(provider: Provider, req: ProviderRequest) -> None:
function _sanitize_context_by_modalities (line 683) | def _sanitize_context_by_modalities(
function _plugin_tool_fix (line 761) | def _plugin_tool_fix(event: AstrMessageEvent, req: ProviderRequest) -> N...
function _handle_webchat (line 790) | async def _handle_webchat(
function _apply_llm_safety_mode (line 834) | def _apply_llm_safety_mode(config: MainAgentBuildConfig, req: ProviderRe...
function _apply_sandbox_tools (line 844) | def _apply_sandbox_tools(
function _proactive_cron_job_tools (line 920) | def _proactive_cron_job_tools(req: ProviderRequest) -> None:
function _get_compress_provider (line 928) | def _get_compress_provider(
function _get_fallback_chat_providers (line 951) | def _get_fallback_chat_providers(
function build_main_agent (line 986) | async def build_main_agent(
FILE: astrbot/core/astr_main_agent_resources.py
class KnowledgeBaseQueryTool (line 151) | class KnowledgeBaseQueryTool(FunctionTool[AstrAgentContext]):
method call (line 172) | async def call(
class SendMessageToUserTool (line 189) | class SendMessageToUserTool(FunctionTool[AstrAgentContext]):
method _resolve_path_from_sandbox (line 240) | async def _resolve_path_from_sandbox(
method call (line 275) | async def call(
function retrieve_knowledge_base (line 399) | async def retrieve_knowledge_base(
FILE: astrbot/core/astrbot_config_mgr.py
class ConfInfo (line 16) | class ConfInfo(TypedDict):
class AstrBotConfigManager (line 31) | class AstrBotConfigManager:
method __init__ (line 34) | def __init__(
method _get_abconf_data (line 48) | def _get_abconf_data(self) -> dict:
method _load_all_configs (line 59) | def _load_all_configs(self) -> None:
method _load_conf_mapping (line 75) | def _load_conf_mapping(self, umo: str | MessageSession) -> ConfInfo:
method _save_conf_mapping (line 103) | def _save_conf_mapping(
method get_conf (line 124) | def get_conf(self, umo: str | MessageSession | None) -> AstrBotConfig:
method default_conf (line 140) | def default_conf(self) -> AstrBotConfig:
method get_conf_info (line 144) | def get_conf_info(self, umo: str | MessageSession) -> ConfInfo:
method get_conf_list (line 151) | def get_conf_list(self) -> list[ConfInfo]:
method create_conf (line 163) | def create_conf(
method delete_conf (line 177) | def delete_conf(self, conf_id: str) -> bool:
method update_conf_info (line 231) | def update_conf_info(self, conf_id: str, name: str | None = None) -> b...
method g (line 265) | def g(
FILE: astrbot/core/backup/constants.py
function get_backup_directories (line 60) | def get_backup_directories() -> dict[str, str]:
FILE: astrbot/core/backup/exporter.py
class AstrBotExporter (line 39) | class AstrBotExporter:
method __init__ (line 57) | def __init__(
method export_all (line 68) | async def export_all(
method _export_main_database (line 206) | async def _export_main_database(self) -> dict[str, list[dict]]:
method _export_kb_metadata (line 227) | async def _export_kb_metadata(self) -> dict[str, list[dict]]:
method _export_kb_documents (line 251) | async def _export_kb_documents(self, kb_helper: Any) -> dict[str, Any]:
method _export_faiss_index (line 272) | async def _export_faiss_index(
method _export_kb_media_files (line 288) | async def _export_kb_media_files(
method _export_directories (line 307) | async def _export_directories(
method _export_attachments (line 358) | async def _export_attachments(
method _model_to_dict (line 374) | def _model_to_dict(self, record: Any) -> dict:
method _add_checksum (line 402) | def _add_checksum(self, path: str, content: str | bytes) -> None:
method _generate_manifest (line 409) | def _generate_manifest(
FILE: astrbot/core/backup/importer.py
function _get_major_version (line 41) | def _get_major_version(version_str: str) -> str:
function _load_platform_stats_invalid_count_warn_limit (line 70) | def _load_platform_stats_invalid_count_warn_limit() -> int:
class _InvalidCountWarnLimiter (line 95) | class _InvalidCountWarnLimiter:
method __init__ (line 98) | def __init__(self, limit: int) -> None:
method warn_invalid_count (line 103) | def warn_invalid_count(self, value: Any, key_for_log: tuple[Any, ...])...
class ImportPreCheckResult (line 130) | class ImportPreCheckResult:
method to_dict (line 158) | def to_dict(self) -> dict:
class ImportResult (line 173) | class ImportResult:
method __init__ (line 176) | def __init__(self) -> None:
method add_warning (line 184) | def add_warning(self, msg: str) -> None:
method add_error (line 188) | def add_error(self, msg: str) -> None:
method to_dict (line 193) | def to_dict(self) -> dict:
class DatabaseClearError (line 204) | class DatabaseClearError(RuntimeError):
class AstrBotImporter (line 208) | class AstrBotImporter:
method __init__ (line 225) | def __init__(
method pre_check (line 237) | def pre_check(self, zip_path: str) -> ImportPreCheckResult:
method _check_version_compatibility (line 300) | def _check_version_compatibility(self, backup_version: str) -> dict:
method import_all (line 349) | async def import_all(
method _validate_version (line 496) | def _validate_version(self, manifest: dict) -> None:
method _clear_main_db (line 516) | async def _clear_main_db(self) -> None:
method _clear_kb_data (line 529) | async def _clear_kb_data(self) -> None:
method _import_main_database (line 556) | async def _import_main_database(
method _preprocess_main_table_rows (line 587) | def _preprocess_main_table_rows(
method _merge_platform_stats_rows (line 602) | def _merge_platform_stats_rows(
method _normalize_platform_stats_entry (line 641) | def _normalize_platform_stats_entry(
method _normalize_platform_stats_timestamp (line 674) | def _normalize_platform_stats_timestamp(self, value: Any) -> str | None:
method _import_knowledge_bases (line 699) | async def _import_knowledge_bases(
method _import_kb_documents (line 777) | async def _import_kb_documents(self, kb_id: str, doc_data: dict) -> None:
method _import_attachments (line 802) | async def _import_attachments(
method _import_directories (line 839) | async def _import_directories(
method _convert_datetime_fields (line 924) | def _convert_datetime_fields(self, row: dict, model_class: type) -> dict:
FILE: astrbot/core/computer/booters/base.py
class ComputerBooter (line 9) | class ComputerBooter:
method fs (line 11) | def fs(self) -> FileSystemComponent: ...
method python (line 14) | def python(self) -> PythonComponent: ...
method shell (line 17) | def shell(self) -> ShellComponent: ...
method capabilities (line 20) | def capabilities(self) -> tuple[str, ...] | None:
method browser (line 29) | def browser(self) -> BrowserComponent | None:
method boot (line 32) | async def boot(self, session_id: str) -> None: ...
method shutdown (line 34) | async def shutdown(self) -> None: ...
method upload_file (line 36) | async def upload_file(self, path: str, file_name: str) -> dict:
method download_file (line 43) | async def download_file(self, remote_path: str, local_path: str) -> None:
method available (line 47) | async def available(self) -> bool:
FILE: astrbot/core/computer/booters/bay_manager.py
class BayContainerManager (line 33) | class BayContainerManager:
method __init__ (line 36) | def __init__(
method ensure_running (line 50) | async def ensure_running(self) -> str:
method wait_healthy (line 121) | async def wait_healthy(self, timeout: int = HEALTH_TIMEOUT_S) -> None:
method read_credentials (line 147) | async def read_credentials(self) -> str:
method close_client (line 210) | async def close_client(self) -> None:
method stop (line 219) | async def stop(self) -> None:
method _find_managed_container (line 237) | async def _find_managed_container(self) -> dict | None:
method _pull_image_if_needed (line 249) | async def _pull_image_if_needed(self) -> None:
FILE: astrbot/core/computer/booters/boxlite.py
class MockShipyardSandboxClient (line 17) | class MockShipyardSandboxClient:
method __init__ (line 18) | def __init__(self, sb_url: str) -> None:
method _exec_operation (line 21) | async def _exec_operation(
method upload_file (line 43) | async def upload_file(self, path: str, remote_path: str) -> dict:
method wait_healthy (line 112) | async def wait_healthy(self, ship_id: str, session_id: str) -> None:
class BoxliteBooter (line 131) | class BoxliteBooter(ComputerBooter):
method boot (line 132) | async def boot(self, session_id: str) -> None:
method shutdown (line 171) | async def shutdown(self) -> None:
method fs (line 177) | def fs(self) -> FileSystemComponent:
method python (line 181) | def python(self) -> PythonComponent:
method shell (line 185) | def shell(self) -> ShellComponent:
method upload_file (line 188) | async def upload_file(self, path: str, file_name: str) -> dict:
FILE: astrbot/core/computer/booters/local.py
function _is_safe_command (line 39) | def _is_safe_command(command: str) -> bool:
function _ensure_safe_path (line 44) | def _ensure_safe_path(path: str) -> str:
function _decode_shell_output (line 56) | def _decode_shell_output(output: bytes | None) -> str:
class LocalShellComponent (line 82) | class LocalShellComponent(ShellComponent):
method exec (line 83) | async def exec(
class LocalPythonComponent (line 134) | class LocalPythonComponent(PythonComponent):
method exec (line 135) | async def exec(
class LocalFileSystemComponent (line 170) | class LocalFileSystemComponent(FileSystemComponent):
method create_file (line 171) | async def create_file(
method read_file (line 184) | async def read_file(self, path: str, encoding: str = "utf-8") -> dict[...
method write_file (line 193) | async def write_file(
method delete_file (line 205) | async def delete_file(self, path: str) -> dict[str, Any]:
method list_dir (line 216) | async def list_dir(
class LocalBooter (line 229) | class LocalBooter(ComputerBooter):
method __init__ (line 230) | def __init__(self) -> None:
method boot (line 235) | async def boot(self, session_id: str) -> None:
method shutdown (line 238) | async def shutdown(self) -> None:
method fs (line 242) | def fs(self) -> FileSystemComponent:
method python (line 246) | def python(self) -> PythonComponent:
method shell (line 250) | def shell(self) -> ShellComponent:
method upload_file (line 253) | async def upload_file(self, path: str, file_name: str) -> dict:
method download_file (line 258) | async def download_file(self, remote_path: str, local_path: str) -> None:
method available (line 263) | async def available(self) -> bool:
FILE: astrbot/core/computer/booters/shipyard.py
class ShipyardBooter (line 9) | class ShipyardBooter(ComputerBooter):
method __init__ (line 10) | def __init__(
method boot (line 23) | async def boot(self, session_id: str) -> None:
method shutdown (line 33) | async def shutdown(self) -> None:
method fs (line 37) | def fs(self) -> FileSystemComponent:
method python (line 41) | def python(self) -> PythonComponent:
method shell (line 45) | def shell(self) -> ShellComponent:
method upload_file (line 48) | async def upload_file(self, path: str, file_name: str) -> dict:
method download_file (line 54) | async def download_file(self, remote_path: str, local_path: str):
method available (line 64) | async def available(self) -> bool:
FILE: astrbot/core/computer/booters/shipyard_neo.py
function _maybe_model_dump (line 18) | def _maybe_model_dump(value: Any) -> dict[str, Any]:
class NeoPythonComponent (line 28) | class NeoPythonComponent(PythonComponent):
method __init__ (line 29) | def __init__(self, sandbox: Any) -> None:
method exec (line 32) | async def exec(
class NeoShellComponent (line 69) | class NeoShellComponent(ShellComponent):
method __init__ (line 70) | def __init__(self, sandbox: Any) -> None:
method exec (line 73) | async def exec(
class NeoFileSystemComponent (line 138) | class NeoFileSystemComponent(FileSystemComponent):
method __init__ (line 139) | def __init__(self, sandbox: Any) -> None:
method create_file (line 142) | async def create_file(
method read_file (line 152) | async def read_file(self, path: str, encoding: str = "utf-8") -> dict[...
method write_file (line 157) | async def write_file(
method delete_file (line 169) | async def delete_file(self, path: str) -> dict[str, Any]:
method list_dir (line 173) | async def list_dir(
class NeoBrowserComponent (line 188) | class NeoBrowserComponent(BrowserComponent):
method __init__ (line 189) | def __init__(self, sandbox: Any) -> None:
method exec (line 192) | async def exec(
method exec_batch (line 211) | async def exec_batch(
method run_skill (line 232) | async def run_skill(
class ShipyardNeoBooter (line 252) | class ShipyardNeoBooter(ComputerBooter):
method __init__ (line 263) | def __init__(
method bay_client (line 283) | def bay_client(self) -> Any:
method sandbox (line 287) | def sandbox(self) -> Any:
method capabilities (line 291) | def capabilities(self) -> tuple[str, ...] | None:
method is_auto_mode (line 302) | def is_auto_mode(self) -> bool:
method boot (line 307) | async def boot(self, session_id: str) -> None:
method _resolve_profile (line 372) | async def _resolve_profile(self, client: Any) -> str:
method shutdown (line 427) | async def shutdown(self) -> None:
method fs (line 445) | def fs(self) -> FileSystemComponent:
method python (line 451) | def python(self) -> PythonComponent:
method shell (line 457) | def shell(self) -> ShellComponent:
method browser (line 463) | def browser(self) -> BrowserComponent:
method upload_file (line 468) | async def upload_file(self, path: str, file_name: str) -> dict:
method download_file (line 482) | async def download_file(self, remote_path: str, local_path: str) -> None:
method available (line 497) | async def available(self) -> bool:
FILE: astrbot/core/computer/computer_client.py
function _list_local_skill_dirs (line 23) | def _list_local_skill_dirs(skills_root: Path) -> list[Path]:
function _discover_bay_credentials (line 34) | def _discover_bay_credentials(endpoint: str) -> str:
function _build_python_exec_command (line 93) | def _build_python_exec_command(script: str) -> str:
function _build_apply_sync_command (line 104) | def _build_apply_sync_command() -> str:
function _build_scan_command (line 180) | def _build_scan_command() -> str:
function _build_sync_and_scan_command (line 294) | def _build_sync_and_scan_command() -> str:
function _shell_exec_succeeded (line 302) | def _shell_exec_succeeded(result: dict) -> bool:
function _format_exec_error_detail (line 309) | def _format_exec_error_detail(result: dict) -> str:
function _decode_sync_payload (line 322) | def _decode_sync_payload(stdout: str) -> dict | None:
function _update_sandbox_skills_cache (line 338) | def _update_sandbox_skills_cache(payload: dict | None) -> None:
function _apply_skills_to_sandbox (line 347) | async def _apply_skills_to_sandbox(booter: ComputerBooter) -> None:
function _scan_sandbox_skills (line 362) | async def _scan_sandbox_skills(booter: ComputerBooter) -> dict | None:
function _sync_skills_to_sandbox (line 379) | async def _sync_skills_to_sandbox(booter: ComputerBooter) -> None:
function get_booter (line 430) | async def get_booter(
function sync_skills_to_active_sandboxes (line 508) | async def sync_skills_to_active_sandboxes() -> None:
function get_local_booter (line 526) | def get_local_booter() -> ComputerBooter:
FILE: astrbot/core/computer/olayer/browser.py
class BrowserComponent (line 8) | class BrowserComponent(Protocol):
method exec (line 11) | async def exec(
method exec_batch (line 23) | async def exec_batch(
method run_skill (line 36) | async def run_skill(
FILE: astrbot/core/computer/olayer/filesystem.py
class FileSystemComponent (line 8) | class FileSystemComponent(Protocol):
method create_file (line 9) | async def create_file(
method read_file (line 15) | async def read_file(self, path: str, encoding: str = "utf-8") -> dict[...
method write_file (line 19) | async def write_file(
method delete_file (line 25) | async def delete_file(self, path: str) -> dict[str, Any]:
method list_dir (line 29) | async def list_dir(
FILE: astrbot/core/computer/olayer/python.py
class PythonComponent (line 8) | class PythonComponent(Protocol):
method exec (line 11) | async def exec(
FILE: astrbot/core/computer/olayer/shell.py
class ShellComponent (line 8) | class ShellComponent(Protocol):
method exec (line 11) | async def exec(
FILE: astrbot/core/computer/tools/browser.py
function _to_json (line 13) | def _to_json(data: Any) -> str:
function _ensure_admin (line 17) | def _ensure_admin(context: ContextWrapper[AstrAgentContext]) -> str | None:
function _get_browser_component (line 26) | async def _get_browser_component(context: ContextWrapper[AstrAgentContex...
class BrowserExecTool (line 41) | class BrowserExecTool(FunctionTool):
method call (line 70) | async def call(
class BrowserBatchExecTool (line 98) | class BrowserBatchExecTool(FunctionTool):
method call (line 132) | async def call(
class RunBrowserSkillTool (line 162) | class RunBrowserSkillTool(FunctionTool):
method call (line 180) | async def call(
FILE: astrbot/core/computer/tools/fs.py
class FileUploadTool (line 81) | class FileUploadTool(FunctionTool):
method call (line 106) | async def call(
class FileDownloadTool (line 146) | class FileDownloadTool(FunctionTool):
method call (line 170) | async def call(
FILE: astrbot/core/computer/tools/neo_skills.py
function _to_jsonable (line 15) | def _to_jsonable(model_like: Any) -> Any:
function _to_json_text (line 25) | def _to_json_text(data: Any) -> str:
function _ensure_admin (line 29) | def _ensure_admin(context: ContextWrapper[AstrAgentContext]) -> str | None:
function _get_neo_context (line 35) | async def _get_neo_context(
class NeoSkillToolBase (line 53) | class NeoSkillToolBase(FunctionTool):
method _run (line 56) | async def _run(
class GetExecutionHistoryTool (line 73) | class GetExecutionHistoryTool(NeoSkillToolBase):
method call (line 92) | async def call(
class AnnotateExecutionTool (line 119) | class AnnotateExecutionTool(NeoSkillToolBase):
method call (line 135) | async def call(
class CreateSkillPayloadTool (line 156) | class CreateSkillPayloadTool(NeoSkillToolBase):
method call (line 186) | async def call(
class GetSkillPayloadTool (line 203) | class GetSkillPayloadTool(NeoSkillToolBase):
method call (line 216) | async def call(
class CreateSkillCandidateTool (line 229) | class CreateSkillCandidateTool(NeoSkillToolBase):
method call (line 261) | async def call(
class ListSkillCandidatesTool (line 282) | class ListSkillCandidatesTool(NeoSkillToolBase):
method call (line 298) | async def call(
class EvaluateSkillCandidateTool (line 319) | class EvaluateSkillCandidateTool(NeoSkillToolBase):
method call (line 336) | async def call(
class PromoteSkillCandidateTool (line 359) | class PromoteSkillCandidateTool(NeoSkillToolBase):
method call (line 388) | async def call(
class ListSkillReleasesTool (line 429) | class ListSkillReleasesTool(NeoSkillToolBase):
method call (line 446) | async def call(
class RollbackSkillReleaseTool (line 469) | class RollbackSkillReleaseTool(NeoSkillToolBase):
method call (line 482) | async def call(
class SyncSkillReleaseTool (line 495) | class SyncSkillReleaseTool(NeoSkillToolBase):
method call (line 512) | async def call(
function _sync_release_to_dict (line 531) | async def _sync_release_to_dict(
FILE: astrbot/core/computer/tools/permissions.py
function check_admin_permission (line 5) | def check_admin_permission(
FILE: astrbot/core/computer/tools/python.py
function handle_result (line 33) | async def handle_result(result: dict, event: AstrMessageEvent) -> ToolEx...
class PythonTool (line 65) | class PythonTool(FunctionTool):
method call (line 70) | async def call(
class LocalPythonTool (line 87) | class LocalPythonTool(FunctionTool):
method call (line 96) | async def call(
FILE: astrbot/core/computer/tools/shell.py
class ExecuteShellTool (line 14) | class ExecuteShellTool(FunctionTool):
method call (line 43) | async def call(
FILE: astrbot/core/config/astrbot_config.py
class RateLimitStrategy (line 14) | class RateLimitStrategy(enum.Enum):
class AstrBotConfig (line 19) | class AstrBotConfig(dict):
method __init__ (line 31) | def __init__(
method _config_schema_to_default_config (line 68) | def _config_schema_to_default_config(self, schema: dict) -> dict:
method check_config_integrity (line 95) | def check_config_integrity(self, refer_conf: dict, conf: dict, path=""):
method save_config (line 154) | def save_config(self, replace_config: dict | None = None) -> None:
method __getattr__ (line 164) | def __getattr__(self, item):
method __delattr__ (line 170) | def __delattr__(self, key) -> None:
method __setattr__ (line 177) | def __setattr__(self, key, value) -> None:
method check_exist (line 180) | def check_exist(self) -> bool:
FILE: astrbot/core/config/default.py
class ChatProviderTemplate (line 251) | class ChatProviderTemplate(TypedDict):
FILE: astrbot/core/config/i18n_utils.py
class ConfigMetadataI18n (line 10) | class ConfigMetadataI18n:
method _get_i18n_key (line 14) | def _get_i18n_key(group: str, section: str, field: str, attr: str) -> ...
method convert_to_i18n_keys (line 33) | def convert_to_i18n_keys(metadata: dict[str, Any]) -> dict[str, Any]:
FILE: astrbot/core/conversation_mgr.py
class ConversationManager (line 17) | class ConversationManager:
method __init__ (line 20) | def __init__(self, db_helper: BaseDatabase) -> None:
method register_on_session_deleted (line 28) | def register_on_session_deleted(
method _trigger_session_deleted (line 43) | async def _trigger_session_deleted(self, unified_msg_origin: str) -> N...
method _convert_conv_from_v2_to_v1 (line 60) | def _convert_conv_from_v2_to_v1(self, conv_v2: ConversationV2) -> Conv...
method new_conversation (line 78) | async def new_conversation(
method switch_conversation (line 112) | async def switch_conversation(
method delete_conversation (line 125) | async def delete_conversation(
method delete_conversations_by_user_id (line 146) | async def delete_conversations_by_user_id(self, unified_msg_origin: st...
method get_curr_conversation_id (line 160) | async def get_curr_conversation_id(self, unified_msg_origin: str) -> s...
method get_conversation (line 176) | async def get_conversation(
method get_conversations (line 202) | async def get_conversations(
method get_filtered_conversations (line 226) | async def get_filtered_conversations(
method update_conversation (line 258) | async def update_conversation(
method update_conversation_title (line 288) | async def update_conversation_title(
method update_conversation_persona_id (line 310) | async def update_conversation_persona_id(
method add_message_pair (line 332) | async def add_message_pair(
method get_human_readable_context (line 367) | async def get_human_readable_context(
FILE: astrbot/core/core_lifecycle.py
class AstrBotCoreLifecycle (line 46) | class AstrBotCoreLifecycle:
method __init__ (line 54) | def __init__(self, log_broker: LogBroker, db: BaseDatabase) -> None:
method _init_or_reload_subagent_orchestrator (line 82) | async def _init_or_reload_subagent_orchestrator(self) -> None:
method initialize (line 100) | async def initialize(self) -> None:
method _load (line 235) | def _load(self) -> None:
method _task_wrapper (line 273) | async def _task_wrapper(self, task: asyncio.Task) -> None:
method start (line 291) | async def start(self) -> None:
method stop (line 315) | async def stop(self) -> None:
method restart (line 350) | async def restart(self) -> None:
method load_platform (line 362) | def load_platform(self) -> list[asyncio.Task]:
method load_pipeline_scheduler (line 375) | async def load_pipeline_scheduler(self) -> dict[str, PipelineScheduler]:
method reload_pipeline_scheduler (line 391) | async def reload_pipeline_scheduler(self, conf_id: str) -> None:
FILE: astrbot/core/cron/events.py
class CronMessageEvent (line 14) | class CronMessageEvent(AstrMessageEvent):
method __init__ (line 17) | def __init__(
method send (line 56) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 62) | async def send_streaming(self, generator, use_fallback: bool = False) ...
FILE: astrbot/core/cron/manager.py
class CronJobManager (line 25) | class CronJobManager:
method __init__ (line 28) | def __init__(self, db: BaseDatabase) -> None:
method start (line 35) | async def start(self, ctx: "Context") -> None:
method shutdown (line 44) | async def shutdown(self) -> None:
method sync_from_db (line 51) | async def sync_from_db(self) -> None:
method add_basic_job (line 64) | async def add_basic_job(
method add_active_job (line 91) | async def add_active_job(
method update_job (line 122) | async def update_job(self, job_id: str, **kwargs) -> CronJob | None:
method delete_job (line 131) | async def delete_job(self, job_id: str) -> None:
method list_jobs (line 136) | async def list_jobs(self, job_type: str | None = None) -> list[CronJob]:
method _remove_scheduled (line 139) | def _remove_scheduled(self, job_id: str) -> None:
method _schedule_job (line 143) | def _schedule_job(self, job: CronJob) -> None:
method _get_next_run_time (line 187) | def _get_next_run_time(self, job_id: str):
method _run_job (line 191) | async def _run_job(self, job_id: str) -> None:
method _run_basic_job (line 225) | async def _run_basic_job(self, job: CronJob) -> None:
method _run_active_agent_job (line 234) | async def _run_active_agent_job(self, job: CronJob, start_time: dateti...
method _woke_main_agent (line 263) | async def _woke_main_agent(
FILE: astrbot/core/db/__init__.py
class BaseDatabase (line 30) | class BaseDatabase(abc.ABC):
method __init__ (line 35) | def __init__(self) -> None:
method initialize (line 55) | async def initialize(self) -> None:
method get_db (line 59) | async def get_db(self) -> T.AsyncGenerator[AsyncSession, None]:
method get_base_stats (line 69) | def get_base_stats(self, offset_sec: int = 86400) -> Stats:
method get_total_message_count (line 75) | def get_total_message_count(self) -> int:
method get_grouped_base_stats (line 81) | def get_grouped_base_stats(self, offset_sec: int = 86400) -> Stats:
method insert_platform_stats (line 88) | async def insert_platform_stats(
method count_platform_stats (line 99) | async def count_platform_stats(self) -> int:
method get_platform_stats (line 104) | async def get_platform_stats(self, offset_sec: int = 86400) -> list[Pl...
method get_conversations (line 109) | async def get_conversations(
method get_conversation_by_id (line 121) | async def get_conversation_by_id(self, cid: str) -> ConversationV2:
method get_all_conversations (line 126) | async def get_all_conversations(
method get_filtered_conversations (line 135) | async def get_filtered_conversations(
method create_conversation (line 147) | async def create_conversation(
method update_conversation (line 162) | async def update_conversation(
method delete_conversation (line 174) | async def delete_conversation(self, cid: str) -> None:
method delete_conversations_by_user_id (line 179) | async def delete_conversations_by_user_id(self, user_id: str) -> None:
method insert_platform_message_history (line 184) | async def insert_platform_message_history(
method delete_platform_message_offset (line 196) | async def delete_platform_message_offset(
method get_platform_message_history (line 206) | async def get_platform_message_history(
method get_platform_message_history_by_id (line 217) | async def get_platform_message_history_by_id(
method insert_attachment (line 225) | async def insert_attachment(
method get_attachment_by_id (line 235) | async def get_attachment_by_id(self, attachment_id: str) -> Attachment:
method get_attachments (line 240) | async def get_attachments(self, attachment_ids: list[str]) -> list[Att...
method delete_attachment (line 245) | async def delete_attachment(self, attachment_id: str) -> bool:
method delete_attachments (line 253) | async def delete_attachments(self, attachment_ids: list[str]) -> int:
method create_api_key (line 261) | async def create_api_key(
method list_api_keys (line 274) | async def list_api_keys(self) -> list[ApiKey]:
method get_api_key_by_id (line 279) | async def get_api_key_by_id(self, key_id: str) -> ApiKey | None:
method get_active_api_key_by_hash (line 284) | async def get_active_api_key_by_hash(self, key_hash: str) -> ApiKey | ...
method touch_api_key (line 289) | async def touch_api_key(self, key_id: str) -> None:
method revoke_api_key (line 294) | async def revoke_api_key(self, key_id: str) -> bool:
method delete_api_key (line 302) | async def delete_api_key(self, key_id: str) -> bool:
method insert_persona (line 310) | async def insert_persona(
method get_persona_by_id (line 336) | async def get_persona_by_id(self, persona_id: str) -> Persona:
method get_personas (line 341) | async def get_personas(self) -> list[Persona]:
method update_persona (line 346) | async def update_persona(
method delete_persona (line 359) | async def delete_persona(self, persona_id: str) -> None:
method insert_persona_folder (line 368) | async def insert_persona_folder(
method get_persona_folder_by_id (line 379) | async def get_persona_folder_by_id(self, folder_id: str) -> PersonaFol...
method get_persona_folders (line 384) | async def get_persona_folders(
method get_all_persona_folders (line 391) | async def get_all_persona_folders(self) -> list[PersonaFolder]:
method update_persona_folder (line 396) | async def update_persona_folder(
method delete_persona_folder (line 408) | async def delete_persona_folder(self, folder_id: str) -> None:
method move_persona_to_folder (line 413) | async def move_persona_to_folder(
method get_personas_by_folder (line 420) | async def get_personas_by_folder(
method batch_update_sort_order (line 427) | async def batch_update_sort_order(
method insert_preference_or_update (line 442) | async def insert_preference_or_update(
method get_preference (line 453) | async def get_preference(self, scope: str, scope_id: str, key: str) ->...
method get_preferences (line 458) | async def get_preferences(
method remove_preference (line 468) | async def remove_preference(self, scope: str, scope_id: str, key: str)...
method clear_preferences (line 473) | async def clear_preferences(self, scope: str, scope_id: str) -> None:
method get_command_configs (line 478) | async def get_command_configs(self) -> list[CommandConfig]:
method get_command_config (line 483) | async def get_command_config(self, handler_full_name: str) -> CommandC...
method upsert_command_config (line 488) | async def upsert_command_config(
method delete_command_config (line 508) | async def delete_command_config(self, handler_full_name: str) -> None:
method delete_command_configs (line 513) | async def delete_command_configs(self, handler_full_names: list[str]) ...
method list_command_conflicts (line 518) | async def list_command_conflicts(
method upsert_command_conflict (line 526) | async def upsert_command_conflict(
method delete_command_conflicts (line 543) | async def delete_command_conflicts(self, ids: list[int]) -> None:
method get_session_conversations (line 566) | async def get_session_conversations(
method create_cron_job (line 581) | async def create_cron_job(
method update_cron_job (line 600) | async def update_cron_job(
method delete_cron_job (line 621) | async def delete_cron_job(self, job_id: str) -> None:
method get_cron_job (line 626) | async def get_cron_job(self, job_id: str) -> CronJob | None:
method list_cron_jobs (line 631) | async def list_cron_jobs(self, job_type: str | None = None) -> list[Cr...
method create_platform_session (line 640) | async def create_platform_session(
method get_platform_session_by_id (line 652) | async def get_platform_session_by_id(
method get_platform_sessions_by_ids (line 659) | async def get_platform_sessions_by_ids(
method get_platform_sessions_by_creator (line 666) | async def get_platform_sessions_by_creator(
method get_platform_sessions_by_creator_paginated (line 680) | async def get_platform_sessions_by_creator_paginated(
method update_platform_session (line 696) | async def update_platform_session(
method delete_platform_session (line 705) | async def delete_platform_session(self, session_id: str) -> None:
method create_chatui_project (line 714) | async def create_chatui_project(
method get_chatui_project_by_id (line 725) | async def get_chatui_project_by_id(self, project_id: str) -> ChatUIPro...
method get_chatui_projects_by_creator (line 730) | async def get_chatui_projects_by_creator(
method update_chatui_project (line 740) | async def update_chatui_project(
method delete_chatui_project (line 751) | async def delete_chatui_project(self, project_id: str) -> None:
method add_session_to_project (line 756) | async def add_session_to_project(
method remove_session_from_project (line 765) | async def remove_session_from_project(self, session_id: str) -> None:
method get_project_sessions (line 770) | async def get_project_sessions(
method get_project_by_session (line 780) | async def get_project_by_session(
FILE: astrbot/core/db/migration/helper.py
function check_migration_needed_v4 (line 17) | async def check_migration_needed_v4(db_helper: BaseDatabase) -> bool:
function do_migration_v4 (line 37) | async def do_migration_v4(
FILE: astrbot/core/db/migration/migra_3_to_4.py
function get_platform_id (line 23) | def get_platform_id(
function get_platform_type (line 33) | def get_platform_type(
function migration_conversation_table (line 43) | async def migration_conversation_table(
function migration_platform_table (line 101) | async def migration_platform_table(
function migration_webchat_data (line 180) | async def migration_webchat_data(
function migration_persona_data (line 236) | async def migration_persona_data(
function migration_preferences (line 279) | async def migration_preferences(
FILE: astrbot/core/db/migration/migra_45_to_46.py
function migrate_45_to_46 (line 6) | async def migrate_45_to_46(acm: AstrBotConfigManager, ucr: UmopConfigRou...
FILE: astrbot/core/db/migration/migra_token_usage.py
function migrate_token_usage (line 15) | async def migrate_token_usage(db_helper: BaseDatabase) -> None:
FILE: astrbot/core/db/migration/migra_webchat_session.py
function migrate_webchat_session (line 20) | async def migrate_webchat_session(db_helper: BaseDatabase) -> None:
FILE: astrbot/core/db/migration/shared_preferences_v3.py
class SharedPreferences (line 10) | class SharedPreferences:
method __init__ (line 11) | def __init__(self, path=None) -> None:
method _load_preferences (line 17) | def _load_preferences(self):
method _save_preferences (line 26) | def _save_preferences(self) -> None:
method get (line 31) | def get(self, key, default: _VT = None) -> _VT:
method put (line 34) | def put(self, key, value) -> None:
method remove (line 38) | def remove(self, key) -> None:
method clear (line 43) | def clear(self) -> None:
FILE: astrbot/core/db/migration/sqlite_v3.py
class Conversation (line 10) | class Conversation:
class SQLiteDatabase (line 81) | class SQLiteDatabase:
method __init__ (line 82) | def __init__(self, db_path: str) -> None:
method _get_conn (line 125) | def _get_conn(self, db_path: str) -> sqlite3.Connection:
method _exec_sql (line 130) | def _exec_sql(self, sql: str, params: tuple | None = None) -> None:
method insert_platform_metrics (line 147) | def insert_platform_metrics(self, metrics: dict) -> None:
method insert_llm_metrics (line 156) | def insert_llm_metrics(self, metrics: dict) -> None:
method get_base_stats (line 165) | def get_base_stats(self, offset_sec: int = 86400) -> Stats:
method get_total_message_count (line 189) | def get_total_message_count(self) -> int:
method get_grouped_base_stats (line 204) | def get_grouped_base_stats(self, offset_sec: int = 86400) -> Stats:
method get_conversation_by_user_id (line 229) | def get_conversation_by_user_id(
method new_conversation (line 252) | def new_conversation(self, user_id: str, cid: str) -> None:
method get_conversations (line 263) | def get_conversations(self, user_id: str) -> list[Conversation]:
method update_conversation (line 290) | def update_conversation(self, user_id: str, cid: str, history: str) ->...
method update_conversation_title (line 300) | def update_conversation_title(self, user_id: str, cid: str, title: str...
method update_conversation_persona_id (line 308) | def update_conversation_persona_id(
method delete_conversation (line 318) | def delete_conversation(self, user_id: str, cid: str) -> None:
method get_all_conversations (line 326) | def get_all_conversations(
method get_filtered_conversations (line 387) | def get_filtered_conversations(
FILE: astrbot/core/db/po.py
class TimestampMixin (line 9) | class TimestampMixin(SQLModel):
class PlatformStat (line 17) | class PlatformStat(SQLModel, table=True):
class ConversationV2 (line 41) | class ConversationV2(TimestampMixin, SQLModel, table=True):
class PersonaFolder (line 75) | class PersonaFolder(TimestampMixin, SQLModel, table=True):
class Persona (line 108) | class Persona(TimestampMixin, SQLModel, table=True):
class CronJob (line 144) | class CronJob(TimestampMixin, SQLModel, table=True):
class Preference (line 175) | class Preference(TimestampMixin, SQLModel, table=True):
class PlatformMessageHistory (line 202) | class PlatformMessageHistory(TimestampMixin, SQLModel, table=True):
class PlatformSession (line 225) | class PlatformSession(TimestampMixin, SQLModel, table=True):
class Attachment (line 262) | class Attachment(TimestampMixin, SQLModel, table=True):
class ApiKey (line 293) | class ApiKey(TimestampMixin, SQLModel, table=True):
class ChatUIProject (line 330) | class ChatUIProject(TimestampMixin, SQLModel, table=True):
class SessionProjectRelation (line 366) | class SessionProjectRelation(SQLModel, table=True):
class CommandConfig (line 389) | class CommandConfig(TimestampMixin, SQLModel, table=True):
class CommandConflict (line 411) | class CommandConflict(TimestampMixin, SQLModel, table=True):
class Conversation (line 439) | class Conversation:
class Personality (line 462) | class Personality(TypedDict):
class Platform (line 491) | class Platform:
class Stats (line 500) | class Stats:
FILE: astrbot/core/db/sqlite.py
class SQLiteDatabase (line 41) | class SQLiteDatabase(BaseDatabase):
method __init__ (line 42) | def __init__(self, db_path: str) -> None:
method initialize (line 48) | async def initialize(self) -> None:
method _ensure_persona_folder_columns (line 64) | async def _ensure_persona_folder_columns(self, conn) -> None:
method _ensure_persona_skills_column (line 84) | async def _ensure_persona_skills_column(self, conn) -> None:
method _ensure_persona_custom_error_message_column (line 96) | async def _ensure_persona_custom_error_message_column(self, conn) -> N...
method insert_platform_stats (line 110) | async def insert_platform_stats(
method count_platform_stats (line 143) | async def count_platform_stats(self) -> int:
method get_platform_stats (line 155) | async def get_platform_stats(self, offset_sec: int = 86400) -> list[Pl...
method get_conversations (line 176) | async def get_conversations(self, user_id=None, platform_id=None):
method get_conversation_by_id (line 191) | async def get_conversation_by_id(self, cid):
method get_all_conversations (line 198) | async def get_all_conversations(self, page=1, page_size=20):
method get_filtered_conversations (line 210) | async def get_filtered_conversations(
method create_conversation (line 264) | async def create_conversation(
method update_conversation (line 296) | async def update_conversation(
method delete_conversation (line 320) | async def delete_conversation(self, cid) -> None:
method delete_conversations_by_user_id (line 330) | async def delete_conversations_by_user_id(self, user_id: str) -> None:
method get_session_conversations (line 340) | async def get_session_conversations(
method insert_platform_message_history (line 449) | async def insert_platform_message_history(
method delete_platform_message_offset (line 471) | async def delete_platform_message_offset(
method get_platform_message_history (line 491) | async def get_platform_message_history(
method get_platform_message_history_by_id (line 513) | async def get_platform_message_history_by_id(
method insert_attachment (line 525) | async def insert_attachment(self, path, type, mime_type):
method get_attachment_by_id (line 538) | async def get_attachment_by_id(self, attachment_id):
method get_attachments (line 546) | async def get_attachments(self, attachment_ids: list[str]) -> list:
method delete_attachment (line 558) | async def delete_attachment(self, attachment_id: str) -> bool:
method delete_attachments (line 572) | async def delete_attachments(self, attachment_ids: list[str]) -> int:
method create_api_key (line 588) | async def create_api_key(
method list_api_keys (line 614) | async def list_api_keys(self) -> list[ApiKey]:
method get_api_key_by_id (line 623) | async def get_api_key_by_id(self, key_id: str) -> ApiKey | None:
method get_active_api_key_by_hash (line 632) | async def get_active_api_key_by_hash(self, key_hash: str) -> ApiKey | ...
method touch_api_key (line 645) | async def touch_api_key(self, key_id: str) -> None:
method revoke_api_key (line 656) | async def revoke_api_key(self, key_id: str) -> bool:
method delete_api_key (line 669) | async def delete_api_key(self, key_id: str) -> bool:
method insert_persona (line 682) | async def insert_persona(
method get_persona_by_id (line 712) | async def get_persona_by_id(self, persona_id):
method get_personas (line 720) | async def get_personas(self):
method update_persona (line 728) | async def update_persona(
method delete_persona (line 759) | async def delete_persona(self, persona_id) -> None:
method insert_persona_folder (line 772) | async def insert_persona_folder(
method get_persona_folder_by_id (line 794) | async def get_persona_folder_by_id(self, folder_id: str) -> PersonaFol...
method get_persona_folders (line 802) | async def get_persona_folders(
method get_all_persona_folders (line 829) | async def get_all_persona_folders(self) -> list[PersonaFolder]:
method update_persona_folder (line 839) | async def update_persona_folder(
method delete_persona_folder (line 869) | async def delete_persona_folder(self, folder_id: str) -> None:
method move_persona_to_folder (line 891) | async def move_persona_to_folder(
method get_personas_by_folder (line 905) | async def get_personas_by_folder(
method batch_update_sort_order (line 930) | async def batch_update_sort_order(
method insert_preference_or_update (line 969) | async def insert_preference_or_update(self, scope, scope_id, key, value):
method get_preference (line 993) | async def get_preference(self, scope, scope_id, key):
method get_preferences (line 1005) | async def get_preferences(self, scope, scope_id=None, key=None):
method remove_preference (line 1017) | async def remove_preference(self, scope, scope_id, key) -> None:
method clear_preferences (line 1031) | async def clear_preferences(self, scope, scope_id) -> None:
method _run_in_tx (line 1048) | async def _run_in_tx(
method _apply_updates (line 1058) | def _apply_updates(model, **updates) -> None:
method _new_command_config (line 1064) | def _new_command_config(
method _new_command_conflict (line 1097) | def _new_command_conflict(
method get_command_configs (line 1121) | async def get_command_configs(self) -> list[CommandConfig]:
method get_command_config (line 1127) | async def get_command_config(
method upsert_command_config (line 1135) | async def upsert_command_config(
method delete_command_config (line 1190) | async def delete_command_config(self, handler_full_name: str) -> None:
method delete_command_configs (line 1193) | async def delete_command_configs(self, handler_full_names: list[str]) ...
method list_command_conflicts (line 1206) | async def list_command_conflicts(
method upsert_command_conflict (line 1218) | async def upsert_command_conflict(
method delete_command_conflicts (line 1269) | async def delete_command_conflicts(self, ids: list[int]) -> None:
method get_base_stats (line 1284) | def get_base_stats(self, offset_sec=86400):
method get_total_message_count (line 1318) | def get_total_message_count(self):
method get_grouped_base_stats (line 1341) | def get_grouped_base_stats(self, offset_sec=86400):
method create_platform_session (line 1380) | async def create_platform_session(
method get_platform_session_by_id (line 1408) | async def get_platform_session_by_id(
method get_platform_sessions_by_ids (line 1420) | async def get_platform_sessions_by_ids(
method get_platform_sessions_by_creator (line 1435) | async def get_platform_sessions_by_creator(
method _build_platform_sessions_query (line 1459) | def _build_platform_sessions_query(
method _rows_to_session_dicts (line 1491) | def _rows_to_session_dicts(rows: T.Sequence[Row[tuple]]) -> list[dict]:
method get_platform_sessions_by_creator_paginated (line 1509) | async def get_platform_sessions_by_creator_paginated(
method update_platform_session (line 1543) | async def update_platform_session(
method delete_platform_session (line 1562) | async def delete_platform_session(self, session_id: str) -> None:
method create_chatui_project (line 1577) | async def create_chatui_project(
method get_chatui_project_by_id (line 1599) | async def get_chatui_project_by_id(self, project_id: str) -> ChatUIPro...
method get_chatui_projects_by_creator (line 1610) | async def get_chatui_projects_by_creator(
method update_chatui_project (line 1629) | async def update_chatui_project(
method delete_chatui_project (line 1654) | async def delete_chatui_project(self, project_id: str) -> None:
method add_session_to_project (line 1672) | async def add_session_to_project(
method remove_session_from_project (line 1697) | async def remove_session_from_project(self, session_id: str) -> None:
method get_project_sessions (line 1708) | async def get_project_sessions(
method get_project_by_session (line 1732) | async def get_project_by_session(
method create_cron_job (line 1756) | async def create_cron_job(
method update_cron_job (line 1793) | async def update_cron_job(
method delete_cron_job (line 1844) | async def delete_cron_job(self, job_id: str) -> None:
method get_cron_job (line 1852) | async def get_cron_job(self, job_id: str) -> CronJob | None:
method list_cron_jobs (line 1860) | async def list_cron_jobs(self, job_type: str | None = None) -> list[Cr...
FILE: astrbot/core/db/vec_db/base.py
class Result (line 6) | class Result:
class BaseVecDB (line 11) | class BaseVecDB:
method initialize (line 12) | async def initialize(self) -> None:
method insert (line 16) | async def insert(
method insert_batch (line 26) | async def insert_batch(
method retrieve (line 45) | async def retrieve(
method delete (line 63) | async def delete(self, doc_id: str) -> bool:
method close (line 73) | async def close(self): ...
FILE: astrbot/core/db/vec_db/faiss_impl/document_storage.py
class BaseDocModel (line 14) | class BaseDocModel(SQLModel, table=False):
class Document (line 18) | class Document(BaseDocModel, table=True):
class DocumentStorage (line 35) | class DocumentStorage:
method __init__ (line 36) | def __init__(self, db_path: str) -> None:
method initialize (line 46) | async def initialize(self) -> None:
method connect (line 83) | async def connect(self) -> None:
method get_session (line 98) | async def get_session(self):
method get_documents (line 103) | async def get_documents(
method insert_document (line 151) | async def insert_document(self, doc_id: str, text: str, metadata: dict...
method insert_documents_batch (line 177) | async def insert_documents_batch(
method delete_document_by_doc_id (line 214) | async def delete_document_by_doc_id(self, doc_id: str) -> None:
method get_document_by_doc_id (line 231) | async def get_document_by_doc_id(self, doc_id: str):
method update_document_by_doc_id (line 252) | async def update_document_by_doc_id(self, doc_id: str, new_text: str) ...
method delete_documents (line 272) | async def delete_documents(self, metadata_filters: dict) -> None:
method count_documents (line 299) | async def count_documents(self, metadata_filters: dict | None = None) ...
method get_user_ids (line 326) | async def get_user_ids(self) -> list[str]:
method _document_to_dict (line 343) | def _document_to_dict(self, document: Document) -> dict:
method tuple_to_dict (line 366) | async def tuple_to_dict(self, row):
method close (line 387) | async def close(self) -> None:
FILE: astrbot/core/db/vec_db/faiss_impl/embedding_storage.py
class EmbeddingStorage (line 12) | class EmbeddingStorage:
method __init__ (line 13) | def __init__(self, dimension: int, path: str | None = None) -> None:
method insert (line 23) | async def insert(self, vector: np.ndarray, id: int) -> None:
method insert_batch (line 41) | async def insert_batch(self, vectors: np.ndarray, ids: list[int]) -> N...
method search (line 59) | async def search(self, vector: np.ndarray, k: int) -> tuple:
method delete (line 74) | async def delete(self, ids: list[int]) -> None:
method save_index (line 86) | async def save_index(self) -> None:
FILE: astrbot/core/db/vec_db/faiss_impl/sqlite_init.sql
type documents (line 2) | CREATE TABLE documents (
type idx_documents_user_id (line 16) | CREATE INDEX idx_documents_user_id ON documents(user_id)
type idx_documents_group_id (line 17) | CREATE INDEX idx_documents_group_id ON documents(group_id)
FILE: astrbot/core/db/vec_db/faiss_impl/vec_db.py
class FaissVecDB (line 14) | class FaissVecDB(BaseVecDB):
method __init__ (line 17) | def __init__(
method initialize (line 35) | async def initialize(self) -> None:
method insert (line 38) | async def insert(
method insert_batch (line 58) | async def insert_batch(
method retrieve (line 103) | async def retrieve(
method delete (line 168) | async def delete(self, doc_id: str) -> None:
method close (line 180) | async def close(self) -> None:
method count_documents (line 183) | async def count_documents(self, metadata_filter: dict | None = None) -...
method delete_documents (line 195) | async def delete_documents(self, metadata_filters: dict) -> None:
FILE: astrbot/core/event_bus.py
class EventBus (line 23) | class EventBus:
method __init__ (line 26) | def __init__(
method dispatch (line 37) | async def dispatch(self) -> None:
method _print_event (line 52) | def _print_event(self, event: AstrMessageEvent, conf_name: str) -> None:
FILE: astrbot/core/exceptions.py
class AstrBotError (line 4) | class AstrBotError(Exception):
class ProviderNotFoundError (line 8) | class ProviderNotFoundError(AstrBotError):
FILE: astrbot/core/file_token_service.py
class FileTokenService (line 9) | class FileTokenService:
method __init__ (line 12) | def __init__(self, default_timeout: float = 300) -> None:
method _cleanup_expired_tokens (line 17) | async def _cleanup_expired_tokens(self) -> None:
method check_token_expired (line 26) | async def check_token_expired(self, file_token: str) -> bool:
method register_file (line 31) | async def register_file(self, file_path: str, timeout: float | None = ...
method handle_file (line 75) | async def handle_file(self, file_token: str) -> str:
FILE: astrbot/core/initial_loader.py
class InitialLoader (line 17) | class InitialLoader:
method __init__ (line 20) | def __init__(self, db: BaseDatabase, log_broker: LogBroker) -> None:
method start (line 26) | async def start(self) -> None:
FILE: astrbot/core/knowledge_base/chunking/base.py
class BaseChunker (line 9) | class BaseChunker(ABC):
method chunk (line 16) | async def chunk(self, text: str, **kwargs) -> list[str]:
FILE: astrbot/core/knowledge_base/chunking/fixed_size.py
class FixedSizeChunker (line 9) | class FixedSizeChunker(BaseChunker):
method __init__ (line 15) | def __init__(self, chunk_size: int = 512, chunk_overlap: int = 50) -> ...
method chunk (line 26) | async def chunk(self, text: str, **kwargs) -> list[str]:
FILE: astrbot/core/knowledge_base/chunking/recursive.py
class RecursiveCharacterChunker (line 6) | class RecursiveCharacterChunker(BaseChunker):
method __init__ (line 7) | def __init__(
method chunk (line 42) | async def chunk(self, text: str, **kwargs) -> list[str]:
method _split_by_character (line 137) | def _split_by_character(
FILE: astrbot/core/knowledge_base/kb_db_sqlite.py
class KBSQLiteDatabase (line 19) | class KBSQLiteDatabase:
method __init__ (line 20) | def __init__(self, db_path: str | None = None) -> None:
method get_db (line 52) | async def get_db(self):
method initialize (line 63) | async def initialize(self) -> None:
method migrate_to_v1 (line 80) | async def migrate_to_v1(self) -> None:
method close (line 167) | async def close(self) -> None:
method get_kb_by_id (line 172) | async def get_kb_by_id(self, kb_id: str) -> KnowledgeBase | None:
method get_kb_by_name (line 179) | async def get_kb_by_name(self, kb_name: str) -> KnowledgeBase | None:
method list_kbs (line 186) | async def list_kbs(self, offset: int = 0, limit: int = 100) -> list[Kn...
method count_kbs (line 198) | async def count_kbs(self) -> int:
method get_document_by_id (line 207) | async def get_document_by_id(self, doc_id: str) -> KBDocument | None:
method list_documents_by_kb (line 214) | async def list_documents_by_kb(
method count_documents_by_kb (line 232) | async def count_documents_by_kb(self, kb_id: str) -> int:
method get_document_with_metadata (line 241) | async def get_document_with_metadata(self, doc_id: str) -> dict | None:
method get_documents_with_metadata_batch (line 259) | async def get_documents_with_metadata_batch(
method delete_document_by_id (line 299) | async def delete_document_by_id(self, doc_id: str, vec_db: FaissVecDB)...
method list_media_by_doc (line 313) | async def list_media_by_doc(self, doc_id: str) -> list[KBMedia]:
method get_media_by_id (line 320) | async def get_media_by_id(self, media_id: str) -> KBMedia | None:
method update_kb_stats (line 327) | async def update_kb_stats(self, kb_id: str, vec_db: FaissVecDB) -> None:
FILE: astrbot/core/knowledge_base/kb_helper.py
class RateLimiter (line 31) | class RateLimiter:
method __init__ (line 34) | def __init__(self, max_rpm: int) -> None:
method __aenter__ (line 39) | async def __aenter__(self):
method __aexit__ (line 51) | async def __aexit__(self, exc_type, exc_val, exc_tb):
function _repair_and_translate_chunk_with_retry (line 55) | async def _repair_and_translate_chunk_with_retry(
class KBHelper (line 108) | class KBHelper:
method __init__ (line 112) | def __init__(
method initialize (line 133) | async def initialize(self) -> None:
method get_ep (line 136) | async def get_ep(self) -> EmbeddingProvider:
method get_rp (line 148) | async def get_rp(self) -> RerankProvider | None:
method _ensure_vec_db (line 160) | async def _ensure_vec_db(self) -> FaissVecDB:
method delete_vec_db (line 177) | async def delete_vec_db(self) -> None:
method terminate (line 185) | async def terminate(self) -> None:
method upload_document (line 189) | async def upload_document(
method list_documents (line 349) | async def list_documents(
method get_document (line 358) | async def get_document(self, doc_id: str) -> KBDocument | None:
method delete_document (line 363) | async def delete_document(self, doc_id: str) -> None:
method delete_chunk (line 375) | async def delete_chunk(self, chunk_id: str, doc_id: str) -> None:
method refresh_kb (line 386) | async def refresh_kb(self) -> None:
method refresh_document (line 392) | async def refresh_document(self, doc_id: str) -> None:
method get_chunks_by_doc_id (line 405) | async def get_chunks_by_doc_id(
method get_chunk_count_by_doc_id (line 433) | async def get_chunk_count_by_doc_id(self, doc_id: str) -> int:
method _save_media (line 439) | async def _save_media(
method upload_from_url (line 470) | async def upload_from_url(
method _clean_and_rechunk_content (line 561) | async def _clean_and_rechunk_content(
FILE: astrbot/core/knowledge_base/kb_mgr.py
class KnowledgeBaseManager (line 23) | class KnowledgeBaseManager:
method __init__ (line 27) | def __init__(
method initialize (line 37) | async def initialize(self) -> None:
method _init_kb_database (line 62) | async def _init_kb_database(self) -> None:
method load_kbs (line 68) | async def load_kbs(self) -> None:
method create_kb (line 82) | async def create_kb(
method get_kb (line 131) | async def get_kb(self, kb_id: str) -> KBHelper | None:
method get_kb_by_name (line 136) | async def get_kb_by_name(self, kb_name: str) -> KBHelper | None:
method delete_kb (line 143) | async def delete_kb(self, kb_id: str) -> bool:
method list_kbs (line 157) | async def list_kbs(self) -> list[KnowledgeBase]:
method update_kb (line 162) | async def update_kb(
method retrieve (line 208) | async def retrieve(
method _format_context (line 258) | def _format_context(self, results: list[RetrievalResult]) -> str:
method terminate (line 279) | async def terminate(self) -> None:
method upload_from_url (line 296) | async def upload_from_url(
FILE: astrbot/core/knowledge_base/models.py
class BaseKBModel (line 7) | class BaseKBModel(SQLModel, table=False):
class KnowledgeBase (line 11) | class KnowledgeBase(BaseKBModel, table=True):
class KBDocument (line 59) | class KBDocument(BaseKBModel, table=True):
class KBMedia (line 93) | class KBMedia(BaseKBModel, table=True):
FILE: astrbot/core/knowledge_base/parsers/base.py
class MediaItem (line 11) | class MediaItem:
class ParseResult (line 24) | class ParseResult:
class BaseParser (line 34) | class BaseParser(ABC):
method parse (line 41) | async def parse(self, file_content: bytes, file_name: str) -> ParseRes...
FILE: astrbot/core/knowledge_base/parsers/markitdown_parser.py
class MarkitdownParser (line 12) | class MarkitdownParser(BaseParser):
method parse (line 15) | async def parse(self, file_content: bytes, file_name: str) -> ParseRes...
FILE: astrbot/core/knowledge_base/parsers/pdf_parser.py
class PDFParser (line 17) | class PDFParser(BaseParser):
method parse (line 23) | async def parse(self, file_content: bytes, file_name: str) -> ParseRes...
FILE: astrbot/core/knowledge_base/parsers/text_parser.py
class TextParser (line 9) | class TextParser(BaseParser):
method parse (line 15) | async def parse(self, file_content: bytes, file_name: str) -> ParseRes...
FILE: astrbot/core/knowledge_base/parsers/url_parser.py
class URLExtractor (line 6) | class URLExtractor:
method __init__ (line 9) | def __init__(self, tavily_keys: list[str]) -> None:
method _get_tavily_key (line 23) | async def _get_tavily_key(self) -> str:
method extract_text_from_url (line 30) | async def extract_text_from_url(self, url: str) -> str:
function extract_text_from_url (line 91) | async def extract_text_from_url(url: str, tavily_keys: list[str]) -> str:
FILE: astrbot/core/knowledge_base/parsers/util.py
function select_parser (line 4) | async def select_parser(ext: str) -> BaseParser:
FILE: astrbot/core/knowledge_base/retrieval/manager.py
class RetrievalResult (line 21) | class RetrievalResult:
class RetrievalManager (line 34) | class RetrievalManager:
method __init__ (line 42) | def __init__(
method retrieve (line 61) | async def retrieve(
method _dense_retrieve (line 196) | async def _dense_retrieve(
method _rerank (line 242) | async def _rerank(
FILE: astrbot/core/knowledge_base/retrieval/rank_fusion.py
class FusedResult (line 15) | class FusedResult:
class RankFusion (line 26) | class RankFusion:
method __init__ (line 34) | def __init__(self, kb_db: KBSQLiteDatabase, k: int = 60) -> None:
method fuse (line 45) | async def fuse(
FILE: astrbot/core/knowledge_base/retrieval/sparse_retriever.py
class SparseResult (line 18) | class SparseResult:
class SparseRetriever (line 29) | class SparseRetriever:
method __init__ (line 37) | def __init__(self, kb_db: KBSQLiteDatabase) -> None:
method retrieve (line 55) | async def retrieve(
FILE: astrbot/core/log.py
class _RecordEnricherFilter (line 23) | class _RecordEnricherFilter(logging.Filter):
method filter (line 26) | def filter(self, record: logging.LogRecord) -> bool:
class _QueueAnsiColorFilter (line 38) | class _QueueAnsiColorFilter(logging.Filter):
method filter (line 49) | def filter(self, record: logging.LogRecord) -> bool:
function _is_plugin_path (line 55) | def _is_plugin_path(pathname: str | None) -> bool:
function _get_short_level_name (line 62) | def _get_short_level_name(level_name: str) -> str:
function _build_source_file (line 73) | def _build_source_file(pathname: str | None) -> str:
function _patch_record (line 82) | def _patch_record(record: "Record") -> None:
class _LoguruInterceptHandler (line 96) | class _LoguruInterceptHandler(logging.Handler):
method emit (line 99) | def emit(self, record: logging.LogRecord) -> None:
class LogBroker (line 126) | class LogBroker:
method __init__ (line 129) | def __init__(self) -> None:
method register (line 133) | def register(self) -> Queue:
method unregister (line 138) | def unregister(self, q: Queue) -> None:
method publish (line 141) | def publish(self, log_entry: dict) -> None:
class LogQueueHandler (line 150) | class LogQueueHandler(logging.Handler):
method __init__ (line 153) | def __init__(self, log_broker: LogBroker) -> None:
method emit (line 157) | def emit(self, record: logging.LogRecord) -> None:
class LogManager (line 168) | class LogManager:
method _default_log_path (line 185) | def _default_log_path(cls) -> str:
method _resolve_log_path (line 189) | def _resolve_log_path(cls, configured_path: str | None) -> str:
method _setup_loguru (line 197) | def _setup_loguru(cls) -> None:
method _setup_root_bridge (line 216) | def _setup_root_bridge(cls) -> None:
method _ensure_logger_enricher_filter (line 232) | def _ensure_logger_enricher_filter(cls, logger: logging.Logger) -> None:
method _ensure_logger_intercept_handler (line 243) | def _ensure_logger_intercept_handler(cls, logger: logging.Logger) -> N...
method GetLogger (line 254) | def GetLogger(cls, log_name: str = "default") -> logging.Logger:
method set_queue_handler (line 266) | def set_queue_handler(cls, logger: logging.Logger, log_broker: LogBrok...
method _remove_sink (line 286) | def _remove_sink(cls, sink_id: int | None) -> None:
method _add_file_sink (line 295) | def _add_file_sink(
method configure_logger (line 340) | def configure_logger(
method configure_trace_logger (line 384) | def configure_trace_logger(cls, config: dict | None) -> None:
FILE: astrbot/core/message/components.py
class ComponentType (line 42) | class ComponentType(str, Enum):
class BaseMessageComponent (line 70) | class BaseMessageComponent(BaseModel):
method __init__ (line 73) | def __init__(self, **kwargs) -> None:
method toDict (line 76) | def toDict(self):
method to_dict (line 86) | async def to_dict(self) -> dict:
class Plain (line 91) | class Plain(BaseMessageComponent):
method __init__ (line 96) | def __init__(self, text: str, convert: bool = True, **_) -> None:
method toDict (line 99) | def toDict(self) -> dict:
method to_dict (line 102) | async def to_dict(self) -> dict:
class Face (line 106) | class Face(BaseMessageComponent):
method __init__ (line 110) | def __init__(self, **_) -> None:
class Record (line 114) | class Record(BaseMessageComponent):
method __init__ (line 127) | def __init__(self, file: str | None, **_) -> None:
method fromFileSystem (line 135) | def fromFileSystem(path, **_):
method fromURL (line 139) | def fromURL(url: str, **_):
method fromBase64 (line 145) | def fromBase64(bs64_data: str, **_):
method convert_to_file_path (line 148) | async def convert_to_file_path(self) -> str:
method convert_to_base64 (line 175) | async def convert_to_base64(self) -> str:
method register_to_file_service (line 199) | async def register_to_file_service(self) -> str:
class Video (line 223) | class Video(BaseMessageComponent):
method __init__ (line 231) | def __init__(self, file: str, **_) -> None:
method fromFileSystem (line 235) | def fromFileSystem(path, **_):
method fromURL (line 239) | def fromURL(url: str, **_):
method convert_to_file_path (line 244) | async def convert_to_file_path(self) -> str:
method register_to_file_service (line 266) | async def register_to_file_service(self) -> str:
method to_dict (line 289) | async def to_dict(self):
class At (line 309) | class At(BaseMessageComponent):
method __init__ (line 314) | def __init__(self, **_) -> None:
method toDict (line 317) | def toDict(self):
class AtAll (line 324) | class AtAll(At):
method __init__ (line 327) | def __init__(self, **_) -> None:
class RPS (line 331) | class RPS(BaseMessageComponent): # TODO
method __init__ (line 334) | def __init__(self, **_) -> None:
class Dice (line 338) | class Dice(BaseMessageComponent): # TODO
method __init__ (line 341) | def __init__(self, **_) -> None:
class Shake (line 345) | class Shake(BaseMessageComponent): # TODO
method __init__ (line 348) | def __init__(self, **_) -> None:
class Share (line 352) | class Share(BaseMessageComponent):
method __init__ (line 359) | def __init__(self, **_) -> None:
class Contact (line 363) | class Contact(BaseMessageComponent): # TODO
method __init__ (line 368) | def __init__(self, **_) -> None:
class Location (line 372) | class Location(BaseMessageComponent): # TODO
method __init__ (line 379) | def __init__(self, **_) -> None:
class Music (line 383) | class Music(BaseMessageComponent):
method __init__ (line 393) | def __init__(self, **_) -> None:
class Image (line 400) | class Image(BaseMessageComponent):
method __init__ (line 413) | def __init__(self, file: str | None, **_) -> None:
method fromURL (line 417) | def fromURL(url: str, **_):
method fromFileSystem (line 423) | def fromFileSystem(path, **_):
method fromBase64 (line 427) | def fromBase64(base64: str, **_):
method fromBytes (line 431) | def fromBytes(byte: bytes):
method fromIO (line 435) | def fromIO(IO):
method convert_to_file_path (line 438) | async def convert_to_file_path(self) -> str:
method convert_to_base64 (line 466) | async def convert_to_base64(self) -> str:
method register_to_file_service (line 491) | async def register_to_file_service(self) -> str:
class Reply (line 515) | class Reply(BaseMessageComponent):
method __init__ (line 537) | def __init__(self, **_) -> None:
class Poke (line 541) | class Poke(BaseMessageComponent):
method __init__ (line 547) | def __init__(self, poke_type: str | int | None = None, **_) -> None:
method target_id (line 556) | def target_id(self) -> str | None:
method toDict (line 566) | def toDict(self):
class Forward (line 574) | class Forward(BaseMessageComponent):
method __init__ (line 578) | def __init__(self, **_) -> None:
class Node (line 582) | class Node(BaseMessageComponent):
method __init__ (line 593) | def __init__(self, content: list[BaseMessageComponent], **_) -> None:
method to_dict (line 599) | async def to_dict(self):
class Nodes (line 636) | class Nodes(BaseMessageComponent):
method __init__ (line 640) | def __init__(self, nodes: list[Node], **_) -> None:
method toDict (line 643) | def toDict(self):
method to_dict (line 653) | async def to_dict(self) -> dict:
class Json (line 662) | class Json(BaseMessageComponent):
method __init__ (line 666) | def __init__(self, data: str | dict, **_) -> None:
class Unknown (line 672) | class Unknown(BaseMessageComponent):
class File (line 677) | class File(BaseMessageComponent):
method __init__ (line 685) | def __init__(self, name: str, file: str = "", url: str = "") -> None:
method file (line 690) | def file(self) -> str:
method file (line 724) | def file(self, value: str) -> None:
method get_file (line 736) | async def get_file(self, allow_return_url: bool = False) -> str:
method _download_file (line 784) | async def _download_file(self) -> None:
method register_to_file_service (line 798) | async def register_to_file_service(self) -> str:
method to_dict (line 821) | async def to_dict(self):
class WechatEmoji (line 842) | class WechatEmoji(BaseMessageComponent):
method __init__ (line 848) | def __init__(self, **_) -> None:
FILE: astrbot/core/message/message_event_result.py
class MessageChain (line 18) | class MessageChain:
method message (line 33) | def message(self, message: str):
method at (line 44) | def at(self, name: str, qq: str | int):
method at_all (line 55) | def at_all(self):
method error (line 67) | def error(self, message: str):
method url_image (line 77) | def url_image(self, url: str):
method file_image (line 90) | def file_image(self, path: str):
method base64_image (line 102) | def base64_image(self, base64_str: str):
method use_t2i (line 111) | def use_t2i(self, use_t2i: bool):
method get_plain_text (line 121) | def get_plain_text(self, with_other_comps_mark: bool = False) -> str:
method squash_plain (line 142) | def squash_plain(self):
class EventResultType (line 167) | class EventResultType(enum.Enum):
class ResultContentType (line 180) | class ResultContentType(enum.Enum):
class MessageEventResult (line 196) | class MessageEventResult(MessageChain):
method stop_event (line 218) | def stop_event(self) -> "MessageEventResult":
method continue_event (line 223) | def continue_event(self) -> "MessageEventResult":
method is_stopped (line 228) | def is_stopped(self) -> bool:
method set_async_stream (line 232) | def set_async_stream(self, stream: AsyncGenerator) -> "MessageEventRes...
method set_result_content_type (line 237) | def set_result_content_type(self, typ: ResultContentType) -> "MessageE...
method is_llm_result (line 247) | def is_llm_result(self) -> bool:
method is_model_result (line 251) | def is_model_result(self) -> bool:
FILE: astrbot/core/persona_error_reply.py
function normalize_persona_custom_error_message (line 9) | def normalize_persona_custom_error_message(value: object) -> str | None:
function extract_persona_custom_error_message_from_persona (line 17) | def extract_persona_custom_error_message_from_persona(
function extract_persona_custom_error_message_from_event (line 26) | def extract_persona_custom_error_message_from_event(event: Any) -> str |...
function set_persona_custom_error_message_on_event (line 37) | def set_persona_custom_error_message_on_event(
function resolve_persona_custom_error_message (line 50) | async def resolve_persona_custom_error_message(
function resolve_event_conversation_persona_id (line 72) | async def resolve_event_conversation_persona_id(
FILE: astrbot/core/persona_mgr.py
class PersonaManager (line 22) | class PersonaManager:
method __init__ (line 23) | def __init__(self, db_helper: BaseDatabase, acm: AstrBotConfigManager)...
method initialize (line 35) | async def initialize(self) -> None:
method get_persona (line 40) | async def get_persona(self, persona_id: str):
method get_persona_v3_by_id (line 47) | def get_persona_v3_by_id(self, persona_id: str | None) -> Personality ...
method get_default_persona_v3 (line 63) | async def get_default_persona_v3(
method resolve_selected_persona (line 75) | async def resolve_selected_persona(
method delete_persona (line 129) | async def delete_persona(self, persona_id: str) -> None:
method update_persona (line 137) | async def update_persona(
method get_all_personas (line 172) | async def get_all_personas(self) -> list[Persona]:
method get_personas_by_folder (line 176) | async def get_personas_by_folder(
method move_persona_to_folder (line 186) | async def move_persona_to_folder(
method create_folder (line 207) | async def create_folder(
method get_folder (line 222) | async def get_folder(self, folder_id: str) -> PersonaFolder | None:
method get_folders (line 226) | async def get_folders(self, parent_id: str | None = None) -> list[Pers...
method get_all_folders (line 234) | async def get_all_folders(self) -> list[PersonaFolder]:
method update_folder (line 238) | async def update_folder(
method delete_folder (line 255) | async def delete_folder(self, folder_id: str) -> None:
method batch_update_sort_order (line 262) | async def batch_update_sort_order(self, items: list[dict]) -> None:
method get_folder_tree (line 276) | async def get_folder_tree(self) -> list[dict]:
method create_persona (line 315) | async def create_persona(
method get_v3_persona_data (line 353) | def get_v3_persona_data(
FILE: astrbot/core/pipeline/__init__.py
function __getattr__ (line 98) | def __getattr__(name: str) -> Any:
function __dir__ (line 108) | def __dir__() -> list[str]:
FILE: astrbot/core/pipeline/bootstrap.py
function ensure_builtin_stages_registered (line 34) | def ensure_builtin_stages_registered() -> None:
FILE: astrbot/core/pipeline/content_safety_check/stage.py
class ContentSafetyCheckStage (line 13) | class ContentSafetyCheckStage(Stage):
method initialize (line 19) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 23) | async def process(
FILE: astrbot/core/pipeline/content_safety_check/strategies/__init__.py
class ContentSafetyStrategy (line 4) | class ContentSafetyStrategy(abc.ABC):
method check (line 6) | def check(self, content: str) -> tuple[bool, str]:
FILE: astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py
class BaiduAipStrategy (line 10) | class BaiduAipStrategy(ContentSafetyStrategy):
method __init__ (line 11) | def __init__(self, appid: str, ak: str, sk: str) -> None:
method check (line 17) | def check(self, content: str) -> tuple[bool, str]:
FILE: astrbot/core/pipeline/content_safety_check/strategies/keywords.py
class KeywordsStrategy (line 6) | class KeywordsStrategy(ContentSafetyStrategy):
method __init__ (line 7) | def __init__(self, extra_keywords: list) -> None:
method check (line 20) | def check(self, content: str) -> tuple[bool, str]:
FILE: astrbot/core/pipeline/content_safety_check/strategies/strategy.py
class StrategySelector (line 6) | class StrategySelector:
method __init__ (line 7) | def __init__(self, config: dict) -> None:
method check (line 29) | def check(self, content: str) -> tuple[bool, str]:
FILE: astrbot/core/pipeline/context.py
class PipelineContext (line 15) | class PipelineContext:
FILE: astrbot/core/pipeline/context_utils.py
function call_handler (line 12) | async def call_handler(
function call_event_hook (line 75) | async def call_event_hook(
FILE: astrbot/core/pipeline/preprocess_stage/stage.py
class PreProcessStage (line 15) | class PreProcessStage(Stage):
method initialize (line 16) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 24) | async def process(
FILE: astrbot/core/pipeline/process_stage/follow_up.py
class FollowUpCapture (line 23) | class FollowUpCapture:
function _event_follow_up_text (line 30) | def _event_follow_up_text(event: AstrMessageEvent) -> str:
function register_active_runner (line 37) | def register_active_runner(umo: str, runner: AgentRunner) -> None:
function unregister_active_runner (line 41) | def unregister_active_runner(umo: str, runner: AgentRunner) -> None:
function _get_follow_up_order_state (line 46) | def _get_follow_up_order_state(umo: str) -> dict[str, object]:
function _advance_follow_up_turn_locked (line 62) | def _advance_follow_up_turn_locked(state: dict[str, object]) -> None:
function _allocate_follow_up_order (line 80) | def _allocate_follow_up_order(umo: str) -> int:
function _mark_follow_up_consumed (line 92) | async def _mark_follow_up_consumed(umo: str, seq: int) -> None:
function _activate_and_wait_follow_up_turn (line 111) | async def _activate_and_wait_follow_up_turn(umo: str, seq: int) -> None:
function _finish_follow_up_turn (line 132) | async def _finish_follow_up_turn(umo: str, seq: int) -> None:
function _monitor_follow_up_ticket (line 150) | async def _monitor_follow_up_ticket(
function try_capture_follow_up (line 161) | def try_capture_follow_up(event: AstrMessageEvent) -> FollowUpCapture | ...
function prepare_follow_up_capture (line 203) | async def prepare_follow_up_capture(capture: FollowUpCapture) -> tuple[b...
function finalize_follow_up_capture (line 213) | async def finalize_follow_up_capture(
FILE: astrbot/core/pipeline/process_stage/method/agent_request.py
class AgentRequestSubStage (line 13) | class AgentRequestSubStage(Stage):
method initialize (line 14) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 34) | async def process(self, event: AstrMessageEvent) -> AsyncGenerator[Non...
FILE: astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py
class InternalAgentSubStage (line 47) | class InternalAgentSubStage(Stage):
method initialize (line 48) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 141) | async def process(
method _save_to_history (line 387) | async def _save_to_history(
FILE: astrbot/core/pipeline/process_stage/method/agent_sub_stages/third_party.py
function run_third_party_agent (line 62) | async def run_third_party_agent(
class _RunnerResultAggregator (line 94) | class _RunnerResultAggregator:
method __init__ (line 95) | def __init__(self) -> None:
method add_chunk (line 99) | def add_chunk(self, chain: MessageChain, is_error: bool) -> None:
method finalize (line 104) | def finalize(
function _start_stream_watchdog (line 124) | def _start_stream_watchdog(
function _close_runner_if_supported (line 151) | async def _close_runner_if_supported(runner: "BaseAgentRunner") -> None:
class ThirdPartyAgentSubStage (line 164) | class ThirdPartyAgentSubStage(Stage):
method initialize (line 165) | async def initialize(self, ctx: PipelineContext) -> None:
method _resolve_persona_custom_error_message (line 189) | async def _resolve_persona_custom_error_message(
method _handle_streaming_response (line 207) | async def _handle_streaming_response(
method _handle_non_streaming_response (line 254) | async def _handle_non_streaming_response(
method process (line 289) | async def process(
FILE: astrbot/core/pipeline/process_stage/method/star_request.py
class StarRequestSubStage (line 17) | class StarRequestSubStage(Stage):
method initialize (line 18) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 23) | async def process(
FILE: astrbot/core/pipeline/process_stage/stage.py
class ProcessStage (line 14) | class ProcessStage(Stage):
method initialize (line 15) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 28) | async def process(
FILE: astrbot/core/pipeline/rate_limit_check/stage.py
class RateLimitStage (line 15) | class RateLimitStage(Stage):
method __init__ (line 22) | def __init__(self) -> None:
method initialize (line 31) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 43) | async def process(
method _remove_expired_timestamps (line 85) | def _remove_expired_timestamps(
FILE: astrbot/core/pipeline/respond/stage.py
class RespondStage (line 19) | class RespondStage(Stage):
method initialize (line 53) | async def initialize(self, ctx: PipelineContext) -> None:
method _word_cnt (line 91) | async def _word_cnt(self, text: str) -> int:
method _calc_comp_interval (line 99) | async def _calc_comp_interval(self, comp: BaseMessageComponent) -> float:
method _is_empty_message_chain (line 110) | async def _is_empty_message_chain(self, chain: list[BaseMessageCompone...
method is_seg_reply_required (line 131) | def is_seg_reply_required(self, event: AstrMessageEvent) -> bool:
method _extract_comp (line 150) | def _extract_comp(
method process (line 170) | async def process(
FILE: astrbot/core/pipeline/result_decorate/stage.py
class ResultDecorateStage (line 22) | class ResultDecorateStage(Stage):
method initialize (line 23) | async def initialize(self, ctx: PipelineContext) -> None:
method _split_text_by_words (line 104) | def _split_text_by_words(self, text: str) -> list[str]:
method process (line 126) | async def process(
FILE: astrbot/core/pipeline/scheduler.py
class PipelineScheduler (line 17) | class PipelineScheduler:
method __init__ (line 20) | def __init__(self, context: PipelineContext) -> None:
method initialize (line 28) | async def initialize(self) -> None:
method _process_stages (line 35) | async def _process_stages(self, event: AstrMessageEvent, from_stage=0)...
method execute (line 78) | async def execute(self, event: AstrMessageEvent) -> None:
FILE: astrbot/core/pipeline/session_status_check/stage.py
class SessionStatusCheckStage (line 12) | class SessionStatusCheckStage(Stage):
method initialize (line 15) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 19) | async def process(
FILE: astrbot/core/pipeline/stage.py
function register_stage (line 13) | def register_stage(cls):
class Stage (line 19) | class Stage(abc.ABC):
method initialize (line 23) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 33) | async def process(
FILE: astrbot/core/pipeline/waking_check/stage.py
function build_unique_session_id (line 28) | def build_unique_session_id(event: AstrMessageEvent) -> str | None:
class WakingCheckStage (line 35) | class WakingCheckStage(Stage):
method initialize (line 45) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 76) | async def process(
FILE: astrbot/core/pipeline/whitelist_check/stage.py
class WhitelistCheckStage (line 12) | class WhitelistCheckStage(Stage):
method initialize (line 15) | async def initialize(self, ctx: PipelineContext) -> None:
method process (line 31) | async def process(
FILE: astrbot/core/platform/astr_message_event.py
class AstrMessageEvent (line 34) | class AstrMessageEvent(abc.ABC):
method __init__ (line 35) | def __init__(
method unified_msg_origin (line 99) | def unified_msg_origin(self) -> str:
method unified_msg_origin (line 104) | def unified_msg_origin(self, value: str) -> None:
method session_id (line 110) | def session_id(self) -> str:
method session_id (line 115) | def session_id(self, value: str) -> None:
method get_platform_name (line 119) | def get_platform_name(self):
method get_platform_id (line 126) | def get_platform_id(self):
method get_message_str (line 133) | def get_message_str(self) -> str:
method _outline_chain (line 137) | def _outline_chain(self, chain: list[BaseMessageComponent] | None) -> ...
method get_message_outline (line 167) | def get_message_outline(self) -> str:
method get_messages (line 174) | def get_messages(self) -> list[BaseMessageComponent]:
method get_message_type (line 178) | def get_message_type(self) -> MessageType:
method get_session_id (line 185) | def get_session_id(self) -> str:
method get_group_id (line 189) | def get_group_id(self) -> str:
method get_self_id (line 193) | def get_self_id(self) -> str:
method get_sender_id (line 197) | def get_sender_id(self) -> str:
method get_sender_name (line 204) | def get_sender_name(self) -> str:
method set_extra (line 216) | def set_extra(self, key, value) -> None:
method get_extra (line 220) | def get_extra(self, key: str | None = None, default=None) -> Any:
method clear_extra (line 226) | def clear_extra(self) -> None:
method is_private_chat (line 231) | def is_private_chat(self) -> bool:
method is_wake_up (line 235) | def is_wake_up(self) -> bool:
method is_admin (line 239) | def is_admin(self) -> bool:
method process_buffer (line 243) | async def process_buffer(self, buffer: str, pattern: re.Pattern) -> str:
method send_streaming (line 255) | async def send_streaming(
method send_typing (line 269) | async def send_typing(self) -> None:
method _pre_send (line 275) | async def _pre_send(self) -> None:
method _post_send (line 278) | async def _post_send(self) -> None:
method set_result (line 281) | def set_result(self, result: MessageEventResult | str) -> None:
method stop_event (line 310) | def stop_event(self) -> None:
method continue_event (line 317) | def continue_event(self) -> None:
method is_stopped (line 324) | def is_stopped(self) -> bool:
method should_call_llm (line 330) | def should_call_llm(self, call_llm: bool) -> None:
method get_result (line 337) | def get_result(self) -> MessageEventResult | None:
method clear_result (line 341) | def clear_result(self) -> None:
method make_result (line 347) | def make_result(self) -> MessageEventResult:
method plain_result (line 362) | def plain_result(self, text: str) -> MessageEventResult:
method image_result (line 366) | def image_result(self, url_or_path: str) -> MessageEventResult:
method chain_result (line 375) | def chain_result(self, chain: list[BaseMessageComponent]) -> MessageEv...
method request_llm (line 383) | def request_llm(
method send (line 435) | async def send(self, message: MessageChain) -> None:
method react (line 454) | async def react(self, emoji: str) -> None:
method get_group (line 463) | async def get_group(self, group_id: str | None = None, **kwargs) -> Gr...
FILE: astrbot/core/platform/astrbot_message.py
class MessageMember (line 10) | class MessageMember:
method __str__ (line 14) | def __str__(self) -> str:
class Group (line 23) | class Group:
method __str__ (line 37) | def __str__(self) -> str:
class AstrBotMessage (line 50) | class AstrBotMessage:
method __init__ (line 64) | def __init__(self) -> None:
method __str__ (line 68) | def __str__(self) -> str:
method group_id (line 72) | def group_id(self) -> str:
method group_id (line 81) | def group_id(self, value: str | None) -> None:
FILE: astrbot/core/platform/manager.py
class PlatformTasks (line 17) | class PlatformTasks:
class PlatformManager (line 22) | class PlatformManager:
method __init__ (line 23) | def __init__(self, config: AstrBotConfig, event_queue: Queue) -> None:
method _is_valid_platform_id (line 38) | def _is_valid_platform_id(self, platform_id: str | None) -> bool:
method _sanitize_platform_id (line 43) | def _sanitize_platform_id(self, platform_id: str | None) -> tuple[str ...
method _start_platform_task (line 49) | def _start_platform_task(self, task_name: str, inst: Platform) -> None:
method _stop_platform_task (line 60) | async def _stop_platform_task(self, client_id: str) -> None:
method _terminate_inst_and_tasks (line 69) | async def _terminate_inst_and_tasks(self, inst: Platform) -> None:
method initialize (line 87) | async def initialize(self) -> None:
method load_platform (line 102) | async def load_platform(self, platform_config: dict) -> None:
method _task_wrapper (line 222) | async def _task_wrapper(
method reload (line 246) | async def reload(self, platform_config: dict) -> None:
method terminate_platform (line 257) | async def terminate_platform(self, platform_id: str) -> None:
method terminate (line 278) | async def terminate(self) -> None:
method get_insts (line 296) | def get_insts(self):
method get_all_stats (line 299) | def get_all_stats(self) -> dict:
FILE: astrbot/core/platform/message_session.py
class MessageSession (line 7) | class MessageSession:
method __str__ (line 18) | def __str__(self) -> str:
method __post_init__ (line 21) | def __post_init__(self):
method from_str (line 25) | def from_str(session_str: str):
FILE: astrbot/core/platform/message_type.py
class MessageType (line 4) | class MessageType(Enum):
FILE: astrbot/core/platform/platform.py
class PlatformStatus (line 18) | class PlatformStatus(Enum):
class PlatformError (line 28) | class PlatformError:
class Platform (line 36) | class Platform(abc.ABC):
method __init__ (line 37) | def __init__(self, config: dict, event_queue: Queue) -> None:
method status (line 51) | def status(self) -> PlatformStatus:
method status (line 56) | def status(self, value: PlatformStatus) -> None:
method errors (line 63) | def errors(self) -> list[PlatformError]:
method last_error (line 68) | def last_error(self) -> PlatformError | None:
method record_error (line 72) | def record_error(self, message: str, traceback_str: str | None = None)...
method clear_errors (line 77) | def clear_errors(self) -> None:
method unified_webhook (line 83) | def unified_webhook(self) -> bool:
method get_stats (line 90) | def get_stats(self) -> dict:
method run (line 120) | def run(self) -> Coroutine[Any, Any, None]:
method terminate (line 124) | async def terminate(self) -> None:
method meta (line 128) | def meta(self) -> PlatformMetadata:
method send_by_session (line 132) | async def send_by_session(
method commit_event (line 143) | def commit_event(self, event: AstrMessageEvent) -> None:
method get_client (line 147) | def get_client(self) -> object:
method webhook_callback (line 150) | async def webhook_callback(self, request: Any) -> Any:
FILE: astrbot/core/platform/platform_metadata.py
class PlatformMetadata (line 5) | class PlatformMetadata:
FILE: astrbot/core/platform/register.py
function register_platform_adapter (line 11) | def register_platform_adapter(
function unregister_platform_adapters_by_module (line 66) | def unregister_platform_adapters_by_module(module_path_prefix: str) -> l...
FILE: astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py
class AiocqhttpMessageEvent (line 22) | class AiocqhttpMessageEvent(AstrMessageEvent):
method __init__ (line 23) | def __init__(
method _from_segment_to_dict (line 35) | async def _from_segment_to_dict(segment: BaseMessageComponent) -> dict:
method _parse_onebot_json (line 70) | async def _parse_onebot_json(message_chain: MessageChain):
method _dispatch_send (line 90) | async def _dispatch_send(
method send_message (line 115) | async def send_message(
method send (line 168) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 184) | async def send_streaming(
method get_group (line 220) | async def get_group(self, group_id=None, **kwargs):
FILE: astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py
class AiocqhttpAdapter (line 35) | class AiocqhttpAdapter(Platform):
method __init__ (line 36) | def __init__(
method send_by_session (line 109) | async def send_by_session(
method convert_message (line 128) | async def convert_message(self, event: Event) -> AstrBotMessage | None:
method _convert_handle_request_event (line 143) | async def _convert_handle_request_event(self, event: Event) -> AstrBot...
method _convert_handle_notice_event (line 168) | async def _convert_handle_notice_event(self, event: Event) -> AstrBotM...
method _convert_handle_message_event (line 198) | async def _convert_handle_message_event(
method run (line 419) | def run(self) -> Awaitable[Any]:
method terminate (line 439) | async def terminate(self) -> None:
method _close_reverse_ws_connections (line 444) | async def _close_reverse_ws_connections(self) -> None:
method shutdown_trigger_placeholder (line 477) | async def shutdown_trigger_placeholder(self) -> None:
method meta (line 481) | def meta(self) -> PlatformMetadata:
method handle_msg (line 484) | async def handle_msg(self, message: AstrBotMessage) -> None:
method get_client (line 495) | def get_client(self) -> CQHttp:
FILE: astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py
class MyEventHandler (line 37) | class MyEventHandler(dingtalk_stream.EventHandler):
method process (line 38) | async def process(self, event: dingtalk_stream.EventMessage):
class DingtalkPlatformAdapter (line 52) | class DingtalkPlatformAdapter(Platform):
method __init__ (line 53) | def __init__(
method _id_to_sid (line 87) | def _id_to_sid(self, dingtalk_id: str | None) -> str:
method send_by_session (line 95) | async def send_by_session(
method send_with_session (line 124) | async def send_with_session(
method send_with_sesison (line 131) | async def send_with_sesison(
method meta (line 139) | def meta(self) -> PlatformMetadata:
method convert_msg (line 148) | async def convert_msg(
method _remember_sender_binding (line 289) | async def _remember_sender_binding(
method download_ding_file (line 315) | async def download_ding_file(
method get_access_token (line 368) | async def get_access_token(self) -> str:
method _get_sender_staff_id (line 393) | async def _get_sender_staff_id(self, session: MessageSesion) -> str:
method _send_group_message (line 406) | async def _send_group_message(
method _send_private_message (line 439) | async def _send_private_message(
method _safe_remove_file (line 472) | def _safe_remove_file(self, file_path: str | None) -> None:
method _prepare_voice_for_dingtalk (line 482) | async def _prepare_voice_for_dingtalk(self, input_path: str) -> tuple[...
method upload_media (line 496) | async def upload_media(self, file_path: str, media_type: str) -> str:
method upload_image (line 526) | async def upload_image(self, image: Image) -> str:
method _send_message_chain (line 530) | async def _send_message_chain(
method send_message_chain_to_group (line 658) | async def send_message_chain_to_group(
method send_message_chain_to_user (line 673) | async def send_message_chain_to_user(
method send_message_chain_with_incoming (line 688) | async def send_message_chain_with_incoming(
method handle_msg (line 735) | async def handle_msg(self, abm: AstrBotMessage) -> None:
method run (line 747) | async def run(self) -> None:
method terminate (line 766) | async def terminate(self) -> None:
method get_client (line 776) | def get_client(self):
FILE: astrbot/core/platform/sources/dingtalk/dingtalk_event.py
class DingtalkMessageEvent (line 7) | class DingtalkMessageEvent(AstrMessageEvent):
method __init__ (line 8) | def __init__(
method send (line 21) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 31) | async def send_streaming(self, generator, use_fallback: bool = False):
FILE: astrbot/core/platform/sources/discord/client.py
class DiscordBotClient (line 15) | class DiscordBotClient(discord.Bot):
method __init__ (line 18) | def __init__(self, token: str, proxy: str | None = None) -> None:
method on_ready (line 35) | async def on_ready(self) -> None:
method _create_message_data (line 54) | def _create_message_data(self, message: discord.Message) -> dict:
method _create_interaction_data (line 74) | def _create_interaction_data(self, interaction: discord.Interaction) -...
method on_message (line 96) | async def on_message(self, message: discord.Message) -> None:
method _extract_interaction_content (line 109) | def _extract_interaction_content(self, interaction: discord.Interactio...
method start_polling (line 133) | async def start_polling(self) -> None:
method close (line 138) | async def close(self) -> None:
FILE: astrbot/core/platform/sources/discord/components.py
class DiscordEmbed (line 7) | class DiscordEmbed(BaseMessageComponent):
method __init__ (line 12) | def __init__(
method to_discord_embed (line 32) | def to_discord_embed(self) -> discord.Embed:
class DiscordButton (line 61) | class DiscordButton(BaseMessageComponent):
method __init__ (line 66) | def __init__(
class DiscordReference (line 83) | class DiscordReference(BaseMessageComponent):
method __init__ (line 88) | def __init__(self, message_id: str, channel_id: str) -> None:
class DiscordView (line 93) | class DiscordView(BaseMessageComponent):
method __init__ (line 98) | def __init__(
method to_discord_view (line 106) | def to_discord_view(self) -> discord.ui.View:
FILE: astrbot/core/platform/sources/discord/discord_platform_adapter.py
class DiscordPlatformAdapter (line 40) | class DiscordPlatformAdapter(Platform):
method __init__ (line 41) | def __init__(
method send_by_session (line 59) | async def send_by_session(
method meta (line 114) | def meta(self) -> PlatformMetadata:
method run (line 125) | async def run(self) -> None:
method _get_message_type (line 167) | def _get_message_type(
method _get_channel_id (line 179) | def _get_channel_id(
method _convert_message_to_abm (line 185) | def _convert_message_to_abm(self, data: dict) -> AstrBotMessage:
method convert_message (line 249) | async def convert_message(self, data: dict) -> AstrBotMessage:
method handle_msg (line 254) | async def handle_msg(self, message: AstrBotMessage, followup_webhook=N...
method terminate (line 326) | async def terminate(self) -> None:
method register_handler (line 361) | def register_handler(self, handler_info) -> None:
method _collect_and_register_commands (line 365) | async def _collect_and_register_commands(self) -> None:
method _create_dynamic_callback (line 418) | def _create_dynamic_callback(self, cmd_name: str):
method _extract_command_info (line 478) | def _extract_command_info(
FILE: astrbot/core/platform/sources/discord/discord_platform_event.py
class DiscordViewComponent (line 28) | class DiscordViewComponent(BaseMessageComponent):
method __init__ (line 31) | def __init__(self, view: discord.ui.View) -> None:
class DiscordPlatformEvent (line 35) | class DiscordPlatformEvent(AstrMessageEvent):
method __init__ (line 36) | def __init__(
method send (line 49) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 100) | async def send_streaming(
method _get_channel (line 115) | async def _get_channel(
method _parse_to_discord (line 128) | async def _parse_to_discord(
method react (line 270) | async def react(self, emoji: str) -> None:
method is_slash_command (line 283) | def is_slash_command(self) -> bool:
method is_button_interaction (line 292) | def is_button_interaction(self) -> bool:
method get_interaction_custom_id (line 301) | def get_interaction_custom_id(self) -> str:
method is_mentioned (line 313) | def is_mentioned(self) -> bool:
method get_mention_clean_content (line 327) | def get_mention_clean_content(self) -> str:
FILE: astrbot/core/platform/sources/kook/kook_adapter.py
class KookPlatformAdapter (line 44) | class KookPlatformAdapter(Platform):
method __init__ (line 45) | def __init__(
method send_by_session (line 57) | async def send_by_session(
method meta (line 72) | def meta(self) -> PlatformMetadata:
method _should_ignore_event_by_bot_nickname (line 77) | def _should_ignore_event_by_bot_nickname(self, author_id: str) -> bool:
method _on_received (line 80) | async def _on_received(self, event: KookMessageEventData):
method run (line 98) | async def run(self):
method _main_loop (line 116) | async def _main_loop(self):
method _cleanup (line 175) | async def _cleanup(self):
method _parse_kmarkdown_text_message (line 194) | def _parse_kmarkdown_text_message(
method _parse_card_message (line 273) | def _parse_card_message(self, data: KookMessageEventData) -> tuple[lis...
method _handle_section_text (line 337) | def _handle_section_text(self, module: SectionModule) -> str:
method _handle_image_group (line 343) | def _handle_image_group(
method convert_message (line 356) | async def convert_message(self, data: KookMessageEventData) -> AstrBot...
method handle_msg (line 408) | async def handle_msg(self, message: AstrBotMessage):
FILE: astrbot/core/platform/sources/kook/kook_client.py
class KookClient (line 30) | class KookClient:
method __init__ (line 31) | def __init__(self, config: KookConfig, event_callback):
method bot_id (line 57) | def bot_id(self):
method bot_nickname (line 61) | def bot_nickname(self):
method bot_username (line 65) | def bot_username(self):
method get_bot_info (line 68) | async def get_bot_info(self) -> None:
method get_gateway_url (line 104) | async def get_gateway_url(self, resume=False, sn=0, session_id=None) -...
method connect (line 140) | async def connect(self, resume=False):
method listen (line 183) | async def listen(self):
method _handle_signal (line 228) | async def _handle_signal(self, event: KookWebsocketEvent):
method _handle_hello (line 257) | async def _handle_hello(self, data: KookHelloEventData):
method _handle_pong (line 272) | async def _handle_pong(self):
method _handle_reconnect (line 277) | async def _handle_reconnect(self):
method _handle_resume_ack (line 285) | async def _handle_resume_ack(self, data: KookResumeAckEventData):
method _heartbeat_loop (line 290) | async def _heartbeat_loop(self):
method _send_ping (line 333) | async def _send_ping(self):
method send_text (line 348) | async def send_text(
method upload_asset (line 394) | async def upload_asset(self, file_url: str | None) -> str:
method wait_until_closed (line 459) | async def wait_until_closed(self):
method close (line 463) | async def close(self):
FILE: astrbot/core/platform/sources/kook/kook_config.py
class KookConfig (line 7) | class KookConfig:
method from_dict (line 36) | def from_dict(cls, config_dict: dict) -> "KookConfig":
method to_dict (line 73) | def to_dict(self) -> dict[str, Any]:
method pretty_jsons (line 76) | def pretty_jsons(self, indent=2) -> str:
FILE: astrbot/core/platform/sources/kook/kook_event.py
class KookEvent (line 35) | class KookEvent(AstrMessageEvent):
method __init__ (line 36) | def __init__(
method _wrap_message (line 50) | def _wrap_message(
method send (line 153) | async def send(self, message: MessageChain):
FILE: astrbot/core/platform/sources/kook/kook_types.py
class KookApiPaths (line 8) | class KookApiPaths:
class KookMessageType (line 26) | class KookMessageType(IntEnum):
class KookModuleType (line 39) | class KookModuleType(str, Enum):
class KookBaseDataClass (line 70) | class KookBaseDataClass(BaseModel):
method from_dict (line 78) | def from_dict(cls, raw_data: dict):
method from_json (line 82) | def from_json(cls, raw_data: str | bytes | bytearray):
method to_dict (line 85) | def to_dict(
method to_json (line 99) | def to_json(
class KookCardModelBase (line 116) | class KookCardModelBase(KookBaseDataClass):
class PlainTextElement (line 122) | class PlainTextElement(KookCardModelBase):
class KmarkdownElement (line 128) | class KmarkdownElement(KookCardModelBase):
class ImageElement (line 133) | class ImageElement(KookCardModelBase):
class ButtonElement (line 142) | class ButtonElement(KookCardModelBase):
class ParagraphStructure (line 156) | class ParagraphStructure(KookCardModelBase):
class HeaderModule (line 163) | class HeaderModule(KookCardModelBase):
class SectionModule (line 168) | class SectionModule(KookCardModelBase):
class ImageGroupModule (line 175) | class ImageGroupModule(KookCardModelBase):
class ContainerModule (line 182) | class ContainerModule(KookCardModelBase):
class ActionGroupModule (line 189) | class ActionGroupModule(KookCardModelBase):
class ContextModule (line 196) | class ContextModule(KookCardModelBase):
class DividerModule (line 202) | class DividerModule(KookCardModelBase):
class FileModule (line 208) | class FileModule(KookCardModelBase):
class CountdownModule (line 218) | class CountdownModule(KookCardModelBase):
class InviteModule (line 230) | class InviteModule(KookCardModelBase):
class KookCardMessage (line 252) | class KookCardMessage(KookBaseDataClass):
method add_module (line 267) | def add_module(self, module: AnyModule):
class KookCardMessageContainer (line 271) | class KookCardMessageContainer(list[KookCardMessage]):
method append (line 274) | def append(self, object: KookCardMessage) -> None:
method to_json (line 277) | def to_json(self, indent: int | None = None, ensure_ascii: bool = True...
method from_dict (line 283) | def from_dict(cls, raw_data: list[dict[str, Any]]):
class OrderMessage (line 287) | class OrderMessage(BaseModel):
class KookMessageSignal (line 294) | class KookMessageSignal(IntEnum):
class KookChannelType (line 314) | class KookChannelType(str, Enum):
class KookAuthor (line 320) | class KookAuthor(KookBaseDataClass):
class KookKMarkdown (line 333) | class KookKMarkdown(KookBaseDataClass):
class KookExtra (line 339) | class KookExtra(KookBaseDataClass):
class KookMessageEventData (line 351) | class KookMessageEventData(KookBaseDataClass):
class KookHelloEventData (line 369) | class KookHelloEventData(KookBaseDataClass):
class KookPingEventData (line 379) | class KookPingEventData(KookBaseDataClass):
class KookPongEventData (line 386) | class KookPongEventData(KookBaseDataClass):
class KookResumeEventData (line 393) | class KookResumeEventData(KookBaseDataClass):
class KookReconnectEventData (line 400) | class KookReconnectEventData(KookBaseDataClass):
class KookResumeAckEventData (line 410) | class KookResumeAckEventData(KookBaseDataClass):
class KookWebsocketEvent (line 419) | class KookWebsocketEvent(KookBaseDataClass):
method _inject_signal_into_data (line 444) | def _inject_signal_into_data(cls, data: Any) -> Any:
class KookUserTag (line 454) | class KookUserTag(KookBaseDataClass):
class KookApiResponseBase (line 460) | class KookApiResponseBase(KookBaseDataClass):
method success (line 465) | def success(self) -> bool:
class KookUserMeData (line 469) | class KookUserMeData(KookBaseDataClass):
class KookUserMeResponse (line 492) | class KookUserMeResponse(KookApiResponseBase):
class KookGatewayIndexData (line 498) | class KookGatewayIndexData(KookBaseDataClass):
class KookGatewayIndexResponse (line 502) | class KookGatewayIndexResponse(KookApiResponseBase):
FILE: astrbot/core/platform/sources/lark/lark_adapter.py
class LarkPlatformAdapter (line 39) | class LarkPlatformAdapter(Platform):
method __init__ (line 40) | def __init__(
method _download_message_resource (line 98) | async def _download_message_resource(
method _build_message_str_from_components (line 131) | def _build_message_str_from_components(
method _parse_post_content (line 156) | def _parse_post_content(content: dict[str, Any]) -> list[dict[str, Any]]:
method _build_at_map (line 168) | def _build_at_map(mentions: list[Any] | None) -> dict[str, Comp.At]:
method _parse_message_components (line 191) | async def _parse_message_components(
method _build_reply_from_parent_id (line 340) | async def _build_reply_from_parent_id(
method _download_file_resource_to_temp (line 413) | async def _download_file_resource_to_temp(
method _clean_expired_events (line 439) | def _clean_expired_events(self) -> None:
method _is_duplicate_event (line 450) | def _is_duplicate_event(self, event_id: str) -> bool:
method send_by_session (line 465) | async def send_by_session(
method meta (line 489) | def meta(self) -> PlatformMetadata:
method convert_msg (line 497) | async def convert_msg(self, event: lark.im.v1.P2ImMessageReceiveV1) ->...
method handle_msg (line 590) | async def handle_msg(self, abm: AstrBotMessage) -> None:
method handle_webhook_event (line 601) | async def handle_webhook_event(self, event_data: dict) -> None:
method run (line 623) | async def run(self) -> None:
method webhook_callback (line 639) | async def webhook_callback(self, request: Any) -> Any:
method terminate (line 646) | async def terminate(self) -> None:
method get_client (line 651) | def get_client(self) -> lark.ws.Client:
method unified_webhook (line 654) | def unified_webhook(self) -> bool:
FILE: astrbot/core/platform/sources/lark/lark_event.py
class LarkMessageEvent (line 43) | class LarkMessageEvent(AstrMessageEvent):
method __init__ (line 44) | def __init__(
method _send_im_message (line 56) | async def _send_im_message(
method _upload_lark_file (line 131) | async def _upload_lark_file(
method _convert_to_lark (line 194) | async def _convert_to_lark(message: MessageChain, lark_client: lark.Cl...
method send_message_chain (line 284) | async def send_message_chain(
method send (line 358) | async def send(self, message: MessageChain) -> None:
method _send_file_message (line 368) | async def _send_file_message(
method _send_audio_message (line 402) | async def _send_audio_message(
method _send_media_message (line 475) | async def _send_media_message(
method react (line 547) | async def react(self, emoji: str) -> None:
method _create_streaming_card (line 568) | async def _create_streaming_card(self) -> str | None:
method _send_card_message (line 630) | async def _send_card_message(
method _update_streaming_text (line 651) | async def _update_streaming_text(
method _close_streaming_mode (line 688) | async def _close_streaming_mode(
method _fallback_send_streaming (line 727) | async def _fallback_send_streaming(self, generator, use_fallback: bool...
method send_streaming (line 743) | async def send_streaming(self, generator, use_fallback: bool = False):
FILE: astrbot/core/platform/sources/lark/server.py
class AESCipher (line 21) | class AESCipher:
method __init__ (line 24) | def __init__(self, key: str) -> None:
method str_to_bytes (line 29) | def str_to_bytes(data):
method _unpad (line 36) | def _unpad(s):
method decrypt (line 39) | def decrypt(self, enc):
method decrypt_string (line 44) | def decrypt_string(self, enc):
class LarkWebhookServer (line 49) | class LarkWebhookServer:
method __init__ (line 55) | def __init__(self, config: dict, event_queue: asyncio.Queue) -> None:
method verify_signature (line 75) | def verify_signature(
method decrypt_event (line 102) | def decrypt_event(self, encrypted_data: str) -> dict:
method handle_challenge (line 117) | async def handle_challenge(self, event_data: dict) -> dict:
method handle_callback (line 131) | async def handle_callback(self, request) -> tuple[dict, int] | dict:
method set_callback (line 200) | def set_callback(self, callback: Callable[[dict], Awaitable[None]]) ->...
FILE: astrbot/core/platform/sources/line/line_adapter.py
class LinePlatformAdapter (line 71) | class LinePlatformAdapter(Platform):
method __init__ (line 72) | def __init__(
method send_by_session (line 97) | async def send_by_session(
method meta (line 107) | def meta(self) -> PlatformMetadata:
method run (line 115) | async def run(self) -> None:
method terminate (line 123) | async def terminate(self) -> None:
method webhook_callback (line 127) | async def webhook_callback(self, request: Any) -> Any:
method handle_webhook_event (line 146) | async def handle_webhook_event(self, payload: dict[str, Any]) -> None:
method convert_message (line 169) | async def convert_message(self, event: dict[str, Any]) -> AstrBotMessa...
method _parse_line_message_components (line 233) | async def _parse_line_message_components(
method _parse_text_with_mentions (line 268) | def _parse_text_with_mentions(self, text: str, mention_obj: dict[str, ...
method _build_image_component (line 307) | async def _build_image_component(
method _build_video_component (line 322) | async def _build_video_component(
method _build_audio_component (line 339) | async def _build_audio_component(
method _build_file_component (line 356) | async def _build_file_component(
method _get_external_content_url (line 378) | def _get_external_content_url(message: dict[str, Any]) -> str:
method _guess_suffix (line 387) | def _guess_suffix(content_type: str | None, fallback: str) -> str:
method _store_temp_content (line 397) | def _store_temp_content(
method _build_message_str (line 421) | def _build_message_str(components: list) -> str:
method _clean_expired_events (line 440) | def _clean_expired_events(self) -> None:
method _is_duplicate_event (line 450) | def _is_duplicate_event(self, event_id: str) -> bool:
method handle_msg (line 457) | async def handle_msg(self, abm: AstrBotMessage) -> None:
FILE: astrbot/core/platform/sources/line/line_api.py
class LineAPIClient (line 14) | class LineAPIClient:
method __init__ (line 15) | def __init__(
method _get_session (line 27) | async def _get_session(self) -> aiohttp.ClientSession:
method close (line 32) | async def close(self) -> None:
method verify_signature (line 36) | def verify_signature(self, raw_body: bytes, signature: str | None) -> ...
method _auth_headers (line 48) | def _auth_headers(self) -> dict[str, str]:
method reply_message (line 51) | async def reply_message(
method push_message (line 69) | async def push_message(
method _post_json (line 87) | async def _post_json(
method get_message_content (line 115) | async def get_message_content(
method _read_content_response (line 150) | async def _read_content_response(
method _extract_filename_from_disposition (line 160) | def _extract_filename_from_disposition(self, disposition: str | None) ...
method _wait_for_transcoding (line 174) | async def _wait_for_transcoding(
FILE: astrbot/core/platform/sources/line/line_event.py
class LineMessageEvent (line 25) | class LineMessageEvent(AstrMessageEvent):
method __init__ (line 26) | def __init__(
method _component_to_message_object (line 38) | async def _component_to_message_object(
method _resolve_image_url (line 105) | async def _resolve_image_url(segment: Image) -> str:
method _resolve_record_url (line 116) | async def _resolve_record_url(segment: Record) -> str:
method _resolve_record_duration (line 127) | async def _resolve_record_duration(segment: Record) -> int:
method _resolve_video_url (line 138) | async def _resolve_video_url(segment: Video) -> str:
method _resolve_video_preview_url (line 149) | async def _resolve_video_preview_url(segment: Video) -> str:
method _resolve_file_url (line 191) | async def _resolve_file_url(segment: File) -> str:
method _resolve_file_size (line 201) | async def _resolve_file_size(segment: File) -> int:
method build_line_messages (line 211) | async def build_line_messages(cls, message_chain: MessageChain) -> lis...
method send (line 228) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 249) | async def send_streaming(
FILE: astrbot/core/platform/sources/misskey/misskey_adapter.py
class MisskeyPlatformAdapter (line 50) | class MisskeyPlatformAdapter(Platform):
method __init__ (line 51) | def __init__(
method meta (line 100) | def meta(self) -> PlatformMetadata:
method run (line 124) | async def run(self) -> None:
method _register_event_handlers (line 153) | def _register_event_handlers(self, streaming) -> None:
method _send_text_only_message (line 166) | async def _send_text_only_message(
method _process_poll_data (line 192) | def _process_poll_data(
method _extract_additional_fields (line 212) | def _extract_additional_fields(self, session, message_chain) -> dict[s...
method _start_websocket_connection (line 236) | async def _start_websocket_connection(self) -> None:
method _handle_notification (line 284) | async def _handle_notification(self, data: dict[str, Any]) -> None:
method _handle_chat_message (line 308) | async def _handle_chat_message(self, data: dict[str, Any]) -> None:
method _debug_handler (line 343) | async def _debug_handler(self, data: dict[str, Any]) -> None:
method _is_bot_mentioned (line 349) | def _is_bot_mentioned(self, note: dict[str, Any]) -> bool:
method send_by_session (line 368) | async def send_by_session(
method convert_message (line 634) | async def convert_message(self, raw_data: dict[str, Any]) -> AstrBotMe...
method convert_chat_message (line 682) | async def convert_chat_message(self, raw_data: dict[str, Any]) -> Astr...
method convert_room_message (line 709) | async def convert_room_message(self, raw_data: dict[str, Any]) -> Astr...
method terminate (line 757) | async def terminate(self) -> None:
method get_client (line 762) | def get_client(self) -> Any:
FILE: astrbot/core/platform/sources/misskey/misskey_api.py
class APIError (line 25) | class APIError(Exception):
class APIConnectionError (line 29) | class APIConnectionError(APIError):
class APIRateLimitError (line 33) | class APIRateLimitError(APIError):
class AuthenticationError (line 37) | class AuthenticationError(APIError):
class WebSocketError (line 41) | class WebSocketError(APIError):
class StreamingClient (line 45) | class StreamingClient:
method __init__ (line 46) | def __init__(self, instance_url: str, access_token: str) -> None:
method connect (line 57) | async def connect(self) -> bool:
method disconnect (line 93) | async def disconnect(self) -> None:
method subscribe_channel (line 101) | async def subscribe_channel(
method unsubscribe_channel (line 119) | async def unsubscribe_channel(self, channel_id: str) -> None:
method add_message_handler (line 135) | def add_message_handler(
method listen (line 142) | async def listen(self) -> None:
method _handle_message (line 190) | async def _handle_message(self, data: dict[str, Any]) -> None:
function retry_async (line 265) | def retry_async(
class MisskeyAPI (line 327) | class MisskeyAPI:
method __init__ (line 328) | def __init__(
method __aenter__ (line 350) | async def __aenter__(self):
method __aexit__ (line 353) | async def __aexit__(self, exc_type, exc_val, exc_tb):
method close (line 357) | async def close(self) -> None:
method get_streaming_client (line 366) | def get_streaming_client(self) -> StreamingClient:
method session (line 372) | def session(self) -> aiohttp.ClientSession:
method _handle_response_status (line 378) | def _handle_response_status(self, status: int, endpoint: str) -> NoRet...
method _process_response (line 413) | async def _process_response(
method _make_request (line 457) | async def _make_request(
method create_note (line 474) | async def create_note(
method upload_file (line 538) | async def upload_file(
method find_files_by_hash (line 578) | async def find_files_by_hash(self, md5_hash: str) -> list[dict[str, An...
method find_files_by_name (line 596) | async def find_files_by_name(
method find_files (line 620) | async def find_files(
method _download_with_existing_session (line 646) | async def _download_with_existing_session(
method _download_with_temp_session (line 664) | async def _download_with_temp_session(
method upload_and_find_file (line 680) | async def upload_and_find_file(
method get_current_user (line 747) | async def get_current_user(self) -> dict[str, Any]:
method send_message (line 751) | async def send_message(
method send_room_message (line 770) | async def send_room_message(
method get_messages (line 789) | async def get_messages(
method get_mentions (line 806) | async def get_mentions(
method send_message_with_media (line 825) | async def send_message_with_media(
method _process_media_urls (line 873) | async def _process_media_urls(self, urls: list[str]) -> list[str]:
method _process_local_files (line 890) | async def _process_local_files(self, file_paths: list[str]) -> list[str]:
method _dispatch_message (line 906) | async def _dispatch_message(
FILE: astrbot/core/platform/sources/misskey/misskey_event.py
class MisskeyPlatformEvent (line 21) | class MisskeyPlatformEvent(AstrMessageEvent):
method __init__ (line 22) | def __init__(
method _is_system_command (line 33) | def _is_system_command(self, message_str: str) -> bool:
method send (line 43) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 129) | async def send_streaming(
FILE: astrbot/core/platform/sources/misskey/misskey_utils.py
class FileIDExtractor (line 9) | class FileIDExtractor:
method extract_file_id (line 13) | def extract_file_id(result: Any) -> str | None:
class MessagePayloadBuilder (line 33) | class MessagePayloadBuilder:
method build_chat_payload (line 37) | def build_chat_payload(
method build_room_payload (line 50) | def build_room_payload(
method build_note_payload (line 63) | def build_note_payload(
function serialize_message_chain (line 77) | def serialize_message_chain(chain: list[Any]) -> tuple[str, bool]:
function resolve_message_visibility (line 120) | def resolve_message_visibility(
function resolve_visibility_from_raw_message (line 176) | def resolve_visibility_from_raw_message(
function is_valid_user_session_id (line 184) | def is_valid_user_session_id(session_id: str | Any) -> bool:
function is_valid_room_session_id (line 198) | def is_valid_room_session_id(session_id: str | Any) -> bool:
function is_valid_chat_session_id (line 212) | def is_valid_chat_session_id(session_id: str | Any) -> bool:
function extract_user_id_from_session_id (line 226) | def extract_user_id_from_session_id(session_id: str) -> str:
function extract_room_id_from_session_id (line 235) | def extract_room_id_from_session_id(session_id: str) -> str:
function add_at_mention_if_needed (line 244) | def add_at_mention_if_needed(
function create_file_component (line 269) | def create_file_component(file_info: dict[str, Any]) -> tuple[Any, str]:
function process_files (line 284) | def process_files(
function format_poll (line 299) | def format_poll(poll: dict[str, Any]) -> str:
function extract_sender_info (line 315) | def extract_sender_info(
function create_base_message (line 335) | def create_base_message(
function process_at_mention (line 375) | def process_at_mention(
function cache_user_info (line 400) | def cache_user_info(
function cache_room_info (line 428) | def cache_room_info(
function resolve_component_url_or_path (line 449) | async def resolve_component_url_or_path(
function summarize_component_for_log (line 515) | def summarize_component_for_log(comp: Any) -> dict[str, Any]:
function upload_local_with_retries (line 528) | async def upload_local_with_retries(
FILE: astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py
function _patch_qq_botpy_formdata (line 28) | def _patch_qq_botpy_formdata() -> None:
class QQOfficialMessageEvent (line 48) | class QQOfficialMessageEvent(AstrMessageEvent):
method __init__ (line 56) | def __init__(
method send (line 68) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 72) | async def send_streaming(self, generator, use_fallback: bool = False):
method _extract_response_message_id (line 152) | def _extract_response_message_id(ret) -> str | None:
method _post_send (line 162) | async def _post_send(self, stream: dict | None = None):
method _send_with_markdown_fallback (line 393) | async def _send_with_markdown_fallback(
method upload_group_and_c2c_image (line 444) | async def upload_group_and_c2c_image(
method upload_group_and_c2c_media (line 483) | async def upload_group_and_c2c_media(
method post_c2c_message (line 541) | async def post_c2c_message(
method _parse_to_qqofficial (line 578) | async def _parse_to_qqofficial(message: MessageChain):
FILE: astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py
class botClient (line 37) | class botClient(Client):
method set_platform (line 38) | def set_platform(self, platform: QQOfficialPlatformAdapter) -> None:
method on_group_at_message_create (line 42) | async def on_group_at_message_create(
method on_at_message_create (line 55) | async def on_at_message_create(self, message: botpy.message.Message) -...
method on_direct_message_create (line 66) | async def on_direct_message_create(
method on_c2c_message_create (line 78) | async def on_c2c_message_create(self, message: botpy.message.C2CMessag...
method _commit (line 87) | def _commit(self, abm: AstrBotMessage) -> None:
class QQOfficialPlatformAdapter (line 101) | class QQOfficialPlatformAdapter(Platform):
method __init__ (line 102) | def __init__(
method send_by_session (line 139) | async def send_by_session(
method _send_by_session_common (line 146) | async def _send_by_session_common(
method remember_session_message_id (line 304) | def remember_session_message_id(self, session_id: str, message_id: str...
method remember_session_scene (line 309) | def remember_session_scene(self, session_id: str, scene: str) -> None:
method _extract_message_id (line 314) | def _extract_message_id(self, ret: Any) -> str | None:
method meta (line 323) | def meta(self) -> PlatformMetadata:
method _normalize_attachment_url (line 332) | def _normalize_attachment_url(url: str | None) -> str:
method _append_attachments (line 340) | def _append_attachments(
method _parse_face_message (line 395) | def _parse_face_message(content: str) -> str:
method _parse_from_qqofficial (line 436) | def _parse_from_qqofficial(
method run (line 503) | def run(self):
method get_client (line 506) | def get_client(self) -> botClient:
method terminate (line 509) | async def terminate(self) -> None:
FILE: astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py
class botClient (line 26) | class botClient(Client):
method set_platform (line 27) | def set_platform(self, platform: "QQOfficialWebhookPlatformAdapter") -...
method on_group_at_message_create (line 31) | async def on_group_at_message_create(
method on_at_message_create (line 44) | async def on_at_message_create(self, message: botpy.message.Message) -...
method on_direct_message_create (line 55) | async def on_direct_message_create(
method on_c2c_message_create (line 67) | async def on_c2c_message_create(self, message: botpy.message.C2CMessag...
method _commit (line 76) | def _commit(self, abm: AstrBotMessage) -> None:
class QQOfficialWebhookPlatformAdapter (line 90) | class QQOfficialWebhookPlatformAdapter(Platform):
method __init__ (line 91) | def __init__(
method send_by_session (line 118) | async def send_by_session(
method remember_session_message_id (line 129) | def remember_session_message_id(self, session_id: str, message_id: str...
method remember_session_scene (line 134) | def remember_session_scene(self, session_id: str, scene: str) -> None:
method _extract_message_id (line 139) | def _extract_message_id(self, ret: Any) -> str | None:
method meta (line 148) | def meta(self) -> PlatformMetadata:
method run (line 156) | async def run(self) -> None:
method get_client (line 173) | def get_client(self) -> botClient:
method webhook_callback (line 176) | async def webhook_callback(self, request: Any) -> Any:
method terminate (line 184) | async def terminate(self) -> None:
FILE: astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py
class QQOfficialWebhookMessageEvent (line 8) | class QQOfficialWebhookMessageEvent(QQOfficialMessageEvent):
method __init__ (line 9) | def __init__(
FILE: astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py
class QQOfficialWebhook (line 17) | class QQOfficialWebhook:
method __init__ (line 18) | def __init__(
method initialize (line 47) | async def initialize(self) -> None:
method repeat_seed (line 66) | async def repeat_seed(self, bot_secret: str, target_size: int = 32) ->...
method webhook_validation (line 72) | async def webhook_validation(self, validation_payload: dict):
method callback (line 87) | async def callback(self):
method handle_callback (line 91) | async def handle_callback(self, request) -> dict:
method start_polling (line 140) | async def start_polling(self) -> None:
method shutdown_trigger (line 150) | async def shutdown_trigger(self) -> None:
FILE: astrbot/core/platform/sources/satori/satori_adapter.py
class SatoriPlatformAdapter (line 34) | class SatoriPlatformAdapter(Platform):
method __init__ (line 35) | def __init__(
method send_by_session (line 72) | async def send_by_session(
method meta (line 86) | def meta(self) -> PlatformMetadata:
method _is_websocket_closed (line 89) | def _is_websocket_closed(self, ws) -> bool:
method run (line 102) | async def run(self) -> None:
method connect_websocket (line 136) | async def connect_websocket(self) -> None:
method send_identify (line 184) | async def send_identify(self) -> None:
method heartbeat_loop (line 212) | async def heartbeat_loop(self) -> None:
method handle_message (line 237) | async def handle_message(self, message: str) -> None:
method handle_event (line 278) | async def handle_event(self, event_data: dict) -> None:
method convert_satori_message (line 310) | async def convert_satori_message(
method _extract_namespace_prefixes (line 406) | def _extract_namespace_prefixes(self, content: str) -> set:
method _extract_quote_element (line 458) | async def _extract_quote_element(self, content: str) -> dict | None:
method _extract_quote_with_regex (line 529) | async def _extract_quote_with_regex(self, content: str) -> dict | None:
method _convert_quote_message (line 552) | async def _convert_quote_message(self, quote: dict) -> AstrBotMessage ...
method parse_satori_elements (line 592) | async def parse_satori_elements(self, content: str) -> list:
method _parse_xml_node (line 637) | async def _parse_xml_node(self, node: ET.Element, elements: list) -> N...
method handle_msg (line 723) | async def handle_msg(self, message: AstrBotMessage) -> None:
method send_http_request (line 735) | async def send_http_request(
method terminate (line 783) | async def terminate(self) -> None:
FILE: astrbot/core/platform/sources/satori/satori_event.py
class SatoriPlatformEvent (line 23) | class SatoriPlatformEvent(AstrMessageEvent):
method __init__ (line 24) | def __init__(
method send_with_adapter (line 56) | async def send_with_adapter(
method send (line 113) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 163) | async def send_streaming(self, generator, use_fallback: bool = False):
method _convert_component_to_satori (line 212) | async def _convert_component_to_satori(self, component) -> str:
method _convert_node_to_satori (line 271) | async def _convert_node_to_satori(self, node: Node) -> str:
method _convert_component_to_satori_static (line 305) | async def _convert_component_to_satori_static(cls, component) -> str:
method _convert_node_to_satori_static (line 365) | async def _convert_node_to_satori_static(cls, node: Node) -> str:
method _convert_nodes_to_satori (line 397) | async def _convert_nodes_to_satori(self, nodes: Nodes) -> str:
method _convert_nodes_to_satori_static (line 416) | async def _convert_nodes_to_satori_static(cls, nodes: Nodes) -> str:
FILE: astrbot/core/platform/sources/slack/client.py
class SlackWebhookClient (line 19) | class SlackWebhookClient:
method __init__ (line 22) | def __init__(
method _setup_routes (line 47) | def _setup_routes(self) -> None:
method handle_callback (line 60) | async def handle_callback(self, req):
method start (line 108) | async def start(self) -> None:
method shutdown_trigger (line 121) | async def shutdown_trigger(self) -> None:
method stop (line 124) | async def stop(self) -> None:
class SlackSocketClient (line 130) | class SlackSocketClient:
method __init__ (line 133) | def __init__(
method _handle_events (line 144) | async def _handle_events(
method start (line 163) | async def start(self) -> None:
method stop (line 177) | async def stop(self) -> None:
FILE: astrbot/core/platform/sources/slack/slack_adapter.py
class SlackAdapter (line 35) | class SlackAdapter(Platform):
method __init__ (line 36) | def __init__(
method send_by_session (line 80) | async def send_by_session(
method convert_message (line 115) | async def convert_message(self, event: dict) -> AstrBotMessage:
method _parse_blocks (line 209) | def _parse_blocks(self, blocks: list) -> list:
method _handle_socket_event (line 288) | async def _handle_socket_event(self, req: SocketModeRequest) -> None:
method get_bot_user_id (line 310) | async def get_bot_user_id(self):
method get_file_base64 (line 314) | async def get_file_base64(self, url: str) -> str:
method run (line 328) | async def run(self) -> None:
method _handle_webhook_event (line 377) | async def _handle_webhook_event(self, event_data: dict) -> None:
method webhook_callback (line 397) | async def webhook_callback(self, request: Any) -> Any:
method terminate (line 404) | async def terminate(self) -> None:
method meta (line 411) | def meta(self) -> PlatformMetadata:
method handle_msg (line 414) | async def handle_msg(self, message: AstrBotMessage) -> None:
method get_client (line 425) | def get_client(self):
method unified_webhook (line 428) | def unified_webhook(self) -> bool:
FILE: astrbot/core/platform/sources/slack/slack_event.py
class SlackMessageEvent (line 19) | class SlackMessageEvent(AstrMessageEvent):
method __init__ (line 20) | def __init__(
method _from_segment_to_slack_block (line 32) | async def _from_segment_to_slack_block(
method _parse_slack_blocks (line 91) | async def _parse_slack_blocks(
method send (line 129) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 175) | async def send_streaming(
method get_group (line 211) | async def get_group(self, group_id=None, **kwargs):
FILE: astrbot/core/platform/sources/telegram/tg_adapter.py
class TelegramPlatformAdapter (line 43) | class TelegramPlatformAdapter(Platform):
method __init__ (line 44) | def __init__(
method send_by_session (line 108) | async def send_by_session(
method meta (line 122) | def meta(self) -> PlatformMetadata:
method run (line 127) | async def run(self) -> None:
method register_commands (line 152) | async def register_commands(self) -> None:
method collect_commands (line 170) | def collect_commands(self) -> list[BotCommand]:
method _extract_command_info (line 200) | def _extract_command_info(
method start (line 241) | async def start(self, update: Update, context: ContextTypes.DEFAULT_TY...
method message_handler (line 252) | async def message_handler(
method convert_message (line 267) | async def convert_message(
method handle_media_group_message (line 448) | async def handle_media_group_message(
method process_media_group (line 509) | async def process_media_group(self, media_group_id: str) -> None:
method handle_msg (line 555) | async def handle_msg(self, message: AstrBotMessage) -> None:
method get_client (line 565) | def get_client(self) -> ExtBot:
method terminate (line 568) | async def terminate(self) -> None:
FILE: astrbot/core/platform/sources/telegram/tg_event.py
function _is_gif (line 28) | def _is_gif(path: str) -> bool:
class TelegramPlatformEvent (line 38) | class TelegramPlatformEvent(AstrMessageEvent):
method _allocate_draft_id (line 54) | def _allocate_draft_id(cls) -> int:
method __init__ (line 72) | def __init__(
method _split_message (line 84) | def _split_message(cls, text: str) -> list[str]:
method _send_chat_action (line 109) | async def _send_chat_action(
method _get_chat_action_for_chain (line 126) | def _get_chat_action_for_chain(cls, chain: list[Any]) -> ChatAction | ...
method _send_media_with_action (line 134) | async def _send_media_with_action(
method _send_voice_with_fallback (line 160) | async def _send_voice_with_fallback(
method _ensure_typing (line 222) | async def _ensure_typing(
method send_typing (line 232) | async def send_typing(self) -> None:
method send_with_client (line 245) | async def send_with_client(
method send (line 334) | async def send(self, message: MessageChain) -> None:
method react (line 341) | async def react(self, emoji: str | None, big: bool = False) -> None:
method _send_message_draft (line 373) | async def _send_message_draft(
method _process_chain_items (line 411) | async def _process_chain_items(
method _send_final_segment (line 477) | async def _send_final_segment(self, delta: str, payload: dict[str, Any...
method send_streaming (line 492) | async def send_streaming(self, generator, use_fallback: bool = False):
method _send_streaming_draft (line 529) | async def _send_streaming_draft(
method _send_streaming_edit (line 632) | async def _send_streaming_edit(
FILE: astrbot/core/platform/sources/webchat/message_parts_helper.py
function strip_message_parts_path_fields (line 31) | def strip_message_parts_path_fields(message_parts: list[dict]) -> list[d...
function webchat_message_parts_have_content (line 35) | def webchat_message_parts_have_content(message_parts: list[dict]) -> bool:
function parse_webchat_message_parts (line 43) | async def parse_webchat_message_parts(
function build_webchat_message_parts (line 164) | async def build_webchat_message_parts(
function webchat_message_parts_to_message_chain (line 238) | def webchat_message_parts_to_message_chain(
function build_message_chain_from_payload (line 310) | async def build_message_chain_from_payload(
function create_attachment_part_from_existing_file (line 330) | async def create_attachment_part_from_existing_file(
function message_chain_to_storage_message_parts (line 362) | async def message_chain_to_storage_message_parts(
function _copy_file_to_attachment_part (line 436) | async def _copy_file_to_attachment_part(
FILE: astrbot/core/platform/sources/webchat/webchat_adapter.py
function _extract_conversation_id (line 32) | def _extract_conversation_id(session_id: str) -> str:
class QueueListener (line 41) | class QueueListener:
method __init__ (line 42) | def __init__(
method run (line 52) | async def run(self) -> None:
class WebChatAdapter (line 62) | class WebChatAdapter(Platform):
method __init__ (line 63) | def __init__(
method send_by_session (line 86) | async def send_by_session(
method _save_proactive_message (line 131) | async def _save_proactive_message(
method _get_message_history (line 152) | async def _get_message_history(
method _parse_message_parts (line 157) | async def _parse_message_parts(
method convert_message (line 199) | async def convert_message(self, data: tuple) -> AstrBotMessage:
method run (line 223) | def run(self) -> Coroutine[Any, Any, None]:
method meta (line 231) | def meta(self) -> PlatformMetadata:
method handle_msg (line 234) | async def handle_msg(self, message: AstrBotMessage) -> None:
method terminate (line 252) | async def terminate(self) -> None:
FILE: astrbot/core/platform/sources/webchat/webchat_event.py
function _extract_conversation_id (line 17) | def _extract_conversation_id(session_id: str) -> str:
class WebChatMessageEvent (line 26) | class WebChatMessageEvent(AstrMessageEvent):
method __init__ (line 27) | def __init__(self, message_str, message_obj, platform_meta, session_id...
method _send (line 32) | async def _send(
method send (line 132) | async def send(self, message: MessageChain | None) -> None:
method send_streaming (line 137) | async def send_streaming(self, generator, use_fallback: bool = False) ...
FILE: astrbot/core/platform/sources/webchat/webchat_queue_mgr.py
class WebChatQueueMgr (line 7) | class WebChatQueueMgr:
method __init__ (line 8) | def __init__(self, queue_maxsize: int = 128, back_queue_maxsize: int =...
method get_or_create_queue (line 21) | def get_or_create_queue(self, conversation_id: str) -> asyncio.Queue:
method get_or_create_back_queue (line 29) | def get_or_create_back_queue(
method remove_back_queue (line 46) | def remove_back_queue(self, request_id: str):
method remove_queues (line 57) | def remove_queues(self, conversation_id: str) -> None:
method remove_queue (line 66) | def remove_queue(self, conversation_id: str):
method list_back_request_ids (line 78) | def list_back_request_ids(self, conversation_id: str) -> list[str]:
method has_queue (line 82) | def has_queue(self, conversation_id: str) -> bool:
method set_listener (line 86) | def set_listener(
method clear_listener (line 94) | async def clear_listener(self) -> None:
method _start_listener_if_needed (line 107) | def _start_listener_if_needed(self, conversation_id: str):
method _listen_to_queue (line 128) | async def _listen_to_queue(
FILE: astrbot/core/platform/sources/wecom/wecom_adapter.py
class WecomServer (line 42) | class WecomServer:
method __init__ (line 43) | def __init__(self, event_queue: asyncio.Queue, config: dict) -> None:
method verify (line 68) | async def verify(self):
method handle_verify (line 72) | async def handle_verify(self, request) -> str:
method callback_command (line 96) | async def callback_command(self):
method handle_callback (line 100) | async def handle_callback(self, request) -> str:
method start_polling (line 127) | async def start_polling(self) -> None:
method shutdown_trigger (line 137) | async def shutdown_trigger(self) -> None:
class WecomPlatformAdapter (line 142) | class WecomPlatformAdapter(Platform):
method __init__ (line 143) | def __init__(
method send_by_session (line 215) | async def send_by_session(
method meta (line 253) | def meta(self) -> PlatformMetadata:
method run (line 263) | async def run(self) -> None:
method webhook_callback (line 305) | async def webhook_callback(self, request: Any) -> Any:
method convert_message (line 313) | async def convert_message(self, msg: BaseMessage) -> AstrBotMessage | ...
method convert_wechat_kf_message (line 380) | async def convert_wechat_kf_message(self, msg: dict) -> AstrBotMessage...
method handle_msg (line 435) | async def handle_msg(self, message: AstrBotMessage) -> None:
method get_client (line 445) | def get_client(self) -> WeChatClient:
method terminate (line 448) | async def terminate(self) -> None:
FILE: astrbot/core/platform/sources/wecom/wecom_event.py
class WecomPlatformEvent (line 15) | class WecomPlatformEvent(AstrMessageEvent):
method __init__ (line 16) | def __init__(
method send_with_client (line 28) | async def send_with_client(
method split_plain (line 35) | async def split_plain(self, plain: str) -> list[str]:
method send (line 81) | async def send(self, message: MessageChain) -> None:
method send_streaming (line 288) | async def send_streaming(self, generator, use_fallback: bool = False):
FILE: astrbot/core/platform/sources/wecom/wecom_kf.py
class WeChatKF (line 27) | class WeChatKF(BaseWeChatAPI):
method sync_msg (line 33) | def sync_msg(self, token, open_kfid, cursor="", limit=1000):
method get_service_state (line 54) | def get_service_state(self, open_kfid, external_userid):
method trans_service_state (line 74) | def trans_service_state(
method get_servicer_list (line 97) | def get_servicer_list(self, open_kfid):
method add_servicer (line 108) | def add_servicer(self, open_kfid, userid_list):
method del_servicer (line 125) | def del_servicer(self, open_kfid, userid_list):
method batchget_customer (line 142) | def batchget_customer(self, external_userid_list):
method get_account_list (line 156) | def get_account_list(self):
method add_contact_way (line 163) | def add_contact_way(self, open_kfid, scene):
method get_upgrade_service_config (line 173) | def get_upgrade_service_config(self):
method upgrade_service (line 180) | def upgrade_service(
method cancel_upgrade_service (line 208) | def cancel_upgrade_service(self, open_kfid, external_userid):
method send_msg_on_event (line 218) | def send_msg_on_event(self, code, msgtype, msg_content, msgid=None):
method get_corp_statistic (line 235) | def get_corp_statistic(self, start_time, end_time, open_kfid=None):
method get_servicer_statistic (line 246) | def get_servicer_statistic(
method account_update (line 269) | def account_update(self, open_kfid, name, media_id):
FILE: astrbot/core/platform/sources/wecom/wecom_kf_message.py
class WeChatKFMessage (line 28) | class WeChatKFMessage(BaseWeChatAPI):
method send (line 45) | def send(self, user_id, open_kfid, msgid="", msg=None):
method send_text (line 68) | def send_text(self, user_id, open_kfid, content, msgid=""):
method send_image (line 76) | def send_image(self, user_id, open_kfid, media_id, msgid=""):
method send_voice (line 84) | def send_voice(self, user_id, open_kfid, media_id, msgid=""):
method send_video (line 92) | def send_video(self, user_id, open_kfid, media_id, msgid=""):
method send_file (line 103) | def send_file(self, user_id, open_kfid, media_id, msgid=""):
method send_articles_link (line 111) | def send_articles_link(self, user_id, open_kfid, article, msgid=""):
method send_msgmenu (line 125) | def send_msgmenu(
method send_location (line 148) | def send_location(
method send_miniprogram (line 173) | def send_miniprogram(
FILE: astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py
class FormatException (line 30) | class FormatException(Exception):
function throw_exception (line 34) | def throw_exception(message, exception_class=FormatException) -> NoReturn:
class SHA1 (line 39) | class SHA1:
method getSHA1 (line 42) | def getSHA1(self, token, timestamp, nonce, encrypt):
class JsonParse (line 66) | class JsonParse:
method extract (line 77) | def extract(self, jsontext):
method generate (line 89) | def generate(self, encrypt, signature, timestamp, nonce):
class PKCS7Encoder (line 107) | class PKCS7Encoder:
method encode (line 112) | def encode(self, text):
method decode (line 129) | def decode(self, decrypted):
class Prpcrypt (line 140) | class Prpcrypt:
method __init__ (line 149) | def __init__(self, key) -> None:
method encrypt (line 155) | def encrypt(self, text, receiveid):
method decrypt (line 183) | def decrypt(self, text, receiveid):
method get_random_str (line 213) | def get_random_str(self):
class WXBizJsonMsgCrypt (line 222) | class WXBizJsonMsgCrypt:
method __init__ (line 224) | def __init__(self, sToken, sEncodingAESKey, sReceiveId) -> None:
method VerifyURL (line 242) | def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
method EncryptMsg (line 253) | def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
method DecryptMsg (line 275) | def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):
FILE: astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py
class WecomAIQueueListener (line 46) | class WecomAIQueueListener:
method __init__ (line 49) | def __init__(
method run (line 57) | async def run(self) -> None:
class WecomAIBotAdapter (line 69) | class WecomAIBotAdapter(Platform):
method __init__ (line 72) | def __init__(
method _handle_queued_message (line 174) | async def _handle_queued_message(self, data: dict) -> None:
method _process_message (line 182) | async def _process_message(
method _process_long_connection_payload (line 359) | async def _process_long_connection_payload(
method _send_long_connection_respond_welcome (line 413) | async def _send_long_connection_respond_welcome(self, req_id: str) -> ...
method _send_long_connection_respond_msg (line 428) | async def _send_long_connection_respond_msg(
method _extract_session_id (line 442) | def _extract_session_id(self, message_data: dict[str, Any]) -> str:
method _enqueue_message (line 454) | async def _enqueue_message(
method convert_message (line 473) | async def convert_message(self, payload: dict) -> AstrBotMessage:
method send_by_session (line 564) | async def send_by_session(
method run (line 588) | def run(self) -> Awaitable[Any]:
method webhook_callback (line 625) | async def webhook_callback(self, request: Any) -> Any:
method terminate (line 635) | async def terminate(self) -> None:
method meta (line 644) | def meta(self) -> PlatformMetadata:
method handle_msg (line 648) | async def handle_msg(self, message: AstrBotMessage) -> None:
method get_client (line 672) | def get_client(self) -> WecomAIBotAPIClient | None:
method get_server (line 676) | def get_server(self) -> WecomAIBotServer | None:
FILE: astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py
class WecomAIBotAPIClient (line 19) | class WecomAIBotAPIClient:
method __init__ (line 22) | def __init__(self, token: str, encoding_aes_key: str) -> None:
method decrypt_message (line 34) | async def decrypt_message(
method encrypt_message (line 82) | async def encrypt_message(
method verify_url (line 113) | def verify_url(
method process_encrypted_image (line 151) | async def process_encrypted_image(
class WecomAIBotStreamMessageBuilder (line 226) | class WecomAIBotStreamMessageBuilder:
method make_text_stream (line 230) | def make_text_stream(stream_id: str, content: str, finish: bool = Fals...
method make_image_stream (line 249) | def make_image_stream(
method make_mixed_stream (line 284) | def make_mixed_stream(
method make_text (line 311) | def make_text(content: str) -> str:
class WecomAIBotMessageParser (line 325) | class WecomAIBotMessageParser:
method parse_text_message (line 329) | def parse_text_message(data: dict[str, Any]) -> str | None:
method parse_image_message (line 346) | def parse_image_message(data: dict[str, Any]) -> str | None:
method parse_stream_message (line 363) | def parse_stream_message(data: dict[str, Any]) -> dict[str, Any] | None:
method parse_mixed_message (line 386) | def parse_mixed_message(data: dict[str, Any]) -> list | None:
method parse_event_message (line 403) | def parse_event_message(data: dict[str, Any]) -> dict[str, Any] | None:
FILE: astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py
class WecomAIBotMessageEvent (line 15) | class WecomAIBotMessageEvent(AstrMessageEvent):
method __init__ (line 20) | def __init__(
method _mark_stream_complete (line 49) | async def _mark_stream_complete(self, stream_id: str) -> None:
method _send (line 61) | async def _send(
method _extract_plain_text_from_chain (line 128) | def _extract_plain_text_from_chain(message_chain: MessageChain | None)...
method send (line 139) | async def send(self, message: MessageChain | None) -> None:
method send_streaming (line 206) | async def send_streaming(self, generator, use_fallback=False) -> None:
FILE: astrbot/core/platform/sources/wecom_ai_bot/wecomai_long_connection.py
class WecomAIBotLongConnectionClient (line 14) | class WecomA
Condensed preview — 1231 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,814K chars).
[
{
"path": ".dockerignore",
"chars": 419,
"preview": "# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm\n# Reference:"
},
{
"path": ".github/FUNDING.yml",
"chars": 846,
"preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
},
{
"path": ".github/ISSUE_TEMPLATE/PLUGIN_PUBLISH.yml",
"chars": 1272,
"preview": "name: 🥳 发布插件\ndescription: 提交插件到插件市场\ntitle: \"[Plugin] 插件名\"\nlabels: [\"plugin-publish\"]\nassignees: []\nbody:\n - type: markd"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.yml",
"chars": 3240,
"preview": "name: '🐛 Report Bug / 报告 Bug'\ntitle: '[Bug]'\ndescription: Submit bug report to help us improve. / 提交报告帮助我们改进。\nlabels: [ "
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.yml",
"chars": 1384,
"preview": "\nname: '🎉 Feature Request / 功能建议'\ntitle: \"[Feature]\"\ndescription: Submit a suggestion to help us improve. / 提交建议帮助我们改进。\n"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 1582,
"preview": "<!--Please describe the motivation for this change: What problem does it solve? (e.g., Fixes XX issue, adds YY feature)-"
},
{
"path": ".github/auto_assign.yml",
"chars": 930,
"preview": "# Set to true to add reviewers to pull requests\naddReviewers: true\n\n# Set to true to add assignees to pull requests\naddA"
},
{
"path": ".github/copilot-instructions.md",
"chars": 3092,
"preview": "# AstrBot Development Instructions\n\nAstrBot is a multi-platform LLM chatbot and development framework written in Python "
},
{
"path": ".github/dependabot.yml",
"chars": 579,
"preview": "# Keep GitHub Actions up to date with GitHub's Dependabot...\n# https://docs.github.com/en/code-security/dependabot/worki"
},
{
"path": ".github/workflows/build-docs.yml",
"chars": 1307,
"preview": "name: release\n\non:\n push:\n tags:\n - 'v*'\n workflow_dispatch:\n\njobs:\n build:\n runs-on: ubuntu-latest # 运行环境"
},
{
"path": ".github/workflows/code-format.yml",
"chars": 645,
"preview": "name: Code Format Check\n\non:\n pull_request:\n branches: [ master ]\n push:\n branches: [ master ]\n\njobs:\n format-c"
},
{
"path": ".github/workflows/codeql.yml",
"chars": 4361,
"preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
},
{
"path": ".github/workflows/coverage_test.yml",
"chars": 1138,
"preview": "name: Run tests and upload coverage\n\non:\n push:\n branches:\n - master\n paths-ignore:\n - 'README.md'\n "
},
{
"path": ".github/workflows/dashboard_ci.yml",
"chars": 1497,
"preview": "name: AstrBot Dashboard CI\n\non:\n push:\n branches: [ \"master\" ]\n pull_request:\n branches: [ \"master\" ]\n\njobs:\n b"
},
{
"path": ".github/workflows/docker-image.yml",
"chars": 6985,
"preview": "name: Docker Image CI/CD\n\non:\n push:\n tags:\n - \"v*\"\n schedule:\n # Run at 00:00 UTC every day\n - cron: \"0"
},
{
"path": ".github/workflows/pr-title-check.yml",
"chars": 1862,
"preview": "name: PR Title Check\n\non:\n pull_request_target:\n types: [opened, edited, reopened, synchronize]\n\njobs:\n title-forma"
},
{
"path": ".github/workflows/release.yml",
"chars": 7694,
"preview": "name: Release\n\non:\n push:\n tags:\n - \"v*\"\n workflow_dispatch:\n inputs:\n ref:\n description: \"Git "
},
{
"path": ".github/workflows/smoke_test.yml",
"chars": 1244,
"preview": "name: Smoke Test\n\non:\n push:\n branches:\n - master\n paths-ignore:\n - 'README*.md'\n - 'changelogs/**"
},
{
"path": ".github/workflows/stale.yml",
"chars": 1814,
"preview": "# 本工作流用于标记并关闭长期不活跃的 Issue。\n# 目前仅针对带 `bug` 标签的 Issue 生效,不会处理 PR。\n#\n# 文档: https://github.com/actions/stale\nname: Mark stal"
},
{
"path": ".github/workflows/sync-wiki.yml",
"chars": 2053,
"preview": "name: sync wiki\n\non:\n workflow_dispatch:\n push:\n branches:\n - master\n paths:\n - '.github/workflows/syn"
},
{
"path": ".gitignore",
"chars": 799,
"preview": "# Python related\n__pycache__\n.mypy_cache\n.venv*\n.conda/\nuv.lock\n.coverage\n\n# IDE and editors\n.vscode\n.idea\n\n# Logs and t"
},
{
"path": ".pre-commit-config.yaml",
"chars": 669,
"preview": "default_install_hook_types: [pre-commit, prepare-commit-msg]\nci:\n autofix_commit_msg: \":balloon: auto fixes by pre-comm"
},
{
"path": ".python-version",
"chars": 4,
"preview": "3.12"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5222,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 3763,
"preview": "# CONTRIBUTING\n\n## 贡献指南\n\n首先,感谢您花时间做出贡献!❤️\n\n所有类型的贡献都受到鼓励和重视。有关不同的帮助方式和处理方式的详细信息,请参阅[目录](#目录)。在做出贡献之前,请确保阅读相关部分。这将使我们维护人员的"
},
{
"path": "Dockerfile",
"chars": 834,
"preview": "FROM python:3.12-slim\nWORKDIR /AstrBot\n\nCOPY . /AstrBot/\n\nRUN apt-get update && apt-get install -y --no-install-recommen"
},
{
"path": "EULA.md",
"chars": 9797,
"preview": "# 最终用户许可协议(EULA)\n\n> 我们热爱开源软件,并始终致力于为所有用户提供健康、安全、可靠的使用体验。 ❤️\n\nFor English edition, please refer to the section below the "
},
{
"path": "FIRST_NOTICE.en-US.md",
"chars": 894,
"preview": "## Welcome to AstrBot\n\n🌟 Thank you for using AstrBot!\n\nAstrBot is an Agentic AI assistant for personal and group chats, "
},
{
"path": "FIRST_NOTICE.md",
"chars": 458,
"preview": "## 欢迎使用 AstrBot\n\n🌟 感谢您使用 AstrBot!\n\nAstrBot 是一款可接入多种 IM 平台的 Agentic AI 个人 / 群聊助手,内置多项强大功能,希望能为您带来高效、愉快的使用体验。❤️\n\n我们想特别说明:\n"
},
{
"path": "LICENSE",
"chars": 34500,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\n Version 3, 19 November 2007\n\n Copyright (C)"
},
{
"path": "Makefile",
"chars": 1107,
"preview": ".PHONY: worktree worktree-add worktree-rm pr-test-neo pr-test-full pr-test-full-fast\n\nWORKTREE_DIR ?= ../astrbot_worktre"
},
{
"path": "README.md",
"chars": 13803,
"preview": "\n\n<div align="
},
{
"path": "README_fr.md",
"chars": 14762,
"preview": "\n\n<div align="
},
{
"path": "README_ja.md",
"chars": 11330,
"preview": "\n\n<div align="
},
{
"path": "README_ru.md",
"chars": 14291,
"preview": "\n\n<div align="
},
{
"path": "README_zh-TW.md",
"chars": 10317,
"preview": "\n\n<div align="
},
{
"path": "README_zh.md",
"chars": 10860,
"preview": "\n\n<div align="
},
{
"path": "astrbot/__init__.py",
"chars": 84,
"preview": "from .core.log import LogManager\n\nlogger = LogManager.GetLogger(log_name=\"astrbot\")\n"
},
{
"path": "astrbot/api/__init__.py",
"chars": 568,
"preview": "from astrbot import logger\nfrom astrbot.core import html_renderer, sp\nfrom astrbot.core.agent.tool import FunctionTool, "
},
{
"path": "astrbot/api/all.py",
"chars": 1464,
"preview": "from astrbot.core.config.astrbot_config import AstrBotConfig\nfrom astrbot import logger\nfrom astrbot.core import html_re"
},
{
"path": "astrbot/api/event/__init__.py",
"chars": 368,
"preview": "from astrbot.core.message.message_event_result import (\n CommandResult,\n EventResultType,\n MessageChain,\n Me"
},
{
"path": "astrbot/api/event/filter/__init__.py",
"chars": 2760,
"preview": "from astrbot.core.star.filter.custom_filter import CustomFilter\nfrom astrbot.core.star.filter.event_message_type import "
},
{
"path": "astrbot/api/message_components.py",
"chars": 46,
"preview": "from astrbot.core.message.components import *\n"
},
{
"path": "astrbot/api/platform/__init__.py",
"chars": 465,
"preview": "from astrbot.core.message.components import *\nfrom astrbot.core.platform import (\n AstrBotMessage,\n AstrMessageEve"
},
{
"path": "astrbot/api/provider/__init__.py",
"chars": 379,
"preview": "from astrbot.core.db.po import Personality\nfrom astrbot.core.provider import Provider, STTProvider\nfrom astrbot.core.pro"
},
{
"path": "astrbot/api/star/__init__.py",
"chars": 238,
"preview": "from astrbot.core.star import Context, Star, StarTools\nfrom astrbot.core.star.config import *\nfrom astrbot.core.star.reg"
},
{
"path": "astrbot/api/util/__init__.py",
"chars": 180,
"preview": "from astrbot.core.utils.session_waiter import (\n SessionController,\n SessionWaiter,\n session_waiter,\n)\n\n__all__"
},
{
"path": "astrbot/builtin_stars/astrbot/long_term_memory.py",
"chars": 7524,
"preview": "import datetime\nimport random\nimport uuid\nfrom collections import defaultdict\n\nfrom astrbot import logger\nfrom astrbot.a"
},
{
"path": "astrbot/builtin_stars/astrbot/main.py",
"chars": 4382,
"preview": "import traceback\n\nfrom astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, filter\nfrom astrbot.api.m"
},
{
"path": "astrbot/builtin_stars/astrbot/metadata.yaml",
"chars": 105,
"preview": "name: astrbot\ndesc: AstrBot 自带插件,包含人格注入、思考内容注入、群聊上下文感知等功能的实现,禁用后将无法使用这些功能。\nauthor: Soulter\nversion: 4.1.0"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/__init__.py",
"chars": 705,
"preview": "# Commands module\n\nfrom .admin import AdminCommands\nfrom .alter_cmd import AlterCmdCommands\nfrom .conversation import Co"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/admin.py",
"chars": 3037,
"preview": "from astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageChain, MessageEventResult\nfrom astrb"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/alter_cmd.py",
"chars": 6478,
"preview": "from astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageChain\nfrom astrbot.core.star.filter."
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/conversation.py",
"chars": 14835,
"preview": "import datetime\n\nfrom astrbot.api import sp, star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\nfro"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/help.py",
"chars": 2902,
"preview": "import aiohttp\n\nfrom astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\nfrom ast"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/llm.py",
"chars": 702,
"preview": "from astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageChain\n\n\nclass LLMCommands:\n def _"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/persona.py",
"chars": 7138,
"preview": "import builtins\nfrom typing import TYPE_CHECKING\n\nfrom astrbot.api import star\nfrom astrbot.api.event import AstrMessage"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/plugin.py",
"chars": 5042,
"preview": "from astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\nfrom astrbot.core import"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/provider.py",
"chars": 26553,
"preview": "from __future__ import annotations\n\nimport asyncio\nimport time\nfrom collections.abc import Sequence\nfrom dataclasses imp"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/setunset.py",
"chars": 1289,
"preview": "from astrbot.api import sp, star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\n\n\nclass SetUnsetComm"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/sid.py",
"chars": 1172,
"preview": "\"\"\"会话ID命令\"\"\"\n\nfrom astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\n\n\nclass SI"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/t2i.py",
"chars": 703,
"preview": "\"\"\"文本转图片命令\"\"\"\n\nfrom astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\n\n\nclass T"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/tts.py",
"chars": 1166,
"preview": "\"\"\"文本转语音命令\"\"\"\n\nfrom astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, MessageEventResult\nfrom astr"
},
{
"path": "astrbot/builtin_stars/builtin_commands/commands/utils/rst_scene.py",
"chars": 745,
"preview": "from enum import Enum\n\n\nclass RstScene(Enum):\n GROUP_UNIQUE_ON = (\"group_unique_on\", \"群聊+会话隔离开启\")\n GROUP_UNIQUE_OF"
},
{
"path": "astrbot/builtin_stars/builtin_commands/main.py",
"chars": 7678,
"preview": "from astrbot.api import star\nfrom astrbot.api.event import AstrMessageEvent, filter\n\nfrom .commands import (\n AdminCo"
},
{
"path": "astrbot/builtin_stars/builtin_commands/metadata.yaml",
"chars": 96,
"preview": "name: builtin_commands\ndesc: AstrBot 自带指令,提供常用的对话管理、工具使用、插件管理等功能。\nauthor: Soulter\nversion: 0.0.1"
},
{
"path": "astrbot/builtin_stars/session_controller/main.py",
"chars": 4899,
"preview": "import copy\nfrom sys import maxsize\n\nimport astrbot.api.message_components as Comp\nfrom astrbot.api import logger\nfrom a"
},
{
"path": "astrbot/builtin_stars/session_controller/metadata.yaml",
"chars": 108,
"preview": "name: session_controller\ndesc: 为插件支持会话控制\nauthor: Cvandia & Soulter\nversion: v1.0.1\nrepo: https://astrbot.app"
},
{
"path": "astrbot/builtin_stars/web_searcher/engines/__init__.py",
"chars": 4269,
"preview": "import random\nimport urllib.parse\nfrom dataclasses import dataclass\n\nfrom aiohttp import ClientSession\nfrom bs4 import B"
},
{
"path": "astrbot/builtin_stars/web_searcher/engines/bing.py",
"chars": 1035,
"preview": "from . import USER_AGENT_BING, SearchEngine\n\n\nclass Bing(SearchEngine):\n def __init__(self) -> None:\n super()."
},
{
"path": "astrbot/builtin_stars/web_searcher/engines/sogo.py",
"chars": 1701,
"preview": "import random\nimport re\nfrom typing import cast\n\nfrom bs4 import BeautifulSoup, Tag\n\nfrom . import USER_AGENTS, SearchEn"
},
{
"path": "astrbot/builtin_stars/web_searcher/main.py",
"chars": 23827,
"preview": "import asyncio\nimport json\nimport random\nimport uuid\n\nimport aiohttp\nfrom bs4 import BeautifulSoup\nfrom readability impo"
},
{
"path": "astrbot/builtin_stars/web_searcher/metadata.yaml",
"chars": 81,
"preview": "name: astrbot-web-searcher\ndesc: 让 LLM 具有网页检索能力\nauthor: Soulter\nversion: 1.14.514"
},
{
"path": "astrbot/cli/__init__.py",
"chars": 23,
"preview": "__version__ = \"4.20.1\"\n"
},
{
"path": "astrbot/cli/__main__.py",
"chars": 1797,
"preview": "\"\"\"AstrBot CLI entry point\"\"\"\n\nimport sys\n\nimport click\n\nfrom . import __version__\nfrom .commands import conf, init, plu"
},
{
"path": "astrbot/cli/commands/__init__.py",
"chars": 149,
"preview": "from .cmd_conf import conf\nfrom .cmd_init import init\nfrom .cmd_plug import plug\nfrom .cmd_run import run\n\n__all__ = [\"c"
},
{
"path": "astrbot/cli/commands/cmd_conf.py",
"chars": 6511,
"preview": "import hashlib\nimport json\nimport zoneinfo\nfrom collections.abc import Callable\nfrom typing import Any\n\nimport click\n\nfr"
},
{
"path": "astrbot/cli/commands/cmd_init.py",
"chars": 1663,
"preview": "import asyncio\nfrom pathlib import Path\n\nimport click\nfrom filelock import FileLock, Timeout\n\nfrom ..utils import check_"
},
{
"path": "astrbot/cli/commands/cmd_plug.py",
"chars": 7607,
"preview": "import re\nimport shutil\nfrom pathlib import Path\n\nimport click\n\nfrom ..utils import (\n PluginStatus,\n build_plug_l"
},
{
"path": "astrbot/cli/commands/cmd_run.py",
"chars": 1999,
"preview": "import asyncio\nimport os\nimport sys\nimport traceback\nfrom pathlib import Path\n\nimport click\nfrom filelock import FileLoc"
},
{
"path": "astrbot/cli/utils/__init__.py",
"chars": 416,
"preview": "from .basic import (\n check_astrbot_root,\n check_dashboard,\n get_astrbot_root,\n)\nfrom .plugin import PluginStat"
},
{
"path": "astrbot/cli/utils/basic.py",
"chars": 3085,
"preview": "from pathlib import Path\n\nimport click\n\n# Static assets bundled inside the installed wheel (built by hatch_build.py).\n_B"
},
{
"path": "astrbot/cli/utils/plugin.py",
"chars": 8847,
"preview": "import shutil\nimport tempfile\nfrom enum import Enum\nfrom io import BytesIO\nfrom pathlib import Path\nfrom zipfile import "
},
{
"path": "astrbot/cli/utils/version_comparator.py",
"chars": 3439,
"preview": "\"\"\"Copied from astrbot.core.utils.version_comparator\"\"\"\n\nimport re\n\n\nclass VersionComparator:\n @staticmethod\n def "
},
{
"path": "astrbot/core/__init__.py",
"chars": 1738,
"preview": "import os\n\nfrom astrbot.core.config import AstrBotConfig\nfrom astrbot.core.config.default import DB_PATH\nfrom astrbot.co"
},
{
"path": "astrbot/core/agent/agent.py",
"chars": 414,
"preview": "from dataclasses import dataclass\nfrom typing import Any, Generic\n\nfrom .hooks import BaseAgentRunHooks\nfrom .run_contex"
},
{
"path": "astrbot/core/agent/context/compressor.py",
"chars": 8349,
"preview": "from typing import TYPE_CHECKING, Protocol, runtime_checkable\n\nfrom ..message import Message\n\nif TYPE_CHECKING:\n from"
},
{
"path": "astrbot/core/agent/context/config.py",
"chars": 1424,
"preview": "from dataclasses import dataclass\nfrom typing import TYPE_CHECKING\n\nfrom .compressor import ContextCompressor\nfrom .toke"
},
{
"path": "astrbot/core/agent/context/manager.py",
"chars": 3986,
"preview": "from astrbot import logger\n\nfrom ..message import Message\nfrom .compressor import LLMSummaryCompressor, TruncateByTurnsC"
},
{
"path": "astrbot/core/agent/context/token_counter.py",
"chars": 2688,
"preview": "import json\nfrom typing import Protocol, runtime_checkable\n\nfrom ..message import AudioURLPart, ImageURLPart, Message, T"
},
{
"path": "astrbot/core/agent/context/truncator.py",
"chars": 7467,
"preview": "from ..message import Message\n\n\nclass ContextTruncator:\n \"\"\"Context truncator.\"\"\"\n\n def _has_tool_calls(self, mess"
},
{
"path": "astrbot/core/agent/handoff.py",
"chars": 2753,
"preview": "from typing import Generic\n\nfrom .agent import Agent\nfrom .run_context import TContext\nfrom .tool import FunctionTool\n\n\n"
},
{
"path": "astrbot/core/agent/hooks.py",
"chars": 862,
"preview": "from typing import Generic\n\nimport mcp\n\nfrom astrbot.core.agent.tool import FunctionTool\nfrom astrbot.core.provider.enti"
},
{
"path": "astrbot/core/agent/mcp_client.py",
"chars": 14841,
"preview": "import asyncio\nimport logging\nfrom contextlib import AsyncExitStack\nfrom datetime import timedelta\nfrom typing import Ge"
},
{
"path": "astrbot/core/agent/message.py",
"chars": 6988,
"preview": "# Inspired by MoonshotAI/kosong, credits to MoonshotAI/kosong authors for the original implementation.\n# License: Apache"
},
{
"path": "astrbot/core/agent/response.py",
"chars": 859,
"preview": "import typing as T\nfrom dataclasses import dataclass, field\n\nfrom astrbot.core.message.message_event_result import Messa"
},
{
"path": "astrbot/core/agent/run_context.py",
"chars": 677,
"preview": "from typing import Any, Generic\n\nfrom pydantic import Field\nfrom pydantic.dataclasses import dataclass\nfrom typing_exten"
},
{
"path": "astrbot/core/agent/runners/__init__.py",
"chars": 65,
"preview": "from .base import BaseAgentRunner\n\n__all__ = [\"BaseAgentRunner\"]\n"
},
{
"path": "astrbot/core/agent/runners/base.py",
"chars": 1885,
"preview": "import abc\nimport typing as T\nfrom enum import Enum, auto\n\nfrom astrbot import logger\nfrom astrbot.core.provider.entitie"
},
{
"path": "astrbot/core/agent/runners/coze/coze_agent_runner.py",
"chars": 13272,
"preview": "import base64\nimport json\nimport sys\nimport typing as T\n\nimport astrbot.core.message.components as Comp\nfrom astrbot imp"
},
{
"path": "astrbot/core/agent/runners/coze/coze_api_client.py",
"chars": 10213,
"preview": "import asyncio\nimport io\nimport json\nfrom collections.abc import AsyncGenerator\nfrom typing import Any\n\nimport aiohttp\n\n"
},
{
"path": "astrbot/core/agent/runners/dashscope/dashscope_agent_runner.py",
"chars": 12651,
"preview": "import asyncio\nimport functools\nimport queue\nimport re\nimport sys\nimport threading\nimport typing as T\n\nfrom dashscope im"
},
{
"path": "astrbot/core/agent/runners/deerflow/constants.py",
"chars": 205,
"preview": "DEERFLOW_PROVIDER_TYPE = \"deerflow\"\nDEERFLOW_THREAD_ID_KEY = \"deerflow_thread_id\"\nDEERFLOW_SESSION_PREFIX = \"deerflow-ep"
},
{
"path": "astrbot/core/agent/runners/deerflow/deerflow_agent_runner.py",
"chars": 24633,
"preview": "import asyncio\nimport hashlib\nimport json\nimport sys\nimport typing as T\nfrom collections import deque\nfrom dataclasses i"
},
{
"path": "astrbot/core/agent/runners/deerflow/deerflow_api_client.py",
"chars": 8270,
"preview": "import codecs\nimport json\nfrom collections.abc import AsyncGenerator\nfrom typing import Any\n\nfrom aiohttp import ClientR"
},
{
"path": "astrbot/core/agent/runners/deerflow/deerflow_content_mapper.py",
"chars": 5947,
"preview": "import base64\nfrom collections.abc import Callable\nfrom typing import Any\n\nimport astrbot.core.message.components as Com"
},
{
"path": "astrbot/core/agent/runners/deerflow/deerflow_stream_utils.py",
"chars": 6681,
"preview": "import typing as T\nfrom collections.abc import Iterable\n\n\ndef extract_text(content: T.Any) -> str:\n if isinstance(con"
},
{
"path": "astrbot/core/agent/runners/dify/dify_agent_runner.py",
"chars": 12644,
"preview": "import base64\nimport os\nimport sys\nimport typing as T\n\nimport astrbot.core.message.components as Comp\nfrom astrbot.core "
},
{
"path": "astrbot/core/agent/runners/dify/dify_api_client.py",
"chars": 6454,
"preview": "import codecs\nimport json\nfrom collections.abc import AsyncGenerator\nfrom typing import Any\n\nfrom aiohttp import ClientR"
},
{
"path": "astrbot/core/agent/runners/tool_loop_agent_runner.py",
"chars": 39888,
"preview": "import asyncio\nimport copy\nimport sys\nimport time\nimport traceback\nimport typing as T\nfrom dataclasses import dataclass,"
},
{
"path": "astrbot/core/agent/tool.py",
"chars": 11894,
"preview": "import copy\nfrom collections.abc import AsyncGenerator, Awaitable, Callable\nfrom typing import Any, Generic\n\nimport json"
},
{
"path": "astrbot/core/agent/tool_executor.py",
"chars": 438,
"preview": "from collections.abc import AsyncGenerator\nfrom typing import Any, Generic\n\nimport mcp\n\nfrom .run_context import Context"
},
{
"path": "astrbot/core/agent/tool_image_cache.py",
"chars": 5236,
"preview": "\"\"\"Tool image cache module for storing and retrieving images returned by tools.\n\nThis module allows LLM to review images"
},
{
"path": "astrbot/core/astr_agent_context.py",
"chars": 637,
"preview": "from pydantic import Field\nfrom pydantic.dataclasses import dataclass\n\nfrom astrbot.core.agent.run_context import Contex"
},
{
"path": "astrbot/core/astr_agent_hooks.py",
"chars": 3054,
"preview": "from typing import Any\n\nfrom mcp.types import CallToolResult\n\nfrom astrbot.core.agent.hooks import BaseAgentRunHooks\nfro"
},
{
"path": "astrbot/core/astr_agent_run_util.py",
"chars": 17890,
"preview": "import asyncio\nimport re\nimport time\nimport traceback\nfrom collections.abc import AsyncGenerator\n\nfrom astrbot.core impo"
},
{
"path": "astrbot/core/astr_agent_tool_exec.py",
"chars": 27055,
"preview": "import asyncio\nimport inspect\nimport json\nimport traceback\nimport typing as T\nimport uuid\nfrom collections.abc import Se"
},
{
"path": "astrbot/core/astr_main_agent.py",
"chars": 46698,
"preview": "from __future__ import annotations\n\nimport asyncio\nimport copy\nimport datetime\nimport json\nimport os\nimport platform\nimp"
},
{
"path": "astrbot/core/astr_main_agent_resources.py",
"chars": 21898,
"preview": "import base64\nimport json\nimport os\nimport uuid\n\nfrom pydantic import Field\nfrom pydantic.dataclasses import dataclass\n\n"
},
{
"path": "astrbot/core/astrbot_config_mgr.py",
"chars": 8340,
"preview": "import os\nimport uuid\nfrom typing import TypedDict, TypeVar\n\nfrom astrbot.core import AstrBotConfig, logger\nfrom astrbot"
},
{
"path": "astrbot/core/backup/__init__.py",
"chars": 521,
"preview": "\"\"\"AstrBot 备份与恢复模块\n\n提供数据导出和导入功能,支持用户在服务器迁移时一键备份和恢复所有数据。\n\"\"\"\n\n# 从 constants 模块导入共享常量\nfrom .constants import (\n BACKUP_"
},
{
"path": "astrbot/core/backup/constants.py",
"chars": 1992,
"preview": "\"\"\"AstrBot 备份模块共享常量\n\n此文件定义了导出器和导入器共享的常量,确保两端配置一致。\n\"\"\"\n\nfrom sqlmodel import SQLModel\n\nfrom astrbot.core.db.po import (\n "
},
{
"path": "astrbot/core/backup/exporter.py",
"chars": 17608,
"preview": "\"\"\"AstrBot 数据导出器\n\n负责将所有数据导出为 ZIP 备份文件。\n导出格式为 JSON,这是数据库无关的方案,支持未来向 MySQL/PostgreSQL 迁移。\n\"\"\"\n\nimport hashlib\nimport json\n"
},
{
"path": "astrbot/core/backup/importer.py",
"chars": 32487,
"preview": "\"\"\"AstrBot 数据导入器\n\n负责从 ZIP 备份文件恢复所有数据。\n导入时进行版本校验:\n- 主版本(前两位)不同时直接拒绝导入\n- 小版本(第三位)不同时提示警告,用户可选择强制导入\n- 版本匹配时也需要用户确认\n\"\"\"\n\nimp"
},
{
"path": "astrbot/core/computer/booters/base.py",
"chars": 1286,
"preview": "from ..olayer import (\n BrowserComponent,\n FileSystemComponent,\n PythonComponent,\n ShellComponent,\n)\n\n\nclass"
},
{
"path": "astrbot/core/computer/booters/bay_manager.py",
"chars": 9795,
"preview": "\"\"\"Manage Bay container lifecycle for zero-config Shipyard Neo integration.\n\nWhen no Bay endpoint is configured, AstrBot"
},
{
"path": "astrbot/core/computer/booters/boxlite.py",
"chars": 6678,
"preview": "import asyncio\nimport random\nfrom typing import Any\n\nimport aiohttp\nimport boxlite\nfrom shipyard.filesystem import FileS"
},
{
"path": "astrbot/core/computer/booters/local.py",
"chars": 8684,
"preview": "from __future__ import annotations\n\nimport asyncio\nimport locale\nimport os\nimport shutil\nimport subprocess\nimport sys\nfr"
},
{
"path": "astrbot/core/computer/booters/shipyard.py",
"chars": 2748,
"preview": "from shipyard import ShipyardClient, Spec\n\nfrom astrbot.api import logger\n\nfrom ..olayer import FileSystemComponent, Pyt"
},
{
"path": "astrbot/core/computer/booters/shipyard_neo.py",
"chars": 17501,
"preview": "from __future__ import annotations\n\nimport os\nimport shlex\nfrom typing import Any, cast\n\nfrom astrbot.api import logger\n"
},
{
"path": "astrbot/core/computer/computer_client.py",
"chars": 17826,
"preview": "import json\nimport os\nimport shutil\nimport uuid\nfrom pathlib import Path\n\nfrom astrbot.api import logger\nfrom astrbot.co"
},
{
"path": "astrbot/core/computer/olayer/__init__.py",
"chars": 263,
"preview": "from .browser import BrowserComponent\nfrom .filesystem import FileSystemComponent\nfrom .python import PythonComponent\nfr"
},
{
"path": "astrbot/core/computer/olayer/browser.py",
"chars": 1140,
"preview": "\"\"\"\nBrowser automation component\n\"\"\"\n\nfrom typing import Any, Protocol\n\n\nclass BrowserComponent(Protocol):\n \"\"\"Browse"
},
{
"path": "astrbot/core/computer/olayer/filesystem.py",
"chars": 865,
"preview": "\"\"\"\nFile system component\n\"\"\"\n\nfrom typing import Any, Protocol\n\n\nclass FileSystemComponent(Protocol):\n async def cre"
},
{
"path": "astrbot/core/computer/olayer/python.py",
"chars": 368,
"preview": "\"\"\"\nPython/IPython component\n\"\"\"\n\nfrom typing import Any, Protocol\n\n\nclass PythonComponent(Protocol):\n \"\"\"Python/IPyt"
},
{
"path": "astrbot/core/computer/olayer/shell.py",
"chars": 430,
"preview": "\"\"\"\nShell component\n\"\"\"\n\nfrom typing import Any, Protocol\n\n\nclass ShellComponent(Protocol):\n \"\"\"Shell operations comp"
},
{
"path": "astrbot/core/computer/tools/__init__.py",
"chars": 1095,
"preview": "from .browser import BrowserBatchExecTool, BrowserExecTool, RunBrowserSkillTool\nfrom .fs import FileDownloadTool, FileUp"
},
{
"path": "astrbot/core/computer/tools/browser.py",
"chars": 7019,
"preview": "import json\nfrom dataclasses import dataclass, field\nfrom typing import Any\n\nfrom astrbot.api import FunctionTool\nfrom a"
},
{
"path": "astrbot/core/computer/tools/fs.py",
"chars": 8045,
"preview": "import os\nimport uuid\nfrom dataclasses import dataclass, field\n\nfrom astrbot.api import FunctionTool, logger\nfrom astrbo"
},
{
"path": "astrbot/core/computer/tools/neo_skills.py",
"chars": 17958,
"preview": "import json\nfrom collections.abc import Awaitable, Callable\nfrom dataclasses import dataclass, field\nfrom typing import "
},
{
"path": "astrbot/core/computer/tools/permissions.py",
"chars": 944,
"preview": "from astrbot.core.agent.run_context import ContextWrapper\nfrom astrbot.core.astr_agent_context import AstrAgentContext\n\n"
},
{
"path": "astrbot/core/computer/tools/python.py",
"chars": 3623,
"preview": "import platform\nfrom dataclasses import dataclass, field\n\nimport mcp\n\nfrom astrbot.api import FunctionTool\nfrom astrbot."
},
{
"path": "astrbot/core/computer/tools/shell.py",
"chars": 2254,
"preview": "import json\nfrom dataclasses import dataclass, field\n\nfrom astrbot.api import FunctionTool\nfrom astrbot.core.agent.run_c"
},
{
"path": "astrbot/core/config/__init__.py",
"chars": 172,
"preview": "from .astrbot_config import *\nfrom .default import DB_PATH, DEFAULT_CONFIG, VERSION\n\n__all__ = [\n \"DB_PATH\",\n \"DEF"
},
{
"path": "astrbot/core/config/astrbot_config.py",
"chars": 5676,
"preview": "import enum\nimport json\nimport logging\nimport os\n\nfrom astrbot.core.utils.astrbot_path import get_astrbot_data_path\n\nfro"
},
{
"path": "astrbot/core/config/default.py",
"chars": 174167,
"preview": "\"\"\"如需修改配置,请在 `data/cmd_config.json` 中修改或者在管理面板中可视化修改。\"\"\"\n\nimport os\nfrom typing import Any, TypedDict\n\nfrom astrbot.core"
},
{
"path": "astrbot/core/config/i18n_utils.py",
"chars": 4045,
"preview": "\"\"\"\n配置元数据国际化工具\n\n提供配置元数据的国际化键转换功能\n\"\"\"\n\nfrom typing import Any\n\n\nclass ConfigMetadataI18n:\n \"\"\"配置元数据国际化转换器\"\"\"\n\n @sta"
},
{
"path": "astrbot/core/conversation_mgr.py",
"chars": 14521,
"preview": "\"\"\"AstrBot 会话-对话管理器, 维护两个本地存储, 其中一个是 json 格式的shared_preferences, 另外一个是数据库.\n\n在 AstrBot 中, 会话和对话是独立的, 会话用于标记对话窗口, 例如群聊\"123"
},
{
"path": "astrbot/core/core_lifecycle.py",
"chars": 13816,
"preview": "\"\"\"Astrbot 核心生命周期管理类, 负责管理 AstrBot 的启动、停止、重启等操作.\n\n该类负责初始化各个组件, 包括 ProviderManager、PlatformManager、ConversationManager、Pl"
},
{
"path": "astrbot/core/cron/__init__.py",
"chars": 66,
"preview": "from .manager import CronJobManager\n\n__all__ = [\"CronJobManager\"]\n"
},
{
"path": "astrbot/core/cron/events.py",
"chars": 2289,
"preview": "import time\nimport uuid\nfrom typing import Any\n\nfrom astrbot.core.message.components import Plain\nfrom astrbot.core.mess"
},
{
"path": "astrbot/core/cron/manager.py",
"chars": 13547,
"preview": "import asyncio\nimport json\nfrom collections.abc import Awaitable, Callable\nfrom datetime import datetime, timezone\nfrom "
},
{
"path": "astrbot/core/db/__init__.py",
"chars": 22883,
"preview": "import abc\nimport datetime\nimport typing as T\nfrom contextlib import asynccontextmanager\nfrom dataclasses import datacla"
},
{
"path": "astrbot/core/db/migration/helper.py",
"chars": 1807,
"preview": "import os\n\nfrom astrbot.api import logger, sp\nfrom astrbot.core.config import AstrBotConfig\nfrom astrbot.core.db import "
},
{
"path": "astrbot/core/db/migration/migra_3_to_4.py",
"chars": 14589,
"preview": "import datetime\nimport json\n\nfrom sqlalchemy import text\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom astrbot.a"
},
{
"path": "astrbot/core/db/migration/migra_45_to_46.py",
"chars": 1536,
"preview": "from astrbot.api import logger, sp\nfrom astrbot.core.astrbot_config_mgr import AstrBotConfigManager\nfrom astrbot.core.um"
},
{
"path": "astrbot/core/db/migration/migra_token_usage.py",
"chars": 1902,
"preview": "\"\"\"Migration script to add token_usage column to conversations table.\n\nThis migration adds the token_usage field to trac"
},
{
"path": "astrbot/core/db/migration/migra_webchat_session.py",
"chars": 4901,
"preview": "\"\"\"Migration script for WebChat sessions.\n\nThis migration creates PlatformSession from existing platform_message_history"
},
{
"path": "astrbot/core/db/migration/shared_preferences_v3.py",
"chars": 1281,
"preview": "import json\nimport os\nfrom typing import TypeVar\n\nfrom astrbot.core.utils.astrbot_path import get_astrbot_data_path\n\n_VT"
},
{
"path": "astrbot/core/db/migration/sqlite_v3.py",
"chars": 14446,
"preview": "import sqlite3\nimport time\nfrom dataclasses import dataclass\nfrom typing import Any\n\nfrom astrbot.core.db.po import Plat"
},
{
"path": "astrbot/core/db/po.py",
"chars": 15738,
"preview": "import uuid\nfrom dataclasses import dataclass, field\nfrom datetime import datetime, timezone\nfrom typing import TypedDic"
},
{
"path": "astrbot/core/db/sqlite.py",
"chars": 69268,
"preview": "import asyncio\nimport threading\nimport typing as T\nfrom collections.abc import Awaitable, Callable\nfrom datetime import "
},
{
"path": "astrbot/core/db/vec_db/base.py",
"chars": 1539,
"preview": "import abc\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Result:\n similarity: float\n data: dict\n\n\nclass Bas"
},
{
"path": "astrbot/core/db/vec_db/faiss_impl/__init__.py",
"chars": 57,
"preview": "from .vec_db import FaissVecDB\n\n__all__ = [\"FaissVecDB\"]\n"
},
{
"path": "astrbot/core/db/vec_db/faiss_impl/document_storage.py",
"chars": 13290,
"preview": "import json\nimport os\nfrom contextlib import asynccontextmanager\nfrom datetime import datetime\n\nfrom sqlalchemy import C"
},
{
"path": "astrbot/core/db/vec_db/faiss_impl/embedding_storage.py",
"chars": 2725,
"preview": "try:\n import faiss\nexcept ModuleNotFoundError:\n raise ImportError(\n \"faiss 未安装。请使用 'pip install faiss-cpu' "
},
{
"path": "astrbot/core/db/vec_db/faiss_impl/sqlite_init.sql",
"chars": 639,
"preview": "-- 创建文档存储表,包含 faiss 中文档的 id,文档文本,create_at,updated_at\nCREATE TABLE documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,"
},
{
"path": "astrbot/core/db/vec_db/faiss_impl/vec_db.py",
"chars": 6694,
"preview": "import time\nimport uuid\n\nimport numpy as np\n\nfrom astrbot import logger\nfrom astrbot.core.provider.provider import Embed"
},
{
"path": "astrbot/core/event_bus.py",
"chars": 2308,
"preview": "\"\"\"事件总线, 用于处理事件的分发和处理\n事件总线是一个异步队列, 用于接收各种消息事件, 并将其发送到Scheduler调度器进行处理\n其中包含了一个无限循环的调度函数, 用于从事件队列中获取新的事件, 并创建一个新的异步任务来执行管道"
},
{
"path": "astrbot/core/exceptions.py",
"chars": 219,
"preview": "from __future__ import annotations\n\n\nclass AstrBotError(Exception):\n \"\"\"Base exception for all AstrBot errors.\"\"\"\n\n\nc"
},
{
"path": "astrbot/core/file_token_service.py",
"chars": 2943,
"preview": "import asyncio\nimport os\nimport platform\nimport time\nimport uuid\nfrom urllib.parse import unquote, urlparse\n\n\nclass File"
},
{
"path": "astrbot/core/initial_loader.py",
"chars": 1558,
"preview": "\"\"\"AstrBot 启动器,负责初始化和启动核心组件和仪表板服务器。\n\n工作流程:\n1. 初始化核心生命周期, 传递数据库和日志代理实例到核心生命周期\n2. 运行核心生命周期任务和仪表板服务器\n\"\"\"\n\nimport asyncio\nim"
},
{
"path": "astrbot/core/knowledge_base/chunking/__init__.py",
"chars": 143,
"preview": "\"\"\"文档分块模块\"\"\"\n\nfrom .base import BaseChunker\nfrom .fixed_size import FixedSizeChunker\n\n__all__ = [\n \"BaseChunker\",\n "
},
{
"path": "astrbot/core/knowledge_base/chunking/base.py",
"chars": 347,
"preview": "\"\"\"文档分块器基类\n\n定义了文档分块处理的抽象接口。\n\"\"\"\n\nfrom abc import ABC, abstractmethod\n\n\nclass BaseChunker(ABC):\n \"\"\"分块器基类\n\n 所有分块器都应"
},
{
"path": "astrbot/core/knowledge_base/chunking/fixed_size.py",
"chars": 1279,
"preview": "\"\"\"固定大小分块器\n\n按照固定的字符数将文本分块,支持重叠区域。\n\"\"\"\n\nfrom .base import BaseChunker\n\n\nclass FixedSizeChunker(BaseChunker):\n \"\"\"固定大小分"
},
{
"path": "astrbot/core/knowledge_base/chunking/recursive.py",
"chars": 5538,
"preview": "from collections.abc import Callable\n\nfrom .base import BaseChunker\n\n\nclass RecursiveCharacterChunker(BaseChunker):\n "
},
{
"path": "astrbot/core/knowledge_base/kb_db_sqlite.py",
"chars": 11880,
"preview": "from contextlib import asynccontextmanager\nfrom pathlib import Path\n\nfrom sqlalchemy import delete, func, select, text, "
},
{
"path": "astrbot/core/knowledge_base/kb_helper.py",
"chars": 21172,
"preview": "import asyncio\nimport json\nimport re\nimport time\nimport uuid\nfrom pathlib import Path\n\nimport aiofiles\n\nfrom astrbot.cor"
},
{
"path": "astrbot/core/knowledge_base/kb_mgr.py",
"chars": 10909,
"preview": "import traceback\nfrom pathlib import Path\n\nfrom astrbot.core import logger\nfrom astrbot.core.provider.manager import Pro"
},
{
"path": "astrbot/core/knowledge_base/models.py",
"chars": 3825,
"preview": "import uuid\nfrom datetime import datetime, timezone\n\nfrom sqlmodel import Field, MetaData, SQLModel, Text, UniqueConstra"
},
{
"path": "astrbot/core/knowledge_base/parsers/__init__.py",
"chars": 242,
"preview": "\"\"\"文档解析器模块\"\"\"\n\nfrom .base import BaseParser, MediaItem, ParseResult\nfrom .pdf_parser import PDFParser\nfrom .text_parser "
},
{
"path": "astrbot/core/knowledge_base/parsers/base.py",
"chars": 729,
"preview": "\"\"\"文档解析器基类和数据结构\n\n定义了文档解析器的抽象接口和相关数据类。\n\"\"\"\n\nfrom abc import ABC, abstractmethod\nfrom dataclasses import dataclass\n\n\n@data"
},
{
"path": "astrbot/core/knowledge_base/parsers/markitdown_parser.py",
"chars": 693,
"preview": "import io\nimport os\n\nfrom markitdown_no_magika import MarkItDown, StreamInfo\n\nfrom astrbot.core.knowledge_base.parsers.b"
},
{
"path": "astrbot/core/knowledge_base/parsers/pdf_parser.py",
"chars": 2865,
"preview": "\"\"\"PDF 文件解析器\n\n支持解析 PDF 文件中的文本和图片资源。\n\"\"\"\n\nimport io\n\nfrom pypdf import PdfReader\n\nfrom astrbot.core.knowledge_base.parser"
},
{
"path": "astrbot/core/knowledge_base/parsers/text_parser.py",
"chars": 887,
"preview": "\"\"\"文本文件解析器\n\n支持解析 TXT 和 Markdown 文件。\n\"\"\"\n\nfrom astrbot.core.knowledge_base.parsers.base import BaseParser, ParseResult\n\n\n"
},
{
"path": "astrbot/core/knowledge_base/parsers/url_parser.py",
"chars": 3072,
"preview": "import asyncio\n\nimport aiohttp\n\n\nclass URLExtractor:\n \"\"\"URL 内容提取器,封装了 Tavily API 调用和密钥管理\"\"\"\n\n def __init__(self, "
},
{
"path": "astrbot/core/knowledge_base/parsers/util.py",
"chars": 376,
"preview": "from .base import BaseParser\n\n\nasync def select_parser(ext: str) -> BaseParser:\n if ext in {\".md\", \".txt\", \".markdown"
},
{
"path": "astrbot/core/knowledge_base/prompts.py",
"chars": 2124,
"preview": "TEXT_REPAIR_SYSTEM_PROMPT = \"\"\"You are a meticulous digital archivist. Your mission is to reconstruct a clean, readable "
},
{
"path": "astrbot/core/knowledge_base/retrieval/__init__.py",
"chars": 318,
"preview": "\"\"\"检索模块\"\"\"\n\nfrom .manager import RetrievalManager, RetrievalResult\nfrom .rank_fusion import FusedResult, RankFusion\nfrom"
},
{
"path": "astrbot/core/knowledge_base/retrieval/hit_stopwords.txt",
"chars": 2350,
"preview": "———\n》),\n)÷(1-\n”,\n)、\n=(\n:\n→\n℃ \n&\n*\n一一\n~~~~\n’\n.\n『\n.一\n./\n-- \n』\n=″\n【\n[*]\n}>\n[⑤]]\n[①D]\nc]\nng昉\n*\n//\n[\n]\n[②e]\n[②g]\n={\n}\n,也 \n‘\nA"
},
{
"path": "astrbot/core/knowledge_base/retrieval/manager.py",
"chars": 8067,
"preview": "\"\"\"检索管理器\n\n协调稠密检索、稀疏检索和 Rerank,提供统一的检索接口\n\"\"\"\n\nimport time\nfrom dataclasses import dataclass\n\nfrom astrbot import logger\nf"
},
{
"path": "astrbot/core/knowledge_base/retrieval/rank_fusion.py",
"chars": 3979,
"preview": "\"\"\"检索结果融合器\n\n使用 Reciprocal Rank Fusion (RRF) 算法融合稠密检索和稀疏检索的结果\n\"\"\"\n\nimport json\nfrom dataclasses import dataclass\n\nfrom as"
},
{
"path": "astrbot/core/knowledge_base/retrieval/sparse_retriever.py",
"chars": 3561,
"preview": "\"\"\"稀疏检索器\n\n使用 BM25 算法进行基于关键词的文档检索\n\"\"\"\n\nimport json\nimport os\nfrom dataclasses import dataclass\n\nimport jieba\nfrom rank_bm"
},
{
"path": "astrbot/core/log.py",
"chars": 13507,
"preview": "\"\"\"日志系统,统一将标准 logging 输出转发到 loguru。\"\"\"\n\nimport asyncio\nimport logging\nimport os\nimport sys\nimport time\nfrom asyncio impo"
},
{
"path": "astrbot/core/message/components.py",
"chars": 26617,
"preview": "\"\"\"MIT License\n\nCopyright (c) 2021 Lxns-Network\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "astrbot/core/message/message_event_result.py",
"chars": 6665,
"preview": "import enum\nfrom collections.abc import AsyncGenerator\nfrom dataclasses import dataclass, field\n\nfrom typing_extensions "
},
{
"path": "astrbot/core/persona_error_reply.py",
"chars": 2873,
"preview": "from __future__ import annotations\n\nfrom collections.abc import Mapping\nfrom typing import Any\n\nPERSONA_CUSTOM_ERROR_MES"
},
{
"path": "astrbot/core/persona_mgr.py",
"chars": 14898,
"preview": "from astrbot import logger\nfrom astrbot.api import sp\nfrom astrbot.core.astrbot_config_mgr import AstrBotConfigManager\nf"
},
{
"path": "astrbot/core/pipeline/__init__.py",
"chars": 3412,
"preview": "\"\"\"Pipeline package exports.\n\nThis module intentionally avoids eager imports of all pipeline stage modules to\nprevent im"
},
{
"path": "astrbot/core/pipeline/bootstrap.py",
"chars": 1454,
"preview": "\"\"\"Pipeline bootstrap utilities.\"\"\"\n\nfrom importlib import import_module\n\nfrom .stage import registered_stages\n\n_BUILTIN"
}
]
// ... and 1031 more files (download for full content)
About this extraction
This page contains the full source code of the AstrBotDevs/AstrBot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1231 files (7.0 MB), approximately 1.9M tokens, and a symbol index with 5411 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.