langbot-plugin 0.4.1__tar.gz → 0.4.2b2__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.2b2}/AGENTS.md +136 -61
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/PKG-INFO +1 -1
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/pyproject.toml +1 -1
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/nsjail_backend.py +54 -14
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_nsjail_backend.py +70 -18
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.github/workflows/publish-pypi.yaml +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.github/workflows/test.yml +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.gitignore +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.python-version +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/CLAUDE.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/LICENSE +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/README.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/data/.env.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/Message.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/PluginPages.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/communication/apis/lb2rt.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/communication/runtime_plugin.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/dependency-management.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/langbot-plugin-social.png +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/base.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/plugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/events.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/base.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/event_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/README.md.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/main.py.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/actions.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/e2b_backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/models.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/runtime.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/security.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/skill_store.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/__main__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/initplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/login.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/logout.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/publish.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/gen/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/gen/renderer.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/i18n.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/en_US.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/controller.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/hotreload.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/form.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/page_components.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/errors.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/req.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/resp.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/marketplace.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/LICENSE +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/README.md +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/app.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connection.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controller.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/plugin/container.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/plugin/mgr.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/settings.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/discover/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/discover/engine.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/importutil.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/log.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/platform.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/version.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/definition/components/test_components.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/definition/test_manifest.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_command_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_platform_logger.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_provider_message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_rag_models.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/test_context.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/test_events.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/proxies/test_base.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/proxies/test_langbot_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/proxies/test_query_based_api.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_backend_selection.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_client.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_e2b_backend.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_runtime.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_server.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_skill_store.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/run/test_controller.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/run/test_runtime_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_buildplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_gencomponent.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_i18n_form.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_initplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_login.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_logout_publish.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_page_components.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_renderer.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_runplugin.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/entities/io/test_protocol.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/helpers/__init__.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/helpers/protocol.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/helper/test_marketplace.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/helper/test_pkgmgr.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/handlers/test_control_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/test_connections.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/test_controllers.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/test_handler.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/plugin/test_container.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/plugin/test_manager.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/test_app.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/test_log.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/test_message.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/utils/test_discovery.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/utils/test_importutil.py +0 -0
- {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/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
|
|
@@ -837,53 +847,118 @@ Encapsulates plugin instance with:
|
|
|
837
847
|
|
|
838
848
|
## CLI Tools
|
|
839
849
|
|
|
840
|
-
### lbp Commands
|
|
850
|
+
### `lbp` Commands
|
|
841
851
|
|
|
842
852
|
```bash
|
|
843
|
-
#
|
|
844
|
-
lbp
|
|
853
|
+
lbp init [plugin_name] # Scaffold a new plugin
|
|
854
|
+
lbp comp <Command|Tool|EventListener> # Generate a component
|
|
855
|
+
lbp run [-s] # Run/remote-debug the plugin against a running Runtime
|
|
856
|
+
lbp build [-o dist] # Build the plugin into a zip
|
|
857
|
+
lbp publish [-o dist] # Publish to LangBot Marketplace (login first: lbp login)
|
|
858
|
+
lbp login [-t TOKEN] / lbp logout # Marketplace account auth
|
|
859
|
+
lbp rt [...] # Run the Plugin Runtime (see below)
|
|
860
|
+
lbp box [...] # Run the Box (sandbox) Runtime (see below)
|
|
861
|
+
lbp ver # Print SDK version
|
|
862
|
+
```
|
|
845
863
|
|
|
846
|
-
|
|
847
|
-
lbp comp [Command|Tool|EventListener]
|
|
864
|
+
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
865
|
|
|
849
|
-
|
|
850
|
-
lbp run [-s]
|
|
866
|
+
## Debugging the Runtime, CLI & SDK
|
|
851
867
|
|
|
852
|
-
|
|
853
|
-
lbp build
|
|
868
|
+
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
869
|
|
|
855
|
-
|
|
856
|
-
lbp publish
|
|
870
|
+
### Recommended workspace layout
|
|
857
871
|
|
|
858
|
-
|
|
859
|
-
|
|
872
|
+
Because LangBot depends on entities defined here, clone both repos as siblings under one parent dir and open that parent in your editor:
|
|
873
|
+
|
|
874
|
+
```
|
|
875
|
+
langbot-projects/
|
|
876
|
+
├── LangBot
|
|
877
|
+
└── langbot-plugin-sdk
|
|
860
878
|
```
|
|
861
879
|
|
|
862
|
-
|
|
880
|
+
Set up LangBot's venv (`cd LangBot && uv sync --dev`) and point your editor's Python interpreter at LangBot's `.venv`.
|
|
881
|
+
|
|
882
|
+
### Plugin Runtime — `lbp rt`
|
|
863
883
|
|
|
864
|
-
|
|
865
|
-
- Variables: plugin_name, plugin_author, component_name
|
|
866
|
-
- Generates boilerplate code and manifests
|
|
884
|
+
Start a standalone Plugin Runtime from this repo:
|
|
867
885
|
|
|
868
|
-
|
|
886
|
+
```bash
|
|
887
|
+
uv run --no-sync lbp rt
|
|
888
|
+
# equivalent: python -m langbot_plugin.cli.__init__ rt
|
|
889
|
+
```
|
|
869
890
|
|
|
870
|
-
|
|
891
|
+
`lbp rt` flags (see `cli/__init__.py`):
|
|
892
|
+
|
|
893
|
+
- `-s`, `--stdio-control`: use stdio for the control connection. **Production only** — in a container LangBot pipes the runtime over stdio.
|
|
894
|
+
- `--ws-control-port` (default `5400`): control port LangBot's main process connects to.
|
|
895
|
+
- `--ws-debug-port` (default `5401`): debug port for `lbp run` to attach a plugin under development.
|
|
896
|
+
- `--debug-only`: do not auto-start plugins in `data/plugins/`; only accept plugins via debug connections.
|
|
897
|
+
- `--skip-deps-check`: skip the per-startup check/install of every installed plugin's dependencies.
|
|
898
|
+
- `--pypi-index-url` / `--pypi-trusted-host`: customize the index used for plugin dependency installs.
|
|
899
|
+
|
|
900
|
+
> **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.
|
|
901
|
+
|
|
902
|
+
### Make LangBot use your locally-modified SDK
|
|
903
|
+
|
|
904
|
+
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
905
|
|
|
872
|
-
1. Start LangBot:
|
|
873
906
|
```bash
|
|
874
|
-
|
|
875
|
-
uv
|
|
907
|
+
# In a terminal where LangBot's .venv is ACTIVE, from the langbot-plugin-sdk dir:
|
|
908
|
+
uv pip install .
|
|
876
909
|
```
|
|
877
910
|
|
|
878
|
-
|
|
911
|
+
### Make LangBot connect to your standalone Runtime (WebSocket)
|
|
912
|
+
|
|
913
|
+
1. In LangBot's `data/config.yaml`, set the control URL:
|
|
914
|
+
|
|
915
|
+
```yaml
|
|
916
|
+
plugin:
|
|
917
|
+
runtime_ws_url: ws://localhost:5400/control/ws
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
2. Launch LangBot with `--standalone-runtime` and `--no-sync` (the latter prevents `uv` from overwriting your locally-installed SDK):
|
|
921
|
+
|
|
922
|
+
```bash
|
|
923
|
+
uv run --no-sync main.py --standalone-runtime
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
Restart LangBot; it now connects to your `lbp rt` over WebSocket, so you can iterate on the runtime/SDK independently.
|
|
927
|
+
|
|
928
|
+
### Box Runtime — `lbp box`
|
|
929
|
+
|
|
930
|
+
The Box Runtime is the sandbox service backing LangBot's `pkg/box` subsystem (`src/langbot_plugin/box/`). Start it with:
|
|
931
|
+
|
|
932
|
+
```bash
|
|
933
|
+
lbp box # WebSocket control transport (default)
|
|
934
|
+
lbp box -s # stdio control transport
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
`lbp box` flags:
|
|
938
|
+
|
|
939
|
+
- `--host` (default `0.0.0.0`): bind address.
|
|
940
|
+
- `-s`, `--stdio-control`: use stdio for the control connection (instead of WebSocket).
|
|
941
|
+
- `--ws-control-port` (default `5410`): control port.
|
|
942
|
+
|
|
943
|
+
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.
|
|
944
|
+
|
|
945
|
+
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.
|
|
946
|
+
|
|
947
|
+
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`.
|
|
948
|
+
|
|
949
|
+
### Plugin development loop
|
|
950
|
+
|
|
879
951
|
```bash
|
|
952
|
+
# 1. Start a LangBot instance (which spawns or connects to a Runtime)
|
|
953
|
+
cd /path/to/LangBot
|
|
954
|
+
uv run main.py
|
|
955
|
+
|
|
956
|
+
# 2. In your plugin dir, attach it to the Runtime's debug port for live debugging
|
|
880
957
|
cd /path/to/your-plugin
|
|
881
958
|
lbp run
|
|
882
959
|
```
|
|
883
960
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
### Debugging Tips
|
|
961
|
+
### Debugging tips
|
|
887
962
|
|
|
888
963
|
- Use `print()` statements (output to stderr for visibility)
|
|
889
964
|
- 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.2b2
|
|
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
|
|
@@ -116,6 +116,19 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
116
116
|
for d in (root_dir, workspace_dir, tmp_dir, home_dir):
|
|
117
117
|
d.mkdir(parents=True, exist_ok=True)
|
|
118
118
|
|
|
119
|
+
# When a host_path is mounted into the sandbox it becomes the nsjail
|
|
120
|
+
# bind-mount source (see _build_mounts). nsjail requires the source to
|
|
121
|
+
# already exist on the host, otherwise the bind-mount fails and the
|
|
122
|
+
# command exits 255 with no stdout/stderr. The per-session loop above
|
|
123
|
+
# never creates host_path (it lives outside session_dir), so ensure it
|
|
124
|
+
# exists here. Read-only mounts intentionally are NOT auto-created: a
|
|
125
|
+
# missing read-only source is a caller error that should surface.
|
|
126
|
+
if (
|
|
127
|
+
spec.host_path is not None
|
|
128
|
+
and spec.host_path_mode == BoxHostMountMode.READ_WRITE
|
|
129
|
+
):
|
|
130
|
+
os.makedirs(spec.host_path, exist_ok=True)
|
|
131
|
+
|
|
119
132
|
# If host_path is specified, we will use it directly instead of the
|
|
120
133
|
# per-session workspace when building nsjail args (see _build_mounts).
|
|
121
134
|
meta = {
|
|
@@ -424,14 +437,24 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
424
437
|
args: list[str] = []
|
|
425
438
|
|
|
426
439
|
if self._cgroup_v2_available:
|
|
427
|
-
# cgroup v2 – precise limits.
|
|
440
|
+
# cgroup v2 – precise limits. nsjail defaults to the legacy cgroup
|
|
441
|
+
# v1 layout, so we MUST opt into v2 explicitly; without this flag
|
|
442
|
+
# nsjail tries to mkdir under /sys/fs/cgroup/<controller>/... (v1
|
|
443
|
+
# paths) and aborts on a v2-only host. The writability of the v2
|
|
444
|
+
# root is already verified in _detect_cgroup_v2().
|
|
445
|
+
args.append('--use_cgroupv2')
|
|
428
446
|
memory_bytes = spec.memory_mb * 1024 * 1024
|
|
429
447
|
args.extend(['--cgroup_mem_max', str(memory_bytes)])
|
|
430
448
|
args.extend(['--cgroup_pids_max', str(spec.pids_limit)])
|
|
431
449
|
cpu_ms = int(spec.cpus * 1000)
|
|
432
450
|
args.extend(['--cgroup_cpu_ms_per_sec', str(cpu_ms)])
|
|
433
451
|
else:
|
|
434
|
-
# rlimit fallback – best-effort.
|
|
452
|
+
# rlimit fallback – best-effort. Used whenever the cgroup v2 root is
|
|
453
|
+
# not writable (the typical containerized case: /sys/fs/cgroup is
|
|
454
|
+
# mounted read-only), so the sandbox still launches with coarse
|
|
455
|
+
# resource caps instead of failing outright.
|
|
456
|
+
# --rlimit_as takes a value in MB (nsjail interprets the bare number
|
|
457
|
+
# as megabytes), matching spec.memory_mb directly.
|
|
435
458
|
args.extend(['--rlimit_as', str(spec.memory_mb)])
|
|
436
459
|
args.extend(['--rlimit_nproc', str(spec.pids_limit)])
|
|
437
460
|
|
|
@@ -478,25 +501,42 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
478
501
|
|
|
479
502
|
@staticmethod
|
|
480
503
|
def _detect_cgroup_v2() -> bool:
|
|
481
|
-
"""Check whether
|
|
504
|
+
"""Check whether cgroup v2 is present AND nsjail can create a cgroup.
|
|
505
|
+
|
|
506
|
+
nsjail (with ``--use_cgroupv2``) creates its own child cgroup by
|
|
507
|
+
``mkdir``-ing directly under the cgroup v2 mount root, then writes to
|
|
508
|
+
``cgroup.subtree_control``. Merely detecting a cgroup v2 hierarchy is
|
|
509
|
+
not enough: inside most containers (Docker/k8s default) ``/sys/fs/cgroup``
|
|
510
|
+
is mounted **read-only**, so the mkdir fails and the whole sandbox
|
|
511
|
+
aborts. We must therefore probe real writability — running as root is
|
|
512
|
+
NOT sufficient, because a read-only bind mount denies root too.
|
|
513
|
+
|
|
514
|
+
Returns True only when we can actually create (and remove) a directory
|
|
515
|
+
under the cgroup v2 root, which is exactly what nsjail needs.
|
|
516
|
+
"""
|
|
482
517
|
cgroup_mount = pathlib.Path('/sys/fs/cgroup')
|
|
483
518
|
if not cgroup_mount.exists():
|
|
484
519
|
return False
|
|
485
|
-
# cgroup v2 has a single hierarchy with cgroup.controllers file.
|
|
520
|
+
# cgroup v2 has a single hierarchy with a cgroup.controllers file.
|
|
486
521
|
controllers = cgroup_mount / 'cgroup.controllers'
|
|
487
522
|
if not controllers.exists():
|
|
488
523
|
return False
|
|
489
|
-
#
|
|
490
|
-
#
|
|
491
|
-
#
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
524
|
+
# Authoritative writability probe: try to create and remove a throwaway
|
|
525
|
+
# cgroup directory under the root, mirroring what nsjail does. This
|
|
526
|
+
# correctly reports False on a read-only /sys/fs/cgroup (the common
|
|
527
|
+
# containerized case) so the backend falls back to rlimit limits
|
|
528
|
+
# instead of selecting a cgroup path that is guaranteed to fail.
|
|
529
|
+
probe = cgroup_mount / f'.langbot-box-probe-{os.getpid()}'
|
|
530
|
+
try:
|
|
531
|
+
probe.mkdir(mode=0o700)
|
|
532
|
+
except Exception:
|
|
533
|
+
return False
|
|
534
|
+
else:
|
|
535
|
+
try:
|
|
536
|
+
probe.rmdir()
|
|
537
|
+
except Exception:
|
|
538
|
+
pass
|
|
497
539
|
return True
|
|
498
|
-
# Conservative: if we can't confirm writability, report unavailable.
|
|
499
|
-
return False
|
|
500
540
|
|
|
501
541
|
async def _kill_session_processes(self, session_dir: pathlib.Path) -> None:
|
|
502
542
|
"""Best-effort kill of nsjail processes associated with a session dir.
|
|
@@ -93,20 +93,62 @@ async def test_start_session_creates_directories(backend, tmp_base):
|
|
|
93
93
|
@pytest.mark.anyio
|
|
94
94
|
async def test_start_session_with_host_path(backend, tmp_base):
|
|
95
95
|
tmp_base.mkdir(parents=True, exist_ok=True)
|
|
96
|
+
host_path = str(tmp_base / 'rw_host')
|
|
96
97
|
spec = BoxSpec(
|
|
97
98
|
session_id='sess2',
|
|
98
99
|
cmd='ls',
|
|
99
|
-
host_path=
|
|
100
|
+
host_path=host_path,
|
|
100
101
|
host_path_mode=BoxHostMountMode.READ_WRITE,
|
|
101
102
|
mount_path='/project',
|
|
102
103
|
)
|
|
103
104
|
|
|
104
105
|
info = await backend.start_session(spec)
|
|
105
|
-
assert info.host_path ==
|
|
106
|
+
assert info.host_path == host_path
|
|
106
107
|
assert info.host_path_mode == BoxHostMountMode.READ_WRITE
|
|
107
108
|
assert info.mount_path == '/project'
|
|
108
109
|
|
|
109
110
|
|
|
111
|
+
@pytest.mark.anyio
|
|
112
|
+
async def test_start_session_creates_missing_rw_host_path(backend, tmp_base):
|
|
113
|
+
"""Regression: a read-write host_path that does not yet exist must be
|
|
114
|
+
created by start_session, otherwise nsjail's --bindmount source is missing
|
|
115
|
+
and the command exits 255 with no output (SaaS MCP shared-workspace bug)."""
|
|
116
|
+
tmp_base.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
host_path = tmp_base / 'never_created' / 'workspace'
|
|
118
|
+
assert not host_path.exists()
|
|
119
|
+
|
|
120
|
+
spec = BoxSpec(
|
|
121
|
+
session_id='sess-mkdir',
|
|
122
|
+
cmd='ls',
|
|
123
|
+
host_path=str(host_path),
|
|
124
|
+
host_path_mode=BoxHostMountMode.READ_WRITE,
|
|
125
|
+
mount_path='/workspace',
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
await backend.start_session(spec)
|
|
129
|
+
assert host_path.is_dir()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@pytest.mark.anyio
|
|
133
|
+
async def test_start_session_does_not_create_ro_host_path(backend, tmp_base):
|
|
134
|
+
"""A missing read-only host_path is a caller error and must NOT be silently
|
|
135
|
+
created — it should surface rather than mount an empty dir."""
|
|
136
|
+
tmp_base.mkdir(parents=True, exist_ok=True)
|
|
137
|
+
host_path = tmp_base / 'ro_missing'
|
|
138
|
+
assert not host_path.exists()
|
|
139
|
+
|
|
140
|
+
spec = BoxSpec(
|
|
141
|
+
session_id='sess-ro',
|
|
142
|
+
cmd='ls',
|
|
143
|
+
host_path=str(host_path),
|
|
144
|
+
host_path_mode=BoxHostMountMode.READ_ONLY,
|
|
145
|
+
mount_path='/project',
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
await backend.start_session(spec)
|
|
149
|
+
assert not host_path.exists()
|
|
150
|
+
|
|
151
|
+
|
|
110
152
|
# ── stop_session ──────────────────────────────────────────────────────
|
|
111
153
|
|
|
112
154
|
@pytest.mark.anyio
|
|
@@ -301,6 +343,9 @@ def test_build_resource_limits_cgroup(backend):
|
|
|
301
343
|
|
|
302
344
|
args = backend._build_resource_limits(spec)
|
|
303
345
|
|
|
346
|
+
# Bug regression: cgroup v2 mode MUST opt in explicitly, otherwise nsjail
|
|
347
|
+
# falls back to the v1 layout and aborts on a v2-only host.
|
|
348
|
+
assert '--use_cgroupv2' in args
|
|
304
349
|
assert '--cgroup_mem_max' in args
|
|
305
350
|
mem_idx = args.index('--cgroup_mem_max')
|
|
306
351
|
assert args[mem_idx + 1] == str(1024 * 1024 * 1024)
|
|
@@ -326,6 +371,7 @@ def test_build_resource_limits_rlimit_fallback(backend):
|
|
|
326
371
|
assert args[nproc_idx + 1] == '128'
|
|
327
372
|
|
|
328
373
|
# cgroup flags should NOT be present.
|
|
374
|
+
assert '--use_cgroupv2' not in args
|
|
329
375
|
assert '--cgroup_mem_max' not in args
|
|
330
376
|
|
|
331
377
|
|
|
@@ -376,36 +422,42 @@ def test_detect_cgroup_v2_no_mount():
|
|
|
376
422
|
assert NsjailBackend._detect_cgroup_v2() is False
|
|
377
423
|
|
|
378
424
|
|
|
379
|
-
def
|
|
380
|
-
|
|
381
|
-
|
|
425
|
+
def test_detect_cgroup_v2_writable():
|
|
426
|
+
"""When the cgroup v2 root is writable (mkdir succeeds), report True.
|
|
427
|
+
|
|
428
|
+
This mirrors the only thing nsjail actually needs: the ability to create a
|
|
429
|
+
child cgroup under /sys/fs/cgroup. Being root is irrelevant on its own.
|
|
430
|
+
"""
|
|
431
|
+
def fake_exists(self):
|
|
432
|
+
path = str(self)
|
|
433
|
+
return path == '/sys/fs/cgroup' or path.endswith('cgroup.controllers')
|
|
382
434
|
|
|
383
435
|
with (
|
|
384
|
-
mock.patch(
|
|
385
|
-
mock.patch.object(pathlib.Path, '
|
|
436
|
+
mock.patch.object(pathlib.Path, 'exists', fake_exists),
|
|
437
|
+
mock.patch.object(pathlib.Path, 'mkdir', return_value=None),
|
|
438
|
+
mock.patch.object(pathlib.Path, 'rmdir', return_value=None),
|
|
386
439
|
):
|
|
387
440
|
assert NsjailBackend._detect_cgroup_v2() is True
|
|
388
441
|
|
|
389
442
|
|
|
390
|
-
def
|
|
443
|
+
def test_detect_cgroup_v2_readonly_root_returns_false():
|
|
444
|
+
"""A read-only /sys/fs/cgroup (the default containerized case) must report
|
|
445
|
+
False so the backend falls back to rlimit limits instead of selecting a
|
|
446
|
+
cgroup path that nsjail cannot use. Root does NOT override a RO mount."""
|
|
391
447
|
def fake_exists(self):
|
|
392
448
|
path = str(self)
|
|
393
|
-
return path == '/sys/fs/cgroup' or path.endswith('cgroup.controllers')
|
|
449
|
+
return path == '/sys/fs/cgroup' or path.endswith('cgroup.controllers')
|
|
394
450
|
|
|
395
451
|
with (
|
|
396
|
-
mock.patch('os.getuid', return_value=
|
|
452
|
+
mock.patch('os.getuid', return_value=0),
|
|
397
453
|
mock.patch.object(pathlib.Path, 'exists', fake_exists),
|
|
398
|
-
mock.patch(
|
|
454
|
+
mock.patch.object(
|
|
455
|
+
pathlib.Path, 'mkdir',
|
|
456
|
+
side_effect=OSError('Read-only file system'),
|
|
457
|
+
),
|
|
399
458
|
):
|
|
400
459
|
assert NsjailBackend._detect_cgroup_v2() is False
|
|
401
460
|
|
|
402
|
-
with (
|
|
403
|
-
mock.patch('os.getuid', return_value=1000),
|
|
404
|
-
mock.patch.object(pathlib.Path, 'exists', fake_exists),
|
|
405
|
-
mock.patch('os.access', return_value=True),
|
|
406
|
-
):
|
|
407
|
-
assert NsjailBackend._detect_cgroup_v2() is True
|
|
408
|
-
|
|
409
461
|
|
|
410
462
|
# ── cleanup_orphaned_containers ───────────────────────────────────────
|
|
411
463
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|