langbot-plugin 0.4.1__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/AGENTS.md +173 -83
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/PKG-INFO +2 -1
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/pyproject.toml +2 -1
- langbot_plugin-0.4.2/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example +77 -0
- langbot_plugin-0.4.2/src/langbot_plugin/assets/templates/README.md.example +15 -0
- langbot_plugin-0.4.2/src/langbot_plugin/assets/templates/readme/README_zh_Hans.md.example +15 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/client.py +6 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/nsjail_backend.py +80 -14
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/initplugin.py +4 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/gen/renderer.py +2 -0
- langbot_plugin-0.4.2/src/langbot_plugin/entities/io/errors.py +91 -0
- langbot_plugin-0.4.2/src/langbot_plugin/runtime/helper/pkgmgr.py +369 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/plugin/mgr.py +78 -12
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_nsjail_backend.py +118 -18
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_initplugin.py +2 -0
- langbot_plugin-0.4.2/tests/entities/io/test_dependency_errors.py +59 -0
- langbot_plugin-0.4.2/tests/runtime/helper/test_pkgmgr.py +388 -0
- langbot_plugin-0.4.2/tests/runtime/io/test_handler.py +578 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/plugin/test_manager.py +62 -2
- langbot_plugin-0.4.1/src/langbot_plugin/assets/templates/README.md.example +0 -3
- langbot_plugin-0.4.1/src/langbot_plugin/entities/io/errors.py +0 -31
- langbot_plugin-0.4.1/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -141
- langbot_plugin-0.4.1/tests/runtime/helper/test_pkgmgr.py +0 -109
- langbot_plugin-0.4.1/tests/runtime/io/test_handler.py +0 -228
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/.github/workflows/publish-pypi.yaml +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/.github/workflows/test.yml +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/.gitignore +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/.python-version +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/CLAUDE.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/LICENSE +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/README.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/data/.env.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/docs/Message.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/docs/PluginPages.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/docs/communication/apis/lb2rt.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/docs/communication/runtime_plugin.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/docs/dependency-management.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/docs/langbot-plugin-social.png +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/base.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/definition/plugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/entities/events.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/proxies/base.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/proxies/event_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/main.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/actions.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/e2b_backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/models.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/runtime.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/security.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/box/skill_store.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/__main__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/login.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/logout.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/publish.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/gen/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/i18n.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/en_US.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/run/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/run/controller.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/run/handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/run/hotreload.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/utils/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/utils/form.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/cli/utils/page_components.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/io/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/io/req.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/io/resp.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/entities/marketplace.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/LICENSE +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/README.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/app.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/connection.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controller.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/plugin/container.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/runtime/settings.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/utils/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/utils/discover/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/utils/discover/engine.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/utils/importutil.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/utils/log.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/utils/platform.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/src/langbot_plugin/version.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/definition/components/test_components.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/definition/test_manifest.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/entities/builtin/test_command_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/entities/builtin/test_platform_logger.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/entities/builtin/test_provider_message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/entities/builtin/test_rag_models.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/entities/test_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/entities/test_events.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/proxies/test_base.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/proxies/test_langbot_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/api/proxies/test_query_based_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_backend_selection.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_e2b_backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_runtime.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/box/test_skill_store.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/run/test_controller.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/run/test_runtime_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_buildplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_gencomponent.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_i18n_form.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_login.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_logout_publish.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_page_components.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_renderer.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/cli/test_runplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/entities/io/test_protocol.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/helpers/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/helpers/protocol.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/helper/test_marketplace.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/io/handlers/test_control_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/io/test_connections.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/io/test_controllers.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/plugin/test_container.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/runtime/test_app.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/test_log.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/test_message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/utils/test_discovery.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/utils/test_importutil.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2}/tests/utils/test_platform.py +0 -0
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
This file is for guiding code agents (like Claude Code, GitHub Copilot, OpenAI Codex, etc.) to work in the langbot-plugin-sdk project.
|
|
3
|
+
This file is for guiding code agents (like Claude Code, GitHub Copilot, OpenAI Codex, etc.) to work in the langbot-plugin-sdk project. `CLAUDE.md` is a symlink to this file.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> Always verify specifics (file paths, CLI flags, function signatures) against the actual source before relying on them. When you find this doc out of date, fix it as part of your change.
|
|
6
6
|
|
|
7
7
|
## Project Overview
|
|
8
8
|
|
|
9
9
|
LangBot Plugin SDK is the infrastructure for LangBot's plugin system, providing:
|
|
10
10
|
- **Plugin SDK**: Python APIs and interfaces for plugin development
|
|
11
|
-
- **Plugin Runtime**: Execution environment managing plugin lifecycle
|
|
12
|
-
- **
|
|
11
|
+
- **Plugin Runtime**: Execution environment managing plugin lifecycle (`lbp rt`)
|
|
12
|
+
- **Box Runtime**: Code-sandbox runtime service backing LangBot's Box subsystem (`lbp box`)
|
|
13
|
+
- **CLI Tools**: `lbp` command for scaffolding, building, debugging, and running runtimes
|
|
13
14
|
- **Communication Protocol**: Bidirectional action-based protocol (stdio/WebSocket)
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **
|
|
16
|
+
This SDK is the shared dependency between LangBot and plugins; LangBot pins it as `langbot-plugin==<x.y.z>` in its `pyproject.toml`. The package version lives in this repo's `pyproject.toml`.
|
|
17
|
+
|
|
18
|
+
The SDK enables developers to extend LangBot with custom components. Six component types are supported (scaffold any of them with `lbp comp <Type>`):
|
|
19
|
+
- **Command**: User-triggered actions (e.g., `!weather tokyo`)
|
|
20
|
+
- **Tool**: LLM-callable functions for AI agents (e.g., web search, database queries)
|
|
21
|
+
- **EventListener**: Handlers for message-pipeline events (e.g., auto-reply, content filtering)
|
|
22
|
+
- **KnowledgeEngine**: Custom knowledge-base retrieval/integration used by RAG
|
|
23
|
+
- **Parser**: Custom parsing of messages/content
|
|
24
|
+
- **Page**: Custom web page embeddable in the LangBot admin panel
|
|
25
|
+
|
|
26
|
+
Component base classes live in `src/langbot_plugin/api/definition/components/` (`command/`, `tool/`, `common/event_listener.py`, `knowledge_engine/`, `parser/`, `page/`).
|
|
19
27
|
|
|
20
28
|
## Technology Stack
|
|
21
29
|
|
|
@@ -47,31 +55,33 @@ langbot-plugin-sdk/
|
|
|
47
55
|
│ │ │ ├── command/ # CommandReturn
|
|
48
56
|
│ │ │ └── provider/ # Session, Conversation
|
|
49
57
|
│ │ └── proxies/ # API proxy classes
|
|
50
|
-
│ │ ├── langbot_api.py # LangBotAPIProxy
|
|
51
|
-
│ │ └── query_based.py # QueryBasedAPIProxy
|
|
52
58
|
│ ├── runtime/ # Plugin runtime system
|
|
53
|
-
│ │ ├──
|
|
54
|
-
│ │
|
|
55
|
-
│ │ │ ├── container.py # PluginContainer
|
|
56
|
-
│ │ │ └── installer.py # Plugin installation
|
|
59
|
+
│ │ ├── app.py # `lbp rt` entrypoint (runtime_app.main)
|
|
60
|
+
│ │ ├── plugin/ # Plugin management (mgr.py, container.py, installer)
|
|
57
61
|
│ │ ├── io/ # Communication layer
|
|
58
|
-
│ │ │ ├──
|
|
59
|
-
│ │ │ ├──
|
|
60
|
-
│ │ │
|
|
61
|
-
│ │
|
|
62
|
-
│
|
|
63
|
-
│
|
|
64
|
-
│ │ ├──
|
|
65
|
-
│ │ ├──
|
|
66
|
-
│ │
|
|
62
|
+
│ │ │ ├── connection.py # Base connection
|
|
63
|
+
│ │ │ ├── connections/ # stdio / ws connection impls
|
|
64
|
+
│ │ │ ├── controller.py , controllers/ # client/server controllers (stdio, ws)
|
|
65
|
+
│ │ │ ├── handler.py , handlers/ # action handlers
|
|
66
|
+
│ │ └── helper/
|
|
67
|
+
│ ├── box/ # Box (code-sandbox) runtime — `lbp box`
|
|
68
|
+
│ │ ├── server.py # `lbp box` entrypoint (box_main)
|
|
69
|
+
│ │ ├── backend.py # Backend abstraction + selection (Docker handled here/runtime)
|
|
70
|
+
│ │ ├── nsjail_backend.py / e2b_backend.py # sandbox backend impls
|
|
71
|
+
│ │ ├── runtime.py , client.py , actions.py , models.py , errors.py , security.py , skill_store.py
|
|
72
|
+
│ ├── cli/ # Command-line tools (`lbp`)
|
|
73
|
+
│ │ ├── __init__.py # lbp entrypoint + argparse subcommands
|
|
74
|
+
│ │ ├── commands/ # init / comp / build / publish / login / logout impls
|
|
75
|
+
│ │ ├── run/ # plugin run (remote-debug) impl
|
|
76
|
+
│ │ ├── gen/ # component generation (Jinja2)
|
|
77
|
+
│ │ ├── i18n.py , locales/ # CLI i18n
|
|
78
|
+
│ │ └── utils/
|
|
67
79
|
│ ├── entities/ # Internal data structures
|
|
68
|
-
│ │
|
|
69
|
-
│
|
|
70
|
-
│ └── utils/ # Utilities
|
|
71
|
-
│ ├── discover/ # Component discovery
|
|
72
|
-
│ └── network/ # Network helpers
|
|
80
|
+
│ │ └── io/ # Communication protocol (actions, errors, resp)
|
|
81
|
+
│ ├── assets/templates/ # Plugin scaffolding templates
|
|
82
|
+
│ └── utils/ # Utilities (discover/, network, log, ...)
|
|
73
83
|
├── docs/ # Documentation
|
|
74
|
-
├── pyproject.toml # Python project config
|
|
84
|
+
├── pyproject.toml # Python project config (version, requires-python >=3.10)
|
|
75
85
|
└── README.md
|
|
76
86
|
```
|
|
77
87
|
|
|
@@ -113,12 +123,12 @@ langbot-plugin-sdk/
|
|
|
113
123
|
|
|
114
124
|
```
|
|
115
125
|
BasePlugin
|
|
116
|
-
├── Command
|
|
117
|
-
|
|
118
|
-
├──
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
├── Command → Subcommand handlers
|
|
127
|
+
├── Tool → call() method
|
|
128
|
+
├── EventListener → event handlers
|
|
129
|
+
├── KnowledgeEngine → knowledge-base retrieval/integration (RAG)
|
|
130
|
+
├── Parser → message/content parsing
|
|
131
|
+
└── Page → custom admin-panel web page
|
|
122
132
|
```
|
|
123
133
|
|
|
124
134
|
## SDK Development
|
|
@@ -806,84 +816,164 @@ Encapsulates plugin instance with:
|
|
|
806
816
|
|
|
807
817
|
### Communication Protocol (`runtime/io/`)
|
|
808
818
|
|
|
809
|
-
**
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
819
|
+
This protocol is **JSON-RPC 2.0 in all but field names** — a bidirectional, action-based
|
|
820
|
+
RPC carried over a single connection. It is the same shape the Language Server Protocol
|
|
821
|
+
(LSP) and the Model Context Protocol (MCP) use: JSON-RPC 2.0 over stdio / WebSocket, with
|
|
822
|
+
either peer free to initiate calls. We did not adopt the spec verbatim, but the semantics
|
|
823
|
+
map 1:1, and it is useful to think of it that way:
|
|
824
|
+
|
|
825
|
+
| Our field (`entities/io`) | JSON-RPC 2.0 | Meaning |
|
|
826
|
+
|----------------------------|--------------------------|---------|
|
|
827
|
+
| `seq_id` | `id` | Correlates a response back to its request |
|
|
828
|
+
| `action` | `method` | Which action to invoke |
|
|
829
|
+
| `data` (in a request) | `params` | Call arguments |
|
|
830
|
+
| `data` (in a response) | `result` | Return value (when `code == 0`) |
|
|
831
|
+
| `code` + `message` | `error.{code,message}` | `code == 0` is success; non-zero carries the failure in `message` |
|
|
832
|
+
| `chunk_status` | (MCP-style streaming ext.) | `continue` per chunk, `end` closes a streamed response |
|
|
833
|
+
|
|
834
|
+
Both peers share one connection and may call each other's actions. Requests and responses
|
|
835
|
+
are told apart by shape: a message carrying `action` is an inbound request, one carrying
|
|
836
|
+
`code` is a response. Each side allocates `seq_id` from its own incrementing counter, so the
|
|
837
|
+
two id spaces are dispatched independently and never collide.
|
|
838
|
+
|
|
839
|
+
**Request** (`ActionRequest`, `entities/io/req.py`):
|
|
816
840
|
```json
|
|
817
|
-
{
|
|
818
|
-
"action": "action_name",
|
|
819
|
-
"seq": 12345,
|
|
820
|
-
"data": {...},
|
|
821
|
-
"chunk_status": "start|continue|end"
|
|
822
|
-
}
|
|
841
|
+
{ "seq_id": 12345, "action": "action_name", "data": {} }
|
|
823
842
|
```
|
|
824
843
|
|
|
825
|
-
**Response
|
|
844
|
+
**Response** (`ActionResponse`, `entities/io/resp.py`):
|
|
826
845
|
```json
|
|
827
|
-
{
|
|
828
|
-
"seq": 12345,
|
|
829
|
-
"ok": true,
|
|
830
|
-
"data": {...}
|
|
831
|
-
}
|
|
846
|
+
{ "seq_id": 12345, "code": 0, "message": "success", "data": {}, "chunk_status": "continue" }
|
|
832
847
|
```
|
|
833
848
|
|
|
834
|
-
|
|
835
|
-
- `
|
|
836
|
-
|
|
849
|
+
- `code == 0` → success, payload in `data`; non-zero → error, human-readable text in `message`.
|
|
850
|
+
- **Streaming**: the responder emits N chunks with `chunk_status: "continue"`, then a final
|
|
851
|
+
`chunk_status: "end"` (consumed by `Handler.call_action_generator`).
|
|
852
|
+
- **File transfer**: large blobs travel as `__file_chunk` actions — 16KB base64 chunks,
|
|
853
|
+
reassembled to `data/temp/lbp/<file_key>` on the receiving side.
|
|
854
|
+
|
|
855
|
+
**Core engine**: `runtime/io/handler.py` (`Handler`) owns `seq_id` allocation, the
|
|
856
|
+
`resp_waiters` (single response) and `resp_queues` (streamed response) correlation maps,
|
|
857
|
+
timeouts, and the receive loop (`Handler.run`).
|
|
858
|
+
|
|
859
|
+
**Transport Implementations** (`Connection` subclasses, `runtime/io/connections/`):
|
|
860
|
+
- `stdio.py`: stdin/stdout — default for subprocess (personal / lightweight) plugins
|
|
861
|
+
- `ws.py`: WebSocket — for containerized / remote plugin deployments
|
|
837
862
|
|
|
838
863
|
## CLI Tools
|
|
839
864
|
|
|
840
|
-
### lbp Commands
|
|
865
|
+
### `lbp` Commands
|
|
841
866
|
|
|
842
867
|
```bash
|
|
843
|
-
#
|
|
844
|
-
lbp
|
|
868
|
+
lbp init [plugin_name] # Scaffold a new plugin
|
|
869
|
+
lbp comp <Command|Tool|EventListener> # Generate a component
|
|
870
|
+
lbp run [-s] # Run/remote-debug the plugin against a running Runtime
|
|
871
|
+
lbp build [-o dist] # Build the plugin into a zip
|
|
872
|
+
lbp publish [-o dist] # Publish to LangBot Marketplace (login first: lbp login)
|
|
873
|
+
lbp login [-t TOKEN] / lbp logout # Marketplace account auth
|
|
874
|
+
lbp rt [...] # Run the Plugin Runtime (see below)
|
|
875
|
+
lbp box [...] # Run the Box (sandbox) Runtime (see below)
|
|
876
|
+
lbp ver # Print SDK version
|
|
877
|
+
```
|
|
845
878
|
|
|
846
|
-
|
|
847
|
-
lbp comp [Command|Tool|EventListener]
|
|
879
|
+
The CLI entrypoint is `src/langbot_plugin/cli/__init__.py` (argparse). `lbp rt` dispatches to `langbot_plugin.runtime.app.main`; `lbp box` dispatches to `langbot_plugin.box.server.main`. Subcommand implementations live under `cli/commands/`, `cli/run/`, and `cli/gen/`.
|
|
848
880
|
|
|
849
|
-
|
|
850
|
-
lbp run [-s]
|
|
881
|
+
## Debugging the Runtime, CLI & SDK
|
|
851
882
|
|
|
852
|
-
|
|
853
|
-
lbp build
|
|
883
|
+
This is the canonical place for runtime/CLI/box debugging detail (LangBot's own `AGENTS.md` only indexes this section). The corresponding user-facing wiki page is ["调试插件运行时、CLI、SDK"](https://docs.langbot.app/zh/develop/plugin-runtime).
|
|
854
884
|
|
|
855
|
-
|
|
856
|
-
|
|
885
|
+
### Recommended workspace layout
|
|
886
|
+
|
|
887
|
+
Because LangBot depends on entities defined here, clone both repos as siblings under one parent dir and open that parent in your editor:
|
|
888
|
+
|
|
889
|
+
```
|
|
890
|
+
langbot-projects/
|
|
891
|
+
├── LangBot
|
|
892
|
+
└── langbot-plugin-sdk
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
Set up LangBot's venv (`cd LangBot && uv sync --dev`) and point your editor's Python interpreter at LangBot's `.venv`.
|
|
896
|
+
|
|
897
|
+
### Plugin Runtime — `lbp rt`
|
|
898
|
+
|
|
899
|
+
Start a standalone Plugin Runtime from this repo:
|
|
857
900
|
|
|
858
|
-
|
|
859
|
-
lbp rt
|
|
901
|
+
```bash
|
|
902
|
+
uv run --no-sync lbp rt
|
|
903
|
+
# equivalent: python -m langbot_plugin.cli.__init__ rt
|
|
860
904
|
```
|
|
861
905
|
|
|
862
|
-
|
|
906
|
+
`lbp rt` flags (see `cli/__init__.py`):
|
|
907
|
+
|
|
908
|
+
- `-s`, `--stdio-control`: use stdio for the control connection. **Production only** — in a container LangBot pipes the runtime over stdio.
|
|
909
|
+
- `--ws-control-port` (default `5400`): control port LangBot's main process connects to.
|
|
910
|
+
- `--ws-debug-port` (default `5401`): debug port for `lbp run` to attach a plugin under development.
|
|
911
|
+
- `--debug-only`: do not auto-start plugins in `data/plugins/`; only accept plugins via debug connections.
|
|
912
|
+
- `--skip-deps-check`: skip the per-startup check/install of every installed plugin's dependencies.
|
|
913
|
+
- `--pypi-index-url` / `--pypi-trusted-host`: customize the index used for plugin dependency installs.
|
|
863
914
|
|
|
864
|
-
|
|
865
|
-
- Variables: plugin_name, plugin_author, component_name
|
|
866
|
-
- Generates boilerplate code and manifests
|
|
915
|
+
> **Transport note:** When LangBot is run directly (not in a container), it spawns the runtime itself and talks **stdio**, which **cannot auto-reconnect** — on disconnect it logs "please restart LangBot". A frequent cause is an **orphan runtime** from a previous backend still holding `5400`/`5401`; kill it and restart.
|
|
867
916
|
|
|
868
|
-
|
|
917
|
+
### Make LangBot use your locally-modified SDK
|
|
869
918
|
|
|
870
|
-
|
|
919
|
+
If you change shared definitions (message entities, plugin data models, etc.), install your local SDK into LangBot's environment so data formats stay compatible at runtime:
|
|
871
920
|
|
|
872
|
-
1. Start LangBot:
|
|
873
921
|
```bash
|
|
874
|
-
|
|
875
|
-
uv
|
|
922
|
+
# In a terminal where LangBot's .venv is ACTIVE, from the langbot-plugin-sdk dir:
|
|
923
|
+
uv pip install .
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
### Make LangBot connect to your standalone Runtime (WebSocket)
|
|
927
|
+
|
|
928
|
+
1. In LangBot's `data/config.yaml`, set the control URL:
|
|
929
|
+
|
|
930
|
+
```yaml
|
|
931
|
+
plugin:
|
|
932
|
+
runtime_ws_url: ws://localhost:5400/control/ws
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
2. Launch LangBot with `--standalone-runtime` and `--no-sync` (the latter prevents `uv` from overwriting your locally-installed SDK):
|
|
936
|
+
|
|
937
|
+
```bash
|
|
938
|
+
uv run --no-sync main.py --standalone-runtime
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
Restart LangBot; it now connects to your `lbp rt` over WebSocket, so you can iterate on the runtime/SDK independently.
|
|
942
|
+
|
|
943
|
+
### Box Runtime — `lbp box`
|
|
944
|
+
|
|
945
|
+
The Box Runtime is the sandbox service backing LangBot's `pkg/box` subsystem (`src/langbot_plugin/box/`). Start it with:
|
|
946
|
+
|
|
947
|
+
```bash
|
|
948
|
+
lbp box # WebSocket control transport (default)
|
|
949
|
+
lbp box -s # stdio control transport
|
|
876
950
|
```
|
|
877
951
|
|
|
878
|
-
|
|
952
|
+
`lbp box` flags:
|
|
953
|
+
|
|
954
|
+
- `--host` (default `0.0.0.0`): bind address.
|
|
955
|
+
- `-s`, `--stdio-control`: use stdio for the control connection (instead of WebSocket).
|
|
956
|
+
- `--ws-control-port` (default `5410`): control port.
|
|
957
|
+
|
|
958
|
+
All Box WebSocket endpoints share one port (default `5410`): `/rpc/ws` (action RPC control channel) plus managed-process stdio relay endpoints under `/v1/sessions/...`. There is **no** `python -m langbot_plugin.box` launch path — `lbp box` is the only supported entrypoint.
|
|
959
|
+
|
|
960
|
+
Box selects the first available sandbox backend among **Docker / nsjail / E2B**. Backends live in `box/backend.py`, `box/nsjail_backend.py`, `box/e2b_backend.py`. A common false "no backend" on the LangBot side is Docker running but the user not in the `docker` group (socket permission denied) — that's a host-permissions issue, not a Box bug.
|
|
961
|
+
|
|
962
|
+
To make LangBot connect to a standalone Box runtime (mirrors the plugin-runtime flow): in LangBot's `data/config.yaml` set `box.runtime.endpoint` to the runtime's base URL (e.g. `ws://127.0.0.1:5410`), pick `box.backend` (`'local'`/`'docker'`/`'nsjail'`/`'e2b'`), and start LangBot with `--standalone-box`. In Docker deployments LangBot reaches the Box runtime at host `langbot_box:5410`.
|
|
963
|
+
|
|
964
|
+
### Plugin development loop
|
|
965
|
+
|
|
879
966
|
```bash
|
|
967
|
+
# 1. Start a LangBot instance (which spawns or connects to a Runtime)
|
|
968
|
+
cd /path/to/LangBot
|
|
969
|
+
uv run main.py
|
|
970
|
+
|
|
971
|
+
# 2. In your plugin dir, attach it to the Runtime's debug port for live debugging
|
|
880
972
|
cd /path/to/your-plugin
|
|
881
973
|
lbp run
|
|
882
974
|
```
|
|
883
975
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
### Debugging Tips
|
|
976
|
+
### Debugging tips
|
|
887
977
|
|
|
888
978
|
- Use `print()` statements (output to stderr for visibility)
|
|
889
979
|
- Check LangBot logs for plugin errors
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langbot-plugin
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: This package contains the SDK, CLI for building plugins for LangBot, plus the runtime for hosting LangBot plugins
|
|
5
5
|
Project-URL: Homepage, https://langbot.app
|
|
6
6
|
Project-URL: Repository, https://github.com/langbot-app/langbot-plugin-sdk
|
|
@@ -14,6 +14,7 @@ Requires-Dist: dotenv>=0.9.9
|
|
|
14
14
|
Requires-Dist: e2b>=2.15
|
|
15
15
|
Requires-Dist: httpx>=0.28.1
|
|
16
16
|
Requires-Dist: jinja2>=3.1.6
|
|
17
|
+
Requires-Dist: packaging>=24.0
|
|
17
18
|
Requires-Dist: pip>=25.2
|
|
18
19
|
Requires-Dist: pydantic-settings>=2.10.1
|
|
19
20
|
Requires-Dist: pydantic>=2.11.5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "langbot-plugin"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.2"
|
|
4
4
|
description = "This package contains the SDK, CLI for building plugins for LangBot, plus the runtime for hosting LangBot plugins"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -14,6 +14,7 @@ dependencies = [
|
|
|
14
14
|
"e2b>=2.15",
|
|
15
15
|
"httpx>=0.28.1",
|
|
16
16
|
"jinja2>=3.1.6",
|
|
17
|
+
"packaging>=24.0",
|
|
17
18
|
"pip>=25.2",
|
|
18
19
|
"pydantic>=2.11.5",
|
|
19
20
|
"pydantic-settings>=2.10.1",
|
langbot_plugin-0.4.2/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{% raw %}name: Release Plugin
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
paths:
|
|
9
|
+
- "manifest.yaml"
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
inputs:
|
|
12
|
+
release:
|
|
13
|
+
description: "Create a new release"
|
|
14
|
+
required: true
|
|
15
|
+
type: boolean
|
|
16
|
+
default: true
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: write
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
release:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Setup Python
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
|
|
33
|
+
- name: Install lbp CLI
|
|
34
|
+
run: pip install langbot-plugin
|
|
35
|
+
|
|
36
|
+
- name: Get metadata
|
|
37
|
+
id: meta
|
|
38
|
+
run: |
|
|
39
|
+
PLUGIN_NAME=$(grep -m1 'name:' manifest.yaml | awk '{print $2}' | tr -d '"'"'"'')
|
|
40
|
+
VERSION=$(grep -m1 'version:' manifest.yaml | awk '{print $2}' | tr -d '"'"'"'')
|
|
41
|
+
AUTHOR=$(grep -m1 'author:' manifest.yaml | awk '{print $2}' | tr -d '"'"'"'')
|
|
42
|
+
echo "name=$PLUGIN_NAME" >> "$GITHUB_OUTPUT"
|
|
43
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
44
|
+
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
|
|
45
|
+
echo "artifact=${AUTHOR}-${PLUGIN_NAME}-${VERSION}" >> "$GITHUB_OUTPUT"
|
|
46
|
+
|
|
47
|
+
- name: Check release exists
|
|
48
|
+
id: check
|
|
49
|
+
run: |
|
|
50
|
+
if gh release view "$TAG" --json tagName > /dev/null 2>&1; then
|
|
51
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
52
|
+
else
|
|
53
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
54
|
+
fi
|
|
55
|
+
env:
|
|
56
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
57
|
+
TAG: ${{ steps.meta.outputs.tag }}
|
|
58
|
+
|
|
59
|
+
- name: Build plugin
|
|
60
|
+
if: steps.check.outputs.exists == 'false'
|
|
61
|
+
run: lbp build -o dist
|
|
62
|
+
|
|
63
|
+
- name: Create release
|
|
64
|
+
if: steps.check.outputs.exists == 'false'
|
|
65
|
+
uses: softprops/action-gh-release@v2
|
|
66
|
+
with:
|
|
67
|
+
tag_name: ${{ steps.meta.outputs.tag }}
|
|
68
|
+
name: ${{ steps.meta.outputs.artifact }}
|
|
69
|
+
body: |
|
|
70
|
+
## ${{ steps.meta.outputs.artifact }}
|
|
71
|
+
|
|
72
|
+
### Installation
|
|
73
|
+
Download `${{ steps.meta.outputs.artifact }}.lbpkg` and install via LangBot plugin marketplace.
|
|
74
|
+
files: dist/${{ steps.meta.outputs.artifact }}.lbpkg
|
|
75
|
+
draft: false
|
|
76
|
+
prerelease: false
|
|
77
|
+
{% endraw %}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# {{ plugin_name }}
|
|
2
|
+
|
|
3
|
+
{{ plugin_description }}
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install this plugin via the LangBot plugin marketplace.
|
|
8
|
+
|
|
9
|
+
## Configuration
|
|
10
|
+
|
|
11
|
+
Configure the plugin parameters in the LangBot admin panel.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
<!-- TODO: Add usage instructions for your plugin here -->
|
|
@@ -233,6 +233,12 @@ class ActionRPCBoxClient(BoxRuntimeClient):
|
|
|
233
233
|
data = await self._call(
|
|
234
234
|
LangBotToBoxAction.START_MANAGED_PROCESS,
|
|
235
235
|
{"session_id": session_id, "spec": spec.model_dump(mode="json")},
|
|
236
|
+
# Starting a managed process can involve a cold dependency bootstrap
|
|
237
|
+
# (e.g. `uvx <pkg>` downloading the package + interpreter on first
|
|
238
|
+
# run), which easily exceeds the default 15s action timeout and
|
|
239
|
+
# caused stdio MCP servers to be torn down mid-install. Give it
|
|
240
|
+
# headroom so the first launch can complete.
|
|
241
|
+
timeout=30.0,
|
|
236
242
|
)
|
|
237
243
|
return BoxManagedProcessInfo.model_validate(data)
|
|
238
244
|
|
|
@@ -44,6 +44,23 @@ _READONLY_ETC_ENTRIES: list[str] = [
|
|
|
44
44
|
'/etc/resolv.conf', # needed when network=ON
|
|
45
45
|
]
|
|
46
46
|
|
|
47
|
+
# Essential character devices bind-mounted into the sandbox's /dev.
|
|
48
|
+
# /dev is a fresh empty tmpfs (see _build_args), so these nodes do not exist
|
|
49
|
+
# unless we bind them in from the host. Tooling that shells out for probes
|
|
50
|
+
# relies on them — notably `uv`/`uvx` redirects its glibc/musl detection
|
|
51
|
+
# subprocess to /dev/null; without it uv fails with "Could not detect either
|
|
52
|
+
# glibc version nor musl libc version" and the process exits before it can do
|
|
53
|
+
# anything (e.g. an stdio MCP server dies before the initialize handshake,
|
|
54
|
+
# surfacing as a misleading "Connection closed / please check URL").
|
|
55
|
+
_DEV_NODES: list[str] = [
|
|
56
|
+
'/dev/null',
|
|
57
|
+
'/dev/zero',
|
|
58
|
+
'/dev/full',
|
|
59
|
+
'/dev/random',
|
|
60
|
+
'/dev/urandom',
|
|
61
|
+
'/dev/tty',
|
|
62
|
+
]
|
|
63
|
+
|
|
47
64
|
_DEFAULT_BASE_DIR = '/tmp/langbot-box-nsjail'
|
|
48
65
|
|
|
49
66
|
|
|
@@ -116,6 +133,19 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
116
133
|
for d in (root_dir, workspace_dir, tmp_dir, home_dir):
|
|
117
134
|
d.mkdir(parents=True, exist_ok=True)
|
|
118
135
|
|
|
136
|
+
# When a host_path is mounted into the sandbox it becomes the nsjail
|
|
137
|
+
# bind-mount source (see _build_mounts). nsjail requires the source to
|
|
138
|
+
# already exist on the host, otherwise the bind-mount fails and the
|
|
139
|
+
# command exits 255 with no stdout/stderr. The per-session loop above
|
|
140
|
+
# never creates host_path (it lives outside session_dir), so ensure it
|
|
141
|
+
# exists here. Read-only mounts intentionally are NOT auto-created: a
|
|
142
|
+
# missing read-only source is a caller error that should surface.
|
|
143
|
+
if (
|
|
144
|
+
spec.host_path is not None
|
|
145
|
+
and spec.host_path_mode == BoxHostMountMode.READ_WRITE
|
|
146
|
+
):
|
|
147
|
+
os.makedirs(spec.host_path, exist_ok=True)
|
|
148
|
+
|
|
119
149
|
# If host_path is specified, we will use it directly instead of the
|
|
120
150
|
# per-session workspace when building nsjail args (see _build_mounts).
|
|
121
151
|
meta = {
|
|
@@ -317,6 +347,15 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
317
347
|
args.extend(['--mount', 'none:/proc:proc:rw'])
|
|
318
348
|
args.extend(['--mount', 'none:/dev:tmpfs:rw'])
|
|
319
349
|
|
|
350
|
+
# /dev is a fresh empty tmpfs, so bind in the essential character
|
|
351
|
+
# devices. Without /dev/null in particular, uv's glibc/musl detection
|
|
352
|
+
# subprocess fails and any uvx-launched process (e.g. stdio MCP servers)
|
|
353
|
+
# exits before doing useful work. Mounted read-write so writes to
|
|
354
|
+
# /dev/null behave normally.
|
|
355
|
+
for dev in _DEV_NODES:
|
|
356
|
+
if os.path.exists(dev):
|
|
357
|
+
args.extend(['--bindmount', f'{dev}:{dev}'])
|
|
358
|
+
|
|
320
359
|
# Working directory.
|
|
321
360
|
args.extend(['--cwd', spec.workdir])
|
|
322
361
|
|
|
@@ -424,14 +463,24 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
424
463
|
args: list[str] = []
|
|
425
464
|
|
|
426
465
|
if self._cgroup_v2_available:
|
|
427
|
-
# cgroup v2 – precise limits.
|
|
466
|
+
# cgroup v2 – precise limits. nsjail defaults to the legacy cgroup
|
|
467
|
+
# v1 layout, so we MUST opt into v2 explicitly; without this flag
|
|
468
|
+
# nsjail tries to mkdir under /sys/fs/cgroup/<controller>/... (v1
|
|
469
|
+
# paths) and aborts on a v2-only host. The writability of the v2
|
|
470
|
+
# root is already verified in _detect_cgroup_v2().
|
|
471
|
+
args.append('--use_cgroupv2')
|
|
428
472
|
memory_bytes = spec.memory_mb * 1024 * 1024
|
|
429
473
|
args.extend(['--cgroup_mem_max', str(memory_bytes)])
|
|
430
474
|
args.extend(['--cgroup_pids_max', str(spec.pids_limit)])
|
|
431
475
|
cpu_ms = int(spec.cpus * 1000)
|
|
432
476
|
args.extend(['--cgroup_cpu_ms_per_sec', str(cpu_ms)])
|
|
433
477
|
else:
|
|
434
|
-
# rlimit fallback – best-effort.
|
|
478
|
+
# rlimit fallback – best-effort. Used whenever the cgroup v2 root is
|
|
479
|
+
# not writable (the typical containerized case: /sys/fs/cgroup is
|
|
480
|
+
# mounted read-only), so the sandbox still launches with coarse
|
|
481
|
+
# resource caps instead of failing outright.
|
|
482
|
+
# --rlimit_as takes a value in MB (nsjail interprets the bare number
|
|
483
|
+
# as megabytes), matching spec.memory_mb directly.
|
|
435
484
|
args.extend(['--rlimit_as', str(spec.memory_mb)])
|
|
436
485
|
args.extend(['--rlimit_nproc', str(spec.pids_limit)])
|
|
437
486
|
|
|
@@ -478,25 +527,42 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
478
527
|
|
|
479
528
|
@staticmethod
|
|
480
529
|
def _detect_cgroup_v2() -> bool:
|
|
481
|
-
"""Check whether
|
|
530
|
+
"""Check whether cgroup v2 is present AND nsjail can create a cgroup.
|
|
531
|
+
|
|
532
|
+
nsjail (with ``--use_cgroupv2``) creates its own child cgroup by
|
|
533
|
+
``mkdir``-ing directly under the cgroup v2 mount root, then writes to
|
|
534
|
+
``cgroup.subtree_control``. Merely detecting a cgroup v2 hierarchy is
|
|
535
|
+
not enough: inside most containers (Docker/k8s default) ``/sys/fs/cgroup``
|
|
536
|
+
is mounted **read-only**, so the mkdir fails and the whole sandbox
|
|
537
|
+
aborts. We must therefore probe real writability — running as root is
|
|
538
|
+
NOT sufficient, because a read-only bind mount denies root too.
|
|
539
|
+
|
|
540
|
+
Returns True only when we can actually create (and remove) a directory
|
|
541
|
+
under the cgroup v2 root, which is exactly what nsjail needs.
|
|
542
|
+
"""
|
|
482
543
|
cgroup_mount = pathlib.Path('/sys/fs/cgroup')
|
|
483
544
|
if not cgroup_mount.exists():
|
|
484
545
|
return False
|
|
485
|
-
# cgroup v2 has a single hierarchy with cgroup.controllers file.
|
|
546
|
+
# cgroup v2 has a single hierarchy with a cgroup.controllers file.
|
|
486
547
|
controllers = cgroup_mount / 'cgroup.controllers'
|
|
487
548
|
if not controllers.exists():
|
|
488
549
|
return False
|
|
489
|
-
#
|
|
490
|
-
#
|
|
491
|
-
#
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
550
|
+
# Authoritative writability probe: try to create and remove a throwaway
|
|
551
|
+
# cgroup directory under the root, mirroring what nsjail does. This
|
|
552
|
+
# correctly reports False on a read-only /sys/fs/cgroup (the common
|
|
553
|
+
# containerized case) so the backend falls back to rlimit limits
|
|
554
|
+
# instead of selecting a cgroup path that is guaranteed to fail.
|
|
555
|
+
probe = cgroup_mount / f'.langbot-box-probe-{os.getpid()}'
|
|
556
|
+
try:
|
|
557
|
+
probe.mkdir(mode=0o700)
|
|
558
|
+
except Exception:
|
|
559
|
+
return False
|
|
560
|
+
else:
|
|
561
|
+
try:
|
|
562
|
+
probe.rmdir()
|
|
563
|
+
except Exception:
|
|
564
|
+
pass
|
|
497
565
|
return True
|
|
498
|
-
# Conservative: if we can't confirm writability, report unavailable.
|
|
499
|
-
return False
|
|
500
566
|
|
|
501
567
|
async def _kill_session_processes(self, session_dir: pathlib.Path) -> None:
|
|
502
568
|
"""Best-effort kill of nsjail processes associated with a session dir.
|
|
@@ -155,6 +155,10 @@ def init_plugin_process(
|
|
|
155
155
|
os.makedirs(assets_dir, exist_ok=True)
|
|
156
156
|
vscode_dir = os.path.join(plugin_dir, ".vscode")
|
|
157
157
|
os.makedirs(vscode_dir, exist_ok=True)
|
|
158
|
+
readme_dir = os.path.join(plugin_dir, "readme")
|
|
159
|
+
os.makedirs(readme_dir, exist_ok=True)
|
|
160
|
+
github_workflows_dir = os.path.join(plugin_dir, ".github", "workflows")
|
|
161
|
+
os.makedirs(github_workflows_dir, exist_ok=True)
|
|
158
162
|
|
|
159
163
|
# Create all files from templates
|
|
160
164
|
for file in init_plugin_files:
|
|
@@ -42,11 +42,13 @@ init_plugin_files = [
|
|
|
42
42
|
"manifest.yaml",
|
|
43
43
|
"main.py",
|
|
44
44
|
"README.md",
|
|
45
|
+
"readme/README_zh_Hans.md",
|
|
45
46
|
"requirements.txt",
|
|
46
47
|
".env.example",
|
|
47
48
|
".gitignore",
|
|
48
49
|
"assets/icon.svg",
|
|
49
50
|
".vscode/launch.json",
|
|
51
|
+
".github/workflows/release.yml",
|
|
50
52
|
]
|
|
51
53
|
|
|
52
54
|
|