langbot-plugin 0.6.1b2__tar.gz → 0.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/ARCHITECTURE.md +29 -7
  2. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/PKG-INFO +1 -1
  3. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/pyproject.toml +1 -1
  4. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/run/controller.py +104 -17
  5. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/run/handler.py +65 -1
  6. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/actions/enums.py +3 -0
  7. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/context.py +10 -0
  8. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/handler.py +86 -17
  9. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/handlers/control.py +7 -2
  10. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/handlers/plugin.py +94 -17
  11. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/artifact.py +22 -0
  12. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/mgr.py +600 -7
  13. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/worker_launcher.py +45 -0
  14. langbot_plugin-0.6.2/src/langbot_plugin/version.py +1 -0
  15. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/run/test_controller.py +180 -0
  16. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/entities/io/test_protocol.py +19 -0
  17. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/packaging/test_release_metadata.py +3 -3
  18. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/handlers/test_legacy_file_chunk.py +17 -4
  19. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/handlers/test_plugin_handler.py +45 -6
  20. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/test_handler.py +122 -0
  21. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_installation_manager.py +1058 -0
  22. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_manager.py +59 -1
  23. langbot_plugin-0.6.2/tests/runtime/plugin/test_shared_worker_subprocess.py +320 -0
  24. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_worker_launcher.py +36 -0
  25. langbot_plugin-0.6.1b2/src/langbot_plugin/version.py +0 -1
  26. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/.github/workflows/cla.yml +0 -0
  27. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/.github/workflows/publish-pypi.yaml +0 -0
  28. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/.github/workflows/publish.yml +0 -0
  29. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/.github/workflows/test.yml +0 -0
  30. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/.gitignore +0 -0
  31. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/.python-version +0 -0
  32. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/AGENTS.md +0 -0
  33. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/CLAUDE.md +0 -0
  34. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/CONTRIBUTING.md +0 -0
  35. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/LICENSE +0 -0
  36. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/README.md +0 -0
  37. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/README_CN.md +0 -0
  38. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/data/.env.example +0 -0
  39. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/Message.md +0 -0
  40. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/PluginPages.md +0 -0
  41. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/agent-runner-interactions.md +0 -0
  42. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/agent-runner-pluginization/PROTOCOL_V1.md +0 -0
  43. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/agent-runner-pluginization/README.md +0 -0
  44. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/agent-runner-pluginization/SDK_RUNTIME_PLAN.md +0 -0
  45. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/certified-plugins.md +0 -0
  46. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/communication/apis/lb2rt.md +0 -0
  47. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/communication/runtime_plugin.md +0 -0
  48. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/dependency-management.md +0 -0
  49. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/langbot-plugin-social.png +0 -0
  50. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/docs/runner.md +0 -0
  51. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/mypy.ini +0 -0
  52. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/scripts/check_action_consistency.py +0 -0
  53. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/scripts/runtime_resource_probe.py +0 -0
  54. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/__init__.py +0 -0
  55. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/__init__.py +0 -0
  56. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/__init__.py +0 -0
  57. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/asset_gateway.py +0 -0
  58. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/daemon.py +0 -0
  59. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/decorators.py +0 -0
  60. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/external_tools.py +0 -0
  61. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/mcp_access.py +0 -0
  62. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/mcp_bridge.py +0 -0
  63. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/mcp_config.py +0 -0
  64. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/mcp_protocol.py +0 -0
  65. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/agent_tools/mcp_stdio.py +0 -0
  66. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/__init__.py +0 -0
  67. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
  68. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
  69. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
  70. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
  71. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
  72. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/base.py +0 -0
  73. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
  74. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
  75. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
  76. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
  77. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
  78. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
  79. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
  80. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
  81. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
  82. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
  83. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/runner/__init__.py +0 -0
  84. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/runner/runner.py +0 -0
  85. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
  86. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
  87. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/definition/plugin.py +0 -0
  88. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/__init__.py +0 -0
  89. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
  90. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
  91. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
  92. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
  93. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
  94. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
  95. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
  96. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
  97. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/platform/errors.py +0 -0
  98. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
  99. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
  100. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
  101. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
  102. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
  103. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
  104. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/provider/reasoning.py +0 -0
  105. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
  106. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
  107. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
  108. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
  109. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
  110. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
  111. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
  112. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
  113. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/__init__.py +0 -0
  114. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/box.py +0 -0
  115. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/capabilities.py +0 -0
  116. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/compat.py +0 -0
  117. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/context.py +0 -0
  118. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/context_access.py +0 -0
  119. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/delivery.py +0 -0
  120. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/errors.py +0 -0
  121. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/event.py +0 -0
  122. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/input.py +0 -0
  123. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/interaction.py +0 -0
  124. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/manifest.py +0 -0
  125. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/page_results.py +0 -0
  126. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/permissions.py +0 -0
  127. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/resources.py +0 -0
  128. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/result.py +0 -0
  129. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/run_ledger.py +0 -0
  130. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/runtime.py +0 -0
  131. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/runtime_registry.py +0 -0
  132. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/state.py +0 -0
  133. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/stats.py +0 -0
  134. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/steering.py +0 -0
  135. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/transcript.py +0 -0
  136. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/builtin/runner/trigger.py +0 -0
  137. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/context.py +0 -0
  138. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/events.py +0 -0
  139. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/entities/execution.py +0 -0
  140. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/__init__.py +0 -0
  141. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/base.py +0 -0
  142. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/event_context.py +0 -0
  143. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
  144. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/invocation.py +0 -0
  145. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
  146. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
  147. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/__init__.py +0 -0
  148. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/admin.py +0 -0
  149. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/api.py +0 -0
  150. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/box.py +0 -0
  151. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/common.py +0 -0
  152. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/context.py +0 -0
  153. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/ledger.py +0 -0
  154. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/platform.py +0 -0
  155. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/reply_stream.py +0 -0
  156. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/resources.py +0 -0
  157. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/state.py +0 -0
  158. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/api/proxies/runner/tracing.py +0 -0
  159. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/__init__.py +0 -0
  160. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
  161. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
  162. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example +0 -0
  163. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
  164. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
  165. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/README.md.example +0 -0
  166. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/__init__.py +0 -0
  167. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
  168. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
  169. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
  170. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
  171. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
  172. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
  173. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
  174. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
  175. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
  176. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
  177. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
  178. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
  179. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
  180. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
  181. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
  182. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
  183. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/runner/__init__.py +0 -0
  184. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/runner/{runner_name}.py.example +0 -0
  185. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/runner/{runner_name}.yaml.example +0 -0
  186. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
  187. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
  188. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
  189. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/main.py.example +0 -0
  190. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
  191. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/readme/README_zh_Hans.md.example +0 -0
  192. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
  193. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/__init__.py +0 -0
  194. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/actions.py +0 -0
  195. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/backend.py +0 -0
  196. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/client.py +0 -0
  197. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/e2b_backend.py +0 -0
  198. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/errors.py +0 -0
  199. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/host_backend.py +0 -0
  200. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/models.py +0 -0
  201. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/nsjail_backend.py +0 -0
  202. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/runtime.py +0 -0
  203. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/security.py +0 -0
  204. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/server.py +0 -0
  205. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/skill_store.py +0 -0
  206. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/box/tenancy.py +0 -0
  207. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/certification.py +0 -0
  208. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/__init__.py +0 -0
  209. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/__main__.py +0 -0
  210. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/__init__.py +0 -0
  211. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
  212. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
  213. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/initplugin.py +0 -0
  214. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/login.py +0 -0
  215. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/logout.py +0 -0
  216. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/publish.py +0 -0
  217. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
  218. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/gen/__init__.py +0 -0
  219. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/gen/renderer.py +0 -0
  220. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/i18n.py +0 -0
  221. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/__init__.py +0 -0
  222. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/en_US.py +0 -0
  223. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
  224. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
  225. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
  226. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
  227. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
  228. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
  229. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/run/__init__.py +0 -0
  230. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/run/hotreload.py +0 -0
  231. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/utils/__init__.py +0 -0
  232. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
  233. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/utils/form.py +0 -0
  234. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/cli/utils/page_components.py +0 -0
  235. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/__init__.py +0 -0
  236. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/__init__.py +0 -0
  237. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
  238. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/errors.py +0 -0
  239. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/req.py +0 -0
  240. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/io/resp.py +0 -0
  241. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/entities/marketplace.py +0 -0
  242. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/LICENSE +0 -0
  243. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/README.md +0 -0
  244. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/__init__.py +0 -0
  245. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/app.py +0 -0
  246. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/bounded_executor.py +0 -0
  247. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/context.py +0 -0
  248. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/event_loop_monitor.py +0 -0
  249. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
  250. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
  251. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -0
  252. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/__init__.py +0 -0
  253. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/connection.py +0 -0
  254. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
  255. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
  256. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
  257. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controller.py +0 -0
  258. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
  259. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
  260. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
  261. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
  262. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
  263. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
  264. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
  265. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
  266. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
  267. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/container.py +0 -0
  268. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/dependency_environment.py +0 -0
  269. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/logbuffer.py +0 -0
  270. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/restart_coordinator.py +0 -0
  271. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/plugin/runner_service.py +0 -0
  272. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/security.py +0 -0
  273. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/runtime/settings.py +0 -0
  274. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/storage.py +0 -0
  275. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/__init__.py +0 -0
  276. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/deadline.py +0 -0
  277. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/discover/__init__.py +0 -0
  278. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/discover/engine.py +0 -0
  279. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/importutil.py +0 -0
  280. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/log.py +0 -0
  281. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/src/langbot_plugin/utils/platform.py +0 -0
  282. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/__init__.py +0 -0
  283. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/definition/components/test_components.py +0 -0
  284. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/definition/components/test_imports.py +0 -0
  285. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/definition/test_manifest.py +0 -0
  286. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/runner/test_context_result.py +0 -0
  287. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/runner/test_history_event_entities.py +0 -0
  288. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/runner/test_interaction.py +0 -0
  289. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/runner/test_run_ledger_entities.py +0 -0
  290. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/test_command_context.py +0 -0
  291. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/test_platform_logger.py +0 -0
  292. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/test_provider_message.py +0 -0
  293. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/builtin/test_rag_models.py +0 -0
  294. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/test_context.py +0 -0
  295. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/entities/test_events.py +0 -0
  296. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/__init__.py +0 -0
  297. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_agent_run_api_proxy.py +0 -0
  298. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_base.py +0 -0
  299. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_box_api.py +0 -0
  300. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_history_event_api_proxy.py +0 -0
  301. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_langbot_api.py +0 -0
  302. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_query_based_api.py +0 -0
  303. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/proxies/test_reasoning_parameter.py +0 -0
  304. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/test_agent_tools_mcp_bridge.py +0 -0
  305. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/test_runner_handlers.py +0 -0
  306. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/test_runner_handlers_matrix.py +0 -0
  307. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/api/test_runner_public_apis.py +0 -0
  308. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/__init__.py +0 -0
  309. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_admission.py +0 -0
  310. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_backend.py +0 -0
  311. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_backend_selection.py +0 -0
  312. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_client.py +0 -0
  313. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_e2b_backend.py +0 -0
  314. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_host_backend.py +0 -0
  315. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_nsjail_backend.py +0 -0
  316. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_runtime.py +0 -0
  317. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_server.py +0 -0
  318. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_skill_store.py +0 -0
  319. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/box/test_storage_analysis.py +0 -0
  320. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/run/test_hotreload.py +0 -0
  321. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/run/test_runtime_handler.py +0 -0
  322. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_buildplugin.py +0 -0
  323. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_gencomponent.py +0 -0
  324. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_i18n_form.py +0 -0
  325. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_initplugin.py +0 -0
  326. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_login.py +0 -0
  327. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_logout_publish.py +0 -0
  328. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_page_components.py +0 -0
  329. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_renderer.py +0 -0
  330. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_runner_usages.py +0 -0
  331. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/cli/test_runplugin.py +0 -0
  332. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/e2e/standalone_runtime_eba_probe.py +0 -0
  333. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/entities/io/test_dependency_errors.py +0 -0
  334. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/fixtures/eba_event_probe_plugin/.gitignore +0 -0
  335. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/fixtures/eba_event_probe_plugin/assets/icon.svg +0 -0
  336. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/fixtures/eba_event_probe_plugin/components/event_listener/default.py +0 -0
  337. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/fixtures/eba_event_probe_plugin/components/event_listener/default.yaml +0 -0
  338. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/fixtures/eba_event_probe_plugin/main.py +0 -0
  339. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/fixtures/eba_event_probe_plugin/manifest.yaml +0 -0
  340. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/helpers/__init__.py +0 -0
  341. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/helpers/protocol.py +0 -0
  342. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/packaging/test_installed_cli_blackbox.py +0 -0
  343. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/helper/test_marketplace.py +0 -0
  344. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/helper/test_pkgmgr.py +0 -0
  345. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/handlers/test_control_handler.py +0 -0
  346. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
  347. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/test_action_consistency.py +0 -0
  348. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/test_connections.py +0 -0
  349. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/test_controllers.py +0 -0
  350. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/test_heartbeat_admission.py +0 -0
  351. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/io/test_stdio_server.py +0 -0
  352. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_artifact_store.py +0 -0
  353. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_container.py +0 -0
  354. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_dependency_environment.py +0 -0
  355. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_legacy_shadow.py +0 -0
  356. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_mgr_runner.py +0 -0
  357. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_restart_coordinator.py +0 -0
  358. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/plugin/test_workload_isolation.py +0 -0
  359. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/test_app.py +0 -0
  360. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/test_bounded_executor.py +0 -0
  361. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/test_event_loop_monitor.py +0 -0
  362. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/runtime/test_pull_api_handlers.py +0 -0
  363. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/test_certification.py +0 -0
  364. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/test_log.py +0 -0
  365. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/test_message.py +0 -0
  366. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/test_plugin_logbuffer.py +0 -0
  367. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/test_storage.py +0 -0
  368. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/utils/test_deadline.py +0 -0
  369. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/utils/test_discovery.py +0 -0
  370. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/utils/test_importutil.py +0 -0
  371. {langbot_plugin-0.6.1b2 → langbot_plugin-0.6.2}/tests/utils/test_platform.py +0 -0
