langbot-plugin 0.4.2b4__tar.gz → 0.4.3__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.3/.github/workflows/cla.yml +41 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/AGENTS.md +46 -22
- langbot_plugin-0.4.3/CONTRIBUTING.md +15 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/PKG-INFO +2 -1
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/pyproject.toml +2 -1
- langbot_plugin-0.4.3/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example +77 -0
- langbot_plugin-0.4.3/src/langbot_plugin/assets/templates/README.md.example +15 -0
- langbot_plugin-0.4.3/src/langbot_plugin/assets/templates/readme/README_zh_Hans.md.example +15 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/nsjail_backend.py +83 -36
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/initplugin.py +4 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/gen/renderer.py +2 -0
- langbot_plugin-0.4.3/src/langbot_plugin/entities/io/errors.py +91 -0
- langbot_plugin-0.4.3/src/langbot_plugin/runtime/helper/pkgmgr.py +369 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/plugin/mgr.py +78 -12
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_nsjail_backend.py +78 -20
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_initplugin.py +2 -0
- langbot_plugin-0.4.3/tests/entities/io/test_dependency_errors.py +59 -0
- langbot_plugin-0.4.3/tests/runtime/helper/test_pkgmgr.py +388 -0
- langbot_plugin-0.4.3/tests/runtime/io/test_handler.py +578 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/plugin/test_manager.py +62 -2
- langbot_plugin-0.4.2b4/src/langbot_plugin/assets/templates/README.md.example +0 -3
- langbot_plugin-0.4.2b4/src/langbot_plugin/entities/io/errors.py +0 -31
- langbot_plugin-0.4.2b4/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -141
- langbot_plugin-0.4.2b4/tests/runtime/helper/test_pkgmgr.py +0 -109
- langbot_plugin-0.4.2b4/tests/runtime/io/test_handler.py +0 -228
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/.github/workflows/publish-pypi.yaml +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/.github/workflows/test.yml +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/.gitignore +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/.python-version +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/CLAUDE.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/LICENSE +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/README.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/data/.env.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/docs/Message.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/docs/PluginPages.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/docs/communication/apis/lb2rt.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/docs/communication/runtime_plugin.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/docs/dependency-management.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/docs/langbot-plugin-social.png +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/base.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/definition/plugin.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/entities/events.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/proxies/base.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/proxies/event_context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/main.py.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/actions.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/backend.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/client.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/e2b_backend.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/errors.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/models.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/runtime.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/security.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/server.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/box/skill_store.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/__main__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/login.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/logout.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/publish.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/gen/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/i18n.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/en_US.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/run/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/run/controller.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/run/handler.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/run/hotreload.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/utils/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/utils/form.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/utils/page_components.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/io/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/io/req.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/io/resp.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/entities/marketplace.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/LICENSE +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/README.md +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/app.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/connection.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controller.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/handler.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/plugin/container.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/runtime/settings.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/utils/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/utils/discover/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/utils/discover/engine.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/utils/importutil.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/utils/log.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/utils/platform.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/version.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/definition/components/test_components.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/definition/test_manifest.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/entities/builtin/test_command_context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/entities/builtin/test_platform_logger.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/entities/builtin/test_provider_message.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/entities/builtin/test_rag_models.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/entities/test_context.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/entities/test_events.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/proxies/test_base.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/proxies/test_langbot_api.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/api/proxies/test_query_based_api.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_backend.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_backend_selection.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_client.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_e2b_backend.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_runtime.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_server.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/box/test_skill_store.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/run/test_controller.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/run/test_runtime_handler.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_buildplugin.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_gencomponent.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_i18n_form.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_login.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_logout_publish.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_page_components.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_renderer.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/cli/test_runplugin.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/entities/io/test_protocol.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/helpers/__init__.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/helpers/protocol.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/helper/test_marketplace.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/io/handlers/test_control_handler.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/io/test_connections.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/io/test_controllers.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/plugin/test_container.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/runtime/test_app.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/test_log.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/test_message.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/utils/test_discovery.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/utils/test_importutil.py +0 -0
- {langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/tests/utils/test_platform.py +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: "CLA Assistant"
|
|
2
|
+
on:
|
|
3
|
+
issue_comment:
|
|
4
|
+
types: [created]
|
|
5
|
+
pull_request_target:
|
|
6
|
+
types: [opened, closed, synchronize, reopened]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
actions: write # re-run the failed CLA check after signing
|
|
10
|
+
contents: read # signatures are stored in the remote langbot-app/cla repo
|
|
11
|
+
pull-requests: write # post guidance comments, lock PR after merge
|
|
12
|
+
statuses: write # set the commit status
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
CLAAssistant:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- name: "CLA Assistant"
|
|
19
|
+
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
|
20
|
+
# Upstream repo was archived in 2026-03; pin to the v2.6.1 commit SHA.
|
|
21
|
+
uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1
|
|
22
|
+
env:
|
|
23
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
24
|
+
# repo-scope PAT with write access to langbot-app/cla
|
|
25
|
+
PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_PAT }}
|
|
26
|
+
with:
|
|
27
|
+
path-to-document: 'https://github.com/langbot-app/LangBot/blob/master/CLA.md'
|
|
28
|
+
remote-organization-name: 'langbot-app'
|
|
29
|
+
remote-repository-name: 'cla'
|
|
30
|
+
path-to-signatures: 'signatures/version1/cla.json'
|
|
31
|
+
branch: 'main'
|
|
32
|
+
allowlist: 'dependabot[bot],github-actions[bot],devin-ai-integration[bot],Copilot,renovate[bot],bot*'
|
|
33
|
+
custom-notsigned-prcomment: |
|
|
34
|
+
Thank you for your contribution! :heart: Before we can merge this pull request, we need you to sign the [LangBot Contributor License Agreement (CLA)](https://github.com/langbot-app/LangBot/blob/master/CLA.md). You keep full copyright of your code — the CLA grants us a license to use and distribute your contribution. Signing takes 10 seconds and covers all repositories in this organization, permanently.
|
|
35
|
+
|
|
36
|
+
感谢您的贡献!合并前请阅读并签署[贡献者许可协议(CLA)](https://github.com/langbot-app/LangBot/blob/master/CLA.md)。您保留代码的全部版权,签署仅需回复下方指定内容,一次签署对本组织全部仓库永久有效。
|
|
37
|
+
custom-allsigned-prcomment: 'All contributors have signed the CLA. :white_check_mark: 所有贡献者均已签署 CLA。'
|
|
38
|
+
lock-pullrequest-aftermerge: true
|
|
39
|
+
# SECURITY: this workflow runs on pull_request_target (it holds secrets and has
|
|
40
|
+
# write access to the base repository). NEVER add an actions/checkout step that
|
|
41
|
+
# checks out the PR's code here.
|
|
@@ -816,34 +816,49 @@ Encapsulates plugin instance with:
|
|
|
816
816
|
|
|
817
817
|
### Communication Protocol (`runtime/io/`)
|
|
818
818
|
|
|
819
|
-
**
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
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`):
|
|
826
840
|
```json
|
|
827
|
-
{
|
|
828
|
-
"action": "action_name",
|
|
829
|
-
"seq": 12345,
|
|
830
|
-
"data": {...},
|
|
831
|
-
"chunk_status": "start|continue|end"
|
|
832
|
-
}
|
|
841
|
+
{ "seq_id": 12345, "action": "action_name", "data": {} }
|
|
833
842
|
```
|
|
834
843
|
|
|
835
|
-
**Response
|
|
844
|
+
**Response** (`ActionResponse`, `entities/io/resp.py`):
|
|
836
845
|
```json
|
|
837
|
-
{
|
|
838
|
-
"seq": 12345,
|
|
839
|
-
"ok": true,
|
|
840
|
-
"data": {...}
|
|
841
|
-
}
|
|
846
|
+
{ "seq_id": 12345, "code": 0, "message": "success", "data": {}, "chunk_status": "continue" }
|
|
842
847
|
```
|
|
843
848
|
|
|
844
|
-
|
|
845
|
-
- `
|
|
846
|
-
|
|
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
|
|
847
862
|
|
|
848
863
|
## CLI Tools
|
|
849
864
|
|
|
@@ -946,6 +961,15 @@ Box selects the first available sandbox backend among **Docker / nsjail / E2B**.
|
|
|
946
961
|
|
|
947
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`.
|
|
948
963
|
|
|
964
|
+
#### nsjail backend in containers — cgroup namespace requirement
|
|
965
|
+
|
|
966
|
+
The official `docker/docker-compose.yaml` runs the Box container with the **Docker (docker.sock) backend**, which has no cgroup requirements. The **nsjail backend** is different and has a non-obvious deployment requirement when run inside a container (e.g. a per-pod Box sidecar, or `BOX__BACKEND=nsjail`):
|
|
967
|
+
|
|
968
|
+
- nsjail with cgroup v2 limits (`--use_cgroupv2`) creates a child cgroup and enables controllers by writing `+memory`/`+pids`/`+cpu` to the cgroup root's `cgroup.subtree_control`. Inside a **private cgroup namespace** (Docker/k8s default) the container's own cgroup root already holds live processes (the Box runtime itself), so the kernel's *no-internal-process* rule rejects that write with **EBUSY** and every sandbox launch aborts with **exit 255**.
|
|
969
|
+
- **Fix: run the Box container in the host cgroup namespace** — compose `cgroup: host` (or `docker run --cgroupns=host`), plus `privileged: true` (nsjail also needs clone-namespaces/chroot). Then `_detect_cgroup_v2()` succeeds and nsjail applies precise cgroup memory/pid/cpu caps.
|
|
970
|
+
- `NsjailBackend._detect_cgroup_v2()` probes the **authoritative** operation (a real `cgroup.subtree_control` write), not just a `mkdir` under the cgroup root — a mkdir probe false-positives in a private cgroupns because mkdir succeeds while the subtree_control write later EBUSYs.
|
|
971
|
+
- **Without cgroups there is no hard memory cap.** When cgroup v2 is unavailable the backend falls back to rlimits but **deliberately does NOT set `--rlimit_as`**: RLIMIT_AS limits *virtual* address space, which `uv`/`node`/Rust/JVM reserve in gigabytes, so a small RLIMIT_AS aborts them instantly (`memory allocation of N bytes failed`, exit 255) — this is what silently broke uvx-based stdio MCP servers. There is no RSS-based rlimit on modern Linux, so accurate memory capping **requires** cgroups (host cgroupns) or a container-level memory limit (compose `mem_limit`). The rlimit fallback still applies safe caps (pids/fsize/nofile).
|
|
972
|
+
|
|
949
973
|
### Plugin development loop
|
|
950
974
|
|
|
951
975
|
```bash
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Contributing to langbot-plugin-sdk
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing! For general contribution guidelines, please refer to the [LangBot contribution guide](https://github.com/langbot-app/LangBot/blob/master/CONTRIBUTING.md).
|
|
4
|
+
|
|
5
|
+
感谢您有意参与贡献!通用贡献指引请参阅 [LangBot 贡献指南](https://github.com/langbot-app/LangBot/blob/master/CONTRIBUTING.md)。
|
|
6
|
+
|
|
7
|
+
## Contributor License Agreement (CLA)
|
|
8
|
+
|
|
9
|
+
To protect the project and every contributor, we require all code contributors to sign the [LangBot Contributor License Agreement](https://github.com/langbot-app/LangBot/blob/master/CLA.md). You keep full copyright of your code — the CLA only grants us a license to use and distribute your contribution.
|
|
10
|
+
|
|
11
|
+
Signing takes 10 seconds: when you open your first PR, a bot will guide you to reply with a single comment. One signature covers all repositories in this organization, permanently.
|
|
12
|
+
|
|
13
|
+
为了保护项目和每一位贡献者,我们要求所有代码贡献者签署 [LangBot 贡献者许可协议(CLA)](https://github.com/langbot-app/LangBot/blob/master/CLA.md)。您保留自己代码的全部版权,CLA 仅授予项目使用、分发您贡献的许可。
|
|
14
|
+
|
|
15
|
+
签署只需 10 秒:首次提交 PR 时,机器人会自动评论提示,按提示回复一句话即完成签署,此后对本组织所有仓库永久有效。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: langbot-plugin
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
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.3"
|
|
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.3/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 -->
|
|
@@ -110,8 +110,13 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
110
110
|
self._cgroup_v2_available = self._detect_cgroup_v2()
|
|
111
111
|
if not self._cgroup_v2_available:
|
|
112
112
|
self.logger.warning(
|
|
113
|
-
'cgroup v2
|
|
114
|
-
'falling back to rlimit-based
|
|
113
|
+
'nsjail cgroup v2 limits unavailable (private cgroup namespace '
|
|
114
|
+
'or read-only /sys/fs/cgroup); falling back to rlimit-based '
|
|
115
|
+
'limits WITHOUT a hard memory cap. RLIMIT_AS is intentionally '
|
|
116
|
+
'not used because it kills uv/node/etc. To enforce a memory '
|
|
117
|
+
'cap, run the Box container in the host cgroup namespace '
|
|
118
|
+
'(--cgroupns=host / compose `cgroup: host`) or set a '
|
|
119
|
+
'container-level memory limit.'
|
|
115
120
|
)
|
|
116
121
|
|
|
117
122
|
self._base_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -475,16 +480,27 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
475
480
|
cpu_ms = int(spec.cpus * 1000)
|
|
476
481
|
args.extend(['--cgroup_cpu_ms_per_sec', str(cpu_ms)])
|
|
477
482
|
else:
|
|
478
|
-
# rlimit fallback –
|
|
479
|
-
#
|
|
480
|
-
#
|
|
481
|
-
#
|
|
482
|
-
#
|
|
483
|
-
#
|
|
484
|
-
|
|
483
|
+
# rlimit fallback – used whenever cgroup v2 delegation is not usable
|
|
484
|
+
# (private cgroup namespace -> EBUSY, or read-only /sys/fs/cgroup).
|
|
485
|
+
#
|
|
486
|
+
# We deliberately do NOT set --rlimit_as for the memory cap.
|
|
487
|
+
# RLIMIT_AS limits *virtual* address space, not resident memory, and
|
|
488
|
+
# modern runtimes reserve huge virtual mappings up front: uv/Rust
|
|
489
|
+
# (and Go/JVM/Node) mmap gigabytes of address space even to do tiny
|
|
490
|
+
# work, so a 512 MB --rlimit_as aborts them instantly with
|
|
491
|
+
# "memory allocation of N bytes failed" (exit 255) — which is what
|
|
492
|
+
# silently broke every uvx-based stdio MCP server in containerized
|
|
493
|
+
# nsjail deployments. There is no RSS-based rlimit on modern Linux
|
|
494
|
+
# (RLIMIT_RSS is ignored), so accurate memory capping REQUIRES
|
|
495
|
+
# cgroups. Operators who need a hard memory cap must run the Box
|
|
496
|
+
# container in the host cgroup namespace (--cgroupns=host /
|
|
497
|
+
# compose `cgroup: host`); otherwise bound memory at the container
|
|
498
|
+
# level (e.g. compose `mem_limit`). We still apply the pid cap,
|
|
499
|
+
# which is a real rlimit that does not break runtimes.
|
|
485
500
|
args.extend(['--rlimit_nproc', str(spec.pids_limit)])
|
|
486
501
|
|
|
487
|
-
# Always set these rlimits regardless of cgroup mode.
|
|
502
|
+
# Always set these rlimits regardless of cgroup mode. These are safe
|
|
503
|
+
# for modern runtimes (unlike RLIMIT_AS).
|
|
488
504
|
args.extend(['--rlimit_fsize', '512']) # max file size 512 MB
|
|
489
505
|
args.extend(['--rlimit_nofile', '256']) # max open fds
|
|
490
506
|
|
|
@@ -527,42 +543,73 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
527
543
|
|
|
528
544
|
@staticmethod
|
|
529
545
|
def _detect_cgroup_v2() -> bool:
|
|
530
|
-
"""Check whether
|
|
531
|
-
|
|
532
|
-
nsjail (with ``--use_cgroupv2``)
|
|
533
|
-
``mkdir
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
546
|
+
"""Check whether nsjail's ``--use_cgroupv2`` path will actually work.
|
|
547
|
+
|
|
548
|
+
nsjail (with ``--use_cgroupv2``) moves itself into a fresh child cgroup
|
|
549
|
+
it ``mkdir``s under the cgroup v2 mount root, then enables controllers
|
|
550
|
+
for that child by writing ``+memory`` (etc.) to the ROOT's
|
|
551
|
+
``cgroup.subtree_control``. BOTH operations must succeed.
|
|
552
|
+
|
|
553
|
+
Probing ``mkdir`` alone is NOT sufficient and produces a false positive
|
|
554
|
+
in the common containerized case: inside a **private** cgroup namespace
|
|
555
|
+
(Docker/k8s default) the container's own cgroup root already contains
|
|
556
|
+
live processes (the Box runtime itself), so the kernel's
|
|
557
|
+
"no-internal-process" rule rejects the ``cgroup.subtree_control`` write
|
|
558
|
+
with ``EBUSY`` even though ``mkdir`` under the root succeeds. nsjail then
|
|
559
|
+
aborts and every sandbox launch exits 255. Conversely a read-only
|
|
560
|
+
``/sys/fs/cgroup`` (another common case) fails the ``mkdir``.
|
|
561
|
+
|
|
562
|
+
So we probe the AUTHORITATIVE operation: a real write to
|
|
563
|
+
``cgroup.subtree_control``. We only consider it available when that
|
|
564
|
+
write succeeds, which is exactly nsjail's requirement. Containerized
|
|
565
|
+
deployments that need cgroup limits must run the Box container in the
|
|
566
|
+
host cgroup namespace (``--cgroupns=host`` / compose ``cgroup: host``);
|
|
567
|
+
otherwise this returns False and the backend uses the rlimit fallback.
|
|
542
568
|
"""
|
|
543
569
|
cgroup_mount = pathlib.Path('/sys/fs/cgroup')
|
|
544
570
|
if not cgroup_mount.exists():
|
|
545
571
|
return False
|
|
546
572
|
# cgroup v2 has a single hierarchy with a cgroup.controllers file.
|
|
547
573
|
controllers = cgroup_mount / 'cgroup.controllers'
|
|
548
|
-
|
|
574
|
+
subtree_control = cgroup_mount / 'cgroup.subtree_control'
|
|
575
|
+
if not controllers.exists() or not subtree_control.exists():
|
|
549
576
|
return False
|
|
550
|
-
#
|
|
551
|
-
# cgroup
|
|
552
|
-
#
|
|
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()}'
|
|
577
|
+
# nsjail enables the controllers it needs (memory, pids, cpu) on the
|
|
578
|
+
# child cgroup, which requires them to be delegated via the root's
|
|
579
|
+
# subtree_control. Only probe controllers actually present here.
|
|
556
580
|
try:
|
|
557
|
-
|
|
581
|
+
available = set(controllers.read_text().split())
|
|
558
582
|
except Exception:
|
|
559
583
|
return False
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
584
|
+
wanted = [c for c in ('memory', 'pids', 'cpu') if c in available]
|
|
585
|
+
if not wanted:
|
|
586
|
+
return False
|
|
587
|
+
# Authoritative writability probe: re-arm a controller that is already
|
|
588
|
+
# enabled (idempotent no-op), or briefly toggle one that is not. A
|
|
589
|
+
# successful write proves nsjail's subtree_control write will also
|
|
590
|
+
# succeed; EBUSY (private cgroupns) or EACCES/EROFS (read-only mount)
|
|
591
|
+
# all surface here and correctly select the rlimit fallback.
|
|
592
|
+
try:
|
|
593
|
+
enabled = set(subtree_control.read_text().split())
|
|
594
|
+
except Exception:
|
|
595
|
+
return False
|
|
596
|
+
probe_controller = wanted[0]
|
|
597
|
+
try:
|
|
598
|
+
if probe_controller in enabled:
|
|
599
|
+
# Already delegated: re-writing the same enable is a harmless
|
|
600
|
+
# no-op that still exercises the write permission + EBUSY rule.
|
|
601
|
+
subtree_control.write_text(f'+{probe_controller}')
|
|
602
|
+
else:
|
|
603
|
+
# Not yet delegated: enable then immediately disable to leave
|
|
604
|
+
# the host configuration untouched.
|
|
605
|
+
subtree_control.write_text(f'+{probe_controller}')
|
|
606
|
+
try:
|
|
607
|
+
subtree_control.write_text(f'-{probe_controller}')
|
|
608
|
+
except Exception:
|
|
609
|
+
pass
|
|
610
|
+
except Exception:
|
|
611
|
+
return False
|
|
612
|
+
return True
|
|
566
613
|
|
|
567
614
|
async def _kill_session_processes(self, session_dir: pathlib.Path) -> None:
|
|
568
615
|
"""Best-effort kill of nsjail processes associated with a session dir.
|
{langbot_plugin-0.4.2b4 → langbot_plugin-0.4.3}/src/langbot_plugin/cli/commands/initplugin.py
RENAMED
|
@@ -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
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConnectionClosedError(Exception):
|
|
5
|
+
"""The connection is closed."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, message: str):
|
|
8
|
+
self.message = message
|
|
9
|
+
|
|
10
|
+
def __str__(self):
|
|
11
|
+
return self.message
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ActionCallTimeoutError(Exception):
|
|
15
|
+
"""The action call timed out."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, message: str):
|
|
18
|
+
self.message = message
|
|
19
|
+
|
|
20
|
+
def __str__(self):
|
|
21
|
+
return self.message
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DependencyInstallError(Exception):
|
|
25
|
+
"""One or more plugin dependencies failed to install via pip.
|
|
26
|
+
|
|
27
|
+
Carries enough structure for callers to log per-package diagnostics or
|
|
28
|
+
surface them to the UI, instead of a single flattened string.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
failed: list[str],
|
|
34
|
+
plugin: str | None = None,
|
|
35
|
+
details: dict[str, str] | None = None,
|
|
36
|
+
):
|
|
37
|
+
# List of requirement specs that pip could not install (after retries).
|
|
38
|
+
self.failed = failed
|
|
39
|
+
# "<author>/<name>" of the plugin being installed, when known.
|
|
40
|
+
self.plugin = plugin
|
|
41
|
+
# Optional per-package error text (requirement spec -> pip stderr tail).
|
|
42
|
+
self.details = details or {}
|
|
43
|
+
prefix = f"Plugin {plugin} " if plugin else ""
|
|
44
|
+
super().__init__(
|
|
45
|
+
f"{prefix}failed to install {len(failed)} dependencies: {failed}"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def __str__(self):
|
|
49
|
+
prefix = f"Plugin {self.plugin} " if self.plugin else ""
|
|
50
|
+
return f"{prefix}failed to install {len(self.failed)} dependencies: {self.failed}"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class DependencyVerificationError(Exception):
|
|
54
|
+
"""Dependencies were installed but could not be verified afterwards.
|
|
55
|
+
|
|
56
|
+
``missing`` holds requirement specs whose distribution/import could not be
|
|
57
|
+
resolved after pip reported success; ``version_mismatch`` holds specs whose
|
|
58
|
+
installed version does not satisfy the requested specifier.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(
|
|
62
|
+
self,
|
|
63
|
+
missing: list[str],
|
|
64
|
+
version_mismatch: list[str] | None = None,
|
|
65
|
+
plugin: str | None = None,
|
|
66
|
+
):
|
|
67
|
+
self.missing = missing
|
|
68
|
+
self.version_mismatch = version_mismatch or []
|
|
69
|
+
self.plugin = plugin
|
|
70
|
+
prefix = f"Plugin {plugin}: " if plugin else ""
|
|
71
|
+
super().__init__(
|
|
72
|
+
f"{prefix}missing dependencies: {missing}, "
|
|
73
|
+
f"version mismatch: {self.version_mismatch}"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def __str__(self):
|
|
77
|
+
prefix = f"Plugin {self.plugin}: " if self.plugin else ""
|
|
78
|
+
return (
|
|
79
|
+
f"{prefix}missing dependencies: {self.missing}, "
|
|
80
|
+
f"version mismatch: {self.version_mismatch}"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ActionCallError(Exception):
|
|
85
|
+
"""The action call failed."""
|
|
86
|
+
|
|
87
|
+
def __init__(self, message: str):
|
|
88
|
+
self.message = message
|
|
89
|
+
|
|
90
|
+
def __str__(self):
|
|
91
|
+
return self.message
|