langbot-plugin 0.7.14__tar.gz → 0.7.16__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.7.16/.github/workflows/box-docker.yml +34 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/ARCHITECTURE.md +4 -1
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/PKG-INFO +1 -1
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/pyproject.toml +1 -1
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/asset_gateway.py +43 -2
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/backend.py +8 -1
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/host_backend.py +22 -16
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/runtime.py +3 -1
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/mgr.py +7 -0
- langbot_plugin-0.7.16/src/langbot_plugin/version.py +1 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/test_agent_tools_mcp_bridge.py +39 -0
- langbot_plugin-0.7.16/tests/box/test_artifact_cache_root.py +91 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_host_backend.py +80 -0
- langbot_plugin-0.7.16/tests/e2e/Dockerfile.box-socket +8 -0
- langbot_plugin-0.7.16/tests/e2e/Dockerfile.box-socket.dockerignore +10 -0
- langbot_plugin-0.7.16/tests/e2e/test_box_socket_mounts.py +125 -0
- langbot_plugin-0.7.16/tests/runtime/plugin/test_event_dispatch_real_worker.py +220 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_manager.py +129 -5
- langbot_plugin-0.7.14/src/langbot_plugin/version.py +0 -1
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/.github/workflows/cla.yml +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/.github/workflows/publish-pypi.yaml +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/.github/workflows/publish.yml +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/.github/workflows/test.yml +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/.gitignore +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/.python-version +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/AGENTS.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/CLAUDE.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/CONTRIBUTING.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/LICENSE +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/README.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/README_CN.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/data/.env.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/Message.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/PluginPages.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/agent-runner-interactions.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/agent-runner-pluginization/PROTOCOL_V1.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/agent-runner-pluginization/README.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/agent-runner-pluginization/SDK_RUNTIME_PLAN.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/certified-plugins.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/communication/apis/lb2rt.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/communication/runtime_plugin.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/dependency-management.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/langbot-plugin-social.png +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/runner.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/docs/stateless-components.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/local_e2e/acceptance.json +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/local_e2e/registration_fanin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/local_e2e/run_acceptance.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/mypy.ini +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/scripts/check_action_consistency.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/scripts/runtime_resource_probe.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/daemon.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/decorators.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/external_tools.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/mcp_access.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/mcp_bridge.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/mcp_config.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/mcp_protocol.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/mcp_stdio.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/base.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/runner/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/runner/runner.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/definition/plugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/platform/errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/provider/reasoning.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/box.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/capabilities.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/compat.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/context_access.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/delivery.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/event.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/input.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/interaction.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/manifest.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/page_results.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/permissions.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/resources.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/result.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/run_ledger.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/runtime.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/runtime_registry.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/state.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/stats.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/steering.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/transcript.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/builtin/runner/trigger.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/events.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/entities/execution.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/base.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/event_context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/invocation.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/admin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/api.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/box.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/common.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/ledger.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/platform.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/reply_stream.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/resources.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/state.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/proxies/runner/tracing.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/artifact.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/README.md.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/runner/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/runner/{runner_name}.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/runner/{runner_name}.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/main.py.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/readme/README_zh_Hans.md.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/actions.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/client.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/e2b_backend.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/models.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/nsjail_backend.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/security.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/server.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/box/tenancy.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/certification.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/__main__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/initplugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/login.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/logout.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/publish.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/gen/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/gen/renderer.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/i18n.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/en_US.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/run/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/run/controller.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/run/handler.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/run/hotreload.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/utils/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/utils/form.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/cli/utils/page_components.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/req.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/io/resp.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/entities/marketplace.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/LICENSE +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/README.md +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/app.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/bounded_executor.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/event_loop_monitor.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/connection.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controller.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/handler.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/ops_metrics.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/artifact.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/container.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/dependency_environment.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/logbuffer.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/restart_coordinator.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/runner_service.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/worker_launcher.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/worker_observability.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/plugin/worker_watchdog.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/security.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/runtime/settings.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/skill_store.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/storage.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/deadline.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/discover/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/discover/engine.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/importutil.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/log.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/utils/platform.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/workspace.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/definition/components/test_components.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/definition/components/test_imports.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/definition/test_manifest.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/runner/test_context_result.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/runner/test_history_event_entities.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/runner/test_interaction.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/runner/test_run_ledger_entities.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/test_command_context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/test_platform_logger.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/test_provider_message.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/builtin/test_rag_models.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/test_context.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/entities/test_events.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_agent_run_api_proxy.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_base.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_box_api.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_history_event_api_proxy.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_langbot_api.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_llm_stream_ownership.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_query_based_api.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/proxies/test_reasoning_parameter.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/test_runner_handlers.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/test_runner_handlers_matrix.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/api/test_runner_public_apis.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_admission.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_backend.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_backend_selection.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_client.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_e2b_backend.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_nsjail_backend.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_runtime.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_server.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_skill_store.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/box/test_storage_analysis.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/run/test_controller.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/run/test_hotreload.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/run/test_runtime_handler.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_buildplugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_gencomponent.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_i18n_form.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_initplugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_login.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_logout_publish.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_page_components.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_renderer.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_runner_usages.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/cli/test_runplugin.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/e2e/standalone_runtime_eba_probe.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/e2e/test_run_mount_isolation.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/entities/io/test_dependency_errors.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/entities/io/test_protocol.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/fixtures/eba_event_probe_plugin/.gitignore +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/fixtures/eba_event_probe_plugin/assets/icon.svg +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/fixtures/eba_event_probe_plugin/components/event_listener/default.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/fixtures/eba_event_probe_plugin/components/event_listener/default.yaml +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/fixtures/eba_event_probe_plugin/main.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/fixtures/eba_event_probe_plugin/manifest.yaml +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/helpers/__init__.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/helpers/protocol.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/packaging/test_installed_cli_blackbox.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/packaging/test_release_metadata.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/helper/test_marketplace.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/helper/test_pkgmgr.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/handlers/test_control_handler.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/handlers/test_legacy_file_chunk.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_action_consistency.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_connections.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_controllers.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_handler.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_heartbeat_admission.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_stdio_server.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/io/test_stream_flow_control.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_artifact_store.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_container.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_dependency_environment.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_exact_dify_real_worker.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_exact_legacy_sdk_compat.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_installation_manager.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_legacy_shadow.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_mgr_runner.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_mode_resource_limits.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_restart_coordinator.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_shared_worker_subprocess.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_worker_launcher.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_worker_plugin_identity.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/plugin/test_workload_isolation.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/test_app.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/test_bounded_executor.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/test_event_loop_monitor.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/test_ops_metrics.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/runtime/test_pull_api_handlers.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_artifact_materialization.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_certification.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_log.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_message.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_plugin_logbuffer.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_skill_store.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_storage.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_worker_observability.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/test_worker_watchdog.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/utils/test_deadline.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/utils/test_discovery.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/utils/test_importutil.py +0 -0
- {langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/tests/utils/test_platform.py +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Box Docker Acceptance
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
box-docker:
|
|
14
|
+
name: Real Docker socket mounts
|
|
15
|
+
runs-on: ubuntu-24.04
|
|
16
|
+
timeout-minutes: 15
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
- name: Build acceptance image
|
|
22
|
+
run: |
|
|
23
|
+
docker build -f tests/e2e/Dockerfile.box-socket \
|
|
24
|
+
-t langbot-box-socket-test .
|
|
25
|
+
docker pull alpine:3.21
|
|
26
|
+
- name: Verify private tmp and shared artifact cache
|
|
27
|
+
shell: bash
|
|
28
|
+
run: |
|
|
29
|
+
shared_root=$(mktemp -d "${RUNNER_TEMP}/box-socket.XXXXXX")
|
|
30
|
+
docker run --rm --init --name langbot-box-socket-test \
|
|
31
|
+
--volume /var/run/docker.sock:/var/run/docker.sock \
|
|
32
|
+
--volume "$shared_root:$shared_root" \
|
|
33
|
+
--env LANGBOT_TEST_BOX_SHARED_ROOT="$shared_root" \
|
|
34
|
+
langbot-box-socket-test
|
|
@@ -458,7 +458,10 @@ values. Ordinary fixed mounts include `content_digest` and `manifest_path` in
|
|
|
458
458
|
the session signature; supported digest-addressed packages are excluded from it.
|
|
459
459
|
Digest-addressed packages use the reserved
|
|
460
460
|
`/opt/langbot-artifacts/<digest>` namespace. Docker/Podman pre-mount a read-only
|
|
461
|
-
cache and atomically populate verified revisions before execution.
|
|
461
|
+
cache and atomically populate verified revisions before execution. Caches live
|
|
462
|
+
under the configured `box.local.host_root`, outside the default writable Workspace,
|
|
463
|
+
and are removed with their session. Containerized Box must share this root at the
|
|
464
|
+
same absolute path as the host daemon. E2B seals and
|
|
462
465
|
verifies packages before publishing stable digest projections. These packages can
|
|
463
466
|
be added after a Box is acquired, without replacing the session. nsjail applies
|
|
464
467
|
all mounts independently per execution. Fixed ordinary host mounts still reject
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: langbot-plugin
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.16
|
|
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
|
{langbot_plugin-0.7.14 → langbot_plugin-0.7.16}/src/langbot_plugin/api/agent_tools/asset_gateway.py
RENAMED
|
@@ -37,6 +37,8 @@ LANGBOT_AGENT_GATEWAY_INSTRUCTIONS = (
|
|
|
37
37
|
"when reply permission is available."
|
|
38
38
|
)
|
|
39
39
|
DEFAULT_RUN_TOKEN_TTL_SECONDS = 3600.0
|
|
40
|
+
MAX_HTTP_MCP_BODY_BYTES = 1024 * 1024
|
|
41
|
+
_HTTP_BODY_TOO_LARGE = object()
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
class _GatewayMCPResolver:
|
|
@@ -137,6 +139,12 @@ class AgentAssetGateway:
|
|
|
137
139
|
self._thread: threading.Thread | None = None
|
|
138
140
|
self._registrations: dict[str, AgentAssetGatewayRegistration] = {}
|
|
139
141
|
self._lock = threading.RLock()
|
|
142
|
+
self._active_handlers = 0
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def active_handler_count(self) -> int:
|
|
146
|
+
with self._lock:
|
|
147
|
+
return self._active_handlers
|
|
140
148
|
|
|
141
149
|
@property
|
|
142
150
|
def endpoint(self) -> str:
|
|
@@ -156,6 +164,19 @@ class AgentAssetGateway:
|
|
|
156
164
|
gateway = self
|
|
157
165
|
|
|
158
166
|
class Handler(BaseHTTPRequestHandler):
|
|
167
|
+
def setup(self) -> None:
|
|
168
|
+
super().setup()
|
|
169
|
+
self.connection.settimeout(gateway.request_timeout)
|
|
170
|
+
with gateway._lock:
|
|
171
|
+
gateway._active_handlers += 1
|
|
172
|
+
|
|
173
|
+
def finish(self) -> None:
|
|
174
|
+
try:
|
|
175
|
+
super().finish()
|
|
176
|
+
finally:
|
|
177
|
+
with gateway._lock:
|
|
178
|
+
gateway._active_handlers -= 1
|
|
179
|
+
|
|
159
180
|
def log_message(self, _format: str, *_args: typing.Any) -> None:
|
|
160
181
|
return
|
|
161
182
|
|
|
@@ -170,7 +191,13 @@ class AgentAssetGateway:
|
|
|
170
191
|
self.send_error(404)
|
|
171
192
|
return
|
|
172
193
|
|
|
173
|
-
|
|
194
|
+
try:
|
|
195
|
+
payload = self._read_json_payload()
|
|
196
|
+
except OSError:
|
|
197
|
+
self.close_connection = True
|
|
198
|
+
return
|
|
199
|
+
if payload is _HTTP_BODY_TOO_LARGE:
|
|
200
|
+
return
|
|
174
201
|
if isinstance(payload, Exception):
|
|
175
202
|
self._write_json(
|
|
176
203
|
400, {"ok": False, "error": f"invalid JSON: {payload}"}
|
|
@@ -190,6 +217,12 @@ class AgentAssetGateway:
|
|
|
190
217
|
return
|
|
191
218
|
self._write_json(200, result)
|
|
192
219
|
|
|
220
|
+
def handle_one_request(self) -> None:
|
|
221
|
+
try:
|
|
222
|
+
super().handle_one_request()
|
|
223
|
+
except (TimeoutError, OSError):
|
|
224
|
+
self.close_connection = True
|
|
225
|
+
|
|
193
226
|
def do_DELETE(self) -> None:
|
|
194
227
|
if self.path not in {"/mcp", "/mcp/http"}:
|
|
195
228
|
self.send_error(404)
|
|
@@ -216,10 +249,18 @@ class AgentAssetGateway:
|
|
|
216
249
|
try:
|
|
217
250
|
length = int(self.headers.get("Content-Length", "0"))
|
|
218
251
|
except ValueError:
|
|
219
|
-
|
|
252
|
+
return ValueError("invalid Content-Length")
|
|
253
|
+
if length < 0:
|
|
254
|
+
return ValueError("invalid Content-Length")
|
|
255
|
+
if length > MAX_HTTP_MCP_BODY_BYTES:
|
|
256
|
+
self._write_empty(413)
|
|
257
|
+
self.close_connection = True
|
|
258
|
+
return _HTTP_BODY_TOO_LARGE
|
|
220
259
|
try:
|
|
221
260
|
body = self.rfile.read(length).decode("utf-8")
|
|
222
261
|
return json.loads(body) if body else {}
|
|
262
|
+
except TimeoutError:
|
|
263
|
+
raise
|
|
223
264
|
except Exception as e:
|
|
224
265
|
return e
|
|
225
266
|
|
|
@@ -169,6 +169,7 @@ class CLISandboxBackend(BaseSandboxBackend):
|
|
|
169
169
|
self.command = command
|
|
170
170
|
self.name = backend_name
|
|
171
171
|
self.cpu_limit_enabled = True
|
|
172
|
+
self.artifact_cache_parent: str | None = None
|
|
172
173
|
self._artifact_roots: dict[str, str] = {}
|
|
173
174
|
|
|
174
175
|
async def is_available(self) -> bool:
|
|
@@ -224,7 +225,13 @@ class CLISandboxBackend(BaseSandboxBackend):
|
|
|
224
225
|
)
|
|
225
226
|
args.extend(["-v", mount_spec])
|
|
226
227
|
|
|
227
|
-
|
|
228
|
+
# Bind sources are resolved by the daemon, not this process. When a
|
|
229
|
+
# shared host root is configured, the cache must live there as well.
|
|
230
|
+
if self.artifact_cache_parent is not None:
|
|
231
|
+
os.makedirs(self.artifact_cache_parent, exist_ok=True)
|
|
232
|
+
artifact_root = tempfile.mkdtemp(
|
|
233
|
+
prefix="langbot-box-artifacts-", dir=self.artifact_cache_parent
|
|
234
|
+
)
|
|
228
235
|
os.chmod(artifact_root, 0o755)
|
|
229
236
|
self._artifact_roots[container_name] = artifact_root
|
|
230
237
|
args.extend(["-v", f"{artifact_root}:{ARTIFACT_MOUNT_ROOT}:ro"])
|
|
@@ -329,21 +329,25 @@ class HostProcessBackend(BaseSandboxBackend):
|
|
|
329
329
|
stderr=asyncio.subprocess.PIPE,
|
|
330
330
|
start_new_session=True,
|
|
331
331
|
)
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
completion = asyncio.gather(
|
|
333
|
+
process.wait(),
|
|
334
|
+
self._read_stream(process.stdout),
|
|
335
|
+
self._read_stream(process.stderr),
|
|
336
|
+
)
|
|
334
337
|
timed_out = False
|
|
335
338
|
try:
|
|
336
|
-
|
|
339
|
+
# Descendants can keep output pipes open after the shell exits.
|
|
340
|
+
# Keep readers alive during cleanup to preserve captured output.
|
|
341
|
+
await asyncio.wait_for(asyncio.shield(completion), timeout=timeout_sec)
|
|
337
342
|
except asyncio.TimeoutError:
|
|
338
343
|
timed_out = True
|
|
339
344
|
await self._terminate_process_group(process)
|
|
340
345
|
except asyncio.CancelledError:
|
|
341
346
|
await self._terminate_process_group(process)
|
|
342
|
-
await
|
|
347
|
+
await completion
|
|
343
348
|
raise
|
|
344
349
|
|
|
345
|
-
stdout_bytes, stdout_total = await
|
|
346
|
-
stderr_bytes, stderr_total = await stderr_task
|
|
350
|
+
_, (stdout_bytes, stdout_total), (stderr_bytes, stderr_total) = await completion
|
|
347
351
|
return _CommandResult(
|
|
348
352
|
return_code=process.returncode if process.returncode is not None else -1,
|
|
349
353
|
stdout=self._clip_captured_bytes(stdout_bytes, stdout_total),
|
|
@@ -357,20 +361,22 @@ class HostProcessBackend(BaseSandboxBackend):
|
|
|
357
361
|
*,
|
|
358
362
|
timeout_sec: float = 2.0,
|
|
359
363
|
) -> None:
|
|
360
|
-
if
|
|
361
|
-
|
|
364
|
+
"""Terminate the isolated group even if its shell has already exited."""
|
|
365
|
+
loop = asyncio.get_running_loop()
|
|
366
|
+
deadline = loop.time() + timeout_sec
|
|
362
367
|
try:
|
|
363
368
|
os.killpg(process.pid, signal.SIGTERM)
|
|
369
|
+
# A shell exit does not mean descendants exited or closed their pipes.
|
|
370
|
+
while True:
|
|
371
|
+
os.killpg(process.pid, 0)
|
|
372
|
+
remaining = deadline - loop.time()
|
|
373
|
+
if remaining <= 0:
|
|
374
|
+
break
|
|
375
|
+
await asyncio.sleep(min(0.05, remaining))
|
|
376
|
+
os.killpg(process.pid, signal.SIGKILL)
|
|
364
377
|
except ProcessLookupError:
|
|
365
378
|
pass
|
|
366
|
-
|
|
367
|
-
await asyncio.wait_for(process.wait(), timeout=timeout_sec)
|
|
368
|
-
except asyncio.TimeoutError:
|
|
369
|
-
try:
|
|
370
|
-
os.killpg(process.pid, signal.SIGKILL)
|
|
371
|
-
except ProcessLookupError:
|
|
372
|
-
pass
|
|
373
|
-
await process.wait()
|
|
379
|
+
await process.wait()
|
|
374
380
|
|
|
375
381
|
@staticmethod
|
|
376
382
|
def _preview(command: str) -> str:
|
|
@@ -22,7 +22,7 @@ import pydantic
|
|
|
22
22
|
from langbot_plugin.entities.io.context import ActionContext
|
|
23
23
|
from langbot_plugin.runtime.event_loop_monitor import EventLoopLagMonitor
|
|
24
24
|
|
|
25
|
-
from .backend import BaseSandboxBackend, DockerBackend
|
|
25
|
+
from .backend import BaseSandboxBackend, CLISandboxBackend, DockerBackend
|
|
26
26
|
from .host_backend import HostProcessBackend
|
|
27
27
|
from .nsjail_backend import NsjailBackend
|
|
28
28
|
from .errors import (
|
|
@@ -1220,6 +1220,8 @@ done
|
|
|
1220
1220
|
for backend in self.backends:
|
|
1221
1221
|
if backend is None:
|
|
1222
1222
|
continue
|
|
1223
|
+
if isinstance(backend, CLISandboxBackend):
|
|
1224
|
+
backend.artifact_cache_parent = self._host_root()
|
|
1223
1225
|
backend_config = config.get(backend.name, {})
|
|
1224
1226
|
if backend_config and hasattr(backend, "configure"):
|
|
1225
1227
|
backend.configure(backend_config)
|
|
@@ -41,6 +41,7 @@ from langbot_plugin.runtime import bounded_executor
|
|
|
41
41
|
from langbot_plugin.runtime import ops_metrics as ops_metrics_module
|
|
42
42
|
from langbot_plugin.api.entities.context import EventContext
|
|
43
43
|
from langbot_plugin.api.definition.components.manifest import ComponentManifest
|
|
44
|
+
from langbot_plugin.api.definition.components.common.event_listener import EventListener
|
|
44
45
|
from langbot_plugin.api.definition.components.tool.tool import Tool
|
|
45
46
|
from langbot_plugin.api.definition.components.command.command import Command
|
|
46
47
|
from langbot_plugin.api.definition.components.knowledge_engine.engine import (
|
|
@@ -3194,6 +3195,12 @@ class PluginManager:
|
|
|
3194
3195
|
if plugin_id not in include_plugins:
|
|
3195
3196
|
continue
|
|
3196
3197
|
|
|
3198
|
+
if not any(
|
|
3199
|
+
component.manifest.kind == EventListener.__kind__
|
|
3200
|
+
for component in plugin.components
|
|
3201
|
+
):
|
|
3202
|
+
continue
|
|
3203
|
+
|
|
3197
3204
|
reply_message_chain_before = _dump_reply_message_chain(event_context)
|
|
3198
3205
|
trusted_query_id = event_context.query_id
|
|
3199
3206
|
trusted_query_uuid = event_context.query_uuid
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.16"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import http.client
|
|
4
5
|
import json
|
|
5
6
|
import os
|
|
6
7
|
import time
|
|
@@ -765,6 +766,44 @@ def test_asset_gateway_cleans_expired_registrations() -> None:
|
|
|
765
766
|
asyncio.run(run_probe())
|
|
766
767
|
|
|
767
768
|
|
|
769
|
+
def test_asset_gateway_http_rejects_oversized_and_times_out_slow_requests() -> None:
|
|
770
|
+
async def run_probe() -> None:
|
|
771
|
+
gateway = AgentAssetGateway(request_timeout=0.1)
|
|
772
|
+
registration = gateway.register_run(
|
|
773
|
+
FakeRunAPI(), _authorized_ctx(), token="bounded-token"
|
|
774
|
+
)
|
|
775
|
+
try:
|
|
776
|
+
assert gateway._server is not None
|
|
777
|
+
port = gateway._server.server_address[1]
|
|
778
|
+
connection = http.client.HTTPConnection("127.0.0.1", port, timeout=1)
|
|
779
|
+
try:
|
|
780
|
+
connection.putrequest("POST", "/mcp")
|
|
781
|
+
connection.putheader("Content-Length", str(1024 * 1024 + 1))
|
|
782
|
+
connection.endheaders()
|
|
783
|
+
assert connection.getresponse().status == 413
|
|
784
|
+
finally:
|
|
785
|
+
connection.close()
|
|
786
|
+
|
|
787
|
+
connection = http.client.HTTPConnection("127.0.0.1", port, timeout=1)
|
|
788
|
+
try:
|
|
789
|
+
connection.putrequest("POST", "/mcp")
|
|
790
|
+
connection.putheader("Content-Length", "100")
|
|
791
|
+
connection.endheaders()
|
|
792
|
+
connection.send(b"{")
|
|
793
|
+
with pytest.raises(http.client.RemoteDisconnected):
|
|
794
|
+
connection.getresponse()
|
|
795
|
+
finally:
|
|
796
|
+
connection.close()
|
|
797
|
+
|
|
798
|
+
await asyncio.sleep(0.05)
|
|
799
|
+
assert gateway.active_handler_count == 0
|
|
800
|
+
finally:
|
|
801
|
+
registration.stop()
|
|
802
|
+
gateway.stop()
|
|
803
|
+
|
|
804
|
+
asyncio.run(run_probe())
|
|
805
|
+
|
|
806
|
+
|
|
768
807
|
def test_daemon_config_and_mcp_payload_edges(monkeypatch) -> None:
|
|
769
808
|
monkeypatch.setenv("LANGBOT_AGENT_RUNTIME_DAEMON_ENABLED", "true")
|
|
770
809
|
monkeypatch.setenv("LANGBOT_AGENT_RUNTIME_DAEMON_HOST", "0.0.0.0")
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Docker/Podman bind sources must use the configured daemon-visible root."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from unittest import mock
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from langbot_plugin.box.backend import CLISandboxBackend, _CommandResult
|
|
10
|
+
from langbot_plugin.box.errors import BoxError
|
|
11
|
+
from langbot_plugin.box.models import ARTIFACT_MOUNT_ROOT, BoxSpec
|
|
12
|
+
from langbot_plugin.box.runtime import BoxRuntime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def configured_backend(tmp_path, monkeypatch, name):
|
|
16
|
+
monkeypatch.delenv("LANGBOT_BOX_CONFIG", raising=False)
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
backend = CLISandboxBackend(logger, name, name)
|
|
19
|
+
runtime = BoxRuntime(logger, backends=[backend])
|
|
20
|
+
# Relative host roots use the runtime's working directory, not the workspace.
|
|
21
|
+
monkeypatch.chdir(tmp_path)
|
|
22
|
+
runtime.init({"local": {"host_root": "shared", "default_workspace": "default"}})
|
|
23
|
+
return backend
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.asyncio
|
|
27
|
+
@pytest.mark.parametrize("name", ["docker", "podman"])
|
|
28
|
+
@pytest.mark.parametrize("mode", ["rw", "ro", "none"])
|
|
29
|
+
async def test_cache_mount_uses_shared_root_without_packages(
|
|
30
|
+
tmp_path, monkeypatch, name, mode
|
|
31
|
+
):
|
|
32
|
+
backend = configured_backend(tmp_path, monkeypatch, name)
|
|
33
|
+
private_tmp = tmp_path / "container-private-tmp"
|
|
34
|
+
private_tmp.mkdir()
|
|
35
|
+
monkeypatch.setattr("tempfile.tempdir", str(private_tmp))
|
|
36
|
+
workspace = tmp_path / "shared" / "default"
|
|
37
|
+
command = mock.AsyncMock(return_value=_CommandResult(0, "", ""))
|
|
38
|
+
with mock.patch.object(backend, "_run_command", command):
|
|
39
|
+
first = await backend.start_session(
|
|
40
|
+
BoxSpec(session_id="first", host_path=str(workspace), host_path_mode=mode)
|
|
41
|
+
)
|
|
42
|
+
second = await backend.start_session(BoxSpec(session_id="second"))
|
|
43
|
+
roots = [Path(root) for root in backend._artifact_roots.values()]
|
|
44
|
+
assert len(set(roots)) == 2
|
|
45
|
+
assert all(
|
|
46
|
+
root.parent == tmp_path / "shared" and root.is_dir() for root in roots
|
|
47
|
+
)
|
|
48
|
+
assert not list(private_tmp.iterdir())
|
|
49
|
+
assert not list(workspace.iterdir())
|
|
50
|
+
for call, root in zip(command.call_args_list, roots):
|
|
51
|
+
args = call.args[0]
|
|
52
|
+
assert f"{root}:{ARTIFACT_MOUNT_ROOT}:ro" in args
|
|
53
|
+
await backend.stop_session(first)
|
|
54
|
+
assert not roots[0].exists() and roots[1].is_dir()
|
|
55
|
+
await backend.stop_session(second)
|
|
56
|
+
assert not backend._artifact_roots
|
|
57
|
+
assert not any(root.exists() for root in roots)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.asyncio
|
|
61
|
+
async def test_failed_creation_cleans_shared_cache(tmp_path, monkeypatch):
|
|
62
|
+
backend = configured_backend(tmp_path, monkeypatch, "docker")
|
|
63
|
+
roots = []
|
|
64
|
+
|
|
65
|
+
async def run(args, **kwargs):
|
|
66
|
+
if args[1] == "run":
|
|
67
|
+
roots.extend(Path(root) for root in backend._artifact_roots.values())
|
|
68
|
+
assert roots[0].is_dir()
|
|
69
|
+
raise BoxError("creation failed")
|
|
70
|
+
return _CommandResult(0, "", "")
|
|
71
|
+
|
|
72
|
+
with mock.patch.object(backend, "_run_command", side_effect=run):
|
|
73
|
+
with pytest.raises(BoxError, match="creation failed"):
|
|
74
|
+
await backend.start_session(BoxSpec(session_id="failed"))
|
|
75
|
+
assert roots and not any(root.exists() for root in roots)
|
|
76
|
+
assert not backend._artifact_roots
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@pytest.mark.asyncio
|
|
80
|
+
async def test_unusable_shared_root_does_not_retry_in_private_tmp(
|
|
81
|
+
tmp_path, monkeypatch
|
|
82
|
+
):
|
|
83
|
+
backend = configured_backend(tmp_path, monkeypatch, "docker")
|
|
84
|
+
backend.artifact_cache_parent = str(tmp_path / "file")
|
|
85
|
+
Path(backend.artifact_cache_parent).write_text("not a directory")
|
|
86
|
+
command = mock.AsyncMock()
|
|
87
|
+
with mock.patch.object(backend, "_run_command", command):
|
|
88
|
+
with pytest.raises(FileExistsError):
|
|
89
|
+
await backend.start_session(BoxSpec(session_id="invalid"))
|
|
90
|
+
command.assert_not_called()
|
|
91
|
+
assert not backend._artifact_roots
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
|
+
import shlex
|
|
7
|
+
import signal
|
|
6
8
|
|
|
7
9
|
import pytest
|
|
8
10
|
|
|
@@ -209,3 +211,81 @@ async def test_host_backend_reports_no_isolation(backend):
|
|
|
209
211
|
assert readiness["mount_isolation"] is False
|
|
210
212
|
assert readiness["network_isolation"] is False
|
|
211
213
|
assert readiness["cgroup_v2"] is False
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@pytest.mark.anyio
|
|
217
|
+
@pytest.mark.parametrize("trigger", ["timeout", "cancel"])
|
|
218
|
+
@pytest.mark.parametrize("topology", ["closed_output", "exited_parent"])
|
|
219
|
+
async def test_host_backend_kills_sigterm_resistant_descendants(
|
|
220
|
+
backend, tmp_path, trigger, topology
|
|
221
|
+
):
|
|
222
|
+
child_script = (
|
|
223
|
+
"trap '' TERM\n"
|
|
224
|
+
+ ("exec >/dev/null 2>&1\n" if topology == "closed_output" else "")
|
|
225
|
+
+ 'printf %s "$$" > child.pid\nexec sleep 30'
|
|
226
|
+
)
|
|
227
|
+
command = (
|
|
228
|
+
"printf before-timeout; printf before-timeout-error >&2\n"
|
|
229
|
+
+ 'printf %s "$$" > parent.pid\n'
|
|
230
|
+
+ f"sh -c {shlex.quote(child_script)} &\n"
|
|
231
|
+
+ "while [ ! -s child.pid ]; do sleep 0.01; done\n"
|
|
232
|
+
+ ("exit 0" if topology == "exited_parent" else "wait")
|
|
233
|
+
)
|
|
234
|
+
spec = _spec(tmp_path, cmd=command, timeout_sec=1 if trigger == "timeout" else 30)
|
|
235
|
+
session = await backend.start_session(spec)
|
|
236
|
+
task = asyncio.create_task(backend.exec(session, spec))
|
|
237
|
+
parent_pid = None
|
|
238
|
+
try:
|
|
239
|
+
loop = asyncio.get_running_loop()
|
|
240
|
+
deadline = loop.time() + 5
|
|
241
|
+
pid_file = tmp_path / "child.pid"
|
|
242
|
+
while not pid_file.exists() or not pid_file.read_text().strip():
|
|
243
|
+
assert loop.time() < deadline, "child did not become ready"
|
|
244
|
+
await asyncio.sleep(0.01)
|
|
245
|
+
child_pid = int(pid_file.read_text())
|
|
246
|
+
parent_pid = int((tmp_path / "parent.pid").read_text())
|
|
247
|
+
assert os.getpgid(child_pid) == parent_pid
|
|
248
|
+
|
|
249
|
+
# Exercise cancellation only after the parent has already been reaped.
|
|
250
|
+
if topology == "exited_parent":
|
|
251
|
+
while True:
|
|
252
|
+
try:
|
|
253
|
+
os.kill(parent_pid, 0)
|
|
254
|
+
except ProcessLookupError:
|
|
255
|
+
break
|
|
256
|
+
assert loop.time() < deadline, "parent shell did not exit"
|
|
257
|
+
await asyncio.sleep(0.01)
|
|
258
|
+
|
|
259
|
+
if trigger == "cancel":
|
|
260
|
+
task.cancel()
|
|
261
|
+
with pytest.raises(asyncio.CancelledError):
|
|
262
|
+
await asyncio.wait_for(asyncio.shield(task), timeout=6)
|
|
263
|
+
else:
|
|
264
|
+
result = await asyncio.wait_for(asyncio.shield(task), timeout=6)
|
|
265
|
+
assert result.status == BoxExecutionStatus.TIMED_OUT
|
|
266
|
+
assert result.stdout == "before-timeout"
|
|
267
|
+
assert result.stderr == "before-timeout-error"
|
|
268
|
+
|
|
269
|
+
deadline = loop.time() + 1
|
|
270
|
+
while True:
|
|
271
|
+
try:
|
|
272
|
+
os.kill(child_pid, 0)
|
|
273
|
+
except ProcessLookupError:
|
|
274
|
+
break
|
|
275
|
+
assert loop.time() < deadline, "SIGTERM-resistant child survived cleanup"
|
|
276
|
+
await asyncio.sleep(0.01)
|
|
277
|
+
finally:
|
|
278
|
+
# A failing regression must not leave a live descendant in the runner.
|
|
279
|
+
if parent_pid is None:
|
|
280
|
+
pid_file = tmp_path / "parent.pid"
|
|
281
|
+
if pid_file.exists() and pid_file.read_text().strip():
|
|
282
|
+
parent_pid = int(pid_file.read_text())
|
|
283
|
+
if parent_pid is not None:
|
|
284
|
+
try:
|
|
285
|
+
os.killpg(parent_pid, signal.SIGKILL)
|
|
286
|
+
except ProcessLookupError:
|
|
287
|
+
pass
|
|
288
|
+
if not task.done():
|
|
289
|
+
task.cancel()
|
|
290
|
+
await asyncio.gather(task, return_exceptions=True)
|
|
291
|
+
await backend.stop_session(session)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
|
2
|
+
RUN apt-get update && apt-get install -y --no-install-recommends docker.io && rm -rf /var/lib/apt/lists/*
|
|
3
|
+
WORKDIR /sdk
|
|
4
|
+
COPY pyproject.toml README.md ./
|
|
5
|
+
COPY src ./src
|
|
6
|
+
COPY tests/e2e/test_box_socket_mounts.py ./tests/e2e/test_box_socket_mounts.py
|
|
7
|
+
RUN uv sync --dev
|
|
8
|
+
CMD ["uv", "run", "--no-sync", "pytest", "-q", "tests/e2e/test_box_socket_mounts.py"]
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Run inside a container with only Docker socket and same-path host_root binds.
|
|
2
|
+
|
|
3
|
+
Set LANGBOT_TEST_BOX_SHARED_ROOT to that shared root to enable this acceptance
|
|
4
|
+
test. The runtime's private /tmp is deliberately not shared with the daemon.
|
|
5
|
+
|
|
6
|
+
Manual acceptance on a disposable Docker host, from the repository root::
|
|
7
|
+
|
|
8
|
+
docker build -f tests/e2e/Dockerfile.box-socket -t langbot-box-socket-test .
|
|
9
|
+
docker pull alpine:3.21
|
|
10
|
+
shared_root=$(mktemp -d)
|
|
11
|
+
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
|
12
|
+
-v "$shared_root:$shared_root" \
|
|
13
|
+
-e LANGBOT_TEST_BOX_SHARED_ROOT="$shared_root" langbot-box-socket-test
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
import tempfile
|
|
22
|
+
|
|
23
|
+
import pytest
|
|
24
|
+
|
|
25
|
+
from langbot_plugin.artifact import build_tree_manifest
|
|
26
|
+
from langbot_plugin.box.backend import DockerBackend
|
|
27
|
+
from langbot_plugin.box.models import ARTIFACT_MOUNT_ROOT, BoxMountSpec, BoxSpec
|
|
28
|
+
from langbot_plugin.box.runtime import BoxRuntime
|
|
29
|
+
|
|
30
|
+
pytestmark = pytest.mark.skipif(
|
|
31
|
+
not os.environ.get("LANGBOT_TEST_BOX_SHARED_ROOT"),
|
|
32
|
+
reason="requires a container with host Docker socket and same-path shared root",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_private_tmp_and_shared_root_with_real_docker():
|
|
37
|
+
assert Path("/.dockerenv").exists(), "Run this test inside the Box container"
|
|
38
|
+
root = Path(os.environ["LANGBOT_TEST_BOX_SHARED_ROOT"])
|
|
39
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
40
|
+
with tempfile.TemporaryDirectory(dir=root, prefix="socket-test-") as shared:
|
|
41
|
+
asyncio.run(_exercise(Path(shared)))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
async def _exercise(shared):
|
|
45
|
+
logger = logging.getLogger(__name__)
|
|
46
|
+
backend = DockerBackend(logger)
|
|
47
|
+
runtime = BoxRuntime(logger, backends=[backend])
|
|
48
|
+
runtime.init(
|
|
49
|
+
{
|
|
50
|
+
"backend": "docker",
|
|
51
|
+
"local": {"host_root": str(shared)},
|
|
52
|
+
"docker": {"cpu_limit_enabled": False},
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
image = os.environ.get("LANGBOT_TEST_BOX_IMAGE", "alpine:3.21")
|
|
56
|
+
empty = BoxSpec(
|
|
57
|
+
session_id="socket-mounts",
|
|
58
|
+
image=image,
|
|
59
|
+
cmd="printf ready",
|
|
60
|
+
network="off",
|
|
61
|
+
host_path=str(shared / "workspace"),
|
|
62
|
+
)
|
|
63
|
+
cache = None
|
|
64
|
+
try:
|
|
65
|
+
# Creating a Box with no packages must still work with a private /tmp.
|
|
66
|
+
result = await runtime.execute(empty)
|
|
67
|
+
assert result.ok and result.stdout == "ready", result.stderr
|
|
68
|
+
session = runtime.get_sessions()[0]
|
|
69
|
+
backend_id = session["backend_session_id"]
|
|
70
|
+
cache = Path(backend._artifact_roots[backend_id])
|
|
71
|
+
assert cache.parent == shared and cache.is_dir()
|
|
72
|
+
inspection = await backend._run_command(
|
|
73
|
+
["docker", "inspect", backend_id], timeout_sec=10, check=True
|
|
74
|
+
)
|
|
75
|
+
container = json.loads(inspection.stdout)[0]
|
|
76
|
+
assert container["HostConfig"]["ReadonlyRootfs"]
|
|
77
|
+
mounts = container["Mounts"]
|
|
78
|
+
workspace_mount = next(m for m in mounts if m["Destination"] == "/workspace")
|
|
79
|
+
assert workspace_mount["Source"] == empty.host_path and workspace_mount["RW"]
|
|
80
|
+
artifact_mount = next(
|
|
81
|
+
m for m in mounts if m["Destination"] == ARTIFACT_MOUNT_ROOT
|
|
82
|
+
)
|
|
83
|
+
assert artifact_mount["Source"] == str(cache) and not artifact_mount["RW"]
|
|
84
|
+
|
|
85
|
+
# Packages prepared in private /tmp are copied into the shared cache;
|
|
86
|
+
# adding one must preserve the already-created sandbox and its state.
|
|
87
|
+
state = await runtime.execute(
|
|
88
|
+
empty.model_copy(update={"cmd": "printf kept >/tmp/state"})
|
|
89
|
+
)
|
|
90
|
+
assert state.ok, state.stderr
|
|
91
|
+
with tempfile.TemporaryDirectory() as private:
|
|
92
|
+
package = Path(private) / "package"
|
|
93
|
+
package.mkdir()
|
|
94
|
+
(package / "value").write_text("package")
|
|
95
|
+
digest, manifest = build_tree_manifest(
|
|
96
|
+
str(package), max_files=10, max_total_bytes=1024
|
|
97
|
+
)
|
|
98
|
+
manifest_path = Path(private) / "manifest.json"
|
|
99
|
+
manifest_path.write_text(json.dumps(manifest))
|
|
100
|
+
mount = BoxMountSpec(
|
|
101
|
+
host_path=str(package),
|
|
102
|
+
mount_path=f"{ARTIFACT_MOUNT_ROOT}/{digest[7:]}",
|
|
103
|
+
mode="ro",
|
|
104
|
+
content_digest=digest,
|
|
105
|
+
manifest_path=str(manifest_path),
|
|
106
|
+
)
|
|
107
|
+
mounted = empty.model_copy(
|
|
108
|
+
update={
|
|
109
|
+
"extra_mounts": [mount],
|
|
110
|
+
"cmd": f"cat {mount.mount_path}/value /tmp/state",
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
result = await runtime.execute(mounted)
|
|
114
|
+
assert result.ok and result.stdout == "packagekept", result.stderr
|
|
115
|
+
assert runtime.get_sessions()[0]["backend_session_id"] == backend_id
|
|
116
|
+
denied = await runtime.execute(
|
|
117
|
+
mounted.model_copy(
|
|
118
|
+
update={"cmd": f"printf changed >{mount.mount_path}/value"}
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
assert not denied.ok
|
|
122
|
+
assert (package / "value").read_text() == "package"
|
|
123
|
+
finally:
|
|
124
|
+
await runtime.shutdown()
|
|
125
|
+
assert cache is not None and not cache.exists()
|