@@ -161,13 +161,27 @@ actions reject tenant context. Plugin payload fields are never authoritative
161
161
  for these bindings.
162
162
 
163
163
  In the `shared` profile, `PluginManager` indexes desired state by the complete
164
- installation binding. The instance-scoped `RECONCILE_PLUGIN_INSTALLATIONS`
164
+ installation binding. Each desired-state entry has an additive
165
+ `execution_mode`: omission or `dedicated` preserves the historical one-process
166
+ per installation behavior, while `shared-runtime-v1` opts a certified
167
+ `shared-runtime-v1` installation into a digest-scoped worker pool. Core is
168
+ responsible for selecting `shared-runtime-v1` only after certification succeeds;
169
+ the Runtime never infers shared authority from tenant-controlled manifest data.
170
+ The instance-scoped `RECONCILE_PLUGIN_INSTALLATIONS`
165
171
  action replays the authoritative set, while tenant-scoped
166
172
  `APPLY_PLUGIN_INSTALLATION` and `REMOVE_PLUGIN_INSTALLATION` actions change one
167
173
  installation. Newer placement generations or Runtime revisions fence the old
168
174
  worker immediately; stale or cross-Workspace transitions fail closed.
169
175
 
170
- Each enabled installation is owned by an installation-scoped Supervisor.
176
+ Dedicated enabled installations remain owned by installation-scoped
177
+ Supervisors. A certified shared worker is keyed by the raw artifact digest and
178
+ currently has pool size one: the first slot attach starts it and the last slot
179
+ detach stops it. Installations sharing that process retain separate
180
+ `BasePlugin`, component, config, Host authority, and lifecycle slots. Updating
181
+ one slot reinitializes that slot without restarting siblings. Revision and
182
+ generation fencing remove the exact stale slot, cancel its in-flight actions,
183
+ and prevent background calls after detach.
184
+
171
185
  Unexpected worker exit is recovered with bounded exponential backoff. Disable,
