langbot-plugin 0.5.2__tar.gz → 0.5.4__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 (269) hide show
  1. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/PKG-INFO +1 -1
  2. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/pyproject.toml +1 -1
  3. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/handler.py +5 -2
  4. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/mgr.py +74 -33
  5. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/restart_coordinator.py +17 -10
  6. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/worker_launcher.py +4 -0
  7. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/security.py +1 -0
  8. langbot_plugin-0.5.4/src/langbot_plugin/version.py +1 -0
  9. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/test_handler.py +15 -0
  10. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_installation_manager.py +104 -0
  11. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_restart_coordinator.py +36 -0
  12. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_worker_launcher.py +2 -0
  13. langbot_plugin-0.5.2/src/langbot_plugin/version.py +0 -1
  14. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/.github/workflows/cla.yml +0 -0
  15. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/.github/workflows/publish-pypi.yaml +0 -0
  16. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/.github/workflows/publish.yml +0 -0
  17. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/.github/workflows/test.yml +0 -0
  18. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/.gitignore +0 -0
  19. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/.python-version +0 -0
  20. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/AGENTS.md +0 -0
  21. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/ARCHITECTURE.md +0 -0
  22. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/CLAUDE.md +0 -0
  23. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/CONTRIBUTING.md +0 -0
  24. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/LICENSE +0 -0
  25. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/README.md +0 -0
  26. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/README_CN.md +0 -0
  27. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/data/.env.example +0 -0
  28. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/docs/Message.md +0 -0
  29. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/docs/PluginPages.md +0 -0
  30. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/docs/communication/apis/lb2rt.md +0 -0
  31. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/docs/communication/runtime_plugin.md +0 -0
  32. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/docs/dependency-management.md +0 -0
  33. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/docs/langbot-plugin-social.png +0 -0
  34. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/scripts/check_action_consistency.py +0 -0
  35. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/scripts/runtime_resource_probe.py +0 -0
  36. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/__init__.py +0 -0
  37. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/__init__.py +0 -0
  38. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/__init__.py +0 -0
  39. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
  40. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
  41. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
  42. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
  43. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
  44. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/base.py +0 -0
  45. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
  46. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
  47. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
  48. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
  49. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
  50. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
  51. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
  52. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
  53. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
  54. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
  55. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
  56. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
  57. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/definition/plugin.py +0 -0
  58. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/__init__.py +0 -0
  59. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
  60. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
  61. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
  62. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
  63. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
  64. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
  65. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
  66. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
  67. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
  68. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
  69. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
  70. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
  71. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
  72. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
  73. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
  74. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
  75. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
  76. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
  77. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
  78. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
  79. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
  80. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
  81. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/context.py +0 -0
  82. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/events.py +0 -0
  83. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/entities/execution.py +0 -0
  84. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/proxies/__init__.py +0 -0
  85. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/proxies/base.py +0 -0
  86. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/proxies/event_context.py +0 -0
  87. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
  88. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
  89. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
  90. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/__init__.py +0 -0
  91. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
  92. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
  93. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/.github/workflows/release.yml.example +0 -0
  94. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
  95. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
  96. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/README.md.example +0 -0
  97. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/__init__.py +0 -0
  98. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
  99. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
  100. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
  101. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
  102. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
  103. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
  104. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
  105. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
  106. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
  107. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
  108. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
  109. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
  110. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
  111. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
  112. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
  113. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
  114. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
  115. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
  116. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
  117. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/main.py.example +0 -0
  118. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
  119. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/readme/README_zh_Hans.md.example +0 -0
  120. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
  121. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/__init__.py +0 -0
  122. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/actions.py +0 -0
  123. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/backend.py +0 -0
  124. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/client.py +0 -0
  125. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/e2b_backend.py +0 -0
  126. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/errors.py +0 -0
  127. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/models.py +0 -0
  128. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/nsjail_backend.py +0 -0
  129. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/runtime.py +0 -0
  130. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/security.py +0 -0
  131. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/server.py +0 -0
  132. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/skill_store.py +0 -0
  133. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/box/tenancy.py +0 -0
  134. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/__init__.py +0 -0
  135. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/__main__.py +0 -0
  136. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/__init__.py +0 -0
  137. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
  138. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
  139. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/initplugin.py +0 -0
  140. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/login.py +0 -0
  141. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/logout.py +0 -0
  142. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/publish.py +0 -0
  143. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
  144. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/gen/__init__.py +0 -0
  145. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/gen/renderer.py +0 -0
  146. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/i18n.py +0 -0
  147. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/__init__.py +0 -0
  148. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/en_US.py +0 -0
  149. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
  150. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
  151. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
  152. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
  153. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
  154. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
  155. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/run/__init__.py +0 -0
  156. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/run/controller.py +0 -0
  157. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/run/handler.py +0 -0
  158. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/run/hotreload.py +0 -0
  159. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/utils/__init__.py +0 -0
  160. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
  161. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/utils/form.py +0 -0
  162. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/cli/utils/page_components.py +0 -0
  163. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/__init__.py +0 -0
  164. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/__init__.py +0 -0
  165. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
  166. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
  167. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/context.py +0 -0
  168. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/errors.py +0 -0
  169. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/req.py +0 -0
  170. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/io/resp.py +0 -0
  171. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/entities/marketplace.py +0 -0
  172. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/LICENSE +0 -0
  173. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/README.md +0 -0
  174. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/__init__.py +0 -0
  175. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/app.py +0 -0
  176. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/bounded_executor.py +0 -0
  177. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/context.py +0 -0
  178. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/event_loop_monitor.py +0 -0
  179. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
  180. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
  181. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -0
  182. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/__init__.py +0 -0
  183. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/connection.py +0 -0
  184. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
  185. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
  186. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
  187. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controller.py +0 -0
  188. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
  189. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
  190. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
  191. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
  192. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
  193. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
  194. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
  195. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
  196. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
  197. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
  198. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
  199. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/artifact.py +0 -0
  200. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/container.py +0 -0
  201. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/dependency_environment.py +0 -0
  202. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/plugin/logbuffer.py +0 -0
  203. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/runtime/settings.py +0 -0
  204. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/utils/__init__.py +0 -0
  205. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/utils/discover/__init__.py +0 -0
  206. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/utils/discover/engine.py +0 -0
  207. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/utils/importutil.py +0 -0
  208. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/utils/log.py +0 -0
  209. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/src/langbot_plugin/utils/platform.py +0 -0
  210. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/__init__.py +0 -0
  211. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/definition/components/test_components.py +0 -0
  212. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/definition/test_manifest.py +0 -0
  213. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/entities/builtin/test_command_context.py +0 -0
  214. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/entities/builtin/test_platform_logger.py +0 -0
  215. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/entities/builtin/test_provider_message.py +0 -0
  216. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/entities/builtin/test_rag_models.py +0 -0
  217. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/entities/test_context.py +0 -0
  218. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/entities/test_events.py +0 -0
  219. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/proxies/test_base.py +0 -0
  220. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/proxies/test_langbot_api.py +0 -0
  221. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/api/proxies/test_query_based_api.py +0 -0
  222. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/__init__.py +0 -0
  223. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_admission.py +0 -0
  224. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_backend.py +0 -0
  225. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_backend_selection.py +0 -0
  226. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_client.py +0 -0
  227. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_e2b_backend.py +0 -0
  228. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_nsjail_backend.py +0 -0
  229. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_runtime.py +0 -0
  230. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_server.py +0 -0
  231. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/box/test_skill_store.py +0 -0
  232. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/run/test_controller.py +0 -0
  233. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/run/test_hotreload.py +0 -0
  234. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/run/test_runtime_handler.py +0 -0
  235. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_buildplugin.py +0 -0
  236. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_gencomponent.py +0 -0
  237. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_i18n_form.py +0 -0
  238. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_initplugin.py +0 -0
  239. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_login.py +0 -0
  240. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_logout_publish.py +0 -0
  241. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_page_components.py +0 -0
  242. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_renderer.py +0 -0
  243. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/cli/test_runplugin.py +0 -0
  244. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/entities/io/test_dependency_errors.py +0 -0
  245. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/entities/io/test_protocol.py +0 -0
  246. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/helpers/__init__.py +0 -0
  247. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/helpers/protocol.py +0 -0
  248. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/packaging/test_installed_cli_blackbox.py +0 -0
  249. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/helper/test_marketplace.py +0 -0
  250. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/helper/test_pkgmgr.py +0 -0
  251. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/handlers/test_control_handler.py +0 -0
  252. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
  253. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
  254. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/test_action_consistency.py +0 -0
  255. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/test_connections.py +0 -0
  256. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/io/test_controllers.py +0 -0
  257. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_artifact_store.py +0 -0
  258. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_container.py +0 -0
  259. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_dependency_environment.py +0 -0
  260. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/plugin/test_manager.py +0 -0
  261. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/test_app.py +0 -0
  262. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/test_bounded_executor.py +0 -0
  263. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/runtime/test_event_loop_monitor.py +0 -0
  264. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/test_log.py +0 -0
  265. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/test_message.py +0 -0
  266. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/test_plugin_logbuffer.py +0 -0
  267. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/utils/test_discovery.py +0 -0
  268. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/tests/utils/test_importutil.py +0 -0
  269. {langbot_plugin-0.5.2 → langbot_plugin-0.5.4}/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.5.2
