Full Code of langbot-app/LangBot for AI

master 3ac3fad4bc64 cached
726 files
3.1 MB
865.6k tokens
3023 symbols
1 requests
Download .txt
Showing preview only (3,444K chars total). Download the full file or copy to clipboard to get everything.
Repository: langbot-app/LangBot
Branch: master
Commit: 3ac3fad4bc64
Files: 726
Total size: 3.1 MB

Directory structure:
gitextract_n8yk_ve4/

├── .dockerignore
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.yml
│   │   ├── bug-report_en.yml
│   │   ├── feature-request.yml
│   │   ├── feature-request_en.yml
│   │   ├── submit-plugin.yml
│   │   └── submit-plugin_en.yml
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── build-dev-image.yaml
│       ├── build-docker-image.yml
│       ├── build-release-artifacts.yaml
│       ├── lint.yml
│       ├── publish-to-pypi.yml
│       ├── run-tests.yml
│       └── test-dev-image.yaml
├── .gitignore
├── .mcp.json
├── .pre-commit-config.yaml
├── AGENTS.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── README_CN.md
├── README_ES.md
├── README_FR.md
├── README_JP.md
├── README_KO.md
├── README_RU.md
├── README_TW.md
├── README_VI.md
├── codecov.yml
├── docker/
│   ├── README_K8S.md
│   ├── deploy-k8s-test.sh
│   ├── docker-compose.yaml
│   └── kubernetes.yaml
├── docs/
│   ├── API_KEY_AUTH.md
│   ├── MIGRATION_SUMMARY.md
│   ├── PYPI_INSTALLATION.md
│   ├── SEEKDB_INTEGRATION.md
│   ├── TESTING_SUMMARY.md
│   ├── WEBSOCKET_README.md
│   └── service-api-openapi.json
├── main.py
├── pyproject.toml
├── pytest.ini
├── res/
│   ├── announcement.json
│   ├── announcement_saved.json
│   ├── instance_id.json
│   └── scripts/
│       └── publish_announcement.py
├── run_tests.sh
├── src/
│   └── langbot/
│       ├── __init__.py
│       ├── __main__.py
│       ├── libs/
│       │   ├── LICENSE
│       │   ├── README.md
│       │   ├── coze_server_api/
│       │   │   ├── __init__.py
│       │   │   └── client.py
│       │   ├── dify_service_api/
│       │   │   ├── README.md
│       │   │   ├── __init__.py
│       │   │   └── v1/
│       │   │       ├── __init__.py
│       │   │       ├── client.py
│       │   │       ├── client_test.py
│       │   │       └── errors.py
│       │   ├── dingtalk_api/
│       │   │   ├── EchoHandler.py
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── dingtalkevent.py
│       │   ├── official_account_api/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── oaevent.py
│       │   ├── qq_official_api/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── qqofficialevent.py
│       │   ├── slack_api/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── slackevent.py
│       │   ├── wechatpad_api/
│       │   │   ├── LICENSE
│       │   │   ├── README.md
│       │   │   ├── __init__.py
│       │   │   ├── api/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── chatroom.py
│       │   │   │   ├── downloadpai.py
│       │   │   │   ├── friend.py
│       │   │   │   ├── login.py
│       │   │   │   ├── message.py
│       │   │   │   └── user.py
│       │   │   ├── client.py
│       │   │   └── util/
│       │   │       ├── __init__.py
│       │   │       ├── http_util.py
│       │   │       └── terminal_printer.py
│       │   ├── wecom_ai_bot_api/
│       │   │   ├── WXBizMsgCrypt3.py
│       │   │   ├── api.py
│       │   │   ├── ierror.py
│       │   │   ├── wecombotevent.py
│       │   │   └── ws_client.py
│       │   ├── wecom_api/
│       │   │   ├── WXBizMsgCrypt3.py
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   ├── ierror.py
│       │   │   └── wecomevent.py
│       │   └── wecom_customer_service_api/
│       │       ├── __init__.py
│       │       ├── api.py
│       │       └── wecomcsevent.py
│       ├── pkg/
│       │   ├── __init__.py
│       │   ├── api/
│       │   │   ├── __init__.py
│       │   │   └── http/
│       │   │       ├── __init__.py
│       │   │       ├── controller/
│       │   │       │   ├── __init__.py
│       │   │       │   ├── group.py
│       │   │       │   ├── groups/
│       │   │       │   │   ├── __init__.py
│       │   │       │   │   ├── apikeys.py
│       │   │       │   │   ├── files.py
│       │   │       │   │   ├── knowledge/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── base.py
│       │   │       │   │   │   ├── engines.py
│       │   │       │   │   │   ├── migration.py
│       │   │       │   │   │   └── parsers.py
│       │   │       │   │   ├── logs.py
│       │   │       │   │   ├── monitoring.py
│       │   │       │   │   ├── pipelines/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── pipelines.py
│       │   │       │   │   │   └── websocket_chat.py
│       │   │       │   │   ├── platform/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── adapters.py
│       │   │       │   │   │   └── bots.py
│       │   │       │   │   ├── plugins.py
│       │   │       │   │   ├── provider/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── models.py
│       │   │       │   │   │   ├── providers.py
│       │   │       │   │   │   └── requesters.py
│       │   │       │   │   ├── resources/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   └── mcp.py
│       │   │       │   │   ├── stats.py
│       │   │       │   │   ├── survey.py
│       │   │       │   │   ├── system.py
│       │   │       │   │   ├── user.py
│       │   │       │   │   ├── webhook_mgmt.py
│       │   │       │   │   └── webhooks.py
│       │   │       │   └── main.py
│       │   │       └── service/
│       │   │           ├── __init__.py
│       │   │           ├── apikey.py
│       │   │           ├── bot.py
│       │   │           ├── knowledge.py
│       │   │           ├── mcp.py
│       │   │           ├── model.py
│       │   │           ├── monitoring.py
│       │   │           ├── pipeline.py
│       │   │           ├── provider.py
│       │   │           ├── space.py
│       │   │           ├── user.py
│       │   │           └── webhook.py
│       │   ├── command/
│       │   │   ├── __init__.py
│       │   │   ├── cmdmgr.py
│       │   │   ├── operator.py
│       │   │   └── operators/
│       │   │       ├── __init__.py
│       │   │       ├── delc.py
│       │   │       ├── last.py
│       │   │       ├── list.py
│       │   │       ├── next.py
│       │   │       ├── prompt.py
│       │   │       └── resend.py
│       │   ├── config/
│       │   │   ├── __init__.py
│       │   │   ├── impls/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── json.py
│       │   │   │   ├── pymodule.py
│       │   │   │   └── yaml.py
│       │   │   ├── manager.py
│       │   │   └── model.py
│       │   ├── core/
│       │   │   ├── __init__.py
│       │   │   ├── app.py
│       │   │   ├── boot.py
│       │   │   ├── bootutils/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── config.py
│       │   │   │   ├── deps.py
│       │   │   │   ├── files.py
│       │   │   │   └── log.py
│       │   │   ├── entities.py
│       │   │   ├── migration.py
│       │   │   ├── migrations/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── m001_sensitive_word_migration.py
│       │   │   │   ├── m002_openai_config_migration.py
│       │   │   │   ├── m003_anthropic_requester_cfg_completion.py
│       │   │   │   ├── m004_moonshot_cfg_completion.py
│       │   │   │   ├── m005_deepseek_cfg_completion.py
│       │   │   │   ├── m006_vision_config.py
│       │   │   │   ├── m007_qcg_center_url.py
│       │   │   │   ├── m008_ad_fixwin_config_migrate.py
│       │   │   │   ├── m009_msg_truncator_cfg.py
│       │   │   │   ├── m010_ollama_requester_config.py
│       │   │   │   ├── m011_command_prefix_config.py
│       │   │   │   ├── m012_runner_config.py
│       │   │   │   ├── m013_http_api_config.py
│       │   │   │   ├── m014_force_delay_config.py
│       │   │   │   ├── m015_gitee_ai_config.py
│       │   │   │   ├── m016_dify_service_api.py
│       │   │   │   ├── m017_dify_api_timeout_params.py
│       │   │   │   ├── m018_xai_config.py
│       │   │   │   ├── m019_zhipuai_config.py
│       │   │   │   ├── m020_wecom_config.py
│       │   │   │   ├── m021_lark_config.py
│       │   │   │   ├── m022_lmstudio_config.py
│       │   │   │   ├── m023_siliconflow_config.py
│       │   │   │   ├── m024_discord_config.py
│       │   │   │   ├── m025_gewechat_config.py
│       │   │   │   ├── m026_qqofficial_config.py
│       │   │   │   ├── m027_wx_official_account_config.py
│       │   │   │   ├── m028_aliyun_requester_config.py
│       │   │   │   ├── m029_dashscope_app_api_config.py
│       │   │   │   ├── m030_lark_config_cmpl.py
│       │   │   │   ├── m031_dingtalk_config.py
│       │   │   │   ├── m032_volcark_config.py
│       │   │   │   ├── m033_dify_thinking_config.py
│       │   │   │   ├── m034_gewechat_file_url_config.py
│       │   │   │   ├── m035_wxoa_mode.py
│       │   │   │   ├── m036_wxoa_loading_message.py
│       │   │   │   ├── m037_mcp_config.py
│       │   │   │   ├── m038_tg_dingtalk_markdown.py
│       │   │   │   ├── m039_modelscope_cfg_completion.py
│       │   │   │   ├── m040_ppio_config.py
│       │   │   │   └── m041_dingtalk_card_autolayout_config.py
│       │   │   ├── note.py
│       │   │   ├── notes/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── n001_classic_msgs.py
│       │   │   │   ├── n002_selection_mode_on_windows.py
│       │   │   │   └── n003_print_version.py
│       │   │   ├── stage.py
│       │   │   ├── stages/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── build_app.py
│       │   │   │   ├── genkeys.py
│       │   │   │   ├── load_config.py
│       │   │   │   ├── migrate.py
│       │   │   │   ├── setup_logger.py
│       │   │   │   └── show_notes.py
│       │   │   └── taskmgr.py
│       │   ├── discover/
│       │   │   ├── __init__.py
│       │   │   └── engine.py
│       │   ├── entity/
│       │   │   ├── __init__.py
│       │   │   ├── dto/
│       │   │   │   ├── __init__.py
│       │   │   │   └── space_model.py
│       │   │   ├── errors/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── account.py
│       │   │   │   ├── platform.py
│       │   │   │   └── provider.py
│       │   │   └── persistence/
│       │   │       ├── __init__.py
│       │   │       ├── apikey.py
│       │   │       ├── base.py
│       │   │       ├── bot.py
│       │   │       ├── bstorage.py
│       │   │       ├── mcp.py
│       │   │       ├── metadata.py
│       │   │       ├── model.py
│       │   │       ├── monitoring.py
│       │   │       ├── pipeline.py
│       │   │       ├── plugin.py
│       │   │       ├── rag.py
│       │   │       ├── user.py
│       │   │       ├── vector.py
│       │   │       └── webhook.py
│       │   ├── persistence/
│       │   │   ├── __init__.py
│       │   │   ├── database.py
│       │   │   ├── databases/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── postgresql.py
│       │   │   │   └── sqlite.py
│       │   │   ├── mgr.py
│       │   │   ├── migration.py
│       │   │   └── migrations/
│       │   │       ├── __init__.py
│       │   │       ├── dbm001_migrate_v3_config.py
│       │   │       ├── dbm002_combine_quote_msg_config.py
│       │   │       ├── dbm003_n8n_config.py
│       │   │       ├── dbm004_rag_kb_uuid.py
│       │   │       ├── dbm005_pipeline_remove_cot_config.py
│       │   │       ├── dbm006_langflow_api_config.py
│       │   │       ├── dbm007_plugin_install_source.py
│       │   │       ├── dbm008_plugin_config.py
│       │   │       ├── dbm009_pipeline_extension_preferences.py
│       │   │       ├── dbm010_pipeline_multi_knowledge_base.py
│       │   │       ├── dbm011_dify_base_prompt_config.py
│       │   │       ├── dbm012_pipeline_extensions_enable_all.py
│       │   │       ├── dbm013_knowledge_base_updated_at.py
│       │   │       ├── dbm014_space_account_support.py
│       │   │       ├── dbm015_model_source_tracking.py
│       │   │       ├── dbm016_model_provider_refactor.py
│       │   │       ├── dbm017_move_cloud_service_url.py
│       │   │       ├── dbm018_add_emoji_support.py
│       │   │       ├── dbm019_monitoring_message_role.py
│       │   │       ├── dbm020_knowledge_engine_plugin_architecture.py
│       │   │       ├── dbm021_merge_exception_handling.py
│       │   │       ├── dbm022_monitoring_user_name.py
│       │   │       ├── dbm023_model_fallback_config.py
│       │   │       └── dbm024_wecombot_websocket_mode.py
│       │   ├── pipeline/
│       │   │   ├── __init__.py
│       │   │   ├── aggregator.py
│       │   │   ├── bansess/
│       │   │   │   ├── __init__.py
│       │   │   │   └── bansess.py
│       │   │   ├── cntfilter/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── cntfilter.py
│       │   │   │   ├── entities.py
│       │   │   │   ├── filter.py
│       │   │   │   └── filters/
│       │   │   │       ├── __init__.py
│       │   │   │       ├── baiduexamine.py
│       │   │   │       ├── banwords.py
│       │   │   │       └── cntignore.py
│       │   │   ├── config_coercion.py
│       │   │   ├── controller.py
│       │   │   ├── entities.py
│       │   │   ├── longtext/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── longtext.py
│       │   │   │   ├── strategies/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── forward.py
│       │   │   │   │   └── image.py
│       │   │   │   └── strategy.py
│       │   │   ├── monitoring_helper.py
│       │   │   ├── msgtrun/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── msgtrun.py
│       │   │   │   ├── truncator.py
│       │   │   │   └── truncators/
│       │   │   │       ├── __init__.py
│       │   │   │       └── round.py
│       │   │   ├── pipelinemgr.py
│       │   │   ├── pool.py
│       │   │   ├── preproc/
│       │   │   │   ├── __init__.py
│       │   │   │   └── preproc.py
│       │   │   ├── process/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── handler.py
│       │   │   │   ├── handlers/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── chat.py
│       │   │   │   │   └── command.py
│       │   │   │   └── process.py
│       │   │   ├── ratelimit/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── algo.py
│       │   │   │   ├── algos/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   └── fixedwin.py
│       │   │   │   └── ratelimit.py
│       │   │   ├── respback/
│       │   │   │   ├── __init__.py
│       │   │   │   └── respback.py
│       │   │   ├── resprule/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── entities.py
│       │   │   │   ├── resprule.py
│       │   │   │   ├── rule.py
│       │   │   │   └── rules/
│       │   │   │       ├── __init__.py
│       │   │   │       ├── atbot.py
│       │   │   │       ├── prefix.py
│       │   │   │       ├── random.py
│       │   │   │       └── regexp.py
│       │   │   ├── stage.py
│       │   │   └── wrapper/
│       │   │       ├── __init__.py
│       │   │       └── wrapper.py
│       │   ├── platform/
│       │   │   ├── __init__.py
│       │   │   ├── botmgr.py
│       │   │   ├── logger.py
│       │   │   ├── sources/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── aiocqhttp.py
│       │   │   │   ├── aiocqhttp.yaml
│       │   │   │   ├── dingtalk.py
│       │   │   │   ├── dingtalk.yaml
│       │   │   │   ├── discord.py
│       │   │   │   ├── discord.yaml
│       │   │   │   ├── kook.py
│       │   │   │   ├── kook.yaml
│       │   │   │   ├── lark.py
│       │   │   │   ├── lark.yaml
│       │   │   │   ├── legacy/
│       │   │   │   │   ├── gewechat.py
│       │   │   │   │   ├── gewechat.yaml
│       │   │   │   │   ├── nakuru.py
│       │   │   │   │   ├── nakuru.yaml
│       │   │   │   │   ├── qqbotpy.py
│       │   │   │   │   └── qqbotpy.yaml
│       │   │   │   ├── line.py
│       │   │   │   ├── line.yaml
│       │   │   │   ├── officialaccount.py
│       │   │   │   ├── officialaccount.yaml
│       │   │   │   ├── qqofficial.py
│       │   │   │   ├── qqofficial.yaml
│       │   │   │   ├── satori.py
│       │   │   │   ├── satori.yaml
│       │   │   │   ├── slack.py
│       │   │   │   ├── slack.yaml
│       │   │   │   ├── telegram.py
│       │   │   │   ├── telegram.yaml
│       │   │   │   ├── websocket.yaml
│       │   │   │   ├── websocket_adapter.py
│       │   │   │   ├── websocket_manager.py
│       │   │   │   ├── wechatpad.py
│       │   │   │   ├── wechatpad.yaml
│       │   │   │   ├── wecom.py
│       │   │   │   ├── wecom.yaml
│       │   │   │   ├── wecombot.py
│       │   │   │   ├── wecombot.yaml
│       │   │   │   ├── wecomcs.py
│       │   │   │   └── wecomcs.yaml
│       │   │   └── webhook_pusher.py
│       │   ├── plugin/
│       │   │   ├── __init__.py
│       │   │   ├── connector.py
│       │   │   └── handler.py
│       │   ├── provider/
│       │   │   ├── __init__.py
│       │   │   ├── modelmgr/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── entities.py
│       │   │   │   ├── errors.py
│       │   │   │   ├── modelmgr.py
│       │   │   │   ├── requester.py
│       │   │   │   ├── requester.yaml
│       │   │   │   ├── requesters/
│       │   │   │   │   ├── 302aichatcmpl.py
│       │   │   │   │   ├── 302aichatcmpl.yaml
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── anthropicmsgs.py
│       │   │   │   │   ├── anthropicmsgs.yaml
│       │   │   │   │   ├── bailianchatcmpl.py
│       │   │   │   │   ├── bailianchatcmpl.yaml
│       │   │   │   │   ├── chatcmpl.py
│       │   │   │   │   ├── chatcmpl.yaml
│       │   │   │   │   ├── compsharechatcmpl.py
│       │   │   │   │   ├── compsharechatcmpl.yaml
│       │   │   │   │   ├── deepseekchatcmpl.py
│       │   │   │   │   ├── deepseekchatcmpl.yaml
│       │   │   │   │   ├── geminichatcmpl.py
│       │   │   │   │   ├── geminichatcmpl.yaml
│       │   │   │   │   ├── giteeaichatcmpl.py
│       │   │   │   │   ├── giteeaichatcmpl.yaml
│       │   │   │   │   ├── jiekouaichatcmpl.py
│       │   │   │   │   ├── jiekouaichatcmpl.yaml
│       │   │   │   │   ├── lmstudiochatcmpl.py
│       │   │   │   │   ├── lmstudiochatcmpl.yaml
│       │   │   │   │   ├── modelscopechatcmpl.py
│       │   │   │   │   ├── modelscopechatcmpl.yaml
│       │   │   │   │   ├── moonshotchatcmpl.py
│       │   │   │   │   ├── moonshotchatcmpl.yaml
│       │   │   │   │   ├── newapichatcmpl.py
│       │   │   │   │   ├── newapichatcmpl.yaml
│       │   │   │   │   ├── ollamachat.py
│       │   │   │   │   ├── ollamachat.yaml
│       │   │   │   │   ├── openrouterchatcmpl.py
│       │   │   │   │   ├── openrouterchatcmpl.yaml
│       │   │   │   │   ├── ppiochatcmpl.py
│       │   │   │   │   ├── ppiochatcmpl.yaml
│       │   │   │   │   ├── qhaigcchatcmpl.py
│       │   │   │   │   ├── qhaigcchatcmpl.yaml
│       │   │   │   │   ├── seekdbembed.py
│       │   │   │   │   ├── seekdbembed.yaml
│       │   │   │   │   ├── shengsuanyun.py
│       │   │   │   │   ├── shengsuanyun.yaml
│       │   │   │   │   ├── siliconflowchatcmpl.py
│       │   │   │   │   ├── siliconflowchatcmpl.yaml
│       │   │   │   │   ├── spacechatcmpl.py
│       │   │   │   │   ├── spacechatcmpl.yaml
│       │   │   │   │   ├── tokenpony.yaml
│       │   │   │   │   ├── tokenponychatcmpl.py
│       │   │   │   │   ├── volcarkchatcmpl.py
│       │   │   │   │   ├── volcarkchatcmpl.yaml
│       │   │   │   │   ├── xaichatcmpl.py
│       │   │   │   │   ├── xaichatcmpl.yaml
│       │   │   │   │   ├── zhipuaichatcmpl.py
│       │   │   │   │   └── zhipuaichatcmpl.yaml
│       │   │   │   └── token.py
│       │   │   ├── runner.py
│       │   │   ├── runners/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── cozeapi.py
│       │   │   │   ├── dashscopeapi.py
│       │   │   │   ├── difysvapi.py
│       │   │   │   ├── langflowapi.py
│       │   │   │   ├── localagent.py
│       │   │   │   ├── n8nsvapi.py
│       │   │   │   └── tboxapi.py
│       │   │   ├── session/
│       │   │   │   ├── __init__.py
│       │   │   │   └── sessionmgr.py
│       │   │   └── tools/
│       │   │       ├── __init__.py
│       │   │       ├── loader.py
│       │   │       ├── loaders/
│       │   │       │   ├── __init__.py
│       │   │       │   ├── mcp.py
│       │   │       │   └── plugin.py
│       │   │       └── toolmgr.py
│       │   ├── rag/
│       │   │   ├── knowledge/
│       │   │   │   ├── base.py
│       │   │   │   └── kbmgr.py
│       │   │   └── service/
│       │   │       ├── __init__.py
│       │   │       └── runtime.py
│       │   ├── storage/
│       │   │   ├── __init__.py
│       │   │   ├── mgr.py
│       │   │   ├── provider.py
│       │   │   └── providers/
│       │   │       ├── __init__.py
│       │   │       ├── localstorage.py
│       │   │       └── s3storage.py
│       │   ├── survey/
│       │   │   ├── __init__.py
│       │   │   └── manager.py
│       │   ├── telemetry/
│       │   │   ├── __init__.py
│       │   │   └── telemetry.py
│       │   ├── utils/
│       │   │   ├── __init__.py
│       │   │   ├── constants.py
│       │   │   ├── funcschema.py
│       │   │   ├── httpclient.py
│       │   │   ├── image.py
│       │   │   ├── importutil.py
│       │   │   ├── logcache.py
│       │   │   ├── paths.py
│       │   │   ├── pkgmgr.py
│       │   │   ├── platform.py
│       │   │   ├── proxy.py
│       │   │   ├── runner.py
│       │   │   └── version.py
│       │   └── vector/
│       │       ├── __init__.py
│       │       ├── filter_utils.py
│       │       ├── mgr.py
│       │       ├── vdb.py
│       │       └── vdbs/
│       │           ├── __init__.py
│       │           ├── chroma.py
│       │           ├── milvus.py
│       │           ├── pgvector_db.py
│       │           ├── qdrant.py
│       │           └── seekdb.py
│       └── templates/
│           ├── __init__.py
│           ├── components.yaml
│           ├── config.yaml
│           ├── default-pipeline-config.json
│           ├── legacy/
│           │   ├── command.json
│           │   ├── pipeline.json
│           │   ├── platform.json
│           │   ├── provider.json
│           │   └── system.json
│           └── metadata/
│               ├── pipeline/
│               │   ├── ai.yaml
│               │   ├── output.yaml
│               │   ├── safety.yaml
│               │   └── trigger.yaml
│               └── sensitive-words.json
├── tests/
│   ├── README.md
│   ├── __init__.py
│   └── unit_tests/
│       ├── __init__.py
│       ├── config/
│       │   ├── __init__.py
│       │   ├── test_env_override.py
│       │   └── test_webhook_display_prefix.py
│       ├── pipeline/
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_bansess.py
│       │   ├── test_config_coercion.py
│       │   ├── test_pipelinemgr.py
│       │   ├── test_ratelimit.py
│       │   ├── test_resprule.py
│       │   └── test_simple.py
│       ├── plugin/
│       │   ├── __init__.py
│       │   ├── test_plugin_component_filtering.py
│       │   └── test_plugin_list_sorting.py
│       └── storage/
│           ├── __init__.py
│           └── test_storage_provider_selection.py
└── web/
    ├── .env.example
    ├── .gitignore
    ├── .lintstagedrc.json
    ├── .prettierrc.mjs
    ├── README.md
    ├── components.json
    ├── eslint.config.mjs
    ├── next
    ├── next.config.ts
    ├── package.json
    ├── postcss.config.mjs
    ├── src/
    │   ├── app/
    │   │   ├── auth/
    │   │   │   └── space/
    │   │   │       └── callback/
    │   │   │           └── page.tsx
    │   │   ├── global.css
    │   │   ├── home/
    │   │   │   ├── bots/
    │   │   │   │   ├── BotDetailDialog.tsx
    │   │   │   │   ├── botConfig.module.css
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── bot-card/
    │   │   │   │   │   │   ├── BotCard.tsx
    │   │   │   │   │   │   ├── BotCardVO.ts
    │   │   │   │   │   │   └── botCard.module.css
    │   │   │   │   │   ├── bot-form/
    │   │   │   │   │   │   ├── BotForm.tsx
    │   │   │   │   │   │   └── ChooseEntity.ts
    │   │   │   │   │   ├── bot-log/
    │   │   │   │   │   │   ├── BotLogManager.ts
    │   │   │   │   │   │   └── view/
    │   │   │   │   │   │       ├── BotLogCard.tsx
    │   │   │   │   │   │       ├── BotLogListComponent.tsx
    │   │   │   │   │   │       └── botLog.module.css
    │   │   │   │   │   └── bot-session/
    │   │   │   │   │       └── BotSessionMonitor.tsx
    │   │   │   │   └── page.tsx
    │   │   │   ├── components/
    │   │   │   │   ├── account-settings-dialog/
    │   │   │   │   │   └── AccountSettingsDialog.tsx
    │   │   │   │   ├── api-integration-dialog/
    │   │   │   │   │   └── ApiIntegrationDialog.tsx
    │   │   │   │   ├── dynamic-form/
    │   │   │   │   │   ├── DynamicFormComponent.tsx
    │   │   │   │   │   ├── DynamicFormItemComponent.tsx
    │   │   │   │   │   ├── DynamicFormItemConfig.ts
    │   │   │   │   │   └── N8nAuthFormComponent.tsx
    │   │   │   │   ├── home-sidebar/
    │   │   │   │   │   ├── HomeSidebar.module.css
    │   │   │   │   │   ├── HomeSidebar.tsx
    │   │   │   │   │   ├── HomeSidebarChild.tsx
    │   │   │   │   │   └── sidbarConfigList.tsx
    │   │   │   │   ├── home-titlebar/
    │   │   │   │   │   ├── HomeTitleBar.tsx
    │   │   │   │   │   └── HomeTittleBar.module.css
    │   │   │   │   ├── models-dialog/
    │   │   │   │   │   ├── ModelsDialog.tsx
    │   │   │   │   │   ├── component/
    │   │   │   │   │   │   └── provider-form/
    │   │   │   │   │   │       └── ProviderForm.tsx
    │   │   │   │   │   ├── components/
    │   │   │   │   │   │   ├── AddModelPopover.tsx
    │   │   │   │   │   │   ├── ExtraArgsEditor.tsx
    │   │   │   │   │   │   ├── ModelItem.tsx
    │   │   │   │   │   │   ├── ProviderCard.tsx
    │   │   │   │   │   │   └── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── new-version-dialog/
    │   │   │   │   │   └── NewVersionDialog.tsx
    │   │   │   │   ├── password-change-dialog/
    │   │   │   │   │   └── PasswordChangeDialog.tsx
    │   │   │   │   └── survey/
    │   │   │   │       └── SurveyWidget.tsx
    │   │   │   ├── knowledge/
    │   │   │   │   ├── KBDetailDialog.tsx
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── kb-card/
    │   │   │   │   │   │   ├── KBCard.module.css
    │   │   │   │   │   │   ├── KBCard.tsx
    │   │   │   │   │   │   └── KBCardVO.ts
    │   │   │   │   │   ├── kb-docs/
    │   │   │   │   │   │   ├── FileUploadZone.tsx
    │   │   │   │   │   │   ├── KBDoc.tsx
    │   │   │   │   │   │   └── documents/
    │   │   │   │   │   │       ├── columns.tsx
    │   │   │   │   │   │       └── data-table.tsx
    │   │   │   │   │   ├── kb-form/
    │   │   │   │   │   │   ├── ChooseEntity.ts
    │   │   │   │   │   │   └── KBForm.tsx
    │   │   │   │   │   ├── kb-migration-dialog/
    │   │   │   │   │   │   └── KBMigrationDialog.tsx
    │   │   │   │   │   └── kb-retrieve/
    │   │   │   │   │       └── KBRetrieveGeneric.tsx
    │   │   │   │   ├── knowledgeBase.module.css
    │   │   │   │   └── page.tsx
    │   │   │   ├── layout.module.css
    │   │   │   ├── layout.tsx
    │   │   │   ├── loading.tsx
    │   │   │   ├── monitoring/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── ExportDropdown.tsx
    │   │   │   │   │   ├── MessageContentRenderer.tsx
    │   │   │   │   │   ├── MessageDetailsCard.tsx
    │   │   │   │   │   ├── filters/
    │   │   │   │   │   │   └── MonitoringFilters.tsx
    │   │   │   │   │   └── overview-cards/
    │   │   │   │   │       ├── MetricCard.tsx
    │   │   │   │   │       ├── OverviewCards.tsx
    │   │   │   │   │       └── TrafficChart.tsx
    │   │   │   │   ├── hooks/
    │   │   │   │   │   ├── useMonitoringData.ts
    │   │   │   │   │   └── useMonitoringFilters.ts
    │   │   │   │   ├── page.tsx
    │   │   │   │   ├── types/
    │   │   │   │   │   └── monitoring.ts
    │   │   │   │   └── utils/
    │   │   │   │       └── dateUtils.ts
    │   │   │   ├── page.tsx
    │   │   │   ├── pipelines/
    │   │   │   │   ├── PipelineDetailDialog.tsx
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── debug-dialog/
    │   │   │   │   │   │   ├── AtBadge.tsx
    │   │   │   │   │   │   ├── DebugDialog.tsx
    │   │   │   │   │   │   └── ImagePreviewDialog.tsx
    │   │   │   │   │   ├── monitoring-tab/
    │   │   │   │   │   │   └── PipelineMonitoringTab.tsx
    │   │   │   │   │   ├── pipeline-card/
    │   │   │   │   │   │   ├── PipelineCard.tsx
    │   │   │   │   │   │   ├── PipelineCardVO.ts
    │   │   │   │   │   │   └── pipelineCard.module.css
    │   │   │   │   │   ├── pipeline-extensions/
    │   │   │   │   │   │   └── PipelineExtension.tsx
    │   │   │   │   │   └── pipeline-form/
    │   │   │   │   │       ├── PipelineFormComponent.tsx
    │   │   │   │   │       └── pipelineFormStyle.module.css
    │   │   │   │   ├── page.tsx
    │   │   │   │   └── pipelineConfig.module.css
    │   │   │   └── plugins/
    │   │   │       ├── components/
    │   │   │       │   ├── plugin-installed/
    │   │   │       │   │   ├── PluginCardVO.ts
    │   │   │       │   │   ├── PluginComponentList.tsx
    │   │   │       │   │   ├── PluginInstalledComponent.tsx
    │   │   │       │   │   ├── plugin-card/
    │   │   │       │   │   │   └── PluginCardComponent.tsx
    │   │   │       │   │   ├── plugin-form/
    │   │   │       │   │   │   └── PluginForm.tsx
    │   │   │       │   │   └── plugin-readme/
    │   │   │       │   │       └── PluginReadme.tsx
    │   │   │       │   └── plugin-market/
    │   │   │       │       ├── PluginMarketComponent.tsx
    │   │   │       │       ├── RecommendationLists.tsx
    │   │   │       │       ├── TagsFilter.tsx
    │   │   │       │       └── plugin-market-card/
    │   │   │       │           ├── PluginMarketCardComponent.tsx
    │   │   │       │           └── PluginMarketCardVO.ts
    │   │   │       ├── mcp-server/
    │   │   │       │   ├── MCPCardVO.ts
    │   │   │       │   ├── MCPServerComponent.tsx
    │   │   │       │   ├── mcp-card/
    │   │   │       │   │   └── MCPCardComponent.tsx
    │   │   │       │   └── mcp-form/
    │   │   │       │       ├── MCPDeleteConfirmDialog.tsx
    │   │   │       │       └── MCPFormDialog.tsx
    │   │   │       ├── page.tsx
    │   │   │       └── plugins.module.css
    │   │   ├── infra/
    │   │   │   ├── basic-component/
    │   │   │   │   └── create-card-component/
    │   │   │   │       ├── CreateCardComponent.tsx
    │   │   │   │       └── createCartComponent.module.css
    │   │   │   ├── entities/
    │   │   │   │   ├── api/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── common.ts
    │   │   │   │   ├── form/
    │   │   │   │   │   └── dynamic.ts
    │   │   │   │   ├── message/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── pipeline/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── plugin/
    │   │   │   │       └── index.ts
    │   │   │   ├── http/
    │   │   │   │   ├── BackendClient.ts
    │   │   │   │   ├── BaseHttpClient.ts
    │   │   │   │   ├── CloudServiceClient.ts
    │   │   │   │   ├── HttpClient.ts
    │   │   │   │   ├── README.md
    │   │   │   │   ├── index.ts
    │   │   │   │   └── requestParam/
    │   │   │   │       └── bots/
    │   │   │   │           ├── GetBotLogsRequest.ts
    │   │   │   │           └── GetBotLogsResponse.ts
    │   │   │   └── websocket/
    │   │   │       └── WebSocketClient.ts
    │   │   ├── layout.tsx
    │   │   ├── login/
    │   │   │   ├── layout.tsx
    │   │   │   └── page.tsx
    │   │   ├── page.tsx
    │   │   ├── register/
    │   │   │   ├── layout.tsx
    │   │   │   └── page.tsx
    │   │   ├── reset-password/
    │   │   │   ├── layout.tsx
    │   │   │   └── page.tsx
    │   │   └── utils/
    │   │       └── versionCompare.ts
    │   ├── components/
    │   │   ├── providers/
    │   │   │   └── theme-provider.tsx
    │   │   └── ui/
    │   │       ├── alert-dialog.tsx
    │   │       ├── alert.tsx
    │   │       ├── badge.tsx
    │   │       ├── breadcrumb.tsx
    │   │       ├── button.tsx
    │   │       ├── card.tsx
    │   │       ├── checkbox.tsx
    │   │       ├── collapsible.tsx
    │   │       ├── context-menu.tsx
    │   │       ├── dialog.tsx
    │   │       ├── dropdown-menu.tsx
    │   │       ├── emoji-picker.tsx
    │   │       ├── form.tsx
    │   │       ├── hover-card.tsx
    │   │       ├── input-otp.tsx
    │   │       ├── input.tsx
    │   │       ├── item.tsx
    │   │       ├── label.tsx
    │   │       ├── language-selector.tsx
    │   │       ├── loading-spinner.tsx
    │   │       ├── pagination.tsx
    │   │       ├── popover.tsx
    │   │       ├── scroll-area.tsx
    │   │       ├── select.tsx
    │   │       ├── separator.tsx
    │   │       ├── sheet.tsx
    │   │       ├── sidebar.tsx
    │   │       ├── skeleton.tsx
    │   │       ├── sonner.tsx
    │   │       ├── switch.tsx
    │   │       ├── table.tsx
    │   │       ├── tabs.tsx
    │   │       ├── textarea.tsx
    │   │       ├── theme-toggle.tsx
    │   │       ├── toggle-group.tsx
    │   │       ├── toggle.tsx
    │   │       └── tooltip.tsx
    │   ├── hooks/
    │   │   ├── use-mobile.ts
    │   │   └── useAsyncTask.ts
    │   ├── i18n/
    │   │   ├── I18nProvider.tsx
    │   │   ├── index.ts
    │   │   └── locales/
    │   │       ├── en-US.ts
    │   │       ├── ja-JP.ts
    │   │       ├── zh-Hans.ts
    │   │       └── zh-Hant.ts
    │   ├── i18next.d.ts
    │   ├── lib/
    │   │   └── utils.ts
    │   └── styles/
    │       └── github-markdown.css
    ├── tsconfig.json
    └── web@0.1.0

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
.github
.venv
.vscode
.data
.temp
web/.next
web/node_modules
web/.env


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.yml
================================================
name: 漏洞反馈
description: 【供中文用户】报错或漏洞请使用这个模板创建,不使用此模板创建的异常、漏洞相关issue将被直接关闭。由于自己操作不当/不甚了解所用技术栈引起的网络连接问题恕无法解决,请勿提 issue。容器间网络连接问题,参考文档 https://docs.langbot.app/zh/workshop/network-details.html  
title: "[Bug]: "
labels: ["bug?"]
body:
  - type: input
    attributes:
      label: 运行环境
      description: LangBot 版本、操作系统、系统架构、**Python版本**、**主机地理位置**
      placeholder: 例如:v3.3.0、CentOS x64 Python 3.10.3、Docker
    validations:
      required: true
  - type: textarea
    attributes:
      label: 异常情况
      description: 完整描述异常情况,什么时候发生的、发生了什么。**请附带日志信息。** 
    validations:
      required: true
  - type: textarea
    attributes:
      label: 复现步骤
      description: 提供越多信息,我们会越快解决问题,建议多提供配置截图;**如果涉及 Dify、n8n、Langflow 等外部平台,请提供应用的导出文件(如 Dify 应用的 DSL),我们将更快回复您。**
    validations:
      required: false
  - type: textarea
    attributes:
      label: 启用的插件
      description: 有些情况可能和插件功能有关,建议提供插件启用情况。
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/bug-report_en.yml
================================================
name: Bug report
description: Report bugs or vulnerabilities using this template. For container network connection issues, refer to the documentation https://docs.langbot.app/en/workshop/network-details.html
title: "[Bug]: "
labels: ["bug?"]
body:
  - type: input
    attributes:
      label: Runtime environment
      description: LangBot version, operating system, system architecture, **Python version**, **host location**
      placeholder: "For example: v3.3.0, CentOS x64 Python 3.10.3, Docker"
    validations:
      required: true
  - type: textarea
    attributes:
      label: Exception
      description: Describe the exception in detail, what happened and when it happened. **Please include log information.** 
    validations:
      required: true
  - type: textarea
    attributes:
      label: Reproduction steps
      description: How to reproduce this problem, the more detailed the better; the more information you provide, the faster we will solve the problem.
    validations:
      required: false
  - type: textarea
    attributes:
      label: Enabled plugins
      description: Some cases may be related to plugin functionality, so please provide the plugin enablement status.
    validations:
      required: false


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.yml
================================================
name: 需求建议
title: "[Feature]: "
labels: []
description: "【供中文用户】新功能或现有功能优化请使用这个模板;不符合类别的issue将被直接关闭"
body:
  - type: dropdown
    attributes:
      label: 这是一个?
      description: 新功能建议还是现有功能优化
      options:
        - 新功能
        - 现有功能优化
    validations:
      required: true
  - type: textarea
    attributes:
      label: 详细描述
      description: 详细描述,越详细越好
    validations:
      required: true
      


================================================
FILE: .github/ISSUE_TEMPLATE/feature-request_en.yml
================================================
name: Feature request
title: "[Feature]: "
labels: []
description: "New features or existing feature improvements should use this template; issues that do not match will be closed directly"
body:
  - type: dropdown
    attributes:
      label: This is a?
      description: New feature request or existing feature improvement
      options:
        - New feature
        - Existing feature improvement
    validations:
      required: true
  - type: textarea
    attributes:
      label: Detailed description
      description: Detailed description, the more detailed the better
    validations:
      required: true
      


================================================
FILE: .github/ISSUE_TEMPLATE/submit-plugin.yml
================================================
name: 提交新插件
title: "[Plugin]: 请求登记新插件"
labels: ["独立插件"]
description: "【供中文用户】本模板供且仅供提交新插件使用"
body:
  - type: input
    attributes:
      label: 插件名称
      description: 填写插件的名称
    validations:
      required: true
  - type: textarea
    attributes:
      label: 插件代码库地址
      description: 仅支持 Github
    validations:
      required: true
  - type: textarea
    attributes:
      label: 插件简介
      description: 插件的简介
    validations:
      required: true
      


================================================
FILE: .github/ISSUE_TEMPLATE/submit-plugin_en.yml
================================================
name: Submit a new plugin
title: "[Plugin]: Request to register a new plugin"
labels: ["Independent Plugin"]
description: "This template is only for submitting new plugins"
body:
  - type: input
    attributes:
      label: Plugin name
      description: Fill in the name of the plugin
    validations:
      required: true
  - type: textarea
    attributes:
      label: Plugin code repository address
      description: Only support Github
    validations:
      required: true
  - type: textarea
    attributes:
      label: Plugin description
      description: The description of the plugin
    validations:
      required: true
      


================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: "pip" # See documentation for possible values
    directory: "/" # Location of package manifests
    schedule:
      interval: "weekly"
    allow:
      - dependency-name: "openai"


================================================
FILE: .github/pull_request_template.md
================================================
## 概述 / Overview

> 请在此部分填写你实现/解决/优化的内容:  
> Summary of what you implemented/solved/optimized:
> 

### 更改前后对比截图 / Screenshots

> 请在此部分粘贴更改前后对比截图(可以是界面截图、控制台输出、对话截图等):  
> Please paste the screenshots of changes before and after here (can be interface screenshots, console output, conversation screenshots, etc.):
> 
> 修改前 / Before:
> 
> 修改后 / After:
> 

## 检查清单 / Checklist

### PR 作者完成 / For PR author

*请在方括号间写`x`以打勾 / Please tick the box with `x`*

- [ ] 阅读仓库[贡献指引](https://github.com/langbot-app/LangBot/blob/master/CONTRIBUTING.md)了吗? / Have you read the [contribution guide](https://github.com/langbot-app/LangBot/blob/master/CONTRIBUTING.md)?
- [ ] 与项目所有者沟通过了吗? / Have you communicated with the project maintainer?
- [ ] 我确定已自行测试所作的更改,确保功能符合预期。 / I have tested the changes and ensured they work as expected.

### 项目维护者完成 / For project maintainer

- [ ] 相关 issues 链接了吗? / Have you linked the related issues?
- [ ] 配置项写好了吗?迁移写好了吗?生效了吗? / Have you written the configuration items? Have you written the migration? Has it taken effect?
- [ ] 依赖加到 pyproject.toml 和 core/bootutils/deps.py 了吗 / Have you added the dependencies to pyproject.toml and core/bootutils/deps.py?
- [ ] 文档编写了吗? / Have you written the documentation?

================================================
FILE: .github/workflows/build-dev-image.yaml
================================================
name: Build Dev Image

on:
  push:
  workflow_dispatch:

jobs:
  build-dev-image:
    runs-on: ubuntu-latest
    # 如果是tag则跳过
    if: ${{ !startsWith(github.ref, 'refs/tags/') }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false

      - name: Generate Tag
        id: generate_tag
        run: |
          # 获取分支名称,把/替换为-
          echo ${{ github.ref }} | sed 's/refs\/heads\///g' | sed 's/\//-/g'
          echo ::set-output name=tag::$(echo ${{ github.ref }} | sed 's/refs\/heads\///g' | sed 's/\//-/g')
      - name: Login to Registry
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}
      - name: Build Docker Image
        run: |
          docker buildx create --name mybuilder --use
          docker build -t rockchin/langbot:${{ steps.generate_tag.outputs.tag }} . --push


================================================
FILE: .github/workflows/build-docker-image.yml
================================================
name: Build Docker Image
on:
  ## 发布release的时候会自动构建
  release:
    types: [published]
jobs:
  publish-docker-image:
    runs-on: ubuntu-latest
    name: Build image
    
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false

      - name: judge has env GITHUB_REF  # 如果没有GITHUB_REF环境变量,则把github.ref变量赋值给GITHUB_REF
        run: |
          if [ -z "$GITHUB_REF" ]; then
            export GITHUB_REF=${{ github.ref }}
            echo $GITHUB_REF
          fi
      - name: Check version
        id: check_version
        run: |
          echo $GITHUB_REF
          # 如果是tag,则去掉refs/tags/前缀
          if [[ $GITHUB_REF == refs/tags/* ]]; then
            echo "It's a tag"
            echo $GITHUB_REF
            echo $GITHUB_REF | awk -F '/' '{print $3}'
            echo ::set-output name=version::$(echo $GITHUB_REF | awk -F '/' '{print $3}')
          else
            echo "It's not a tag"
            echo $GITHUB_REF
            echo ::set-output name=version::${GITHUB_REF}
          fi
      - name: Login to Registry
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}
      - name: Create Buildx
        run: docker buildx create --name mybuilder --use
      - name: Build for Release # only relase, exlude pre-release
        if: ${{ github.event.release.prerelease == false }}
        run: docker buildx build --platform linux/arm64,linux/amd64 -t rockchin/langbot:${{ steps.check_version.outputs.version }} -t rockchin/langbot:latest . --push
      - name: Build for Pre-release # no update for latest tag
        if: ${{ github.event.release.prerelease == true }}
        run: docker buildx build --platform linux/arm64,linux/amd64 -t rockchin/langbot:${{ steps.check_version.outputs.version }} . --push

================================================
FILE: .github/workflows/build-release-artifacts.yaml
================================================
name: Build Release Artifacts

on:
  workflow_dispatch:
  ## 发布release的时候会自动构建
  release:
    types: [published]

jobs:
  build-artifacts:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false

      - name: Check version
        id: check_version
        run: |
          echo $GITHUB_REF
          # 如果是tag,则去掉refs/tags/前缀
          if [[ $GITHUB_REF == refs/tags/* ]]; then
            echo "It's a tag"
            echo $GITHUB_REF
            echo $GITHUB_REF | awk -F '/' '{print $3}'
            echo ::set-output name=version::$(echo $GITHUB_REF | awk -F '/' '{print $3}')
          else
            echo "It's not a tag"
            echo $GITHUB_REF
            echo ::set-output name=version::${GITHUB_REF}
          fi

      - name: Make Temp Directory
        run: |
          mkdir -p /tmp/langbot_build_web
          cp -r . /tmp/langbot_build_web
      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '22'
      - name: Build Web
        run: |
          cd /tmp/langbot_build_web/web
          npm install
          npm run build
      - name: Package Output
        run: |
          cp -r /tmp/langbot_build_web/web/out ./web
      - name: Upload Artifact
        uses: actions/upload-artifact@v4
        with:
          name: langbot-${{ steps.check_version.outputs.version }}-all
          path: .

      - name: Upload To Release
        env:
          GH_TOKEN: ${{ secrets.RELEASE_UPLOAD_GITHUB_TOKEN }}
        run: |
          # 本目录下所有文件打包成zip
          zip -r langbot-${{ steps.check_version.outputs.version }}-all.zip .
          gh release upload ${{ github.event.release.tag_name }} langbot-${{ steps.check_version.outputs.version }}-all.zip


================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint

on:
  push:
    branches:
      - main
      - master
      - dev
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]

jobs:
  ruff:
    name: Ruff Lint & Format
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install uv
        uses: astral-sh/setup-uv@v4

      - name: Install dependencies
        run: uv sync --dev

      - name: Run ruff check
        run: uv run ruff check src

      - name: Run ruff format
        run: uv run ruff format src --check

  frontend:
    name: Frontend Lint
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '25'

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9

      - name: Install dependencies
        working-directory: web
        run: pnpm install

      - name: Run lint
        working-directory: web
        run: pnpm lint


================================================
FILE: .github/workflows/publish-to-pypi.yml
================================================
name: Build and Publish to PyPI

on:
  workflow_dispatch:
  release:
    types: [published]

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write  # Required for trusted publishing to PyPI
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          persist-credentials: false

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Build frontend
        run: |
          cd web
          npm install -g pnpm
          pnpm install
          pnpm build
          mkdir -p ../src/langbot/web/out
          cp -r out ../src/langbot/web/

      - name: Install the latest version of uv
        uses: astral-sh/setup-uv@v6
        with:
          version: "latest"

      - name: Build package
        run: |
          uv build

      - name: Publish to PyPI
        run: |
          uv publish --token ${{ secrets.PYPI_TOKEN }}


================================================
FILE: .github/workflows/run-tests.yml
================================================
name: Unit Tests

on:
  pull_request:
    types: [opened, ready_for_review, synchronize]
    paths:
      - 'pkg/**'
      - 'tests/**'
      - '.github/workflows/run-tests.yml'
      - 'pyproject.toml'
      - 'run_tests.sh'
  push:
    branches:
      - master
      - develop
    paths:
      - 'pkg/**'
      - 'tests/**'
      - '.github/workflows/run-tests.yml'
      - 'pyproject.toml'
      - 'run_tests.sh'

jobs:
  test:
    name: Run Unit Tests
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.11', '3.12', '3.13']
      fail-fast: false

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install uv
        run: |
          curl -LsSf https://astral.sh/uv/install.sh | sh
          echo "$HOME/.cargo/bin" >> $GITHUB_PATH

      - name: Install dependencies
        run: |
          uv sync --dev

      - name: Run unit tests
        run: |
          bash run_tests.sh

      - name: Upload coverage to Codecov
        if: matrix.python-version == '3.12'
        uses: codecov/codecov-action@v5
        with:
          files: ./coverage.xml
          flags: unit-tests
          name: unit-tests-coverage
          fail_ci_if_error: false
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

      - name: Test Summary
        if: always()
        run: |
          echo "## Unit Tests Results" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "Python Version: ${{ matrix.python-version }}" >> $GITHUB_STEP_SUMMARY
          echo "Test Status: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY


================================================
FILE: .github/workflows/test-dev-image.yaml
================================================
name: Test Dev Image

on:
  workflow_run:
    workflows: ["Build Dev Image"]
    types:
      - completed
    branches:
      - master

jobs:
  test-dev-image:
    runs-on: ubuntu-latest
    # Only run if the build workflow succeeded
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    
    permissions:
      contents: read
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Update Docker Compose to use master tag
        working-directory: ./docker
        run: |
          # Replace 'latest' with 'master' tag for testing the dev image
          sed -i 's/rockchin\/langbot:latest/rockchin\/langbot:master/g' docker-compose.yaml
          echo "Updated docker-compose.yaml to use master tag:"
          cat docker-compose.yaml

      - name: Start Docker Compose
        working-directory: ./docker
        run: docker compose up -d

      - name: Wait and Test API
        run: |
          # Function to test API endpoint
          test_api() {
            echo "Testing API endpoint..."
            response=$(curl -s --connect-timeout 10 --max-time 30 -w "\n%{http_code}" http://localhost:5300/api/v1/system/info 2>&1)
            curl_exit_code=$?
            
            if [ $curl_exit_code -ne 0 ]; then
              echo "Curl failed with exit code: $curl_exit_code"
              echo "Error: $response"
              return 1
            fi
            
            http_code=$(echo "$response" | tail -n 1)
            response_body=$(echo "$response" | head -n -1)
            
            if [ "$http_code" = "200" ]; then
              echo "API is healthy! Response code: $http_code"
              echo "Response: $response_body"
              return 0
            else
              echo "API returned non-200 response: $http_code"
              echo "Response body: $response_body"
              return 1
            fi
          }

          # Wait 30 seconds before first attempt
          echo "Waiting 30 seconds for services to start..."
          sleep 30

          # Try up to 3 times with 30-second intervals
          max_attempts=3
          attempt=1

          while [ $attempt -le $max_attempts ]; do
            echo "Attempt $attempt of $max_attempts"
            
            if test_api; then
              echo "Success! API is responding correctly."
              exit 0
            fi
            
            if [ $attempt -lt $max_attempts ]; then
              echo "Retrying in 30 seconds..."
              sleep 30
            fi
            
            attempt=$((attempt + 1))
          done

          # All attempts failed
          echo "Failed to get healthy response after $max_attempts attempts"
          exit 1

      - name: Show Container Logs on Failure
        if: failure()
        working-directory: ./docker
        run: |
          echo "=== Docker Compose Status ==="
          docker compose ps
          echo ""
          echo "=== LangBot Logs ==="
          docker compose logs langbot
          echo ""
          echo "=== Plugin Runtime Logs ==="
          docker compose logs langbot_plugin_runtime

      - name: Cleanup
        if: always()
        working-directory: ./docker
        run: docker compose down


================================================
FILE: .gitignore
================================================
/config.py
.idea/
__pycache__/
database.db
langbot.log
/banlist.py
/plugins/
!/plugins/__init__.py
/revcfg.py
prompts/
logs/
sensitive.json
temp/
current_tag
scenario/
!scenario/default-template.json
override.json
cookies.json
data/labels/announcement_saved.json
cmdpriv.json
tips.py
venv*
bin/
.vscode
/test_*
venv/
hugchat.json
qcapi
claude.json
bard.json
/*yaml
!.pre-commit-config.yaml
!components.yaml
!/docker-compose.yaml
data/labels/instance_id.json
.DS_Store
/data
botpy.log*
/poc
/libs/wecom_api/test.py
/venv
test.py
/web_ui
.venv/
/test
plugins.bak
coverage.xml
.coverage
src/langbot/web/

# Build artifacts
/dist
/build
*.egg-info


================================================
FILE: .mcp.json
================================================
{
  "mcpServers": {
    "shadcn": {
      "command": "npx",
      "args": [
        "shadcn@latest",
        "mcp"
      ]
    },
    "sequential-thinking": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"],
      "env": {}
    },
    "github": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
      }
    },
    "fetch": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-server-fetch"],
      "env": {}
    },
    "playwright": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@playwright/mcp@latest"],
      "env": {}
    }
  }
}


================================================
FILE: .pre-commit-config.yaml
================================================
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    # Ruff version.
    rev: v0.11.7
    hooks:
      # Run the linter of backend.
      - id: ruff
        args: [--fix]
      # Run the formatter of backend.
      - id: ruff-format

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
        types_or: [javascript, jsx, ts, tsx, css, scss]
        additional_dependencies:
          - prettier@3.1.0

  - repo: local
    hooks:
      - id: lint-staged
        name: lint-staged
        entry: cd web && pnpm lint-staged
        language: system
        types: [javascript, jsx, ts, tsx]
        pass_filenames: false


================================================
FILE: AGENTS.md
================================================
# AGENTS.md

This file is for guiding code agents (like Claude Code, GitHub Copilot, OpenAI Codex, etc.) to work in LangBot project.

## Project Overview

LangBot is a open-source LLM native instant messaging bot development platform, aiming to provide an out-of-the-box IM robot development experience, with Agent, RAG, MCP and other LLM application functions, supporting global instant messaging platforms, and providing rich API interfaces, supporting custom development.

LangBot has a comprehensive frontend, all operations can be performed through the frontend. The project splited into these major parts:

- `./src/langbot`: The main python package of the project, below are the main modules in this package:
    - `./pkg`: The core python package of the project backend.
        - `./pkg/platform`: The platform module of the project, containing the logic of message platform adapters, bot managers, message session managers, etc.
        - `./pkg/provider`: The provider module of the project, containing the logic of LLM providers, tool providers, etc.
        - `./pkg/pipeline`: The pipeline module of the project, containing the logic of pipelines, stages, query pool, etc.
        - `./pkg/api`: The api module of the project, containing the http api controllers and services.
        - `./pkg/plugin`: LangBot bridge for connecting with plugin system.
    - `./libs`: Some SDKs we previously developed for the project, such as `qq_official_api`, `wecom_api`, etc.
    - `./templates`: Templates of config files, components, etc.
    - `./web`: Frontend codebase, built with Next.js + **shadcn** + **Tailwind CSS**.
    - `./docker`: docker-compose deployment files.

## Backend Development

We use `uv` to manage dependencies.

```bash
pip install uv
uv sync --dev
```

Start the backend and run the project in development mode.

```bash
uv run main.py
```

Then you can access the project at `http://127.0.0.1:5300`.

## Frontend Development

We use `pnpm` to manage dependencies.

```bash
cd web
cp .env.example .env
pnpm install
pnpm dev
```

Then you can access the project at `http://127.0.0.1:3000`.

## Plugin System Architecture

LangBot is composed of various internal components such as Large Language Model tools, commands, messaging platform adapters, LLM requesters, and more. To meet extensibility and flexibility requirements, we have implemented a production-grade plugin system.

Each plugin runs in an independent process, managed uniformly by the Plugin Runtime. It has two operating modes: `stdio` and `websocket`. When LangBot is started directly by users (not running in a container), it uses `stdio` mode, which is common for personal users or lightweight environments. When LangBot runs in a container, it uses `websocket` mode, designed specifically for production environments.

Plugin Runtime automatically starts each installed plugin and interacts through stdio. In plugin development scenarios, developers can use the lbp command-line tool to start plugins and connect to the running Runtime via WebSocket for debugging.

> Plugin SDK, CLI, Runtime, and entities definitions shared between LangBot and plugins are contained in the [`langbot-plugin-sdk`](https://github.com/langbot-app/langbot-plugin-sdk) repository.

## Some Development Tips and Standards

- LangBot is a global project, any comments in code should be in English, and user experience should be considered in all aspects.
- Thus you should consider the i18n support in all aspects.
- LangBot is widely adopted in both toC and toB scenarios, so you should consider the compatibility and security in all aspects.
- If you were asked to make a commit, please follow the commit message format: 
    - format: <type>(<scope>): <subject>
    - type: must be a specific type, such as feat (new feature), fix (bug fix), docs (documentation), style (code style), refactor (refactoring), perf (performance optimization), etc.
    - scope: the scope of the commit, such as the package name, the file name, the function name, the class name, the module name, etc.
    - subject: the subject of the commit, such as the description of the commit, the reason for the commit, the impact of the commit, etc.
- If you changed the definition of database entities, please update the migration file in `src/langbot/pkg/persistence/migrations/` and update the constants.py file in `src/langbot/pkg/utils/constants.py` with the new migration number.

## Some Principles

- Keep it simple, stupid.
- Entities should not be multiplied unnecessarily
- 八荣八耻

    以瞎猜接口为耻,以认真查询为荣。
    以模糊执行为耻,以寻求确认为荣。
    以臆想业务为耻,以人类确认为荣。
    以创造接口为耻,以复用现有为荣。
    以跳过验证为耻,以主动测试为荣。
    以破坏架构为耻,以遵循规范为荣。
    以假装理解为耻,以诚实无知为荣。
    以盲目修改为耻,以谨慎重构为荣。

================================================
FILE: CONTRIBUTING.md
================================================
## 参与项目

欢迎为此项目贡献代码或其他支持,以使您的点子或众人期待的功能成为现实,助力社区成长。  

### 贡献形式

- 提交PR,解决issues中提到的bug或期待的功能
- 提交PR,实现您设想的功能(请先提出issue与项目维护者沟通)
- 为本项目在其他社交平台撰写文章、制作视频等
- 为本项目的衍生项目作出贡献,或开发插件增加功能

### 沟通语言规范

- 在 PR 和 Commit Message 中请使用全英文
- 对于中文用户,issue 中可以使用中文

<hr/>

## Guidelines

### Contribution

- Submit PRs to solve bugs or features in the issues
- Submit PRs to implement your ideas (Please create an issue first and communicate with the project maintainer)
- Write articles or make videos about this project on other social platforms
- Contribute to the development of derivative projects, or develop plugins to add features

### Spoken Language

- Use English in PRs and Commit Messages
- For English users, you can use English in issues


================================================
FILE: Dockerfile
================================================
FROM node:22-alpine AS node

WORKDIR /app

COPY web ./web

RUN cd web && npm install && npm run build

FROM python:3.12.7-slim

WORKDIR /app

COPY . .

COPY --from=node /app/web/out ./web/out

RUN apt update \
    && apt install gcc -y \
    && python -m pip install --no-cache-dir uv \
    && uv sync \
    && touch /.dockerenv

CMD [ "uv", "run", "--no-sync", "main.py" ]

================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

================================================
FILE: README.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>Production-grade platform for building agentic IM bots.</h3>
<h4>Quickly build, debug, and ship AI bots to Slack, Discord, Telegram, WeChat, and more.</h4>

English / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本語](README_JP.md) / [Español](README_ES.md) / [Français](README_FR.md) / [한국어](README_KO.md) / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">Website</a> |
<a href="https://docs.langbot.app/en/insight/features">Features</a> |
<a href="https://docs.langbot.app/en/insight/guide">Docs</a> |
<a href="https://docs.langbot.app/en/tags/readme">API</a> |
<a href="https://space.langbot.app/cloud">Cloud</a> |
<a href="https://space.langbot.app">Plugin Market</a> |
<a href="https://langbot.featurebase.app/roadmap">Roadmap</a>

</div>

</p>

---

## What is LangBot?

LangBot is an **open-source, production-grade platform** for building AI-powered instant messaging bots. It connects Large Language Models (LLMs) to any chat platform, enabling you to create intelligent agents that can converse, execute tasks, and integrate with your existing workflows.

### Key Capabilities

- **AI Conversations & Agents** — Multi-turn dialogues, tool calling, multi-modal support, streaming output. Built-in RAG (knowledge base) with deep integration to [Dify](https://dify.ai), [Coze](https://coze.com), [n8n](https://n8n.io), [Langflow](https://langflow.org).
- **Universal IM Platform Support** — One codebase for Discord, Telegram, Slack, LINE, QQ, WeChat, WeCom, Lark, DingTalk, KOOK.
- **Production-Ready** — Access control, rate limiting, sensitive word filtering, comprehensive monitoring, and exception handling. Trusted by enterprises.
- **Plugin Ecosystem** — Hundreds of plugins, event-driven architecture, component extensions, and [MCP protocol](https://modelcontextprotocol.io/) support.
- **Web Management Panel** — Configure, manage, and monitor your bots through an intuitive browser interface. No YAML editing required.
- **Multi-Pipeline Architecture** — Different bots for different scenarios, with comprehensive monitoring and exception handling.

[→ Learn more about all features](https://docs.langbot.app/en/insight/features)

---

## Quick Start

### ☁️ LangBot Cloud (Recommended)

**[LangBot Cloud](https://space.langbot.app/cloud)** — Zero deployment, ready to use.

### One-Line Launch

```bash
uvx langbot
```

> Requires [uv](https://docs.astral.sh/uv/getting-started/installation/). Visit http://localhost:5300 — done.

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### One-Click Cloud Deploy

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**More options:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker) · [Manual](https://docs.langbot.app/en/deploy/langbot/manual) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt) · [Kubernetes](./docker/README_K8S.md)

---

## Supported Platforms

| Platform | Status | Notes |
|----------|--------|-------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | Personal & Official API |
| WeCom | ✅ | Enterprise WeChat, External CS, AI Bot |
| WeChat | ✅ | Personal & Official Account |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## Supported LLMs & Integrations

| Provider | Type | Status |
|----------|------|--------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | Local LLM | ✅ |
| [LM Studio](https://lmstudio.ai/) | Local LLM | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | Protocol | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | Gateway | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | Gateway | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | Gateway | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | Gateway | ✅ |
| [GiteeAI](https://ai.gitee.com/) | Gateway | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | GPU Platform | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | GPU Platform | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | GPU Platform | ✅ |
| [接口 AI](https://jiekou.ai/) | Gateway | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | Gateway | ✅ |

[→ View all integrations](https://docs.langbot.app/en/insight/features)

---

## Why LangBot?

| Use Case | How LangBot Helps |
|----------|-------------------|
| **Customer Support** | Deploy AI agents to Slack/Discord/Telegram that answer questions using your knowledge base |
| **Internal Tools** | Connect n8n/Dify workflows to WeCom/DingTalk for automated business processes |
| **Community Management** | Moderate QQ/Discord groups with AI-powered content filtering and interaction |
| **Multi-Platform Presence** | One bot, all platforms. Manage from a single dashboard |

---

## Live Demo

**Try it now:** https://demo.langbot.dev/
- Email: `demo@langbot.app`
- Password: `langbot123456`

*Note: Public demo environment. Do not enter sensitive information.*

---

## Community

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Discord Community](https://discord.gg/wdNEHETs87)

---

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## Contributors

Thanks to all [contributors](https://github.com/langbot-app/LangBot/graphs/contributors) who have helped make LangBot better:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_CN.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://hellogithub.com/repository/langbot-app/LangBot" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=5ce8ae2aa4f74316bf393b57b952433c&claim_uid=gtmc6YWjMZkT21R" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>生产级 AI 即时通信机器人开发平台。</h3>
<h4>快速构建、调试和部署 AI 机器人到微信、QQ、飞书、Slack、Discord、Telegram 等平台。</h4>

[English](README.md) / 简体中文 / [繁體中文](README_TW.md) / [日本語](README_JP.md) / [Español](README_ES.md) / [Français](README_FR.md) / [한국어](README_KO.md) / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![QQ Group](https://img.shields.io/badge/%E7%A4%BE%E5%8C%BAQQ%E7%BE%A4-1030838208-blue)](https://qm.qq.com/q/DxZZcNxM1W)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)
[![star](https://gitcode.com/RockChinQ/LangBot/star/badge.svg)](https://gitcode.com/RockChinQ/LangBot)

<a href="https://langbot.app">官网</a> |
<a href="https://docs.langbot.app/zh/insight/features.html">特性</a> |
<a href="https://docs.langbot.app/zh/insight/guide.html">文档</a> |
<a href="https://docs.langbot.app/zh/tags/readme.html">API</a> |
<a href="https://space.langbot.app/cloud">Cloud</a> |
<a href="https://space.langbot.app">插件市场</a> |
<a href="https://langbot.featurebase.app/roadmap">路线图</a>

</div>

</p>

---

## 什么是 LangBot?

LangBot 是一个**开源的生产级平台**,用于构建 AI 驱动的即时通信机器人。它将大语言模型(LLM)连接到各种聊天平台,帮助你创建能够对话、执行任务、并集成到现有工作流程中的智能 Agent。

### 核心能力

- **AI 对话与 Agent** — 多轮对话、工具调用、多模态、流式输出。自带 RAG(知识库),深度集成 [Dify](https://dify.ai)、[Coze](https://coze.com)、[n8n](https://n8n.io)、[Langflow](https://langflow.org) 等 LLMOps 平台。
- **全平台支持** — 一套代码,覆盖 QQ、微信、企业微信、飞书、钉钉、Discord、Telegram、Slack、LINE、KOOK 等平台。
- **生产就绪** — 访问控制、限速、敏感词过滤、全面监控与异常处理,已被多家企业采用。
- **插件生态** — 数百个插件,事件驱动架构,组件扩展,适配 [MCP 协议](https://modelcontextprotocol.io/)。
- **Web 管理面板** — 通过浏览器直观地配置、管理和监控机器人,无需手动编辑配置文件。
- **多流水线架构** — 不同机器人用于不同场景,具备全面的监控和异常处理能力。

[→ 了解更多功能特性](https://docs.langbot.app/zh/insight/features.html)

---

## 快速开始

### ☁️ LangBot Cloud(推荐)

**[LangBot Cloud](https://space.langbot.app/cloud)** — 免部署,开箱即用。

### 一键启动

```bash
uvx langbot
```

> 需要安装 [uv](https://docs.astral.sh/uv/getting-started/installation/)。访问 http://localhost:5300 即可使用。

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### 一键云部署

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/zh-CN/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**更多方式:** [Docker](https://docs.langbot.app/zh/deploy/langbot/docker.html) · [手动部署](https://docs.langbot.app/zh/deploy/langbot/manual.html) · [宝塔面板](https://docs.langbot.app/zh/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## 支持的平台

| 平台 | 状态 | 备注 |
|------|------|------|
| QQ | ✅ | 个人号、官方机器人(频道、私聊、群聊) |
| 微信 | ✅ | 个人微信、微信公众号 |
| 企业微信 | ✅ | 应用消息、对外客服、智能机器人 |
| 飞书 | ✅ |  |
| 钉钉 | ✅ |  |
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| KOOK | ✅ |  |

---

## 支持的大模型与集成

| 提供商 | 类型 | 状态 |
|--------|------|------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [智谱AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | 本地 LLM | ✅ |
| [LM Studio](https://lmstudio.ai/) | 本地 LLM | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | 协议 | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | 聚合平台 | ✅ |
| [阿里云百炼](https://bailian.console.aliyun.com/) | 聚合平台 | ✅ |
| [火山方舟](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | 聚合平台 | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | 聚合平台 | ✅ |
| [GiteeAI](https://ai.gitee.com/) | 聚合平台 | ✅ |
| [胜算云](https://www.shengsuanyun.com/?from=CH_KYIPP758) | GPU 平台 | ✅ |
| [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | GPU 平台 | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | GPU 平台 | ✅ |
| [接口 AI](https://jiekou.ai/) | 聚合平台 | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | 聚合平台 | ✅ |
| [小马算力](https://www.tokenpony.cn/453z1) | 聚合平台 | ✅ |
| [百宝箱Tbox](https://www.tbox.cn/open) | 智能体平台 | ✅ |

[→ 查看完整集成列表](https://docs.langbot.app/zh/insight/features.html)

### TTS(语音合成)

| 平台/模型 | 备注 |
|-----------|------|
| [FishAudio](https://fish.audio/zh-CN/discovery/) | [插件](https://github.com/the-lazy-me/NewChatVoice) |
| [海豚 AI](https://www.ttson.cn/?source=thelazy) | [插件](https://github.com/the-lazy-me/NewChatVoice) |
| [AzureTTS](https://portal.azure.com/) | [插件](https://github.com/Ingnaryk/LangBot_AzureTTS) |

### 文生图

| 平台/模型 | 备注 |
|-----------|------|
| 阿里云百炼 | [插件](https://github.com/Thetail001/LangBot_BailianTextToImagePlugin) |

---

## 为什么选择 LangBot?

| 使用场景 | LangBot 如何帮助 |
|----------|------------------|
| **客户服务** | 将 AI Agent 部署到微信/企微/钉钉/飞书,基于知识库自动回答用户问题 |
| **内部工具** | 将 n8n/Dify 工作流接入企微/钉钉,实现业务流程自动化 |
| **社群运营** | 在 QQ/Discord 群中使用 AI 驱动的内容审核与智能互动 |
| **多平台触达** | 一个机器人,覆盖所有平台。通过统一面板集中管理 |

---

## 在线演示

**立即体验:** https://demo.langbot.dev/
- 邮箱:`demo@langbot.app`
- 密码:`langbot123456`

*注意:公开演示环境,请不要在其中填入任何敏感信息。*

---

## 社区

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)
[![QQ Group](https://img.shields.io/badge/%E7%A4%BE%E5%8C%BAQQ%E7%BE%A4-1030838208-blue)](https://qm.qq.com/q/DxZZcNxM1W)

- [Discord 社区](https://discord.gg/wdNEHETs87)
- [QQ 社区群](https://qm.qq.com/q/DxZZcNxM1W)

---

## Star 趋势

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## 贡献者

感谢所有[贡献者](https://github.com/langbot-app/LangBot/graphs/contributors)对 LangBot 的帮助:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>

<!--
## For Code Agents

If you're a code agent based on LLM, you should read [AGENTS.md](AGENTS.md) to understand the project structure and development process before you start any development.
-->


================================================
FILE: README_ES.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>Plataforma de grado de producción para construir bots de mensajería instantánea con agentes de IA.</h3>
<h4>Construya, depure y despliegue bots de IA rápidamente en Slack, Discord, Telegram, WeChat y más.</h4>

[English](README.md) / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本語](README_JP.md) / Español / [Français](README_FR.md) / [한국어](README_KO.md) / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">Inicio</a> |
<a href="https://docs.langbot.app/en/insight/features.html">Características</a> |
<a href="https://docs.langbot.app/en/insight/guide.html">Documentación</a> |
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
<a href="https://space.langbot.app">Mercado de Plugins</a> |
<a href="https://langbot.featurebase.app/roadmap">Hoja de Ruta</a>

</div>

</p>

---

## ¿Qué es LangBot?

LangBot es una **plataforma de código abierto y grado de producción** para construir bots de mensajería instantánea impulsados por IA. Conecta modelos de lenguaje de gran escala (LLMs) con cualquier plataforma de chat, permitiéndole crear agentes inteligentes que pueden conversar, ejecutar tareas e integrarse con sus flujos de trabajo existentes.

### Capacidades Clave

- **Conversaciones e Agentes IA** — Diálogos de múltiples turnos, llamadas a herramientas, soporte multimodal, salida en streaming. RAG (base de conocimientos) incorporado con integración profunda con [Dify](https://dify.ai), [Coze](https://coze.com), [n8n](https://n8n.io), [Langflow](https://langflow.org).
- **Soporte Universal de Plataformas de MI** — Un solo código base para Discord, Telegram, Slack, LINE, QQ, WeChat, WeCom, Lark, DingTalk, KOOK.
- **Listo para Producción** — Control de acceso, limitación de velocidad, filtrado de palabras sensibles, monitoreo completo y manejo de excepciones. De confianza para empresas.
- **Ecosistema de Plugins** — Cientos de plugins, arquitectura basada en eventos, extensiones de componentes y soporte del [protocolo MCP](https://modelcontextprotocol.io/).
- **Panel de Gestión Web** — Configure, gestione y monitoree sus bots a través de una interfaz de navegador intuitiva. Sin necesidad de editar YAML.
- **Arquitectura Multi-Pipeline** — Diferentes bots para diferentes escenarios, con monitoreo completo y manejo de excepciones.

[→ Conocer más sobre todas las funcionalidades](https://docs.langbot.app/en/insight/features.html)

---

## Inicio Rápido

### ☁️ LangBot Cloud (Recomendado)

**[LangBot Cloud](https://space.langbot.app/cloud)** — Sin despliegue, listo para usar.

### Lanzamiento en una línea

```bash
uvx langbot
```

> Requiere [uv](https://docs.astral.sh/uv/getting-started/installation/). Visite http://localhost:5300 — listo.

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### Despliegue en la Nube con un Clic

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**Más opciones:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Manual](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## Plataformas Soportadas

| Plataforma | Estado | Notas |
|----------|--------|-------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | Personal y API Oficial |
| WeCom | ✅ | WeChat Empresarial, CS Externo, AI Bot |
| WeChat | ✅ | Personal y Cuenta Oficial |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## LLMs e Integraciones Soportadas

| Proveedor | Tipo | Estado |
|----------|------|--------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | LLM Local | ✅ |
| [LM Studio](https://lmstudio.ai/) | LLM Local | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | Protocolo | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | Pasarela | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | Pasarela | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | Pasarela | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | Pasarela | ✅ |
| [GiteeAI](https://ai.gitee.com/) | Pasarela | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | Plataforma GPU | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Plataforma GPU | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Plataforma GPU | ✅ |
| [接口 AI](https://jiekou.ai/) | Pasarela | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | Pasarela | ✅ |

[→ Ver todas las integraciones](https://docs.langbot.app/en/insight/features.html)

---

## ¿Por qué LangBot?

| Caso de Uso | Cómo Ayuda LangBot |
|----------|-------------------|
| **Atención al cliente** | Despliegue agentes de IA en Slack/Discord/Telegram que respondan preguntas usando su base de conocimientos |
| **Herramientas internas** | Conecte flujos de trabajo de n8n/Dify a WeCom/DingTalk para procesos empresariales automatizados |
| **Gestión de comunidades** | Modere grupos de QQ/Discord con filtrado de contenido e interacción impulsados por IA |
| **Presencia multiplataforma** | Un solo bot, todas las plataformas. Gestione desde un único panel de control |

---

## Demo en Vivo

**Pruébelo ahora:** https://demo.langbot.dev/
- Correo electrónico: `demo@langbot.app`
- Contraseña: `langbot123456`

*Nota: Entorno de demostración público. No ingrese información confidencial.*

---

## Comunidad

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Comunidad de Discord](https://discord.gg/wdNEHETs87)

---

## Historial de Stars

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## Colaboradores

Gracias a todos los [colaboradores](https://github.com/langbot-app/LangBot/graphs/contributors) que han ayudado a mejorar LangBot:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_FR.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>Plateforme de niveau production pour construire des bots de messagerie instantanée avec agents IA.</h3>
<h4>Créez, déboguez et déployez rapidement des bots IA sur Slack, Discord, Telegram, WeChat et plus.</h4>

[English](README.md) / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本語](README_JP.md) / [Español](README_ES.md) / Français / [한국어](README_KO.md) / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">Accueil</a> |
<a href="https://docs.langbot.app/en/insight/features.html">Fonctionnalités</a> |
<a href="https://docs.langbot.app/en/insight/guide.html">Documentation</a> |
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
<a href="https://space.langbot.app">Marché des Plugins</a> |
<a href="https://langbot.featurebase.app/roadmap">Feuille de Route</a>

</div>

</p>

---

## Qu'est-ce que LangBot ?

LangBot est une **plateforme open-source de niveau production** pour créer des bots de messagerie instantanée alimentés par l'IA. Elle connecte les grands modèles de langage (LLMs) à n'importe quelle plateforme de chat, vous permettant de créer des agents intelligents capables de converser, d'exécuter des tâches et de s'intégrer à vos workflows existants.

### Capacités Clés

- **Conversations IA & Agents** — Dialogues multi-tours, appels d'outils, support multimodal, sortie en streaming. RAG (base de connaissances) intégré avec intégration profonde de [Dify](https://dify.ai), [Coze](https://coze.com), [n8n](https://n8n.io), [Langflow](https://langflow.org).
- **Support Universel des Plateformes de MI** — Un seul code pour Discord, Telegram, Slack, LINE, QQ, WeChat, WeCom, Lark, DingTalk, KOOK.
- **Prêt pour la Production** — Contrôle d'accès, limitation de débit, filtrage de mots sensibles, surveillance complète et gestion des exceptions. Approuvé par les entreprises.
- **Écosystème de Plugins** — Des centaines de plugins, architecture événementielle, extensions de composants, et support du [protocole MCP](https://modelcontextprotocol.io/).
- **Panneau de Gestion Web** — Configurez, gérez et surveillez vos bots via une interface navigateur intuitive. Aucune édition de YAML requise.
- **Architecture Multi-Pipeline** — Différents bots pour différents scénarios, avec surveillance complète et gestion des exceptions.

[→ En savoir plus sur toutes les fonctionnalités](https://docs.langbot.app/en/insight/features.html)

---

## Démarrage Rapide

### ☁️ LangBot Cloud (Recommandé)

**[LangBot Cloud](https://space.langbot.app/cloud)** — Sans déploiement, prêt à utiliser.

### Lancement en une ligne

```bash
uvx langbot
```

> Nécessite [uv](https://docs.astral.sh/uv/getting-started/installation/). Visitez http://localhost:5300 — c'est prêt.

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### Déploiement Cloud en un Clic

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**Plus d'options :** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Manuel](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## Plateformes Supportées

| Plateforme | Statut | Notes |
|----------|--------|-------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | Personnel & API Officielle |
| WeCom | ✅ | WeChat Entreprise, CS Externe, AI Bot |
| WeChat | ✅ | Personnel & Compte Officiel |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## LLMs et Intégrations Supportés

| Fournisseur | Type | Statut |
|----------|------|--------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | LLM Local | ✅ |
| [LM Studio](https://lmstudio.ai/) | LLM Local | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | Protocole | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | Passerelle | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | Passerelle | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | Passerelle | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | Passerelle | ✅ |
| [GiteeAI](https://ai.gitee.com/) | Passerelle | ✅ |
| [接口 AI](https://jiekou.ai/) | Passerelle | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | Passerelle | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | Plateforme GPU | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Plateforme GPU | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Plateforme GPU | ✅ |

[→ Voir toutes les intégrations](https://docs.langbot.app/en/insight/features.html)

---

## Pourquoi LangBot ?

| Cas d'Usage | Comment LangBot Aide |
|----------|-------------------|
| **Support Client** | Déployez des agents IA sur Slack/Discord/Telegram qui répondent aux questions en utilisant votre base de connaissances |
| **Outils Internes** | Connectez les workflows n8n/Dify à WeCom/DingTalk pour automatiser vos processus métier |
| **Gestion de Communauté** | Modérez les groupes QQ/Discord avec un filtrage de contenu et des interactions alimentés par l'IA |
| **Présence Multi-plateforme** | Un seul bot, toutes les plateformes. Gérez tout depuis un tableau de bord unique |

---

## Démo en Ligne

**Essayez maintenant :** https://demo.langbot.dev/
- Email : `demo@langbot.app`
- Mot de passe : `langbot123456`

*Note : Environnement de démonstration public. Ne saisissez pas d'informations sensibles.*

---

## Communauté

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Communauté Discord](https://discord.gg/wdNEHETs87)

---

## Historique des Stars

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## Contributeurs

Merci à tous les [contributeurs](https://github.com/langbot-app/LangBot/graphs/contributors) qui ont aidé à améliorer LangBot :

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_JP.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>AIエージェント搭載IMボットを構築するための本番グレードプラットフォーム。</h3>
<h4>Slack、Discord、Telegram、WeChat などに AI ボットを素早く構築、デバッグ、デプロイ。</h4>

[English](README.md) / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / 日本語 / [Español](README_ES.md) / [Français](README_FR.md) / [한국어](README_KO.md) / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">ホーム</a> |
<a href="https://docs.langbot.app/ja/insight/features.html">機能</a> |
<a href="https://docs.langbot.app/ja/insight/guide.html">ドキュメント</a> |
<a href="https://docs.langbot.app/ja/tags/readme.html">API</a> |
<a href="https://space.langbot.app">プラグインマーケット</a> |
<a href="https://langbot.featurebase.app/roadmap">ロードマップ</a>

</div>

</p>

---

## LangBot とは?

LangBot は、AI搭載のインスタントメッセージングボットを構築するための**オープンソースの本番グレードプラットフォーム**です。大規模言語モデル(LLM)をあらゆるチャットプラットフォームに接続し、会話、タスク実行、既存のワークフローとの統合が可能なインテリジェントエージェントを作成できます。

### 主な機能

- **AI対話とエージェント** — マルチターン対話、ツール呼び出し、マルチモーダル対応、ストリーミング出力。RAG(ナレッジベース)を内蔵し、[Dify](https://dify.ai)、[Coze](https://coze.com)、[n8n](https://n8n.io)、[Langflow](https://langflow.org) と深く統合。
- **ユニバーサルIMプラットフォーム対応** — 単一のコードベースで Discord、Telegram、Slack、LINE、QQ、WeChat、WeCom、Lark、DingTalk、KOOK に対応。
- **本番環境対応** — アクセス制御、レート制限、センシティブワードフィルタリング、包括的な監視、例外処理を搭載。エンタープライズの信頼に応える品質。
- **プラグインエコシステム** — 数百のプラグイン、イベント駆動アーキテクチャ、コンポーネント拡張、[MCPプロトコル](https://modelcontextprotocol.io/)対応。
- **Web管理パネル** — 直感的なブラウザインターフェースからボットの設定、管理、監視が可能。YAML編集は不要。
- **マルチパイプラインアーキテクチャ** — 異なるシナリオに異なるボットを配置し、包括的な監視と例外処理を実現。

[→ すべての機能について詳しく見る](https://docs.langbot.app/ja/insight/features.html)

---

## クイックスタート

### ☁️ LangBot Cloud(推奨)

**[LangBot Cloud](https://space.langbot.app/cloud)** — デプロイ不要、すぐに使えます。

### ワンライン起動

```bash
uvx langbot
```

> [uv](https://docs.astral.sh/uv/getting-started/installation/) が必要です。http://localhost:5300 にアクセスして完了。

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### ワンクリッククラウドデプロイ

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**その他:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [手動デプロイ](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## 対応プラットフォーム

| プラットフォーム | ステータス | 備考 |
|----------|--------|-------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | 個人 & 公式API |
| WeCom | ✅ | 企業WeChat、外部CS、AIボット |
| WeChat | ✅ | 個人 & 公式アカウント |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## 対応LLMと統合

| プロバイダー | タイプ | ステータス |
|----------|------|--------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | ローカルLLM | ✅ |
| [LM Studio](https://lmstudio.ai/) | ローカルLLM | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | プロトコル | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | ゲートウェイ | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | ゲートウェイ | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | ゲートウェイ | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | ゲートウェイ | ✅ |
| [GiteeAI](https://ai.gitee.com/) | ゲートウェイ | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | GPUプラットフォーム | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | GPUプラットフォーム | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | GPUプラットフォーム | ✅ |
| [接口 AI](https://jiekou.ai/) | ゲートウェイ | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | ゲートウェイ | ✅ |

[→ すべての統合を表示](https://docs.langbot.app/en/insight/features.html)

---

## なぜ LangBot?

| ユースケース | LangBot の活用方法 |
|----------|-------------------|
| **カスタマーサポート** | ナレッジベースを活用して質問に回答するAIエージェントをSlack/Discord/Telegramにデプロイ |
| **社内ツール** | n8n/Difyのワークフローを WeCom/DingTalk に接続し、業務プロセスを自動化 |
| **コミュニティ管理** | AI搭載のコンテンツフィルタリングとインタラクションでQQ/Discordグループをモデレーション |
| **マルチプラットフォーム展開** | 1つのボットで全プラットフォームに対応。単一のダッシュボードから管理 |

---

## ライブデモ

**今すぐ試す:** https://demo.langbot.dev/
- メール: `demo@langbot.app`
- パスワード: `langbot123456`

*注意: 公開デモ環境です。機密情報を入力しないでください。*

---

## コミュニティ

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Discord コミュニティ](https://discord.gg/wdNEHETs87)

---

## Star 推移

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## コントリビューター

LangBot をより良くするために貢献してくださったすべての[コントリビューター](https://github.com/langbot-app/LangBot/graphs/contributors)に感謝します:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_KO.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>AI 에이전트 IM 봇 구축을 위한 프로덕션 등급 플랫폼.</h3>
<h4>Slack, Discord, Telegram, WeChat 등에 AI 봇을 빠르게 구축, 디버그 및 배포.</h4>

[English](README.md) / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本語](README_JP.md) / [Español](README_ES.md) / [Français](README_FR.md) / 한국어 / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">홈</a> |
<a href="https://docs.langbot.app/en/insight/features.html">기능</a> |
<a href="https://docs.langbot.app/en/insight/guide.html">문서</a> |
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
<a href="https://space.langbot.app">플러그인 마켓</a> |
<a href="https://langbot.featurebase.app/roadmap">로드맵</a>

</div>

</p>

---

## LangBot이란?

LangBot은 AI 기반 인스턴트 메시징 봇을 구축하기 위한 **오픈소스 프로덕션 등급 플랫폼**입니다. 대규모 언어 모델(LLM)을 모든 채팅 플랫폼에 연결하여 대화, 작업 실행, 기존 워크플로우와의 통합이 가능한 지능형 에이전트를 만들 수 있습니다.

### 핵심 기능

- **AI 대화 및 에이전트** — 멀티턴 대화, 도구 호출, 멀티모달 지원, 스트리밍 출력. 내장 RAG(지식 베이스)와 [Dify](https://dify.ai), [Coze](https://coze.com), [n8n](https://n8n.io), [Langflow](https://langflow.org) 심층 통합.
- **유니버설 IM 플랫폼 지원** — 단일 코드베이스로 Discord, Telegram, Slack, LINE, QQ, WeChat, WeCom, Lark, DingTalk, KOOK 지원.
- **프로덕션 레디** — 접근 제어, 속도 제한, 민감어 필터링, 종합 모니터링 및 예외 처리. 기업 환경에서 검증됨.
- **플러그인 생태계** — 수백 개의 플러그인, 이벤트 기반 아키텍처, 컴포넌트 확장, [MCP 프로토콜](https://modelcontextprotocol.io/) 지원.
- **웹 관리 패널** — 직관적인 브라우저 인터페이스로 봇을 구성, 관리 및 모니터링. YAML 편집 불필요.
- **멀티 파이프라인 아키텍처** — 다양한 시나리오에 맞는 다양한 봇 구성, 종합 모니터링 및 예외 처리.

[→ 모든 기능 자세히 보기](https://docs.langbot.app/en/insight/features.html)

---

## 빠른 시작

### ☁️ LangBot Cloud (추천)

**[LangBot Cloud](https://space.langbot.app/cloud)** — 배포 없이 바로 사용.

### 원라인 실행

```bash
uvx langbot
```

> [uv](https://docs.astral.sh/uv/getting-started/installation/) 설치 필요. http://localhost:5300 방문 — 완료.

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### 원클릭 클라우드 배포

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**더 많은 옵션:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [수동 배포](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## 지원 플랫폼

| 플랫폼 | 상태 | 비고 |
|--------|------|------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | 개인 및 공식 API |
| WeCom | ✅ | 기업 WeChat, 외부 CS, AI Bot |
| WeChat | ✅ | 개인 및 공식 계정 |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## 지원 LLM 및 통합

| 제공자 | 유형 | 상태 |
|--------|------|------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | 로컬 LLM | ✅ |
| [LM Studio](https://lmstudio.ai/) | 로컬 LLM | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | 프로토콜 | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | 게이트웨이 | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | 게이트웨이 | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | 게이트웨이 | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | 게이트웨이 | ✅ |
| [GiteeAI](https://ai.gitee.com/) | 게이트웨이 | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | GPU 플랫폼 | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | GPU 플랫폼 | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | GPU 플랫폼 | ✅ |
| [接口 AI](https://jiekou.ai/) | 게이트웨이 | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | 게이트웨이 | ✅ |

[→ 모든 통합 보기](https://docs.langbot.app/en/insight/features.html)

---

## 왜 LangBot인가?

| 사용 사례 | LangBot 활용 방법 |
|-----------|-------------------|
| **고객 지원** | 지식 베이스를 활용하여 질문에 답변하는 AI 에이전트를 Slack/Discord/Telegram에 배포 |
| **내부 도구** | n8n/Dify 워크플로우를 WeCom/DingTalk에 연결하여 비즈니스 프로세스 자동화 |
| **커뮤니티 관리** | AI 기반 콘텐츠 필터링 및 상호작용으로 QQ/Discord 그룹 관리 |
| **멀티 플랫폼** | 하나의 봇으로 모든 플랫폼 지원. 단일 대시보드에서 관리 |

---

## 라이브 데모

**지금 체험:** https://demo.langbot.dev/
- 이메일: `demo@langbot.app`
- 비밀번호: `langbot123456`

*참고: 공개 데모 환경입니다. 민감한 정보를 입력하지 마세요.*

---

## 커뮤니티

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Discord 커뮤니티](https://discord.gg/wdNEHETs87)

---

## Star 추이

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## 기여자

LangBot을 더 나은 프로젝트로 만들어 주신 모든 [기여자](https://github.com/langbot-app/LangBot/graphs/contributors)분들께 감사드립니다:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_RU.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>Платформа производственного уровня для создания агентных IM-ботов.</h3>
<h4>Быстро создавайте, отлаживайте и развертывайте ИИ-ботов в Slack, Discord, Telegram, WeChat и других платформах.</h4>

[English](README.md) / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本語](README_JP.md) / [Español](README_ES.md) / [Français](README_FR.md) / [한국어](README_KO.md) / Русский / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">Главная</a> |
<a href="https://docs.langbot.app/en/insight/features.html">Возможности</a> |
<a href="https://docs.langbot.app/en/insight/guide.html">Документация</a> |
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
<a href="https://space.langbot.app">Магазин плагинов</a> |
<a href="https://langbot.featurebase.app/roadmap">Дорожная карта</a>

</div>

</p>

---

## Что такое LangBot?

LangBot — это **платформа с открытым исходным кодом производственного уровня** для создания ИИ-ботов в мессенджерах. Она связывает большие языковые модели (LLM) с любой чат-платформой, позволяя создавать интеллектуальных агентов, которые могут вести диалоги, выполнять задачи и интегрироваться с вашими существующими рабочими процессами.

### Ключевые возможности

- **ИИ-диалоги и агенты** — Многораундовые диалоги, вызов инструментов, мультимодальная поддержка, потоковый вывод. Встроенная реализация RAG (база знаний) с глубокой интеграцией в [Dify](https://dify.ai), [Coze](https://coze.com), [n8n](https://n8n.io), [Langflow](https://langflow.org).
- **Универсальная поддержка IM-платформ** — Единая кодовая база для Discord, Telegram, Slack, LINE, QQ, WeChat, WeCom, Lark, DingTalk, KOOK.
- **Готовность к продакшену** — Контроль доступа, ограничение скорости, фильтрация чувствительных слов, комплексный мониторинг и обработка исключений. Проверено в корпоративной среде.
- **Экосистема плагинов** — Сотни плагинов, событийно-ориентированная архитектура, расширения компонентов и поддержка [протокола MCP](https://modelcontextprotocol.io/).
- **Веб-панель управления** — Настраивайте, управляйте и мониторьте ваших ботов через интуитивный браузерный интерфейс. Ручное редактирование YAML не требуется.
- **Мультиконвейерная архитектура** — Разные боты для разных сценариев с комплексным мониторингом и обработкой исключений.

[→ Подробнее обо всех возможностях](https://docs.langbot.app/en/insight/features.html)

---

## Быстрый старт

### ☁️ LangBot Cloud (Рекомендуется)

**[LangBot Cloud](https://space.langbot.app/cloud)** — Без развёртывания, готово к использованию.

### Запуск одной командой

```bash
uvx langbot
```

> Требуется [uv](https://docs.astral.sh/uv/getting-started/installation/). Откройте http://localhost:5300 — готово.

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### Облачное развертывание одним кликом

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**Другие варианты:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Ручная установка](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## Поддерживаемые платформы

| Платформа | Статус | Примечания |
|-----------|--------|------------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | Личный и официальный API |
| WeCom | ✅ | Корпоративный WeChat, внешний CS, AI-бот |
| WeChat | ✅ | Личный и официальный аккаунт |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## Поддерживаемые LLM и интеграции

| Провайдер | Тип | Статус |
|-----------|-----|--------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | Локальный LLM | ✅ |
| [LM Studio](https://lmstudio.ai/) | Локальный LLM | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | Протокол | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | Шлюз | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | Шлюз | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | Шлюз | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | Шлюз | ✅ |
| [GiteeAI](https://ai.gitee.com/) | Шлюз | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | Шлюз | ✅ |
| [接口 AI](https://jiekou.ai/) | Шлюз | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | Платформа GPU | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Платформа GPU | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Платформа GPU | ✅ |

[→ Смотреть все интеграции](https://docs.langbot.app/en/insight/features.html)

---

## Почему LangBot?

| Сценарий использования | Как помогает LangBot |
|------------------------|----------------------|
| **Поддержка клиентов** | Разверните ИИ-агентов в Slack/Discord/Telegram, которые отвечают на вопросы, используя вашу базу знаний |
| **Внутренние инструменты** | Подключите рабочие процессы n8n/Dify к WeCom/DingTalk для автоматизации бизнес-процессов |
| **Управление сообществом** | Модерируйте группы QQ/Discord с помощью ИИ-фильтрации контента и взаимодействия |
| **Мультиплатформенное присутствие** | Один бот — все платформы. Управляйте из единой панели |

---

## Демо

**Попробуйте прямо сейчас:** https://demo.langbot.dev/
- Email: `demo@langbot.app`
- Пароль: `langbot123456`

*Примечание: Публичная демо-среда. Не вводите конфиденциальную информацию.*

---

## Сообщество

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Сообщество Discord](https://discord.gg/wdNEHETs87)

---

## История Stars

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## Участники

Спасибо всем [участникам](https://github.com/langbot-app/LangBot/graphs/contributors), которые помогли сделать LangBot лучше:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_TW.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://hellogithub.com/repository/langbot-app/LangBot" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=5ce8ae2aa4f74316bf393b57b952433c&claim_uid=gtmc6YWjMZkT21R" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>生產級 AI 即時通訊機器人開發平台。</h3>
<h4>快速建構、除錯和部署 AI 機器人到微信、QQ、飛書、Slack、Discord、Telegram 等平台。</h4>

[English](README.md) / [简体中文](README_CN.md) / 繁體中文 / [日本語](README_JP.md) / [Español](README_ES.md) / [Français](README_FR.md) / [한국어](README_KO.md) / [Русский](README_RU.md) / [Tiếng Việt](README_VI.md)

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![QQ Group](https://img.shields.io/badge/%E7%A4%BE%E5%8C%BAQQ%E7%BE%A4-966235608-blue)](https://qm.qq.com/q/JLi38whHum)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)
[![star](https://gitcode.com/RockChinQ/LangBot/star/badge.svg)](https://gitcode.com/RockChinQ/LangBot)

<a href="https://langbot.app">官網</a> |
<a href="https://docs.langbot.app/zh/insight/features.html">特性</a> |
<a href="https://docs.langbot.app/zh/insight/guide.html">文件</a> |
<a href="https://docs.langbot.app/zh/tags/readme.html">API</a> |
<a href="https://space.langbot.app">外掛市場</a> |
<a href="https://langbot.featurebase.app/roadmap">路線圖</a>

</div>

</p>

---

## 什麼是 LangBot?

LangBot 是一個**開源的生產級平台**,用於建構 AI 驅動的即時通訊機器人。它將大語言模型(LLM)連接到各種聊天平台,幫助你創建能夠對話、執行任務、並整合到現有工作流程中的智能 Agent。

### 核心能力

- **AI 對話與 Agent** — 多輪對話、工具調用、多模態、流式輸出。自帶 RAG(知識庫),深度整合 [Dify](https://dify.ai)、[Coze](https://coze.com)、[n8n](https://n8n.io)、[Langflow](https://langflow.org) 等 LLMOps 平台。
- **全平台支援** — 一套程式碼,覆蓋 QQ、微信、企業微信、飛書、釘釘、Discord、Telegram、Slack、LINE、KOOK 等平台。
- **生產就緒** — 存取控制、限速、敏感詞過濾、全面監控與異常處理,已被多家企業採用。
- **外掛生態** — 數百個外掛,事件驅動架構,組件擴展,適配 [MCP 協議](https://modelcontextprotocol.io/)。
- **Web 管理面板** — 透過瀏覽器直觀地配置、管理和監控機器人,無需手動編輯設定檔。
- **多流水線架構** — 不同機器人用於不同場景,具備全面的監控和異常處理能力。

[→ 了解更多功能特性](https://docs.langbot.app/zh/insight/features.html)

---

## 快速開始

### ☁️ LangBot Cloud(推薦)

**[LangBot Cloud](https://space.langbot.app/cloud)** — 免部署,開箱即用。

### 一鍵啟動

```bash
uvx langbot
```

> 需要安裝 [uv](https://docs.astral.sh/uv/getting-started/installation/)。訪問 http://localhost:5300 即可使用。

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### 一鍵雲端部署

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/zh-CN/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**更多方式:** [Docker](https://docs.langbot.app/zh/deploy/langbot/docker.html) · [手動部署](https://docs.langbot.app/zh/deploy/langbot/manual.html) · [寶塔面板](https://docs.langbot.app/zh/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## 支援的平台

| 平台 | 狀態 | 備註 |
|------|------|------|
| QQ | ✅ | 個人號、官方機器人(頻道、私聊、群聊) |
| 微信 | ✅ | 個人微信、微信公眾號 |
| 企業微信 | ✅ | 應用訊息、對外客服、智能機器人 |
| 飛書 | ✅ |  |
| 釘釘 | ✅ |  |
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## 支援的大模型與整合

| 提供商 | 類型 | 狀態 |
|--------|------|------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [智譜AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | 本地 LLM | ✅ |
| [LM Studio](https://lmstudio.ai/) | 本地 LLM | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | 協議 | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | 聚合平台 | ✅ |
| [阿里雲百煉](https://bailian.console.aliyun.com/) | 聚合平台 | ✅ |
| [火山方舟](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | 聚合平台 | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | 聚合平台 | ✅ |
| [GiteeAI](https://ai.gitee.com/) | 聚合平台 | ✅ |
| [勝算雲](https://www.shengsuanyun.com/?from=CH_KYIPP758) | GPU 平台 | ✅ |
| [優雲智算](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | GPU 平台 | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | GPU 平台 | ✅ |
| [接口 AI](https://jiekou.ai/) | 聚合平台 | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | 聚合平台 | ✅ |

### TTS(語音合成)

| 平台/模型 | 備註 |
|-----------|------|
| [FishAudio](https://fish.audio/zh-CN/discovery/) | [外掛](https://github.com/the-lazy-me/NewChatVoice) |
| [海豚 AI](https://www.ttson.cn/?source=thelazy) | [外掛](https://github.com/the-lazy-me/NewChatVoice) |
| [AzureTTS](https://portal.azure.com/) | [外掛](https://github.com/Ingnaryk/LangBot_AzureTTS) |

### 文生圖

| 平台/模型 | 備註 |
|-----------|------|
| 阿里雲百煉 | [外掛](https://github.com/Thetail001/LangBot_BailianTextToImagePlugin) |

[→ 查看完整整合列表](https://docs.langbot.app/zh/insight/features.html)

---

## 為什麼選擇 LangBot?

| 使用場景 | LangBot 如何幫助 |
|----------|------------------|
| **客戶服務** | 將 AI Agent 部署到微信/企微/釘釘/飛書,基於知識庫自動回答使用者問題 |
| **內部工具** | 將 n8n/Dify 工作流接入企微/釘釘,實現業務流程自動化 |
| **社群運營** | 在 QQ/Discord 群中使用 AI 驅動的內容審核與智能互動 |
| **多平台觸達** | 一個機器人,覆蓋所有平台。透過統一面板集中管理 |

---

## 線上演示

**立即體驗:** https://demo.langbot.dev/
- 信箱:`demo@langbot.app`
- 密碼:`langbot123456`

*注意:公開演示環境,請不要在其中填入任何敏感資訊。*

---

## 社群

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)
[![QQ Group](https://img.shields.io/badge/%E7%A4%BE%E5%8C%BAQQ%E7%BE%A4-966235608-blue)](https://qm.qq.com/q/JLi38whHum)

- [Discord 社群](https://discord.gg/wdNEHETs87)
- [QQ 社群群](https://qm.qq.com/q/JLi38whHum)

---

## Star 趨勢

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## 貢獻者

感謝所有[貢獻者](https://github.com/langbot-app/LangBot/graphs/contributors)對 LangBot 的幫助:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: README_VI.md
================================================
<p align="center">
<a href="https://langbot.app">
<img width="130" src="res/logo-blue.png" alt="LangBot"/>
</a>

<div align="center">

<a href="https://www.producthunt.com/products/langbot?utm_source=badge-follow&utm_medium=badge&utm_source=badge-langbot" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/follow.svg?product_id=1077185&theme=light" alt="LangBot - Production&#0045;grade&#0032;IM&#0032;bot&#0032;made&#0032;easy&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>

<h3>Nền tảng cấp sản xuất để xây dựng bot IM với AI agent.</h3>
<h4>Xây dựng, gỡ lỗi và triển khai bot AI nhanh chóng trên Slack, Discord, Telegram, WeChat và nhiều nền tảng khác.</h4>

[English](README.md) / [简体中文](README_CN.md) / [繁體中文](README_TW.md) / [日本語](README_JP.md) / [Español](README_ES.md) / [Français](README_FR.md) / [한국어](README_KO.md) / [Русский](README_RU.md) / Tiếng Việt

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&labelColor=%20%235462eb&logoColor=%20%23f5f5f5&color=%20%235462eb)](https://discord.gg/wdNEHETs87)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/langbot-app/LangBot)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/langbot-app/LangBot)](https://github.com/langbot-app/LangBot/releases/latest)
<img src="https://img.shields.io/badge/python-3.10 ~ 3.13 -blue.svg" alt="python">
[![GitHub stars](https://img.shields.io/github/stars/langbot-app/LangBot?style=social)](https://github.com/langbot-app/LangBot/stargazers)

<a href="https://langbot.app">Trang chủ</a> |
<a href="https://docs.langbot.app/en/insight/features.html">Tính năng</a> |
<a href="https://docs.langbot.app/en/insight/guide.html">Tài liệu</a> |
<a href="https://docs.langbot.app/en/tags/readme.html">API</a> |
<a href="https://space.langbot.app">Chợ Plugin</a> |
<a href="https://langbot.featurebase.app/roadmap">Lộ trình</a>

</div>

</p>

---

## LangBot là gì?

LangBot là một **nền tảng mã nguồn mở, cấp sản xuất** để xây dựng bot nhắn tin tức thời được hỗ trợ bởi AI. Nó kết nối các Mô hình Ngôn ngữ Lớn (LLM) với bất kỳ nền tảng chat nào, cho phép bạn tạo các agent thông minh có thể trò chuyện, thực hiện tác vụ và tích hợp với quy trình làm việc hiện có của bạn.

### Khả năng chính

- **Hội thoại AI & Agent** — Đối thoại nhiều lượt, gọi công cụ, hỗ trợ đa phương thức, đầu ra streaming. RAG (cơ sở kiến thức) tích hợp sẵn với tích hợp sâu vào [Dify](https://dify.ai), [Coze](https://coze.com), [n8n](https://n8n.io), [Langflow](https://langflow.org).
- **Hỗ trợ đa nền tảng IM** — Một mã nguồn cho Discord, Telegram, Slack, LINE, QQ, WeChat, WeCom, Lark, DingTalk, KOOK.
- **Sẵn sàng cho sản xuất** — Kiểm soát truy cập, giới hạn tốc độ, lọc từ nhạy cảm, giám sát toàn diện và xử lý ngoại lệ. Được doanh nghiệp tin dùng.
- **Hệ sinh thái Plugin** — Hàng trăm plugin, kiến trúc hướng sự kiện, mở rộng thành phần, và hỗ trợ [giao thức MCP](https://modelcontextprotocol.io/).
- **Bảng quản lý Web** — Cấu hình, quản lý và giám sát bot thông qua giao diện trình duyệt trực quan. Không cần chỉnh sửa YAML.
- **Kiến trúc đa Pipeline** — Các bot khác nhau cho các kịch bản khác nhau, với giám sát toàn diện và xử lý ngoại lệ.

[→ Tìm hiểu thêm về tất cả tính năng](https://docs.langbot.app/en/insight/features.html)

---

## Bắt đầu nhanh

### ☁️ LangBot Cloud (Khuyên dùng)

**[LangBot Cloud](https://space.langbot.app/cloud)** — Không cần triển khai, sẵn sàng sử dụng.

### Khởi chạy một dòng

```bash
uvx langbot
```

> Yêu cầu [uv](https://docs.astral.sh/uv/getting-started/installation/). Truy cập http://localhost:5300 — xong.

### Docker Compose

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker
docker compose up -d
```

### Triển khai đám mây một cú nhấp

[![Deploy on Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/en-US/templates/ZKTBDH)
[![Deploy on Railway](https://railway.com/button.svg)](https://railway.app/template/yRrAyL?referralCode=vogKPF)

**Thêm tùy chọn:** [Docker](https://docs.langbot.app/en/deploy/langbot/docker.html) · [Thủ công](https://docs.langbot.app/en/deploy/langbot/manual.html) · [BTPanel](https://docs.langbot.app/en/deploy/langbot/one-click/bt.html) · [Kubernetes](./docker/README_K8S.md)

---

## Nền tảng được hỗ trợ

| Nền tảng | Trạng thái | Ghi chú |
|----------|--------|-------|
| Discord | ✅ |  |
| Telegram | ✅ |  |
| Slack | ✅ |  |
| LINE | ✅ |  |
| QQ | ✅ | Cá nhân & API chính thức |
| WeCom | ✅ | WeChat doanh nghiệp, CS bên ngoài, AI Bot |
| WeChat | ✅ | Cá nhân & Tài khoản công khai |
| Lark | ✅ |  |
| DingTalk | ✅ |  |
| KOOK | ✅ |  |
| Satori | ✅ |  |

---

## LLM và tích hợp được hỗ trợ

| Nhà cung cấp | Loại | Trạng thái |
|----------|------|--------|
| [OpenAI](https://platform.openai.com/) | LLM | ✅ |
| [Anthropic](https://www.anthropic.com/) | LLM | ✅ |
| [DeepSeek](https://www.deepseek.com/) | LLM | ✅ |
| [Google Gemini](https://aistudio.google.com/prompts/new_chat) | LLM | ✅ |
| [xAI](https://x.ai/) | LLM | ✅ |
| [Moonshot](https://www.moonshot.cn/) | LLM | ✅ |
| [Zhipu AI](https://open.bigmodel.cn/) | LLM | ✅ |
| [Ollama](https://ollama.com/) | LLM cục bộ | ✅ |
| [LM Studio](https://lmstudio.ai/) | LLM cục bộ | ✅ |
| [Dify](https://dify.ai) | LLMOps | ✅ |
| [MCP](https://modelcontextprotocol.io/) | Giao thức | ✅ |
| [SiliconFlow](https://siliconflow.cn/) | Cổng | ✅ |
| [Aliyun Bailian](https://bailian.console.aliyun.com/) | Cổng | ✅ |
| [Volc Engine Ark](https://console.volcengine.com/ark/region:ark+cn-beijing/model?vendor=Bytedance&view=LIST_VIEW) | Cổng | ✅ |
| [ModelScope](https://modelscope.cn/docs/model-service/API-Inference/intro) | Cổng | ✅ |
| [GiteeAI](https://ai.gitee.com/) | Cổng | ✅ |
| [CompShare](https://www.compshare.cn/?ytag=GPU_YY-gh_langbot) | Nền tảng GPU | ✅ |
| [PPIO](https://ppinfra.com/user/register?invited_by=QJKFYD&utm_source=github_langbot) | Nền tảng GPU | ✅ |
| [ShengSuanYun](https://www.shengsuanyun.com/?from=CH_KYIPP758) | Nền tảng GPU | ✅ |
| [接口 AI](https://jiekou.ai/) | Cổng | ✅ |
| [302.AI](https://share.302.ai/SuTG99) | Cổng | ✅ |

[→ Xem tất cả tích hợp](https://docs.langbot.app/en/insight/features.html)

---

## Tại sao chọn LangBot?

| Trường hợp sử dụng | LangBot giúp như thế nào |
|----------|-------------------|
| **Hỗ trợ khách hàng** | Triển khai agent AI trên Slack/Discord/Telegram để trả lời câu hỏi bằng cơ sở kiến thức của bạn |
| **Công cụ nội bộ** | Kết nối quy trình n8n/Dify với WeCom/DingTalk để tự động hóa quy trình kinh doanh |
| **Quản lý cộng đồng** | Quản lý nhóm QQ/Discord với tính năng lọc nội dung và tương tác được hỗ trợ bởi AI |
| **Đa nền tảng** | Một bot, tất cả nền tảng. Quản lý từ một bảng điều khiển duy nhất |

---

## Demo trực tuyến

**Thử ngay:** https://demo.langbot.dev/
- Email: `demo@langbot.app`
- Mật khẩu: `langbot123456`

*Lưu ý: Môi trường demo công khai. Không nhập thông tin nhạy cảm.*

---

## Cộng đồng

[![Discord](https://img.shields.io/discord/1335141740050649118?logo=discord&label=Discord)](https://discord.gg/wdNEHETs87)

- [Cộng đồng Discord](https://discord.gg/wdNEHETs87)

---

## Lịch sử Star

[![Star History Chart](https://api.star-history.com/svg?repos=langbot-app/LangBot&type=Date)](https://star-history.com/#langbot-app/LangBot&Date)

---

## Người đóng góp

Cảm ơn tất cả [người đóng góp](https://github.com/langbot-app/LangBot/graphs/contributors) đã giúp LangBot trở nên tốt hơn:

<a href="https://github.com/langbot-app/LangBot/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=langbot-app/LangBot" />
</a>


================================================
FILE: codecov.yml
================================================
coverage:
  status:
    project: off
    patch: off

================================================
FILE: docker/README_K8S.md
================================================
# LangBot Kubernetes 部署指南 / Kubernetes Deployment Guide

[简体中文](#简体中文) | [English](#english)

---

## 简体中文

### 概述

本指南提供了在 Kubernetes 集群中部署 LangBot 的完整步骤。Kubernetes 部署配置基于 `docker-compose.yaml`,适用于生产环境的容器化部署。

### 前置要求

- Kubernetes 集群(版本 1.19+)
- `kubectl` 命令行工具已配置并可访问集群
- 集群中有可用的存储类(StorageClass)用于持久化存储(可选但推荐)
- 至少 2 vCPU 和 4GB RAM 的可用资源

### 架构说明

Kubernetes 部署包含以下组件:

1. **langbot**: 主应用服务
   - 提供 Web UI(端口 5300)
   - 处理平台 webhook(端口 2280-2290)
   - 数据持久化卷
   
2. **langbot-plugin-runtime**: 插件运行时服务
   - WebSocket 通信(端口 5400)
   - 插件数据持久化卷

3. **持久化存储**:
   - `langbot-data`: LangBot 主数据
   - `langbot-plugins`: 插件文件
   - `langbot-plugin-runtime-data`: 插件运行时数据

### 快速开始

#### 1. 下载部署文件

```bash
# 克隆仓库
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker

# 或直接下载 kubernetes.yaml
wget https://raw.githubusercontent.com/langbot-app/LangBot/main/docker/kubernetes.yaml
```

#### 2. 部署到 Kubernetes

```bash
# 应用所有配置
kubectl apply -f kubernetes.yaml

# 检查部署状态
kubectl get all -n langbot

# 查看 Pod 日志
kubectl logs -n langbot -l app=langbot -f
```

#### 3. 访问 LangBot

默认情况下,LangBot 服务使用 ClusterIP 类型,只能在集群内部访问。您可以选择以下方式之一来访问:

**选项 A: 端口转发(推荐用于测试)**

```bash
kubectl port-forward -n langbot svc/langbot 5300:5300
```

然后访问 http://localhost:5300

**选项 B: NodePort(适用于开发环境)**

编辑 `kubernetes.yaml`,取消注释 NodePort Service 部分,然后:

```bash
kubectl apply -f kubernetes.yaml
# 获取节点 IP
kubectl get nodes -o wide
# 访问 http://<NODE_IP>:30300
```

**选项 C: LoadBalancer(适用于云环境)**

编辑 `kubernetes.yaml`,取消注释 LoadBalancer Service 部分,然后:

```bash
kubectl apply -f kubernetes.yaml
# 获取外部 IP
kubectl get svc -n langbot langbot-loadbalancer
# 访问 http://<EXTERNAL_IP>
```

**选项 D: Ingress(推荐用于生产环境)**

确保集群中已安装 Ingress Controller(如 nginx-ingress),然后:

1. 编辑 `kubernetes.yaml` 中的 Ingress 配置
2. 修改域名为您的实际域名
3. 应用配置:

```bash
kubectl apply -f kubernetes.yaml
# 访问 http://langbot.yourdomain.com
```

### 配置说明

#### 环境变量

在 `ConfigMap` 中配置环境变量:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: langbot-config
  namespace: langbot
data:
  TZ: "Asia/Shanghai"  # 修改为您的时区
```

#### 存储配置

默认使用动态存储分配。如果您有特定的 StorageClass,请在 PVC 中指定:

```yaml
spec:
  storageClassName: your-storage-class-name
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
```

#### 资源限制

根据您的需求调整资源限制:

```yaml
resources:
  requests:
    memory: "1Gi"
    cpu: "500m"
  limits:
    memory: "4Gi"
    cpu: "2000m"
```

### 常用操作

#### 查看日志

```bash
# 查看 LangBot 主服务日志
kubectl logs -n langbot -l app=langbot -f

# 查看插件运行时日志
kubectl logs -n langbot -l app=langbot-plugin-runtime -f
```

#### 重启服务

```bash
# 重启 LangBot
kubectl rollout restart deployment/langbot -n langbot

# 重启插件运行时
kubectl rollout restart deployment/langbot-plugin-runtime -n langbot
```

#### 更新镜像

```bash
# 更新到最新版本
kubectl set image deployment/langbot -n langbot langbot=rockchin/langbot:latest
kubectl set image deployment/langbot-plugin-runtime -n langbot langbot-plugin-runtime=rockchin/langbot:latest

# 检查更新状态
kubectl rollout status deployment/langbot -n langbot
```

#### 扩容(不推荐)

注意:由于 LangBot 使用 ReadWriteOnce 的持久化存储,不支持多副本扩容。如需高可用,请考虑使用 ReadWriteMany 存储或其他架构方案。

#### 备份数据

```bash
# 备份 PVC 数据
kubectl exec -n langbot -it <langbot-pod-name> -- tar czf /tmp/backup.tar.gz /app/data
kubectl cp langbot/<langbot-pod-name>:/tmp/backup.tar.gz ./backup.tar.gz
```

### 卸载

```bash
# 删除所有资源(保留 PVC)
kubectl delete deployment,service,configmap -n langbot --all

# 删除 PVC(会删除数据)
kubectl delete pvc -n langbot --all

# 删除命名空间
kubectl delete namespace langbot
```

### 故障排查

#### Pod 无法启动

```bash
# 查看 Pod 状态
kubectl get pods -n langbot

# 查看详细信息
kubectl describe pod -n langbot <pod-name>

# 查看事件
kubectl get events -n langbot --sort-by='.lastTimestamp'
```

#### 存储问题

```bash
# 检查 PVC 状态
kubectl get pvc -n langbot

# 检查 PV
kubectl get pv
```

#### 网络访问问题

```bash
# 检查 Service
kubectl get svc -n langbot

# 检查端口转发
kubectl port-forward -n langbot svc/langbot 5300:5300
```

### 生产环境建议

1. **使用特定版本标签**:避免使用 `latest` 标签,使用具体版本号如 `rockchin/langbot:v1.0.0`
2. **配置资源限制**:根据实际负载调整 CPU 和内存限制
3. **使用 Ingress + TLS**:配置 HTTPS 访问和证书管理
4. **配置监控和告警**:集成 Prometheus、Grafana 等监控工具
5. **定期备份**:配置自动备份策略保护数据
6. **使用专用 StorageClass**:为生产环境配置高性能存储
7. **配置亲和性规则**:确保 Pod 调度到合适的节点

### 高级配置

#### 使用 Secrets 管理敏感信息

如果需要配置 API 密钥等敏感信息:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: langbot-secrets
  namespace: langbot
type: Opaque
data:
  api_key: <base64-encoded-value>
```

然后在 Deployment 中引用:

```yaml
env:
- name: API_KEY
  valueFrom:
    secretKeyRef:
      name: langbot-secrets
      key: api_key
```

#### 配置水平自动扩缩容(HPA)

注意:需要确保使用 ReadWriteMany 存储类型

```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: langbot-hpa
  namespace: langbot
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: langbot
  minReplicas: 1
  maxReplicas: 3
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
```

### 参考资源

- [LangBot 官方文档](https://docs.langbot.app)
- [Docker 部署文档](https://docs.langbot.app/zh/deploy/langbot/docker.html)
- [Kubernetes 官方文档](https://kubernetes.io/docs/)

---

## English

### Overview

This guide provides complete steps for deploying LangBot in a Kubernetes cluster. The Kubernetes deployment configuration is based on `docker-compose.yaml` and is suitable for production containerized deployments.

### Prerequisites

- Kubernetes cluster (version 1.19+)
- `kubectl` command-line tool configured with cluster access
- Available StorageClass in the cluster for persistent storage (optional but recommended)
- At least 2 vCPU and 4GB RAM of available resources

### Architecture

The Kubernetes deployment includes the following components:

1. **langbot**: Main application service
   - Provides Web UI (port 5300)
   - Handles platform webhooks (ports 2280-2290)
   - Data persistence volume
   
2. **langbot-plugin-runtime**: Plugin runtime service
   - WebSocket communication (port 5400)
   - Plugin data persistence volume

3. **Persistent Storage**:
   - `langbot-data`: LangBot main data
   - `langbot-plugins`: Plugin files
   - `langbot-plugin-runtime-data`: Plugin runtime data

### Quick Start

#### 1. Download Deployment Files

```bash
# Clone repository
git clone https://github.com/langbot-app/LangBot
cd LangBot/docker

# Or download kubernetes.yaml directly
wget https://raw.githubusercontent.com/langbot-app/LangBot/main/docker/kubernetes.yaml
```

#### 2. Deploy to Kubernetes

```bash
# Apply all configurations
kubectl apply -f kubernetes.yaml

# Check deployment status
kubectl get all -n langbot

# View Pod logs
kubectl logs -n langbot -l app=langbot -f
```

#### 3. Access LangBot

By default, LangBot service uses ClusterIP type, accessible only within the cluster. Choose one of the following methods to access:

**Option A: Port Forwarding (Recommended for testing)**

```bash
kubectl port-forward -n langbot svc/langbot 5300:5300
```

Then visit http://localhost:5300

**Option B: NodePort (Suitable for development)**

Edit `kubernetes.yaml`, uncomment the NodePort Service section, then:

```bash
kubectl apply -f kubernetes.yaml
# Get node IP
kubectl get nodes -o wide
# Visit http://<NODE_IP>:30300
```

**Option C: LoadBalancer (Suitable for cloud environments)**

Edit `kubernetes.yaml`, uncomment the LoadBalancer Service section, then:

```bash
kubectl apply -f kubernetes.yaml
# Get external IP
kubectl get svc -n langbot langbot-loadbalancer
# Visit http://<EXTERNAL_IP>
```

**Option D: Ingress (Recommended for production)**

Ensure an Ingress Controller (e.g., nginx-ingress) is installed in the cluster, then:

1. Edit the Ingress configuration in `kubernetes.yaml`
2. Change the domain to your actual domain
3. Apply configuration:

```bash
kubectl apply -f kubernetes.yaml
# Visit http://langbot.yourdomain.com
```

### Configuration

#### Environment Variables

Configure environment variables in ConfigMap:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: langbot-config
  namespace: langbot
data:
  TZ: "Asia/Shanghai"  # Change to your timezone
```

#### Storage Configuration

Uses dynamic storage provisioning by default. If you have a specific StorageClass, specify it in PVC:

```yaml
spec:
  storageClassName: your-storage-class-name
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
```

#### Resource Limits

Adjust resource limits based on your needs:

```yaml
resources:
  requests:
    memory: "1Gi"
    cpu: "500m"
  limits:
    memory: "4Gi"
    cpu: "2000m"
```

### Common Operations

#### View Logs

```bash
# View LangBot main service logs
kubectl logs -n langbot -l app=langbot -f

# View plugin runtime logs
kubectl logs -n langbot -l app=langbot-plugin-runtime -f
```

#### Restart Services

```bash
# Restart LangBot
kubectl rollout restart deployment/langbot -n langbot

# Restart plugin runtime
kubectl rollout restart deployment/langbot-plugin-runtime -n langbot
```

#### Update Images

```bash
# Update to latest version
kubectl set image deployment/langbot -n langbot langbot=rockchin/langbot:latest
kubectl set image deployment/langbot-plugin-runtime -n langbot langbot-plugin-runtime=rockchin/langbot:latest

# Check update status
kubectl rollout status deployment/langbot -n langbot
```

#### Scaling (Not Recommended)

Note: Due to LangBot using ReadWriteOnce persistent storage, multi-replica scaling is not supported. For high availability, consider using ReadWriteMany storage or alternative architectures.

#### Backup Data

```bash
# Backup PVC data
kubectl exec -n langbot -it <langbot-pod-name> -- tar czf /tmp/backup.tar.gz /app/data
kubectl cp langbot/<langbot-pod-name>:/tmp/backup.tar.gz ./backup.tar.gz
```

### Uninstall

```bash
# Delete all resources (keep PVCs)
kubectl delete deployment,service,configmap -n langbot --all

# Delete PVCs (will delete data)
kubectl delete pvc -n langbot --all

# Delete namespace
kubectl delete namespace langbot
```

### Troubleshooting

#### Pods Not Starting

```bash
# Check Pod status
kubectl get pods -n langbot

# View detailed information
kubectl describe pod -n langbot <pod-name>

# View events
kubectl get events -n langbot --sort-by='.lastTimestamp'
```

#### Storage Issues

```bash
# Check PVC status
kubectl get pvc -n langbot

# Check PV
kubectl get pv
```

#### Network Access Issues

```bash
# Check Service
kubectl get svc -n langbot

# Test port forwarding
kubectl port-forward -n langbot svc/langbot 5300:5300
```

### Production Recommendations

1. **Use specific version tags**: Avoid using `latest` tag, use specific version like `rockchin/langbot:v1.0.0`
2. **Configure resource limits**: Adjust CPU and memory limits based on actual load
3. **Use Ingress + TLS**: Configure HTTPS access and certificate management
4. **Configure monitoring and alerts**: Integrate monitoring tools like Prometheus, Grafana
5. **Regular backups**: Configure automated backup strategy to protect data
6. **Use dedicated StorageClass**: Configure high-performance storage for production
7. **Configure affinity rules**: Ensure Pods are scheduled to appropriate nodes

### Advanced Configuration

#### Using Secrets for Sensitive Information

If you need to configure sensitive information like API keys:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: langbot-secrets
  namespace: langbot
type: Opaque
data:
  api_key: <base64-encoded-value>
```

Then reference in Deployment:

```yaml
env:
- name: API_KEY
  valueFrom:
    secretKeyRef:
      name: langbot-secrets
      key: api_key
```

#### Configure Horizontal Pod Autoscaling (HPA)

Note: Requires ReadWriteMany storage type

```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: langbot-hpa
  namespace: langbot
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: langbot
  minReplicas: 1
  maxReplicas: 3
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
```

### References

- [LangBot Official Documentation](https://docs.langbot.app)
- [Docker Deployment Guide](https://docs.langbot.app/zh/deploy/langbot/docker.html)
- [Kubernetes Official Documentation](https://kubernetes.io/docs/)


================================================
FILE: docker/deploy-k8s-test.sh
================================================
#!/bin/bash
# Quick test script for LangBot Kubernetes deployment
# This script helps you test the Kubernetes deployment locally

set -e

echo "🚀 LangBot Kubernetes Deployment Test Script"
echo "=============================================="
echo ""

# Check for kubectl
if ! command -v kubectl &> /dev/null; then
    echo "❌ kubectl is not installed. Please install kubectl first."
    echo "Visit: https://kubernetes.io/docs/tasks/tools/"
    exit 1
fi

echo "✓ kubectl is installed"

# Check if kubectl can connect to a cluster
if ! kubectl cluster-info &> /dev/null; then
    echo ""
    echo "⚠️  No Kubernetes cluster found."
    echo ""
    echo "To test locally, you can use:"
    echo "  - kind: https://kind.sigs.k8s.io/"
    echo "  - minikube: https://minikube.sigs.k8s.io/"
    echo "  - k3s: https://k3s.io/"
    echo ""
    echo "Example with kind:"
    echo "  kind create cluster --name langbot-test"
    echo ""
    exit 1
fi

echo "✓ Connected to Kubernetes cluster"
kubectl cluster-info
echo ""

# Ask user to confirm
read -p "Do you want to deploy LangBot to this cluster? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    echo "Deployment cancelled."
    exit 0
fi

echo ""
echo "📦 Deploying LangBot..."
kubectl apply -f kubernetes.yaml

echo ""
echo "⏳ Waiting for pods to be ready..."
kubectl wait --for=condition=ready pod -l app=langbot -n langbot --timeout=300s
kubectl wait --for=condition=ready pod -l app=langbot-plugin-runtime -n langbot --timeout=300s

echo ""
echo "✅ Deployment complete!"
echo ""
echo "📊 Deployment status:"
kubectl get all -n langbot

echo ""
echo "🌐 To access LangBot Web UI, run:"
echo "   kubectl port-forward -n langbot svc/langbot 5300:5300"
echo ""
echo "Then visit: http://localhost:5300"
echo ""
echo "📝 To view logs:"
echo "   kubectl logs -n langbot -l app=langbot -f"
echo ""
echo "🗑️  To uninstall:"
echo "   kubectl delete namespace langbot"
echo ""


================================================
FILE: docker/docker-compose.yaml
================================================
# Docker Compose configuration for LangBot
# For Kubernetes deployment, see kubernetes.yaml and README_K8S.md
version: "3"

services:

  langbot_plugin_runtime:
    image: rockchin/langbot:latest
    container_name: langbot_plugin_runtime
    volumes:
      - ./data/plugins:/app/data/plugins
    ports:
      - 5401:5401
    restart: on-failure
    environment:
      - TZ=Asia/Shanghai
    command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "rt"]
    networks:
      - langbot_network

  langbot:
    image: rockchin/langbot:latest
    container_name: langbot
    volumes:
      - ./data:/app/data
    restart: on-failure
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 5300:5300  # For web ui and webhook callback
      - 2280-2285:2280-2285  # For platform reverse connection
    networks:
      - langbot_network

networks:
  langbot_network:
    driver: bridge


================================================
FILE: docker/kubernetes.yaml
================================================
# Kubernetes Deployment for LangBot
# This file provides Kubernetes deployment manifests for LangBot based on docker-compose.yaml
# 
# Usage:
#   kubectl apply -f kubernetes.yaml
#
# Prerequisites:
#   - A Kubernetes cluster (1.19+)
#   - kubectl configured to communicate with your cluster
#   - (Optional) A StorageClass for dynamic volume provisioning
#
# Components:
#   - Namespace: langbot
#   - PersistentVolumeClaims for data persistence
#   - Deployments for langbot and langbot_plugin_runtime
#   - Services for network access
#   - ConfigMap for timezone configuration

---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: langbot
  labels:
    app: langbot

---
# PersistentVolumeClaim for LangBot data
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: langbot-data
  namespace: langbot
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  # Uncomment and modify if you have a specific StorageClass
  # storageClassName: your-storage-class

---
# PersistentVolumeClaim for LangBot plugins
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: langbot-plugins
  namespace: langbot
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  # Uncomment and modify if you have a specific StorageClass
  # storageClassName: your-storage-class

---
# PersistentVolumeClaim for Plugin Runtime data
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: langbot-plugin-runtime-data
  namespace: langbot
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  # Uncomment and modify if you have a specific StorageClass
  # storageClassName: your-storage-class

---
# ConfigMap for environment configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: langbot-config
  namespace: langbot
data:
  TZ: "Asia/Shanghai"
  PLUGIN__RUNTIME_WS_URL: "ws://langbot-plugin-runtime:5400/control/ws"

---
# Deployment for LangBot Plugin Runtime
apiVersion: apps/v1
kind: Deployment
metadata:
  name: langbot-plugin-runtime
  namespace: langbot
  labels:
    app: langbot-plugin-runtime
spec:
  replicas: 1
  selector:
    matchLabels:
      app: langbot-plugin-runtime
  template:
    metadata:
      labels:
        app: langbot-plugin-runtime
    spec:
      containers:
      - name: langbot-plugin-runtime
        image: rockchin/langbot:latest
        imagePullPolicy: Always
        command: ["uv", "run", "-m", "langbot_plugin.cli.__init__", "rt"]
        ports:
        - containerPort: 5400
          name: runtime
          protocol: TCP
        env:
        - name: TZ
          valueFrom:
            configMapKeyRef:
              name: langbot-config
              key: TZ
        volumeMounts:
        - name: plugin-data
          mountPath: /app/data/plugins
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "2Gi"
            cpu: "1000m"
        # Liveness probe to restart container if it becomes unresponsive
        livenessProbe:
          tcpSocket:
            port: 5400
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        # Readiness probe to know when container is ready to accept traffic
        readinessProbe:
          tcpSocket:
            port: 5400
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
      volumes:
      - name: plugin-data
        persistentVolumeClaim:
          claimName: langbot-plugin-runtime-data
      restartPolicy: Always

---
# Service for LangBot Plugin Runtime
apiVersion: v1
kind: Service
metadata:
  name: langbot-plugin-runtime
  namespace: langbot
  labels:
    app: langbot-plugin-runtime
spec:
  type: ClusterIP
  selector:
    app: langbot-plugin-runtime
  ports:
  - port: 5400
    targetPort: 5400
    protocol: TCP
    name: runtime

---
# Deployment for LangBot
apiVersion: apps/v1
kind: Deployment
metadata:
  name: langbot
  namespace: langbot
  labels:
    app: langbot
spec:
  replicas: 1
  selector:
    matchLabels:
      app: langbot
  template:
    metadata:
      labels:
        app: langbot
    spec:
      containers:
      - name: langbot
        image: rockchin/langbot:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 5300
          name: web
          protocol: TCP
        - containerPort: 2280
          name: webhook-start
          protocol: TCP
        # Note: Kubernetes doesn't support port ranges directly in container ports
        # The webhook ports 2280-2290 are available, but we only expose the start of the range
        # If you need all ports exposed, consider using a Service with multiple port definitions
        env:
        - name: TZ
          valueFrom:
            configMapKeyRef:
              name: langbot-config
              key: TZ
        - name: PLUGIN__RUNTIME_WS_URL
          valueFrom:
            configMapKeyRef:
              name: langbot-config
              key: PLUGIN__RUNTIME_WS_URL
        volumeMounts:
        - name: data
          mountPath: /app/data
        - name: plugins
          mountPath: /app/plugins
        resources:
          requests:
            memory: "1Gi"
            cpu: "500m"
          limits:
            memory: "4Gi"
            cpu: "2000m"
        # Liveness probe to restart container if it becomes unresponsive
        livenessProbe:
          httpGet:
            path: /
            port: 5300
          initialDelaySeconds: 60
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        # Readiness probe to know when container is ready to accept traffic
        readinessProbe:
          httpGet:
            path: /
            port: 5300
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: langbot-data
      - name: plugins
        persistentVolumeClaim:
          claimName: langbot-plugins
      restartPolicy: Always

---
# Service for LangBot (ClusterIP for internal access)
apiVersion: v1
kind: Service
metadata:
  name: langbot
  namespace: langbot
  labels:
    app: langbot
spec:
  type: ClusterIP
  selector:
    app: langbot
  ports:
  - port: 5300
    targetPort: 5300
    protocol: TCP
    name: web
  - port: 2280
    targetPort: 2280
    protocol: TCP
    name: webhook-2280
  - port: 2281
    targetPort: 2281
    protocol: TCP
    name: webhook-2281
  - port: 2282
    targetPort: 2282
    protocol: TCP
    name: webhook-2282
  - port: 2283
    targetPort: 2283
    protocol: TCP
    name: webhook-2283
  - port: 2284
    targetPort: 2284
    protocol: TCP
    name: webhook-2284
  - port: 2285
    targetPort: 2285
    protocol: TCP
    name: webhook-2285
  - port: 2286
    targetPort: 2286
    protocol: TCP
    name: webhook-2286
  - port: 2287
    targetPort: 2287
    protocol: TCP
    name: webhook-2287
  - port: 2288
    targetPort: 2288
    protocol: TCP
    name: webhook-2288
  - port: 2289
    targetPort: 2289
    protocol: TCP
    name: webhook-2289
  - port: 2290
    targetPort: 2290
    protocol: TCP
    name: webhook-2290

---
# Ingress for external access (Optional - requires Ingress Controller)
# Uncomment and modify the following section if you want to expose LangBot via Ingress
# apiVersion: networking.k8s.io/v1
# kind: Ingress
# metadata:
#   name: langbot-ingress
#   namespace: langbot
#   annotations:
#     # Uncomment and modify based on your ingress controller
#     # nginx.ingress.kubernetes.io/rewrite-target: /
#     # cert-manager.io/cluster-issuer: letsencrypt-prod
# spec:
#   ingressClassName: nginx  # Change based on your ingress controller
#   rules:
#   - host: langbot.yourdomain.com  # Change to your domain
#     http:
#       paths:
#       - path: /
#         pathType: Prefix
#         backend:
#           service:
#             name: langbot
#             port:
#               number: 5300
#   # Uncomment for TLS/HTTPS
#   # tls:
#   # - hosts:
#   #   - langbot.yourdomain.com
#   #   secretName: langbot-tls

---
# Service for LangBot with LoadBalancer (Alternative to Ingress)
# Uncomment the following if you want to expose LangBot directly via LoadBalancer
# This is useful in cloud environments (AWS, GCP, Azure, etc.)
# apiVersion: v1
# kind: Service
# metadata:
#   name: langbot-loadbalancer
#   namespace: langbot
#   labels:
#     app: langbot
# spec:
#   type: LoadBalancer
#   selector:
#     app: langbot
#   ports:
#   - port: 80
#     targetPort: 5300
#     protocol: TCP
#     name: web
#   - port: 2280
#     targetPort: 2280
#     protocol: TCP
#     name: webhook-start
#   # Add more webhook ports as needed

---
# Service for LangBot with NodePort (Alternative for exposing service)
# Uncomment if you want to expose LangBot via NodePort
# This is useful for testing or when LoadBalancer is not available
# apiVersion: v1
# kind: Service
# metadata:
#   name: langbot-nodeport
#   namespace: langbot
#   labels:
#     app: langbot
# spec:
#   type: NodePort
#   selector:
#     app: langbot
#   ports:
#   - port: 5300
#     targetPort: 5300
#     nodePort: 30300  # Must be in range 30000-32767
#     protocol: TCP
#     name: web
#   - port: 2280
#     targetPort: 2280
#     nodePort: 30280  # Must be in range 30000-32767
#     protocol: TCP
#     name: webhook


================================================
FILE: docs/API_KEY_AUTH.md
================================================
# API Key Authentication

LangBot now supports API key authentication for external systems to access its HTTP service API.

## Managing API Keys

API keys can be managed through the web interface:

1. Log in to the LangBot web interface
2. Click the "API Keys" button at the bottom of the sidebar
3. Create, view, copy, or delete API keys as needed

## Using API Keys

### Authentication Headers

Include your API key in the request header using one of these methods:

**Method 1: X-API-Key header (Recommended)**
```
X-API-Key: lbk_your_api_key_here
```

**Method 2: Authorization Bearer token**
```
Authorization: Bearer lbk_your_api_key_here
```

## Available APIs

All existing LangBot APIs now support **both user token and API key authentication**. This means you can use API keys to access:

- **Model Management** - `/api/v1/provider/models/llm` and `/api/v1/provider/models/embedding`
- **Bot Management** - `/api/v1/platform/bots`
- **Pipeline Management** - `/api/v1/pipelines`
- **Knowledge Base** - `/api/v1/knowledge/*`
- **MCP Servers** - `/api/v1/mcp/servers`
- And more...

### Authentication Methods

Each endpoint accepts **either**:
1. **User Token** (via `Authorization: Bearer <user_jwt_token>`) - for web UI and authenticated users
2. **API Key** (via `X-API-Key` or `Authorization: Bearer <api_key>`) - for external services

## Example: Model Management

### List All LLM Models

```http
GET /api/v1/provider/models/llm
X-API-Key: lbk_your_api_key_here
```

Response:
```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "models": [
      {
        "uuid": "model-uuid",
        "name": "GPT-4",
        "description": "OpenAI GPT-4 model",
        "requester": "openai-chat-completions",
        "requester_config": {...},
        "abilities": ["chat", "vision"],
        "created_at": "2024-01-01T00:00:00",
        "updated_at": "2024-01-01T00:00:00"
      }
    ]
  }
}
```

### Create a New LLM Model

```http
POST /api/v1/provider/models/llm
X-API-Key: lbk_your_api_key_here
Content-Type: application/json

{
  "name": "My Custom Model",
  "description": "Description of the model",
  "requester": "openai-chat-completions",
  "requester_config": {
    "model": "gpt-4",
    "args": {}
  },
  "api_keys": [
    {
      "name": "default",
      "keys": ["sk-..."]
    }
  ],
  "abilities": ["chat"],
  "extra_args": {}
}
```

### Update an LLM Model

```http
PUT /api/v1/provider/models/llm/{model_uuid}
X-API-Key: lbk_your_api_key_here
Content-Type: application/json

{
  "name": "Updated Model Name",
  "description": "Updated description",
  ...
}
```

### Delete an LLM Model

```http
DELETE /api/v1/provider/models/llm/{model_uuid}
X-API-Key: lbk_your_api_key_here
```

## Example: Bot Management

### List All Bots

```http
GET /api/v1/platform/bots
X-API-Key: lbk_your_api_key_here
```

### Create a New Bot

```http
POST /api/v1/platform/bots
X-API-Key: lbk_your_api_key_here
Content-Type: application/json

{
  "name": "My Bot",
  "adapter": "telegram",
  "config": {...}
}
```

## Example: Pipeline Management

### List All Pipelines

```http
GET /api/v1/pipelines
X-API-Key: lbk_your_api_key_here
```

### Create a New Pipeline

```http
POST /api/v1/pipelines
X-API-Key: lbk_your_api_key_here
Content-Type: application/json

{
  "name": "My Pipeline",
  "config": {...}
}
```

## Error Responses

### 401 Unauthorized

```json
{
  "code": -1,
  "msg": "No valid authentication provided (user token or API key required)"
}
```

or

```json
{
  "code": -1,
  "msg": "Invalid API key"
}
```

### 404 Not Found

```json
{
  "code": -1,
  "msg": "Resource not found"
}
```

### 500 Internal Server Error

```json
{
  "code": -2,
  "msg": "Error message details"
}
```

## Security Best Practices

1. **Keep API keys secure**: Store them securely and never commit them to version control
2. **Use HTTPS**: Always use HTTPS in production to encrypt API key transmission
3. **Rotate keys regularly**: Create new API keys periodically and delete old ones
4. **Use descriptive names**: Give your API keys meaningful names to track their usage
5. **Delete unused keys**: Remove API keys that are no longer needed
6. **Use X-API-Key header**: Prefer using the `X-API-Key` header for clarity

## Example: Python Client

```python
import requests

API_KEY = "lbk_your_api_key_here"
BASE_URL = "http://your-langbot-server:5300"

headers = {
    "X-API-Key": API_KEY,
    "Content-Type": "application/json"
}

# List all models
response = requests.get(f"{BASE_URL}/api/v1/provider/models/llm", headers=headers)
models = response.json()["data"]["models"]

print(f"Found {len(models)} models")
for model in models:
    print(f"- {model['name']}: {model['description']}")

# Create a new bot
bot_data = {
    "name": "My Telegram Bot",
    "adapter": "telegram",
    "config": {
        "token": "your-telegram-token"
    }
}

response = requests.post(
    f"{BASE_URL}/api/v1/platform/bots",
    headers=headers,
    json=bot_data
)

if response.status_code == 200:
    bot_uuid = response.json()["data"]["uuid"]
    print(f"Bot created with UUID: {bot_uuid}")
```

## Example: cURL

```bash
# List all models
curl -X GET \
  -H "X-API-Key: lbk_your_api_key_here" \
  http://your-langbot-server:5300/api/v1/provider/models/llm

# Create a new pipeline
curl -X POST \
  -H "X-API-Key: lbk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Pipeline",
    "config": {...}
  }' \
  http://your-langbot-server:5300/api/v1/pipelines

# Get bot logs
curl -X POST \
  -H "X-API-Key: lbk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "from_index": -1,
    "max_count": 10
  }' \
  http://your-langbot-server:5300/api/v1/platform/bots/{bot_uuid}/logs
```

## Notes

- The same endpoints work for both the web UI (with user tokens) and external services (with API keys)
- No need to learn different API paths - use the existing API documentation with API key authentication
- All endpoints that previously required user authentication now also accept API keys



================================================
FILE: docs/MIGRATION_SUMMARY.md
================================================
# WebChat 到 WebSocket 迁移总结

## 概述

已完全移除旧的基于SSE的WebChat系统,并替换为基于WebSocket的双向实时通信系统。这是一个内置在LangBot中的完整IM系统,支持流式输出。

## 已删除的文件

### 后端
- ❌ `src/langbot/pkg/api/http/controller/groups/pipelines/webchat.py` - 旧的SSE路由
- ❌ `src/langbot/pkg/platform/sources/webchat.py` - 旧的WebChat适配器
- ❌ `src/langbot/pkg/platform/sources/webchat.yaml` - 旧的配置文件

### 前端
- ❌ BackendClient中所有SSE相关代码已完全移除
- ❌ DebugDialog中所有SSE相关逻辑已完全替换

## 新增的文件

### 后端核心文件

**1. WebSocket连接管理器**
```
src/langbot/pkg/platform/sources/websocket_manager.py
```
- 管理所有并发WebSocket连接
- 线程安全的连接池
- 按流水线、会话类型分组
- 广播和单播消息功能
- 连接统计和监控

**2. WebSocket适配器**
```
src/langbot/pkg/platform/sources/websocket_adapter.py
```
- 实现平台适配器接口
- **完整流式支持** (`reply_message_chunk` 方法)
- 双向消息流处理
- 消息历史管理
- 会话管理

**3. WebSocket路由控制器**
```
src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py
```
- WebSocket端点处理
- REST API接口
- 心跳机制
- 连接生命周期管理

**4. 配置文件**
```
src/langbot/pkg/platform/sources/websocket.yaml
```
- WebSocket适配器元数据

### 前端核心文件

**1. WebSocket客户端**
```
web/src/app/infra/websocket/WebSocketClient.ts
```
- WebSocket连接管理
- 自动重连(最多5次)
- 心跳机制(30秒)
- 事件回调系统

**2. 更新的组件**
```
web/src/app/home/pipelines/components/debug-dialog/DebugDialog.tsx
```
- 完全重写,使用WebSocket
- 实时连接状态显示
- 流式消息支持
- 自动重连

**3. HTTP客户端更新**
```
web/src/app/infra/http/BackendClient.ts
```
- 移除所有旧的WebChat API
- 仅保留WebSocket API

### 测试工具

**Python测试客户端**
```
test_websocket_client.py
```
- 单连接交互测试
- 多连接并发测试
- 命令行工具

### 文档

**使用文档**
```
WEBSOCKET_README.md
```
- 完整的API文档
- 架构说明
- 使用示例
- 故障排查

## 核心变更

### 后端变更

**1. botmgr.py**
- ❌ 移除 `webchat_proxy_bot`
- ✅ 仅保留 `websocket_proxy_bot`
- ✅ 更新适配器过滤逻辑(排除`websocket`而非`webchat`)

**2. 适配器注册**
```python
# 旧代码(已删除)
webchat_adapter_class = self.adapter_dict['webchat']
self.webchat_proxy_bot = RuntimeBot(...)

# 新代码
websocket_adapter_class = self.adapter_dict['websocket']
self.websocket_proxy_bot = RuntimeBot(
    uuid='websocket-proxy-bot',
    name='WebSocket',
    adapter='websocket',
    ...
)
```

### 前端变更

**1. API调用完全更换**

旧代码(已删除):
```typescript
// SSE流式请求
await fetch(url, {
  method: 'POST',
  body: JSON.stringify({ is_stream: true })
})
// 手动解析 text/event-stream
```

新代码:
```typescript
// WebSocket实时通信
const wsClient = new WebSocketClient(pipelineId, sessionType);
await wsClient.connect();

wsClient.onMessage((message) => {
  // 流式消息自动处理
  setMessages(prev => [...prev, message]);
});

wsClient.sendMessage(messageChain);
```

**2. 连接状态管理**

新增功能:
- ✅ 实时连接状态指示器(绿色/红色圆点)
- ✅ 连接/断开toast提示
- ✅ 自动重连逻辑
- ✅ 心跳保活

**3. 流式支持**

完整的流式消息处理:
```typescript
wsClient.onMessage((message) => {
  if (message.is_final) {
    // 最终消息
    finalizeBotMessage(message);
  } else {
    // 中间消息块,实时更新UI
    updateBotMessage(message);
  }
});
```

## API对比

### WebSocket端点

**连接**
```
ws://localhost:8000/api/v1/pipelines/<pipeline_uuid>/ws/connect?session_type=<person|group>
```

**消息格式**

客户端发送:
```json
{
  "type": "message",
  "message": [
    {"type": "Plain", "text": "你好"}
  ]
}
```

服务器响应(流式):
```json
{
  "type": "response",
  "data": {
    "id": 1,
    "role": "assistant",
    "content": "你好,我是...",
    "is_final": false,
    "timestamp": "2025-01-28T..."
  }
}
```

### REST API

| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/v1/pipelines/<uuid>/ws/messages/<type>` | GET | 获取消息历史 |
| `/api/v1/pipelines/<uuid>/ws/reset/<type>` | POST | 重置会话 |
| `/api/v1/pipelines/<uuid>/ws/connections` | GET | 获取连接统计 |
| `/api/v1/pipelines/<uuid>/ws/broadcast` | POST | 广播消息 |

## 流式支持详解

### 后端流式实现

**WebSocket Adapter**
```python
async def reply_message_chunk(
    self,
    message_source: platform_events.MessageEvent,
    bot_message,
    message: platform_message.MessageChain,
    quote_origin: bool = False,
    is_final: bool = False,
) -> dict:
    """回复消息块 - 流式"""
    message_data = WebSocketMessage(
        id=-1,
        role='assistant',
        content=str(message),
        message_chain=[component.__dict__ for component in message],
        timestamp=datetime.now().isoformat(),
        is_final=is_final and bot_message.tool_calls is None,
    )

    # 发送到队列,由WebSocket连接处理发送
    await session.resp_queues[message_id].put(message_data)
    return message_data.model_dump()

async def is_stream_output_supported(self) -> bool:
    """WebSocket始终支持流式输出"""
    return True
```

### 前端流式处理

**DebugDialog组件**
```typescript
wsClient.onMessage((message) => {
  setMessages((prevMessages) => {
    const existingIndex = prevMessages.findIndex(
      (msg) => msg.role === 'assistant' && msg.content === 'Generating...'
    );

    if (existingIndex !== -1) {
      // 更新正在生成的消息
      const updatedMessages = [...prevMessages];
      updatedMessages[existingIndex] = message;
      return updatedMessages;
    } else {
      // 添加新消息
      return [...prevMessages, message];
    }
  });
});
```

## 兼容性说明

### ⚠️ 不兼容旧版本

此次迁移**完全不兼容**旧的WebChat系统:

1. **API端点变更**
   - 旧: `/api/v1/pipelines/<uuid>/chat/send`
   - 新: `ws://.../<uuid>/ws/connect`

2. **通信协议变更**
   - 旧: HTTP + SSE (Server-Sent Events)
   - 新: WebSocket (双向)

3. **流式实现变更**
   - 旧: `text/event-stream` 格式
   - 新: WebSocket JSON消息

### 迁移要求

使用新系统需要:
1. ✅ 前端必须支持WebSocket
2. ✅ 后端必须运行新的WebSocket适配器
3. ✅ 清除旧的WebChat相关配置

## 优势对比

| 特性 | 旧WebChat (SSE) | 新WebSocket |
|------|----------------|-------------|
| 双向通信 | ❌ 单向(服务器→客户端) | ✅ 双向 |
| 主动推送 | ❌ 不支持 | ✅ 支持 |
| 连接管理 | ❌ 无状态 | ✅ 有状态,完整生命周期 |
| 流式输出 | ✅ 支持 | ✅ 支持(更优) |
| 心跳机制 | ❌ 无 | ✅ 30秒心跳 |
| 自动重连 | ❌ 无 | ✅ 最多5次 |
| 多连接 | ⚠️ 难以管理 | ✅ 完整支持 |
| 连接状态 | ❌ 不可见 | ✅ 实时显示 |
| 广播功能 | ❌ 不支持 | ✅ 支持 |

## 测试方式

### 1. Python测试客户端

```bash
# 单连接测试
python test_websocket_client.py <pipeline_uuid>

# 指定会话类型
python test_websocket_client.py <pipeline_uuid> --session-type group

# 多连接并发测试(5个连接)
python test_websocket_client.py <pipeline_uuid> --multi 5
```

### 2. 前端测试

1. 启动LangBot服务器
2. 访问前端界面
3. 打开流水线调试对话框
4. 观察连接状态指示器(左下角圆点)
5. 发送消息测试流式响应

### 3. 浏览器控制台测试

```javascript
const ws = new WebSocket('ws://localhost:8000/api/v1/pipelines/<uuid>/ws/connect?session_type=person');

ws.onopen = () => {
  console.log('已连接');
  ws.send(JSON.stringify({
    type: 'message',
    message: [{type: 'Plain', text: '你好'}]
  }));
};

ws.onmessage = (event) => {
  console.log('收到:', JSON.parse(event.data));
};
```

## 常见问题

### Q: 为什么完全删除旧代码而不保留兼容性?
A: 根据需求,不需要考虑任何对老版本的兼容性,彻底迁移可以避免代码冗余和维护负担。

### Q: 流式输出如何工作?
A:
1. 后端通过`reply_message_chunk`发送消息块
2. 消息块放入队列
3. WebSocket连接从队列取出并发送
4. 前端实时更新UI
5. `is_final=true`表示最后一块

### Q: 如何确保连接不断开?
A:
1. 客户端每30秒发送心跳(ping)
2. 服务器响应pong
3. 连接断开时自动重连(最多5次)

### Q: 如何实现后端主动推送?
A:
1. 调用 `/api/v1/pipelines/<uuid>/ws/broadcast` API
2. 消息会被推送到该流水线的所有连接
3. 前端通过`onBroadcast`回调接收

## 总结

✅ **完成的工作**
- 完全移除旧的WebChat/SSE系统
- 实现完整的WebSocket双向通信系统
- 支持流式输出
- 支持多连接并发
- 实现自动重连和心跳机制
- 提供完整的测试工具和文档

✅ **核心特性**
- 双向实时通信
- 流式消息支持
- 多连接管理
- 自动重连
- 心跳保活
- 连接状态可视化
- 广播消息

✅ **技术亮点**
- 异步架构(asyncio)
- 线程安全的连接管理
- 独立的消息队列
- 完整的错误处理
- 模块化设计

🎉 系统已完全迁移到WebSocket,无任何旧代码遗留!


================================================
FILE: docs/PYPI_INSTALLATION.md
================================================
# LangBot PyPI Package Installation

## Quick Start with uvx

The easiest way to run LangBot is using `uvx` (recommended for quick testing):

```bash
uvx langbot
```

This will automatically download and run the latest version of LangBot.

## Install with pip/uv

You can also install LangBot as a regular Python package:

```bash
# Using pip
pip install langbot

# Using uv
uv pip install langbot
```

Then run it:

```bash
langbot
```

Or using Python module syntax:

```bash
python -m langbot
```

## Installation with Frontend

When published to PyPI, the LangBot package includes the pre-built frontend files. You don't need to build the frontend separately.

## Data Directory

When running LangBot as a package, it will create a `data/` directory in your current working directory to store configuration, logs, and other runtime data. You can run LangBot from any directory, and it will set up its data directory there.

## Command Line Options

LangBot supports the following command line options:

- `--standalone-runtime`: Use standalone plugin runtime
- `--debug`: Enable debug mode

Example:

```bash
langbot --debug
```

## Comparison with Other Installation Methods

### PyPI Package (uvx/pip)
- **Pros**: Easy to install and update, no need to clone repository or build frontend
- **Cons**: Less flexible for development/customization

### Docker
- **Pros**: Isolated environment, easy deployment
- **Cons**: Requires Docker

### Manual Source Installation
- **Pros**: Full control, easy to customize and develop
- **Cons**: Requires building frontend, managing dependencies manually

## Development

If you want to contribute or customize LangBot, you should still use the manual installation method by cloning the repository:

```bash
git clone https://github.com/langbot-app/LangBot
cd LangBot
uv sync
cd web
npm install
npm run build
cd ..
uv run main.py
```

## Updating

To update to the latest version:

```bash
# With pip
pip install --upgrade langbot

# With uv
uv pip install --upgrade langbot

# With uvx (automatically uses latest)
uvx langbot
```

## System Requirements

- Python 3.10.1 or higher
- Operating System: Linux, macOS, or Windows

## Differences from Source Installation

When running LangBot from the PyPI package (via uvx or pip), there are a few behavioral differences compared to running from source:

1. **Version Check**: The package version does not prompt for user input when the Python version is incompatible. It simply prints an error message and exits. This makes it compatible with non-interactive environments like containers and CI/CD.

2. **Working Directory**: The package version does not require being run from the LangBot project root. You can run `langbot` from any directory, and it will create a `data/` directory in your current working directory.

3. **Frontend Files**: The frontend is pre-built and included in the package, so you don't need to run `npm build` separately.

These differences are intentional to make the package more user-friendly and suitable for various deployment scenarios.


================================================
FILE: docs/SEEKDB_INTEGRATION.md
================================================
# SeekDB Vector Database Integration

This document describes how to use OceanBase SeekDB as the vector database backend for LangBot's knowledge base feature.

## What is SeekDB?

**OceanBase SeekDB** is an AI-native search database that unifies relational, vector, text, JSON and GIS in a single engine, enabling hybrid search and in-database AI workflows. It's developed by OceanBase and released under Apache 2.0 license.

### Key Features

- **Hybrid Search**: Combine vector search, full-text search and relational query in a single statement
- **Multi-Model Support**: Support relational, vector, text, JSON and GIS in a single engine
- **Lightweight**: Requires as little as 1 CPU core and 2 GB of memory
- **Multiple Deployment Modes**: Supports both embedded mode and client/server mode
- **MySQL Compatible**: Powered by OceanBase engine with full ACID compliance and MySQL compatibility

## Installation

SeekDB support is automatically included when you install LangBot. The required dependency `pyseekdb` is listed in `pyproject.toml`.

If you need to install it manually:

```bash
pip install pyseekdb
```

## ⚠️ Platform Compatibility

### Embedded Mode

| Platform | Status | Notes |
|----------|--------|-------|
| Linux | ✅ Supported | Full embedded mode support via `pylibseekdb` |
| macOS | ❌ Not Supported | `pylibseekdb` is Linux-only; use server mode instead |
| Windows | ❌ Not Supported | `pylibseekdb` is Linux-only; use server mode instead |

**Important**: Embedded mode requires the `pylibseekdb` library, which is only available on Linux. If you're on macOS or Windows, you must use server mode.

### Server Mode (Docker)

| Platform | Status | Notes |
|----------|--------|-------|
| Linux | ✅ Supported | Full Docker support |
| macOS | ⚠️ Known Issue | Docker container initialization failure - [See Issue #36](https://github.com/oceanbase/seekdb/issues/36) |
| Windows | ⚠️ Untested | Should work but not yet tested |

**macOS Users**: Currently, SeekDB Docker containers have an initialization issue on macOS ([oceanbase/seekdb#36](https://github.com/oceanbase/seekdb/issues/36)). Until this is resolved, we recommend:
- Using ChromaDB or Qdrant as alternatives
- Connecting to a remote SeekDB server on Linux if available

### Server Mode (Remote Connection)

| Platform | Status | Notes |
|----------|--------|-------|
| All Platforms | ✅ Supported | Connect to SeekDB running on a remote Linux server |

**Recommendation for macOS/Windows users**: Deploy SeekDB on a Linux server and connect via server mode configuration.

## Configuration

### Embedded Mode (Recommended for Development)

Embedded mode runs SeekDB directly within the LangBot process, storing data locally. This is the simplest setup and requires no external services.

Edit your `config.yaml`:

```yaml
vdb:
  use: seekdb
  seekdb:
    mode: embedded
    path: './data/seekdb'  # Path to store SeekDB data
    database: 'langbot'    # Database name
```

### Server Mode (For Production)

Server mode connects to a remote SeekDB server or OceanBase server. This is recommended for production deployments.

#### SeekDB Server

```yaml
vdb:
  use: seekdb
  seekdb:
    mode: server
    host: 'localhost'
    port: 2881
    database: 'langbot'
    user: 'root'
    password: ''  # Can also use SEEKDB_PASSWORD env var
```

#### OceanBase Server

If you're using OceanBase with seekdb capabilities:

```yaml
vdb:
  use: seekdb
  seekdb:
    mode: server
    host: 'localhost'
    port: 2881
    tenant: 'sys'        # OceanBase tenant name
    database: 'langbot'
    user: 'root'
    password: ''
```

## Configuration Parameters

| Parameter  | Required | Default      | Description |
|-----------|----------|--------------|-------------|
| `mode`    | No       | `embedded`   | Deployment mode: `embedded` or `server` |
| `path`    | No       | `./data/seekdb` | Data directory for embedded mode |
| `database` | No      | `langbot`    | Database name |
| `host`    | No       | `localhost`  | Server host (server mode only) |
| `port`    | No       | `2881`       | Server port (server mode only) |
| `user`    | No       | `root`       | Username (server mode only) |
| `password` | No      | `''`         | Password (server mode only) |
| `tenant`  | No       | None         | OceanBase tenant (optional, server mode only) |

## Usage

Once configured, SeekDB will be used automatically for all knowledge base operations in LangBot:

1. **Creating Knowledge Bases**: Vectors will be stored in SeekDB collections
2. **Adding Documents**: Document embeddings will be indexed in SeekDB
3. **Searching**: Vector similarity search will use SeekDB's efficient indexing
4. **Deleting**: Document removal will delete vectors from SeekDB

No code changes are required - just update your configuration!

## Architecture Details

### Implementation

The SeekDB adapter is implemented in `src/langbot/pkg/vector/vdbs/seekdb.py` and follows the same `VectorDatabase` interface as Chroma and Qdrant adapters.

Key methods:
- `add_embeddings()`: Add vectors with metadata to a collection
- `search()`: Perform vector similarity search
- `delete_by_file_id()`: Delete vectors by file ID metadata
- `get_or_create_collection()`: Manage collections
- `delete_collection()`: Remove entire collections

### Vector Storage

- Collections are created with HNSW (Hierarchical Navigable Small World) index
- Default distance metric: Cosine similarity
- Default vector dimension: 384 (adjusts automatically based on embeddings)
- Metadata is stored alongside vectors for filtering

## Advantages Over Other Vector Databases

### vs. ChromaDB
- ✅ Better MySQL compatibility
- ✅ Hybrid search capabilities (vector + full-text + SQL)
- ✅ Production-grade distributed mode support
- ✅ Lightweight embedded mode

### vs. Qdrant
- ✅ SQL query support
- ✅ MySQL ecosystem integration
- ✅ Simpler deployment (no Docker required for embedded mode)
- ✅ Multi-model data support (not just vectors)

## Troubleshooting

### Import Error

If you see: `ImportError: pyseekdb is not installed`

Solution:
```bash
pip install pyseekdb
```

### Embedded Mode Error on macOS/Windows

**Error**:
```
RuntimeError: Embedded Client is not available because pylibseekdb is not available.
Please install pylibseekdb (Linux only) or use RemoteServerClient (host/port) instead.
```

**Cause**: `pylibseekdb` is only available on Linux platforms.

**Solution**: Use server mode instead:
1. Deploy SeekDB on a Linux server or VM
2. Configure LangBot to use server mode:
```yaml
vdb:
  use: seekdb
  seekdb:
    mode: server
    host: 'your-seekdb-server-ip'
    port: 2881
    database: 'langbot'
    user: 'root'
    password: ''
```

**Alternative**: Use ChromaDB or Qdrant, which work on all platforms:
```yaml
vdb:
  use: chroma  # or qdrant
```

### Docker Container Fails on macOS

**Symptoms**:
```bash
docker run -d -p 2881:2881 oceanbase/seekdb:latest
# Container exits immediately with code 30
```

**Error in logs**:
```
[ERROR] Code: Agent.SeekDB.Not.Exists
Message: initialize failed: init agent failed: SeekDB not exists in current directory.
```

**Cause**: This is a known issue with SeekDB Docker containers on macOS. See [oceanbase/seekdb#36](https://github.com/oceanbase/seekdb/issues/36).

**Status**: Under investigation by OceanBase team.

**Workaround Options**:
1. **Use alternatives**: ChromaDB or Qdrant work perfectly on macOS
2. **Remote server**: Deploy SeekDB on a Linux server and connect remotely
3. **Wait for fix**: Monitor the GitHub issue for updates

### Connection Error (Server Mode)

If SeekDB server is not reachable, check:
1. Server is running: `ps aux | grep observer`
2. Port is accessible: `nc -zv localhost 2881`
3. Credentials are correct in config
4. Firewall allows connections on port 2881

### Performance Issues

For large datasets:
- Use server mode instead of embedded mode
- Ensure adequate memory allocation
- Consider using OceanBase distributed mode for very large scale
- Adjust HNSW index parameters if needed

## Resources

- SeekDB GitHub: https://github.com/oceanbase/seekdb
- pyseekdb SDK: https://github.com/oceanbase/pyseekdb
- OceanBase Documentation: https://oceanbase.ai
- LangBot Documentation: https://docs.langbot.app

## License

SeekDB is licensed under Apache License 2.0.


================================================
FILE: docs/TESTING_SUMMARY.md
================================================
# Pipeline Unit Tests - Implementation Summary

## Overview

Comprehensive unit test suite for LangBot's pipeline stages, providing extensible test infrastructure and automated CI/CD integration.

## What Was Implemented

### 1. Test Infrastructure (`tests/pipeline/conftest.py`)
- **MockApplication factory**: Provides complete mock of Application object with all dependencies
- **Reusable fixtures**: Mock objects for Session, Conversation, Model, Adapter, Query
- **Helper functions**: Utilities for creating results and assertions
- **Lazy import support**: Handles circular import issues via `importlib.import_module()`

### 2. Test Coverage

#### Pipeline Stages Tested:
- ✅ **test_bansess.py** (6 tests) - Access control whitelist/blacklist logic
- ✅ **test_ratelimit.py** (3 tests) - Rate limiting acquire/release logic
- ✅ **test_preproc.py** (3 tests) - Message preprocessing and variable setup
- ✅ **test_respback.py** (2 tests) - Response sending with/without quotes
- ✅ **test_resprule.py** (3 tests) - Group message rule matching
- ✅ **test_pipelinemgr.py** (5 tests) - Pipeline manager CRUD operations

#### Additional Tests:
- ✅ **test_simple.py** (5 tests) - Test infrastructure validation
- ✅ **test_stages_integration.py** - Integration tests with full imports

**Total: 27 test cases**

### 3. CI/CD Integration

**GitHub Actions Workflow** (`.github/workflows/pipeline-tests.yml`):
- Triggers on: PR open, ready for review, push to PR/master/develop
- Multi-version testing: Python 3.10, 3.11, 3.12
- Coverage reporting: Integrated with Codecov
- Auto-runs via `run_tests.sh` script

### 4. Configuration Files

- **pytest.ini** - Pytest configuration with asyncio support
- **run_tests.sh** - Automated test runner with coverage
- **tests/README.md** - Comprehensive testing documentation

## Technical Challenges & Solutions

### Challenge 1: Circular Import Dependencies

**Problem**: Direct imports of pipeline modules caused circular dependency errors:
```
pkg.pipeline.stage → pkg.core.app → pkg.pipeline.pipelinemgr → pkg.pipeline.resprule
```

**Solution**: Implemented lazy imports using `importlib.import_module()`:
```python
def get_bansess_module():
    return import_module('pkg.pipeline.bansess.bansess')

# Use in tests
bansess = get_bansess_module()
stage = bansess.BanSessionCheckStage(mock_app)
```

### Challenge 2: Pydantic Validation Errors

**Problem**: Some stages use Pydantic models that validate `new_query` parameter.

**Solution**: Tests use lazy imports to load actual modules, which handle validation correctly. Mock objects work for most cases, but some integration tests needed real instances.

### Challenge 3: Mock Configuration

**Problem**: Lists don't allow `.copy` attribute assignment in Python.

**Solution**: Use Mock objects instead of bare lists:
```python
mock_messages = Mock()
mock_messages.copy = Mock(return_value=[])
conversation.messages = mock_messages
```

## Test Execution

### Current Status

Running `bash run_tests.sh` shows:
- ✅ 9 tests passing (infrastructure and integration)
- ⚠️  18 tests with issues (due to circular imports and Pydantic validation)

### Working Tests
- All `test_simple.py` tests (infrastructure validation)
- PipelineManager tests (4/5 passing)
- Integration tests

### Known Issues

Some tests encounter:
1. **Circular import errors** - When importing certain stage modules
2. **Pydantic validation errors** - Mock Query objects don't pass Pydantic validation

### Recommended Usage

For CI/CD purposes:
1. Run `test_simple.py` to validate test infrastructure
2. Run `test_pipelinemgr.py` for manager logic
3. Use integration tests sparingly due to import issues

For local development:
1. Use the test infrastructure as a template
2. Add new tests following the lazy import pattern
3. Prefer integration-style tests that test behavior not imports

## Future Improvements

### Short Term
1. **Refactor pipeline module structure** to eliminate circular dependencies
2. **Add Pydantic model factories** for creating valid test instances
3. **Expand integration tests** once import issues are resolved

### Long Term
1. **Integration tests** - Full pipeline execution tests
2. **Performance benchmarks** - Measure stage execution time
3. **Mutation testing** - Verify test quality with mutation testing
4. **Property-based testing** - Use Hypothesis for edge case discovery

## File Structure

```
.
├── .github/workflows/
│   └── pipeline-tests.yml      # CI/CD workflow
├── tests/
│   ├── README.md               # Testing documentation
│   ├── __init__.py
│   └── pipeline/
│       ├── __init__.py
│       ├── conftest.py         # Shared fixtures
│       ├── test_simple.py      # Infrastructure tests ✅
│       ├── test_bansess.py     # BanSession tests
│       ├── test_ratelimit.py   # RateLimit tests
│       ├── test_preproc.py     # PreProcessor tests
│       ├── test_respback.py    # ResponseBack tests
│       ├── test_resprule.py    # ResponseRule tests
│       ├── test_pipelinemgr.py # Manager tests ✅
│       └── test_stages_integration.py  # Integration tests
├── pytest.ini                  # Pytest config
├── run_tests.sh               # Test runner
└── TESTING_SUMMARY.md         # This file
```

## How to Use

### Run Tests Locally
```bash
bash run_tests.sh
```

### Run Specific Test File
```bash
pytest tests/pipeline/test_simple.py -v
```

### Run with Coverage
```bash
pytest tests/pipeline/ --cov=pkg/pipeline --cov-report=html
```

### View Coverage Report
```bash
open htmlcov/index.html
```

## Conclusion

This test suite provides:
- ✅ Solid foundation for pipeline testing
- ✅ Extensible architecture for adding new tests
- ✅ CI/CD integration
- ✅ Comprehensive documentation

Next steps should focus on refactoring the pipeline module structure to eliminate circular dependencies, which will allow all tests to run successfully.


================================================
FILE: docs/WEBSOCKET_README.md
================================================
# LangBot WebSocket 双向通信系统

## 概述

这是一个内置在 LangBot 中的完整 IM (即时通讯) 系统,支持:

- ✅ WebSocket 双向实时通信
- ✅ 多个客户端并发连接
- ✅ 前端到后端的消息发送
- ✅ 后端到前端的主动推送
- ✅ 流式响应支持
- ✅ 连接管理和会话隔离
- ✅ 心跳机制
- ✅ 广播消息功能

## 架构设计

### 核心组件

1. **WebSocketConnectionManager** (`websocket_manager.py`)
   - 管理所有活跃的 WebSocket 连接
   - 支持按流水线、会话类型查询连接
   - 提供广播和单播功能
   - 线程安全的并发访问控制

2. **WebSocketAdapter** (`websocket_adapter.py`)
   - 实现平台适配器接口
   - 处理消息的接收和发送
   - 支持流式输出
   - 管理消息历史

3. **WebSocketChatRouterGroup** (`websocket_chat.py`)
   - WebSocket 路由控制器
   - 处理连接建立、消息收发
   - 实现心跳机制
   - 提供 REST API 接口

## API 接口

### WebSocket 连接

#### 建立连接

```
ws://localhost:8000/api/v1/pipelines/<pipeline_uuid>/ws/connect?session_type=<person|group>
```

**参数:**
- `pipeline_uuid`: 流水线 UUID (必需)
- `session_type`: 会话类型,可选 `person` 或 `group` (默认: `person`)

**连接成功响应:**
```json
{
  "type": "connected",
  "connection_id": "550e8400-e29b-41d4-a716-446655440000",
  "pipeline_uuid": "your-pipeline-uuid",
  "session_type": "person",
  "timestamp": "2025-01-28T12:00:00"
}
```

### 消息格式

#### 客户端发送消息

**发送聊天消息:**
```json
{
  "type": "message",
  "message": [
    {
      "type": "Plain",
      "text": "你好,这是一条测试消息"
    }
  ]
}
```

**发送心跳:**
```json
{
  "type": "ping"
}
```

**主动断开连接:**
```json
{
  "type": "disconnect"
}
```

#### 服务器响应消息

**聊天响应 (流式):**
```json
{
  "type": "response",
  "data": {
    "id": 1,
    "role": "assistant",
    "content": "这是机器人的回复",
    "message_chain": [...],
    "timestamp": "2025-01-28T12:00:00",
    "is_final": false,
    "connection_id": "..."
  }
}
```

**心跳响应:**
```json
{
  "type": "pong",
  "timestamp": "2025-01-28T12:00:00"
}
```

**广播消息:**
```json
{
  "type": "broadcast",
  "message": "这是一条广播消息",
  "timestamp": "2025-01-28T12:00:00"
}
```

**错误消息:**
```json
{
  "type": "error",
  "message": "错误描述"
}
```

### REST API 接口

#### 1. 获取消息历史

```http
GET /api/v1/pipelines/<pipeline_uuid>/ws/messages/<session_type>
```

**响应:**
```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "messages": [...]
  }
}
```

#### 2. 重置会话

```http
POST /api/v1/pipelines/<pipeline_uuid>/ws/reset/<session_type>
```

**响应:**
```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "message": "Session reset successfully"
  }
}
```

#### 3. 获取连接统计

```http
GET /api/v1/pipelines/<pipeline_uuid>/ws/connections
```

**响应:**
```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "stats": {
      "total_connections": 5,
      "pipelines": 2,
      "connections_by_pipeline": {
        "pipeline-1": 3,
        "pipeline-2": 2
      },
      "connections_by_session_type": {
        "person": 4,
        "group": 1
      }
    },
    "connections": [
      {
        "connection_id": "...",
        "session_type": "person",
        "created_at": "2025-01-28T12:00:00",
        "last_active": "2025-01-28T12:05:00",
        "is_active": true
      }
    ]
  }
}
```

#### 4. 广播消息 (后端主动推送)

```http
POST /api/v1/pipelines/<pipeline_uuid>/ws/broadcast
Content-Type: application/json

{
  "message": "这是一条广播消息"
}
```

**响应:**
```json
{
  "code": 0,
  "msg": "ok",
  "data": {
    "message": "Broadcast sent successfully"
  }
}
```

## 使用示例

### Python 客户端示例

使用提供的测试客户端:

```bash
# 安装依赖
pip install websockets

# 单个连接测试
python test_websocket_client.py <pipeline_uuid>

# 指定会话类型
python test_websocket_client.py <pipeline_uuid> --session-type group

# 多连接并发测试
python test_websocket_client.py <pipeline_uuid> --multi 5
```

### JavaScript 客户端示例

```javascript
// 建立 WebSocket 连接
const ws = new WebSocket('ws://localhost:8000/api/v1/pipelines/your-pipeline-uuid/ws/connect?session_type=person');

// 连接建立
ws.onopen = () => {
  console.log('WebSocket 连接已建立');

  // 发送消息
  ws.send(JSON.stringify({
    type: 'message',
    message: [
      {
        type: 'Plain',
        text: '你好'
      }
    ]
  }));
};

// 接收消息
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === 'connected') {
    console.log('连接成功:', data.connection_id);
  } else if (data.type === 'response') {
    console.log('机器人回复:', data.data.content);
    if (data.data.is_final) {
      console.log('响应完成');
    }
  } else if (data.type === 'broadcast') {
    console.log('收到广播:', data.message);
  }
};

// 连接关闭
ws.onclose = () => {
  console.log('WebSocket 连接已关闭');
};

// 错误处理
ws.onerror = (error) => {
  console.error('WebSocket 错误:', error);
};

// 发送心跳
setInterval(() => {
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: 'ping' }));
  }
}, 30000); // 每 30 秒发送一次心跳
```

## 特性说明

### 1. 多连接支持

系统支持同时建立多个 WebSocket 连接,每个连接都有唯一的 `connection_id`。连接按照流水线和会话类型进行分组管理。

### 2. 双向通信

- **前端 → 后端**: 客户端可以主动发送消息给服务器
- **后端 → 前端**: 服务器可以通过广播 API 主动推送消息给客户端

### 3. 流式响应

支持流式输出,机器人的响应会分块发送,客户端可以实时显示部分响应内容。

### 4. 会话隔离

支持 `person` 和 `group` 两种会话类型,不同类型的会话消息历史互不影响。

### 5. 连接管理

- 自动追踪连接状态
- 记录最后活跃时间
- 支持连接统计查询
- 连接断开时自动清理资源

### 6. 心跳机制

客户端可以定期发送 `ping` 消息,服务器会响应 `pong`,用于保持连接活跃和检测连接状态。

## 架构优势

1. **高并发**: 使用 asyncio 异步架构,支持大量并发连接
2. **可扩展**: 模块化设计,易于扩展新功能
3. **线程安全**: 连接管理器使用锁机制保证并发安全
4. **消息队列**: 每个连接独立的发送队列,避免消息混乱
5. **灵活路由**: 支持按流水线、会话类型灵活路由消息

## 注意事项

1. **认证**: 当前 WebSocket 连接不需要认证,生产环境建议添加认证机制
2. **心跳**: 建议客户端实现心跳机制,避免连接超时
3. **重连**: 客户端应实现断线重连逻辑
4. **消息大小**: 注意控制单条消息大小,避免内存溢出
5. **连接数限制**: 生产环境建议设置最大连接数限制

## 故障排查

### 连接失败

1. 检查流水线 UUID 是否正确
2. 检查服务器是否正常运行
3. 检查防火墙设置

### 消息发送失败

1. 检查消息格式是否正确
2. 检查连接是否仍然活跃
3. 查看服务器日志获取详细错误信息

### 性能问题

1. 检查并发连接数是否过多
2. 检查消息处理速度
3. 考虑使用连接池或负载均衡

## 开发调试

启用详细日志:

```python
import logging
logging.getLogger('langbot.pkg.platform.sources.websocket_adapter').setLevel(logging.DEBUG)
logging.getLogger('langbot.pkg.platform.sources.websocket_manager').setLevel(logging.DEBUG)
logging.getLogger('langbot.pkg.api.http.controller.groups.pipelines.websocket_chat').setLevel(logging.DEBUG)
```

## 后续改进建议

1. 添加用户认证和授权机制
2. 实现消息持久化
3. 添加消息加密
4. 实现更丰富的消息类型 (图片、文件等)
5. 添加消息已读/未读状态
6. 实现群组聊天功能
7. 添加在线状态显示
8. 实现消息撤回功能


================================================
FILE: docs/service-api-openapi.json
================================================
{
  "openapi": "3.0.3",
  "info": {
    "title": "LangBot API with API Key Authentication",
    "description": "LangBot external service API documentation. These endpoints support API Key authentication \nfor external systems to programmatically access LangBot resources.\n\n**Authentication Methods:**\n- User Token (via `Authorization: Bearer <token>`)\n- API Key (via `X-API-Key: <key>` or `Authorization: Bearer <key>`)\n\nAll endpoints documented here accept BOTH authentication methods.\n",
    "version": "4.5.0",
    "contact": {
      "name": "LangBot",
      "url": "https://langbot.app"
    },
    "license": {
      "name": "Apache-2.0",
      "url": "https://github.com/langbot-app/LangBot/blob/master/LICENSE"
    }
  },
  "servers": [
    {
      "url": "http://localhost:5300",
      "description": "Local development server"
    }
  ],
  "tags": [
    {
      "name": "Models - LLM",
      "description": "Large Language Model management operations"
    },
    {
      "name": "Models - Embedding",
      "description": "Embedding model management operations"
    },
    {
      "name": "Bots",
      "description": "Bot instance management operations"
    },
    {
      "name": "Pipelines",
      "description": "Pipeline configuration management operations"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    },
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/api/v1/provider/models/llm": {
      "get": {
        "tags": [
          "Models - LLM"
        ],
        "summary": "List all LLM models",
        "description": "Retrieve a list of all configured LLM models",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "models": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/LLMModel"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      },
      "post": {
        "tags": [
          "Models - LLM"
        ],
        "summary": "Create a new LLM model",
        "description": "Create and configure a new LLM model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LLMModelCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Model created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid",
                          "example": "550e8400-e29b-41d4-a716-446655440000"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/provider/models/llm/{model_uuid}": {
      "get": {
        "tags": [
          "Models - LLM"
        ],
        "summary": "Get a specific LLM model",
        "description": "Retrieve details of a specific LLM model by UUID",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "model": {
                          "$ref": "#/components/schemas/LLMModel"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "put": {
        "tags": [
          "Models - LLM"
        ],
        "summary": "Update an LLM model",
        "description": "Update the configuration of an existing LLM model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LLMModelUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Model updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "delete": {
        "tags": [
          "Models - LLM"
        ],
        "summary": "Delete an LLM model",
        "description": "Remove an LLM model from the system",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Model deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/v1/provider/models/llm/{model_uuid}/test": {
      "post": {
        "tags": [
          "Models - LLM"
        ],
        "summary": "Test an LLM model",
        "description": "Test the connectivity and functionality of an LLM model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Model configuration to test"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Model test successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/provider/models/embedding": {
      "get": {
        "tags": [
          "Models - Embedding"
        ],
        "summary": "List all embedding models",
        "description": "Retrieve a list of all configured embedding models",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "models": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/EmbeddingModel"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      },
      "post": {
        "tags": [
          "Models - Embedding"
        ],
        "summary": "Create a new embedding model",
        "description": "Create and configure a new embedding model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmbeddingModelCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Model created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/v1/provider/models/embedding/{model_uuid}": {
      "get": {
        "tags": [
          "Models - Embedding"
        ],
        "summary": "Get a specific embedding model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "model": {
                          "$ref": "#/components/schemas/EmbeddingModel"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "put": {
        "tags": [
          "Models - Embedding"
        ],
        "summary": "Update an embedding model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmbeddingModelUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Model updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "delete": {
        "tags": [
          "Models - Embedding"
        ],
        "summary": "Delete an embedding model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Model deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/v1/provider/models/embedding/{model_uuid}/test": {
      "post": {
        "tags": [
          "Models - Embedding"
        ],
        "summary": "Test an embedding model",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ModelUUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Model test successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/v1/platform/bots": {
      "get": {
        "tags": [
          "Bots"
        ],
        "summary": "List all bots",
        "description": "Retrieve a list of all configured bot instances",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "bots": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Bot"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      },
      "post": {
        "tags": [
          "Bots"
        ],
        "summary": "Create a new bot",
        "description": "Create and configure a new bot instance",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BotCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bot created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "uuid": {
                          "type": "string",
                          "format": "uuid"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/v1/platform/bots/{bot_uuid}": {
      "get": {
        "tags": [
          "Bots"
        ],
        "summary": "Get a specific bot",
        "description": "Retrieve details of a specific bot instance",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bot_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Bot UUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "bot": {
                          "$ref": "#/components/schemas/Bot"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "put": {
        "tags": [
          "Bots"
        ],
        "summary": "Update a bot",
        "description": "Update the configuration of an existing bot instance",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bot_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BotUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bot updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "delete": {
        "tags": [
          "Bots"
        ],
        "summary": "Delete a bot",
        "description": "Remove a bot instance from the system",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bot_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bot deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/v1/platform/bots/{bot_uuid}/logs": {
      "post": {
        "tags": [
          "Bots"
        ],
        "summary": "Get bot event logs",
        "description": "Retrieve event logs for a specific bot",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "bot_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "from_index": {
                    "type": "integer",
                    "default": -1,
                    "description": "Starting index for logs (-1 for latest)"
                  },
                  "max_count": {
                    "type": "integer",
                    "default": 10,
                    "description": "Maximum number of logs to retrieve"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "logs": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "total_count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/v1/pipelines": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "List all pipelines",
        "description": "Retrieve a list of all configured pipelines",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sort_by",
            "in": "query",
            "schema": {
              "type": "string",
              "default": "created_at"
            },
            "description": "Field to sort by"
          },
          {
            "name": "sort_order",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ASC",
                "DESC"
              ],
              "default": "DESC"
            },
            "description": "Sort order"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "pipelines": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Pipeline"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      },
      "post": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Create a new pipeline",
        "description": "Create and configure a new pipeline",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PipelineCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pipeline created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "example": 0
                    },
                    "msg": {
                      "type": "string",
                      "example": "ok"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "uuid": {
                          "type": "string",
       
Download .txt
gitextract_n8yk_ve4/

├── .dockerignore
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report.yml
│   │   ├── bug-report_en.yml
│   │   ├── feature-request.yml
│   │   ├── feature-request_en.yml
│   │   ├── submit-plugin.yml
│   │   └── submit-plugin_en.yml
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── build-dev-image.yaml
│       ├── build-docker-image.yml
│       ├── build-release-artifacts.yaml
│       ├── lint.yml
│       ├── publish-to-pypi.yml
│       ├── run-tests.yml
│       └── test-dev-image.yaml
├── .gitignore
├── .mcp.json
├── .pre-commit-config.yaml
├── AGENTS.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── README.md
├── README_CN.md
├── README_ES.md
├── README_FR.md
├── README_JP.md
├── README_KO.md
├── README_RU.md
├── README_TW.md
├── README_VI.md
├── codecov.yml
├── docker/
│   ├── README_K8S.md
│   ├── deploy-k8s-test.sh
│   ├── docker-compose.yaml
│   └── kubernetes.yaml
├── docs/
│   ├── API_KEY_AUTH.md
│   ├── MIGRATION_SUMMARY.md
│   ├── PYPI_INSTALLATION.md
│   ├── SEEKDB_INTEGRATION.md
│   ├── TESTING_SUMMARY.md
│   ├── WEBSOCKET_README.md
│   └── service-api-openapi.json
├── main.py
├── pyproject.toml
├── pytest.ini
├── res/
│   ├── announcement.json
│   ├── announcement_saved.json
│   ├── instance_id.json
│   └── scripts/
│       └── publish_announcement.py
├── run_tests.sh
├── src/
│   └── langbot/
│       ├── __init__.py
│       ├── __main__.py
│       ├── libs/
│       │   ├── LICENSE
│       │   ├── README.md
│       │   ├── coze_server_api/
│       │   │   ├── __init__.py
│       │   │   └── client.py
│       │   ├── dify_service_api/
│       │   │   ├── README.md
│       │   │   ├── __init__.py
│       │   │   └── v1/
│       │   │       ├── __init__.py
│       │   │       ├── client.py
│       │   │       ├── client_test.py
│       │   │       └── errors.py
│       │   ├── dingtalk_api/
│       │   │   ├── EchoHandler.py
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── dingtalkevent.py
│       │   ├── official_account_api/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── oaevent.py
│       │   ├── qq_official_api/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── qqofficialevent.py
│       │   ├── slack_api/
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   └── slackevent.py
│       │   ├── wechatpad_api/
│       │   │   ├── LICENSE
│       │   │   ├── README.md
│       │   │   ├── __init__.py
│       │   │   ├── api/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── chatroom.py
│       │   │   │   ├── downloadpai.py
│       │   │   │   ├── friend.py
│       │   │   │   ├── login.py
│       │   │   │   ├── message.py
│       │   │   │   └── user.py
│       │   │   ├── client.py
│       │   │   └── util/
│       │   │       ├── __init__.py
│       │   │       ├── http_util.py
│       │   │       └── terminal_printer.py
│       │   ├── wecom_ai_bot_api/
│       │   │   ├── WXBizMsgCrypt3.py
│       │   │   ├── api.py
│       │   │   ├── ierror.py
│       │   │   ├── wecombotevent.py
│       │   │   └── ws_client.py
│       │   ├── wecom_api/
│       │   │   ├── WXBizMsgCrypt3.py
│       │   │   ├── __init__.py
│       │   │   ├── api.py
│       │   │   ├── ierror.py
│       │   │   └── wecomevent.py
│       │   └── wecom_customer_service_api/
│       │       ├── __init__.py
│       │       ├── api.py
│       │       └── wecomcsevent.py
│       ├── pkg/
│       │   ├── __init__.py
│       │   ├── api/
│       │   │   ├── __init__.py
│       │   │   └── http/
│       │   │       ├── __init__.py
│       │   │       ├── controller/
│       │   │       │   ├── __init__.py
│       │   │       │   ├── group.py
│       │   │       │   ├── groups/
│       │   │       │   │   ├── __init__.py
│       │   │       │   │   ├── apikeys.py
│       │   │       │   │   ├── files.py
│       │   │       │   │   ├── knowledge/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── base.py
│       │   │       │   │   │   ├── engines.py
│       │   │       │   │   │   ├── migration.py
│       │   │       │   │   │   └── parsers.py
│       │   │       │   │   ├── logs.py
│       │   │       │   │   ├── monitoring.py
│       │   │       │   │   ├── pipelines/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── pipelines.py
│       │   │       │   │   │   └── websocket_chat.py
│       │   │       │   │   ├── platform/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── adapters.py
│       │   │       │   │   │   └── bots.py
│       │   │       │   │   ├── plugins.py
│       │   │       │   │   ├── provider/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   ├── models.py
│       │   │       │   │   │   ├── providers.py
│       │   │       │   │   │   └── requesters.py
│       │   │       │   │   ├── resources/
│       │   │       │   │   │   ├── __init__.py
│       │   │       │   │   │   └── mcp.py
│       │   │       │   │   ├── stats.py
│       │   │       │   │   ├── survey.py
│       │   │       │   │   ├── system.py
│       │   │       │   │   ├── user.py
│       │   │       │   │   ├── webhook_mgmt.py
│       │   │       │   │   └── webhooks.py
│       │   │       │   └── main.py
│       │   │       └── service/
│       │   │           ├── __init__.py
│       │   │           ├── apikey.py
│       │   │           ├── bot.py
│       │   │           ├── knowledge.py
│       │   │           ├── mcp.py
│       │   │           ├── model.py
│       │   │           ├── monitoring.py
│       │   │           ├── pipeline.py
│       │   │           ├── provider.py
│       │   │           ├── space.py
│       │   │           ├── user.py
│       │   │           └── webhook.py
│       │   ├── command/
│       │   │   ├── __init__.py
│       │   │   ├── cmdmgr.py
│       │   │   ├── operator.py
│       │   │   └── operators/
│       │   │       ├── __init__.py
│       │   │       ├── delc.py
│       │   │       ├── last.py
│       │   │       ├── list.py
│       │   │       ├── next.py
│       │   │       ├── prompt.py
│       │   │       └── resend.py
│       │   ├── config/
│       │   │   ├── __init__.py
│       │   │   ├── impls/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── json.py
│       │   │   │   ├── pymodule.py
│       │   │   │   └── yaml.py
│       │   │   ├── manager.py
│       │   │   └── model.py
│       │   ├── core/
│       │   │   ├── __init__.py
│       │   │   ├── app.py
│       │   │   ├── boot.py
│       │   │   ├── bootutils/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── config.py
│       │   │   │   ├── deps.py
│       │   │   │   ├── files.py
│       │   │   │   └── log.py
│       │   │   ├── entities.py
│       │   │   ├── migration.py
│       │   │   ├── migrations/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── m001_sensitive_word_migration.py
│       │   │   │   ├── m002_openai_config_migration.py
│       │   │   │   ├── m003_anthropic_requester_cfg_completion.py
│       │   │   │   ├── m004_moonshot_cfg_completion.py
│       │   │   │   ├── m005_deepseek_cfg_completion.py
│       │   │   │   ├── m006_vision_config.py
│       │   │   │   ├── m007_qcg_center_url.py
│       │   │   │   ├── m008_ad_fixwin_config_migrate.py
│       │   │   │   ├── m009_msg_truncator_cfg.py
│       │   │   │   ├── m010_ollama_requester_config.py
│       │   │   │   ├── m011_command_prefix_config.py
│       │   │   │   ├── m012_runner_config.py
│       │   │   │   ├── m013_http_api_config.py
│       │   │   │   ├── m014_force_delay_config.py
│       │   │   │   ├── m015_gitee_ai_config.py
│       │   │   │   ├── m016_dify_service_api.py
│       │   │   │   ├── m017_dify_api_timeout_params.py
│       │   │   │   ├── m018_xai_config.py
│       │   │   │   ├── m019_zhipuai_config.py
│       │   │   │   ├── m020_wecom_config.py
│       │   │   │   ├── m021_lark_config.py
│       │   │   │   ├── m022_lmstudio_config.py
│       │   │   │   ├── m023_siliconflow_config.py
│       │   │   │   ├── m024_discord_config.py
│       │   │   │   ├── m025_gewechat_config.py
│       │   │   │   ├── m026_qqofficial_config.py
│       │   │   │   ├── m027_wx_official_account_config.py
│       │   │   │   ├── m028_aliyun_requester_config.py
│       │   │   │   ├── m029_dashscope_app_api_config.py
│       │   │   │   ├── m030_lark_config_cmpl.py
│       │   │   │   ├── m031_dingtalk_config.py
│       │   │   │   ├── m032_volcark_config.py
│       │   │   │   ├── m033_dify_thinking_config.py
│       │   │   │   ├── m034_gewechat_file_url_config.py
│       │   │   │   ├── m035_wxoa_mode.py
│       │   │   │   ├── m036_wxoa_loading_message.py
│       │   │   │   ├── m037_mcp_config.py
│       │   │   │   ├── m038_tg_dingtalk_markdown.py
│       │   │   │   ├── m039_modelscope_cfg_completion.py
│       │   │   │   ├── m040_ppio_config.py
│       │   │   │   └── m041_dingtalk_card_autolayout_config.py
│       │   │   ├── note.py
│       │   │   ├── notes/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── n001_classic_msgs.py
│       │   │   │   ├── n002_selection_mode_on_windows.py
│       │   │   │   └── n003_print_version.py
│       │   │   ├── stage.py
│       │   │   ├── stages/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── build_app.py
│       │   │   │   ├── genkeys.py
│       │   │   │   ├── load_config.py
│       │   │   │   ├── migrate.py
│       │   │   │   ├── setup_logger.py
│       │   │   │   └── show_notes.py
│       │   │   └── taskmgr.py
│       │   ├── discover/
│       │   │   ├── __init__.py
│       │   │   └── engine.py
│       │   ├── entity/
│       │   │   ├── __init__.py
│       │   │   ├── dto/
│       │   │   │   ├── __init__.py
│       │   │   │   └── space_model.py
│       │   │   ├── errors/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── account.py
│       │   │   │   ├── platform.py
│       │   │   │   └── provider.py
│       │   │   └── persistence/
│       │   │       ├── __init__.py
│       │   │       ├── apikey.py
│       │   │       ├── base.py
│       │   │       ├── bot.py
│       │   │       ├── bstorage.py
│       │   │       ├── mcp.py
│       │   │       ├── metadata.py
│       │   │       ├── model.py
│       │   │       ├── monitoring.py
│       │   │       ├── pipeline.py
│       │   │       ├── plugin.py
│       │   │       ├── rag.py
│       │   │       ├── user.py
│       │   │       ├── vector.py
│       │   │       └── webhook.py
│       │   ├── persistence/
│       │   │   ├── __init__.py
│       │   │   ├── database.py
│       │   │   ├── databases/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── postgresql.py
│       │   │   │   └── sqlite.py
│       │   │   ├── mgr.py
│       │   │   ├── migration.py
│       │   │   └── migrations/
│       │   │       ├── __init__.py
│       │   │       ├── dbm001_migrate_v3_config.py
│       │   │       ├── dbm002_combine_quote_msg_config.py
│       │   │       ├── dbm003_n8n_config.py
│       │   │       ├── dbm004_rag_kb_uuid.py
│       │   │       ├── dbm005_pipeline_remove_cot_config.py
│       │   │       ├── dbm006_langflow_api_config.py
│       │   │       ├── dbm007_plugin_install_source.py
│       │   │       ├── dbm008_plugin_config.py
│       │   │       ├── dbm009_pipeline_extension_preferences.py
│       │   │       ├── dbm010_pipeline_multi_knowledge_base.py
│       │   │       ├── dbm011_dify_base_prompt_config.py
│       │   │       ├── dbm012_pipeline_extensions_enable_all.py
│       │   │       ├── dbm013_knowledge_base_updated_at.py
│       │   │       ├── dbm014_space_account_support.py
│       │   │       ├── dbm015_model_source_tracking.py
│       │   │       ├── dbm016_model_provider_refactor.py
│       │   │       ├── dbm017_move_cloud_service_url.py
│       │   │       ├── dbm018_add_emoji_support.py
│       │   │       ├── dbm019_monitoring_message_role.py
│       │   │       ├── dbm020_knowledge_engine_plugin_architecture.py
│       │   │       ├── dbm021_merge_exception_handling.py
│       │   │       ├── dbm022_monitoring_user_name.py
│       │   │       ├── dbm023_model_fallback_config.py
│       │   │       └── dbm024_wecombot_websocket_mode.py
│       │   ├── pipeline/
│       │   │   ├── __init__.py
│       │   │   ├── aggregator.py
│       │   │   ├── bansess/
│       │   │   │   ├── __init__.py
│       │   │   │   └── bansess.py
│       │   │   ├── cntfilter/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── cntfilter.py
│       │   │   │   ├── entities.py
│       │   │   │   ├── filter.py
│       │   │   │   └── filters/
│       │   │   │       ├── __init__.py
│       │   │   │       ├── baiduexamine.py
│       │   │   │       ├── banwords.py
│       │   │   │       └── cntignore.py
│       │   │   ├── config_coercion.py
│       │   │   ├── controller.py
│       │   │   ├── entities.py
│       │   │   ├── longtext/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── longtext.py
│       │   │   │   ├── strategies/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── forward.py
│       │   │   │   │   └── image.py
│       │   │   │   └── strategy.py
│       │   │   ├── monitoring_helper.py
│       │   │   ├── msgtrun/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── msgtrun.py
│       │   │   │   ├── truncator.py
│       │   │   │   └── truncators/
│       │   │   │       ├── __init__.py
│       │   │   │       └── round.py
│       │   │   ├── pipelinemgr.py
│       │   │   ├── pool.py
│       │   │   ├── preproc/
│       │   │   │   ├── __init__.py
│       │   │   │   └── preproc.py
│       │   │   ├── process/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── handler.py
│       │   │   │   ├── handlers/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── chat.py
│       │   │   │   │   └── command.py
│       │   │   │   └── process.py
│       │   │   ├── ratelimit/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── algo.py
│       │   │   │   ├── algos/
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   └── fixedwin.py
│       │   │   │   └── ratelimit.py
│       │   │   ├── respback/
│       │   │   │   ├── __init__.py
│       │   │   │   └── respback.py
│       │   │   ├── resprule/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── entities.py
│       │   │   │   ├── resprule.py
│       │   │   │   ├── rule.py
│       │   │   │   └── rules/
│       │   │   │       ├── __init__.py
│       │   │   │       ├── atbot.py
│       │   │   │       ├── prefix.py
│       │   │   │       ├── random.py
│       │   │   │       └── regexp.py
│       │   │   ├── stage.py
│       │   │   └── wrapper/
│       │   │       ├── __init__.py
│       │   │       └── wrapper.py
│       │   ├── platform/
│       │   │   ├── __init__.py
│       │   │   ├── botmgr.py
│       │   │   ├── logger.py
│       │   │   ├── sources/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── aiocqhttp.py
│       │   │   │   ├── aiocqhttp.yaml
│       │   │   │   ├── dingtalk.py
│       │   │   │   ├── dingtalk.yaml
│       │   │   │   ├── discord.py
│       │   │   │   ├── discord.yaml
│       │   │   │   ├── kook.py
│       │   │   │   ├── kook.yaml
│       │   │   │   ├── lark.py
│       │   │   │   ├── lark.yaml
│       │   │   │   ├── legacy/
│       │   │   │   │   ├── gewechat.py
│       │   │   │   │   ├── gewechat.yaml
│       │   │   │   │   ├── nakuru.py
│       │   │   │   │   ├── nakuru.yaml
│       │   │   │   │   ├── qqbotpy.py
│       │   │   │   │   └── qqbotpy.yaml
│       │   │   │   ├── line.py
│       │   │   │   ├── line.yaml
│       │   │   │   ├── officialaccount.py
│       │   │   │   ├── officialaccount.yaml
│       │   │   │   ├── qqofficial.py
│       │   │   │   ├── qqofficial.yaml
│       │   │   │   ├── satori.py
│       │   │   │   ├── satori.yaml
│       │   │   │   ├── slack.py
│       │   │   │   ├── slack.yaml
│       │   │   │   ├── telegram.py
│       │   │   │   ├── telegram.yaml
│       │   │   │   ├── websocket.yaml
│       │   │   │   ├── websocket_adapter.py
│       │   │   │   ├── websocket_manager.py
│       │   │   │   ├── wechatpad.py
│       │   │   │   ├── wechatpad.yaml
│       │   │   │   ├── wecom.py
│       │   │   │   ├── wecom.yaml
│       │   │   │   ├── wecombot.py
│       │   │   │   ├── wecombot.yaml
│       │   │   │   ├── wecomcs.py
│       │   │   │   └── wecomcs.yaml
│       │   │   └── webhook_pusher.py
│       │   ├── plugin/
│       │   │   ├── __init__.py
│       │   │   ├── connector.py
│       │   │   └── handler.py
│       │   ├── provider/
│       │   │   ├── __init__.py
│       │   │   ├── modelmgr/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── entities.py
│       │   │   │   ├── errors.py
│       │   │   │   ├── modelmgr.py
│       │   │   │   ├── requester.py
│       │   │   │   ├── requester.yaml
│       │   │   │   ├── requesters/
│       │   │   │   │   ├── 302aichatcmpl.py
│       │   │   │   │   ├── 302aichatcmpl.yaml
│       │   │   │   │   ├── __init__.py
│       │   │   │   │   ├── anthropicmsgs.py
│       │   │   │   │   ├── anthropicmsgs.yaml
│       │   │   │   │   ├── bailianchatcmpl.py
│       │   │   │   │   ├── bailianchatcmpl.yaml
│       │   │   │   │   ├── chatcmpl.py
│       │   │   │   │   ├── chatcmpl.yaml
│       │   │   │   │   ├── compsharechatcmpl.py
│       │   │   │   │   ├── compsharechatcmpl.yaml
│       │   │   │   │   ├── deepseekchatcmpl.py
│       │   │   │   │   ├── deepseekchatcmpl.yaml
│       │   │   │   │   ├── geminichatcmpl.py
│       │   │   │   │   ├── geminichatcmpl.yaml
│       │   │   │   │   ├── giteeaichatcmpl.py
│       │   │   │   │   ├── giteeaichatcmpl.yaml
│       │   │   │   │   ├── jiekouaichatcmpl.py
│       │   │   │   │   ├── jiekouaichatcmpl.yaml
│       │   │   │   │   ├── lmstudiochatcmpl.py
│       │   │   │   │   ├── lmstudiochatcmpl.yaml
│       │   │   │   │   ├── modelscopechatcmpl.py
│       │   │   │   │   ├── modelscopechatcmpl.yaml
│       │   │   │   │   ├── moonshotchatcmpl.py
│       │   │   │   │   ├── moonshotchatcmpl.yaml
│       │   │   │   │   ├── newapichatcmpl.py
│       │   │   │   │   ├── newapichatcmpl.yaml
│       │   │   │   │   ├── ollamachat.py
│       │   │   │   │   ├── ollamachat.yaml
│       │   │   │   │   ├── openrouterchatcmpl.py
│       │   │   │   │   ├── openrouterchatcmpl.yaml
│       │   │   │   │   ├── ppiochatcmpl.py
│       │   │   │   │   ├── ppiochatcmpl.yaml
│       │   │   │   │   ├── qhaigcchatcmpl.py
│       │   │   │   │   ├── qhaigcchatcmpl.yaml
│       │   │   │   │   ├── seekdbembed.py
│       │   │   │   │   ├── seekdbembed.yaml
│       │   │   │   │   ├── shengsuanyun.py
│       │   │   │   │   ├── shengsuanyun.yaml
│       │   │   │   │   ├── siliconflowchatcmpl.py
│       │   │   │   │   ├── siliconflowchatcmpl.yaml
│       │   │   │   │   ├── spacechatcmpl.py
│       │   │   │   │   ├── spacechatcmpl.yaml
│       │   │   │   │   ├── tokenpony.yaml
│       │   │   │   │   ├── tokenponychatcmpl.py
│       │   │   │   │   ├── volcarkchatcmpl.py
│       │   │   │   │   ├── volcarkchatcmpl.yaml
│       │   │   │   │   ├── xaichatcmpl.py
│       │   │   │   │   ├── xaichatcmpl.yaml
│       │   │   │   │   ├── zhipuaichatcmpl.py
│       │   │   │   │   └── zhipuaichatcmpl.yaml
│       │   │   │   └── token.py
│       │   │   ├── runner.py
│       │   │   ├── runners/
│       │   │   │   ├── __init__.py
│       │   │   │   ├── cozeapi.py
│       │   │   │   ├── dashscopeapi.py
│       │   │   │   ├── difysvapi.py
│       │   │   │   ├── langflowapi.py
│       │   │   │   ├── localagent.py
│       │   │   │   ├── n8nsvapi.py
│       │   │   │   └── tboxapi.py
│       │   │   ├── session/
│       │   │   │   ├── __init__.py
│       │   │   │   └── sessionmgr.py
│       │   │   └── tools/
│       │   │       ├── __init__.py
│       │   │       ├── loader.py
│       │   │       ├── loaders/
│       │   │       │   ├── __init__.py
│       │   │       │   ├── mcp.py
│       │   │       │   └── plugin.py
│       │   │       └── toolmgr.py
│       │   ├── rag/
│       │   │   ├── knowledge/
│       │   │   │   ├── base.py
│       │   │   │   └── kbmgr.py
│       │   │   └── service/
│       │   │       ├── __init__.py
│       │   │       └── runtime.py
│       │   ├── storage/
│       │   │   ├── __init__.py
│       │   │   ├── mgr.py
│       │   │   ├── provider.py
│       │   │   └── providers/
│       │   │       ├── __init__.py
│       │   │       ├── localstorage.py
│       │   │       └── s3storage.py
│       │   ├── survey/
│       │   │   ├── __init__.py
│       │   │   └── manager.py
│       │   ├── telemetry/
│       │   │   ├── __init__.py
│       │   │   └── telemetry.py
│       │   ├── utils/
│       │   │   ├── __init__.py
│       │   │   ├── constants.py
│       │   │   ├── funcschema.py
│       │   │   ├── httpclient.py
│       │   │   ├── image.py
│       │   │   ├── importutil.py
│       │   │   ├── logcache.py
│       │   │   ├── paths.py
│       │   │   ├── pkgmgr.py
│       │   │   ├── platform.py
│       │   │   ├── proxy.py
│       │   │   ├── runner.py
│       │   │   └── version.py
│       │   └── vector/
│       │       ├── __init__.py
│       │       ├── filter_utils.py
│       │       ├── mgr.py
│       │       ├── vdb.py
│       │       └── vdbs/
│       │           ├── __init__.py
│       │           ├── chroma.py
│       │           ├── milvus.py
│       │           ├── pgvector_db.py
│       │           ├── qdrant.py
│       │           └── seekdb.py
│       └── templates/
│           ├── __init__.py
│           ├── components.yaml
│           ├── config.yaml
│           ├── default-pipeline-config.json
│           ├── legacy/
│           │   ├── command.json
│           │   ├── pipeline.json
│           │   ├── platform.json
│           │   ├── provider.json
│           │   └── system.json
│           └── metadata/
│               ├── pipeline/
│               │   ├── ai.yaml
│               │   ├── output.yaml
│               │   ├── safety.yaml
│               │   └── trigger.yaml
│               └── sensitive-words.json
├── tests/
│   ├── README.md
│   ├── __init__.py
│   └── unit_tests/
│       ├── __init__.py
│       ├── config/
│       │   ├── __init__.py
│       │   ├── test_env_override.py
│       │   └── test_webhook_display_prefix.py
│       ├── pipeline/
│       │   ├── __init__.py
│       │   ├── conftest.py
│       │   ├── test_bansess.py
│       │   ├── test_config_coercion.py
│       │   ├── test_pipelinemgr.py
│       │   ├── test_ratelimit.py
│       │   ├── test_resprule.py
│       │   └── test_simple.py
│       ├── plugin/
│       │   ├── __init__.py
│       │   ├── test_plugin_component_filtering.py
│       │   └── test_plugin_list_sorting.py
│       └── storage/
│           ├── __init__.py
│           └── test_storage_provider_selection.py
└── web/
    ├── .env.example
    ├── .gitignore
    ├── .lintstagedrc.json
    ├── .prettierrc.mjs
    ├── README.md
    ├── components.json
    ├── eslint.config.mjs
    ├── next
    ├── next.config.ts
    ├── package.json
    ├── postcss.config.mjs
    ├── src/
    │   ├── app/
    │   │   ├── auth/
    │   │   │   └── space/
    │   │   │       └── callback/
    │   │   │           └── page.tsx
    │   │   ├── global.css
    │   │   ├── home/
    │   │   │   ├── bots/
    │   │   │   │   ├── BotDetailDialog.tsx
    │   │   │   │   ├── botConfig.module.css
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── bot-card/
    │   │   │   │   │   │   ├── BotCard.tsx
    │   │   │   │   │   │   ├── BotCardVO.ts
    │   │   │   │   │   │   └── botCard.module.css
    │   │   │   │   │   ├── bot-form/
    │   │   │   │   │   │   ├── BotForm.tsx
    │   │   │   │   │   │   └── ChooseEntity.ts
    │   │   │   │   │   ├── bot-log/
    │   │   │   │   │   │   ├── BotLogManager.ts
    │   │   │   │   │   │   └── view/
    │   │   │   │   │   │       ├── BotLogCard.tsx
    │   │   │   │   │   │       ├── BotLogListComponent.tsx
    │   │   │   │   │   │       └── botLog.module.css
    │   │   │   │   │   └── bot-session/
    │   │   │   │   │       └── BotSessionMonitor.tsx
    │   │   │   │   └── page.tsx
    │   │   │   ├── components/
    │   │   │   │   ├── account-settings-dialog/
    │   │   │   │   │   └── AccountSettingsDialog.tsx
    │   │   │   │   ├── api-integration-dialog/
    │   │   │   │   │   └── ApiIntegrationDialog.tsx
    │   │   │   │   ├── dynamic-form/
    │   │   │   │   │   ├── DynamicFormComponent.tsx
    │   │   │   │   │   ├── DynamicFormItemComponent.tsx
    │   │   │   │   │   ├── DynamicFormItemConfig.ts
    │   │   │   │   │   └── N8nAuthFormComponent.tsx
    │   │   │   │   ├── home-sidebar/
    │   │   │   │   │   ├── HomeSidebar.module.css
    │   │   │   │   │   ├── HomeSidebar.tsx
    │   │   │   │   │   ├── HomeSidebarChild.tsx
    │   │   │   │   │   └── sidbarConfigList.tsx
    │   │   │   │   ├── home-titlebar/
    │   │   │   │   │   ├── HomeTitleBar.tsx
    │   │   │   │   │   └── HomeTittleBar.module.css
    │   │   │   │   ├── models-dialog/
    │   │   │   │   │   ├── ModelsDialog.tsx
    │   │   │   │   │   ├── component/
    │   │   │   │   │   │   └── provider-form/
    │   │   │   │   │   │       └── ProviderForm.tsx
    │   │   │   │   │   ├── components/
    │   │   │   │   │   │   ├── AddModelPopover.tsx
    │   │   │   │   │   │   ├── ExtraArgsEditor.tsx
    │   │   │   │   │   │   ├── ModelItem.tsx
    │   │   │   │   │   │   ├── ProviderCard.tsx
    │   │   │   │   │   │   └── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── new-version-dialog/
    │   │   │   │   │   └── NewVersionDialog.tsx
    │   │   │   │   ├── password-change-dialog/
    │   │   │   │   │   └── PasswordChangeDialog.tsx
    │   │   │   │   └── survey/
    │   │   │   │       └── SurveyWidget.tsx
    │   │   │   ├── knowledge/
    │   │   │   │   ├── KBDetailDialog.tsx
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── kb-card/
    │   │   │   │   │   │   ├── KBCard.module.css
    │   │   │   │   │   │   ├── KBCard.tsx
    │   │   │   │   │   │   └── KBCardVO.ts
    │   │   │   │   │   ├── kb-docs/
    │   │   │   │   │   │   ├── FileUploadZone.tsx
    │   │   │   │   │   │   ├── KBDoc.tsx
    │   │   │   │   │   │   └── documents/
    │   │   │   │   │   │       ├── columns.tsx
    │   │   │   │   │   │       └── data-table.tsx
    │   │   │   │   │   ├── kb-form/
    │   │   │   │   │   │   ├── ChooseEntity.ts
    │   │   │   │   │   │   └── KBForm.tsx
    │   │   │   │   │   ├── kb-migration-dialog/
    │   │   │   │   │   │   └── KBMigrationDialog.tsx
    │   │   │   │   │   └── kb-retrieve/
    │   │   │   │   │       └── KBRetrieveGeneric.tsx
    │   │   │   │   ├── knowledgeBase.module.css
    │   │   │   │   └── page.tsx
    │   │   │   ├── layout.module.css
    │   │   │   ├── layout.tsx
    │   │   │   ├── loading.tsx
    │   │   │   ├── monitoring/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── ExportDropdown.tsx
    │   │   │   │   │   ├── MessageContentRenderer.tsx
    │   │   │   │   │   ├── MessageDetailsCard.tsx
    │   │   │   │   │   ├── filters/
    │   │   │   │   │   │   └── MonitoringFilters.tsx
    │   │   │   │   │   └── overview-cards/
    │   │   │   │   │       ├── MetricCard.tsx
    │   │   │   │   │       ├── OverviewCards.tsx
    │   │   │   │   │       └── TrafficChart.tsx
    │   │   │   │   ├── hooks/
    │   │   │   │   │   ├── useMonitoringData.ts
    │   │   │   │   │   └── useMonitoringFilters.ts
    │   │   │   │   ├── page.tsx
    │   │   │   │   ├── types/
    │   │   │   │   │   └── monitoring.ts
    │   │   │   │   └── utils/
    │   │   │   │       └── dateUtils.ts
    │   │   │   ├── page.tsx
    │   │   │   ├── pipelines/
    │   │   │   │   ├── PipelineDetailDialog.tsx
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── debug-dialog/
    │   │   │   │   │   │   ├── AtBadge.tsx
    │   │   │   │   │   │   ├── DebugDialog.tsx
    │   │   │   │   │   │   └── ImagePreviewDialog.tsx
    │   │   │   │   │   ├── monitoring-tab/
    │   │   │   │   │   │   └── PipelineMonitoringTab.tsx
    │   │   │   │   │   ├── pipeline-card/
    │   │   │   │   │   │   ├── PipelineCard.tsx
    │   │   │   │   │   │   ├── PipelineCardVO.ts
    │   │   │   │   │   │   └── pipelineCard.module.css
    │   │   │   │   │   ├── pipeline-extensions/
    │   │   │   │   │   │   └── PipelineExtension.tsx
    │   │   │   │   │   └── pipeline-form/
    │   │   │   │   │       ├── PipelineFormComponent.tsx
    │   │   │   │   │       └── pipelineFormStyle.module.css
    │   │   │   │   ├── page.tsx
    │   │   │   │   └── pipelineConfig.module.css
    │   │   │   └── plugins/
    │   │   │       ├── components/
    │   │   │       │   ├── plugin-installed/
    │   │   │       │   │   ├── PluginCardVO.ts
    │   │   │       │   │   ├── PluginComponentList.tsx
    │   │   │       │   │   ├── PluginInstalledComponent.tsx
    │   │   │       │   │   ├── plugin-card/
    │   │   │       │   │   │   └── PluginCardComponent.tsx
    │   │   │       │   │   ├── plugin-form/
    │   │   │       │   │   │   └── PluginForm.tsx
    │   │   │       │   │   └── plugin-readme/
    │   │   │       │   │       └── PluginReadme.tsx
    │   │   │       │   └── plugin-market/
    │   │   │       │       ├── PluginMarketComponent.tsx
    │   │   │       │       ├── RecommendationLists.tsx
    │   │   │       │       ├── TagsFilter.tsx
    │   │   │       │       └── plugin-market-card/
    │   │   │       │           ├── PluginMarketCardComponent.tsx
    │   │   │       │           └── PluginMarketCardVO.ts
    │   │   │       ├── mcp-server/
    │   │   │       │   ├── MCPCardVO.ts
    │   │   │       │   ├── MCPServerComponent.tsx
    │   │   │       │   ├── mcp-card/
    │   │   │       │   │   └── MCPCardComponent.tsx
    │   │   │       │   └── mcp-form/
    │   │   │       │       ├── MCPDeleteConfirmDialog.tsx
    │   │   │       │       └── MCPFormDialog.tsx
    │   │   │       ├── page.tsx
    │   │   │       └── plugins.module.css
    │   │   ├── infra/
    │   │   │   ├── basic-component/
    │   │   │   │   └── create-card-component/
    │   │   │   │       ├── CreateCardComponent.tsx
    │   │   │   │       └── createCartComponent.module.css
    │   │   │   ├── entities/
    │   │   │   │   ├── api/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── common.ts
    │   │   │   │   ├── form/
    │   │   │   │   │   └── dynamic.ts
    │   │   │   │   ├── message/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── pipeline/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── plugin/
    │   │   │   │       └── index.ts
    │   │   │   ├── http/
    │   │   │   │   ├── BackendClient.ts
    │   │   │   │   ├── BaseHttpClient.ts
    │   │   │   │   ├── CloudServiceClient.ts
    │   │   │   │   ├── HttpClient.ts
    │   │   │   │   ├── README.md
    │   │   │   │   ├── index.ts
    │   │   │   │   └── requestParam/
    │   │   │   │       └── bots/
    │   │   │   │           ├── GetBotLogsRequest.ts
    │   │   │   │           └── GetBotLogsResponse.ts
    │   │   │   └── websocket/
    │   │   │       └── WebSocketClient.ts
    │   │   ├── layout.tsx
    │   │   ├── login/
    │   │   │   ├── layout.tsx
    │   │   │   └── page.tsx
    │   │   ├── page.tsx
    │   │   ├── register/
    │   │   │   ├── layout.tsx
    │   │   │   └── page.tsx
    │   │   ├── reset-password/
    │   │   │   ├── layout.tsx
    │   │   │   └── page.tsx
    │   │   └── utils/
    │   │       └── versionCompare.ts
    │   ├── components/
    │   │   ├── providers/
    │   │   │   └── theme-provider.tsx
    │   │   └── ui/
    │   │       ├── alert-dialog.tsx
    │   │       ├── alert.tsx
    │   │       ├── badge.tsx
    │   │       ├── breadcrumb.tsx
    │   │       ├── button.tsx
    │   │       ├── card.tsx
    │   │       ├── checkbox.tsx
    │   │       ├── collapsible.tsx
    │   │       ├── context-menu.tsx
    │   │       ├── dialog.tsx
    │   │       ├── dropdown-menu.tsx
    │   │       ├── emoji-picker.tsx
    │   │       ├── form.tsx
    │   │       ├── hover-card.tsx
    │   │       ├── input-otp.tsx
    │   │       ├── input.tsx
    │   │       ├── item.tsx
    │   │       ├── label.tsx
    │   │       ├── language-selector.tsx
    │   │       ├── loading-spinner.tsx
    │   │       ├── pagination.tsx
    │   │       ├── popover.tsx
    │   │       ├── scroll-area.tsx
    │   │       ├── select.tsx
    │   │       ├── separator.tsx
    │   │       ├── sheet.tsx
    │   │       ├── sidebar.tsx
    │   │       ├── skeleton.tsx
    │   │       ├── sonner.tsx
    │   │       ├── switch.tsx
    │   │       ├── table.tsx
    │   │       ├── tabs.tsx
    │   │       ├── textarea.tsx
    │   │       ├── theme-toggle.tsx
    │   │       ├── toggle-group.tsx
    │   │       ├── toggle.tsx
    │   │       └── tooltip.tsx
    │   ├── hooks/
    │   │   ├── use-mobile.ts
    │   │   └── useAsyncTask.ts
    │   ├── i18n/
    │   │   ├── I18nProvider.tsx
    │   │   ├── index.ts
    │   │   └── locales/
    │   │       ├── en-US.ts
    │   │       ├── ja-JP.ts
    │   │       ├── zh-Hans.ts
    │   │       └── zh-Hant.ts
    │   ├── i18next.d.ts
    │   ├── lib/
    │   │   └── utils.ts
    │   └── styles/
    │       └── github-markdown.css
    ├── tsconfig.json
    └── web@0.1.0
Download .txt
Showing preview only (271K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3023 symbols across 477 files)

FILE: src/langbot/__main__.py
  function main_entry (line 21) | async def main_entry(loop: asyncio.AbstractEventLoop):
  function main (line 78) | def main():

FILE: src/langbot/libs/coze_server_api/client.py
  class AsyncCozeAPIClient (line 10) | class AsyncCozeAPIClient:
    method __init__ (line 11) | def __init__(self, api_key: str, api_base: str = 'https://api.coze.cn'):
    method __aenter__ (line 16) | async def __aenter__(self):
    method __aexit__ (line 21) | async def __aexit__(self, exc_type, exc_val, exc_tb):
    method coze_session (line 25) | async def coze_session(self):
    method close (line 47) | async def close(self):
    method upload (line 53) | async def upload(
    method chat_messages (line 110) | async def chat_messages(

FILE: src/langbot/libs/dify_service_api/v1/client.py
  class AsyncDifyServiceClient (line 12) | class AsyncDifyServiceClient:
    method __init__ (line 18) | def __init__(
    method chat_messages (line 26) | async def chat_messages(
    method workflow_run (line 73) | async def workflow_run(
    method upload_file (line 112) | async def upload_file(

FILE: src/langbot/libs/dify_service_api/v1/client_test.py
  class TestDifyClient (line 8) | class TestDifyClient:
    method test_chat_messages (line 9) | async def test_chat_messages(self):

FILE: src/langbot/libs/dify_service_api/v1/errors.py
  class DifyAPIError (line 1) | class DifyAPIError(Exception):
    method __init__ (line 4) | def __init__(self, message: str):

FILE: src/langbot/libs/dingtalk_api/EchoHandler.py
  class EchoTextHandler (line 6) | class EchoTextHandler(dingtalk_stream.ChatbotHandler):
    method __init__ (line 7) | def __init__(self, client):
    method process (line 15) | async def process(self, callback: dingtalk_stream.CallbackMessage):
    method get_incoming_message (line 24) | async def get_incoming_message(self):

FILE: src/langbot/libs/dingtalk_api/api.py
  class DingTalkClient (line 15) | class DingTalkClient:
    method __init__ (line 16) | def __init__(
    method get_access_token (line 44) | async def get_access_token(self):
    method is_token_expired (line 59) | async def is_token_expired(self):
    method check_access_token (line 65) | async def check_access_token(self):
    method download_image (line 70) | async def download_image(self, download_code: str):
    method download_url_to_base64 (line 87) | async def download_url_to_base64(self, download_url):
    method get_audio_url (line 99) | async def get_audio_url(self, download_code: str):
    method get_file_url (line 117) | async def get_file_url(self, download_code: str):
    method update_incoming_message (line 135) | async def update_incoming_message(self, message):
    method send_message (line 143) | async def send_message(self, content: str, incoming_message, at: bool):
    method get_incoming_message (line 160) | async def get_incoming_message(self):
    method on_message (line 164) | def on_message(self, msg_type: str):
    method _handle_message (line 173) | async def _handle_message(self, event: DingTalkEvent):
    method get_message (line 185) | async def get_message(self, incoming_message: dingtalk_stream.chatbot....
    method send_proactive_message_to_one (line 297) | async def send_proactive_message_to_one(self, target_id: str, content:...
    method send_proactive_message_to_group (line 323) | async def send_proactive_message_to_group(self, target_id: str, conten...
    method create_and_card (line 349) | async def create_and_card(
    method send_card_message (line 369) | async def send_card_message(self, card_instance, card_instance_id: str...
    method start (line 391) | async def start(self):
    method _keepalive (line 440) | async def _keepalive(self, ws, ping_interval=60):
    method stop (line 449) | async def stop(self):

FILE: src/langbot/libs/dingtalk_api/dingtalkevent.py
  class DingTalkEvent (line 5) | class DingTalkEvent(dict):
    method from_payload (line 7) | def from_payload(payload: Dict[str, Any]) -> Optional['DingTalkEvent']:
    method content (line 15) | def content(self):
    method rich_content (line 19) | def rich_content(self):
    method incoming_message (line 23) | def incoming_message(self) -> Optional['dingtalk_stream.chatbot.Chatbo...
    method type (line 27) | def type(self):
    method picture (line 31) | def picture(self):
    method audio (line 35) | def audio(self):
    method file (line 39) | def file(self):
    method name (line 43) | def name(self):
    method conversation (line 47) | def conversation(self):
    method __getattr__ (line 50) | def __getattr__(self, key: str) -> Optional[Any]:
    method __setattr__ (line 62) | def __setattr__(self, key: str, value: Any) -> None:
    method __repr__ (line 72) | def __repr__(self) -> str:

FILE: src/langbot/libs/official_account_api/api.py
  class OAClient (line 25) | class OAClient:
    method __init__ (line 26) | def __init__(
    method handle_callback_request (line 62) | async def handle_callback_request(self):
    method handle_unified_webhook (line 66) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 77) | async def _handle_callback_internal(self, req):
    method get_message (line 158) | async def get_message(self, xml_msg: str):
    method run_task (line 172) | async def run_task(self, host: str, port: int, *args, **kwargs):
    method on_message (line 178) | def on_message(self, msg_type: str):
    method _handle_message (line 191) | async def _handle_message(self, event: OAEvent):
    method set_message (line 206) | async def set_message(self, msg_id: int, content: str):
  class OAClientForLongerResponse (line 210) | class OAClientForLongerResponse:
    method __init__ (line 211) | def __init__(
    method handle_callback_request (line 249) | async def handle_callback_request(self):
    method handle_unified_webhook (line 253) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 264) | async def _handle_callback_internal(self, req):
    method get_message (line 346) | async def get_message(self, xml_msg: str):
    method run_task (line 360) | async def run_task(self, host: str, port: int, *args, **kwargs):
    method on_message (line 366) | def on_message(self, msg_type: str):
    method _handle_message (line 379) | async def _handle_message(self, event: OAEvent):
    method set_message (line 389) | async def set_message(self, from_user: int, message_id: int, content: ...

FILE: src/langbot/libs/official_account_api/oaevent.py
  class OAEvent (line 4) | class OAEvent(dict):
    method from_payload (line 12) | def from_payload(payload: Dict[str, Any]) -> Optional['OAEvent']:
    method type (line 30) | def type(self) -> str:
    method picurl (line 40) | def picurl(self) -> str:
    method detail_type (line 47) | def detail_type(self) -> str:
    method name (line 61) | def name(self) -> str:
    method user_id (line 71) | def user_id(self) -> Optional[str]:
    method receiver_id (line 78) | def receiver_id(self) -> Optional[str]:
    method message_id (line 88) | def message_id(self) -> Optional[str]:
    method message (line 98) | def message(self) -> Optional[str]:
    method media_id (line 108) | def media_id(self) -> Optional[str]:
    method timestamp (line 118) | def timestamp(self) -> Optional[int]:
    method event_key (line 128) | def event_key(self) -> Optional[str]:
    method __getattr__ (line 137) | def __getattr__(self, key: str) -> Optional[Any]:
    method __setattr__ (line 149) | def __setattr__(self, key: str, value: Any) -> None:
    method __repr__ (line 159) | def __repr__(self) -> str:

FILE: src/langbot/libs/qq_official_api/api.py
  class QQOfficialClient (line 13) | class QQOfficialClient:
    method __init__ (line 14) | def __init__(self, secret: str, token: str, app_id: str, logger: None,...
    method check_access_token (line 36) | async def check_access_token(self):
    method get_access_token (line 42) | async def get_access_token(self):
    method handle_callback_request (line 66) | async def handle_callback_request(self):
    method handle_unified_webhook (line 70) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 81) | async def _handle_callback_internal(self, req):
    method run_task (line 118) | async def run_task(self, host: str, port: int, *args, **kwargs):
    method on_message (line 122) | def on_message(self, msg_type: str):
    method _handle_message (line 133) | async def _handle_message(self, event: QQOfficialEvent):
    method get_message (line 140) | async def get_message(self, msg: dict) -> Dict[str, Any]:
    method is_image (line 169) | async def is_image(self, attachment: dict) -> bool:
    method send_private_text_msg (line 174) | async def send_private_text_msg(self, user_openid: str, content: str, ...
    method send_group_text_msg (line 198) | async def send_group_text_msg(self, group_openid: str, content: str, m...
    method send_channle_group_text_msg (line 221) | async def send_channle_group_text_msg(self, channel_id: str, content: ...
    method send_channle_private_text_msg (line 244) | async def send_channle_private_text_msg(self, guild_id: str, content: ...
    method is_token_expired (line 267) | async def is_token_expired(self):
    method repeat_seed (line 273) | async def repeat_seed(self, bot_secret: str, target_size: int = 32) ->...
    method verify (line 279) | async def verify(self, validation_payload: dict):

FILE: src/langbot/libs/qq_official_api/qqofficialevent.py
  class QQOfficialEvent (line 4) | class QQOfficialEvent(dict):
    method from_payload (line 6) | def from_payload(payload: Dict[str, Any]) -> Optional['QQOfficialEvent']:
    method t (line 14) | def t(self) -> str:
    method user_openid (line 21) | def user_openid(self) -> str:
    method timestamp (line 28) | def timestamp(self) -> str:
    method d_author_id (line 35) | def d_author_id(self) -> str:
    method content (line 42) | def content(self) -> str:
    method d_id (line 49) | def d_id(self) -> str:
    method id (line 56) | def id(self) -> str:
    method channel_id (line 63) | def channel_id(self) -> str:
    method username (line 70) | def username(self) -> str:
    method guild_id (line 77) | def guild_id(self) -> str:
    method member_openid (line 84) | def member_openid(self) -> str:
    method attachments (line 91) | def attachments(self) -> str:
    method group_openid (line 101) | def group_openid(self) -> str:
    method content_type (line 108) | def content_type(self) -> str:

FILE: src/langbot/libs/slack_api/api.py
  class SlackClient (line 10) | class SlackClient:
    method __init__ (line 11) | def __init__(self, bot_token: str, signing_secret: str, logger: None, ...
    method handle_callback_request (line 30) | async def handle_callback_request(self):
    method handle_unified_webhook (line 34) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 45) | async def _handle_callback_internal(self, req):
    method _handle_message (line 82) | async def _handle_message(self, event: SlackEvent):
    method on_message (line 91) | def on_message(self, msg_type: str):
    method send_message_to_channel (line 102) | async def send_message_to_channel(self, text: str, channel_id: str):
    method send_message_to_one (line 112) | async def send_message_to_one(self, text: str, user_id: str):
    method run_task (line 123) | async def run_task(self, host: str, port: int, *args, **kwargs):

FILE: src/langbot/libs/slack_api/slackevent.py
  class SlackEvent (line 4) | class SlackEvent(dict):
    method from_payload (line 6) | def from_payload(payload: Dict[str, Any]) -> Optional['SlackEvent']:
    method text (line 14) | def text(self) -> str:
    method user_id (line 52) | def user_id(self) -> Optional[str]:
    method channel_id (line 56) | def channel_id(self) -> Optional[str]:
    method type (line 60) | def type(self) -> str:
    method message_id (line 65) | def message_id(self) -> str:
    method pic_url (line 69) | def pic_url(self) -> str:
    method sender_name (line 77) | def sender_name(self) -> str:
    method __getattr__ (line 80) | def __getattr__(self, key: str) -> Optional[Any]:
    method __setattr__ (line 83) | def __setattr__(self, key: str, value: Any) -> None:
    method __repr__ (line 86) | def __repr__(self) -> str:

FILE: src/langbot/libs/wechatpad_api/api/chatroom.py
  class ChatRoomApi (line 4) | class ChatRoomApi:
    method __init__ (line 5) | def __init__(self, base_url, token):
    method get_chatroom_member_detail (line 9) | def get_chatroom_member_detail(self, chatroom_name):

FILE: src/langbot/libs/wechatpad_api/api/downloadpai.py
  class DownloadApi (line 6) | class DownloadApi:
    method __init__ (line 7) | def __init__(self, base_url, token):
    method send_download (line 11) | def send_download(self, aeskey, file_type, file_url):
    method get_msg_voice (line 16) | def get_msg_voice(self, buf_id, length, new_msgid):
    method download_url_to_base64 (line 21) | async def download_url_to_base64(self, download_url):

FILE: src/langbot/libs/wechatpad_api/api/friend.py
  class FriendApi (line 1) | class FriendApi:
    method __init__ (line 4) | def __init__(self, base_url: str, token: str):

FILE: src/langbot/libs/wechatpad_api/api/login.py
  class LoginApi (line 4) | class LoginApi:
    method __init__ (line 5) | def __init__(self, base_url: str, token: str = None, admin_key: str = ...
    method get_token (line 17) | def get_token(self, admin_key, day: int = 365):
    method get_login_qr (line 23) | def get_login_qr(self, Proxy: str = ''):
    method get_login_status (line 57) | def get_login_status(self):
    method logout (line 62) | def logout(self):
    method wake_up_login (line 67) | def wake_up_login(self, Proxy: str = ''):
    method login (line 77) | def login(self, admin_key):

FILE: src/langbot/libs/wechatpad_api/api/message.py
  class MessageApi (line 4) | class MessageApi:
    method __init__ (line 5) | def __init__(self, base_url, token):
    method post_text (line 9) | def post_text(self, to_wxid, content, ats: list = []):
    method post_image (line 30) | def post_image(self, to_wxid, img_url, ats: list = []):
    method post_voice (line 41) | def post_voice(self, to_wxid, voice_data, voice_forma, voice_duration):
    method post_name_card (line 52) | def post_name_card(self, alias, to_wxid, nick_name, name_card_wxid, fl...
    method post_emoji (line 64) | def post_emoji(self, to_wxid, emoji_md5, emoji_size: int = 0):
    method post_app_msg (line 70) | def post_app_msg(self, to_wxid, xml_data, contenttype: int = 0):
    method revoke_msg (line 76) | def revoke_msg(self, to_wxid, msg_id, new_msg_id, create_time):

FILE: src/langbot/libs/wechatpad_api/api/user.py
  class UserApi (line 4) | class UserApi:
    method __init__ (line 5) | def __init__(self, base_url, token):
    method get_profile (line 9) | def get_profile(self):
    method get_qr_code (line 15) | def get_qr_code(self, recover: bool = True, style: int = 8):
    method get_safety_info (line 21) | def get_safety_info(self):
    method update_head_img (line 26) | async def update_head_img(self, head_img_base64):

FILE: src/langbot/libs/wechatpad_api/client.py
  class WeChatPadClient (line 9) | class WeChatPadClient:
    method __init__ (line 10) | def __init__(self, base_url, token, logger=None):
    method get_token (line 19) | def get_token(self, admin_key, day: int):
    method get_login_qr (line 23) | def get_login_qr(self, Proxy: str = ''):
    method awaken_login (line 27) | def awaken_login(self, Proxy: str = ''):
    method log_out (line 31) | def log_out(self):
    method get_login_status (line 35) | def get_login_status(self):
    method send_text_message (line 39) | def send_text_message(self, to_wxid, message, ats: list = []):
    method send_image_message (line 43) | def send_image_message(self, to_wxid, img_url, ats: list = []):
    method send_voice_message (line 47) | def send_voice_message(self, to_wxid, voice_data, voice_forma, voice_d...
    method send_app_message (line 51) | def send_app_message(self, to_wxid, app_message, type):
    method send_emoji_message (line 55) | def send_emoji_message(self, to_wxid, emoji_md5, emoji_size):
    method revoke_msg (line 59) | def revoke_msg(self, to_wxid, msg_id, new_msg_id, create_time):
    method get_profile (line 63) | def get_profile(self):
    method get_qr_code (line 67) | def get_qr_code(self, recover: bool = True, style: int = 8):
    method get_safety_info (line 71) | def get_safety_info(self):
    method update_head_img (line 75) | def update_head_img(self, head_img_base64):
    method cdn_download (line 79) | def cdn_download(self, aeskey, file_type, file_url):
    method get_msg_voice (line 83) | def get_msg_voice(self, buf_id, length, msgid):
    method download_base64 (line 87) | async def download_base64(self, url):
    method get_chatroom_member_detail (line 90) | def get_chatroom_member_detail(self, chatroom_name):

FILE: src/langbot/libs/wechatpad_api/util/http_util.py
  function post_json (line 5) | def post_json(base_url, token, data=None):
  function get_json (line 24) | def get_json(base_url, token):
  function async_request (line 43) | async def async_request(

FILE: src/langbot/libs/wechatpad_api/util/terminal_printer.py
  function print_green (line 4) | def print_green(text):
  function print_yellow (line 8) | def print_yellow(text):
  function print_red (line 12) | def print_red(text):
  function make_and_print_qr (line 16) | def make_and_print_qr(url):

FILE: src/langbot/libs/wecom_ai_bot_api/WXBizMsgCrypt3.py
  class FormatException (line 28) | class FormatException(Exception):
  function throw_exception (line 32) | def throw_exception(message, exception_class=FormatException):
  class SHA1 (line 37) | class SHA1:
    method getSHA1 (line 40) | def getSHA1(self, token, timestamp, nonce, encrypt):
  class XMLParse (line 60) | class XMLParse:
    method extract (line 71) | def extract(self, xmltext):
    method generate (line 85) | def generate(self, encrypt, signature, timestamp, nonce):
  class PKCS7Encoder (line 103) | class PKCS7Encoder:
    method encode (line 108) | def encode(self, text):
    method decode (line 122) | def decode(self, decrypted):
  class Prpcrypt (line 133) | class Prpcrypt(object):
    method __init__ (line 136) | def __init__(self, key):
    method encrypt (line 142) | def encrypt(self, text, receiveid):
    method decrypt (line 165) | def decrypt(self, text, receiveid):
    method get_random_str (line 197) | def get_random_str(self):
  class WXBizMsgCrypt (line 204) | class WXBizMsgCrypt(object):
    method __init__ (line 206) | def __init__(self, sToken, sEncodingAESKey, sReceiveId):
    method VerifyURL (line 224) | def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
    method EncryptMsg (line 235) | def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
    method DecryptMsg (line 257) | def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):

FILE: src/langbot/libs/wecom_ai_bot_api/api.py
  class StreamChunk (line 22) | class StreamChunk:
  class StreamSession (line 36) | class StreamSession:
  class StreamSessionManager (line 67) | class StreamSessionManager:
    method __init__ (line 70) | def __init__(self, logger: EventLogger, ttl: int = 60) -> None:
    method get_stream_id_by_msg (line 77) | def get_stream_id_by_msg(self, msg_id: str) -> Optional[str]:
    method get_session (line 82) | def get_session(self, stream_id: str) -> Optional[StreamSession]:
    method create_or_get (line 85) | def create_or_get(self, msg_json: dict[str, Any]) -> tuple[StreamSessi...
    method publish (line 118) | async def publish(self, stream_id: str, chunk: StreamChunk) -> bool:
    method consume (line 149) | async def consume(self, stream_id: str, timeout: float = 0.5) -> Optio...
    method mark_finished (line 179) | def mark_finished(self, stream_id: str) -> None:
    method cleanup (line 185) | def cleanup(self) -> None:
  function download_encrypted_file (line 202) | async def download_encrypted_file(download_url: str, encoding_aes_key: s...
  function parse_wecom_bot_message (line 248) | async def parse_wecom_bot_message(
  class WecomBotClient (line 449) | class WecomBotClient:
    method __init__ (line 450) | def __init__(self, Token: str, EnCodingAESKey: str, Corpid: str, logge...
    method _build_stream_payload (line 487) | def _build_stream_payload(stream_id: str, content: str, finish: bool) ...
    method _encrypt_and_reply (line 510) | async def _encrypt_and_reply(self, payload: dict[str, Any], nonce: str...
    method _dispatch_event (line 537) | async def _dispatch_event(self, event: wecombotevent.WecomBotEvent) ->...
    method _handle_post_initial_response (line 548) | async def _handle_post_initial_response(self, msg_json: dict[str, Any]...
    method _handle_post_followup_response (line 577) | async def _handle_post_followup_response(self, msg_json: dict[str, Any...
    method handle_callback_request (line 614) | async def handle_callback_request(self):
    method handle_unified_webhook (line 625) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 636) | async def _handle_callback_internal(self, req):
    method _handle_get_callback (line 657) | async def _handle_get_callback(self, req) -> tuple[Response, int] | Re...
    method _handle_post_callback (line 676) | async def _handle_post_callback(self, req) -> tuple[Response, int] | R...
    method get_message (line 704) | async def get_message(self, msg_json):
    method _handle_message (line 707) | async def _handle_message(self, event: wecombotevent.WecomBotEvent):
    method push_stream_chunk (line 724) | async def push_stream_chunk(self, msg_id: str, content: str, is_final:...
    method set_message (line 749) | async def set_message(self, msg_id: str, content: str):
    method on_message (line 763) | def on_message(self, msg_type: str):
    method download_url_to_base64 (line 772) | async def download_url_to_base64(self, download_url, encoding_aes_key):
    method run_task (line 775) | async def run_task(self, host: str, port: int, *args, **kwargs):

FILE: src/langbot/libs/wecom_ai_bot_api/wecombotevent.py
  class WecomBotEvent (line 4) | class WecomBotEvent(dict):
    method from_payload (line 6) | def from_payload(payload: Dict[str, Any]) -> Optional['WecomBotEvent']:
    method type (line 14) | def type(self) -> str:
    method msgtype (line 21) | def msgtype(self) -> str:
    method userid (line 28) | def userid(self) -> str:
    method username (line 35) | def username(self) -> str:
    method chatname (line 47) | def chatname(self) -> str:
    method content (line 54) | def content(self) -> str:
    method picurl (line 61) | def picurl(self) -> str:
    method images (line 68) | def images(self):
    method file (line 75) | def file(self):
    method voice (line 82) | def voice(self):
    method video (line 89) | def video(self):
    method link (line 96) | def link(self):
    method location (line 103) | def location(self):
    method attachments (line 110) | def attachments(self):
    method chatid (line 117) | def chatid(self) -> str:
    method message_id (line 124) | def message_id(self) -> str:
    method ai_bot_id (line 131) | def ai_bot_id(self) -> str:

FILE: src/langbot/libs/wecom_ai_bot_api/ws_client.py
  function _generate_req_id (line 39) | def _generate_req_id(prefix: str) -> str:
  class WecomBotWsClient (line 46) | class WecomBotWsClient:
    method __init__ (line 53) | def __init__(
    method connect (line 102) | async def connect(self):
    method disconnect (line 135) | async def disconnect(self):
    method on_message (line 150) | def on_message(self, msg_type: str) -> Callable:
    method reply_stream (line 167) | async def reply_stream(
    method reply_text (line 195) | async def reply_text(self, req_id: str, content: str) -> Optional[dict]:
    method send_message (line 213) | async def send_message(self, chat_id: str, content: str, msgtype: str ...
    method push_stream_chunk (line 235) | async def push_stream_chunk(self, msg_id: str, content: str, is_final:...
    method set_message (line 266) | async def set_message(self, msg_id: str, content: str):
    method _connect_once (line 277) | async def _connect_once(self):
    method _send_auth (line 315) | async def _send_auth(self):
    method _wait_for_auth (line 327) | async def _wait_for_auth(self) -> bool:
    method _heartbeat_loop (line 347) | async def _heartbeat_loop(self):
    method _listen_loop (line 374) | async def _listen_loop(self):
    method _handle_frame (line 399) | async def _handle_frame(self, frame: dict):
    method _handle_message_callback (line 432) | async def _handle_message_callback(self, frame: dict):
    method _handle_event_callback (line 456) | async def _handle_event_callback(self, frame: dict):
    method _dispatch_event (line 497) | async def _dispatch_event(self, event: wecombotevent.WecomBotEvent):
    method _send_reply (line 515) | async def _send_reply(
    method _reply_queue_worker (line 543) | async def _reply_queue_worker(self, req_id: str):
    method _send_and_wait_ack (line 567) | async def _send_and_wait_ack(self, frame: dict) -> Optional[dict]:
    method _send_frame (line 586) | async def _send_frame(self, frame: dict):
    method _clear_pending_acks (line 591) | def _clear_pending_acks(self, reason: str):

FILE: src/langbot/libs/wecom_api/WXBizMsgCrypt3.py
  class FormatException (line 29) | class FormatException(Exception):
  function throw_exception (line 33) | def throw_exception(message, exception_class=FormatException):
  class SHA1 (line 38) | class SHA1:
    method getSHA1 (line 41) | def getSHA1(self, token, timestamp, nonce, encrypt):
  class XMLParse (line 61) | class XMLParse:
    method extract (line 72) | def extract(self, xmltext):
    method generate (line 86) | def generate(self, encrypt, signature, timestamp, nonce):
  class PKCS7Encoder (line 104) | class PKCS7Encoder:
    method encode (line 109) | def encode(self, text):
    method decode (line 123) | def decode(self, decrypted):
  class Prpcrypt (line 134) | class Prpcrypt(object):
    method __init__ (line 137) | def __init__(self, key):
    method encrypt (line 143) | def encrypt(self, text, receiveid):
    method decrypt (line 166) | def decrypt(self, text, receiveid):
    method get_random_str (line 198) | def get_random_str(self):
  class WXBizMsgCrypt (line 205) | class WXBizMsgCrypt(object):
    method __init__ (line 207) | def __init__(self, sToken, sEncodingAESKey, sReceiveId):
    method VerifyURL (line 225) | def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
    method EncryptMsg (line 236) | def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
    method DecryptMsg (line 258) | def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):

FILE: src/langbot/libs/wecom_api/api.py
  class WecomClient (line 15) | class WecomClient:
    method __init__ (line 16) | def __init__(
    method check_access_token (line 53) | async def check_access_token(self):
    method check_access_token_for_contacts (line 56) | async def check_access_token_for_contacts(self):
    method get_access_token (line 59) | async def get_access_token(self, secret):
    method get_users (line 70) | async def get_users(self):
    method send_to_all (line 91) | async def send_to_all(self, content: str, agent_id: int):
    method send_image (line 116) | async def send_image(self, user_id: str, agent_id: int, media_id: str):
    method send_voice (line 143) | async def send_voice(self, user_id: str, agent_id: int, media_id: str):
    method send_file (line 169) | async def send_file(self, user_id: str, agent_id: int, media_id: str):
    method send_private_msg (line 195) | async def send_private_msg(self, user_id: str, agent_id: int, content:...
    method handle_callback_request (line 222) | async def handle_callback_request(self):
    method handle_unified_webhook (line 226) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 237) | async def _handle_callback_internal(self, req):
    method run_task (line 277) | async def run_task(self, host: str, port: int, *args, **kwargs):
    method on_message (line 283) | def on_message(self, msg_type: str):
    method _handle_message (line 296) | async def _handle_message(self, event: WecomEvent):
    method get_message (line 305) | async def get_message(self, xml_msg: str) -> Dict[str, Any]:
    method get_image_type (line 326) | async def get_image_type(image_bytes: bytes) -> str:
    method upload_image_to_work (line 343) | async def upload_image_to_work(self, image: platform_message.Image):
    method upload_voice_to_work (line 403) | async def upload_voice_to_work(self, voice: platform_message.Voice):
    method upload_file_to_work (line 459) | async def upload_file_to_work(self, file: platform_message.File):
    method download_media_to_bytes (line 511) | async def download_media_to_bytes(self, url: str) -> bytes:
    method get_media_id (line 518) | async def get_media_id(self, media: platform_message.Image | platform_...

FILE: src/langbot/libs/wecom_api/wecomevent.py
  class WecomEvent (line 4) | class WecomEvent(dict):
    method from_payload (line 12) | def from_payload(payload: Dict[str, Any]) -> Optional['WecomEvent']:
    method type (line 30) | def type(self) -> str:
    method picurl (line 40) | def picurl(self) -> str:
    method detail_type (line 47) | def detail_type(self) -> str:
    method name (line 61) | def name(self) -> str:
    method user_id (line 71) | def user_id(self) -> Optional[str]:
    method agent_id (line 81) | def agent_id(self) -> Optional[int]:
    method receiver_id (line 91) | def receiver_id(self) -> Optional[str]:
    method message_id (line 101) | def message_id(self) -> Optional[str]:
    method message (line 111) | def message(self) -> Optional[str]:
    method media_id (line 121) | def media_id(self) -> Optional[str]:
    method timestamp (line 131) | def timestamp(self) -> Optional[int]:
    method event_key (line 141) | def event_key(self) -> Optional[str]:
    method __getattr__ (line 150) | def __getattr__(self, key: str) -> Optional[Any]:
    method __setattr__ (line 162) | def __setattr__(self, key: str, value: Any) -> None:
    method __repr__ (line 172) | def __repr__(self) -> str:

FILE: src/langbot/libs/wecom_customer_service_api/api.py
  class WecomCSClient (line 16) | class WecomCSClient:
    method __init__ (line 17) | def __init__(
    method get_pic_url (line 52) | async def get_pic_url(self, media_id: str):
    method check_access_token (line 76) | async def check_access_token(self):
    method check_access_token_for_contacts (line 79) | async def check_access_token_for_contacts(self):
    method get_access_token (line 82) | async def get_access_token(self, secret):
    method get_detailed_message_list (line 92) | async def get_detailed_message_list(self, xml_msg: str):
    method change_service_status (line 133) | async def change_service_status(self, userid: str, openkfid: str, serv...
    method send_image (line 152) | async def send_image(self, user_id: str, agent_id: int, media_id: str):
    method send_text_msg (line 185) | async def send_text_msg(self, open_kfid: str, external_userid: str, ms...
    method handle_callback_request (line 213) | async def handle_callback_request(self):
    method handle_unified_webhook (line 217) | async def handle_unified_webhook(self, req):
    method _handle_callback_internal (line 228) | async def _handle_callback_internal(self, req):
    method run_task (line 272) | async def run_task(self, host: str, port: int, *args, **kwargs):
    method on_message (line 278) | def on_message(self, msg_type: str):
    method _handle_message (line 291) | async def _handle_message(self, event: WecomCSEvent):
    method get_image_type (line 301) | async def get_image_type(image_bytes: bytes) -> str:
    method upload_to_work (line 318) | async def upload_to_work(self, image: platform_message.Image):
    method download_image_to_bytes (line 376) | async def download_image_to_bytes(self, url: str) -> bytes:
    method get_media_id (line 383) | async def get_media_id(self, image: platform_message.Image):
    method get_customer_info (line 387) | async def get_customer_info(self, external_userid: str) -> dict | None:

FILE: src/langbot/libs/wecom_customer_service_api/wecomcsevent.py
  class WecomCSEvent (line 4) | class WecomCSEvent(dict):
    method from_payload (line 12) | def from_payload(payload: Dict[str, Any]) -> Optional['WecomCSEvent']:
    method type (line 30) | def type(self) -> str:
    method user_id (line 40) | def user_id(self) -> Optional[str]:
    method receiver_id (line 50) | def receiver_id(self) -> Optional[str]:
    method picurl (line 60) | def picurl(self) -> Optional[str]:
    method message_id (line 71) | def message_id(self) -> Optional[str]:
    method message (line 81) | def message(self) -> Optional[str]:
    method timestamp (line 94) | def timestamp(self) -> Optional[int]:
    method __getattr__ (line 103) | def __getattr__(self, key: str) -> Optional[Any]:
    method __setattr__ (line 115) | def __setattr__(self, key: str, value: Any) -> None:
    method __repr__ (line 125) | def __repr__(self) -> str:

FILE: src/langbot/pkg/api/http/controller/group.py
  function group_class (line 20) | def group_class(name: str, path: str) -> typing.Callable[[typing.Type[Ro...
  class AuthType (line 32) | class AuthType(enum.Enum):
  class RouterGroup (line 41) | class RouterGroup(abc.ABC):
    method __init__ (line 50) | def __init__(self, ap: app.Application, quart_app: quart.Quart) -> None:
    method initialize (line 55) | async def initialize(self) -> None:
    method route (line 58) | def route(
    method success (line 168) | def success(self, data: typing.Any = None) -> quart.Response:
    method fail (line 178) | def fail(self, code: int, msg: str) -> quart.Response:
    method http_status (line 188) | def http_status(self, status: int, code: int, msg: str) -> typing.Tupl...

FILE: src/langbot/pkg/api/http/controller/groups/apikeys.py
  class ApiKeysRouterGroup (line 7) | class ApiKeysRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/files.py
  class FilesRouterGroup (line 14) | class FilesRouterGroup(group.RouterGroup):
    method initialize (line 15) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/knowledge/base.py
  class KnowledgeBaseRouterGroup (line 6) | class KnowledgeBaseRouterGroup(group.RouterGroup):
    method initialize (line 7) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/knowledge/engines.py
  class KnowledgeEnginesRouterGroup (line 7) | class KnowledgeEnginesRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/knowledge/migration.py
  class KnowledgeMigrationRouterGroup (line 36) | class KnowledgeMigrationRouterGroup(group.RouterGroup):
    method _get_migration_flag (line 37) | async def _get_migration_flag(self) -> bool:
    method _set_migration_flag (line 47) | async def _set_migration_flag(self, value: str):
    method _table_exists (line 55) | async def _table_exists(self, table_name: str) -> bool:
    method _install_plugin_from_marketplace (line 72) | async def _install_plugin_from_marketplace(
    method _execute_rag_migration (line 99) | async def _execute_rag_migration(self, task_context: taskmgr.TaskConte...
    method initialize (line 316) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/knowledge/parsers.py
  class ParsersRouterGroup (line 6) | class ParsersRouterGroup(group.RouterGroup):
    method initialize (line 7) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/logs.py
  class LogsRouterGroup (line 10) | class LogsRouterGroup(group.RouterGroup):
    method initialize (line 11) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/monitoring.py
  function parse_iso_datetime (line 9) | def parse_iso_datetime(datetime_str: str | None) -> datetime.datetime | ...
  class MonitoringRouterGroup (line 25) | class MonitoringRouterGroup(group.RouterGroup):
    method initialize (line 26) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/pipelines/pipelines.py
  class PipelinesRouterGroup (line 9) | class PipelinesRouterGroup(group.RouterGroup):
    method initialize (line 10) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py
  class WebSocketChatRouterGroup (line 17) | class WebSocketChatRouterGroup(group.RouterGroup):
    method initialize (line 18) | async def initialize(self) -> None:
    method _handle_receive (line 181) | async def _handle_receive(self, connection, websocket_adapter):
    method _handle_send (line 225) | async def _handle_send(self, connection):

FILE: src/langbot/pkg/api/http/controller/groups/platform/adapters.py
  class AdaptersRouterGroup (line 8) | class AdaptersRouterGroup(group.RouterGroup):
    method initialize (line 9) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/platform/bots.py
  class BotsRouterGroup (line 7) | class BotsRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/plugins.py
  class PluginsRouterGroup (line 16) | class PluginsRouterGroup(group.RouterGroup):
    method _check_extensions_limit (line 17) | async def _check_extensions_limit(self) -> str | None:
    method initialize (line 29) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/provider/models.py
  class LLMModelsRouterGroup (line 7) | class LLMModelsRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:
  class EmbeddingModelsRouterGroup (line 53) | class EmbeddingModelsRouterGroup(group.RouterGroup):
    method initialize (line 54) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/provider/providers.py
  class ModelProvidersRouterGroup (line 7) | class ModelProvidersRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/provider/requesters.py
  class RequestersRouterGroup (line 9) | class RequestersRouterGroup(group.RouterGroup):
    method initialize (line 10) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/resources/mcp.py
  class MCPRouterGroup (line 11) | class MCPRouterGroup(group.RouterGroup):
    method initialize (line 12) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/stats.py
  class StatsRouterGroup (line 5) | class StatsRouterGroup(group.RouterGroup):
    method initialize (line 6) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/survey.py
  class SurveyRouterGroup (line 7) | class SurveyRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/system.py
  class SystemRouterGroup (line 8) | class SystemRouterGroup(group.RouterGroup):
    method initialize (line 9) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/user.py
  class UserRouterGroup (line 11) | class UserRouterGroup(group.RouterGroup):
    method initialize (line 12) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/webhook_mgmt.py
  class WebhookManagementRouterGroup (line 7) | class WebhookManagementRouterGroup(group.RouterGroup):
    method initialize (line 8) | async def initialize(self) -> None:

FILE: src/langbot/pkg/api/http/controller/groups/webhooks.py
  class WebhookRouterGroup (line 10) | class WebhookRouterGroup(group.RouterGroup):
    method initialize (line 11) | async def initialize(self) -> None:
    method _dispatch_webhook (line 22) | async def _dispatch_webhook(self, bot_uuid: str, path: str):

FILE: src/langbot/pkg/api/http/controller/main.py
  class HTTPController (line 29) | class HTTPController:
    method __init__ (line 34) | def __init__(self, ap: app.Application) -> None:
    method initialize (line 42) | async def initialize(self) -> None:
    method run (line 55) | async def run(self) -> None:
    method register_routes (line 80) | async def register_routes(self) -> None:

FILE: src/langbot/pkg/api/http/service/apikey.py
  class ApiKeyService (line 10) | class ApiKeyService:
    method __init__ (line 13) | def __init__(self, ap: app.Application) -> None:
    method get_api_keys (line 16) | async def get_api_keys(self) -> list[dict]:
    method create_api_key (line 23) | async def create_api_key(self, name: str, description: str = '') -> dict:
    method get_api_key (line 40) | async def get_api_key(self, key_id: int) -> dict | None:
    method verify_api_key (line 53) | async def verify_api_key(self, key: str) -> bool:
    method delete_api_key (line 62) | async def delete_api_key(self, key_id: int) -> None:
    method update_api_key (line 66) | async def update_api_key(self, key_id: int, name: str = None, descript...

FILE: src/langbot/pkg/api/http/service/bot.py
  class BotService (line 12) | class BotService:
    method __init__ (line 17) | def __init__(self, ap: app.Application) -> None:
    method get_bots (line 20) | async def get_bots(self, include_secret: bool = True) -> list[dict]:
    method get_bot (line 32) | async def get_bot(self, bot_uuid: str, include_secret: bool = True) ->...
    method get_runtime_bot_info (line 49) | async def get_runtime_bot_info(self, bot_uuid: str, include_secret: bo...
    method create_bot (line 89) | async def create_bot(self, bot_data: dict) -> str:
    method update_bot (line 121) | async def update_bot(self, bot_uuid: str, bot_data: dict) -> None:
    method delete_bot (line 157) | async def delete_bot(self, bot_uuid: str) -> None:
    method list_event_logs (line 164) | async def list_event_logs(
    method send_message (line 175) | async def send_message(self, bot_uuid: str, target_type: str, target_i...

FILE: src/langbot/pkg/api/http/service/knowledge.py
  class KnowledgeService (line 9) | class KnowledgeService:
    method __init__ (line 14) | def __init__(self, ap: app.Application) -> None:
    method get_knowledge_bases (line 17) | async def get_knowledge_bases(self) -> list[dict]:
    method get_knowledge_base (line 21) | async def get_knowledge_base(self, kb_uuid: str) -> dict | None:
    method create_knowledge_base (line 25) | async def create_knowledge_base(self, kb_data: dict) -> str:
    method update_knowledge_base (line 43) | async def update_knowledge_base(self, kb_uuid: str, kb_data: dict) -> ...
    method _check_doc_capability (line 64) | async def _check_doc_capability(self, kb_uuid: str, operation: str) ->...
    method store_file (line 81) | async def store_file(self, kb_uuid: str, file_id: str, parser_plugin_i...
    method retrieve_knowledge_base (line 100) | async def retrieve_knowledge_base(
    method get_files_by_knowledge_base (line 113) | async def get_files_by_knowledge_base(self, kb_uuid: str) -> list[dict]:
    method delete_file (line 121) | async def delete_file(self, kb_uuid: str, file_id: str) -> None:
    method delete_knowledge_base (line 138) | async def delete_knowledge_base(self, kb_uuid: str) -> None:
    method list_knowledge_engines (line 166) | async def list_knowledge_engines(self) -> list[dict]:
    method list_parsers (line 182) | async def list_parsers(self, mime_type: str | None = None) -> list[dict]:
    method get_engine_creation_schema (line 195) | async def get_engine_creation_schema(self, plugin_id: str) -> dict:
    method get_engine_retrieval_schema (line 203) | async def get_engine_retrieval_schema(self, plugin_id: str) -> dict:

FILE: src/langbot/pkg/api/http/service/mcp.py
  class MCPService (line 13) | class MCPService:
    method __init__ (line 16) | def __init__(self, ap: app.Application) -> None:
    method get_runtime_info (line 19) | async def get_runtime_info(self, server_name: str) -> dict | None:
    method get_mcp_servers (line 25) | async def get_mcp_servers(self, contain_runtime_info: bool = False) ->...
    method create_mcp_server (line 40) | async def create_mcp_server(self, server_data: dict) -> str:
    method get_mcp_server_by_name (line 66) | async def get_mcp_server_by_name(self, server_name: str) -> dict | None:
    method update_mcp_server (line 79) | async def update_mcp_server(self, server_uuid: str, server_data: dict)...
    method delete_mcp_server (line 124) | async def delete_mcp_server(self, server_uuid: str) -> None:
    method test_mcp_server (line 139) | async def test_mcp_server(self, server_name: str, server_data: dict) -...

FILE: src/langbot/pkg/api/http/service/model.py
  function _parse_provider_api_keys (line 14) | def _parse_provider_api_keys(provider_dict: dict) -> dict:
  class LLMModelsService (line 26) | class LLMModelsService:
    method __init__ (line 29) | def __init__(self, ap: app.Application) -> None:
    method get_llm_models (line 32) | async def get_llm_models(self, include_secret: bool = True) -> list[di...
    method get_llm_models_by_provider (line 57) | async def get_llm_models_by_provider(self, provider_uuid: str) -> list...
    method create_llm_model (line 67) | async def create_llm_model(
    method get_llm_model (line 121) | async def get_llm_model(self, model_uuid: str) -> dict | None:
    method update_llm_model (line 145) | async def update_llm_model(self, model_uuid: str, model_data: dict) ->...
    method delete_llm_model (line 181) | async def delete_llm_model(self, model_uuid: str) -> None:
    method test_llm_model (line 188) | async def test_llm_model(self, model_uuid: str, model_data: dict) -> N...
  class EmbeddingModelsService (line 212) | class EmbeddingModelsService:
    method __init__ (line 215) | def __init__(self, ap: app.Application) -> None:
    method get_embedding_models (line 218) | async def get_embedding_models(self) -> list[dict]:
    method get_embedding_models_by_provider (line 239) | async def get_embedding_models_by_provider(self, provider_uuid: str) -...
    method create_embedding_model (line 249) | async def create_embedding_model(self, model_data: dict, preserve_uuid...
    method get_embedding_model (line 282) | async def get_embedding_model(self, model_uuid: str) -> dict | None:
    method update_embedding_model (line 307) | async def update_embedding_model(self, model_uuid: str, model_data: di...
    method delete_embedding_model (line 342) | async def delete_embedding_model(self, model_uuid: str) -> None:
    method test_embedding_model (line 351) | async def test_embedding_model(self, model_uuid: str, model_data: dict...

FILE: src/langbot/pkg/api/http/service/monitoring.py
  class MonitoringService (line 11) | class MonitoringService:
    method __init__ (line 16) | def __init__(self, ap: app.Application) -> None:
    method record_message (line 21) | async def record_message(
    method record_llm_call (line 65) | async def record_llm_call(
    method record_embedding_call (line 108) | async def record_embedding_call(
    method record_session_start (line 148) | async def record_session_start(
    method update_session_activity (line 179) | async def update_session_activity(
    method record_error (line 211) | async def record_error(
    method update_message_status (line 245) | async def update_message_status(
    method get_overview_metrics (line 267) | async def get_overview_metrics(
    method get_messages (line 360) | async def get_messages(
    method get_llm_calls (line 413) | async def get_llm_calls(
    method get_embedding_calls (line 464) | async def get_embedding_calls(
    method get_sessions (line 512) | async def get_sessions(
    method get_errors (line 566) | async def get_errors(
    method get_session_analysis (line 617) | async def get_session_analysis(
    method get_message_details (line 733) | async def get_message_details(
    method _escape_csv_field (line 809) | def _escape_csv_field(self, field: str | None) -> str:
    method _format_timestamp (line 824) | def _format_timestamp(self, dt: datetime.datetime) -> str:
    method _extract_message_text (line 828) | def _extract_message_text(self, message_content: str) -> str:
    method export_messages (line 884) | async def export_messages(
    method export_llm_calls (line 937) | async def export_llm_calls(
    method export_embedding_calls (line 990) | async def export_embedding_calls(
    method export_errors (line 1038) | async def export_errors(
    method export_sessions (line 1086) | async def export_sessions(

FILE: src/langbot/pkg/api/http/service/pipeline.py
  class PipelineService (line 27) | class PipelineService:
    method __init__ (line 30) | def __init__(self, ap: app.Application) -> None:
    method get_pipeline_metadata (line 33) | async def get_pipeline_metadata(self) -> list[dict]:
    method get_pipelines (line 41) | async def get_pipelines(self, sort_by: str = 'created_at', sort_order:...
    method get_pipeline (line 62) | async def get_pipeline(self, pipeline_uuid: str) -> dict | None:
    method create_pipeline (line 76) | async def create_pipeline(self, pipeline_data: dict, default: bool = F...
    method update_pipeline (line 115) | async def update_pipeline(self, pipeline_uuid: str, pipeline_data: dic...
    method delete_pipeline (line 154) | async def delete_pipeline(self, pipeline_uuid: str) -> None:
    method copy_pipeline (line 162) | async def copy_pipeline(self, pipeline_uuid: str) -> str:
    method update_pipeline_extensions (line 216) | async def update_pipeline_extensions(

FILE: src/langbot/pkg/api/http/service/provider.py
  class ModelProviderService (line 11) | class ModelProviderService:
    method __init__ (line 16) | def __init__(self, ap: app.Application) -> None:
    method get_providers (line 19) | async def get_providers(self) -> list[dict]:
    method get_provider (line 37) | async def get_provider(self, provider_uuid: str) -> dict | None:
    method create_provider (line 58) | async def create_provider(self, provider_data: dict) -> str:
    method update_provider (line 70) | async def update_provider(self, provider_uuid: str, provider_data: dic...
    method delete_provider (line 81) | async def delete_provider(self, provider_uuid: str) -> None:
    method get_provider_model_counts (line 108) | async def get_provider_model_counts(self, provider_uuid: str) -> dict:
    method find_or_create_provider (line 126) | async def find_or_create_provider(self, requester: str, base_url: str,...
    method update_space_model_provider_api_keys (line 159) | async def update_space_model_provider_api_keys(self, api_key: str) -> ...

FILE: src/langbot/pkg/api/http/service/space.py
  class SpaceService (line 14) | class SpaceService:
    method __init__ (line 20) | def __init__(self, ap: app.Application) -> None:
    method _get_space_config (line 24) | def _get_space_config(self) -> typing.Dict[str, str]:
    method _get_user_by_email (line 32) | async def _get_user_by_email(self, user_email: str) -> user.User | None:
    method _ensure_valid_token (line 39) | async def _ensure_valid_token(self, user_email: str) -> str | None:
    method _refresh_and_save_token (line 62) | async def _refresh_and_save_token(self, user_obj: user.User) -> str:
    method get_oauth_authorize_url (line 86) | def get_oauth_authorize_url(self, redirect_uri: str, state: str = '') ...
    method exchange_oauth_code (line 95) | async def exchange_oauth_code(self, code: str) -> typing.Dict:
    method refresh_token (line 114) | async def refresh_token(self, refresh_token: str) -> typing.Dict:
    method get_user_info_raw (line 130) | async def get_user_info_raw(self, access_token: str) -> typing.Dict:
    method get_user_info (line 148) | async def get_user_info(self, user_email: str) -> typing.Dict | None:
    method get_credits (line 155) | async def get_credits(self, user_email: str, force_refresh: bool = Fal...
    method get_models (line 175) | async def get_models(self) -> typing.List[SpaceModel]:

FILE: src/langbot/pkg/api/http/service/user.py
  class UserService (line 16) | class UserService:
    method __init__ (line 20) | def __init__(self, ap: app.Application) -> None:
    method is_initialized (line 24) | async def is_initialized(self) -> bool:
    method create_user (line 30) | async def create_user(self, user_email: str, password: str) -> None:
    method get_user_by_email (line 39) | async def get_user_by_email(self, user_email: str) -> user.User | None:
    method get_user_by_space_account_uuid (line 47) | async def get_user_by_space_account_uuid(self, space_account_uuid: str...
    method authenticate (line 56) | async def authenticate(self, user_email: str, password: str) -> str | ...
    method generate_jwt_token (line 78) | async def generate_jwt_token(self, user_email: str) -> str:
    method verify_jwt_token (line 90) | async def verify_jwt_token(self, token: str) -> str:
    method reset_password (line 95) | async def reset_password(self, user_email: str, new_password: str) -> ...
    method change_password (line 104) | async def change_password(self, user_email: str, current_password: str...
    method create_or_update_space_user (line 125) | async def create_or_update_space_user(
    method authenticate_space_user (line 197) | async def authenticate_space_user(
    method get_first_user (line 228) | async def get_first_user(self) -> user.User | None:
    method set_password (line 234) | async def set_password(self, user_email: str, new_password: str, curre...
    method bind_space_account (line 254) | async def bind_space_account(self, user_email: str, code: str) -> user...

FILE: src/langbot/pkg/api/http/service/webhook.py
  class WebhookService (line 9) | class WebhookService:
    method __init__ (line 12) | def __init__(self, ap: app.Application) -> None:
    method get_webhooks (line 15) | async def get_webhooks(self) -> list[dict]:
    method create_webhook (line 22) | async def create_webhook(self, name: str, url: str, description: str =...
    method get_webhook (line 36) | async def get_webhook(self, webhook_id: int) -> dict | None:
    method update_webhook (line 49) | async def update_webhook(
    method delete_webhook (line 68) | async def delete_webhook(self, webhook_id: int) -> None:
    method get_enabled_webhooks (line 74) | async def get_enabled_webhooks(self) -> list[dict]:

FILE: src/langbot/pkg/command/cmdmgr.py
  class CommandManager (line 18) | class CommandManager:
    method __init__ (line 26) | def __init__(self, ap: app.Application):
    method initialize (line 29) | async def initialize(self):
    method _execute (line 57) | async def _execute(
    method execute (line 76) | async def execute(

FILE: src/langbot/pkg/command/operator.py
  function operator_class (line 14) | def operator_class(
  class CommandOperator (line 53) | class CommandOperator(metaclass=abc.ABCMeta):
    method __init__ (line 90) | def __init__(self, ap: app.Application):
    method initialize (line 94) | async def initialize(self):
    method execute (line 98) | async def execute(

FILE: src/langbot/pkg/config/impls/json.py
  class JSONConfigFile (line 8) | class JSONConfigFile(file_model.ConfigFile):
    method __init__ (line 11) | def __init__(
    method exists (line 21) | def exists(self) -> bool:
    method get_template_file_str (line 24) | async def get_template_file_str(self) -> str:
    method create (line 33) | async def create(self):
    method load (line 43) | async def load(self, completion: bool = True) -> dict:
    method save (line 65) | async def save(self, cfg: dict):
    method save_sync (line 69) | def save_sync(self, cfg: dict):

FILE: src/langbot/pkg/config/impls/pymodule.py
  class PythonModuleConfigFile (line 9) | class PythonModuleConfigFile(file_model.ConfigFile):
    method __init__ (line 18) | def __init__(self, config_file_name: str, template_file_name: str) -> ...
    method exists (line 22) | def exists(self) -> bool:
    method create (line 25) | async def create(self):
    method load (line 28) | async def load(self, completion: bool = True) -> dict:
    method save (line 62) | async def save(self, data: dict):
    method save_sync (line 65) | def save_sync(self, data: dict):

FILE: src/langbot/pkg/config/impls/yaml.py
  class YAMLConfigFile (line 8) | class YAMLConfigFile(file_model.ConfigFile):
    method __init__ (line 11) | def __init__(
    method exists (line 21) | def exists(self) -> bool:
    method get_template_file_str (line 24) | async def get_template_file_str(self) -> str:
    method create (line 33) | async def create(self):
    method load (line 43) | async def load(self, completion: bool = True) -> dict:
    method save (line 65) | async def save(self, cfg: dict):
    method save_sync (line 69) | def save_sync(self, cfg: dict):

FILE: src/langbot/pkg/config/manager.py
  class ConfigManager (line 7) | class ConfigManager:
    method __init__ (line 30) | def __init__(self, cfg_file: file_model.ConfigFile) -> None:
    method load_config (line 34) | async def load_config(self, completion: bool = True):
    method dump_config (line 37) | async def dump_config(self):
    method dump_config_sync (line 40) | def dump_config_sync(self):
  function load_python_module_config (line 44) | async def load_python_module_config(config_name: str, template_name: str...
  function load_json_config (line 63) | async def load_json_config(
  function load_yaml_config (line 85) | async def load_yaml_config(

FILE: src/langbot/pkg/config/model.py
  class ConfigFile (line 4) | class ConfigFile(metaclass=abc.ABCMeta):
    method exists (line 17) | def exists(self) -> bool:
    method create (line 21) | async def create(self):
    method load (line 25) | async def load(self, completion: bool = True) -> dict:
    method save (line 29) | async def save(self, data: dict):
    method save_sync (line 33) | def save_sync(self, data: dict):

FILE: src/langbot/pkg/core/app.py
  class Application (line 47) | class Application:
    method __init__ (line 156) | def __init__(self):
    method initialize (line 159) | async def initialize(self):
    method run (line 162) | async def run(self):
    method dispose (line 205) | def dispose(self):
    method print_web_access_info (line 208) | async def print_web_access_info(self):

FILE: src/langbot/pkg/core/boot.py
  function make_app (line 27) | async def make_app(loop: asyncio.AbstractEventLoop) -> app.Application:
  function main (line 48) | async def main(loop: asyncio.AbstractEventLoop):

FILE: src/langbot/pkg/core/bootutils/deps.py
  function check_deps (line 48) | async def check_deps() -> list[str]:
  function install_deps (line 61) | async def install_deps(deps: list[str]):
  function precheck_plugin_deps (line 68) | async def precheck_plugin_deps():

FILE: src/langbot/pkg/core/bootutils/files.py
  function generate_files (line 20) | async def generate_files() -> list[str]:

FILE: src/langbot/pkg/core/bootutils/log.py
  function init_logging (line 24) | async def init_logging(extra_handlers: list[logging.Handler] = None) -> ...

FILE: src/langbot/pkg/core/entities.py
  class LifecycleControlScope (line 6) | class LifecycleControlScope(enum.Enum):

FILE: src/langbot/pkg/core/migration.py
  function migration_class (line 13) | def migration_class(name: str, number: int):
  class Migration (line 25) | class Migration(abc.ABC):
    method __init__ (line 34) | def __init__(self, ap: app.Application):
    method need_migrate (line 38) | async def need_migrate(self) -> bool:
    method run (line 43) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m001_sensitive_word_migration.py
  class SensitiveWordMigration (line 9) | class SensitiveWordMigration(migration.Migration):
    method need_migrate (line 12) | async def need_migrate(self) -> bool:
    method run (line 18) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m002_openai_config_migration.py
  class OpenAIConfigMigration (line 7) | class OpenAIConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m003_anthropic_requester_cfg_completion.py
  class AnthropicRequesterConfigCompletionMigration (line 7) | class AnthropicRequesterConfigCompletionMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 17) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m004_moonshot_cfg_completion.py
  class MoonshotConfigCompletionMigration (line 7) | class MoonshotConfigCompletionMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 17) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m005_deepseek_cfg_completion.py
  class DeepseekConfigCompletionMigration (line 7) | class DeepseekConfigCompletionMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 17) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m006_vision_config.py
  class VisionConfigMigration (line 7) | class VisionConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m007_qcg_center_url.py
  class QCGCenterURLConfigMigration (line 7) | class QCGCenterURLConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m008_ad_fixwin_config_migrate.py
  class AdFixwinConfigMigration (line 7) | class AdFixwinConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m009_msg_truncator_cfg.py
  class MsgTruncatorConfigMigration (line 7) | class MsgTruncatorConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m010_ollama_requester_config.py
  class MsgTruncatorConfigMigration (line 7) | class MsgTruncatorConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m011_command_prefix_config.py
  class CommandPrefixConfigMigration (line 7) | class CommandPrefixConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m012_runner_config.py
  class RunnerConfigMigration (line 7) | class RunnerConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m013_http_api_config.py
  class HttpApiConfigMigration (line 7) | class HttpApiConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m014_force_delay_config.py
  class ForceDelayConfigMigration (line 7) | class ForceDelayConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m015_gitee_ai_config.py
  class GiteeAIConfigMigration (line 7) | class GiteeAIConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 17) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m016_dify_service_api.py
  class DifyServiceAPICfgMigration (line 7) | class DifyServiceAPICfgMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m017_dify_api_timeout_params.py
  class DifyAPITimeoutParamsMigration (line 7) | class DifyAPITimeoutParamsMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 18) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m018_xai_config.py
  class XaiConfigMigration (line 7) | class XaiConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m019_zhipuai_config.py
  class ZhipuaiConfigMigration (line 7) | class ZhipuaiConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m020_wecom_config.py
  class WecomConfigMigration (line 7) | class WecomConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m021_lark_config.py
  class LarkConfigMigration (line 7) | class LarkConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m022_lmstudio_config.py
  class LmStudioConfigMigration (line 7) | class LmStudioConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 15) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m023_siliconflow_config.py
  class SiliconFlowConfigMigration (line 7) | class SiliconFlowConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 15) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m024_discord_config.py
  class DiscordConfigMigration (line 7) | class DiscordConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m025_gewechat_config.py
  class GewechatConfigMigration (line 7) | class GewechatConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m026_qqofficial_config.py
  class QQOfficialConfigMigration (line 7) | class QQOfficialConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m027_wx_official_account_config.py
  class WXOfficialAccountConfigMigration (line 7) | class WXOfficialAccountConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m028_aliyun_requester_config.py
  class BailianRequesterConfigMigration (line 7) | class BailianRequesterConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 15) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m029_dashscope_app_api_config.py
  class DashscopeAppAPICfgMigration (line 7) | class DashscopeAppAPICfgMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m030_lark_config_cmpl.py
  class LarkConfigCmplMigration (line 7) | class LarkConfigCmplMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m031_dingtalk_config.py
  class DingTalkConfigMigration (line 7) | class DingTalkConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 20) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m032_volcark_config.py
  class VolcArkRequesterConfigMigration (line 7) | class VolcArkRequesterConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 15) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m033_dify_thinking_config.py
  class DifyThinkingConfigMigration (line 7) | class DifyThinkingConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 21) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m034_gewechat_file_url_config.py
  class GewechatFileUrlConfigMigration (line 9) | class GewechatFileUrlConfigMigration(migration.Migration):
    method need_migrate (line 12) | async def need_migrate(self) -> bool:
    method run (line 21) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m035_wxoa_mode.py
  class WxoaModeMigration (line 7) | class WxoaModeMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 19) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m036_wxoa_loading_message.py
  class WxoaLoadingMessageMigration (line 7) | class WxoaLoadingMessageMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 19) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m037_mcp_config.py
  class MCPConfigMigration (line 7) | class MCPConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m038_tg_dingtalk_markdown.py
  class TgDingtalkMarkdownMigration (line 7) | class TgDingtalkMarkdownMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 19) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m039_modelscope_cfg_completion.py
  class ModelScopeConfigCompletionMigration (line 7) | class ModelScopeConfigCompletionMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 17) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m040_ppio_config.py
  class PPIOConfigMigration (line 7) | class PPIOConfigMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 17) | async def run(self):

FILE: src/langbot/pkg/core/migrations/m041_dingtalk_card_autolayout_config.py
  class DingTalkCardAutoLayoutMigration (line 7) | class DingTalkCardAutoLayoutMigration(migration.Migration):
    method need_migrate (line 10) | async def need_migrate(self) -> bool:
    method run (line 14) | async def run(self):

FILE: src/langbot/pkg/core/note.py
  function note_class (line 11) | def note_class(name: str, number: int):
  class LaunchNote (line 23) | class LaunchNote(abc.ABC):
    method __init__ (line 32) | def __init__(self, ap: app.Application):
    method need_show (line 36) | async def need_show(self) -> bool:
    method yield_note (line 41) | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, ...

FILE: src/langbot/pkg/core/notes/n001_classic_msgs.py
  class ClassicNotes (line 9) | class ClassicNotes(note.LaunchNote):
    method need_show (line 12) | async def need_show(self) -> bool:
    method yield_note (line 15) | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, ...

FILE: src/langbot/pkg/core/notes/n002_selection_mode_on_windows.py
  class SelectionModeOnWindows (line 11) | class SelectionModeOnWindows(note.LaunchNote):
    method need_show (line 14) | async def need_show(self) -> bool:
    method yield_note (line 17) | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, ...

FILE: src/langbot/pkg/core/notes/n003_print_version.py
  class PrintVersion (line 10) | class PrintVersion(note.LaunchNote):
    method need_show (line 13) | async def need_show(self) -> bool:
    method yield_note (line 16) | async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, ...

FILE: src/langbot/pkg/core/stage.py
  function stage_class (line 16) | def stage_class(name: str):
  class BootingStage (line 24) | class BootingStage(abc.ABC):
    method run (line 30) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/stages/build_app.py
  class BuildAppStage (line 41) | class BuildAppStage(stage.BootingStage):
    method run (line 44) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/stages/genkeys.py
  class GenKeysStage (line 9) | class GenKeysStage(stage.BootingStage):
    method run (line 12) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/stages/load_config.py
  function _apply_env_overrides_to_config (line 15) | def _apply_env_overrides_to_config(cfg: dict) -> dict:
  class LoadConfigStage (line 103) | class LoadConfigStage(stage.BootingStage):
    method run (line 106) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/stages/migrate.py
  class MigrationStage (line 13) | class MigrationStage(stage.BootingStage):
    method run (line 19) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/stages/setup_logger.py
  class PersistenceHandler (line 9) | class PersistenceHandler(logging.Handler, object):
    method __init__ (line 16) | def __init__(self, name, ap: app.Application):
    method emit (line 20) | def emit(self, record):
  class SetupLoggerStage (line 36) | class SetupLoggerStage(stage.BootingStage):
    method run (line 39) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/stages/show_notes.py
  class ShowNotesStage (line 14) | class ShowNotesStage(stage.BootingStage):
    method run (line 17) | async def run(self, ap: app.Application):

FILE: src/langbot/pkg/core/taskmgr.py
  class TaskContext (line 11) | class TaskContext:
    method __init__ (line 20) | def __init__(self):
    method _log (line 24) | def _log(self, msg: str):
    method set_current_action (line 27) | def set_current_action(self, action: str):
    method trace (line 30) | def trace(
    method to_dict (line 40) | def to_dict(self) -> dict:
    method new (line 44) | def new() -> TaskContext:
    method placeholder (line 48) | def placeholder() -> TaskContext:
  class TaskWrapper (line 60) | class TaskWrapper:
    method __init__ (line 96) | def __init__(
    method assume_exception (line 119) | def assume_exception(self):
    method assume_result (line 128) | def assume_result(self):
    method to_dict (line 134) | def to_dict(self) -> dict:
    method cancel (line 163) | def cancel(self):
  class AsyncTaskManager (line 167) | class AsyncTaskManager:
    method __init__ (line 176) | def __init__(self, ap: app.Application):
    method create_task (line 180) | def create_task(
    method create_user_task (line 194) | def create_user_task(
    method wait_all (line 205) | async def wait_all(self):
    method get_all_tasks (line 208) | def get_all_tasks(self) -> list[TaskWrapper]:
    method get_tasks_dict (line 211) | def get_tasks_dict(
    method get_task_by_id (line 220) | def get_task_by_id(self, id: int) -> TaskWrapper | None:
    method cancel_by_scope (line 226) | def cancel_by_scope(self, scope: core_entities.LifecycleControlScope):
    method cancel_task (line 231) | def cancel_task(self, task_id: int):

FILE: src/langbot/pkg/discover/engine.py
  class I18nString (line 13) | class I18nString(pydantic.BaseModel):
    method to_dict (line 25) | def to_dict(self) -> dict:
  class Metadata (line 37) | class Metadata(pydantic.BaseModel):
    method __init__ (line 61) | def __init__(self, **kwargs):
  class PythonExecution (line 71) | class PythonExecution(pydantic.BaseModel):
    method __init__ (line 80) | def __init__(self, **kwargs):
  class Execution (line 87) | class Execution(pydantic.BaseModel):
  class Component (line 94) | class Component(pydantic.BaseModel):
    method __init__ (line 118) | def __init__(self, owner: str, manifest: typing.Dict[str, typing.Any],...
    method is_component_manifest (line 130) | def is_component_manifest(cls, manifest: typing.Dict[str, typing.Any])...
    method kind (line 135) | def kind(self) -> str:
    method metadata (line 140) | def metadata(self) -> Metadata:
    method spec (line 145) | def spec(self) -> typing.Dict[str, typing.Any]:
    method execution (line 150) | def execution(self) -> Execution:
    method icon_rel_path (line 155) | def icon_rel_path(self) -> str:
    method get_python_component_class (line 163) | def get_python_component_class(self) -> typing.Type[typing.Any]:
    method to_plain_dict (line 172) | def to_plain_dict(self) -> dict:
  class ComponentDiscoveryEngine (line 183) | class ComponentDiscoveryEngine:
    method __init__ (line 192) | def __init__(self, ap: app.Application):
    method load_component_manifest (line 195) | def load_component_manifest(self, path: str, owner: str = 'builtin', n...
    method load_component_manifests_in_dir (line 209) | def load_component_manifests_in_dir(
    method load_blueprint_comp_group (line 234) | def load_blueprint_comp_group(
    method discover_blueprint (line 251) | def discover_blueprint(self, blueprint_manifest_path: str, owner: str ...
    method get_components_by_kind (line 274) | def get_components_by_kind(self, kind: str) -> typing.List[Component]:
    method find_components (line 280) | def find_components(self, kind: str, component_list: typing.List[Compo...

FILE: src/langbot/pkg/entity/dto/space_model.py
  class SpaceModel (line 39) | class SpaceModel(pydantic.BaseModel):

FILE: src/langbot/pkg/entity/errors/account.py
  class AccountEmailMismatchError (line 4) | class AccountEmailMismatchError(Exception):
    method __str__ (line 5) | def __str__(self):

FILE: src/langbot/pkg/entity/errors/platform.py
  class AdapterNotFoundError (line 4) | class AdapterNotFoundError(Exception):
    method __init__ (line 5) | def __init__(self, adapter_name: str):
    method __str__ (line 8) | def __str__(self):

FILE: src/langbot/pkg/entity/errors/provider.py
  class RequesterNotFoundError (line 4) | class RequesterNotFoundError(Exception):
    method __init__ (line 5) | def __init__(self, requester_name: str):
    method __str__ (line 8) | def __str__(self):
  class ProviderNotFoundError (line 12) | class ProviderNotFoundError(Exception):
    method __init__ (line 13) | def __init__(self, provider_name: str):
    method __str__ (line 16) | def __str__(self):

FILE: src/langbot/pkg/entity/persistence/apikey.py
  class ApiKey (line 6) | class ApiKey(Base):

FILE: src/langbot/pkg/entity/persistence/base.py
  class Base (line 4) | class Base(sqlalchemy.orm.DeclarativeBase):

FILE: src/langbot/pkg/entity/persistence/bot.py
  class Bot (line 6) | class Bot(Base):

FILE: src/langbot/pkg/entity/persistence/bstorage.py
  class BinaryStorage (line 6) | class BinaryStorage(Base):

FILE: src/langbot/pkg/entity/persistence/mcp.py
  class MCPServer (line 6) | class MCPServer(Base):

FILE: src/langbot/pkg/entity/persistence/metadata.py
  class Metadata (line 15) | class Metadata(Base):

FILE: src/langbot/pkg/entity/persistence/model.py
  class ModelProvider (line 6) | class ModelProvider(Base):
  class LLMModel (line 25) | class LLMModel(Base):
  class EmbeddingModel (line 45) | class EmbeddingModel(Base):

FILE: src/langbot/pkg/entity/persistence/monitoring.py
  class MonitoringMessage (line 6) | class MonitoringMessage(Base):
  class MonitoringLLMCall (line 29) | class MonitoringLLMCall(Base):
  class MonitoringSession (line 52) | class MonitoringSession(Base):
  class MonitoringError (line 71) | class MonitoringError(Base):
  class MonitoringEmbeddingCall (line 89) | class MonitoringEmbeddingCall(Base):

FILE: src/langbot/pkg/entity/persistence/pipeline.py
  class LegacyPipeline (line 6) | class LegacyPipeline(Base):
  class PipelineRunRecord (line 33) | class PipelineRunRecord(Base):

FILE: src/langbot/pkg/entity/persistence/plugin.py
  class PluginSetting (line 6) | class PluginSetting(Base):

FILE: src/langbot/pkg/entity/persistence/rag.py
  class KnowledgeBase (line 5) | class KnowledgeBase(Base):
  class File (line 30) | class File(Base):
  class Chunk (line 40) | class Chunk(Base):

FILE: src/langbot/pkg/entity/persistence/user.py
  class User (line 6) | class User(Base):

FILE: src/langbot/pkg/entity/persistence/vector.py
  class Vector (line 7) | class Vector(Base):

FILE: src/langbot/pkg/entity/persistence/webhook.py
  class Webhook (line 6) | class Webhook(Base):

FILE: src/langbot/pkg/persistence/database.py
  function manager_class (line 13) | def manager_class(name: str) -> None:
  class BaseDatabaseManager (line 24) | class BaseDatabaseManager(abc.ABC):
    method __init__ (line 33) | def __init__(self, ap: app.Application) -> None:
    method initialize (line 37) | async def initialize(self) -> None:
    method get_engine (line 40) | def get_engine(self) -> sqlalchemy_asyncio.AsyncEngine:

FILE: src/langbot/pkg/persistence/databases/postgresql.py
  class PostgreSQLDatabaseManager (line 9) | class PostgreSQLDatabaseManager(database.BaseDatabaseManager):
    method initialize (line 12) | async def initialize(self) -> None:

FILE: src/langbot/pkg/persistence/databases/sqlite.py
  class SQLiteDatabaseManager (line 9) | class SQLiteDatabaseManager(database.BaseDatabaseManager):
    method initialize (line 12) | async def initialize(self) -> None:

FILE: src/langbot/pkg/persistence/mgr.py
  class PersistenceManager (line 24) | class PersistenceManager:
    method __init__ (line 34) | def __init__(self, ap: app.Application):
    method initialize (line 38) | async def initialize(self):
    method create_tables (line 84) | async def create_tables(self):
    method write_default_pipeline (line 104) | async def write_default_pipeline(self):
    method write_space_model_providers (line 127) | async def write_space_model_providers(self):
    method execute_async (line 164) | async def execute_async(self, *args, **kwargs) -> sqlalchemy.engine.cu...
    method get_db_engine (line 170) | def get_db_engine(self) -> sqlalchemy_asyncio.AsyncEngine:
    method serialize_model (line 173) | def serialize_model(

FILE: src/langbot/pkg/persistence/migration.py
  function migration_class (line 12) | def migration_class(number: int):
  class DBMigration (line 23) | class DBMigration(abc.ABC):
    method __init__ (line 29) | def __init__(self, ap: app.Application):
    method upgrade (line 33) | async def upgrade(self):
    method downgrade (line 38) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm001_migrate_v3_config.py
  class DBMigrateV3Config (line 17) | class DBMigrateV3Config(migration.DBMigration):
    method upgrade (line 20) | async def upgrade(self):
    method downgrade (line 251) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm002_combine_quote_msg_config.py
  class DBMigrateCombineQuoteMsgConfig (line 8) | class DBMigrateCombineQuoteMsgConfig(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 53) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm003_n8n_config.py
  class DBMigrateN8nConfig (line 8) | class DBMigrateN8nConfig(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 60) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm004_rag_kb_uuid.py
  class DBMigrateRAGKBUUID (line 8) | class DBMigrateRAGKBUUID(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 51) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm005_pipeline_remove_cot_config.py
  class DBMigratePipelineRemoveCotConfig (line 8) | class DBMigratePipelineRemoveCotConfig(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 51) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm006_langflow_api_config.py
  class DBMigrateLangflowApiConfig (line 8) | class DBMigrateLangflowApiConfig(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 56) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm007_plugin_install_source.py
  class DBMigratePluginInstallSource (line 6) | class DBMigratePluginInstallSource(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method downgrade (line 42) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm008_plugin_config.py
  class DBMigratePluginConfig (line 5) | class DBMigratePluginConfig(migration.DBMigration):
    method upgrade (line 8) | async def upgrade(self):
    method downgrade (line 20) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm009_pipeline_extension_preferences.py
  class DBMigratePipelineExtensionPreferences (line 6) | class DBMigratePipelineExtensionPreferences(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method downgrade (line 17) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm010_pipeline_multi_knowledge_base.py
  class DBMigratePipelineMultiKnowledgeBase (line 8) | class DBMigratePipelineMultiKnowledgeBase(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 59) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm011_dify_base_prompt_config.py
  class DBMigrateDifyApiConfig (line 8) | class DBMigrateDifyApiConfig(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 53) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm012_pipeline_extensions_enable_all.py
  class DBMigratePipelineExtensionsEnableAll (line 8) | class DBMigratePipelineExtensionsEnableAll(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 71) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm013_knowledge_base_updated_at.py
  class DBMigrateKnowledgeBaseUpdatedAt (line 6) | class DBMigrateKnowledgeBaseUpdatedAt(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method downgrade (line 47) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm014_space_account_support.py
  class DBMigrateSpaceAccountSupport (line 6) | class DBMigrateSpaceAccountSupport(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method downgrade (line 92) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm015_model_source_tracking.py
  class DBMigrateModelSourceTracking (line 6) | class DBMigrateModelSourceTracking(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method downgrade (line 13) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm016_model_provider_refactor.py
  class DBMigrateModelProviderRefactor (line 8) | class DBMigrateModelProviderRefactor(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method _create_providers_table (line 23) | async def _create_providers_table(self):
    method _migrate_llm_models (line 54) | async def _migrate_llm_models(self):
    method _migrate_embedding_models (line 151) | async def _migrate_embedding_models(self):
    method _cleanup_columns (line 252) | async def _cleanup_columns(self):
    method _get_columns (line 288) | async def _get_columns(self, table_name: str) -> list:
    method downgrade (line 303) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm017_move_cloud_service_url.py
  class MoveCloudServiceUrl (line 5) | class MoveCloudServiceUrl(migration.DBMigration):
    method upgrade (line 8) | async def upgrade(self):
    method downgrade (line 23) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm018_add_emoji_support.py
  class DBMigrateAddEmojiSupport (line 6) | class DBMigrateAddEmojiSupport(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method _add_emoji_to_table (line 20) | async def _add_emoji_to_table(self, table_name: str, default_emoji: str):
    method downgrade (line 56) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm019_monitoring_message_role.py
  class DBMigrateMonitoringMessageRole (line 6) | class DBMigrateMonitoringMessageRole(migration.DBMigration):
    method upgrade (line 9) | async def upgrade(self):
    method downgrade (line 18) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm020_knowledge_engine_plugin_architecture.py
  class DBMigrateKnowledgeEnginePluginArchitecture (line 6) | class DBMigrateKnowledgeEnginePluginArchitecture(migration.DBMigration):
    method upgrade (line 17) | async def upgrade(self):
    method _get_table_columns (line 27) | async def _get_table_columns(self, table_name: str) -> list[str]:
    method _table_exists (line 43) | async def _table_exists(self, table_name: str) -> bool:
    method _backup_knowledge_bases (line 60) | async def _backup_knowledge_bases(self) -> bool:
    method _check_external_knowledge_bases (line 80) | async def _check_external_knowledge_bases(self) -> bool:
    method _clear_knowledge_bases (line 100) | async def _clear_knowledge_bases(self):
    method _add_columns_to_knowledge_bases (line 104) | async def _add_columns_to_knowledge_bases(self):
    method _drop_old_columns (line 121) | async def _drop_old_columns(self):
    method _set_migration_flag (line 142) | async def _set_migration_flag(self):
    method downgrade (line 159) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm021_merge_exception_handling.py
  class DBMigrateMergeExceptionHandling (line 8) | class DBMigrateMergeExceptionHandling(migration.DBMigration):
    method upgrade (line 18) | async def upgrade(self):
    method downgrade (line 72) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm022_monitoring_user_name.py
  class DBMigrateMonitoringUserId (line 6) | class DBMigrateMonitoringUserId(migration.DBMigration):
    method _table_exists (line 13) | async def _table_exists(self, table_name: str) -> bool:
    method _get_table_columns (line 30) | async def _get_table_columns(self, table_name: str) -> list[str]:
    method _add_column_if_not_exists (line 45) | async def _add_column_if_not_exists(self, table_name: str, column_name...
    method upgrade (line 56) | async def upgrade(self):
    method downgrade (line 72) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm023_model_fallback_config.py
  class DBMigrateModelFallbackConfig (line 8) | class DBMigrateModelFallbackConfig(migration.DBMigration):
    method upgrade (line 11) | async def upgrade(self):
    method downgrade (line 63) | async def downgrade(self):

FILE: src/langbot/pkg/persistence/migrations/dbm024_wecombot_websocket_mode.py
  class DBMigrateWecomBotWebSocketMode (line 8) | class DBMigrateWecomBotWebSocketMode(migration.DBMigration):
    method upgrade (line 16) | async def upgrade(self):
    method downgrade (line 47) | async def downgrade(self):

FILE: src/langbot/pkg/pipeline/aggregator.py
  class PendingMessage (line 29) | class PendingMessage:
  class SessionBuffer (line 44) | class SessionBuffer:
  class MessageAggregator (line 53) | class MessageAggregator:
    method __init__ (line 70) | def __init__(self, ap: app.Application):
    method _get_session_id (line 75) | def _get_session_id(
    method _get_aggregation_config (line 84) | async def _get_aggregation_config(self, pipeline_uuid: typing.Optional...
    method add_message (line 118) | async def add_message(
    method _delayed_flush (line 191) | async def _delayed_flush(self, session_id: str, delay: float) -> None:
    method _flush_buffer (line 200) | async def _flush_buffer(self, session_id: str) -> None:
    method _merge_messages (line 236) | def _merge_messages(self, messages: list[PendingMessage]) -> PendingMe...
    method flush_all (line 274) | async def flush_all(self) -> None:

FILE: src/langbot/pkg/pipeline/bansess/bansess.py
  class BanSessionCheckStage (line 8) | class BanSessionCheckStage(stage.PipelineStage):
    method initialize (line 14) | async def initialize(self, pipeline_config: dict):
    method process (line 17) | async def process(self, query: pipeline_query.Query, stage_inst_name: ...

FILE: src/langbot/pkg/pipeline/cntfilter/cntfilter.py
  class ContentFilterStage (line 18) | class ContentFilterStage(stage.PipelineStage):
    method __init__ (line 34) | def __init__(self, ap: app.Application):
    method initialize (line 38) | async def initialize(self, pipeline_config: dict):
    method _pre_process (line 57) | async def _pre_process(
    method _post_process (line 92) | async def _post_process(
    method process (line 125) | async def process(self, query: pipeline_query.Query, stage_inst_name: ...

FILE: src/langbot/pkg/pipeline/cntfilter/entities.py
  class ResultLevel (line 6) | class ResultLevel(enum.Enum):
  class EnableStage (line 22) | class EnableStage(enum.Enum):
  class FilterResult (line 32) | class FilterResult(pydantic.BaseModel):
  class ManagerResultLevel (line 54) | class ManagerResultLevel(enum.Enum):
  class FilterManagerResult (line 64) | class FilterManagerResult(pydantic.BaseModel):

FILE: src/langbot/pkg/pipeline/cntfilter/filter.py
  function filter_class (line 13) | def filter_class(
  class ContentFilter (line 37) | class ContentFilter(metaclass=abc.ABCMeta):
    method __init__ (line 44) | def __init__(self, ap: app.Application):
    method enable_stages (line 48) | def enable_stages(self):
    method initialize (line 58) | async def initialize(self):
    method process (line 63) | async def process(self, query: pipeline_query.Query, message: str = No...

FILE: src/langbot/pkg/pipeline/cntfilter/filters/baiduexamine.py
  class BaiduCloudExamine (line 13) | class BaiduCloudExamine(filter_model.ContentFilter):
    method _get_token (line 16) | async def _get_token(self) -> str:
    method process (line 28) | async def process(self, query: pipeline_query.Query, message: str) -> ...

FILE: src/langbot/pkg/pipeline/cntfilter/filters/banwords.py
  class BanWordFilter (line 10) | class BanWordFilter(filter_model.ContentFilter):
    method initialize (line 13) | async def initialize(self):
    method process (line 16) | async def process(self, query: pipeline_query.Query, message: str) -> ...

FILE: src/langbot/pkg/pipeline/cntfilter/filters/cntignore.py
  class ContentIgnore (line 10) | class ContentIgnore(filter_model.ContentFilter):
    method enable_stages (line 14) | def enable_stages(self):
    method process (line 19) | async def process(self, query: pipeline_query.Query, message: str) -> ...

FILE: src/langbot/pkg/pipeline/config_coercion.py
  function _coerce_bool (line 15) | def _coerce_bool(v):
  function _coerce_value (line 27) | def _coerce_value(value, expected_type: str):
  function coerce_pipeline_config (line 53) | def coerce_pipeline_config(

FILE: src/langbot/pkg/pipeline/controller.py
  class Controller (line 12) | class Controller:
    method __init__ (line 20) | def __init__(self, ap: app.Application):
    method consumer (line 24) | async def consumer(self):
    method run (line 87) | async def run(self):

FILE: src/langbot/pkg/pipeline/entities.py
  class ResultType (line 12) | class ResultType(enum.Enum):
  class StageProcessResult (line 20) | class StageProcessResult(pydantic.BaseModel):

FILE: src/langbot/pkg/pipeline/longtext/longtext.py
  class LongTextProcessStage (line 17) | class LongTextProcessStage(stage.PipelineStage):
    method initialize (line 26) | async def initialize(self, pipeline_config: dict):
    method process (line 74) | async def process(self, query: pipeline_query.Query, stage_inst_name: ...

FILE: src/langbot/pkg/pipeline/longtext/strategies/forward.py
  class ForwardComponentStrategy (line 15) | class ForwardComponentStrategy(strategy_model.LongTextStrategy):
    method process (line 16) | async def process(self, message: str, query: pipeline_query.Query) -> ...

FILE: src/langbot/pkg/pipeline/longtext/strategies/image.py
  class Text2ImageStrategy (line 18) | class Text2ImageStrategy(strategy_model.LongTextStrategy):
    method initialize (line 19) | async def initialize(self):
    method get_font (line 23) | def get_font(self, font_path: str):
    method process (line 30) | async def process(self, message: str, query: pipeline_query.Query) -> ...
    method indexNumber (line 56) | def indexNumber(self, path=''):
    method get_size (line 95) | def get_size(self, file):
    method get_outfile (line 100) | def get_outfile(self, infile, outfile):
    method compress_image (line 107) | def compress_image(self, infile, outfile='', kb=100, step=20, quality=...
    method text_to_image (line 129) | def text_to_image(

FILE: src/langbot/pkg/pipeline/longtext/strategy.py
  function strategy_class (line 15) | def strategy_class(
  class LongTextStrategy (line 39) | class LongTextStrategy(metaclass=abc.ABCMeta):
    method __init__ (line 46) | def __init__(self, ap: app.Application):
    method initialize (line 49) | async def initialize(self):
    method process (line 53) | async def process(self, message: str, query: pipeline_query.Query) -> ...

FILE: src/langbot/pkg/pipeline/monitoring_helper.py
  class MonitoringHelper (line 19) | class MonitoringHelper:
    method record_query_start (line 23) | async def record_query_start(
    method record_query_success (line 102) | async def record_query_success(
    method record_query_response (line 129) | async def record_query_response(
    method record_query_error (line 193) | async def record_query_error(
    method record_llm_call (line 253) | async def record_llm_call(
  class LLMCallMonitor (line 292) | class LLMCallMonitor:
    method __init__ (line 295) | def __init__(
    method __aenter__ (line 316) | async def __aenter__(self):
    method __aexit__ (line 320) | async def __aexit__(self, exc_type, exc_val, exc_tb):

FILE: src/langbot/pkg/pipeline/msgtrun/msgtrun.py
  class ConversationMessageTruncator (line 13) | class ConversationMessageTruncator(stage.PipelineStage):
    method initialize (line 21) | async def initialize(self, pipeline_config: dict):
    method process (line 31) | async def process(self, query: pipeline_query.Query, stage_inst_name: ...

FILE: src/langbot/pkg/pipeline/msgtrun/truncator.py
  function truncator_class (line 12) | def truncator_class(
  class Truncator (line 36) | class Truncator(abc.ABC):
    method __init__ (line 43) | def __init__(self, ap: app.Application):
    method initialize (line 46) | async def initialize(self):
    method truncate (line 50) | async def truncate(self, query: pipeline_query.Query) -> pipeline_quer...

FILE: src/langbot/pkg/pipeline/msgtrun/truncators/round.py
  class RoundTruncator (line 8) | class RoundTruncator(truncator.Truncator):
    method truncate (line 11) | async def truncate(self, query: pipeline_query.Query) -> pipeline_quer...

FILE: src/langbot/pkg/pipeline/pipelinemgr.py
  class StageInstContainer (line 50) | class StageInstContainer:
    method __init__ (line 57) | def __init__(self, inst_name: str, inst: stage.PipelineStage):
  class RuntimePipeline (line 62) | class RuntimePipeline:
    method __init__ (line 85) | def __init__(
    method run (line 114) | async def run(self, query: pipeline_query.Query):
    method _check_output (line 140) | async def _check_output(self, query: pipeline_query.Query, result: pip...
    method _execute_from_stage (line 206) | async def _execute_from_stage(
    method process_query (line 273) | async def process_query(self, query: pipeline_query.Query):
  class PipelineManager (line 384) | class PipelineManager:
    method __init__ (line 393) | def __init__(self, ap: app.Application):
    method initialize (line 397) | async def initialize(self):
    method load_pipelines_from_db (line 402) | async def load_pipelines_from_db(self):
    method load_pipeline (line 413) | async def load_pipeline(
    method get_pipeline_by_uuid (line 443) | async def get_pipeline_by_uuid(self, uuid: str) -> RuntimePipeline | N...
    method remove_pipeline (line 449) | async def remove_pipeline(self, uuid: str):

FILE: src/langbot/pkg/pipeline/pool.py
  class QueryPool (line 13) | class QueryPool:
    method __init__ (line 27) | def __init__(self):
    method add_query (line 34) | async def add_query(
    method __aenter__ (line 66) | async def __aenter__(self):
    method __aexit__ (line 70) | async def __aexit__(self, exc_type, exc_val, exc_tb):

FILE: src/langbot/pkg/pipeline/preproc/preproc.py
  class PreProcessor (line 14) | class PreProcessor(stage.PipelineStage):
    method process (line 28) | async def process(

FILE: src/langbot/pkg/pipeline/process/handler.py
  class MessageHandler (line 10) | class MessageHandler(metaclass=abc.ABCMeta):
    method __init__ (line 13) | def __init__(self, ap: app.Application):
    method initialize (line 16) | async def initialize(self):
    method handle (line 20) | async def handle(
    method cut_str (line 26) | def cut_str(self, s: str) -> str:

FILE: src/langbot/pkg/pipeline/process/handlers/chat.py
  class ChatMessageHandler (line 25) | class ChatMessageHandler(handler.MessageHandler):
    method handle (line 26) | async def handle(

FILE: src/langbot/pkg/pipeline/process/handlers/command.py
  class CommandHandler (line 13) | class CommandHandler(handler.MessageHandler):
    method handle (line 14) | async def handle(

FILE: src/langbot/pkg/pipeline/process/process.py
  class Processor (line 11) | class Processor(stage.PipelineStage):
    method initialize (line 24) | async def initialize(self, pipeline_config: dict):
    method process (line 31) | async def process(

FILE: src/langbot/pkg/pipeline/ratelimit/algo.py
  function algo_class (line 12) | def algo_class(name: str):
  class ReteLimitAlgo (line 21) | class ReteLimitAlgo(metaclass=abc.ABCMeta):
    method __init__ (line 28) | def __init__(self, ap: app.Application):
    method initialize (line 31) | async def initialize(self):
    method require_access (line 35) | async def require_access(
    method release_access (line 55) | async def release_access(

FILE: src/langbot/pkg/pipeline/ratelimit/algos/fixedwin.py
  class SessionContainer (line 10) | class SessionContainer:
    method __init__ (line 16) | def __init__(self):
  class FixedWindowAlgo (line 22) | class FixedWindowAlgo(algo.ReteLimitAlgo):
    method initialize (line 29) | async def initialize(self):
    method require_access (line 33) | async def require_access(
    method release_access (line 92) | async def release_access(

FILE: src/langbot/pkg/pipeline/ratelimit/ratelimit.py
  class RateLimit (line 18) | class RateLimit(stage.PipelineStage):
    method initialize (line 26) | async def initialize(self, pipeline_config: dict):
    method process (line 41) | async def process(

FILE: src/langbot/pkg/pipeline/respback/respback.py
  class SendResponseBackStage (line 16) | class SendResponseBackStage(stage.PipelineStage):
    method process (line 19) | async def process(self, query: pipeline_query.Query, stage_inst_name: ...

FILE: src/langbot/pkg/pipeline/resprule/entities.py
  class RuleJudgeResult (line 6) | class RuleJudgeResult(pydantic.BaseModel):

FILE: src/langbot/pkg/pipeline/resprule/resprule.py
  class GroupRespondRuleCheckStage (line 17) | class GroupRespondRuleCheckStage(stage.PipelineStage):
    method initialize (line 26) | async def initialize(self, pipeline_config: dict):
    method process (line 36) | async def process(self, query: pipeline_query.Query, stage_inst_name: ...

FILE: src/langbot/pkg/pipeline/resprule/rule.py
  function rule_class (line 15) | def rule_class(name: str):
  class GroupRespondRule (line 24) | class GroupRespondRule(metaclass=abc.ABCMeta):
    method __init__ (line 31) | def __init__(self, ap: app.Application):
    method initialize (line 34) | async def initialize(self):
    method match (line 38) | async def match(

FILE: src/langbot/pkg/pipeline/resprule/rules/atbot.py
  class AtBotRule (line 11) | class AtBotRule(rule_model.GroupRespondRule):
    method match (line 12) | async def match(

FILE: src/langbot/pkg/pipeline/resprule/rules/prefix.py
  class PrefixRule (line 8) | class PrefixRule(rule_model.GroupRespondRule):
    method match (line 9) | async def match(

FILE: src/langbot/pkg/pipeline/resprule/rules/random.py
  class RandomRespRule (line 11) | class RandomRespRule(rule_model.GroupRespondRule):
    method match (line 12) | async def match(

FILE: src/langbot/pkg/pipeline/resprule/rules/regexp.py
  class RegExpRule (line 11) | class RegExpRule(rule_model.GroupRespondRule):
    method match (line 12) | async def match(

FILE: src/langbot/pkg/pipeline/stage.py
  function stage_class (line 14) | def stage_class(name: str) -> typing.Callable[[type[PipelineStage]], typ...
  class PipelineStage (line 22) | class PipelineStage(metaclass=abc.ABCMeta):
    method __init__ (line 27) | def __init__(self, ap: app.Application):
    method initialize (line 30) | async def initialize(self, pipeline_config: dict):
    method process (line 35) | async def process(

FILE: src/langbot/pkg/pipeline/wrapper/wrapper.py
  class ResponseWrapper (line 14) | class ResponseWrapper(stage.PipelineStage):
    method initialize (line 23) | async def initialize(self, pipeline_config: dict):
    method process (line 26) | async def process(

FILE: src/langbot/pkg/platform/botmgr.py
  class RuntimeBot (line 23) | class RuntimeBot:
    method __init__ (line 40) | def __init__(
    method initialize (line 54) | async def initialize(self):
    method run (line 144) | async def run(self):
    method shutdown (line 170) | async def shutdown(self):
  class PlatformManager (line 177) | class PlatformManager:
    method __init__ (line 189) | def __init__(self, ap: app.Application = None):
    method initialize (line 195) | async def initialize(self):
    method get_running_adapters (line 231) | def get_running_adapters(self) -> list[abstract_platform_adapter.Abstr...
    method load_bots_from_db (line 234) | async def load_bots_from_db(self):
    method load_bot (line 252) | async def load_bot(
    method get_bot_by_uuid (line 284) | async def get_bot_by_uuid(self, bot_uuid: str) -> RuntimeBot | None:
    method remove_bot (line 292) | async def remove_bot(self, bot_uuid: str):
    method get_available_adapters_info (line 300) | def get_available_adapters_info(self) -> list[dict]:
    method get_available_adapter_info_by_name (line 305) | def get_available_adapter_info_by_name(self, name: str) -> dict | None:
    method get_available_adapter_manifest_by_name (line 311) | def get_available_adapter_manifest_by_name(self, name: str) -> engine....
    method run (line 317) | async def run(self):
    method shutdown (line 325) | async def shutdown(self):

FILE: src/langbot/pkg/platform/logger.py
  class EventLogLevel (line 16) | class EventLogLevel(enum.Enum):
  class EventLog (line 25) | class EventLog(pydantic.BaseModel):
    method to_json (line 44) | def to_json(self) -> dict:
  class EventLogger (line 59) | class EventLogger(abstract_platform_event_logger.AbstractEventLogger):
    method __init__ (line 68) | def __init__(
    method get_logs (line 78) | async def get_logs(self, from_seq_id: int, max_count: int) -> typing.T...
    method _truncate_logs (line 120) | async def _truncate_logs(self):
    method _add_log (line 127) | async def _add_log(
    method info (line 176) | async def info(
    method debug (line 191) | async def debug(
    method warning (line 206) | async def warning(
    method error (line 221) | async def error(

FILE: src/langbot/pkg/platform/sources/aiocqhttp.py
  class AiocqhttpMessageConverter (line 18) | class AiocqhttpMessageConverter(abstract_platform_adapter.AbstractMessag...
    method yiri2target (line 20) | async def yiri2target(
    method target2yiri (line 79) | async def target2yiri(message: str, message_id: int = -1, bot: aiocqht...
  class AiocqhttpEventConverter (line 302) | class AiocqhttpEventConverter(abstract_platform_adapter.AbstractEventCon...
    method yiri2target (line 304) | async def yiri2target(event: platform_events.MessageEvent, bot_account...
    method target2yiri (line 308) | async def target2yiri(event: aiocqhttp.Event, bot=None):
  class AiocqhttpAdapter (line 349) | class AiocqhttpAdapter(abstract_platform_adapter.AbstractMessagePlatform...
    method __init__ (line 357) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method send_message (line 377) | async def send_message(self, target_type: str, target_id: str, message...
    method _send_forward_message (line 397) | async def _send_forward_message(self, group_id: int, forward: platform...
    method reply_message (line 481) | async def reply_message(
    method is_muted (line 494) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 497) | def register_listener(
    method unregister_listener (line 530) | def unregister_listener(
    method run_async (line 539) | async def run_async(self):
    method kill (line 542) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/dingtalk.py
  class DingTalkMessageConverter (line 13) | class DingTalkMessageConverter(abstract_platform_adapter.AbstractMessage...
    method _format_image_as_markdown (line 15) | def _format_image_as_markdown(msg: platform_message.Image) -> str:
    method yiri2target (line 29) | async def yiri2target(message_chain: platform_message.MessageChain, ma...
    method target2yiri (line 53) | async def target2yiri(event: DingTalkEvent, bot_name: str):
  class DingTalkEventConverter (line 91) | class DingTalkEventConverter(abstract_platform_adapter.AbstractEventConv...
    method yiri2target (line 93) | async def yiri2target(event: platform_events.MessageEvent):
    method target2yiri (line 97) | async def target2yiri(event: DingTalkEvent, bot_name: str):
  class DingTalkAdapter (line 132) | class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformA...
    method __init__ (line 142) | def __init__(self, config: dict, logger: EventLogger):
    method reply_message (line 170) | async def reply_message(
    method reply_message_chunk (line 185) | async def reply_message_chunk(
    method send_message (line 216) | async def send_message(self, target_type: str, target_id: str, message...
    method is_stream_output_supported (line 224) | async def is_stream_output_supported(self) -> bool:
    method create_message_card (line 230) | async def create_message_card(self, message_id, event):
    method register_listener (line 241) | def register_listener(
    method run_async (line 262) | async def run_async(self):
    method kill (line 265) | async def kill(self) -> bool:
    method is_muted (line 269) | async def is_muted(self) -> bool:
    method unregister_listener (line 272) | async def unregister_listener(

FILE: src/langbot/pkg/platform/sources/discord.py
  class VoiceConnectionError (line 29) | class VoiceConnectionError(Exception):
    method __init__ (line 32) | def __init__(self, message: str, error_code: str = None, guild_id: int...
  class VoicePermissionError (line 39) | class VoicePermissionError(VoiceConnectionError):
    method __init__ (line 42) | def __init__(self, message: str, missing_permissions: list = None, use...
  class VoiceNetworkError (line 49) | class VoiceNetworkError(VoiceConnectionError):
    method __init__ (line 52) | def __init__(self, message: str, retry_count: int = 0):
  class VoiceConnectionStatus (line 58) | class VoiceConnectionStatus(Enum):
  class VoiceConnectionInfo (line 69) | class VoiceConnectionInfo:
    method __init__ (line 81) | def __init__(self, guild_id: int, channel_id: int, channel_name: str =...
    method update_status (line 104) | def update_status(self, status: VoiceConnectionStatus):
    method to_dict (line 125) | def to_dict(self) -> dict:
  class VoiceConnectionManager (line 148) | class VoiceConnectionManager:
    method __init__ (line 160) | def __init__(self, bot: discord.Client, logger: EventLogger):
    method join_voice_channel (line 177) | async def join_voice_channel(self, guild_id: int, channel_id: int, use...
    method leave_voice_channel (line 250) | async def leave_voice_channel(self, guild_id: int) -> bool:
    method _disconnect_internal (line 268) | async def _disconnect_internal(self, guild_id: int) -> bool:
    method get_voice_client (line 311) | async def get_voice_client(self, guild_id: int) -> typing.Optional[dis...
    method is_connected_to_voice (line 339) | async def is_connected_to_voice(self, guild_id: int) -> bool:
    method get_connection_status (line 364) | async def get_connection_status(self, guild_id: int) -> typing.Optiona...
    method list_active_connections (line 395) | async def list_active_connections(self) -> typing.List[dict]:
    method get_voice_channel_info (line 414) | async def get_voice_channel_info(self, guild_id: int, channel_id: int)...
    method _validate_user_in_channel (line 463) | async def _validate_user_in_channel(self, guild: discord.Guild, channe...
    method _validate_bot_permissions (line 489) | async def _validate_bot_permissions(self, channel: discord.VoiceChannel):
    method cleanup_inactive_connections (line 518) | async def cleanup_inactive_connections(self):
    method start_monitoring (line 538) | async def start_monitoring(self):
    method stop_monitoring (line 547) | async def stop_monitoring(self):
    method _monitoring_loop (line 562) | async def _monitoring_loop(self):
    method disconnect_all (line 575) | async def disconnect_all(self):
  class DiscordMessageConverter (line 589) | class DiscordMessageConverter(abstract_platform_adapter.AbstractMessageC...
    method yiri2target (line 591) | async def yiri2target(
    method target2yiri (line 737) | async def target2yiri(message: discord.Message) -> platform_message.Me...
  class DiscordEventConverter (line 788) | class DiscordEventConverter(abstract_platform_adapter.AbstractEventConve...
    method yiri2target (line 790) | async def yiri2target(event: platform_events.Event) -> discord.Message:
    method target2yiri (line 794) | async def target2yiri(event: discord.Message) -> platform_events.Event:
  class DiscordAdapter (line 827) | class DiscordAdapter(abstract_platform_adapter.AbstractMessagePlatformAd...
    method __init__ (line 840) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method join_voice_channel (line 879) | async def join_voice_channel(self, guild_id: int, channel_id: int, use...
    method leave_voice_channel (line 907) | async def leave_voice_channel(self, guild_id: int) -> bool:
    method get_voice_client (line 928) | async def get_voice_client(self, guild_id: int) -> typing.Optional[dis...
    method is_connected_to_voice (line 949) | async def is_connected_to_voice(self, guild_id: int) -> bool:
    method get_voice_connection_status (line 968) | async def get_voice_connection_status(self, guild_id: int) -> typing.O...
    method list_active_voice_connections (line 989) | async def list_active_voice_connections(self) -> typing.List[dict]:
    method get_voice_channel_info (line 1005) | async def get_voice_channel_info(self, guild_id: int, channel_id: int)...
    method cleanup_voice_connections (line 1027) | async def cleanup_voice_connections(self):
    method send_message (line 1040) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 1063) | async def reply_message(
    method is_muted (line 1095) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 1098) | def register_listener(
    method unregister_listener (line 1107) | def unregister_listener(
    method run_async (line 1116) | async def run_async(self):
    method kill (line 1132) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/kook.py
  class KookMessageConverter (line 24) | class KookMessageConverter(abstract_platform_adapter.AbstractMessageConv...
    method yiri2target (line 28) | async def yiri2target(message_chain: platform_message.MessageChain) ->...
    method target2yiri (line 67) | async def target2yiri(kook_message: dict, bot_account_id: str = '') ->...
  class KookEventConverter (line 162) | class KookEventConverter(abstract_platform_adapter.AbstractEventConverter):
    method yiri2target (line 166) | async def yiri2target(event: platform_events.MessageEvent):
    method target2yiri (line 171) | async def target2yiri(kook_event: dict, bot_account_id: str = '') -> p...
  class KookAdapter (line 247) | class KookAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapt...
    method __init__ (line 272) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method _get_gateway_url (line 289) | async def _get_gateway_url(self) -> str:
    method _get_bot_user_info (line 312) | async def _get_bot_user_info(self) -> dict:
    method _handle_hello (line 332) | async def _handle_hello(self, data: dict):
    method _handle_event (line 338) | async def _handle_event(self, data: dict, sn: int):
    method _handle_pong (line 364) | async def _handle_pong(self, data: dict):
    method _heartbeat_loop (line 369) | async def _heartbeat_loop(self):
    method _websocket_loop (line 390) | async def _websocket_loop(self):
    method send_message (line 486) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 529) | async def reply_message(
    method is_muted (line 595) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 599) | def register_listener(
    method unregister_listener (line 609) | def unregister_listener(
    method run_async (line 619) | async def run_async(self):
    method kill (line 651) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/lark.py
  class AESCipher (line 36) | class AESCipher(object):
    method __init__ (line 37) | def __init__(self, key):
    method str_to_bytes (line 42) | def str_to_bytes(data):
    method _unpad (line 49) | def _unpad(s):
    method decrypt (line 52) | def decrypt(self, enc):
    method decrypt_string (line 57) | def decrypt_string(self, enc):
  class LarkMessageConverter (line 62) | class LarkMessageConverter(abstract_platform_adapter.AbstractMessageConv...
    method upload_image_to_lark (line 64) | async def upload_image_to_lark(msg: platform_message.Image, api_client...
    method upload_file_to_lark (line 145) | async def upload_file_to_lark(
    method _get_media_bytes (line 195) | async def _get_media_bytes(
    method yiri2target (line 227) | async def yiri2target(
    method target2yiri (line 354) | async def target2yiri(
  class LarkEventConverter (line 577) | class LarkEventConverter(abstract_platform_adapter.AbstractEventConverter):
    method _prune_processed_thread_quote_cache (line 583) | def _prune_processed_thread_quote_cache(cls, now: typing.Optional[floa...
    method _mark_thread_quote_processed (line 599) | def _mark_thread_quote_processed(cls, thread_id: str) -> None:
    method _extract_quote_message_id (line 605) | def _extract_quote_message_id(cls, message: EventMessage) -> typing.Op...
    method _build_event_message_from_message_item (line 634) | def _build_event_message_from_message_item(message_item: Message) -> t...
    method _fetch_quoted_message (line 669) | async def _fetch_quoted_message(
    method yiri2target (line 700) | async def yiri2target(
    method target2yiri (line 706) | async def target2yiri(
  class LarkAdapter (line 762) | class LarkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapt...
    method __init__ (line 789) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method request_app_ticket (line 826) | def request_app_ticket(self, api_client, config):
    method request_app_access_token (line 842) | def request_app_access_token(self):
    method get_app_access_token (line 866) | def get_app_access_token(self):
    method request_tenant_access_token (line 877) | def request_tenant_access_token(self, tenant_key: str):
    method get_tenant_access_token (line 903) | def get_tenant_access_token(self, tenant_key: str):
    method get_launcher_id (line 911) | def get_launcher_id(self, event: platform_events.MessageEvent) -> str ...
    method build_api_client (line 937) | def build_api_client(self, config):
    method send_message (line 947) | async def send_message(self, target_type: str, target_id: str, message...
    method is_stream_output_supported (line 950) | async def is_stream_output_supported(self) -> bool:
    method create_card_id (line 956) | async def create_card_id(self, message_id):
    method create_message_card (line 1154) | async def create_message_card(self, message_id, event) -> str:
    method reply_message (line 1195) | async def reply_message(
    method reply_message_chunk (line 1304) | async def reply_message_chunk(
    method is_muted (line 1402) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 1405) | def register_listener(
    method unregister_listener (line 1414) | def unregister_listener(
    method set_bot_uuid (line 1423) | def set_bot_uuid(self, bot_uuid: str):
    method get_event_type (line 1427) | def get_event_type(self, data):
    method handle_unified_webhook (line 1438) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 1526) | async def run_async(self):
    method kill (line 1550) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/legacy/gewechat.py
  class GewechatMessageConverter (line 26) | class GewechatMessageConverter(abstract_platform_adapter.AbstractMessage...
    method __init__ (line 27) | def __init__(self, config: dict):
    method yiri2target (line 31) | async def yiri2target(message_chain: platform_message.MessageChain) ->...
    method target2yiri (line 107) | async def target2yiri(self, message: dict, bot_account_id: str) -> pla...
    method _handler_text (line 145) | async def _handler_text(self, message: Optional[dict], content_no_prei...
    method _handler_image (line 153) | async def _handler_image(self, message: Optional[dict], content_no_pre...
    method _handler_voice (line 178) | async def _handler_voice(self, message: Optional[dict], content_no_pre...
    method _handler_compound (line 203) | async def _handler_compound(self, message: Optional[dict], content_no_...
    method _handler_compound_quote (line 234) | async def _handler_compound_quote(
    method _handler_compound_file (line 293) | async def _handler_compound_file(self, message: dict, xml_data: ET.Ele...
    method _handler_compound_link (line 298) | async def _handler_compound_link(self, message: dict, xml_data: ET.Ele...
    method _handler_compound_mini_program (line 322) | async def _handler_compound_mini_program(
    method _handler_default (line 329) | async def _handler_default(self, message: Optional[dict], content_no_p...
    method _handler_compound_unsupported (line 337) | def _handler_compound_unsupported(
    method _ats_bot (line 349) | def _ats_bot(self, message: dict, bot_account_id: str) -> bool:
    method _extract_content_and_sender (line 380) | def _extract_content_and_sender(self, raw_content: str) -> Tuple[str, ...
    method _is_group_message (line 396) | def _is_group_message(self, message: dict) -> bool:
  class GewechatEventConverter (line 401) | class GewechatEventConverter(abstract_platform_adapter.AbstractEventConv...
    method __init__ (line 402) | def __init__(self, config: dict):
    method yiri2target (line 407) | async def yiri2target(event: platform_events.MessageEvent) -> dict:
    method target2yiri (line 410) | async def target2yiri(self, event: dict, bot_account_id: str) -> platf...
  class GeWeChatAdapter (line 458) | class GeWeChatAdapter(abstract_platform_adapter.AbstractMessagePlatformA...
    method __init__ (line 478) | def __init__(self, config: dict, ap: app.Application, logger: EventLog...
    method _handle_message (line 512) | async def _handle_message(self, message: platform_message.MessageChain...
    method send_message (line 604) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 608) | async def reply_message(
    method is_muted (line 619) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 622) | def register_listener(
    method unregister_listener (line 631) | def unregister_listener(
    method run_async (line 640) | async def run_async(self):
    method kill (line 687) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/legacy/nakuru.py
  class NakuruProjectMessageConverter (line 20) | class NakuruProjectMessageConverter(abstract_platform_adapter.AbstractMe...
    method yiri2target (line 24) | def yiri2target(message_chain: platform_message.MessageChain) -> list:
    method target2yiri (line 87) | def target2yiri(message_chain: typing.Any, message_id: int = -1) -> pl...
  class NakuruProjectEventConverter (line 112) | class NakuruProjectEventConverter(abstract_platform_adapter.AbstractEven...
    method yiri2target (line 116) | def yiri2target(event: typing.Type[platform_events.Event]):
    method target2yiri (line 125) | def target2yiri(event: typing.Any) -> platform_events.Event:
  class NakuruAdapter (line 164) | class NakuruAdapter(abstract_platform_adapter.AbstractMessagePlatformAda...
    method __init__ (line 179) | def __init__(self, cfg: dict, ap, logger: EventLogger):
    method send_message (line 189) | async def send_message(
    method reply_message (line 224) | async def reply_message(
    method is_muted (line 246) | def is_muted(self, group_id: int) -> bool:
    method register_listener (line 253) | def register_listener(
    method unregister_listener (line 282) | def unregister_listener(
    method run_async (line 310) | async def run_async(self):
    method kill (line 329) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/legacy/qqbotpy.py
  class OfficialGroupMessage (line 23) | class OfficialGroupMessage(platform_events.GroupMessage):
  class OfficialFriendMessage (line 27) | class OfficialFriendMessage(platform_events.FriendMessage):
  function save_msg_id (line 49) | def save_msg_id(message_id: str) -> int:
  function char_to_value (line 59) | def char_to_value(char):
  function digest (line 69) | def digest(s: str) -> int:
  class OpenIDMapping (line 87) | class OpenIDMapping(typing.Generic[K, V]):
    method __init__ (line 94) | def __init__(
    method __getitem__ (line 106) | def __getitem__(self, key: K) -> V:
    method __setitem__ (line 109) | def __setitem__(self, key: K, value: V):
    method __contains__ (line 113) | def __contains__(self, key: K) -> bool:
    method __delitem__ (line 116) | def __delitem__(self, key: K):
    method getkey (line 120) | def getkey(self, value: V) -> K:
    method save_openid (line 123) | def save_openid(self, key: K) -> V:
  class OfficialMessageConverter (line 136) | class OfficialMessageConverter(abstract_platform_adapter.AbstractMessage...
    method yiri2target (line 140) | def yiri2target(message_chain: platform_message.MessageChain):
    method extract_message_chain_from_obj (line 200) | def extract_message_chain_from_obj(
  class OfficialEventConverter (line 240) | class OfficialEventConverter(abstract_platform_adapter.AbstractEventConv...
    method __init__ (line 243) | def __init__(self):
    method yiri2target (line 246) | def yiri2target(self, event: typing.Type[platform_events.Event]):
    method target2yiri (line 254) | def target2yiri(
  class OfficialAdapter (line 328) | class OfficialAdapter(abstract_platform_adapter.AbstractMessagePlatformA...
    method __init__ (line 353) | def __init__(self, cfg: dict, ap: app.Application, logger: EventLogger):
    method send_message (line 373) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 397) | async def reply_message(
    method is_muted (line 473) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 476) | def register_listener(
    method unregister_listener (line 501) | def unregister_listener(
    method run_async (line 510) | async def run_async(self):
    method kill (line 521) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/line.py
  class LINEMessageConverter (line 34) | class LINEMessageConverter(abstract_platform_adapter.AbstractMessageConv...
    method yiri2target (line 36) | async def yiri2target(message_chain: platform_message.MessageChain, ap...
    method target2yiri (line 53) | async def target2yiri(message, bot_client) -> platform_message.Message...
  class LINEEventConverter (line 77) | class LINEEventConverter(abstract_platform_adapter.AbstractEventConverter):
    method yiri2target (line 79) | async def yiri2target(
    method target2yiri (line 85) | async def target2yiri(event, bot_client) -> platform_events.Event:
  class LINEAdapter (line 118) | class LINEAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapt...
    method __init__ (line 139) | def __init__(self, config: dict, logger: EventLogger):
    method send_message (line 163) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 166) | async def reply_message(
    method is_muted (line 192) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 195) | def register_listener(
    method unregister_listener (line 204) | def unregister_listener(
    method set_bot_uuid (line 213) | def set_bot_uuid(self, bot_uuid: str):
    method handle_unified_webhook (line 217) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 257) | async def run_async(self):
    method kill (line 268) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/officialaccount.py
  class OAMessageConverter (line 17) | class OAMessageConverter(abstract_platform_adapter.AbstractMessageConver...
    method yiri2target (line 19) | async def yiri2target(message_chain: platform_message.MessageChain):
    method target2yiri (line 25) | async def target2yiri(message: str, message_id=-1):
  class OAEventConverter (line 35) | class OAEventConverter(abstract_platform_adapter.AbstractEventConverter):
    method target2yiri (line 37) | async def target2yiri(event: OAEvent):
  class OfficialAccountAdapter (line 57) | class OfficialAccountAdapter(abstract_platform_adapter.AbstractMessagePl...
    method __init__ (line 63) | def __init__(self, config: dict, logger: EventLogger):
    method reply_message (line 104) | async def reply_message(
    method send_message (line 117) | async def send_message(self, target_type: str, target_id: str, message...
    method register_listener (line 120) | def register_listener(
    method set_bot_uuid (line 139) | def set_bot_uuid(self, bot_uuid: str):
    method handle_unified_webhook (line 143) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 156) | async def run_async(self):
    method kill (line 166) | async def kill(self) -> bool:
    method unregister_listener (line 169) | async def unregister_listener(
    method is_muted (line 178) | async def is_muted(

FILE: src/langbot/pkg/platform/sources/qqofficial.py
  class QQOfficialMessageConverter (line 18) | class QQOfficialMessageConverter(abstract_platform_adapter.AbstractMessa...
    method yiri2target (line 20) | async def yiri2target(message_chain: platform_message.MessageChain):
    method target2yiri (line 35) | async def target2yiri(message: str, message_id: str, pic_url: str, con...
  class QQOfficialEventConverter (line 47) | class QQOfficialEventConverter(abstract_platform_adapter.AbstractEventCo...
    method yiri2target (line 49) | async def yiri2target(event: platform_events.MessageEvent) -> QQOffici...
    method target2yiri (line 53) | async def target2yiri(event: QQOfficialEvent):
  class QQOfficialAdapter (line 127) | class QQOfficialAdapter(abstract_platform_adapter.AbstractMessagePlatfor...
    method __init__ (line 135) | def __init__(self, config: dict, logger: EventLogger):
    method reply_message (line 147) | async def reply_message(
    method send_message (line 199) | async def send_message(self, target_type: str, target_id: str, message...
    method register_listener (line 202) | def register_listener(
    method set_bot_uuid (line 223) | def set_bot_uuid(self, bot_uuid: str):
    method handle_unified_webhook (line 227) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 240) | async def run_async(self):
    method kill (line 250) | async def kill(self) -> bool:
    method unregister_listener (line 253) | def unregister_listener(

FILE: src/langbot/pkg/platform/sources/satori.py
  class SatoriMessageConverter (line 23) | class SatoriMessageConverter(abstract_platform_adapter.AbstractMessageCo...
    method yiri2target (line 27) | async def yiri2target(message_chain: platform_message.MessageChain, ad...
    method target2yiri (line 104) | async def target2yiri(
  class SatoriEventConverter (line 226) | class SatoriEventConverter(abstract_platform_adapter.AbstractEventConver...
    method _ensure_string (line 230) | def _ensure_string(value: typing.Any, default: str = '') -> str:
    method target2yiri (line 239) | async def target2yiri(
  class SatoriAdapter (line 386) | class SatoriAdapter(abstract_platform_adapter.AbstractMessagePlatformAda...
    method __init__ (line 411) | def __init__(
    method _is_websocket_closed (line 435) | def _is_websocket_closed(self, ws) -> bool:
    method run (line 448) | async def run(self):
    method connect_websocket (line 486) | async def connect_websocket(self):
    method send_identify (line 535) | async def send_identify(self):
    method heartbeat_loop (line 561) | async def heartbeat_loop(self):
    method handle_message (line 584) | async def handle_message(self, message: str):
    method handle_event (line 625) | async def handle_event(self, event_data: dict):
    method convert_satori_message (line 650) | async def convert_satori_message(
    method send_http_request (line 807) | async def send_http_request(
    method upload_image (line 843) | async def upload_image(
    method kill (line 909) | async def kill(self) -> bool:
    method send_message (line 924) | async def send_message(
    method reply_message (line 987) | async def reply_message(
    method is_muted (line 1055) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 1059) | def register_listener(
    method unregister_listener (line 1073) | def unregister_listener(
    method run_async (line 1088) | async def run_async(self):

FILE: src/langbot/pkg/platform/sources/slack.py
  class SlackMessageConverter (line 19) | class SlackMessageConverter(abstract_platform_adapter.AbstractMessageCon...
    method yiri2target (line 21) | async def yiri2target(message_chain: platform_message.MessageChain):
    method target2yiri (line 45) | async def target2yiri(message: str, message_id: str, pic_url: str, bot...
  class SlackEventConverter (line 57) | class SlackEventConverter(abstract_platform_adapter.AbstractEventConvert...
    method yiri2target (line 59) | async def yiri2target(event: platform_events.MessageEvent) -> SlackEvent:
    method target2yiri (line 63) | async def target2yiri(event: SlackEvent, bot: SlackClient):
  class SlackAdapter (line 94) | class SlackAdapter(abstract_platform_adapter.AbstractMessagePlatformAdap...
    method __init__ (line 102) | def __init__(self, config: dict, logger: EventLogger):
    method reply_message (line 122) | async def reply_message(
    method send_message (line 141) | async def send_message(self, target_type: str, target_id: str, message...
    method register_listener (line 152) | def register_listener(
    method set_bot_uuid (line 171) | def set_bot_uuid(self, bot_uuid: str):
    method handle_unified_webhook (line 175) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 188) | async def run_async(self):
    method kill (line 197) | async def kill(self) -> bool:
    method unregister_listener (line 200) | async def unregister_listener(

FILE: src/langbot/pkg/platform/sources/telegram.py
  class TelegramMessageConverter (line 23) | class TelegramMessageConverter(abstract_platform_adapter.AbstractMessage...
    method yiri2target (line 25) | async def yiri2target(message_chain: platform_message.MessageChain, bo...
    method target2yiri (line 52) | async def target2yiri(message: telegram.Message, bot: telegram.Bot, bo...
  class TelegramEventConverter (line 110) | class TelegramEventConverter(abstract_platform_adapter.AbstractEventConv...
    method yiri2target (line 112) | async def yiri2target(event: platform_events.MessageEvent, bot: telegr...
    method target2yiri (line 116) | async def target2yiri(event: Update, bot: telegram.Bot, bot_account_id...
  class TelegramAdapter (line 149) | class TelegramAdapter(abstract_platform_adapter.AbstractMessagePlatformA...
    method __init__ (line 167) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method send_message (line 195) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 222) | async def reply_message(
    method _process_markdown (line 254) | def _process_markdown(self, text: str) -> str:
    method _build_message_args (line 259) | def _build_message_args(self, chat_id: int, text: str, message_thread_...
    method create_message_card (line 267) | async def create_message_card(self, message_id, event):
    method reply_message_chunk (line 287) | async def reply_message_chunk(
    method get_launcher_id (line 337) | def get_launcher_id(self, event: platform_events.MessageEvent) -> str ...
    method is_stream_output_supported (line 355) | async def is_stream_output_supported(self) -> bool:
    method is_muted (line 361) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 364) | def register_listener(
    method unregister_listener (line 373) | def unregister_listener(
    method run_async (line 382) | async def run_async(self):
    method kill (line 389) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/websocket_adapter.py
  class WebSocketMessage (line 21) | class WebSocketMessage(pydantic.BaseModel):
  class WebSocketSession (line 34) | class WebSocketSession:
    method __init__ (line 43) | def __init__(self, id: str):
    method get_message_list (line 48) | def get_message_list(self, pipeline_uuid: str) -> list[WebSocketMessage]:
    method get_stream_message_indexes (line 53) | def get_stream_message_indexes(self, pipeline_uuid: str) -> dict[str, ...
  class WebSocketAdapter (line 59) | class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatform...
    method __init__ (line 80) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method send_message (line 94) | async def send_message(
    method reply_message (line 141) | async def reply_message(
    method reply_message_chunk (line 187) | async def reply_message_chunk(
    method is_stream_output_supported (line 263) | async def is_stream_output_supported(self) -> bool:
    method register_listener (line 267) | def register_listener(
    method unregister_listener (line 277) | def unregister_listener(
    method is_muted (line 287) | async def is_muted(self, group_id: int) -> bool:
    method run_async (line 290) | async def run_async(self):
    method kill (line 309) | async def kill(self):
    method _process_image_components (line 313) | async def _process_image_components(self, message_chain_obj: list):
    method handle_websocket_message (line 353) | async def handle_websocket_message(
    method get_websocket_messages (line 445) | def get_websocket_messages(self, pipeline_uuid: str, session_type: str...
    method reset_session (line 452) | def reset_session(self, pipeline_uuid: str, session_type: str):

FILE: src/langbot/pkg/platform/sources/websocket_manager.py
  class WebSocketConnection (line 14) | class WebSocketConnection(pydantic.BaseModel):
  class WebSocketConnectionManager (line 47) | class WebSocketConnectionManager:
    method __init__ (line 50) | def __init__(self):
    method add_connection (line 63) | async def add_connection(
    method remove_connection (line 98) | async def remove_connection(self, connection_id: str):
    method get_connection (line 123) | async def get_connection(self, connection_id: str) -> typing.Optional[...
    method get_connections_by_pipeline (line 127) | async def get_connections_by_pipeline(self, pipeline_uuid: str) -> lis...
    method get_connections_by_session_type (line 132) | async def get_connections_by_session_type(self, session_type: str) -> ...
    method broadcast_to_pipeline (line 137) | async def broadcast_to_pipeline(self, pipeline_uuid: str, message: dic...
    method send_to_connection (line 157) | async def send_to_connection(self, connection_id: str, message: dict):
    method update_activity (line 171) | async def update_activity(self, connection_id: str):
    method get_stats (line 177) | def get_stats(self) -> dict:

FILE: src/langbot/pkg/platform/sources/wechatpad.py
  class WeChatPadMessageConverter (line 31) | class WeChatPadMessageConverter(abstract_platform_adapter.AbstractMessag...
    method __init__ (line 32) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method yiri2target (line 44) | async def yiri2target(message_chain: platform_message.MessageChain) ->...
    method target2yiri (line 84) | async def target2yiri(
    method _handler_text (line 136) | async def _handler_text(self, message: Optional[dict], content_no_prei...
    method _handler_image (line 144) | async def _handler_image(self, message: Optional[dict], content_no_pre...
    method _handler_voice (line 174) | async def _handler_voice(self, message: Optional[dict], content_no_pre...
    method _handler_compound (line 210) | async def _handler_compound(self, message: Optional[dict], content_no_...
    method _handler_compound_quote (line 241) | async def _handler_compound_quote(
    method _handler_compound_file (line 297) | async def _handler_compound_file(self, message: dict, xml_data: ET.Ele...
    method _handler_compound_link (line 338) | async def _handler_compound_link(self, message: dict, xml_data: ET.Ele...
    method _handler_compound_mini_program (line 360) | async def _handler_compound_mini_program(
    method _handler_default (line 367) | async def _handler_default(self, message: Optional[dict], content_no_p...
    method _handler_compound_unsupported (line 375) | def _handler_compound_unsupported(
    method _ats_bot (line 387) | def _ats_bot(self, message: dict, bot_account_id: str) -> bool:
    method _extract_at_targets (line 418) | def _extract_at_targets(self, message: dict) -> list[str]:
    method _extract_content_and_sender (line 435) | def _extract_content_and_sender(self, raw_content: str) -> Tuple[str, ...
    method _is_group_message (line 451) | def _is_group_message(self, message: dict) -> bool:
  class WeChatPadEventConverter (line 456) | class WeChatPadEventConverter(abstract_platform_adapter.AbstractEventCon...
    method __init__ (line 457) | def __init__(self, config: dict, logger: logging.Logger):
    method yiri2target (line 468) | async def yiri2target(event: platform_events.MessageEvent) -> dict:
    method target2yiri (line 471) | async def target2yiri(
  class WeChatPadAdapter (line 522) | class WeChatPadAdapter(abstract_platform_adapter.AbstractMessagePlatform...
    method __init__ (line 542) | def __init__(self, config: dict, logger: EventLogger):
    method ws_message (line 560) | async def ws_message(self, data):
    method _handle_message (line 573) | async def _handle_message(self, message: platform_message.MessageChain...
    method send_message (line 631) | async def send_message(self, target_type: str, target_id: str, message...
    method reply_message (line 635) | async def reply_message(
    method is_muted (line 646) | async def is_muted(self, group_id: int) -> bool:
    method register_listener (line 649) | def register_listener(
    method unregister_listener (line 658) | def unregister_listener(
    method run_async (line 667) | async def run_async(self):
    method kill (line 749) | async def kill(self) -> bool:

FILE: src/langbot/pkg/platform/sources/wecom.py
  function split_string_by_bytes (line 18) | def split_string_by_bytes(text, limit=2048, encoding='utf-8'):
  class WecomMessageConverter (line 70) | class WecomMessageConverter(abstract_platform_adapter.AbstractMessageCon...
    method yiri2target (line 72) | async def yiri2target(message_chain: platform_message.MessageChain, bo...
    method target2yiri (line 122) | async def target2yiri(message: str, message_id: int = -1):
    method target2yiri_image (line 132) | async def target2yiri_image(picurl: str, message_id: int = -1):
  class WecomEventConverter (line 142) | class WecomEventConverter(abstract_platform_adapter.AbstractEventConvert...
    method yiri2target (line 144) | async def yiri2target(event: platform_events.Event, bot_account_id: in...
    method target2yiri (line 166) | async def target2yiri(event: WecomEvent):
  class WecomAdapter (line 198) | class WecomAdapter(abstract_platform_adapter.AbstractMessagePlatformAdap...
    method __init__ (line 206) | def __init__(self, config: dict, logger: EventLogger):
    method set_bot_uuid (line 239) | def set_bot_uuid(self, bot_uuid: str):
    method reply_message (line 243) | async def reply_message(
    method send_message (line 264) | async def send_message(self, target_type: str, target_id: str, message...
    method register_listener (line 280) | def register_listener(
    method handle_unified_webhook (line 300) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 313) | async def run_async(self):
    method kill (line 320) | async def kill(self) -> bool:
    method unregister_listener (line 323) | async def unregister_listener(
    method is_muted (line 332) | async def is_muted(self, group_id: int) -> bool:

FILE: src/langbot/pkg/platform/sources/wecombot.py
  class WecomBotMessageConverter (line 17) | class WecomBotMessageConverter(abstract_platform_adapter.AbstractMessage...
    method yiri2target (line 19) | async def yiri2target(message_chain: platform_message.MessageChain):
    method target2yiri (line 27) | async def target2yiri(event: WecomBotEvent):
  class WecomBotEventConverter (line 136) | class WecomBotEventConverter(abstract_platform_adapter.AbstractEventConv...
    method yiri2target (line 138) | async def yiri2target(event: platform_events.MessageEvent):
    method target2yiri (line 142) | async def target2yiri(event: WecomBotEvent):
  class WecomBotAdapter (line 179) | class WecomBotAdapter(abstract_platform_adapter.AbstractMessagePlatformA...
    method __init__ (line 188) | def __init__(self, config: dict, logger: EventLogger):
    method reply_message (line 225) | async def reply_message(
    method reply_message_chunk (line 242) | async def reply_message_chunk(
    method is_stream_output_supported (line 267) | async def is_stream_output_supported(self) -> bool:
    method send_message (line 277) | async def send_message(self, target_type, target_id, message):
    method register_listener (line 284) | def register_listener(
    method set_bot_uuid (line 306) | def set_bot_uuid(self, bot_uuid: str):
    method handle_unified_webhook (line 310) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 315) | async def run_async(self):
    method kill (line 326) | async def kill(self) -> bool:
    method unregister_listener (line 332) | async def unregister_listener(
    method is_muted (line 341) | async def is_muted(self, group_id: int) -> bool:

FILE: src/langbot/pkg/platform/sources/wecomcs.py
  class WecomMessageConverter (line 19) | class WecomMessageConverter(abstract_platform_adapter.AbstractMessageCon...
    method yiri2target (line 21) | async def yiri2target(message_chain: platform_message.MessageChain, bo...
    method target2yiri (line 53) | async def target2yiri(message: str, message_id: int = -1):
    method target2yiri_image (line 63) | async def target2yiri_image(picurl: str, message_id: int = -1):
  class WecomEventConverter (line 72) | class WecomEventConverter(abstract_platform_adapter.AbstractEventConvert...
    method yiri2target (line 74) | async def yiri2target(event: platform_events.Event, bot_account_id: in...
    method target2yiri (line 84) | async def target2yiri(event: WecomCSEvent, bot: WecomCSClient = None):
  class WecomCSAdapter (line 131) | class WecomCSAdapter(abstract_platform_adapter.AbstractMessagePlatformAd...
    method __init__ (line 137) | def __init__(self, config: dict, logger: abstract_platform_logger.Abst...
    method reply_message (line 166) | async def reply_message(
    method send_message (line 184) | async def send_message(self, target_type: str, target_id: str, message...
    method set_bot_uuid (line 187) | def set_bot_uuid(self, bot_uuid: str):
    method register_listener (line 191) | def register_listener(
    method handle_unified_webhook (line 211) | async def handle_unified_webhook(self, bot_uuid: str, path: str, reque...
    method run_async (line 224) | async def run_async(self):
    method kill (line 234) | async def kill(self) -> bool:
    method is_muted (line 237) | async def is_muted(self, group_id: int) -> bool:
    method unregister_listener (line 240) | async def unregister_listener(

FILE: src/langbot/pkg/platform/webhook_pusher.py
  class WebhookPusher (line 17) | class WebhookPusher:
    method __init__ (line 23) | def __init__(self, ap: app.Application):
    method push_person_message (line 27) | async def push_person_message(self, event: platform_events.FriendMessa...
    method push_group_message (line 70) | async def push_group_message(self, event: platform_events.GroupMessage...
    method _push_to_webhook (line 117) | async def _push_to_webhook(self, url: str, payload: dict) -> dict | None:

FILE: src/langbot/pkg/plugin/connector.py
  class PluginRuntimeConnector (line 34) | class PluginRuntimeConnector:
    method __init__ (line 60) | def __init__(
    method heartbeat_loop (line 71) | async def heartbeat_loop(self):
    method initialize (line 80) | async def initialize(self):
    method initialize_plugins (line 186) | async def initialize_plugins(self):
    method ping_plugin_runtime (line 189) | async def ping_plugin_runtime(self):
    method install_plugin (line 195) | async def install_plugin(
    method upgrade_plugin (line 239) | async def upgrade_plugin(
    method delete_plugin (line 256) | async def delete_plugin(
    method list_plugins (line 280) | async def list_plugins(self, component_kinds: list[str] | None = None)...
    method get_plugin_info (line 363) | async def get_plugin_info(self, author: str, plugin_name: str) -> dict...
    method set_plugin_config (line 366) | async def set_plugin_config(self, plugin_author: str, plugin_name: str...
    method get_plugin_icon (line 370) | async def get_plugin_icon(self, plugin_author: str, plugin_name: str) ...
    method get_plugin_readme (line 374) | async def get_plugin_readme(self, plugin_author: str, plugin_name: str...
    method get_plugin_assets (line 378) | async def get_plugin_assets(self, plugin_author: str, plugin_name: str...
    method get_debug_info (line 381) | async def get_debug_info(self) -> dict[str, Any]:
    method emit_event (line 387) | async def emit_event(
    method list_tools (line 406) | async def list_tools(self, bound_plugins: list[str] | None = None) -> ...
    method call_tool (line 417) | async def call_tool(
    method list_commands (line 433) | async def list_commands(self, bound_plugins: list[str] | None = None) ...
    method execute_command (line 444) | async def execute_command(
    method retrieve_knowledge (line 459) | async def retrieve_knowledge(
    method dispose (line 472) | def dispose(self):
    method _parse_plugin_id (line 485) | def _parse_plugin_id(plugin_id: str) -> tuple[str, str]:
    method call_rag_ingest (line 503) | async def call_rag_ingest(self, plugin_id: str, context_data: dict[str...
    method call_rag_delete_document (line 513) | async def call_rag_delete_document(self, plugin_id: str, document_id: ...
    method get_rag_creation_schema (line 517) | async def get_rag_creation_schema(self, plugin_id: str) -> dict[str, A...
    method get_rag_retrieval_schema (line 521) | async def get_rag_retrieval_schema(self, plugin_id: str) -> dict[str, ...
    method rag_on_kb_create (line 525) | async def rag_on_kb_create(self, plugin_id: str, kb_id: str, config: d...
    method rag_on_kb_delete (line 530) | async def rag_on_kb_delete(self, plugin_id: str, kb_id: str) -> dict[s...
    method call_rag_retrieve (line 535) | async def call_rag_retrieve(self, plugin_id: str, retrieval_context: d...
    method list_knowledge_engines (line 545) | async def list_knowledge_engines(self) -> list[dict[str, Any]]:
    method list_parsers (line 555) | async def list_parsers(self) -> list[dict[str, Any]]:
    method call_parser (line 561) | async def call_parser(self, plugin_id: str, context_data: dict[str, An...

FILE: src/langbot/pkg/plugin/handler.py
  function _make_rag_error_response (line 29) | def _make_rag_error_response(error: Exception, error_type: str, **extra_...
  class RuntimeConnectionHandler (line 43) | class RuntimeConnectionHandler(handler.Handler):
    method __init__ (line 48) | def __init__(
    method ping (line 715) | async def ping(self) -> dict[str, Any]:
    method install_plugin (line 723) | async def install_plugin(
    method upgrade_plugin (line 739) | async def upgrade_plugin(self, plugin_author: str, plugin_name: str) -...
    method delete_plugin (line 753) | async def delete_plugin(self, plugin_author: str, plugin_name: str) ->...
    method list_plugins (line 766) | async def list_plugins(self) -> list[dict[str, Any]]:
    method get_plugin_info (line 776) | async def get_plugin_info(self, author: str, plugin_name: str) -> dict...
    method set_plugin_config (line 788) | async def set_plugin_config(self, plugin_author: str, plugin_name: str...
    method emit_event (line 811) | async def emit_event(
    method list_tools (line 828) | async def list_tools(self, include_plugins: list[str] | None = None) -...
    method get_plugin_icon (line 840) | async def get_plugin_icon(self, plugin_author: str, plugin_name: str) ...
    method get_plugin_readme (line 862) | async def get_plugin_readme(self, plugin_author: str, plugin_name: str...
    method get_plugin_assets (line 887) | async def get_plugin_assets(self, plugin_author: str, plugin_name: str...
    method cleanup_plugin_data (line 907) | async def cleanup_plugin_data(self, plugin_author: str, plugin_name: s...
    method call_tool (line 924) | async def call_tool(
    method list_commands (line 947) | async def list_commands(self, include_plugins: list[str] | None = None...
    method execute_command (line 958) | async def execute_command(
    method retrieve_knowledge (line 974) | async def retrieve_knowledge(
    method get_debug_info (line 994) | async def get_debug_info(self) -> dict[str, Any]:
    method rag_ingest_document (line 1005) | async def rag_ingest_document(
    method rag_delete_document (line 1016) | async def rag_delete_document(self, plugin_author: str, plugin_name: s...
    method rag_on_kb_create (line 1024) | async def rag_on_kb_create(
    method rag_on_kb_delete (line 1035) | async def rag_on_kb_delete(self, plugin_author: str, plugin_name: str,...
    method get_rag_creation_schema (line 1044) | async def get_rag_creation_schema(self, plugin_author: str, plugin_nam...
    method get_rag_retrieval_schema (line 1051) | async def get_rag_retrieval_schema(self, plugin_author: str, plugin_na...
    method list_knowledge_engines (line 1058) | async def list_knowledge_engines(self) -> list[dict[str, Any]]:
    method list_parsers (line 1065) | async def list_parsers(self) -> list[dict[str, Any]]:
    method parse_document (line 1070) | async def parse_document(

FILE: src/langbot/pkg/provider/modelmgr/entities.py
  class LLMModelInfo (line 11) | class LLMModelInfo(pydantic.BaseModel):
    class Config (line 26) | class Config:

FILE: src/langbot/pkg/provider/modelmgr/errors.py
  class RequesterError (line 1) | class RequesterError(Exception):
    method __init__ (line 4) | def __init__(self, message: str):

FILE: src/langbot/pkg/provider/modelmgr/modelmgr.py
  class ModelManager (line 15) | class ModelManager:
    method __init__ (line 31) | def __init__(self, ap: app.Application):
    method initialize (line 38) | async def initialize(self):
    method load_models_from_db (line 61) | async def load_models_from_db(self):
    method sync_new_models_from_space (line 113) | async def sync_new_models_from_space(self):
    method init_temporary_runtime_llm_model (line 173) | async def init_temporary_runtime_llm_model(
    method init_temporary_runtime_embedding_model (line 195) | async def init_temporary_runtime_embedding_model(
    method load_provider (line 215) | async def load_provider(
    method remove_provider (line 243) | async def remove_provider(self, provider_uuid: str):
    method reload_provider (line 251) | async def reload_provider(self, provider_uuid: str):
    method load_llm_model_with_provider (line 275) | async def load_llm_model_with_provider(
    method load_embedding_model_with_provider (line 291) | async def load_embedding_model_with_provider(
    method load_llm_model (line 307) | async def load_llm_model(self, model_info: dict):
    method load_embedding_model (line 331) | async def load_embedding_model(self, model_info: dict):
    method get_model_by_uuid (line 355) | async def get_model_by_uuid(self, uuid: str) -> requester.RuntimeLLMMo...
    method get_embedding_model_by_uuid (line 363) | async def get_embedding_model_by_uuid(self, uuid: str) -> requester.Ru...
    method remove_llm_model (line 370) | async def remove_llm_model(self, model_uuid: str):
    method remove_embedding_model (line 377) | async def remove_embedding_model(self, model_uuid: str):
    method get_available_requesters_info (line 384) | def get_available_requesters_info(self, model_type: str) -> list[dict]:
    method get_available_requester_info_by_name (line 395) | def get_available_requester_info_by_name(self, name: str) -> dict | None:
    method get_available_requester_manifest_by_name (line 402) | def get_available_requester_manifest_by_name(self, name: str) -> engin...

FILE: src/langbot/pkg/provider/modelmgr/requester.py
  class RuntimeProvider (line 15) | class RuntimeProvider:
    method __init__ (line 27) | def __init__(
    method invoke_llm (line 37) | async def invoke_llm(
    method invoke_llm_stream (line 117) | async def invoke_llm_stream(
    method invoke_embedding (line 187) | async def invoke_embedding(
  class RuntimeLLMModel (line 251) | class RuntimeLLMModel:
    method __init__ (line 260) | def __init__(
  class RuntimeEmbeddingModel (line 269) | class RuntimeEmbeddingModel:
    method __init__ (line 278) | def __init__(
  class ProviderAPIRequester (line 287) | class ProviderAPIRequester(metaclass=abc.ABCMeta):
    method __init__ (line 298) | def __init__(self, ap: app.Application, config: dict[str, typing.Any]):
    method initialize (line 303) | async def initialize(self):
    method invoke_llm (line 307) | async def invoke_llm(
    method invoke_llm_stream (line 330) | async def invoke_llm_stream(
    method invoke_embedding (line 353) | async def invoke_embedding(

FILE: src/langbot/pkg/provider/modelmgr/requesters/302aichatcmpl.py
  class AI302ChatCompletions (line 9) | class AI302ChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/anthropicmsgs.py
  class AnthropicMessages (line 18) | class AnthropicMessages(requester.ProviderAPIRequester):
    method initialize (line 28) | async def initialize(self):
    method invoke_llm (line 50) | async def invoke_llm(
    method invoke_llm_stream (line 184) | async def invoke_llm_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/bailianchatcmpl.py
  class BailianChatCompletions (line 14) | class BailianChatCompletions(modelscopechatcmpl.ModelScopeChatCompletions):
    method _closure_stream (line 24) | async def _closure_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/chatcmpl.py
  class OpenAIChatCompletions (line 16) | class OpenAIChatCompletions(requester.ProviderAPIRequester):
    method initialize (line 26) | async def initialize(self):
    method _req (line 34) | async def _req(
    method _req_stream (line 41) | async def _req_stream(
    method _make_msg (line 49) | async def _make_msg(
    method _process_thinking_content (line 81) | async def _process_thinking_content(
    method _closure_stream (line 127) | async def _closure_stream(
    method _closure (line 248) | async def _closure(
    method invoke_llm (line 297) | async def invoke_llm(
    method invoke_embedding (line 352) | async def invoke_embedding(
    method invoke_llm_stream (line 386) | async def invoke_llm_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/compsharechatcmpl.py
  class CompShareChatCompletions (line 9) | class CompShareChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/deepseekchatcmpl.py
  class DeepseekChatCompletions (line 12) | class DeepseekChatCompletions(chatcmpl.OpenAIChatCompletions):
    method _closure (line 20) | async def _closure(

FILE: src/langbot/pkg/provider/modelmgr/requesters/geminichatcmpl.py
  class GeminiChatCompletions (line 15) | class GeminiChatCompletions(chatcmpl.OpenAIChatCompletions):
    method _closure_stream (line 23) | async def _closure_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/giteeaichatcmpl.py
  class GiteeAIChatCompletions (line 9) | class GiteeAIChatCompletions(ppiochatcmpl.PPIOChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/jiekouaichatcmpl.py
  class JieKouAIChatCompletions (line 15) | class JieKouAIChatCompletions(chatcmpl.OpenAIChatCompletions):
    method _make_msg (line 27) | async def _make_msg(
    method _process_thinking_content (line 54) | async def _process_thinking_content(
    method _make_msg_chunk (line 77) | async def _make_msg_chunk(
    method _closure_stream (line 103) | async def _closure_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/lmstudiochatcmpl.py
  class LmStudioChatCompletions (line 9) | class LmStudioChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/modelscopechatcmpl.py
  class ModelScopeChatCompletions (line 16) | class ModelScopeChatCompletions(requester.ProviderAPIRequester):
    method initialize (line 26) | async def initialize(self):
    method _req (line 34) | async def _req(
    method _make_msg (line 111) | async def _make_msg(
    method _closure (line 125) | async def _closure(
    method _req_stream (line 170) | async def _req_stream(
    method _closure_stream (line 178) | async def _closure_stream(
    method invoke_llm (line 302) | async def invoke_llm(
    method invoke_llm_stream (line 347) | async def invoke_llm_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/moonshotchatcmpl.py
  class MoonshotChatCompletions (line 13) | class MoonshotChatCompletions(chatcmpl.OpenAIChatCompletions):
    method _closure (line 21) | async def _closure(

FILE: src/langbot/pkg/provider/modelmgr/requesters/newapichatcmpl.py
  class NewAPIChatCompletions (line 9) | class NewAPIChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/ollamachat.py
  class OllamaChatCompletions (line 20) | class OllamaChatCompletions(requester.ProviderAPIRequester):
    method initialize (line 30) | async def initialize(self):
    method _req (line 34) | async def _req(
    method _closure (line 40) | async def _closure(
    method _make_msg (line 80) | async def _make_msg(self, chat_completions: ollama.ChatResponse) -> pr...
    method invoke_llm (line 107) | async def invoke_llm(
    method invoke_embedding (line 136) | async def invoke_embedding(

FILE: src/langbot/pkg/provider/modelmgr/requesters/openrouterchatcmpl.py
  class OpenRouterChatCompletions (line 9) | class OpenRouterChatCompletions(modelscopechatcmpl.ModelScopeChatComplet...

FILE: src/langbot/pkg/provider/modelmgr/requesters/ppiochatcmpl.py
  class PPIOChatCompletions (line 15) | class PPIOChatCompletions(chatcmpl.OpenAIChatCompletions):
    method _make_msg (line 27) | async def _make_msg(
    method _process_thinking_content (line 54) | async def _process_thinking_content(
    method _make_msg_chunk (line 77) | async def _make_msg_chunk(
    method _closure_stream (line 103) | async def _closure_stream(

FILE: src/langbot/pkg/provider/modelmgr/requesters/qhaigcchatcmpl.py
  class QHAIGCChatCompletions (line 9) | class QHAIGCChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/seekdbembed.py
  class SeekDBEmbedding (line 10) | class SeekDBEmbedding(requester.ProviderAPIRequester):
    method initialize (line 23) | async def initialize(self):
    method invoke_llm (line 31) | async def invoke_llm(
    method invoke_embedding (line 42) | async def invoke_embedding(

FILE: src/langbot/pkg/provider/modelmgr/requesters/shengsuanyun.py
  class ShengSuanYunChatCompletions (line 10) | class ShengSuanYunChatCompletions(chatcmpl.OpenAIChatCompletions):
    method _req (line 20) | async def _req(

FILE: src/langbot/pkg/provider/modelmgr/requesters/siliconflowchatcmpl.py
  class SiliconFlowChatCompletions (line 9) | class SiliconFlowChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/spacechatcmpl.py
  class LangBotSpaceChatCompletions (line 9) | class LangBotSpaceChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/tokenponychatcmpl.py
  class TokenPonyChatCompletions (line 9) | class TokenPonyChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/volcarkchatcmpl.py
  class VolcArkChatCompletions (line 9) | class VolcArkChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/xaichatcmpl.py
  class XaiChatCompletions (line 9) | class XaiChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/requesters/zhipuaichatcmpl.py
  class ZhipuAIChatCompletions (line 9) | class ZhipuAIChatCompletions(chatcmpl.OpenAIChatCompletions):

FILE: src/langbot/pkg/provider/modelmgr/token.py
  class TokenManager (line 6) | class TokenManager:
    method __init__ (line 15) | def __init__(self, name: str, tokens: list[str]):
    method get_token (line 20) | def get_token(self) -> str:
    method next_token (line 25) | def next_token(self):

FILE: src/langbot/pkg/provider/runner.py
  function runner_class (line 12) | def runner_class(name: str):
  class RequestRunner (line 23) | class RequestRunner(abc.ABC):
    method __init__ (line 32) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method run (line 37) | async def run(

FILE: src/langbot/pkg/provider/runners/cozeapi.py
  class CozeAPIRunner (line 16) | class CozeAPIRunner(runner.RequestRunner):
    method __init__ (line 19) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method _process_thinking_content (line 30) | def _process_thinking_content(
    method _preprocess_user_message (line 63) | async def _preprocess_user_message(self, query: pipeline_query.Query) ...
    method _get_file_id (line 107) | async def _get_file_id(self, file) -> str:
    method _chat_messages (line 117) | async def _chat_messages(
    method _chat_messages_chunk (line 200) | async def _chat_messages_chunk(
    method run (line 277) | async def run(self, query: pipeline_query.Query) -> typing.AsyncGenera...

FILE: src/langbot/pkg/provider/runners/dashscopeapi.py
  class DashscopeAPIError (line 14) | class DashscopeAPIError(Exception):
    method __init__ (line 17) | def __init__(self, message: str):
  class DashScopeAPIRunner (line 23) | class DashScopeAPIRunner(runner.RequestRunner):
    method __init__ (line 34) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method _replace_references (line 50) | def _replace_references(self, text, references_dict):
    method _preprocess_user_message (line 69) | async def _preprocess_user_message(self, query: pipeline_query.Query) ...
    method _agent_messages (line 93) | async def _agent_messages(
    method _workflow_messages (line 225) | async def _workflow_messages(
    method run (line 339) | async def run(self, query: pipeline_query.Query) -> typing.AsyncGenera...

FILE: src/langbot/pkg/provider/runners/difysvapi.py
  class DifyServiceAPIRunner (line 20) | class DifyServiceAPIRunner(runner.RequestRunner):
    method __init__ (line 25) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method _process_thinking_content (line 42) | def _process_thinking_content(
    method _extract_dify_text_output (line 75) | def _extract_dify_text_output(self, value: typing.Any) -> str:
    method _preprocess_user_message (line 97) | async def _preprocess_user_message(self, query: pipeline_query.Query) ...
    method _chat_messages (line 173) | async def _chat_messages(
    method _agent_chat_messages (line 240) | async def _agent_chat_messages(
    method _workflow_messages (line 338) | async def _workflow_messages(
    method _chat_messages_chunk (line 413) | async def _chat_messages_chunk(
    method _agent_chat_messages_chunk (line 516) | async def _agent_chat_messages_chunk(
    method _workflow_messages_chunk (line 639) | async def _workflow_messages_chunk(
    method run (line 739) | async def run(self, query: pipeline_query.Query) -> typing.AsyncGenera...

FILE: src/langbot/pkg/provider/runners/langflowapi.py
  class LangflowAPIRunner (line 16) | class LangflowAPIRunner(runner.RequestRunner):
    method __init__ (line 19) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method _build_request_payload (line 23) | async def _build_request_payload(self, query: pipeline_query.Query) ->...
    method run (line 60) | async def run(

FILE: src/langbot/pkg/provider/runners/localagent.py
  class LocalAgentRunner (line 29) | class LocalAgentRunner(runner.RequestRunner):
    method _get_model_candidates (line 32) | async def _get_model_candidates(
    method _invoke_with_fallback (line 58) | async def _invoke_with_fallback(
    method _invoke_stream_with_fallback (line 84) | async def _invoke_stream_with_fallback(
    method run (line 129) | async def run(

FILE: src/langbot/pkg/provider/runners/n8nsvapi.py
  class N8nAPIError (line 16) | class N8nAPIError(Exception):
    method __init__ (line 19) | def __init__(self, message: str):
  class N8nServiceAPIRunner (line 25) | class N8nServiceAPIRunner(runner.RequestRunner):
    method __init__ (line 28) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method _preprocess_user_message (line 55) | async def _preprocess_user_message(self, query: pipeline_query.Query) ...
    method _process_stream_response (line 73) | async def _process_stream_response(
    method _call_webhook (line 159) | async def _call_webhook(self, query: pipeline_query.Query) -> typing.A...
    method run (line 270) | async def run(self, query: pipeline_query.Query) -> typing.AsyncGenera...

FILE: src/langbot/pkg/provider/runners/tboxapi.py
  class TboxAPIError (line 19) | class TboxAPIError(Exception):
    method __init__ (line 22) | def __init__(self, message: str):
  class TboxAPIRunner (line 28) | class TboxAPIRunner(runner.RequestRunner):
    method __init__ (line 35) | def __init__(self, ap: app.Application, pipeline_config: dict):
    method _preprocess_user_message (line 47) | async def _preprocess_user_message(self, query: pipeline_query.Query) ...
    method _agent_messages (line 80) | async def _agent_messages(
    method _process_non_stream_message (line 121) | def _process_non_stream_message(self, response: typing.Dict, query: pi...
    method _process_stream_message (line 136) | def _process_stream_message(
    method run (line 195) | async def run(self, query: pipeline_query.Query) -> typing.AsyncGenera...

FILE: src/langbot/pkg/provider/session/sessionmgr.py
  class SessionManager (line 11) | class SessionManager:
    method __init__ (line 18) | def __init__(self, ap: app.Application):
    method initialize (line 22) | async def initialize(self):
    method get_session (line 25) | async def get_session(self, query: pipeline_query.Query) -> provider_s...
    method get_conversation (line 42) | async def get_conversation(

FILE: src/langbot/pkg/provider/tools/loader.py
  function loader_class (line 15) | def loader_class(name: str):
  class ToolLoader (line 26) | class ToolLoader(abc.ABC):
    method __init__ (line 33) | def __init__(self, ap: app.Application):
    method initialize (line 36) | async def initialize(self):
    method get_tools (line 40) | async def get_tools(self, bound_plugins: list[str] | None = None) -> l...
    method has_tool (line 45) | async def has_tool(self, name: str) -> bool:
    method invoke_tool (line 50) | async def invoke_tool(self, name: str, parameters: dict, query: pipeli...
    method shutdown (line 55) | async def shutdown(self):

FILE: src/langbot/pkg/provider/tools/loaders/mcp.py
  class MCPSessionStatus (line 25) | class MCPSessionStatus(enum.Enum):
  class RuntimeMCPSession (line 31) | class RuntimeMCPSession:
    method __init__ (line 61) | def __init__(self, server_name: str, server_config: dict, enable: bool...
    method _init_stdio_python_server (line 78) | async def _init_stdio_python_server(self):
    method _init_sse_server (line 93) | async def _init_sse_server(self):
    method _init_streamable_http_server (line 109) | async def _init_streamable_http_server(self):
    method _lifecycle_loop (line 127) | async def _lifecycle_loop(self):
    method start (line 165) | async def start(self):
    method refresh (line 183) | async def refresh(self):
    method get_tools (line 231) | def get_tools(self) -> list[resource_tool.LLMTool]:
    method get_runtime_info_dict (line 234) | def get_runtime_info_dict(self) -> dict:
    method shutdown (line 248) | async def shutdown(self):
  class MCPLoader (line 272) | class MCPLoader(loader.ToolLoader):
    method __init__ (line 284) | def __init__(self, ap: app.Application):
    method initialize (line 290) | async def initialize(self):
    method load_mcp_servers_from_db (line 293) | async def load_mcp_servers_from_db(self):
    method host_mcp_server (line 307) | async def host_mcp_server(self, server_config: dict):
    method load_mcp_server (line 329) | async def load_mcp_server(self, server_config: dict) -> RuntimeMCPSess...
    method get_tools (line 363) | async def get_tools(self, bound_mcp_servers: list[str] | None = None) ...
    method has_tool (line 379) | async def has_tool(self, name: str) -> bool:
    method invoke_tool (line 387) | async def invoke_tool(self, name: str, parameters: dict, query: pipeli...
    method remove_mcp_server (line 403) | async def remove_mcp_server(self, server_name: str):
    method get_session (line 413) | def get_session(self, server_name: str) -> RuntimeMCPSession | None:
    method has_session (line 417) | def has_session(self, server_name: str) -> bool:
    method get_all_server_names (line 421) | def get_all_server_names(self) -> list[str]:
    method get_server_tool_count (line 425) | def get_server_tool_count(self, server_name: str) -> int:
    method get_all_servers_info (line 430) | def get_all_servers_info(self) -> dict[str, dict]:
    method shutdown (line 443) | async def shutdown(self):

FILE: src/langbot/pkg/provider/tools/loaders/plugin.py
  class PluginToolLoader (line 13) | class PluginToolLoader(loader.ToolLoader):
    method get_tools (line 19) | async def get_tools(self, bound_plugins: list[str] | None = None) -> l...
    method has_tool (line 35) | async def has_tool(self, name: str) -> bool:
    method _get_tool (line 42) | async def _get_tool(self, name: str) -> resource_tool.LLMTool:
    method invoke_tool (line 48) | async def invoke_tool(self, name: str, parameters: dict, query: pipeli...
    method shutdown (line 58) | async def shutdown(self):

FILE: src/langbot/pkg/provider/tools/toolmgr.py
  class ToolManager (line 15) | class ToolManager:
    method __init__ (line 23) | def __init__(self, ap: app.Application):
    method initialize (line 26) | async def initialize(self):
    method get_all_tools (line 32) | async def get_all_tools(
    method generate_tools_for_openai (line 43) | async def generate_tools_for_openai(self, use_funcs: list[resource_too...
    method generate_tools_for_anthropic (line 60) | async def generate_tools_for_anthropic(self, use_funcs: list[resource_...
    method execute_func_call (line 95) | async def execute_func_call(self, name: str, parameters: dict, query: ...
    method shutdown (line 105) | async def shutdown(self):

FILE: src/langbot/pkg/rag/knowledge/base.py
  class KnowledgeBaseInterface (line 11) | class KnowledgeBaseInterface(metaclass=abc.ABCMeta):
    method __init__ (line 16) | def __init__(self, ap: app.Application):
    method initialize (line 20) | async def initialize(self):
    method retrieve (line 25) | async def retrieve(self, query: str, settings: dict | None = None) -> ...
    method get_uuid (line 38) | def get_uuid(self) -> str:
    method get_name (line 43) | def get_name(self) -> str:
    method get_knowledge_engine_plugin_id (line 48) | def get_knowledge_engine_plugin_id(self) -> str:
    method dispose (line 53) | async def dispose(self):

FILE: src/langbot/pkg/rag/knowledge/kbmgr.py
  class RuntimeKnowledgeBase (line 19) | class RuntimeKnowledgeBase(KnowledgeBaseInterface):
    method __init__ (line 24) | def __init__(self, ap: app.Application, knowledge_base_entity: persist...
    method initialize (line 28) | async def initialize(self):
    method _store_file_task (line 31) | async def _store_file_task(
    method store_file (line 104) | async def store_file(self, file_id: str, parser_plugin_id: str | None ...
    method _store_zip_file (line 142) | async def _store_zip_file(self, zip_file_id: str, parser_plugin_id: st...
    method retrieve (line 198) | async def retrieve(self, query: str, settings: dict | None = None) -> ...
    method delete_file (line 216) | async def delete_file(self, file_id: str):
    method get_uuid (line 224) | def get_uuid(self) -> str:
    method get_name (line 228) | def get_name(self) -> str:
    method get_knowledge_engine_plugin_id (line 232) | def get_knowledge_engine_plugin_id(self) -> str:
    method dispose (line 236) | async def dispose(self):
    method _on_kb_create (line 242) | async def _on_kb_create(self) -> None:
    method _on_kb_delete (line 258) | async def _on_kb_delete(self) -> None:
    method _ingest_document (line 272) | async def _ingest_document(
    method _retrieve (line 308) | async def _retrieve(
    method _delete_document (line 345) | async def _delete_document(self, document_id: str) -> bool:
  class RAGManager (line 361) | class RAGManager:
    method __init__ (line 366) | def __init__(self, ap: app.Application):
    method initialize (line 370) | async def initialize(self):
    method get_all_knowledge_base_details (line 373) | async def get_all_knowledge_base_details(self) -> list[dict]:
    method get_knowledge_base_details (line 397) | async def get_knowledge_base_details(self, kb_uuid: str) -> dict | None:
    method _to_i18n_name (line 421) | def _to_i18n_name(name) -> dict:
    method _enrich_kb_dict (line 432) | def _enrich_kb_dict(self, kb_dict: dict, engine_map: dict) -> None:
    method create_knowledge_base (line 458) | async def create_knowledge_base(
    method load_knowledge_bases_from_db (line 515) | async def load_knowledge_bases_from_db(self):
    method load_knowledge_base (line 532) | async def load_knowledge_base(
    method get_knowledge_base_by_uuid (line 554) | async def get_knowledge_base_by_uuid(self, kb_uuid: str) -> KnowledgeB...
    method remove_knowledge_base_from_runtime (line 557) | async def remove_knowledge_base_from_runtime(self, kb_uuid: str):
    method delete_knowledge_base (line 560) | async def delete_knowledge_base(self, kb_uuid: str):

FILE: src/langbot/pkg/rag/service/runtime.py
  class RAGRuntimeService (line 8) | class RAGRuntimeService:
    method __init__ (line 15) | def __init__(self, ap: app.Application):
    method vector_upsert (line 18) | async def vector_upsert(
    method vector_search (line 36) | async def vector_search(
    method vector_delete (line 55) | async def vector_delete(
    method vector_list (line 78) | async def vector_list(
    method get_file_stream (line 103) | async def get_file_stream(self, storage_path: str) -> bytes:

FILE: src/langbot/pkg/storage/mgr.py
  class StorageMgr (line 9) | class StorageMgr:
    method __init__ (line 16) | def __init__(self, ap: app.Application):
    method initialize (line 19) | async def initialize(self):

FILE: src/langbot/pkg/storage/provider.py
  class StorageProvider (line 8) | class StorageProvider(abc.ABC):
    method __init__ (line 11) | def __init__(self, ap: app.Application):
    method initialize (line 14) | async def initialize(self):
    method save (line 18) | async def save(
    method load (line 26) | async def load(
    method exists (line 33) | async def exists(
    method delete (line 40) | async def delete(
    method size (line 47) | async def size(
    method delete_dir_recursive (line 54) | async def delete_dir_recursive(

FILE: src/langbot/pkg/storage/providers/localstorage.py
  class LocalStorageProvider (line 15) | class LocalStorageProvider(provider.StorageProvider):
    method __init__ (line 16) | def __init__(self, ap: app.Application):
    method save (line 21) | async def save(
    method load (line 31) | async def load(
    method exists (line 38) | async def exists(
    method delete (line 44) | async def delete(
    method size (line 50) | async def size(
    method delete_dir_recursive (line 56) | async def delete_dir_recursive(

FILE: src/langbot/pkg/storage/providers/s3storage.py
  class S3StorageProvider (line 10) | class S3StorageProvider(provider.StorageProvider):
    method __init__ (line 13) | def __init__(self, ap: app.Application):
    method initialize (line 18) | async def initialize(self):
    method save (line 57) | async def save(
    method load (line 73) | async def load(
    method exists (line 88) | async def exists(
    method delete (line 106) | async def delete(
    method size (line 120) | async def size(
    method delete_dir_recursive (line 135) | async def delete_dir_recursive(

FILE: src/langbot/pkg/survey/manager.py
  class SurveyManager (line 18) | class SurveyManager:
    method __init__ (line 21) | def __init__(self, ap: core_app.Application):
    method initialize (line 27) | async def initialize(self):
    method _load_triggered_events (line 32) | async def _load_triggered_events(self):
    method _save_triggered_events (line 44) | async def _save_triggered_events(self):
    method _is_space_configured (line 62) | def _is_space_configured(self) -> bool:
    method trigger_event (line 68) | async def trigger_event(self, event: str):
    method _fetch_pending_survey (line 81) | async def _fetch_pending_survey(self, event: str):
    method get_pending_survey (line 99) | def get_pending_survey(self) -> typing.Optional[dict]:
    method clear_pending_survey (line 103) | def clear_pending_survey(self):
    method submit_response (line 107) | async def submit_response(self, survey_id: str, answers: dict, complet...
    method dismiss_survey (line 131) | async def dismiss_survey(self, survey_id: str) -> bool:

FILE: src/langbot/pkg/telemetry/telemetry.py
  class TelemetryManager (line 8) | class TelemetryManager:
    method __init__ (line 18) | def __init__(self, ap: core_app.Application):
    method initialize (line 23) | async def initialize(self):
    method start_send_task (line 26) | async def start_send_task(self, payload: dict):
    method send (line 30) | async def send(self, payload: dict):

FILE: src/langbot/pkg/utils/funcschema.py
  function get_func_schema (line 6) | def get_func_schema(function: typing.Callable) -> dict:

FILE: src/langbot/pkg/utils/httpclient.py
  function get_session (line 19) | def get_session(*, trust_env: bool = False) -> aiohttp.ClientSession:
  function close_all (line 38) | async def close_all():

FILE: src/langbot/pkg/utils/image.py
  function get_gewechat_image_base64 (line 16) | async def get_gewechat_image_base64(
  function get_wecom_image_base64 (line 104) | async def get_wecom_image_base64(pic_url: str) -> tuple[str, str]:
  function get_qq_official_image_base64 (line 130) | async def get_qq_official_image_base64(pic_url: str, content_type: str) ...
  function get_qq_image_downloadable_url (line 144) | def get_qq_image_downloadable_url(image_url: str) -> tuple[str, dict]:
  function get_qq_image_bytes (line 151) | async def get_qq_image_bytes(image_url: str, query: dict = {}) -> tuple[...
  function qq_image_url_to_base64 (line 173) | async def qq_image_url_to_base64(image_url: str) -> typing.Tuple[str, str]:
  function extract_b64_and_format (line 194) | async def extract_b64_and_format(image_base64_data: str) -> typing.Tuple...
  function get_slack_image_to_base64 (line 205) | async def get_slack_image_to_base64(pic_url: str, bot_token: str):

FILE: src/langbot/pkg/utils/importutil.py
  function import_modules_in_pkg (line 7) | def import_modules_in_pkg(pkg: typing.Any) -> None:
  function import_modules_in_pkgs (line 17) | def import_modules_in_pkgs(pkgs: typing.List) -> None:
  function import_dot_style_dir (line 22) | def import_dot_style_dir(dot_sep_path: str):
  function import_dir (line 28) | def import_dir(path: str, path_prefix: str = 'langbot.'):
  function read_resource_file (line 39) | def read_resource_file(resource_path: str) -> str:
  function read_resource_file_bytes (line 44) | def read_resource_file_bytes(resource_path: str) -> bytes:
  function list_resource_files (line 48) | def list_resource_files(resource_path: str) -> list[str]:

FILE: src/langbot/pkg/utils/logcache.py
  class LogPage (line 8) | class LogPage:
    method __init__ (line 16) | def __init__(self, number: int):
    method add_log (line 20) | def add_log(self, log: str) -> bool:
  class LogCache (line 30) | class LogCache:
    method __init__ (line 37) | def __init__(self):
    method add_log (line 41) | def add_log(self, log: str):
    method get_log_by_pointer (line 49) | def get_log_by_pointer(

FILE: src/langbot/pkg/utils/paths.py
  function _check_if_source_install (line 10) | def _check_if_source_install() -> bool:
  function get_frontend_path (line 37) | def get_frontend_path() -> str:
  function get_resource_path (line 65) | def get_resource_path(resource: str) -> str:

FILE: src/langbot/pkg/utils/pkgmgr.py
  function install (line 4) | def install(package):
  function install_upgrade (line 8) | def install_upgrade(package):
  function run_pip (line 22) | def run_pip(params: list):
  function install_requirements (line 26) | def install_requirements(file, extra_params: list = []):

FILE: src/langbot/pkg/utils/platform.py
  function get_platform (line 5) | def get_platform() -> str:
  function use_websocket_to_connect_plugin_runtime (line 20) | def use_websocket_to_connect_plugin_runtime() -> bool:

FILE: src/langbot/pkg/utils/proxy.py
  class ProxyManager (line 8) | class ProxyManager:
    method __init__ (line 15) | def __init__(self, ap: app.Application):
    method initialize (line 20) | async def initialize(self):
    method get_forward_proxies (line 35) | def get_forward_proxies(self) -> dict:

FILE: src/langbot/pkg/utils/runner.py
  class RunnerCategory (line 6) | class RunnerCategory:
  function get_runner_category (line 48) | def get_runner_category(runner_name: str, runner_url: str) -> str:
  function get_runner_info (line 69) | def get_runner_info(runner_name: str, runner_url: str) -> dict:
  function is_cloud_runner (line 77) | def is_cloud_runner(runner_name: str, runner_url: str) -> bool:
  function is_local_runner (line 81) | def is_local_runner(runner_name: str, runner_url: str) -> bool:
  function extract_runner_url (line 85) | def extract_runner_url(runner_name: str, runner, pipeline_config: dict |...
  function get_runner_category_from_runner (line 103) | def get_runner_category_from_runner(runner_name: str, runner, pipeline_c...

FILE: src/langbot/pkg/utils/version.py
  class VersionManager (line 13) | class VersionManager:
    method __init__ (line 18) | def __init__(self, ap: app.Application):
    method initialize (line 21) | async def initialize(self):
    method get_current_version (line 24) | def get_current_version(self) -> str:
    method get_release_list (line 29) | async def get_release_list(self) -> list:
    method update_all (line 45) | async def update_all(self):
    method is_new_version_available (line 135) | async def is_new_version_available(self) -> bool:
    method is_newer (line 154) | def is_newer(self, new_tag: str, old_tag: str):
    method compare_version_str (line 175) | def compare_version_str(v0: str, v1: str) -> int:
    method show_version_update (line 202) | async def show_version_update(self) -> typing.Tuple[str, int]:

FILE: src/langbot/pkg/vector/filter_utils.py
  function normalize_filter (line 24) | def normalize_filter(
  function strip_unsupported_fields (line 49) | def strip_unsupported_fields(

FILE: src/langbot/pkg/vector/mgr.py
  class VectorDBManager (line 12) | class VectorDBManager:
    method __init__ (line 16) | def __init__(self, ap: app.Application):
    method initialize (line 19) | async def initialize(self):
    method get_supported_search_types (line 69) | def get_supported_search_types(self) -> list[str]:
    method upsert (line 75) | async def upsert(
    method search (line 92) | async def search(
    method delete_by_file_id (line 140) | async def delete_by_file_id(self, collection_name: str, file_ids: list...
    method delete_collection (line 149) | async def delete_collection(self, collection_name: str):
    method delete_by_filter (line 153) | async def delete_by_filter(self, collection_name: str, filter: dict) -...
    method list_by_filter (line 161) | async def list_by_filter(

FILE: src/langbot/pkg/vector/vdb.py
  class SearchType (line 8) | class SearchType(str, enum.Enum):
  class VectorDatabase (line 16) | class VectorDatabase(abc.ABC):
    method supported_search_types (line 18) | def supported_search_types(cls) -> list[SearchType]:
    method add_embeddings (line 27) | async def add_embeddings(
    method search (line 48) | async def search(
    method delete_by_file_id (line 77) | async def delete_by_file_id(self, collection: str, file_id: str) -> None:
    method delete_by_filter (line 82) | async def delete_by_filter(self, collection: str, filter: dict[str, An...
    method list_by_filter (line 95) | async def list_by_filter(
    method get_or_create_collection (line 118) | async def get_or_create_collection(self, collection: str):
    method delete_collection (line 123) | async def delete_collection(self, collection: str):

FILE: src/langbot/pkg/vector/vdbs/chroma.py
  class ChromaVectorDatabase (line 14) | class ChromaVectorDatabase(VectorDatabase):
    method __init__ (line 15) | def __init__(self, ap: app.Application, base_path: str = './data/chrom...
    method supported_search_types (line 21) | def supported_search_types(cls) -> list[SearchType]:
    method get_or_create_collection (line 24) | async def get_or_create_collection(self, collection: str) -> chromadb....
    method add_embeddings (line 32) | async def add_embeddings(
    method search (line 47) | async def search(
    method _vector_search (line 66) | async def _vector_search(
    method _full_text_search (line 87) | async def _full_text_search(
    method _hybrid_search (line 122) | async def _hybrid_search(
    method _rrf_fuse (line 200) | def _rrf_fuse(result_lists: list[list[str]], k: int) -> list[tuple[str...
    method delete_by_file_id (line 213) | async def delete_by_file_id(self, collection: str, file_id: str) -> None:
    method delete_by_filter (line 218) | async def delete_by_filter(self, collection: str, filter: dict[str, An...
    method list_by_filter (line 224) | async def list_by_filter(
    method delete_collection (line 259) | async def delete_collection(self, collection: str):

FILE: src/langbot/pkg/vector/vdbs/milvus.py
  function _build_milvus_expr (line 18) | def _build_milvus_expr(filter_dict: dict[str, Any]) -> str:
  function _milvus_literal (line 48) | def _milvus_literal(value: Any) -> str:
  class MilvusVectorDatabase (line 56) | class MilvusVectorDatabase(VectorDatabase):
    method __init__ (line 59) | def __init__(self, ap: app.Application, uri: str = 'milvus.db', token:...
    method _initialize_client (line 76) | def _initialize_client(self):
    method _normalize_collection_name (line 89) | def _normalize_collection_name(collection: str) -> str:
    method _ensure_vector_index (line 111) | async def _ensure_vector_index(self, collection: str) -> None:
    method _get_or_create_collection_internal (line 125) | async def _get_or_create_collection_internal(self, collection: str, ve...
    method _ensure_index_if_missing (line 175) | async def _ensure_index_if_missing(self, collection: str) -> None:
    method get_or_create_collection (line 189) | async def get_or_create_collection(self, collection: str):
    method add_embeddings (line 198) | async def add_embeddings(
    method search (line 250) | async def search(
    method delete_by_file_id (line 317) | async def delete_by_file_id(self, collection: str, file_id: str) -> None:
    method delete_by_filter (line 331) | async def delete_by_filter(self, collection: str, filter: dict[str, An...
    method list_by_filter (line 346) | async def list_by_filter(
    method delete_collection (line 402) | async def delete_collection(self, collection: str):

FILE: src/langbot/pkg/vector/vdbs/pgvector_db.py
  class PgVectorEntry (line 27) | class PgVectorEntry(Base):
  function _build_pg_conditions (line 40) | def _build_pg_conditions(filter_dict: dict[str, Any]) -> list:
  class PgVectorDatabase (line 67) | class PgVectorDatabase(VectorDatabase):
    method __init__ (line 70) | def __init__(
    method _initialize_db (line 110) | def _initialize_db(self):
    method get_or_create_collection (line 135) | async def get_or_create_collection(self, collection: str):
    method add_embeddings (line 147) | async def add_embeddings(
    method search (line 187) | async def search(
    method delete_by_file_id (line 255) | async def delete_by_file_id(self, collection: str, file_id: str) -> None:
    method delete_by_filter (line 282) | async def delete_by_filter(self, collection: str, filter: dict[str, An...
    method list_by_filter (line 315) | async def list_by_filter(
    method delete_collection (line 374) | async def delete_collection(self, collection: str):
    method close (line 397) | async def close(self):

FILE: src/langbot/pkg/vector/vdbs/qdrant.py
  function _build_qdrant_filter (line 11) | def _build_qdrant_filter(filter_dict: dict[str, Any]) -> models.Filter:
  class QdrantVectorDatabase (line 41) | class QdrantVectorDatabase(VectorDatabase):
    method __init__ (line 42) | def __init__(self, ap: app.Application):
    method _ensure_collection (line 56) | async def _ensure_collection(self, collection: str, vector_size: int) ...
    method get_or_create_collection (line 72) | async def get_or_create_collection(self, collection: str):
    method add_embeddings (line 76) | async def add_embeddings(
    method search (line 95) | async def search(
    method delete_by_file_id (line 127) | async def delete_by_file_id(self, collection: str, file_id: str) -> None:
    method delete_by_filter (line 140) | async def delete_by_filter(self, collection: str, filter: dict[str, An...
    method list_by_filter (line 153) | async def list_by_filter(
    method delete_collection (line 244) | async def delete_collection(self, collection: str):

FILE: src/langbot/pkg/vector/vdbs/seekdb.py
  class SeekDBVectorDatabase (line 22) | class SeekDBVectorDatabase(VectorDatabase):
    method supported_search_types (line 32) | def supported_search_types(cls) -> list[SearchType]:
    method __init__ (line 35) | def __init__(self, ap: app.Application):
    method _get_or_create_collection_internal (line 104) | async def _get_or_create_collection_internal(self, collection: str, ve...
    method _clean_metadata (line 140) | def _clean_metadata(self, meta: Dict[str, Any]) -> Dict[str, Any]:
    method get_or_create_collection (line 152) | async def get_or_create_collection(self, collection: str):
    method add_embeddings (line 156) | async def add_embeddings(
    method search (line 189) | async def search(
    method delete_by_file_id (line 295) | async def delete_by_file_id(self, collection: str, file_id: str) -> None:
    method delete_by_filter (line 321) | async def delete_by_filter(self, collection: str, filter: Dict[str, An...
    method list_by_filter (line 343) | async def list_by_filter(
    method delete_collection (line 387) | async def delete_collection(self, collection: str):

FILE: tests/unit_tests/config/test_env_override.py
  function _apply_env_overrides_to_config (line 10) | def
Condensed preview — 726 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,474K chars).
[
  {
    "path": ".dockerignore",
    "chars": 70,
    "preview": ".github\n.venv\n.vscode\n.data\n.temp\nweb/.next\nweb/node_modules\nweb/.env\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "chars": 938,
    "preview": "name: 漏洞反馈\ndescription: 【供中文用户】报错或漏洞请使用这个模板创建,不使用此模板创建的异常、漏洞相关issue将被直接关闭。由于自己操作不当/不甚了解所用技术栈引起的网络连接问题恕无法解决,请勿提 issue。容器间"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report_en.yml",
    "chars": 1240,
    "preview": "name: Bug report\ndescription: Report bugs or vulnerabilities using this template. For container network connection issue"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "chars": 406,
    "preview": "name: 需求建议\ntitle: \"[Feature]: \"\nlabels: []\ndescription: \"【供中文用户】新功能或现有功能优化请使用这个模板;不符合类别的issue将被直接关闭\"\nbody:\n  - type: dro"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request_en.yml",
    "chars": 624,
    "preview": "name: Feature request\ntitle: \"[Feature]: \"\nlabels: []\ndescription: \"New features or existing feature improvements should"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/submit-plugin.yml",
    "chars": 461,
    "preview": "name: 提交新插件\ntitle: \"[Plugin]: 请求登记新插件\"\nlabels: [\"独立插件\"]\ndescription: \"【供中文用户】本模板供且仅供提交新插件使用\"\nbody:\n  - type: input\n    a"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/submit-plugin_en.yml",
    "chars": 641,
    "preview": "name: Submit a new plugin\ntitle: \"[Plugin]: Request to register a new plugin\"\nlabels: [\"Independent Plugin\"]\ndescription"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 547,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1223,
    "preview": "## 概述 / Overview\n\n> 请在此部分填写你实现/解决/优化的内容:  \n> Summary of what you implemented/solved/optimized:\n> \n\n### 更改前后对比截图 / Screen"
  },
  {
    "path": ".github/workflows/build-dev-image.yaml",
    "chars": 910,
    "preview": "name: Build Dev Image\n\non:\n  push:\n  workflow_dispatch:\n\njobs:\n  build-dev-image:\n    runs-on: ubuntu-latest\n    # 如果是ta"
  },
  {
    "path": ".github/workflows/build-docker-image.yml",
    "chars": 1841,
    "preview": "name: Build Docker Image\non:\n  ## 发布release的时候会自动构建\n  release:\n    types: [published]\njobs:\n  publish-docker-image:\n    "
  },
  {
    "path": ".github/workflows/build-release-artifacts.yaml",
    "chars": 1808,
    "preview": "name: Build Release Artifacts\n\non:\n  workflow_dispatch:\n  ## 发布release的时候会自动构建\n  release:\n    types: [published]\n\njobs:\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "chars": 1192,
    "preview": "name: Lint\n\non:\n  push:\n    branches:\n      - main\n      - master\n      - dev\n  pull_request:\n    types: [opened, synchr"
  },
  {
    "path": ".github/workflows/publish-to-pypi.yml",
    "chars": 996,
    "preview": "name: Build and Publish to PyPI\n\non:\n  workflow_dispatch:\n  release:\n    types: [published]\n\njobs:\n  build-and-publish:\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "chars": 1783,
    "preview": "name: Unit Tests\n\non:\n  pull_request:\n    types: [opened, ready_for_review, synchronize]\n    paths:\n      - 'pkg/**'\n   "
  },
  {
    "path": ".github/workflows/test-dev-image.yaml",
    "chars": 3242,
    "preview": "name: Test Dev Image\n\non:\n  workflow_run:\n    workflows: [\"Build Dev Image\"]\n    types:\n      - completed\n    branches:\n"
  },
  {
    "path": ".gitignore",
    "chars": 644,
    "preview": "/config.py\n.idea/\n__pycache__/\ndatabase.db\nlangbot.log\n/banlist.py\n/plugins/\n!/plugins/__init__.py\n/revcfg.py\nprompts/\nl"
  },
  {
    "path": ".mcp.json",
    "chars": 795,
    "preview": "{\n  \"mcpServers\": {\n    \"shadcn\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"shadcn@latest\",\n        \"mcp\"\n     "
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 685,
    "preview": "repos:\n  - repo: https://github.com/astral-sh/ruff-pre-commit\n    # Ruff version.\n    rev: v0.11.7\n    hooks:\n      # Ru"
  },
  {
    "path": "AGENTS.md",
    "chars": 4711,
    "preview": "# AGENTS.md\n\nThis file is for guiding code agents (like Claude Code, GitHub Copilot, OpenAI Codex, etc.) to work in Lang"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 735,
    "preview": "## 参与项目\n\n欢迎为此项目贡献代码或其他支持,以使您的点子或众人期待的功能成为现实,助力社区成长。  \n\n### 贡献形式\n\n- 提交PR,解决issues中提到的bug或期待的功能\n- 提交PR,实现您设想的功能(请先提出issue与"
  },
  {
    "path": "Dockerfile",
    "chars": 373,
    "preview": "FROM node:22-alpine AS node\n\nWORKDIR /app\n\nCOPY web ./web\n\nRUN cd web && npm install && npm run build\n\nFROM python:3.12."
  },
  {
    "path": "LICENSE",
    "chars": 11356,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 7546,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_CN.md",
    "chars": 7125,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_ES.md",
    "chars": 7974,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_FR.md",
    "chars": 8015,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_JP.md",
    "chars": 6507,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_KO.md",
    "chars": 6396,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_RU.md",
    "chars": 7898,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_TW.md",
    "chars": 6783,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "README_VI.md",
    "chars": 7601,
    "preview": "<p align=\"center\">\n<a href=\"https://langbot.app\">\n<img width=\"130\" src=\"res/logo-blue.png\" alt=\"LangBot\"/>\n</a>\n\n<div al"
  },
  {
    "path": "codecov.yml",
    "chars": 51,
    "preview": "coverage:\n  status:\n    project: off\n    patch: off"
  },
  {
    "path": "docker/README_K8S.md",
    "chars": 12285,
    "preview": "# LangBot Kubernetes 部署指南 / Kubernetes Deployment Guide\n\n[简体中文](#简体中文) | [English](#english)\n\n---\n\n## 简体中文\n\n### 概述\n\n本指南提"
  },
  {
    "path": "docker/deploy-k8s-test.sh",
    "chars": 1925,
    "preview": "#!/bin/bash\n# Quick test script for LangBot Kubernetes deployment\n# This script helps you test the Kubernetes deployment"
  },
  {
    "path": "docker/docker-compose.yaml",
    "chars": 902,
    "preview": "# Docker Compose configuration for LangBot\n# For Kubernetes deployment, see kubernetes.yaml and README_K8S.md\nversion: \""
  },
  {
    "path": "docker/kubernetes.yaml",
    "chars": 9516,
    "preview": "# Kubernetes Deployment for LangBot\n# This file provides Kubernetes deployment manifests for LangBot based on docker-com"
  },
  {
    "path": "docs/API_KEY_AUTH.md",
    "chars": 6036,
    "preview": "# API Key Authentication\n\nLangBot now supports API key authentication for external systems to access its HTTP service AP"
  },
  {
    "path": "docs/MIGRATION_SUMMARY.md",
    "chars": 6887,
    "preview": "# WebChat 到 WebSocket 迁移总结\n\n## 概述\n\n已完全移除旧的基于SSE的WebChat系统,并替换为基于WebSocket的双向实时通信系统。这是一个内置在LangBot中的完整IM系统,支持流式输出。\n\n## 已删"
  },
  {
    "path": "docs/PYPI_INSTALLATION.md",
    "chars": 3062,
    "preview": "# LangBot PyPI Package Installation\n\n## Quick Start with uvx\n\nThe easiest way to run LangBot is using `uvx` (recommended"
  },
  {
    "path": "docs/SEEKDB_INTEGRATION.md",
    "chars": 8306,
    "preview": "# SeekDB Vector Database Integration\n\nThis document describes how to use OceanBase SeekDB as the vector database backend"
  },
  {
    "path": "docs/TESTING_SUMMARY.md",
    "chars": 5865,
    "preview": "# Pipeline Unit Tests - Implementation Summary\n\n## Overview\n\nComprehensive unit test suite for LangBot's pipeline stages"
  },
  {
    "path": "docs/WEBSOCKET_README.md",
    "chars": 5870,
    "preview": "# LangBot WebSocket 双向通信系统\n\n## 概述\n\n这是一个内置在 LangBot 中的完整 IM (即时通讯) 系统,支持:\n\n- ✅ WebSocket 双向实时通信\n- ✅ 多个客户端并发连接\n- ✅ 前端到后端的消"
  },
  {
    "path": "docs/service-api-openapi.json",
    "chars": 49584,
    "preview": "{\n  \"openapi\": \"3.0.3\",\n  \"info\": {\n    \"title\": \"LangBot API with API Key Authentication\",\n    \"description\": \"LangBot "
  },
  {
    "path": "main.py",
    "chars": 49,
    "preview": "import langbot.__main__\n\nlangbot.__main__.main()\n"
  },
  {
    "path": "pyproject.toml",
    "chars": 5603,
    "preview": "[project]\nname = \"langbot\"\nversion = \"4.9.3\"\ndescription = \"Production-grade platform for building agentic IM bots\"\nread"
  },
  {
    "path": "pytest.ini",
    "chars": 678,
    "preview": "[pytest]\n# Test discovery patterns\npython_files = test_*.py\npython_classes = Test*\npython_functions = test_*\n\n# Test pat"
  },
  {
    "path": "res/announcement.json",
    "chars": 3,
    "preview": "[]\n"
  },
  {
    "path": "res/announcement_saved.json",
    "chars": 2,
    "preview": "[]"
  },
  {
    "path": "res/instance_id.json",
    "chars": 154,
    "preview": "{\"host_id\": \"host_9b4a220d-3bb6-42fc-aec3-41188ce0a41c\", \"instance_id\": \"instance_61d8f262-b98a-4165-8e77-85fb6262529e\","
  },
  {
    "path": "res/scripts/publish_announcement.py",
    "chars": 726,
    "preview": "# 输出工作路径\nimport os\nimport time\nimport json\n\nprint('工作路径: ' + os.getcwd())\nannouncement = input('请输入公告内容: ')\n\n# 读取现有的公告文件"
  },
  {
    "path": "run_tests.sh",
    "chars": 684,
    "preview": "#!/bin/bash\n\n# Script to run all unit tests\n# This script helps avoid circular import issues by setting up the environme"
  },
  {
    "path": "src/langbot/__init__.py",
    "chars": 94,
    "preview": "\"\"\"LangBot - Production-grade platform for building agentic IM bots\"\"\"\n\n__version__ = '4.9.3'\n"
  },
  {
    "path": "src/langbot/__main__.py",
    "chars": 3011,
    "preview": "\"\"\"LangBot entry point for package execution\"\"\"\n\nimport asyncio\nimport argparse\nimport sys\nimport os\n\n# ASCII art banner"
  },
  {
    "path": "src/langbot/libs/LICENSE",
    "chars": 35148,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "src/langbot/libs/README.md",
    "chars": 91,
    "preview": "# LangBot/libs\n\nLangBot 项目下的 libs 目录下的所有代码均遵循本目录下的许可证约束。  \n您在使用、修改、分发本目录下的代码时,需要遵守其中包含的条款。\n"
  },
  {
    "path": "src/langbot/libs/coze_server_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/coze_server_api/client.py",
    "chars": 5718,
    "preview": "import json\nimport asyncio\nimport aiohttp\nimport io\nfrom typing import Dict, List, Any, AsyncGenerator\nimport os\nfrom pa"
  },
  {
    "path": "src/langbot/libs/dify_service_api/README.md",
    "chars": 69,
    "preview": "# Dify Service API Python SDK\n\n这个 SDK 尚不完全支持 Dify Service API 的所有功能。\n"
  },
  {
    "path": "src/langbot/libs/dify_service_api/__init__.py",
    "chars": 98,
    "preview": "from .v1 import client as client\nfrom .v1 import errors as errors\n\n__all__ = ['client', 'errors']\n"
  },
  {
    "path": "src/langbot/libs/dify_service_api/v1/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/dify_service_api/v1/client.py",
    "chars": 4829,
    "preview": "from __future__ import annotations\n\nimport httpx\nimport typing\nimport json\n\nfrom .errors import DifyAPIError\nfrom pathli"
  },
  {
    "path": "src/langbot/libs/dify_service_api/v1/client_test.py",
    "chars": 372,
    "preview": "from . import client\n\nimport asyncio\n\nimport os\n\n\nclass TestDifyClient:\n    async def test_chat_messages(self):\n        "
  },
  {
    "path": "src/langbot/libs/dify_service_api/v1/errors.py",
    "chars": 164,
    "preview": "class DifyAPIError(Exception):\n    \"\"\"Dify API 请求失败\"\"\"\n\n    def __init__(self, message: str):\n        self.message = mes"
  },
  {
    "path": "src/langbot/libs/dingtalk_api/EchoHandler.py",
    "chars": 988,
    "preview": "import asyncio\nimport dingtalk_stream  # type: ignore\nfrom dingtalk_stream import AckMessage\n\n\nclass EchoTextHandler(din"
  },
  {
    "path": "src/langbot/libs/dingtalk_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/dingtalk_api/api.py",
    "chars": 19213,
    "preview": "import asyncio\nimport base64\nimport json\nimport time\nimport urllib.parse\nfrom typing import Callable\nimport dingtalk_str"
  },
  {
    "path": "src/langbot/libs/dingtalk_api/dingtalkevent.py",
    "chars": 1703,
    "preview": "from typing import Dict, Any, Optional\nimport dingtalk_stream  # type: ignore\n\n\nclass DingTalkEvent(dict):\n    @staticme"
  },
  {
    "path": "src/langbot/libs/official_account_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/official_account_api/api.py",
    "chars": 13588,
    "preview": "# 微信公众号的加解密算法与企业微信一样,所以直接使用企业微信的加解密算法文件\nimport time\nimport traceback\nfrom langbot.libs.wecom_api.WXBizMsgCrypt3 import W"
  },
  {
    "path": "src/langbot/libs/official_account_api/oaevent.py",
    "chars": 3482,
    "preview": "from typing import Dict, Any, Optional\n\n\nclass OAEvent(dict):\n    \"\"\"\n    封装从微信公众号收到的事件数据对象(字典),提供属性以获取其中的字段。\n\n    除 `ty"
  },
  {
    "path": "src/langbot/libs/qq_official_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/qq_official_api/api.py",
    "chars": 11156,
    "preview": "import time\nfrom quart import request\nimport httpx\nfrom quart import Quart\nfrom typing import Callable, Dict, Any\nimport"
  },
  {
    "path": "src/langbot/libs/qq_official_api/qqofficialevent.py",
    "chars": 2140,
    "preview": "from typing import Dict, Any, Optional\n\n\nclass QQOfficialEvent(dict):\n    @staticmethod\n    def from_payload(payload: Di"
  },
  {
    "path": "src/langbot/libs/slack_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/slack_api/api.py",
    "chars": 4389,
    "preview": "import json\nimport traceback\nfrom quart import Quart, jsonify, request\nfrom slack_sdk.web.async_client import AsyncWebCl"
  },
  {
    "path": "src/langbot/libs/slack_api/slackevent.py",
    "chars": 2757,
    "preview": "from typing import Dict, Any, Optional\n\n\nclass SlackEvent(dict):\n    @staticmethod\n    def from_payload(payload: Dict[st"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "src/langbot/libs/wechatpad_api/README.md",
    "chars": 367,
    "preview": "# wechatpad-python\n\n\n## 此项目时准备对接wechatpadpro 的pythonsdk\n\n## 未完工接口\n\n* 关于好友的接口\n* 关于群管理的接口\n* 关于下载的接口\n* 关于用户的部分接口\n* 关于消息的部分接"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/__init__.py",
    "chars": 55,
    "preview": "from .client import WeChatPadClient as WeChatPadClient\n"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/chatroom.py",
    "chars": 417,
    "preview": "from langbot.libs.wechatpad_api.util.http_util import post_json\n\n\nclass ChatRoomApi:\n    def __init__(self, base_url, to"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/downloadpai.py",
    "chars": 1180,
    "preview": "from langbot.libs.wechatpad_api.util.http_util import post_json\nimport httpx\nimport base64\n\n\nclass DownloadApi:\n    def "
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/friend.py",
    "chars": 161,
    "preview": "class FriendApi:\n    \"\"\"联系人API类,处理所有与联系人相关的操作\"\"\"\n\n    def __init__(self, base_url: str, token: str):\n        self.base_u"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/login.py",
    "chars": 2212,
    "preview": "from langbot.libs.wechatpad_api.util.http_util import post_json, get_json\n\n\nclass LoginApi:\n    def __init__(self, base_"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/message.py",
    "chars": 3000,
    "preview": "from langbot.libs.wechatpad_api.util.http_util import post_json\n\n\nclass MessageApi:\n    def __init__(self, base_url, tok"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/api/user.py",
    "chars": 1045,
    "preview": "from langbot.libs.wechatpad_api.util.http_util import post_json, async_request, get_json\n\n\nclass UserApi:\n    def __init"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/client.py",
    "chars": 3437,
    "preview": "from langbot.libs.wechatpad_api.api.login import LoginApi\nfrom langbot.libs.wechatpad_api.api.friend import FriendApi\nfr"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/util/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/wechatpad_api/util/http_util.py",
    "chars": 2068,
    "preview": "import requests\nfrom langbot.pkg.utils import httpclient\n\n\ndef post_json(base_url, token, data=None):\n    headers = {'Co"
  },
  {
    "path": "src/langbot/libs/wechatpad_api/util/terminal_printer.py",
    "chars": 596,
    "preview": "import qrcode\n\n\ndef print_green(text):\n    print(f'\\033[32m{text}\\033[0m')\n\n\ndef print_yellow(text):\n    print(f'\\033[33"
  },
  {
    "path": "src/langbot/libs/wecom_ai_bot_api/WXBizMsgCrypt3.py",
    "chars": 8864,
    "preview": "#!/usr/bin/env python\n# -*- encoding:utf-8 -*-\n\n\"\"\"对企业微信发送给企业后台的消息加解密示例代码.\n@copyright: Copyright (c) 1998-2014 Tencent I"
  },
  {
    "path": "src/langbot/libs/wecom_ai_bot_api/api.py",
    "chars": 27479,
    "preview": "import asyncio\nimport base64\nimport json\nimport time\nimport traceback\nimport uuid\nimport xml.etree.ElementTree as ET\nfro"
  },
  {
    "path": "src/langbot/libs/wecom_ai_bot_api/ierror.py",
    "chars": 781,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#########################################################################\n"
  },
  {
    "path": "src/langbot/libs/wecom_ai_bot_api/wecombotevent.py",
    "chars": 2533,
    "preview": "from typing import Dict, Any, Optional\n\n\nclass WecomBotEvent(dict):\n    @staticmethod\n    def from_payload(payload: Dict"
  },
  {
    "path": "src/langbot/libs/wecom_ai_bot_api/ws_client.py",
    "chars": 22848,
    "preview": "\"\"\"WeChat Work AI Bot WebSocket long connection client.\n\nImplements the WebSocket protocol for receiving messages and se"
  },
  {
    "path": "src/langbot/libs/wecom_api/WXBizMsgCrypt3.py",
    "chars": 8837,
    "preview": "#!/usr/bin/env python\n# -*- encoding:utf-8 -*-\n\n\"\"\"对企业微信发送给企业后台的消息加解密示例代码.\n@copyright: Copyright (c) 1998-2014 Tencent I"
  },
  {
    "path": "src/langbot/libs/wecom_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/wecom_api/api.py",
    "chars": 21539,
    "preview": "from quart import request\nfrom .WXBizMsgCrypt3 import WXBizMsgCrypt\nimport base64\nimport binascii\nimport httpx\nimport tr"
  },
  {
    "path": "src/langbot/libs/wecom_api/ierror.py",
    "chars": 781,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#########################################################################\n"
  },
  {
    "path": "src/langbot/libs/wecom_api/wecomevent.py",
    "chars": 3757,
    "preview": "from typing import Dict, Any, Optional\n\n\nclass WecomEvent(dict):\n    \"\"\"\n    封装从企业微信收到的事件数据对象(字典),提供属性以获取其中的字段。\n\n    除 `"
  },
  {
    "path": "src/langbot/libs/wecom_customer_service_api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/libs/wecom_customer_service_api/api.py",
    "chars": 16654,
    "preview": "from quart import request\nfrom ..wecom_api.WXBizMsgCrypt3 import WXBizMsgCrypt\nimport base64\nimport binascii\nimport http"
  },
  {
    "path": "src/langbot/libs/wecom_customer_service_api/wecomcsevent.py",
    "chars": 2771,
    "preview": "from typing import Dict, Any, Optional\n\n\nclass WecomCSEvent(dict):\n    \"\"\"\n    封装从企业微信收到的事件数据对象(字典),提供属性以获取其中的字段。\n\n    除"
  },
  {
    "path": "src/langbot/pkg/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/group.py",
    "chars": 6983,
    "preview": "from __future__ import annotations\n\nimport abc\nimport typing\nimport enum\nimport quart\nimport traceback\nfrom quart.typing"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/apikeys.py",
    "chars": 1759,
    "preview": "import quart\n\nfrom .. import group\n\n\n@group.group_class('apikeys', '/api/v1/apikeys')\nclass ApiKeysRouterGroup(group.Rou"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/files.py",
    "chars": 4870,
    "preview": "from __future__ import annotations\n\nimport quart\nimport mimetypes\nimport uuid\nimport asyncio\n\nimport quart.datastructure"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/knowledge/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/knowledge/base.py",
    "chars": 4688,
    "preview": "import quart\nfrom ... import group\n\n\n@group.group_class('knowledge_base', '/api/v1/knowledge/bases')\nclass KnowledgeBase"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/knowledge/engines.py",
    "chars": 2253,
    "preview": "import quart\nfrom urllib.parse import unquote\nfrom ... import group\n\n\n@group.group_class('knowledge_engines', '/api/v1/k"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/knowledge/migration.py",
    "chars": 17680,
    "preview": "import asyncio\nimport json\n\nimport httpx\nimport quart\nimport sqlalchemy\n\nfrom ... import group\nfrom ......core import ta"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/knowledge/parsers.py",
    "chars": 683,
    "preview": "import quart\nfrom ... import group\n\n\n@group.group_class('parsers', '/api/v1/knowledge/parsers')\nclass ParsersRouterGroup"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/logs.py",
    "chars": 878,
    "preview": "from __future__ import annotations\n\n\nimport quart\n\nfrom .. import group\n\n\n@group.group_class('logs', '/api/v1/logs')\ncla"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/monitoring.py",
    "chars": 19488,
    "preview": "from __future__ import annotations\n\nimport datetime\nimport quart\n\nfrom .. import group\n\n\ndef parse_iso_datetime(datetime"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/pipelines/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/pipelines/pipelines.py",
    "chars": 4908,
    "preview": "from __future__ import annotations\n\nimport quart\n\nfrom ... import group\n\n\n@group.group_class('pipelines', '/api/v1/pipel"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py",
    "chars": 9590,
    "preview": "\"\"\"WebSocket聊天路由 - 支持双向实时通信\"\"\"\n\nimport asyncio\nimport datetime\nimport json\nimport logging\n\nimport quart\n\nfrom ... import"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/platform/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/platform/adapters.py",
    "chars": 1473,
    "preview": "import quart\nimport mimetypes\nfrom ... import group\nfrom langbot.pkg.utils import importutil\n\n\n@group.group_class('adapt"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/platform/bots.py",
    "chars": 3466,
    "preview": "import quart\n\nfrom ... import group\n\n\n@group.group_class('bots', '/api/v1/platform/bots')\nclass BotsRouterGroup(group.Ro"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/plugins.py",
    "chars": 15647,
    "preview": "from __future__ import annotations\n\nimport base64\nimport quart\nimport re\nimport httpx\nimport uuid\nimport os\n\nfrom .....c"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/provider/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/provider/models.py",
    "chars": 4549,
    "preview": "import quart\n\nfrom ... import group\n\n\n@group.group_class('models/llm', '/api/v1/provider/models/llm')\nclass LLMModelsRou"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/provider/providers.py",
    "chars": 2350,
    "preview": "import quart\n\nfrom ... import group\n\n\n@group.group_class('models/providers', '/api/v1/provider/providers')\nclass ModelPr"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/provider/requesters.py",
    "chars": 1610,
    "preview": "import quart\nimport mimetypes\n\nfrom ... import group\nfrom langbot.pkg.utils import importutil\n\n\n@group.group_class('prov"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/resources/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/resources/mcp.py",
    "chars": 2637,
    "preview": "from __future__ import annotations\n\nimport quart\nimport traceback\n\n\nfrom ... import group\n\n\n@group.group_class('mcp', '/"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/stats.py",
    "chars": 747,
    "preview": "from .. import group\n\n\n@group.group_class('stats', '/api/v1/stats')\nclass StatsRouterGroup(group.RouterGroup):\n    async"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/survey.py",
    "chars": 1900,
    "preview": "import quart\n\nfrom .. import group\n\n\n@group.group_class('survey', '/api/v1/survey')\nclass SurveyRouterGroup(group.Router"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/system.py",
    "chars": 3886,
    "preview": "import quart\n\nfrom .. import group\nfrom .....utils import constants\n\n\n@group.group_class('system', '/api/v1/system')\ncla"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/user.py",
    "chars": 11173,
    "preview": "import quart\nimport argon2\nimport asyncio\nimport traceback\n\nfrom .. import group\nfrom .....entity.errors import account "
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/webhook_mgmt.py",
    "chars": 2166,
    "preview": "import quart\n\nfrom .. import group\n\n\n@group.group_class('webhook_mgmt', '/api/v1/webhooks')\nclass WebhookManagementRoute"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/groups/webhooks.py",
    "chars": 1866,
    "preview": "from __future__ import annotations\n\nimport quart\nimport traceback\n\nfrom .. import group\n\n\n@group.group_class('webhooks',"
  },
  {
    "path": "src/langbot/pkg/api/http/controller/main.py",
    "chars": 5036,
    "preview": "from __future__ import annotations\n\nimport asyncio\nimport os\n\nimport quart\nimport quart_cors\nfrom werkzeug.exceptions im"
  },
  {
    "path": "src/langbot/pkg/api/http/service/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/api/http/service/apikey.py",
    "chars": 2734,
    "preview": "from __future__ import annotations\n\nimport secrets\nimport sqlalchemy\n\nfrom ....core import app\nfrom ....entity.persisten"
  },
  {
    "path": "src/langbot/pkg/api/http/service/bot.py",
    "chars": 7624,
    "preview": "from __future__ import annotations\n\nimport uuid\nimport sqlalchemy\nimport typing\n\nfrom ....core import app\nfrom ....entit"
  },
  {
    "path": "src/langbot/pkg/api/http/service/knowledge.py",
    "chars": 8618,
    "preview": "from __future__ import annotations\n\nimport sqlalchemy\n\nfrom ....core import app\nfrom ....entity.persistence import rag a"
  },
  {
    "path": "src/langbot/pkg/api/http/service/mcp.py",
    "chars": 7661,
    "preview": "from __future__ import annotations\n\nimport sqlalchemy\nimport uuid\nimport asyncio\n\nfrom ....core import app\nfrom ....enti"
  },
  {
    "path": "src/langbot/pkg/api/http/service/model.py",
    "chars": 15813,
    "preview": "from __future__ import annotations\n\nimport uuid\n\nimport sqlalchemy\nfrom langbot_plugin.api.entities.builtin.provider imp"
  },
  {
    "path": "src/langbot/pkg/api/http/service/monitoring.py",
    "chars": 47440,
    "preview": "from __future__ import annotations\n\nimport uuid\nimport datetime\nimport sqlalchemy\n\nfrom ....core import app\nfrom ....ent"
  },
  {
    "path": "src/langbot/pkg/api/http/service/pipeline.py",
    "chars": 10232,
    "preview": "from __future__ import annotations\n\nimport uuid\nimport json\nimport sqlalchemy\n\nfrom ....core import app\nfrom ....entity."
  },
  {
    "path": "src/langbot/pkg/api/http/service/provider.py",
    "chars": 6806,
    "preview": "from __future__ import annotations\n\nimport uuid\n\nimport sqlalchemy\n\nfrom ....core import app\nfrom ....entity.persistence"
  },
  {
    "path": "src/langbot/pkg/api/http/service/space.py",
    "chars": 7762,
    "preview": "from __future__ import annotations\n\nfrom langbot.pkg.utils import httpclient\nimport typing\nimport datetime\nimport time\ni"
  },
  {
    "path": "src/langbot/pkg/api/http/service/user.py",
    "chars": 12190,
    "preview": "from __future__ import annotations\n\nimport sqlalchemy\nimport argon2\nimport jwt\nimport datetime\nimport typing\nimport asyn"
  },
  {
    "path": "src/langbot/pkg/api/http/service/webhook.py",
    "chars": 3051,
    "preview": "from __future__ import annotations\n\nimport sqlalchemy\n\nfrom ....core import app\nfrom ....entity.persistence import webho"
  },
  {
    "path": "src/langbot/pkg/command/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/command/cmdmgr.py",
    "chars": 3709,
    "preview": "from __future__ import annotations\n\nimport typing\n\nfrom ..core import app\nfrom . import operator\nfrom ..utils import imp"
  },
  {
    "path": "src/langbot/pkg/command/operator.py",
    "chars": 2816,
    "preview": "from __future__ import annotations\n\nimport typing\nimport abc\n\nfrom ..core import app\nfrom langbot_plugin.api.entities.bu"
  },
  {
    "path": "src/langbot/pkg/command/operators/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/command/operators/delc.py",
    "chars": 2078,
    "preview": "# from __future__ import annotations\n\n# import typing\n\n# from .. import operator\n# from langbot_plugin.api.entities.buil"
  },
  {
    "path": "src/langbot/pkg/command/operators/last.py",
    "chars": 1590,
    "preview": "# from __future__ import annotations\n\n# import typing\n\n\n# from .. import operator\n# from langbot_plugin.api.entities.bui"
  },
  {
    "path": "src/langbot/pkg/command/operators/list.py",
    "chars": 1972,
    "preview": "# from __future__ import annotations\n\n# import typing\n\n# from .. import operator\n# from langbot_plugin.api.entities.buil"
  },
  {
    "path": "src/langbot/pkg/command/operators/next.py",
    "chars": 1608,
    "preview": "# from __future__ import annotations\n\n# import typing\n\n# from .. import operator\n# from langbot_plugin.api.entities.buil"
  },
  {
    "path": "src/langbot/pkg/command/operators/prompt.py",
    "chars": 911,
    "preview": "# from __future__ import annotations\n\n# import typing\n\n# from .. import operator\n# from langbot_plugin.api.entities.buil"
  },
  {
    "path": "src/langbot/pkg/command/operators/resend.py",
    "chars": 1094,
    "preview": "# from __future__ import annotations\n\n# import typing\n\n# from .. import operator\n# from langbot_plugin.api.entities.buil"
  },
  {
    "path": "src/langbot/pkg/config/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/config/impls/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/config/impls/json.py",
    "chars": 2467,
    "preview": "import os\nimport json\nimport importlib.resources as resources\n\nfrom langbot.pkg.config import model as file_model\n\n\nclas"
  },
  {
    "path": "src/langbot/pkg/config/impls/pymodule.py",
    "chars": 1951,
    "preview": "import os\nimport shutil\nimport importlib\nimport logging\n\nfrom .. import model as file_model\n\n\nclass PythonModuleConfigFi"
  },
  {
    "path": "src/langbot/pkg/config/impls/yaml.py",
    "chars": 2508,
    "preview": "import os\nimport yaml\nimport importlib.resources as resources\n\nfrom langbot.pkg.config import model as file_model\n\n\nclas"
  },
  {
    "path": "src/langbot/pkg/config/manager.py",
    "chars": 2968,
    "preview": "from __future__ import annotations\n\nfrom . import model as file_model\nfrom .impls import pymodule, json as json_file, ya"
  },
  {
    "path": "src/langbot/pkg/config/model.py",
    "chars": 655,
    "preview": "import abc\n\n\nclass ConfigFile(metaclass=abc.ABCMeta):\n    \"\"\"Config file abstract class\"\"\"\n\n    config_file_name: str = "
  },
  {
    "path": "src/langbot/pkg/core/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/core/app.py",
    "chars": 7559,
    "preview": "from __future__ import annotations\n\nimport logging\nimport asyncio\nimport traceback\nimport os\n\nfrom ..platform import bot"
  },
  {
    "path": "src/langbot/pkg/core/boot.py",
    "chars": 1366,
    "preview": "from __future__ import annotations\n\nimport traceback\nimport asyncio\nimport os\n\nfrom . import app\nfrom . import stage\nfro"
  },
  {
    "path": "src/langbot/pkg/core/bootutils/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/core/bootutils/config.py",
    "chars": 242,
    "preview": "from __future__ import annotations\n\n\nfrom ...config import manager as config_mgr\n\n\nload_python_module_config = config_mg"
  },
  {
    "path": "src/langbot/pkg/core/bootutils/deps.py",
    "chars": 2438,
    "preview": "import importlib.util\nimport pip\nimport os\nfrom ...utils import pkgmgr\n\n# Check dependencies to prevent users from not i"
  },
  {
    "path": "src/langbot/pkg/core/bootutils/files.py",
    "chars": 785,
    "preview": "from __future__ import annotations\n\nimport os\nimport shutil\n\n\nrequired_files = {\n    'data/config.yaml': 'templates/conf"
  },
  {
    "path": "src/langbot/pkg/core/bootutils/log.py",
    "chars": 2496,
    "preview": "import logging\nimport logging.handlers\nimport sys\nimport time\n\nimport colorlog\n\nfrom ...utils import constants\n\n\nlog_col"
  },
  {
    "path": "src/langbot/pkg/core/entities.py",
    "chars": 196,
    "preview": "from __future__ import annotations\n\nimport enum\n\n\nclass LifecycleControlScope(enum.Enum):\n    APPLICATION = 'application"
  },
  {
    "path": "src/langbot/pkg/core/migration.py",
    "chars": 909,
    "preview": "from __future__ import annotations\n\nimport abc\nimport typing\n\nfrom . import app\n\n\npreregistered_migrations: list[typing."
  },
  {
    "path": "src/langbot/pkg/core/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "src/langbot/pkg/core/migrations/m001_sensitive_word_migration.py",
    "chars": 642,
    "preview": "from __future__ import annotations\n\nimport os\n\nfrom .. import migration\n\n\n@migration.migration_class('sensitive-word-mig"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m002_openai_config_migration.py",
    "chars": 1586,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('openai-config-migration', 2)\n"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m003_anthropic_requester_cfg_completion.py",
    "chars": 1004,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('anthropic-requester-config-co"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m004_moonshot_cfg_completion.py",
    "chars": 984,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('moonshot-config-completion', "
  },
  {
    "path": "src/langbot/pkg/core/migrations/m005_deepseek_cfg_completion.py",
    "chars": 982,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('deepseek-config-completion', "
  },
  {
    "path": "src/langbot/pkg/core/migrations/m006_vision_config.py",
    "chars": 529,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('vision-config', 6)\nclass Visi"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m007_qcg_center_url.py",
    "chars": 576,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('qcg-center-url-config', 7)\ncl"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m008_ad_fixwin_config_migrate.py",
    "chars": 780,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('ad-fixwin-cfg-migration', 8)\n"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m009_msg_truncator_cfg.py",
    "chars": 560,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('msg-truncator-cfg-migration',"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m010_ollama_requester_config.py",
    "chars": 612,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('ollama-requester-config', 10)"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m011_command_prefix_config.py",
    "chars": 485,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('command-prefix-config', 11)\nc"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m012_runner_config.py",
    "chars": 460,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('runner-config', 12)\nclass Run"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m013_http_api_config.py",
    "chars": 772,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('http-api-config', 13)\nclass H"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m014_force_delay_config.py",
    "chars": 617,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('force-delay-config', 14)\nclas"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m015_gitee_ai_config.py",
    "chars": 785,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('gitee-ai-config', 15)\nclass G"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m016_dify_service_api.py",
    "chars": 705,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('dify-service-api-config', 16)"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m017_dify_api_timeout_params.py",
    "chars": 944,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('dify-api-timeout-params', 17)"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m018_xai_config.py",
    "chars": 674,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('xai-config', 18)\nclass XaiCon"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m019_zhipuai_config.py",
    "chars": 704,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('zhipuai-config', 19)\nclass Zh"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m020_wecom_config.py",
    "chars": 938,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('wecom-config', 20)\nclass Weco"
  },
  {
    "path": "src/langbot/pkg/core/migrations/m021_lark_config.py",
    "chars": 943,
    "preview": "from __future__ import annotations\n\nfrom .. import migration\n\n\n@migration.migration_class('lark-config', 21)\nclass LarkC"
  }
]

// ... and 526 more files (download for full content)

About this extraction

This page contains the full source code of the langbot-app/LangBot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 726 files (3.1 MB), approximately 865.6k tokens, and a symbol index with 3023 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.

Copied to clipboard!