172
186
  remove, placement generation changes, Runtime revision changes, and shutdown
173
187
  fence the old Supervisor before it can relaunch, while reconcile and control
@@ -183,9 +197,14 @@ installation or Workspace identity.
183
197
 
184
198
  Plugin packages are verified against `artifact_digest` and extracted once into
185
199
  a read-only `artifacts/sha256/<digest>/code` tree. Installations may share that
186
- code tree, but each gets a separate process and private `home`, `tmp`, and `data`
187
- directories. A worker receives a short-lived, one-use registration capability
188
- bound to the complete installation tuple; it cannot select its own tenant scope.
200
+ code tree. Dedicated mode gives each installation a separate process and private
201
+ `home`, `tmp`, and `data` directories. Certified shared workers mount no
202
+ installation or tenant-writable directory; their writable scratch belongs to
203
+ the digest process and tenant state must go through Host actions. A dedicated
204
+ worker capability is bound to one complete installation tuple. A shared worker
205
+ capability is additionally bound to its digest; after registration, every slot
206
+ RPC carries an exact current `InstallationBinding` and cannot select or rebind
207
+ tenant scope.
189
208
 
190
209
  Before any desired-state artifact worker is launched, the Runtime prepares an
191
210
  immutable dependency tree. The resulting `site-packages` tree is keyed by the