3
+ Version: 0.5.4
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.5.2"
3
+ version = "0.5.4"
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 = [
@@ -34,7 +34,10 @@ from langbot_plugin.entities.io.errors import (
34
34
  ActionCallError,
35
35
  )
36
36
  from langbot_plugin.entities.io.actions.enums import ActionType, CommonAction
37
- from langbot_plugin.runtime.security import PLUGIN_RUNTIME_PROFILE_ENV
37
+ from langbot_plugin.runtime.security import (
38
+ PLUGIN_FILE_STORAGE_DIR_ENV,
39
+ PLUGIN_RUNTIME_PROFILE_ENV,
40
+ )
38
41
  from langbot_plugin.runtime.bounded_executor import blocking_work_scope
39
42
 
40
43
  logger = logging.getLogger(__name__)
@@ -124,7 +127,7 @@ class Handler(abc.ABC):
124
127
 
125
128
  if file_storage_dir is None:
126
129
  runtime_profile = os.environ.get(PLUGIN_RUNTIME_PROFILE_ENV, "oss_dev")
127
- file_storage_dir = (
130
+ file_storage_dir = os.environ.get(PLUGIN_FILE_STORAGE_DIR_ENV) or (
128
131
  SHARED_WORKER_FILE_STORAGE_DIR
129
132
  if runtime_profile == "shared"
130
133
  else FILE_STORAGE_DIR
@@ -219,6 +219,23 @@ class PluginManager:
219
219
  initial_policy.max_concurrent_restarts
220
220
  )
221
221
 
222
+ async def _complete_installation_transition(
223
+ self,
224
+ operation: typing.Coroutine[typing.Any, typing.Any, None],
225
+ ) -> None:
226
+ """Join one lifecycle mutation through repeated caller cancellation."""
227
+
228
+ task = asyncio.create_task(operation)
229
+ cancelled = False
230
+ while not task.done():
231
+ try:
232
+ await asyncio.shield(task)
233
+ except asyncio.CancelledError:
234
+ cancelled = True
235
+ task.result()
236
+ if cancelled:
237
+ raise asyncio.CancelledError
238
+
222
239
  @property
223
240
  def installation_runtimes(
224
241
  self,
@@ -1058,11 +1075,20 @@ class PluginManager:
1058
1075
  self,
1059
1076
  binding: InstallationBinding,
1060
1077
  ) -> dict[str, typing.Any]:
1061
- binding = self.context.deactivate_installation_binding(binding)
1062
- async with self._installation_lifecycle_semaphore():
1063
- await self._revoke_installation_runtime(binding)
1064
- if self._active_binding_by_uuid.get(binding.installation_uuid) == binding:
1065
- self._active_binding_by_uuid.pop(binding.installation_uuid, None)
1078
+ async def remove() -> None:
1079
+ removed_binding = self.context.deactivate_installation_binding(binding)
1080
+ async with self._installation_lifecycle_semaphore():
1081
+ await self._revoke_installation_runtime(removed_binding)
1082
+ if (
1083
+ self._active_binding_by_uuid.get(removed_binding.installation_uuid)
1084
+ == removed_binding
1085
+ ):
1086
+ self._active_binding_by_uuid.pop(
1087
+ removed_binding.installation_uuid,
1088
+ None,
1089
+ )
1090
+
1091
+ await self._complete_installation_transition(remove())
1066
1092
  return {
1067
1093
  "installation_uuid": binding.installation_uuid,
1068
1094
  "state": "removed",
@@ -1108,22 +1134,26 @@ class PluginManager:
1108
1134
  lock = self._retain_installation_operation_lock(installation_uuid)
1109
1135
  try:
1110
1136
  async with lock:
1111
- if self.context.is_current_installation_binding(
1112
- current_binding
1113
- ):
1114
- self.context.deactivate_installation_binding(
1137
+
1138
+ async def remove_current() -> None:
1139
+ if self.context.is_current_installation_binding(
1115
1140
  current_binding
1116
- )
1117
- async with self._installation_lifecycle_semaphore():
1118
- await self._revoke_installation_runtime(current_binding)
1119
- if (
1120
- self._active_binding_by_uuid.get(installation_uuid)
1121
- == current_binding
1122
- ):
1123
- self._active_binding_by_uuid.pop(
1124
- installation_uuid,
1125
- None,
1126
- )
1141
+ ):
1142
+ self.context.deactivate_installation_binding(
1143
+ current_binding
1144
+ )
1145
+ async with self._installation_lifecycle_semaphore():
1146
+ await self._revoke_installation_runtime(current_binding)
1147
+ if (
1148
+ self._active_binding_by_uuid.get(installation_uuid)
1149
+ == current_binding
1150
+ ):
1151
+ self._active_binding_by_uuid.pop(
1152
+ installation_uuid,
1153
+ None,
1154
+ )
1155
+
1156
+ await self._complete_installation_transition(remove_current())
1127
1157
  removed.append(installation_uuid)
1128
1158
  finally:
1129
1159
  self._forget_installation_operation_lock(
@@ -1469,10 +1499,12 @@ class PluginManager:
1469
1499
  binding: InstallationBinding,
1470
1500
  ) -> None:
1471
1501
  self._revoke_registration_capabilities_for_binding(binding)
1472
- runtime = self._installations.pop(binding, None)
1502
+ runtime = self._installations.get(binding)
1473
1503
  if runtime is None:
1474
1504
  return
1475
1505
  await self._stop_installation_worker(runtime)
1506
+ if self._installations.get(binding) is runtime:
1507
+ self._installations.pop(binding, None)
1476
1508
 
1477
1509
  async def _stop_installation_worker(
1478
1510
  self,
@@ -1486,20 +1518,29 @@ class PluginManager:
1486
1518
  except Exception as exc:
1487
1519
  logger.warning("Failed to notify revoked plugin worker: %s", exc)
1488
1520
  close = getattr(handler, "close", None)
1489
- if close is not None:
1490
- await close()
1491
- else:
1492
- await handler.conn.close()
1493
- if handler in self.plugin_handlers:
1494
- self.plugin_handlers.remove(handler)
1521
+ try:
1522
+ if close is not None:
1523
+ await close()
1524
+ else:
1525
+ await handler.conn.close()
1526
+ except Exception as exc:
1527
+ logger.warning("Failed to close revoked plugin worker: %s", exc)
1528
+ finally:
1529
+ if handler in self.plugin_handlers:
1530
+ self.plugin_handlers.remove(handler)
1531
+ runtime.plugin_handler = None
1495
1532
  process = handler.stdio_process
1496
1533
  if process is not None and process.returncode is None:
1497
- stopped = await stdio_client_controller.stop_process(process)
1498
- if not stopped:
1499
- logger.error(
1500
- "Plugin worker process did not exit after SIGKILL: %s",
1501
- runtime.binding.installation_uuid,
1502
- )
1534
+ try:
1535
+ stopped = await stdio_client_controller.stop_process(process)
1536
+ except Exception as exc:
1537
+ logger.error("Failed to stop revoked plugin worker: %s", exc)
1538
+ else:
1539
+ if not stopped:
1540
+ logger.error(
1541
+ "Plugin worker process did not exit after SIGKILL: %s",
1542
+ runtime.binding.installation_uuid,
1543
+ )
1503
1544
  runtime.plugin_handler = None
1504
1545
  if runtime.plugin_container is not None:
1505
1546
  self._binding_by_container_id.pop(id(runtime.plugin_container), None)
@@ -3,14 +3,16 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import collections
5
5
  import time
6
- from collections.abc import Awaitable
6
+ from collections.abc import Coroutine
7
7
  from dataclasses import dataclass
8
8
  from typing import Callable
9
9
 
10
10
  from langbot_plugin.entities.io.context import PluginWorkerPolicy
11
11
 
12
12
 
13
- async def _complete_state_transition(operation: Awaitable[None]) -> None:
13
+ async def _complete_state_transition(
14
+ operation: Coroutine[object, object, None],
15
+ ) -> None:
14
16
  """Finish one tiny coordinator mutation even if its caller is cancelled.
15
17
 
16
18
  A supervisor cancellation must not strand the circuit in half-open state.
@@ -19,14 +21,19 @@ async def _complete_state_transition(operation: Awaitable[None]) -> None:
19
21
  """
20
22
 
21
23
  task = asyncio.create_task(operation)
22
- try:
23
- await asyncio.shield(task)
24
- except asyncio.CancelledError:
25
- # The cancellation has already been delivered to this caller; the
26
- # shielded mutation remains live and can now be joined directly before
27
- # propagating the original cancellation.
28
- await task
29
- raise
24
+ cancelled = False
25
+ while not task.done():
26
+ try:
27
+ await asyncio.shield(task)
28
+ except asyncio.CancelledError:
29
+ # A caller can be cancelled repeatedly while the mutation is
30
+ # waiting for the state lock. Keep joining the shielded task until
31
+ # the transition is complete; otherwise a half-open probe can be
32
+ # stranded permanently.
33
+ cancelled = True
34
+ task.result()
35
+ if cancelled:
36
+ raise asyncio.CancelledError
30
37
 
31
38
 
32
39
  @dataclass(slots=True)
@@ -28,6 +28,7 @@ from langbot_plugin.runtime.plugin.dependency_environment import (
28
28
  from langbot_plugin.runtime.helper import pkgmgr as pkgmgr_helper
29
29
  from langbot_plugin.runtime import bounded_executor
30
30
  from langbot_plugin.runtime.security import (
31
+ PLUGIN_FILE_STORAGE_DIR_ENV,
31
32
  PLUGIN_REGISTRATION_CAPABILITY_ENV,
32
33
  PLUGIN_RUNTIME_PROFILE_ENV,
33
34
  )
@@ -140,6 +141,9 @@ class PluginWorkerLauncher:
140
141
  "--prod",
141
142
  ],
142
143
  env={
144
+ PLUGIN_FILE_STORAGE_DIR_ENV: str(
145
+ launch_spec.paths.root_path / "rpc-transfer"
146
+ ),
143
147
  PLUGIN_REGISTRATION_CAPABILITY_ENV: (
144
148
  launch_spec.registration_capability
145
149
  ),
@@ -15,6 +15,7 @@ PLUGIN_DEBUG_KEY_HEADER = "X-LangBot-Plugin-Debug-Key"
15
15
  PLUGIN_REGISTRATION_CAPABILITY_ENV = "LANGBOT_PLUGIN_REGISTRATION_CAPABILITY"
16
16
  PLUGIN_REGISTRATION_CAPABILITY_HEADER = "X-LangBot-Plugin-Registration-Capability"
17
17
  PLUGIN_RUNTIME_PROFILE_ENV = "LANGBOT_PLUGIN_RUNTIME_PROFILE"
18
+ PLUGIN_FILE_STORAGE_DIR_ENV = "LANGBOT_PLUGIN_FILE_STORAGE_DIR"
18
19
  RUNTIME_SECRET_MIN_LENGTH = 32
19
20
  WORKSPACE_DEBUG_TOKEN_TTL_SECONDS = 2 * 60 * 60
20
21
 
@@ -0,0 +1 @@
1
+ __version__ = "0.5.4"
@@ -511,6 +511,21 @@ def test_handler_file_storage_dir_is_created_for_instances(tmp_path, monkeypatch
511
511
  assert (tmp_path / "data" / "temp" / "lbp").is_dir()
512
512
 
513
513
 
514
+ def test_managed_worker_file_storage_uses_launcher_directory(tmp_path, monkeypatch):
515
+ artifact = tmp_path / "artifact" / "code"
516
+ artifact.mkdir(parents=True)
517
+ artifact.chmod(0o555)
518
+ rpc_transfer = tmp_path / "installations" / "installation-a" / "rpc-transfer"
519
+ monkeypatch.chdir(artifact)
520
+ monkeypatch.setenv("LANGBOT_PLUGIN_FILE_STORAGE_DIR", str(rpc_transfer))
521
+
522
+ handler = Handler(QueueConnection())
523
+
524
+ assert handler.file_storage_dir == str(rpc_transfer)
525
+ assert rpc_transfer.is_dir()
526
+ assert not (artifact / "data").exists()
527
+
528
+
514
529
  def test_shared_worker_file_storage_uses_private_writable_tmp(tmp_path, monkeypatch):
515
530
  worker_tmp = tmp_path / "lbp-rpc"
516
531
  monkeypatch.setenv(PLUGIN_RUNTIME_PROFILE_ENV, "shared")
@@ -131,6 +131,110 @@ async def test_manager_indexes_same_artifact_installations_by_complete_binding(
131
131
  assert context.is_current_installation_binding(binding_b)
132
132
 
133
133
 
134
+ async def test_cancelled_remove_finishes_worker_revoke_before_propagating(
135
+ tmp_path,
136
+ ):
137
+ context, manager = _manager(tmp_path)
138
+ package = _package()
139
+ digest = hashlib.sha256(package).hexdigest()
140
+ binding = _binding(
141
+ "installation-a",
142
+ digest,
143
+ workspace_uuid="workspace-a",
144
+ )
145
+ await manager.apply_plugin_installation(
146
+ binding,
147
+ artifact_package=package,
148
+ enabled=False,
149
+ )
150
+ runtime = manager.installation_runtimes[binding]
151
+ shutdown_started = asyncio.Event()
152
+ allow_shutdown = asyncio.Event()
153
+
154
+ class Handler:
155
+ stdio_process = None
156
+ conn = None
157
+
158
+ def cancel_inflight_messages(self):
159
+ return None
160
+
161
+ async def shutdown_plugin(self):
162
+ shutdown_started.set()
163
+ await allow_shutdown.wait()
164
+
165
+ async def close(self):
166
+ return None
167
+
168
+ handler = Handler()
169
+ runtime.plugin_handler = handler
170
+ manager.plugin_handlers.append(handler)
171
+
172
+ remove_task = asyncio.create_task(manager.remove_plugin_installation(binding))
173
+ await asyncio.wait_for(shutdown_started.wait(), timeout=1)
174
+ remove_task.cancel()
175
+ await asyncio.sleep(0)
176
+ remove_task.cancel()
177
+ allow_shutdown.set()
178
+
179
+ with pytest.raises(asyncio.CancelledError):
180
+ await remove_task
181
+ assert not context.is_current_installation_binding(binding)
182
+ assert binding not in manager.installation_runtimes
183
+ assert binding.installation_uuid not in manager._active_binding_by_uuid
184
+ assert handler not in manager.plugin_handlers
185
+ assert runtime.plugin_handler is None
186
+
187
+ with pytest.raises(ValueError, match="stale"):
188
+ await manager.reconcile_plugin_installations(
189
+ (PluginInstallationDesiredState(binding=binding, enabled=False),)
190
+ )
191
+
192
+
193
+ async def test_remove_finishes_state_cleanup_when_handler_close_fails(
194
+ tmp_path,
195
+ ):
196
+ context, manager = _manager(tmp_path)
197
+ package = _package()
198
+ digest = hashlib.sha256(package).hexdigest()
199
+ binding = _binding(
200
+ "installation-a",
201
+ digest,
202
+ workspace_uuid="workspace-a",
203
+ )
204
+ await manager.apply_plugin_installation(
205
+ binding,
206
+ artifact_package=package,
207
+ enabled=False,
208
+ )
209
+ runtime = manager.installation_runtimes[binding]
210
+
211
+ class Handler:
212
+ stdio_process = None
213
+ conn = None
214
+
215
+ def cancel_inflight_messages(self):
216
+ return None
217
+
218
+ async def shutdown_plugin(self):
219
+ return None
220
+
221
+ async def close(self):
222
+ raise RuntimeError("close failed")
223
+
224
+ handler = Handler()
225
+ runtime.plugin_handler = handler
226
+ manager.plugin_handlers.append(handler)
227
+
228
+ result = await manager.remove_plugin_installation(binding)
229
+
230
+ assert result["state"] == "removed"
231
+ assert not context.is_current_installation_binding(binding)
232
+ assert binding not in manager.installation_runtimes
233
+ assert binding.installation_uuid not in manager._active_binding_by_uuid
234
+ assert handler not in manager.plugin_handlers
235
+ assert runtime.plugin_handler is None
236
+
237
+
134
238
  async def test_desired_state_does_not_reject_on_aggregate_worker_capacity(
135
239
  tmp_path,
136
240
  monkeypatch,
@@ -198,6 +198,42 @@ async def test_abandoned_probe_releases_slot_without_counting_failure():
198
198
  await replacement_probe.abandon()
199
199
 
200
200
 
201
+ async def test_repeated_cancellation_cannot_strand_half_open_probe():
202
+ coordinator = PluginRestartCoordinator()
203
+ coordinator.configure(
204
+ _policy(
205
+ max_concurrent_restarts=1,
206
+ restart_failure_threshold=1,
207
+ restart_circuit_open_seconds=0.01,
208
+ )
209
+ )
210
+ failed = await coordinator.acquire("installation-a")
211
+ await failed.record_failure()
212
+ probe = await asyncio.wait_for(
213
+ coordinator.acquire("installation-a"),
214
+ timeout=1,
215
+ )
216
+ assert probe.is_half_open_probe is True
217
+
218
+ await coordinator._state_lock.acquire()
219
+ abandon_task = asyncio.create_task(probe.abandon())
220
+ await asyncio.sleep(0)
221
+ abandon_task.cancel()
222
+ await asyncio.sleep(0)
223
+ abandon_task.cancel()
224
+ coordinator._state_lock.release()
225
+
226
+ with pytest.raises(asyncio.CancelledError):
227
+ await abandon_task
228
+ assert coordinator.snapshot()["half_open_probe_inflight"] is False
229
+
230
+ replacement = await asyncio.wait_for(
231
+ coordinator.acquire("installation-a"),
232
+ timeout=1,
233
+ )
234
+ await replacement.abandon()
235
+
236
+
201
237
  async def test_cancelled_acquire_does_not_leak_launch_slot():
202
238
  coordinator = PluginRestartCoordinator()
203
239
  coordinator.configure(
@@ -22,6 +22,7 @@ from langbot_plugin.runtime.plugin.worker_launcher import (
22
22
  PluginWorkerLauncher,
23
23
  )
24
24
  from langbot_plugin.runtime.security import (
25
+ PLUGIN_FILE_STORAGE_DIR_ENV,
25
26
  PLUGIN_REGISTRATION_CAPABILITY_ENV,
26
27
  PLUGIN_RUNTIME_PROFILE_ENV,
27
28
  )
@@ -327,6 +328,7 @@ def test_launcher_builds_profile_specific_controllers(tmp_path):
327
328
  assert oss_controller.command == sys.executable
328
329
  assert oss_controller.working_dir == str(launch_spec.artifact.code_path)
329
330
  assert oss_controller.env == {
331
+ PLUGIN_FILE_STORAGE_DIR_ENV: str(launch_spec.paths.root_path / "rpc-transfer"),
330
332
  PLUGIN_REGISTRATION_CAPABILITY_ENV: "capability-value",
331
333
  PLUGIN_RUNTIME_PROFILE_ENV: "oss_dev",
332
334
  }
@@ -1 +0,0 @@
1
- __version__ = "0.5.2"
File without changes
File without changes
File without changes
File without changes