langbot-plugin 0.7.16__tar.gz → 0.7.18__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 → langbot_plugin-0.7.18}/PKG-INFO +1 -1
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/pyproject.toml +1 -1
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/manifest.py +52 -7
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/nsjail_backend.py +2 -2
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/skill_store.py +137 -29
- langbot_plugin-0.7.18/src/langbot_plugin/version.py +1 -0
- langbot_plugin-0.7.18/tests/api/definition/test_manifest_component_path.py +183 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_nsjail_backend.py +18 -6
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_skill_store.py +141 -7
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_skill_store.py +1 -1
- langbot_plugin-0.7.16/src/langbot_plugin/version.py +0 -1
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.github/workflows/box-docker.yml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.github/workflows/cla.yml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.github/workflows/publish-pypi.yaml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.github/workflows/publish.yml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.github/workflows/test.yml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.gitignore +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/.python-version +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/AGENTS.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/ARCHITECTURE.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/CLAUDE.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/CONTRIBUTING.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/LICENSE +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/README.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/README_CN.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/data/.env.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/Message.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/PluginPages.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/agent-runner-interactions.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/agent-runner-pluginization/PROTOCOL_V1.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/agent-runner-pluginization/README.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/agent-runner-pluginization/SDK_RUNTIME_PLAN.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/certified-plugins.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/communication/apis/lb2rt.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/communication/runtime_plugin.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/dependency-management.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/langbot-plugin-social.png +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/runner.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/docs/stateless-components.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/local_e2e/acceptance.json +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/local_e2e/registration_fanin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/local_e2e/run_acceptance.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/mypy.ini +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/scripts/check_action_consistency.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/scripts/runtime_resource_probe.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/asset_gateway.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/daemon.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/decorators.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/external_tools.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/mcp_access.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/mcp_bridge.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/mcp_config.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/mcp_protocol.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/agent_tools/mcp_stdio.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/base.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/runner/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/runner/runner.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/definition/plugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/platform/errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/provider/reasoning.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/box.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/capabilities.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/compat.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/context_access.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/delivery.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/event.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/input.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/interaction.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/manifest.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/page_results.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/permissions.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/resources.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/result.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/run_ledger.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/runtime.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/runtime_registry.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/state.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/stats.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/steering.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/transcript.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/builtin/runner/trigger.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/events.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/entities/execution.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/base.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/event_context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/invocation.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/admin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/api.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/box.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/common.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/ledger.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/platform.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/reply_stream.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/resources.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/state.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/api/proxies/runner/tracing.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/artifact.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/README.md.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/runner/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/runner/{runner_name}.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/runner/{runner_name}.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/main.py.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/readme/README_zh_Hans.md.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/actions.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/backend.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/client.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/e2b_backend.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/host_backend.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/models.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/runtime.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/security.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/server.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/box/tenancy.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/certification.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/__main__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/initplugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/login.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/logout.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/publish.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/gen/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/gen/renderer.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/i18n.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/en_US.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/run/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/run/controller.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/run/handler.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/run/hotreload.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/utils/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/utils/form.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/cli/utils/page_components.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/req.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/io/resp.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/entities/marketplace.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/LICENSE +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/README.md +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/app.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/bounded_executor.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/event_loop_monitor.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/connection.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controller.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/handler.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/ops_metrics.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/artifact.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/container.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/dependency_environment.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/logbuffer.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/mgr.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/restart_coordinator.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/runner_service.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/worker_launcher.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/worker_observability.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/plugin/worker_watchdog.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/security.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/runtime/settings.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/storage.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/deadline.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/discover/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/discover/engine.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/importutil.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/log.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/utils/platform.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/src/langbot_plugin/workspace.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/definition/components/test_components.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/definition/components/test_imports.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/definition/test_manifest.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/runner/test_context_result.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/runner/test_history_event_entities.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/runner/test_interaction.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/runner/test_run_ledger_entities.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/test_command_context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/test_platform_logger.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/test_provider_message.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/builtin/test_rag_models.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/test_context.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/entities/test_events.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_agent_run_api_proxy.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_base.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_box_api.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_history_event_api_proxy.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_langbot_api.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_llm_stream_ownership.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_query_based_api.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/proxies/test_reasoning_parameter.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/test_agent_tools_mcp_bridge.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/test_runner_handlers.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/test_runner_handlers_matrix.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/api/test_runner_public_apis.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_admission.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_artifact_cache_root.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_backend.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_backend_selection.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_client.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_e2b_backend.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_host_backend.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_runtime.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_server.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/box/test_storage_analysis.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/run/test_controller.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/run/test_hotreload.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/run/test_runtime_handler.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_buildplugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_gencomponent.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_i18n_form.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_initplugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_login.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_logout_publish.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_page_components.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_renderer.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_runner_usages.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/cli/test_runplugin.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/e2e/Dockerfile.box-socket +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/e2e/Dockerfile.box-socket.dockerignore +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/e2e/standalone_runtime_eba_probe.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/e2e/test_box_socket_mounts.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/e2e/test_run_mount_isolation.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/entities/io/test_dependency_errors.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/entities/io/test_protocol.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/fixtures/eba_event_probe_plugin/.gitignore +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/fixtures/eba_event_probe_plugin/assets/icon.svg +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/fixtures/eba_event_probe_plugin/components/event_listener/default.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/fixtures/eba_event_probe_plugin/components/event_listener/default.yaml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/fixtures/eba_event_probe_plugin/main.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/fixtures/eba_event_probe_plugin/manifest.yaml +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/helpers/__init__.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/helpers/protocol.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/packaging/test_installed_cli_blackbox.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/packaging/test_release_metadata.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/helper/test_marketplace.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/helper/test_pkgmgr.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/handlers/test_control_handler.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/handlers/test_legacy_file_chunk.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_action_consistency.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_connections.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_controllers.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_handler.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_heartbeat_admission.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_stdio_server.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/io/test_stream_flow_control.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_artifact_store.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_container.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_dependency_environment.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_event_dispatch_real_worker.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_exact_dify_real_worker.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_exact_legacy_sdk_compat.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_installation_manager.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_legacy_shadow.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_manager.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_mgr_runner.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_mode_resource_limits.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_restart_coordinator.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_shared_worker_subprocess.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_worker_launcher.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_worker_plugin_identity.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/plugin/test_workload_isolation.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/test_app.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/test_bounded_executor.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/test_event_loop_monitor.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/test_ops_metrics.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/runtime/test_pull_api_handlers.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_artifact_materialization.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_certification.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_log.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_message.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_plugin_logbuffer.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_storage.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_worker_observability.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/test_worker_watchdog.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/utils/test_deadline.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/utils/test_discovery.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/utils/test_importutil.py +0 -0
- {langbot_plugin-0.7.16 → langbot_plugin-0.7.18}/tests/utils/test_platform.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: langbot-plugin
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.18
|
|
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
|
|
@@ -231,17 +231,62 @@ class ComponentManifest(pydantic.BaseModel):
|
|
|
231
231
|
else None
|
|
232
232
|
)
|
|
233
233
|
|
|
234
|
+
def _resolve_component_module(self) -> tuple[str, str]:
|
|
235
|
+
"""Return the plugin directory to import from and the module path.
|
|
236
|
+
|
|
237
|
+
``execution.python.path`` comes from the plugin's own manifest, so it is
|
|
238
|
+
untrusted input. Only a module inside the plugin directory may be
|
|
239
|
+
imported: absolute paths, drive letters and ``..`` components are
|
|
240
|
+
rejected outright rather than relied on to fail later during import.
|
|
241
|
+
"""
|
|
242
|
+
if self.execution is None:
|
|
243
|
+
raise ValueError("Execution is not set")
|
|
244
|
+
python = self.execution.python
|
|
245
|
+
declared = python.path or ""
|
|
246
|
+
if not declared or "\x00" in declared:
|
|
247
|
+
raise ValueError("execution.python.path is empty")
|
|
248
|
+
|
|
249
|
+
portable = declared.replace("\\", "/")
|
|
250
|
+
if portable.startswith("/") or os.path.isabs(declared):
|
|
251
|
+
raise ValueError(
|
|
252
|
+
f"execution.python.path must be relative to the plugin: {declared}"
|
|
253
|
+
)
|
|
254
|
+
if any(part == ".." for part in portable.split("/")):
|
|
255
|
+
raise ValueError(
|
|
256
|
+
f"execution.python.path escapes the plugin directory: {declared}"
|
|
257
|
+
)
|
|
258
|
+
if len(portable.split("/", 1)[0]) >= 2 and portable.split("/", 1)[0][1] == ":":
|
|
259
|
+
raise ValueError(f"execution.python.path uses a drive letter: {declared}")
|
|
260
|
+
|
|
261
|
+
# Workers run at the plugin root; _rel_dir is the manifest's directory.
|
|
262
|
+
# Keep that directory in the module name so relative imports still work.
|
|
263
|
+
plugin_dir = os.path.abspath(".")
|
|
264
|
+
target = os.path.abspath(os.path.join(plugin_dir, self._rel_dir, portable))
|
|
265
|
+
if os.path.commonpath([plugin_dir, target]) != plugin_dir:
|
|
266
|
+
raise ValueError(
|
|
267
|
+
f"execution.python.path escapes the plugin directory: {declared}"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
if target.endswith(".py"):
|
|
271
|
+
target = target[: -len(".py")]
|
|
272
|
+
relative = os.path.relpath(target, plugin_dir)
|
|
273
|
+
return plugin_dir, relative.replace(os.sep, ".").replace("/", ".")
|
|
274
|
+
|
|
234
275
|
def get_python_component_class(self) -> typing.Type[typing.Any]:
|
|
235
276
|
"""获取Python组件类"""
|
|
236
277
|
if self.execution is None:
|
|
237
278
|
raise ValueError("Execution is not set")
|
|
238
|
-
module_path =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
279
|
+
plugin_dir, module_path = self._resolve_component_module()
|
|
280
|
+
# Insert for the duration of the import only: a permanent append would
|
|
281
|
+
# let one plugin shadow modules for every plugin loaded after it.
|
|
282
|
+
sys.path.insert(0, plugin_dir)
|
|
283
|
+
try:
|
|
284
|
+
module = importlib.import_module(module_path)
|
|
285
|
+
finally:
|
|
286
|
+
try:
|
|
287
|
+
sys.path.remove(plugin_dir)
|
|
288
|
+
except ValueError: # pragma: no cover - defensive
|
|
289
|
+
pass
|
|
245
290
|
return getattr(module, self.execution.python.attr)
|
|
246
291
|
|
|
247
292
|
def to_plain_dict(self) -> dict:
|
|
@@ -780,9 +780,9 @@ class NsjailBackend(BaseSandboxBackend):
|
|
|
780
780
|
try:
|
|
781
781
|
await asyncio.wait_for(process.wait(), timeout=timeout_sec)
|
|
782
782
|
except asyncio.TimeoutError:
|
|
783
|
-
process.kill()
|
|
784
783
|
timed_out = True
|
|
785
|
-
|
|
784
|
+
# Let nsjail reap its children and remove their cgroups before exit.
|
|
785
|
+
await self._terminate_process(process)
|
|
786
786
|
except asyncio.CancelledError:
|
|
787
787
|
await self._terminate_process(process)
|
|
788
788
|
await asyncio.gather(
|
|
@@ -8,6 +8,7 @@ import json
|
|
|
8
8
|
import mimetypes
|
|
9
9
|
import os
|
|
10
10
|
import posixpath
|
|
11
|
+
import re
|
|
11
12
|
import shutil
|
|
12
13
|
import stat
|
|
13
14
|
import tempfile
|
|
@@ -22,16 +23,11 @@ from .artifact import build_tree_manifest
|
|
|
22
23
|
from .workspace import workspace_namespace
|
|
23
24
|
|
|
24
25
|
|
|
25
|
-
_FRONTMATTER_FIELDS = (
|
|
26
|
-
"name",
|
|
27
|
-
"display_name",
|
|
28
|
-
"description",
|
|
29
|
-
)
|
|
30
|
-
|
|
31
26
|
_PUBLIC_SKILL_FIELDS = (
|
|
32
27
|
"name",
|
|
33
28
|
"display_name",
|
|
34
29
|
"description",
|
|
30
|
+
"metadata",
|
|
35
31
|
"instructions",
|
|
36
32
|
"package_root",
|
|
37
33
|
"manifest_path",
|
|
@@ -151,9 +147,21 @@ def parse_frontmatter(content: str) -> tuple[dict, str]:
|
|
|
151
147
|
|
|
152
148
|
|
|
153
149
|
def build_skill_md(metadata: dict, instructions: str) -> str:
|
|
150
|
+
# Preserve complete extensible Agent Skills frontmatter.
|
|
154
151
|
frontmatter = {}
|
|
155
|
-
for key in
|
|
156
|
-
|
|
152
|
+
for key, value in (metadata or {}).items():
|
|
153
|
+
if key in {
|
|
154
|
+
"package_root",
|
|
155
|
+
"manifest_path",
|
|
156
|
+
"entry_file",
|
|
157
|
+
"instructions",
|
|
158
|
+
"revision",
|
|
159
|
+
"created_at",
|
|
160
|
+
"updated_at",
|
|
161
|
+
"source_path",
|
|
162
|
+
"python_project",
|
|
163
|
+
}:
|
|
164
|
+
continue
|
|
157
165
|
if value is None:
|
|
158
166
|
continue
|
|
159
167
|
if isinstance(value, str) and not value.strip():
|
|
@@ -220,9 +228,20 @@ class SkillStore:
|
|
|
220
228
|
skill = self._load_published_skill(skill_name)
|
|
221
229
|
retained_text_bytes += sum(
|
|
222
230
|
len(value.encode("utf-8"))
|
|
223
|
-
for value in skill.
|
|
224
|
-
if isinstance(value, str)
|
|
231
|
+
for key, value in skill.items()
|
|
232
|
+
if key != "metadata" and isinstance(value, str)
|
|
225
233
|
)
|
|
234
|
+
metadata = skill.get("metadata")
|
|
235
|
+
if metadata is not None:
|
|
236
|
+
retained_text_bytes += len(
|
|
237
|
+
json.dumps(
|
|
238
|
+
metadata,
|
|
239
|
+
ensure_ascii=False,
|
|
240
|
+
sort_keys=True,
|
|
241
|
+
default=str,
|
|
242
|
+
separators=(",", ":"),
|
|
243
|
+
).encode("utf-8")
|
|
244
|
+
)
|
|
226
245
|
if retained_text_bytes > _MAX_SKILL_LIST_TOTAL_TEXT_BYTES:
|
|
227
246
|
raise ValueError("Skill listing exceeds the configured text limit")
|
|
228
247
|
skills.append(skill)
|
|
@@ -352,7 +371,9 @@ class SkillStore:
|
|
|
352
371
|
)
|
|
353
372
|
|
|
354
373
|
package_root, entry_file = discovered[0]
|
|
355
|
-
|
|
374
|
+
skill = self._load_skill_package(package_root, entry_file)
|
|
375
|
+
self._validate_agent_skill_package(package_root, skill.get("metadata") or {})
|
|
376
|
+
return skill
|
|
356
377
|
|
|
357
378
|
def scan_import_directory(self, path: str, *, source_root: str) -> dict:
|
|
358
379
|
"""Scan a trusted import source without granting arbitrary host access."""
|
|
@@ -611,12 +632,16 @@ class SkillStore:
|
|
|
611
632
|
|
|
612
633
|
tmp_dir = tempfile.mkdtemp(prefix="langbot_skill_preview_")
|
|
613
634
|
try:
|
|
614
|
-
skill_root = self._extract_uploaded_skill_to_temp(
|
|
635
|
+
skill_root, allow_root_package = self._extract_uploaded_skill_to_temp(
|
|
636
|
+
file_bytes, tmp_dir
|
|
637
|
+
)
|
|
615
638
|
skill_root = self._resolve_source_subdir_root(skill_root, source_subdir)
|
|
639
|
+
allow_root_package = allow_root_package and not source_subdir.strip()
|
|
616
640
|
return self._preview_skill_candidates(
|
|
617
641
|
skill_root,
|
|
618
642
|
base_target_name=self._uploaded_skill_target_stem(filename),
|
|
619
643
|
suffix=target_suffix,
|
|
644
|
+
allow_root_package=allow_root_package,
|
|
620
645
|
)
|
|
621
646
|
finally:
|
|
622
647
|
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
@@ -637,18 +662,24 @@ class SkillStore:
|
|
|
637
662
|
|
|
638
663
|
tmp_dir = tempfile.mkdtemp(prefix="langbot_skill_upload_")
|
|
639
664
|
try:
|
|
640
|
-
skill_root = self._extract_uploaded_skill_to_temp(
|
|
665
|
+
skill_root, allow_root_package = self._extract_uploaded_skill_to_temp(
|
|
666
|
+
file_bytes, tmp_dir
|
|
667
|
+
)
|
|
641
668
|
skill_root = self._resolve_source_subdir_root(skill_root, source_subdir)
|
|
669
|
+
allow_root_package = allow_root_package and not source_subdir.strip()
|
|
642
670
|
previews = self._preview_skill_candidates(
|
|
643
671
|
skill_root,
|
|
644
672
|
base_target_name=self._uploaded_skill_target_stem(filename),
|
|
645
673
|
suffix=target_suffix,
|
|
674
|
+
allow_root_package=allow_root_package,
|
|
646
675
|
)
|
|
647
676
|
selected_previews = self._select_preview_candidates(
|
|
648
677
|
previews,
|
|
649
678
|
{"source_paths": source_paths or [], "source_path": source_path},
|
|
650
679
|
)
|
|
651
|
-
scanned = self._install_preview_candidates(
|
|
680
|
+
scanned = self._install_preview_candidates(
|
|
681
|
+
skill_root, selected_previews, allow_root_package=allow_root_package
|
|
682
|
+
)
|
|
652
683
|
return scanned
|
|
653
684
|
finally:
|
|
654
685
|
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
@@ -881,15 +912,31 @@ class SkillStore:
|
|
|
881
912
|
imported = self._read_skill_package(source_root) if source_root else None
|
|
882
913
|
staging_root, package_root = self._stage_package(source_root or None)
|
|
883
914
|
try:
|
|
884
|
-
metadata = {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
915
|
+
metadata = dict((imported or {}).get("metadata") or {})
|
|
916
|
+
metadata.update(
|
|
917
|
+
{
|
|
918
|
+
"name": skill_name,
|
|
919
|
+
"display_name": self._resolve_create_field(
|
|
920
|
+
data, "display_name", imported, default=""
|
|
921
|
+
),
|
|
922
|
+
"description": self._resolve_create_field(
|
|
923
|
+
data, "description", imported, default=""
|
|
924
|
+
),
|
|
925
|
+
}
|
|
926
|
+
)
|
|
927
|
+
for key, value in data.items():
|
|
928
|
+
if (
|
|
929
|
+
key
|
|
930
|
+
not in {
|
|
931
|
+
"name",
|
|
932
|
+
"display_name",
|
|
933
|
+
"description",
|
|
934
|
+
"instructions",
|
|
935
|
+
"package_root",
|
|
936
|
+
}
|
|
937
|
+
and value is not None
|
|
938
|
+
):
|
|
939
|
+
metadata[key] = value
|
|
893
940
|
instructions = self._resolve_create_field(
|
|
894
941
|
data, "instructions", imported, default=""
|
|
895
942
|
)
|
|
@@ -1137,6 +1184,7 @@ class SkillStore:
|
|
|
1137
1184
|
"name": skill_name,
|
|
1138
1185
|
"display_name": str(metadata.get("display_name") or skill_name).strip(),
|
|
1139
1186
|
"description": str(metadata.get("description") or "").strip(),
|
|
1187
|
+
"metadata": dict(metadata),
|
|
1140
1188
|
"instructions": instructions,
|
|
1141
1189
|
"package_root": package_root,
|
|
1142
1190
|
"entry_file": entry_file,
|
|
@@ -1168,6 +1216,7 @@ class SkillStore:
|
|
|
1168
1216
|
"entry_file": skill.get("entry_file", "SKILL.md"),
|
|
1169
1217
|
"display_name": skill.get("display_name", ""),
|
|
1170
1218
|
"description": skill.get("description", ""),
|
|
1219
|
+
"metadata": dict(skill.get("metadata") or {}),
|
|
1171
1220
|
"instructions": skill.get("instructions", ""),
|
|
1172
1221
|
}
|
|
1173
1222
|
|
|
@@ -1193,7 +1242,12 @@ class SkillStore:
|
|
|
1193
1242
|
return os.path.join(self.root, target_name)
|
|
1194
1243
|
|
|
1195
1244
|
def _preview_skill_candidates(
|
|
1196
|
-
self,
|
|
1245
|
+
self,
|
|
1246
|
+
root_path: str,
|
|
1247
|
+
*,
|
|
1248
|
+
base_target_name: str,
|
|
1249
|
+
suffix: str,
|
|
1250
|
+
allow_root_package: bool = False,
|
|
1197
1251
|
) -> list[dict]:
|
|
1198
1252
|
discovered = self._discover_skill_directories(root_path, max_depth=2)
|
|
1199
1253
|
if not discovered:
|
|
@@ -1205,6 +1259,12 @@ class SkillStore:
|
|
|
1205
1259
|
for package_root, entry_file in discovered:
|
|
1206
1260
|
skill = self._load_skill_package(package_root, entry_file)
|
|
1207
1261
|
relative_path = os.path.relpath(package_root, root_path)
|
|
1262
|
+
is_archive_root_skill = allow_root_package and relative_path in ("", ".")
|
|
1263
|
+
self._validate_agent_skill_package(
|
|
1264
|
+
package_root,
|
|
1265
|
+
skill.get("metadata") or {},
|
|
1266
|
+
require_directory_name=not is_archive_root_skill,
|
|
1267
|
+
)
|
|
1208
1268
|
if relative_path in ("", "."):
|
|
1209
1269
|
relative_path = ""
|
|
1210
1270
|
skill["source_path"] = relative_path.replace(os.sep, "/")
|
|
@@ -1216,6 +1276,37 @@ class SkillStore:
|
|
|
1216
1276
|
previews.sort(key=lambda item: item["source_path"])
|
|
1217
1277
|
return [self._serialize_skill_with_source(preview) for preview in previews]
|
|
1218
1278
|
|
|
1279
|
+
@staticmethod
|
|
1280
|
+
def _validate_agent_skill_package(
|
|
1281
|
+
package_root: str, metadata: dict, *, require_directory_name: bool = True
|
|
1282
|
+
) -> None:
|
|
1283
|
+
name = metadata.get("name")
|
|
1284
|
+
if not isinstance(name, str) or not name.strip():
|
|
1285
|
+
raise ValueError(
|
|
1286
|
+
f"Skill package {package_root} must declare a frontmatter name"
|
|
1287
|
+
)
|
|
1288
|
+
name = name.strip()
|
|
1289
|
+
if not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", name):
|
|
1290
|
+
raise ValueError(
|
|
1291
|
+
"Skill name must use lowercase letters, numbers, and hyphens"
|
|
1292
|
+
)
|
|
1293
|
+
if len(name) > 64:
|
|
1294
|
+
raise ValueError("Skill name cannot exceed 64 characters")
|
|
1295
|
+
directory_name = os.path.basename(os.path.normpath(package_root))
|
|
1296
|
+
if require_directory_name and name != directory_name:
|
|
1297
|
+
raise ValueError(
|
|
1298
|
+
f'Skill frontmatter name "{name}" must match directory "{directory_name}"'
|
|
1299
|
+
)
|
|
1300
|
+
description = metadata.get("description")
|
|
1301
|
+
if not isinstance(description, str) or not description.strip():
|
|
1302
|
+
raise ValueError(
|
|
1303
|
+
f'Skill "{name}" must declare a non-empty frontmatter description'
|
|
1304
|
+
)
|
|
1305
|
+
if len(description) > 1024:
|
|
1306
|
+
raise ValueError(
|
|
1307
|
+
f'Skill "{name}" description cannot exceed 1024 characters'
|
|
1308
|
+
)
|
|
1309
|
+
|
|
1219
1310
|
@staticmethod
|
|
1220
1311
|
def _serialize_skill_with_source(skill: dict) -> dict:
|
|
1221
1312
|
data = SkillStore._serialize_skill(skill)
|
|
@@ -1265,7 +1356,11 @@ class SkillStore:
|
|
|
1265
1356
|
return selected
|
|
1266
1357
|
|
|
1267
1358
|
def _install_preview_candidates(
|
|
1268
|
-
self,
|
|
1359
|
+
self,
|
|
1360
|
+
root_path: str,
|
|
1361
|
+
selected_previews: list[dict],
|
|
1362
|
+
*,
|
|
1363
|
+
allow_root_package: bool = False,
|
|
1269
1364
|
) -> list[dict]:
|
|
1270
1365
|
installed: list[dict] = []
|
|
1271
1366
|
try:
|
|
@@ -1273,7 +1368,18 @@ class SkillStore:
|
|
|
1273
1368
|
source_root = self._preview_source_root(
|
|
1274
1369
|
root_path, preview["source_path"]
|
|
1275
1370
|
)
|
|
1276
|
-
|
|
1371
|
+
if preview["source_path"] or not allow_root_package:
|
|
1372
|
+
scanned = SkillStore(self.root).scan_directory(source_root)
|
|
1373
|
+
else:
|
|
1374
|
+
entry = self._find_skill_entry(source_root)
|
|
1375
|
+
if entry is None:
|
|
1376
|
+
raise ValueError(f"No SKILL.md found in {source_root}")
|
|
1377
|
+
scanned = self._load_skill_package(entry[0], entry[1])
|
|
1378
|
+
self._validate_agent_skill_package(
|
|
1379
|
+
source_root,
|
|
1380
|
+
scanned.get("metadata") or {},
|
|
1381
|
+
require_directory_name=False,
|
|
1382
|
+
)
|
|
1277
1383
|
skill_name = self._validate_skill_name(scanned["name"])
|
|
1278
1384
|
self._ensure_legacy_packages_published()
|
|
1279
1385
|
with self._skill_lock(skill_name):
|
|
@@ -1303,7 +1409,9 @@ class SkillStore:
|
|
|
1303
1409
|
|
|
1304
1410
|
return installed
|
|
1305
1411
|
|
|
1306
|
-
def _extract_uploaded_skill_to_temp(
|
|
1412
|
+
def _extract_uploaded_skill_to_temp(
|
|
1413
|
+
self, file_bytes: bytes, tmp_dir: str
|
|
1414
|
+
) -> tuple[str, bool]:
|
|
1307
1415
|
extract_dir = os.path.join(tmp_dir, "extracted")
|
|
1308
1416
|
try:
|
|
1309
1417
|
with zipfile.ZipFile(io.BytesIO(file_bytes), "r") as zf:
|
|
@@ -1313,8 +1421,8 @@ class SkillStore:
|
|
|
1313
1421
|
|
|
1314
1422
|
entries = os.listdir(extract_dir)
|
|
1315
1423
|
if len(entries) == 1 and os.path.isdir(os.path.join(extract_dir, entries[0])):
|
|
1316
|
-
return os.path.join(extract_dir, entries[0])
|
|
1317
|
-
return extract_dir
|
|
1424
|
+
return os.path.join(extract_dir, entries[0]), False
|
|
1425
|
+
return extract_dir, True
|
|
1318
1426
|
|
|
1319
1427
|
@staticmethod
|
|
1320
1428
|
def _validate_zip_upload_size(file_bytes: bytes) -> None:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.18"
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Component module resolution must stay inside the plugin directory.
|
|
2
|
+
|
|
3
|
+
``execution.python.path`` is plugin-authored manifest data, so it is untrusted.
|
|
4
|
+
These tests pin the resolver to the plugin directory and check that importing a
|
|
5
|
+
component no longer leaves the plugin directory on ``sys.path``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import textwrap
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from langbot_plugin.api.definition.components.manifest import ComponentManifest
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.fixture(autouse=True)
|
|
17
|
+
def _clean_component_modules(tmp_path, monkeypatch):
|
|
18
|
+
"""Drop cached component modules so each test resolves its own plugin dir."""
|
|
19
|
+
monkeypatch.chdir(tmp_path)
|
|
20
|
+
before = {
|
|
21
|
+
name
|
|
22
|
+
for name in sys.modules
|
|
23
|
+
if name == "components" or name.startswith("components.")
|
|
24
|
+
}
|
|
25
|
+
for name in before:
|
|
26
|
+
sys.modules.pop(name, None)
|
|
27
|
+
yield
|
|
28
|
+
for name in [
|
|
29
|
+
n for n in sys.modules if n == "components" or n.startswith("components.")
|
|
30
|
+
]:
|
|
31
|
+
sys.modules.pop(name, None)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _manifest(rel_path: str, python_path: str, attr: str = "Component"):
|
|
35
|
+
return ComponentManifest(
|
|
36
|
+
owner="plugin",
|
|
37
|
+
manifest={
|
|
38
|
+
"apiVersion": "v1",
|
|
39
|
+
"kind": "Command",
|
|
40
|
+
"metadata": {
|
|
41
|
+
"name": "probe",
|
|
42
|
+
"label": {"en_US": "probe"},
|
|
43
|
+
"description": {"en_US": "probe"},
|
|
44
|
+
},
|
|
45
|
+
"spec": {},
|
|
46
|
+
"execution": {"python": {"path": python_path, "attr": attr}},
|
|
47
|
+
},
|
|
48
|
+
rel_path=rel_path,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _plugin(tmp_path, files: dict[str, str]):
|
|
53
|
+
for name, content in files.items():
|
|
54
|
+
target = tmp_path / name
|
|
55
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
56
|
+
target.write_text(textwrap.dedent(content))
|
|
57
|
+
return tmp_path
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@pytest.mark.parametrize(
|
|
61
|
+
"declared",
|
|
62
|
+
[
|
|
63
|
+
"../outside.py",
|
|
64
|
+
"../../etc/evil.py",
|
|
65
|
+
"components/../../outside.py",
|
|
66
|
+
"/etc/passwd.py",
|
|
67
|
+
"C:/windows/evil.py",
|
|
68
|
+
"c:evil.py",
|
|
69
|
+
"",
|
|
70
|
+
],
|
|
71
|
+
)
|
|
72
|
+
def test_paths_outside_the_plugin_are_rejected(tmp_path, declared):
|
|
73
|
+
plugin = _plugin(tmp_path, {"manifest.yaml": ""})
|
|
74
|
+
manifest = _manifest(str(plugin / "manifest.yaml"), declared)
|
|
75
|
+
with pytest.raises(ValueError):
|
|
76
|
+
manifest.get_python_component_class()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_component_inside_the_plugin_is_imported(tmp_path, monkeypatch):
|
|
80
|
+
plugin = _plugin(
|
|
81
|
+
tmp_path,
|
|
82
|
+
{
|
|
83
|
+
"components/__init__.py": "",
|
|
84
|
+
"components/inside_once.py": """
|
|
85
|
+
class Component:
|
|
86
|
+
marker = "INSIDE"
|
|
87
|
+
""",
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
manifest = _manifest(str(plugin / "manifest.yaml"), "components/inside_once.py")
|
|
91
|
+
|
|
92
|
+
component = manifest.get_python_component_class()
|
|
93
|
+
|
|
94
|
+
assert component.marker == "INSIDE"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_import_does_not_leave_the_plugin_dir_on_sys_path(tmp_path, monkeypatch):
|
|
98
|
+
"""A leaked path would let one plugin shadow modules for later plugins."""
|
|
99
|
+
plugin = _plugin(
|
|
100
|
+
tmp_path,
|
|
101
|
+
{
|
|
102
|
+
"components/__init__.py": "",
|
|
103
|
+
"components/leak_check.py": """
|
|
104
|
+
class Component:
|
|
105
|
+
marker = "INSIDE"
|
|
106
|
+
""",
|
|
107
|
+
},
|
|
108
|
+
)
|
|
109
|
+
manifest = _manifest(str(plugin / "manifest.yaml"), "components/leak_check.py")
|
|
110
|
+
before = list(sys.path)
|
|
111
|
+
|
|
112
|
+
manifest.get_python_component_class()
|
|
113
|
+
|
|
114
|
+
assert str(plugin) not in sys.path
|
|
115
|
+
assert len(sys.path) == len(before)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_relative_path_without_py_suffix_works(tmp_path, monkeypatch):
|
|
119
|
+
plugin = _plugin(
|
|
120
|
+
tmp_path,
|
|
121
|
+
{
|
|
122
|
+
"components/__init__.py": "",
|
|
123
|
+
"components/no_suffix_mod.py": """
|
|
124
|
+
class Component:
|
|
125
|
+
marker = "NO_SUFFIX"
|
|
126
|
+
""",
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
manifest = _manifest(str(plugin / "manifest.yaml"), "components/no_suffix_mod")
|
|
130
|
+
|
|
131
|
+
assert manifest.get_python_component_class().marker == "NO_SUFFIX"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_importing_a_missing_component_leaves_sys_path_clean(tmp_path, monkeypatch):
|
|
135
|
+
plugin = _plugin(tmp_path, {"manifest.yaml": ""})
|
|
136
|
+
manifest = _manifest(str(plugin / "manifest.yaml"), "components/missing.py")
|
|
137
|
+
before = list(sys.path)
|
|
138
|
+
|
|
139
|
+
with pytest.raises(ModuleNotFoundError):
|
|
140
|
+
manifest.get_python_component_class()
|
|
141
|
+
|
|
142
|
+
assert str(plugin) not in sys.path
|
|
143
|
+
assert len(sys.path) == len(before)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@pytest.mark.parametrize("packages", [True, False])
|
|
147
|
+
def test_nested_component_preserves_package_and_relative_imports(tmp_path, packages):
|
|
148
|
+
files = {
|
|
149
|
+
"components/knowledge_engine/parser.py": 'VALUE = "parsed"',
|
|
150
|
+
"components/knowledge_engine/engine.py": """
|
|
151
|
+
from .parser import VALUE
|
|
152
|
+
|
|
153
|
+
class Component:
|
|
154
|
+
marker = VALUE
|
|
155
|
+
|
|
156
|
+
def lazy_import(self):
|
|
157
|
+
from .parser import VALUE
|
|
158
|
+
return VALUE
|
|
159
|
+
""",
|
|
160
|
+
}
|
|
161
|
+
if packages:
|
|
162
|
+
files.update(
|
|
163
|
+
{
|
|
164
|
+
"components/__init__.py": "",
|
|
165
|
+
"components/knowledge_engine/__init__.py": "",
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
_plugin(tmp_path, files)
|
|
169
|
+
manifest = _manifest("components/knowledge_engine/engine.yaml", "engine.py")
|
|
170
|
+
before = list(sys.path)
|
|
171
|
+
|
|
172
|
+
component = manifest.get_python_component_class()
|
|
173
|
+
|
|
174
|
+
assert component.__module__ == "components.knowledge_engine.engine"
|
|
175
|
+
assert component.marker == "parsed"
|
|
176
|
+
assert component().lazy_import() == "parsed"
|
|
177
|
+
assert sys.path == before
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def test_manifest_outside_plugin_root_is_rejected(tmp_path):
|
|
181
|
+
manifest = _manifest(str(tmp_path.parent / "outside.yaml"), "outside.py")
|
|
182
|
+
with pytest.raises(ValueError, match="escapes the plugin directory"):
|
|
183
|
+
manifest.get_python_component_class()
|
|
@@ -573,9 +573,11 @@ async def test_exec_timeout(backend, tmp_base):
|
|
|
573
573
|
|
|
574
574
|
|
|
575
575
|
@pytest.mark.anyio
|
|
576
|
-
|
|
576
|
+
@pytest.mark.parametrize("stop_reason", ["timeout", "cancel"])
|
|
577
|
+
async def test_run_nsjail_termination_allows_cleanup(
|
|
577
578
|
backend,
|
|
578
579
|
monkeypatch,
|
|
580
|
+
stop_reason,
|
|
579
581
|
):
|
|
580
582
|
class EmptyStream:
|
|
581
583
|
async def read(self, _size):
|
|
@@ -589,6 +591,7 @@ async def test_run_nsjail_cancellation_terminates_and_reaps_process(
|
|
|
589
591
|
self.wait_started = asyncio.Event()
|
|
590
592
|
self.exit_requested = asyncio.Event()
|
|
591
593
|
self.terminated = False
|
|
594
|
+
self.killed = False
|
|
592
595
|
|
|
593
596
|
async def wait(self):
|
|
594
597
|
self.wait_started.set()
|
|
@@ -601,6 +604,7 @@ async def test_run_nsjail_cancellation_terminates_and_reaps_process(
|
|
|
601
604
|
self.exit_requested.set()
|
|
602
605
|
|
|
603
606
|
def kill(self):
|
|
607
|
+
self.killed = True
|
|
604
608
|
self.exit_requested.set()
|
|
605
609
|
|
|
606
610
|
process = HangingProcess()
|
|
@@ -614,14 +618,22 @@ async def test_run_nsjail_cancellation_terminates_and_reaps_process(
|
|
|
614
618
|
create_subprocess_exec,
|
|
615
619
|
)
|
|
616
620
|
task = asyncio.create_task(
|
|
617
|
-
backend._run_nsjail(
|
|
621
|
+
backend._run_nsjail(
|
|
622
|
+
["nsjail", "--help"],
|
|
623
|
+
timeout_sec=0.01 if stop_reason == "timeout" else 60,
|
|
624
|
+
)
|
|
618
625
|
)
|
|
619
626
|
await process.wait_started.wait()
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
627
|
+
if stop_reason == "cancel":
|
|
628
|
+
task.cancel()
|
|
629
|
+
with pytest.raises(asyncio.CancelledError):
|
|
630
|
+
await task
|
|
631
|
+
else:
|
|
632
|
+
result = await task
|
|
633
|
+
assert result.timed_out is True
|
|
634
|
+
assert result.return_code == -1
|
|
624
635
|
assert process.terminated is True
|
|
636
|
+
assert process.killed is False
|
|
625
637
|
assert process.returncode == -15
|
|
626
638
|
|
|
627
639
|
|