@@ -197,7 +216,8 @@ stable `dependency_prepare_failed` desired-state failure. Pip control options in
197
216
  an artifact's `requirements.txt` are rejected because only Runtime configuration
198
217
  may select indexes or trusted hosts.
199
218
 
200
- Shared workers launch through nsjail with policy-owned cgroup CPU, memory, and
219
+ Workers in the shared Runtime profile launch through nsjail with policy-owned
220
+ cgroup CPU, memory, and
201
221
  PID limits plus file/process rlimits. If `require_hard_limits` is true, missing
202
222
  nsjail or cgroup v2 delegation makes configuration fail closed. Their dependency
203
223
  tree is prepared in a separate nsjail and mounted read-only into the worker.
@@ -305,7 +325,9 @@ An OSS-only exception permits legacy knowledge `FILE_CHUNK` replies carrying
305
325
  instance and already-bound Workspace/generation, and its installation capability
306
326
  must exactly match a live registered plugin connection. Payload scope is ignored.
307
327
  Shared transfers still require a complete binding; candidate artifact pretransfer
308
- validates that binding without activating desired state.
328
+ validates that binding without activating desired state. Transfer ownership and
329
+ tenant-visible plugin containers/log routing remain installation scoped even
330
+ when several slots use one process.
309
331
 
310
332
  Legacy OSS plugins are stored under `data/plugins/{author}__{name}`. Runtime
311
333
  plugin processes normally run as separate Python processes and connect back via
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: langbot-plugin
3
- Version: 0.6.1b2
3
+ Version: 0.6.2
4
4
  Summary: This package contains the SDK, CLI for building plugins for LangBot, plus the runtime for hosting LangBot plugins
5
5
  Project-URL: Homepage, https://langbot.app
6
6
  Project-URL: Repository, https://github.com/langbot-app/langbot-plugin-sdk
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "langbot-plugin"
3
- version = "0.6.1b2"
3
+ version = "0.6.2"
4
4
  description = "This package contains the SDK, CLI for building plugins for LangBot, plus the runtime for hosting LangBot plugins"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -4,6 +4,7 @@ import asyncio
4
4
  import os
5
5
  import typing
6
6
  import logging
7
+ import copy
7
8
 
8
9
  from langbot_plugin.api.definition.components.manifest import ComponentManifest
9
10
  from langbot_plugin.runtime.plugin.container import (
@@ -32,6 +33,7 @@ from langbot_plugin.api.definition.components.page import Page
32
33
  from langbot_plugin.api.definition.components.parser.parser import Parser
33
34
  from langbot_plugin.api.definition.components.runner.runner import Runner
34
35
  from langbot_plugin.entities.io.errors import ConnectionClosedError
36
+ from langbot_plugin.entities.io.context import InstallationBinding
35
37
  from langbot_plugin.cli.run.hotreload import HotReloader, reload_plugin_modules
36
38
  from langbot_plugin.runtime.security import (
37
39
  PLUGIN_DEBUG_KEY_ENV,
@@ -44,6 +46,39 @@ from langbot_plugin.runtime.security import (
44
46
  logger = logging.getLogger(__name__)
45
47
 
46
48
 
49
+ class _SlotHandlerProxy:
50
+ """Bind every worker-to-Runtime call to one exact installation slot."""
51
+
52
+ def __init__(self, handler: PluginRuntimeHandler, binding: InstallationBinding):
53
+ self._handler = handler
54
+ self._binding = binding
55
+
56
+ async def call_action(self, action, data, timeout=15.0, **kwargs):
57
+ kwargs["action_context"] = self._binding
58
+ return await self._handler.call_action(action, data, timeout=timeout, **kwargs)
59
+
60
+ def call_action_generator(self, action, data, timeout=15.0, **kwargs):
61
+ kwargs["action_context"] = self._binding
62
+ return self._handler.call_action_generator(
63
+ action, data, timeout=timeout, **kwargs
64
+ )
65
+
66
+ async def send_file(self, file_bytes, file_extension, **kwargs):
67
+ kwargs["action_context"] = self._binding
68
+ return await self._handler.send_file(file_bytes, file_extension, **kwargs)
69
+
70
+ async def read_local_file(self, file_key, **kwargs):
71
+ kwargs["action_context"] = self._binding
72
+ return await self._handler.read_local_file(file_key, **kwargs)
73
+
74
+ async def delete_local_file(self, file_key, **kwargs):
75
+ kwargs["action_context"] = self._binding
76
+ return await self._handler.delete_local_file(file_key, **kwargs)
77
+
78
+ def __getattr__(self, name):
79
+ return getattr(self._handler, name)
80
+
81
+
47
82
  def _apply_runner_class_defaults(
48
83
  component_manifest: ComponentManifest,
49
84
  component_impl_cls: type[Runner],
@@ -119,6 +154,7 @@ class PluginRuntimeController:
119
154
  status=RuntimeContainerStatus.UNMOUNTED,
120
155
  components=components_containers,
121
156
  )
157
+ self._slot_containers: dict[str, PluginContainer] = {}
122
158
 
123
159
  async def run(self) -> None:
124
160
  await self._controller_task
@@ -167,6 +203,8 @@ class PluginRuntimeController:
167
203
 
168
204
  async def new_connection_callback(connection: Connection):
169
205
  self.handler = PluginRuntimeHandler(connection, self.initialize)
206
+ self.handler._slot_initialize_callback = self.initialize_slot
207
+ self.handler._slot_detach_callback = self.detach_slot
170
208
 
171
209
  async def disconnect_callback(hdl: PluginRuntimeHandler):
172
210
  if self.prod_mode:
@@ -304,18 +342,30 @@ class PluginRuntimeController:
304
342
  )
305
343
  logger.debug(f"plugin_settings: {plugin_settings}")
306
344
 
307
- self.plugin_container.enabled = plugin_settings["enabled"]
308
- self.plugin_container.priority = plugin_settings["priority"]
309
- self.plugin_container.plugin_config = plugin_settings["plugin_config"]
345
+ await self._initialize_container(
346
+ self.plugin_container,
347
+ self.handler,
348
+ plugin_settings,
349
+ )
350
+
351
+ async def _initialize_container(
352
+ self,
353
+ plugin_container: PluginContainer,
354
+ runtime_handler: typing.Any,
355
+ plugin_settings: dict[str, typing.Any],
356
+ ) -> None:
357
+ """Initialize one object graph without mutating controller-global routing."""
358
+
359
+ plugin_container.enabled = plugin_settings["enabled"]
360
+ plugin_container.priority = plugin_settings["priority"]
361
+ plugin_container.plugin_config = plugin_settings["plugin_config"]
310
362
  # initialize plugin instance
311
- plugin_cls = self.plugin_container.manifest.get_python_component_class()
363
+ plugin_cls = plugin_container.manifest.get_python_component_class()
312
364
  assert isinstance(plugin_cls, type(BasePlugin))
313
- self.plugin_container.plugin_instance = plugin_cls()
314
- self.plugin_container.plugin_instance.config = (
315
- self.plugin_container.plugin_config
316
- )
317
- self.plugin_container.plugin_instance.plugin_runtime_handler = self.handler
318
- await self.plugin_container.plugin_instance.initialize()
365
+ plugin_container.plugin_instance = plugin_cls()
366
+ plugin_container.plugin_instance.config = plugin_container.plugin_config
367
+ plugin_container.plugin_instance.plugin_runtime_handler = runtime_handler
368
+ await plugin_container.plugin_instance.initialize()
319
369
 
320
370
  preinitialize_component_classes: list[type[BaseComponent]] = [
321
371
  EventListener,
@@ -328,7 +378,7 @@ class PluginRuntimeController:
328
378
  ]
329
379
 
330
380
  for component_cls in preinitialize_component_classes:
331
- for component_container in self.plugin_container.components:
381
+ for component_container in plugin_container.components:
332
382
  logger.debug(
333
383
  f"Checking component {component_container.manifest.metadata.name}: "
334
384
  f"kind={component_container.manifest.kind}, expected={component_cls.__kind__}"
@@ -349,15 +399,15 @@ class PluginRuntimeController:
349
399
  component_impl_cls,
350
400
  )
351
401
  component_container.component_instance.bind_runtime(
352
- plugin_runtime_handler=self.handler,
353
- plugin_config=self.plugin_container.plugin_config,
402
+ plugin_runtime_handler=runtime_handler,
403
+ plugin_config=plugin_container.plugin_config,
354
404
  plugin_identity=(
355
- f"{self.plugin_container.manifest.metadata.author}/"
356
- f"{self.plugin_container.manifest.metadata.name}"
405
+ f"{plugin_container.manifest.metadata.author}/"
406
+ f"{plugin_container.manifest.metadata.name}"
357
407
  ),
358
408
  )
359
409
  component_container.component_instance.plugin = (
360
- self.plugin_container.plugin_instance
410
+ plugin_container.plugin_instance
361
411
  )
362
412
  await component_container.component_instance.initialize()
363
413
  logger.info(
@@ -369,12 +419,49 @@ class PluginRuntimeController:
369
419
  f"Plugin {self.plugin_container.manifest.metadata.author}/{self.plugin_container.manifest.metadata.name} initialized"
370
420
  )
371
421
 
372
- self.plugin_container.status = RuntimeContainerStatus.INITIALIZED
422
+ plugin_container.status = RuntimeContainerStatus.INITIALIZED
423
+
424
+ async def initialize_slot(
425
+ self,
426
+ installation_uuid: str | InstallationBinding,
427
+ plugin_settings: dict[str, typing.Any],
428
+ ) -> PluginContainer:
429
+ """Create or replace one installation's independent object graph."""
430
+
431
+ slot_key = (
432
+ installation_uuid.installation_uuid
433
+ if isinstance(installation_uuid, InstallationBinding)
434
+ else installation_uuid
435
+ )
436
+ slot = PluginContainer.from_dict(
437
+ copy.deepcopy(self.plugin_container.model_dump())
438
+ )
439
+ slot.plugin_instance = NonePlugin()
440
+ for component in slot.components:
441
+ component.component_instance = NoneComponent()
442
+ runtime_handler: typing.Any = self.handler
443
+ if isinstance(installation_uuid, InstallationBinding):
444
+ runtime_handler = _SlotHandlerProxy(self.handler, installation_uuid)
445
+ await self._initialize_container(slot, runtime_handler, plugin_settings)
446
+ self._slot_containers[slot_key] = slot
447
+ return slot
448
+
449
+ def plugin_container_for_slot(
450
+ self,
451
+ installation_uuid: str,
452
+ ) -> PluginContainer | None:
453
+ return self._slot_containers.get(installation_uuid)
454
+
455
+ async def detach_slot(self, installation_uuid: str) -> None:
456
+ """Drop exactly one slot; sibling instances remain resident."""
457
+
458
+ self._slot_containers.pop(installation_uuid, None)
373
459
 
374
460
  async def cleanup_instances(self) -> None:
375
461
  """Clean up all plugin and component instances."""
376
462
  logger.info("Cleaning up plugin instances...")
377
463
 
464
+ self._slot_containers.clear()
378
465
  # Clear component instances
379
466
  for component_container in self.plugin_container.components:
380
467
  # Reset component instance
@@ -19,6 +19,7 @@ from langbot_plugin.api.definition.components.base import NoneComponent
19
19
  from langbot_plugin.api.definition.components.common.event_listener import EventListener
20
20
  from langbot_plugin.entities.io.actions.enums import PluginToRuntimeAction
21
21
  from langbot_plugin.entities.io.actions.enums import RuntimeToPluginAction
22
+ from langbot_plugin.entities.io.context import InstallationBinding
22
23
  from langbot_plugin.api.definition.components.tool.tool import Tool
23
24
  from langbot_plugin.api.definition.components.command.command import Command
24
25
  from langbot_plugin.api.definition.components.knowledge_engine.engine import (
@@ -138,7 +139,7 @@ async def _iter_runner_results_with_deadline(
138
139
  class PluginRuntimeHandler(Handler):
139
140
  """The handler for running plugins."""
140
141
 
141
- plugin_container: PluginContainer
142
+ _base_plugin_container: PluginContainer
142
143
 
143
144
  shutdown_callback: (
144
145
  typing.Callable[[], typing.Coroutine[typing.Any, typing.Any, None]] | None
@@ -155,6 +156,18 @@ class PluginRuntimeHandler(Handler):
155
156
  super().__init__(connection)
156
157
  self.name = "FromRuntime"
157
158
  self._shutdown_task: asyncio.Task[None] | None = None
159
+ self._slot_containers: dict[str, PluginContainer] = {}
160
+ self._slot_initialize_callback: (
161
+ typing.Callable[
162
+ [InstallationBinding, dict[str, typing.Any]],
163
+ typing.Coroutine[typing.Any, typing.Any, PluginContainer],
164
+ ]
165
+ | None
166
+ ) = None
167
+ self._slot_detach_callback: (
168
+ typing.Callable[[str], typing.Coroutine[typing.Any, typing.Any, None]]
169
+ | None
170
+ ) = None
158
171
 
159
172
  @self.action(RuntimeToPluginAction.INITIALIZE_PLUGIN)
160
173
  async def initialize_plugin(data: dict[str, typing.Any]) -> ActionResponse:
@@ -164,6 +177,44 @@ class PluginRuntimeHandler(Handler):
164
177
  await plugin_initialize_callback(data["plugin_settings"])
165
178
  return ActionResponse.success({})
166
179
 
180
+ @self.action(RuntimeToPluginAction.ATTACH_PLUGIN_SLOT)
181
+ async def attach_plugin_slot(data: dict[str, typing.Any]) -> ActionResponse:
182
+ binding = self.current_action_context
183
+ if not isinstance(binding, InstallationBinding):
184
+ raise ValueError("Shared slot attach requires InstallationBinding")
185
+ if self._slot_initialize_callback is None:
186
+ raise ValueError("Shared slot initialization is unavailable")
187
+ container = await self._slot_initialize_callback(
188
+ binding,
189
+ data["plugin_settings"],
190
+ )
191
+ self._slot_containers[binding.installation_uuid] = container
192
+ return ActionResponse.success({})
193
+
194
+ @self.action(RuntimeToPluginAction.DETACH_PLUGIN_SLOT)
195
+ async def detach_plugin_slot(data: dict[str, typing.Any]) -> ActionResponse:
196
+ del data
197
+ binding = self.current_action_context
198
+ if not isinstance(binding, InstallationBinding):
199
+ raise ValueError("Shared slot detach requires InstallationBinding")
200
+ if self._slot_detach_callback is not None:
201
+ await self._slot_detach_callback(binding.installation_uuid)
202
+ self._slot_containers.pop(binding.installation_uuid, None)
203
+ return ActionResponse.success({})
204
+
205
+ @self.action(RuntimeToPluginAction.GET_PLUGIN_SLOT_CONTAINER)
206
+ async def get_plugin_slot_container(
207
+ data: dict[str, typing.Any],
208
+ ) -> ActionResponse:
209
+ del data
210
+ binding = self.current_action_context
211
+ if not isinstance(binding, InstallationBinding):
212
+ raise ValueError("Shared slot lookup requires InstallationBinding")
213
+ container = self._slot_containers.get(binding.installation_uuid)
214
+ if container is None:
215
+ raise ValueError("Shared plugin slot is not attached")
216
+ return ActionResponse.success(container.model_dump())
217
+
167
218
  @self.action(RuntimeToPluginAction.GET_PLUGIN_CONTAINER)
168
219
  async def get_plugin_container(data: dict[str, typing.Any]) -> ActionResponse:
169
220
  return ActionResponse.success(self.plugin_container.model_dump())
@@ -713,6 +764,19 @@ class PluginRuntimeHandler(Handler):
713
764
 
714
765
  return ActionResponse.success(result.model_dump(mode="json"))
715
766
 
767
+ @property
768
+ def plugin_container(self) -> PluginContainer:
769
+ binding = self.current_action_context
770
+ if isinstance(binding, InstallationBinding):
771
+ slot = self._slot_containers.get(binding.installation_uuid)
772
+ if slot is not None:
773
+ return slot
774
+ return self._base_plugin_container
775
+
776
+ @plugin_container.setter
777
+ def plugin_container(self, value: PluginContainer) -> None:
778
+ self._base_plugin_container = value
779
+
716
780
  async def register_plugin(
717
781
  self,
718
782
  prod_mode: bool = False,
@@ -134,6 +134,9 @@ class RuntimeToPluginAction(ActionType):
134
134
  """The action from runtime to plugin."""
135
135
 
136
136
  INITIALIZE_PLUGIN = "initialize_plugin"
137
+ ATTACH_PLUGIN_SLOT = "attach_plugin_slot"
138
+ DETACH_PLUGIN_SLOT = "detach_plugin_slot"
139
+ GET_PLUGIN_SLOT_CONTAINER = "get_plugin_slot_container"
137
140
  GET_PLUGIN_CONTAINER = "get_plugin_container"
138
141
  GET_PLUGIN_ICON = "get_plugin_icon"
139
142
  GET_PLUGIN_README = "get_plugin_readme"
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import json
4
4
  import math
5
5
  import re
6
+ from enum import Enum
6
7
  from typing import Literal
7
8
 
8
9
  import pydantic
@@ -11,6 +12,13 @@ import pydantic
11
12
  _SHA256_DIGEST_PATTERN = re.compile(r"^[0-9a-f]{64}$")
12
13
 
13
14
 
15
+ class PluginExecutionMode(str, Enum):
16
+ """Process placement selected by the trusted control plane."""
17
+
18
+ DEDICATED = "dedicated"
19
+ SHARED_CERTIFIED = "shared-runtime-v1"
20
+
21
+
14
22
  class RuntimeIdentity(pydantic.BaseModel):
15
23
  """Stable instance scope plus this Runtime process' short-lived identity."""
16
24
 
@@ -333,6 +341,7 @@ class PluginInstallationDesiredState(pydantic.BaseModel):
333
341
 
334
342
  binding: InstallationBinding
335
343
  enabled: bool = True
344
+ execution_mode: PluginExecutionMode = PluginExecutionMode.DEDICATED
336
345
 
337
346
  model_config = pydantic.ConfigDict(extra="forbid", frozen=True)
338
347
 
@@ -364,6 +373,7 @@ class ReconcilePluginInstallationsRequest(pydantic.BaseModel):
364
373
  class ApplyPluginInstallationRequest(pydantic.BaseModel):
365
374
  artifact_file_key: str | None = None
366
375
  enabled: bool = True
376
+ execution_mode: PluginExecutionMode = PluginExecutionMode.DEDICATED
367
377
 
368
378
  model_config = pydantic.ConfigDict(extra="forbid", frozen=True)
369
379
 
@@ -68,8 +68,11 @@ async def _run_small_protocol_work(fn: Callable[..., Any], *args: Any) -> Any:
68
68
  def _file_storage_path(
69
69
  file_key: str,
70
70
  file_storage_dir: str | os.PathLike[str] = FILE_STORAGE_DIR,
71
+ *,
72
+ action_context: ActionEnvelopeContext | None = None,
73
+ create_namespace: bool = False,
71
74
  ) -> str:
72
- """Resolve one opaque transfer key without accepting path syntax."""
75
+ """Resolve one opaque key inside its durable authority namespace."""
73
76
 
74
77
  if not isinstance(file_key, str):
75
78
  raise ValueError("Invalid file transfer key")
@@ -85,7 +88,20 @@ def _file_storage_path(
85
88
  or _SAFE_FILE_KEY_PATTERN.fullmatch(key) is None
86
89
  ):
87
90
  raise ValueError("Invalid file transfer key")
88
- return os.path.join(os.fspath(file_storage_dir), key)
91
+ if action_context is None:
92
+ namespace = "unbound"
93
+ else:
94
+ serialized_context = json.dumps(
95
+ action_context.model_dump(mode="json"),
96
+ sort_keys=True,
97
+ separators=(",", ":"),
98
+ ).encode("utf-8")
99
+ namespace = hashlib.sha256(serialized_context).hexdigest()
100
+ namespace_path = os.path.join(os.fspath(file_storage_dir), namespace)
101
+ if create_namespace:
102
+ os.makedirs(namespace_path, mode=0o700, exist_ok=True)
103
+ os.chmod(namespace_path, 0o700)
104
+ return os.path.join(namespace_path, key)
89
105
 
90
106
 
91
107
  class Handler(abc.ABC):
@@ -123,6 +139,9 @@ class Handler(abc.ABC):
123
139
  self.resp_waiters = {}
124
140
  self.resp_queues = {}
125
141
  self._action_tasks: set[asyncio.Task[None]] = set()
142
+ self._action_task_contexts: dict[
143
+ asyncio.Task[None], ActionEnvelopeContext | None
144
+ ] = {}
126
145
  self._active_tasks: set[asyncio.Task[None]] = set()
127
146
  # Reserved tasks remain in the common set for cancellation and accounting.
128
147
  self._reserved_action_tasks: set[asyncio.Task[None]] = set()
@@ -162,10 +181,6 @@ class Handler(abc.ABC):
162
181
 
163
182
  @self.action(CommonAction.FILE_CHUNK)
164
183
  async def file_chunk(data: dict[str, Any]) -> ActionResponse:
165
- file_path = _file_storage_path(
166
- data["file_key"],
167
- self.file_storage_dir,
168
- )
169
184
  chunk_base64 = data["chunk_base64"]
170
185
  chunk_index = data["chunk_index"]
171
186
  chunk_amount = data["chunk_amount"]
@@ -188,12 +203,19 @@ class Handler(abc.ABC):
188
203
  if len(chunk_bytes) > FILE_CHUNK_LENGTH:
189
204
  raise ValueError("File transfer chunk exceeds the protocol limit")
190
205
  async with self._file_transfer_lock:
206
+ transfer_context = self.resolve_effective_action_context()
207
+ file_path = _file_storage_path(
208
+ data["file_key"],
209
+ self.file_storage_dir,
210
+ action_context=transfer_context,
211
+ create_namespace=True,
212
+ )
191
213
  if (
192
- data["file_key"] not in self._owned_transfer_files
214
+ file_path not in self._owned_transfer_files
193
215
  and len(self._owned_transfer_files) >= MAX_ACTIVE_FILE_TRANSFERS
194
216
  ):
195
217
  raise ValueError("Active file transfer capacity reached")
196
- self._owned_transfer_files.add(data["file_key"])
218
+ self._owned_transfer_files.add(file_path)
197
219
  # The first chunk replaces stale partial data for the same
198
220
  # opaque transfer id; later chunks append. Runtime-side
199
221
  # installation handlers cap the aggregate bytes written on
@@ -440,6 +462,9 @@ class Handler(abc.ABC):
440
462
  request.context,
441
463
  )
442
464
  context_token = self._current_action_context.set(action_context)
465
+ current_task = asyncio.current_task()
466
+ if current_task is not None:
467
+ self._action_task_contexts[current_task] = action_context
443
468
 
444
469
  with blocking_work_scope(getattr(action_context, "workspace_uuid", None)):
445
470
  response = self.actions[action_name](request.data)
@@ -476,6 +501,9 @@ class Handler(abc.ABC):
476
501
  finally:
477
502
  if context_token is not None:
478
503
  self._current_action_context.reset(context_token)
504
+ current_task = asyncio.current_task()
505
+ if current_task is not None:
506
+ self._action_task_contexts.pop(current_task, None)
479
507
  if action_name and not action_name.startswith("__"):
480
508
  logger.debug("[Action] %s", action_name)
481
509
 
@@ -532,6 +560,16 @@ class Handler(abc.ABC):
532
560
  for action_task in tuple(self._action_tasks):
533
561
  action_task.cancel()
534
562
 
563
+ def cancel_inflight_messages_for_context(
564
+ self,
565
+ action_context: ActionEnvelopeContext,
566
+ ) -> None:
567
+ """Cancel only requests owned by one exact installation revision."""
568
+
569
+ for action_task, owned_context in tuple(self._action_task_contexts.items()):
570
+ if owned_context == action_context:
571
+ action_task.cancel()
572
+
535
573
  async def call_action(
536
574
  self,
537
575
  action: ActionType,
@@ -753,6 +791,16 @@ class Handler(abc.ABC):
753
791
  )
754
792
  return context
755
793
 
794
+ def resolve_effective_action_context(
795
+ self,
796
+ action_context: ActionEnvelopeContext | dict[str, Any] | None = None,
797
+ ) -> ActionEnvelopeContext | None:
798
+ """Resolve explicit, task-local, then connection-bound authority."""
799
+
800
+ if action_context is not None:
801
+ return self.resolve_outbound_action_context(action_context)
802
+ return self._current_action_context.get() or self._bound_action_context
803
+
756
804
  # decorator to register an action
757
805
  def action(
758
806
  self, name: ActionType
@@ -847,8 +895,18 @@ class Handler(abc.ABC):
847
895
  )
848
896
  return file_key
849
897
 
850
- async def read_local_file(self, file_key: str) -> bytes:
851
- file_path = _file_storage_path(file_key, self.file_storage_dir)
898
+ async def read_local_file(
899
+ self,
900
+ file_key: str,
901
+ *,
902
+ action_context: ActionEnvelopeContext | dict[str, Any] | None = None,
903
+ ) -> bytes:
904
+ transfer_context = self.resolve_effective_action_context(action_context)
905
+ file_path = _file_storage_path(
906
+ file_key,
907
+ self.file_storage_dir,
908
+ action_context=transfer_context,
909
+ )
852
910
 
853
911
  def read_file() -> bytes:
854
912
  if self.max_file_bytes is not None:
@@ -866,33 +924,44 @@ class Handler(abc.ABC):
866
924
  await run_blocking_with_backpressure(os.path.getsize, file_path)
867
925
  return content
868
926
 
869
- async def delete_local_file(self, file_key: str) -> None:
927
+ async def delete_local_file(
928
+ self,
929
+ file_key: str,
930
+ *,
931
+ action_context: ActionEnvelopeContext | dict[str, Any] | None = None,
932
+ ) -> None:
933
+ transfer_context = self.resolve_effective_action_context(action_context)
934
+ file_path = _file_storage_path(
935
+ file_key,
936
+ self.file_storage_dir,
937
+ action_context=transfer_context,
938
+ )
870
939
  async with self._file_transfer_lock:
871
940
  try:
872
941
  await run_blocking_with_backpressure(
873
942
  os.remove,
874
- _file_storage_path(file_key, self.file_storage_dir),
943
+ file_path,
875
944
  )
876
945
  except FileNotFoundError:
877
946
  pass
878
947
  finally:
879
- self._owned_transfer_files.discard(file_key)
948
+ self._owned_transfer_files.discard(file_path)
880
949
 
881
950
  async def _cleanup_owned_transfers(self) -> None:
882
951
  async with self._file_transfer_lock:
883
- file_keys = tuple(self._owned_transfer_files)
952
+ file_paths = tuple(self._owned_transfer_files)
884
953
  self._owned_transfer_files.clear()
885
- for file_key in file_keys:
954
+ for file_path in file_paths:
886
955
  try:
887
956
  await run_blocking_cleanup(
888
957
  os.remove,
889
- _file_storage_path(file_key, self.file_storage_dir),
958
+ file_path,
890
959
  )
891
960
  except FileNotFoundError:
892
961
  pass
893
962
  except OSError as exc:
894
963
  logger.warning(
895
964
  "Failed to clean runtime transfer file %s: %s",
896
- file_key,
965
+ os.path.basename(file_path),
897
966
  exc,
898
967
  )
@@ -167,10 +167,15 @@ class ControlConnectionHandler(handler.Handler):
167
167
  if request.artifact_file_key is not None:
168
168
  artifact_package = await self.read_local_file(request.artifact_file_key)
169
169
  await self.delete_local_file(request.artifact_file_key)
170
+ apply_kwargs: dict[str, Any] = {
171
+ "artifact_package": artifact_package,
172
+ "enabled": request.enabled,
173
+ }
174
+ if request.execution_mode.value != "dedicated":
175
+ apply_kwargs["execution_mode"] = request.execution_mode
170
176
  result = await self.context.plugin_mgr.apply_plugin_installation(
171
177
  binding,
172
- artifact_package=artifact_package,
173
- enabled=request.enabled,
178
+ **apply_kwargs,
174
179
  )
175
180
  return handler.ActionResponse.success(result)
176
181