langbot-plugin 0.4.1__tar.gz → 0.4.2b2__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 (235) hide show
  1. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/AGENTS.md +136 -61
  2. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/PKG-INFO +1 -1
  3. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/pyproject.toml +1 -1
  4. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/nsjail_backend.py +54 -14
  5. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_nsjail_backend.py +70 -18
  6. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.github/workflows/publish-pypi.yaml +0 -0
  7. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.github/workflows/test.yml +0 -0
  8. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.gitignore +0 -0
  9. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/.python-version +0 -0
  10. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/CLAUDE.md +0 -0
  11. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/LICENSE +0 -0
  12. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/README.md +0 -0
  13. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/data/.env.example +0 -0
  14. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/Message.md +0 -0
  15. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/PluginPages.md +0 -0
  16. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/communication/apis/lb2rt.md +0 -0
  17. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/communication/runtime_plugin.md +0 -0
  18. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/dependency-management.md +0 -0
  19. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/docs/langbot-plugin-social.png +0 -0
  20. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/__init__.py +0 -0
  21. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/__init__.py +0 -0
  22. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/__init__.py +0 -0
  23. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/__init__.py +0 -0
  24. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/platform/__init__.py +0 -0
  25. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/platform/adapter.py +0 -0
  26. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/abstract/platform/event_logger.py +0 -0
  27. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/__init__.py +0 -0
  28. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/base.py +0 -0
  29. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/command/__init__.py +0 -0
  30. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/command/command.py +0 -0
  31. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/common/__init__.py +0 -0
  32. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/common/event_listener.py +0 -0
  33. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/knowledge_engine/__init__.py +0 -0
  34. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/knowledge_engine/engine.py +0 -0
  35. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/manifest.py +0 -0
  36. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/page/__init__.py +0 -0
  37. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/parser/__init__.py +0 -0
  38. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/parser/parser.py +0 -0
  39. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/tool/__init__.py +0 -0
  40. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/components/tool/tool.py +0 -0
  41. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/definition/plugin.py +0 -0
  42. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/__init__.py +0 -0
  43. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/__init__.py +0 -0
  44. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/command/__init__.py +0 -0
  45. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/command/context.py +0 -0
  46. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/command/errors.py +0 -0
  47. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/pipeline/__init__.py +0 -0
  48. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/pipeline/query.py +0 -0
  49. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/__init__.py +0 -0
  50. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/entities.py +0 -0
  51. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/events.py +0 -0
  52. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/logger.py +0 -0
  53. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/platform/message.py +0 -0
  54. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/__init__.py +0 -0
  55. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/message.py +0 -0
  56. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/prompt.py +0 -0
  57. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/provider/session.py +0 -0
  58. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/__init__.py +0 -0
  59. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/context.py +0 -0
  60. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/enums.py +0 -0
  61. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/errors.py +0 -0
  62. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/rag/models.py +0 -0
  63. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/resource/__init__.py +0 -0
  64. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/builtin/resource/tool.py +0 -0
  65. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/context.py +0 -0
  66. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/entities/events.py +0 -0
  67. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/__init__.py +0 -0
  68. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/base.py +0 -0
  69. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/event_context.py +0 -0
  70. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/execute_context.py +0 -0
  71. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/langbot_api.py +0 -0
  72. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/api/proxies/query_based_api.py +0 -0
  73. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/__init__.py +0 -0
  74. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/langbot-page-sdk.js +0 -0
  75. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/.env.example.example +0 -0
  76. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/.gitignore.example +0 -0
  77. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/.vscode/launch.json.example +0 -0
  78. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/README.md.example +0 -0
  79. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/__init__.py +0 -0
  80. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/assets/icon.svg.example +0 -0
  81. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/__init__.py +0 -0
  82. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/commands/__init__.py +0 -0
  83. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.py.example +0 -0
  84. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/commands/{cmd_name}.yaml.example +0 -0
  85. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/event_listener/__init__.py +0 -0
  86. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/event_listener/default.py.example +0 -0
  87. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/event_listener/default.yaml.example +0 -0
  88. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/knowledge_engine/__init__.py +0 -0
  89. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.py.example +0 -0
  90. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/knowledge_engine/{knowledge_engine_name}.yaml.example +0 -0
  91. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.html.example +0 -0
  92. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/pages/{page_name}.yaml.example +0 -0
  93. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/parser/__init__.py +0 -0
  94. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.py.example +0 -0
  95. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/parser/{parser_name}.yaml.example +0 -0
  96. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/tools/__init__.py +0 -0
  97. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.py.example +0 -0
  98. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/components/tools/{tool_name}.yaml.example +0 -0
  99. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/main.py.example +0 -0
  100. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/manifest.yaml.example +0 -0
  101. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/assets/templates/requirements.txt.example +0 -0
  102. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/__init__.py +0 -0
  103. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/actions.py +0 -0
  104. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/backend.py +0 -0
  105. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/client.py +0 -0
  106. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/e2b_backend.py +0 -0
  107. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/errors.py +0 -0
  108. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/models.py +0 -0
  109. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/runtime.py +0 -0
  110. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/security.py +0 -0
  111. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/server.py +0 -0
  112. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/box/skill_store.py +0 -0
  113. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/__init__.py +0 -0
  114. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/__main__.py +0 -0
  115. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/__init__.py +0 -0
  116. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/buildplugin.py +0 -0
  117. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/gencomponent.py +0 -0
  118. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/initplugin.py +0 -0
  119. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/login.py +0 -0
  120. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/logout.py +0 -0
  121. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/publish.py +0 -0
  122. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/commands/runplugin.py +0 -0
  123. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/gen/__init__.py +0 -0
  124. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/gen/renderer.py +0 -0
  125. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/i18n.py +0 -0
  126. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/__init__.py +0 -0
  127. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/en_US.py +0 -0
  128. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/es_ES.py +0 -0
  129. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/ja_JP.py +0 -0
  130. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/th_TH.py +0 -0
  131. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/vi_VN.py +0 -0
  132. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/zh_Hans.py +0 -0
  133. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/locales/zh_Hant.py +0 -0
  134. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/__init__.py +0 -0
  135. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/controller.py +0 -0
  136. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/handler.py +0 -0
  137. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/run/hotreload.py +0 -0
  138. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/__init__.py +0 -0
  139. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/cloudsv.py +0 -0
  140. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/form.py +0 -0
  141. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/cli/utils/page_components.py +0 -0
  142. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/__init__.py +0 -0
  143. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/__init__.py +0 -0
  144. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/actions/__init__.py +0 -0
  145. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/actions/enums.py +0 -0
  146. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/errors.py +0 -0
  147. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/req.py +0 -0
  148. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/io/resp.py +0 -0
  149. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/entities/marketplace.py +0 -0
  150. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/LICENSE +0 -0
  151. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/README.md +0 -0
  152. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/__init__.py +0 -0
  153. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/app.py +0 -0
  154. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/context.py +0 -0
  155. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/helper/__init__.py +0 -0
  156. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/helper/marketplace.py +0 -0
  157. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/helper/pkgmgr.py +0 -0
  158. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/__init__.py +0 -0
  159. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connection.py +0 -0
  160. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connections/__init__.py +0 -0
  161. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connections/stdio.py +0 -0
  162. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/connections/ws.py +0 -0
  163. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controller.py +0 -0
  164. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/__init__.py +0 -0
  165. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/stdio/__init__.py +0 -0
  166. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/stdio/client.py +0 -0
  167. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/stdio/server.py +0 -0
  168. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/ws/__init__.py +0 -0
  169. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/ws/client.py +0 -0
  170. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/controllers/ws/server.py +0 -0
  171. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handler.py +0 -0
  172. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handlers/__init__.py +0 -0
  173. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handlers/control.py +0 -0
  174. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/io/handlers/plugin.py +0 -0
  175. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/plugin/__init__.py +0 -0
  176. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/plugin/container.py +0 -0
  177. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/plugin/mgr.py +0 -0
  178. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/runtime/settings.py +0 -0
  179. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/__init__.py +0 -0
  180. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/discover/__init__.py +0 -0
  181. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/discover/engine.py +0 -0
  182. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/importutil.py +0 -0
  183. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/log.py +0 -0
  184. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/utils/platform.py +0 -0
  185. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/src/langbot_plugin/version.py +0 -0
  186. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/__init__.py +0 -0
  187. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/definition/components/test_components.py +0 -0
  188. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/definition/test_manifest.py +0 -0
  189. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_command_context.py +0 -0
  190. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_platform_logger.py +0 -0
  191. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_provider_message.py +0 -0
  192. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/builtin/test_rag_models.py +0 -0
  193. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/test_context.py +0 -0
  194. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/entities/test_events.py +0 -0
  195. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/proxies/test_base.py +0 -0
  196. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/proxies/test_langbot_api.py +0 -0
  197. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/api/proxies/test_query_based_api.py +0 -0
  198. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/__init__.py +0 -0
  199. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_backend.py +0 -0
  200. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_backend_selection.py +0 -0
  201. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_client.py +0 -0
  202. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_e2b_backend.py +0 -0
  203. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_runtime.py +0 -0
  204. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_server.py +0 -0
  205. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/box/test_skill_store.py +0 -0
  206. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/run/test_controller.py +0 -0
  207. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/run/test_runtime_handler.py +0 -0
  208. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_buildplugin.py +0 -0
  209. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_gencomponent.py +0 -0
  210. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_i18n_form.py +0 -0
  211. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_initplugin.py +0 -0
  212. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_login.py +0 -0
  213. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_logout_publish.py +0 -0
  214. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_page_components.py +0 -0
  215. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_renderer.py +0 -0
  216. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/cli/test_runplugin.py +0 -0
  217. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/entities/io/test_protocol.py +0 -0
  218. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/helpers/__init__.py +0 -0
  219. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/helpers/protocol.py +0 -0
  220. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/helper/test_marketplace.py +0 -0
  221. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/helper/test_pkgmgr.py +0 -0
  222. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/handlers/test_control_handler.py +0 -0
  223. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/handlers/test_import_contracts.py +0 -0
  224. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/handlers/test_plugin_handler.py +0 -0
  225. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/test_connections.py +0 -0
  226. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/test_controllers.py +0 -0
  227. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/io/test_handler.py +0 -0
  228. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/plugin/test_container.py +0 -0
  229. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/plugin/test_manager.py +0 -0
  230. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/runtime/test_app.py +0 -0
  231. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/test_log.py +0 -0
  232. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/test_message.py +0 -0
  233. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/utils/test_discovery.py +0 -0
  234. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/utils/test_importutil.py +0 -0
  235. {langbot_plugin-0.4.1 → langbot_plugin-0.4.2b2}/tests/utils/test_platform.py +0 -0
@@ -1,21 +1,29 @@
1
1
  # AGENTS.md
2
2
 
3
- This file is for guiding code agents (like Claude Code, GitHub Copilot, OpenAI Codex, etc.) to work in the langbot-plugin-sdk project.
3
+ This file is for guiding code agents (like Claude Code, GitHub Copilot, OpenAI Codex, etc.) to work in the langbot-plugin-sdk project. `CLAUDE.md` is a symlink to this file.
4
4
 
5
- **IMPORTANT**: This document may contain outdated information and may differ from the actual content. Please refer to the actual situation for accuracy.
5
+ > Always verify specifics (file paths, CLI flags, function signatures) against the actual source before relying on them. When you find this doc out of date, fix it as part of your change.
6
6
 
7
7
  ## Project Overview
8
8
 
9
9
  LangBot Plugin SDK is the infrastructure for LangBot's plugin system, providing:
10
10
  - **Plugin SDK**: Python APIs and interfaces for plugin development
11
- - **Plugin Runtime**: Execution environment managing plugin lifecycle
12
- - **CLI Tools**: `lbp` command for scaffolding, building, and debugging plugins
11
+ - **Plugin Runtime**: Execution environment managing plugin lifecycle (`lbp rt`)
12
+ - **Box Runtime**: Code-sandbox runtime service backing LangBot's Box subsystem (`lbp box`)
13
+ - **CLI Tools**: `lbp` command for scaffolding, building, debugging, and running runtimes
13
14
  - **Communication Protocol**: Bidirectional action-based protocol (stdio/WebSocket)
14
15
 
15
- The SDK enables developers to extend LangBot with custom:
16
- - **Commands**: User-triggered actions (e.g., `!weather tokyo`)
17
- - **Tools**: LLM-callable functions for AI agents (e.g., web search, database queries)
18
- - **Event Listeners**: Handlers for message events (e.g., auto-reply, content filtering)
16
+ This SDK is the shared dependency between LangBot and plugins; LangBot pins it as `langbot-plugin==<x.y.z>` in its `pyproject.toml`. The package version lives in this repo's `pyproject.toml`.
17
+
18
+ The SDK enables developers to extend LangBot with custom components. Six component types are supported (scaffold any of them with `lbp comp <Type>`):
19
+ - **Command**: User-triggered actions (e.g., `!weather tokyo`)
20
+ - **Tool**: LLM-callable functions for AI agents (e.g., web search, database queries)
21
+ - **EventListener**: Handlers for message-pipeline events (e.g., auto-reply, content filtering)
22
+ - **KnowledgeEngine**: Custom knowledge-base retrieval/integration used by RAG
23
+ - **Parser**: Custom parsing of messages/content
24
+ - **Page**: Custom web page embeddable in the LangBot admin panel
25
+
26
+ Component base classes live in `src/langbot_plugin/api/definition/components/` (`command/`, `tool/`, `common/event_listener.py`, `knowledge_engine/`, `parser/`, `page/`).
19
27
 
20
28
  ## Technology Stack
21
29
 
@@ -47,31 +55,33 @@ langbot-plugin-sdk/
47
55
  │ │ │ ├── command/ # CommandReturn
48
56
  │ │ │ └── provider/ # Session, Conversation
49
57
  │ │ └── proxies/ # API proxy classes
50
- │ │ ├── langbot_api.py # LangBotAPIProxy
51
- │ │ └── query_based.py # QueryBasedAPIProxy
52
58
  │ ├── runtime/ # Plugin runtime system
53
- │ │ ├── plugin/ # Plugin management
54
- │ │ ├── mgr.py # PluginManager
55
- │ │ │ ├── container.py # PluginContainer
56
- │ │ │ └── installer.py # Plugin installation
59
+ │ │ ├── app.py # `lbp rt` entrypoint (runtime_app.main)
60
+ │ │ ├── plugin/ # Plugin management (mgr.py, container.py, installer)
57
61
  │ │ ├── io/ # Communication layer
58
- │ │ │ ├── handler.py # Action handler
59
- │ │ │ ├── stdio.py # Stdio transport
60
- │ │ │ └── websocket.py # WebSocket transport
61
- │ │ └── event/ # Event dispatching
62
- ├── cli/ # Command-line tools
63
- ├── main.py # lbp entrypoint
64
- │ │ ├── init.py # Plugin initialization
65
- │ │ ├── gen/ # Component generation
66
- │ │ └── run.py # Plugin debugging
62
+ │ │ │ ├── connection.py # Base connection
63
+ │ │ │ ├── connections/ # stdio / ws connection impls
64
+ │ │ │ ├── controller.py , controllers/ # client/server controllers (stdio, ws)
65
+ │ │ │ ├── handler.py , handlers/ # action handlers
66
+ │ └── helper/
67
+ │ ├── box/ # Box (code-sandbox) runtime — `lbp box`
68
+ │ │ ├── server.py # `lbp box` entrypoint (box_main)
69
+ │ │ ├── backend.py # Backend abstraction + selection (Docker handled here/runtime)
70
+ │ │ ├── nsjail_backend.py / e2b_backend.py # sandbox backend impls
71
+ │ │ ├── runtime.py , client.py , actions.py , models.py , errors.py , security.py , skill_store.py
72
+ │ ├── cli/ # Command-line tools (`lbp`)
73
+ │ │ ├── __init__.py # lbp entrypoint + argparse subcommands
74
+ │ │ ├── commands/ # init / comp / build / publish / login / logout impls
75
+ │ │ ├── run/ # plugin run (remote-debug) impl
76
+ │ │ ├── gen/ # component generation (Jinja2)
77
+ │ │ ├── i18n.py , locales/ # CLI i18n
78
+ │ │ └── utils/
67
79
  │ ├── entities/ # Internal data structures
68
- │ │ ├── io/ # Communication protocol
69
- │ └── plugin/ # Plugin metadata
70
- │ └── utils/ # Utilities
71
- │ ├── discover/ # Component discovery
72
- │ └── network/ # Network helpers
80
+ │ │ └── io/ # Communication protocol (actions, errors, resp)
81
+ ├── assets/templates/ # Plugin scaffolding templates
82
+ │ └── utils/ # Utilities (discover/, network, log, ...)
73
83
  ├── docs/ # Documentation
74
- ├── pyproject.toml # Python project config
84
+ ├── pyproject.toml # Python project config (version, requires-python >=3.10)
75
85
  └── README.md
76
86
  ```
77
87
 
@@ -113,12 +123,12 @@ langbot-plugin-sdk/
113
123
 
114
124
  ```
115
125
  BasePlugin
116
- ├── Command (1+ per plugin)
117
- │ └── Subcommand handlers
118
- ├── Tool (0+ per plugin)
119
- │ └── call() method
120
- └── EventListener (1 per plugin)
121
- └── Event handlers
126
+ ├── Command Subcommand handlers
127
+ ├── Tool → call() method
128
+ ├── EventListener → event handlers
129
+ ├── KnowledgeEngine → knowledge-base retrieval/integration (RAG)
130
+ ├── Parser → message/content parsing
131
+ └── Page → custom admin-panel web page
122
132
  ```
123
133
 
124
134
  ## SDK Development
@@ -837,53 +847,118 @@ Encapsulates plugin instance with:
837
847
 
838
848
  ## CLI Tools
839
849
 
840
- ### lbp Commands
850
+ ### `lbp` Commands
841
851
 
842
852
  ```bash
843
- # Initialize new plugin
844
- lbp init [plugin_name]
853
+ lbp init [plugin_name] # Scaffold a new plugin
854
+ lbp comp <Command|Tool|EventListener> # Generate a component
855
+ lbp run [-s] # Run/remote-debug the plugin against a running Runtime
856
+ lbp build [-o dist] # Build the plugin into a zip
857
+ lbp publish [-o dist] # Publish to LangBot Marketplace (login first: lbp login)
858
+ lbp login [-t TOKEN] / lbp logout # Marketplace account auth
859
+ lbp rt [...] # Run the Plugin Runtime (see below)
860
+ lbp box [...] # Run the Box (sandbox) Runtime (see below)
861
+ lbp ver # Print SDK version
862
+ ```
845
863
 
846
- # Generate component
847
- lbp comp [Command|Tool|EventListener]
864
+ The CLI entrypoint is `src/langbot_plugin/cli/__init__.py` (argparse). `lbp rt` dispatches to `langbot_plugin.runtime.app.main`; `lbp box` dispatches to `langbot_plugin.box.server.main`. Subcommand implementations live under `cli/commands/`, `cli/run/`, and `cli/gen/`.
848
865
 
849
- # Run plugin locally (requires running LangBot)
850
- lbp run [-s]
866
+ ## Debugging the Runtime, CLI & SDK
851
867
 
852
- # Build plugin for distribution
853
- lbp build
868
+ This is the canonical place for runtime/CLI/box debugging detail (LangBot's own `AGENTS.md` only indexes this section). The corresponding user-facing wiki page is ["调试插件运行时、CLI、SDK"](https://docs.langbot.app/zh/develop/plugin-runtime).
854
869
 
855
- # Publish to marketplace
856
- lbp publish
870
+ ### Recommended workspace layout
857
871
 
858
- # Start runtime (for WebSocket mode)
859
- lbp rt
872
+ Because LangBot depends on entities defined here, clone both repos as siblings under one parent dir and open that parent in your editor:
873
+
874
+ ```
875
+ langbot-projects/
876
+ ├── LangBot
877
+ └── langbot-plugin-sdk
860
878
  ```
861
879
 
862
- ### Template System (`cli/gen/`)
880
+ Set up LangBot's venv (`cd LangBot && uv sync --dev`) and point your editor's Python interpreter at LangBot's `.venv`.
881
+
882
+ ### Plugin Runtime — `lbp rt`
863
883
 
864
- - Jinja2-based templates in `assets/templates/`
865
- - Variables: plugin_name, plugin_author, component_name
866
- - Generates boilerplate code and manifests
884
+ Start a standalone Plugin Runtime from this repo:
867
885
 
868
- ## Testing & Debugging
886
+ ```bash
887
+ uv run --no-sync lbp rt
888
+ # equivalent: python -m langbot_plugin.cli.__init__ rt
889
+ ```
869
890
 
870
- ### Local Testing
891
+ `lbp rt` flags (see `cli/__init__.py`):
892
+
893
+ - `-s`, `--stdio-control`: use stdio for the control connection. **Production only** — in a container LangBot pipes the runtime over stdio.
894
+ - `--ws-control-port` (default `5400`): control port LangBot's main process connects to.
895
+ - `--ws-debug-port` (default `5401`): debug port for `lbp run` to attach a plugin under development.
896
+ - `--debug-only`: do not auto-start plugins in `data/plugins/`; only accept plugins via debug connections.
897
+ - `--skip-deps-check`: skip the per-startup check/install of every installed plugin's dependencies.
898
+ - `--pypi-index-url` / `--pypi-trusted-host`: customize the index used for plugin dependency installs.
899
+
900
+ > **Transport note:** When LangBot is run directly (not in a container), it spawns the runtime itself and talks **stdio**, which **cannot auto-reconnect** — on disconnect it logs "please restart LangBot". A frequent cause is an **orphan runtime** from a previous backend still holding `5400`/`5401`; kill it and restart.
901
+
902
+ ### Make LangBot use your locally-modified SDK
903
+
904
+ If you change shared definitions (message entities, plugin data models, etc.), install your local SDK into LangBot's environment so data formats stay compatible at runtime:
871
905
 
872
- 1. Start LangBot:
873
906
  ```bash
874
- cd /path/to/LangBot
875
- uv run main.py
907
+ # In a terminal where LangBot's .venv is ACTIVE, from the langbot-plugin-sdk dir:
908
+ uv pip install .
876
909
  ```
877
910
 
878
- 2. Run plugin:
911
+ ### Make LangBot connect to your standalone Runtime (WebSocket)
912
+
913
+ 1. In LangBot's `data/config.yaml`, set the control URL:
914
+
915
+ ```yaml
916
+ plugin:
917
+ runtime_ws_url: ws://localhost:5400/control/ws
918
+ ```
919
+
920
+ 2. Launch LangBot with `--standalone-runtime` and `--no-sync` (the latter prevents `uv` from overwriting your locally-installed SDK):
921
+
922
+ ```bash
923
+ uv run --no-sync main.py --standalone-runtime
924
+ ```
925
+
926
+ Restart LangBot; it now connects to your `lbp rt` over WebSocket, so you can iterate on the runtime/SDK independently.
927
+
928
+ ### Box Runtime — `lbp box`
929
+
930
+ The Box Runtime is the sandbox service backing LangBot's `pkg/box` subsystem (`src/langbot_plugin/box/`). Start it with:
931
+
932
+ ```bash
933
+ lbp box # WebSocket control transport (default)
934
+ lbp box -s # stdio control transport
935
+ ```
936
+
937
+ `lbp box` flags:
938
+
939
+ - `--host` (default `0.0.0.0`): bind address.
940
+ - `-s`, `--stdio-control`: use stdio for the control connection (instead of WebSocket).
941
+ - `--ws-control-port` (default `5410`): control port.
942
+
943
+ All Box WebSocket endpoints share one port (default `5410`): `/rpc/ws` (action RPC control channel) plus managed-process stdio relay endpoints under `/v1/sessions/...`. There is **no** `python -m langbot_plugin.box` launch path — `lbp box` is the only supported entrypoint.
944
+
945
+ Box selects the first available sandbox backend among **Docker / nsjail / E2B**. Backends live in `box/backend.py`, `box/nsjail_backend.py`, `box/e2b_backend.py`. A common false "no backend" on the LangBot side is Docker running but the user not in the `docker` group (socket permission denied) — that's a host-permissions issue, not a Box bug.
946
+
947
+ To make LangBot connect to a standalone Box runtime (mirrors the plugin-runtime flow): in LangBot's `data/config.yaml` set `box.runtime.endpoint` to the runtime's base URL (e.g. `ws://127.0.0.1:5410`), pick `box.backend` (`'local'`/`'docker'`/`'nsjail'`/`'e2b'`), and start LangBot with `--standalone-box`. In Docker deployments LangBot reaches the Box runtime at host `langbot_box:5410`.
948
+
949
+ ### Plugin development loop
950
+
879
951
  ```bash
952
+ # 1. Start a LangBot instance (which spawns or connects to a Runtime)
953
+ cd /path/to/LangBot
954
+ uv run main.py
955
+
956
+ # 2. In your plugin dir, attach it to the Runtime's debug port for live debugging
880
957
  cd /path/to/your-plugin
881
958
  lbp run
882
959
  ```
883
960
 
884
- Plugin connects to LangBot via stdio for testing.
885
-
886
- ### Debugging Tips
961
+ ### Debugging tips
887
962
 
888
963
  - Use `print()` statements (output to stderr for visibility)
889
964
  - Check LangBot logs for plugin errors
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langbot-plugin
3
- Version: 0.4.1
3
+ Version: 0.4.2b2
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.4.1"
3
+ version = "0.4.2b2"
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 = [
@@ -116,6 +116,19 @@ class NsjailBackend(BaseSandboxBackend):
116
116
  for d in (root_dir, workspace_dir, tmp_dir, home_dir):
117
117
  d.mkdir(parents=True, exist_ok=True)
118
118
 
119
+ # When a host_path is mounted into the sandbox it becomes the nsjail
120
+ # bind-mount source (see _build_mounts). nsjail requires the source to
121
+ # already exist on the host, otherwise the bind-mount fails and the
122
+ # command exits 255 with no stdout/stderr. The per-session loop above
123
+ # never creates host_path (it lives outside session_dir), so ensure it
124
+ # exists here. Read-only mounts intentionally are NOT auto-created: a
125
+ # missing read-only source is a caller error that should surface.
126
+ if (
127
+ spec.host_path is not None
128
+ and spec.host_path_mode == BoxHostMountMode.READ_WRITE
129
+ ):
130
+ os.makedirs(spec.host_path, exist_ok=True)
131
+
119
132
  # If host_path is specified, we will use it directly instead of the
120
133
  # per-session workspace when building nsjail args (see _build_mounts).
121
134
  meta = {
@@ -424,14 +437,24 @@ class NsjailBackend(BaseSandboxBackend):
424
437
  args: list[str] = []
425
438
 
426
439
  if self._cgroup_v2_available:
427
- # cgroup v2 – precise limits.
440
+ # cgroup v2 – precise limits. nsjail defaults to the legacy cgroup
441
+ # v1 layout, so we MUST opt into v2 explicitly; without this flag
442
+ # nsjail tries to mkdir under /sys/fs/cgroup/<controller>/... (v1
443
+ # paths) and aborts on a v2-only host. The writability of the v2
444
+ # root is already verified in _detect_cgroup_v2().
445
+ args.append('--use_cgroupv2')
428
446
  memory_bytes = spec.memory_mb * 1024 * 1024
429
447
  args.extend(['--cgroup_mem_max', str(memory_bytes)])
430
448
  args.extend(['--cgroup_pids_max', str(spec.pids_limit)])
431
449
  cpu_ms = int(spec.cpus * 1000)
432
450
  args.extend(['--cgroup_cpu_ms_per_sec', str(cpu_ms)])
433
451
  else:
434
- # rlimit fallback – best-effort.
452
+ # rlimit fallback – best-effort. Used whenever the cgroup v2 root is
453
+ # not writable (the typical containerized case: /sys/fs/cgroup is
454
+ # mounted read-only), so the sandbox still launches with coarse
455
+ # resource caps instead of failing outright.
456
+ # --rlimit_as takes a value in MB (nsjail interprets the bare number
457
+ # as megabytes), matching spec.memory_mb directly.
435
458
  args.extend(['--rlimit_as', str(spec.memory_mb)])
436
459
  args.extend(['--rlimit_nproc', str(spec.pids_limit)])
437
460
 
@@ -478,25 +501,42 @@ class NsjailBackend(BaseSandboxBackend):
478
501
 
479
502
  @staticmethod
480
503
  def _detect_cgroup_v2() -> bool:
481
- """Check whether the host runs cgroup v2 and we can write to it."""
504
+ """Check whether cgroup v2 is present AND nsjail can create a cgroup.
505
+
506
+ nsjail (with ``--use_cgroupv2``) creates its own child cgroup by
507
+ ``mkdir``-ing directly under the cgroup v2 mount root, then writes to
508
+ ``cgroup.subtree_control``. Merely detecting a cgroup v2 hierarchy is
509
+ not enough: inside most containers (Docker/k8s default) ``/sys/fs/cgroup``
510
+ is mounted **read-only**, so the mkdir fails and the whole sandbox
511
+ aborts. We must therefore probe real writability — running as root is
512
+ NOT sufficient, because a read-only bind mount denies root too.
513
+
514
+ Returns True only when we can actually create (and remove) a directory
515
+ under the cgroup v2 root, which is exactly what nsjail needs.
516
+ """
482
517
  cgroup_mount = pathlib.Path('/sys/fs/cgroup')
483
518
  if not cgroup_mount.exists():
484
519
  return False
485
- # cgroup v2 has a single hierarchy with cgroup.controllers file.
520
+ # cgroup v2 has a single hierarchy with a cgroup.controllers file.
486
521
  controllers = cgroup_mount / 'cgroup.controllers'
487
522
  if not controllers.exists():
488
523
  return False
489
- # Check if we can write to a cgroup subtree (needed for nsjail).
490
- # A rough heuristic: if the user owns a cgroup directory we're probably
491
- # running under systemd user delegation.
492
- user_slice = cgroup_mount / f'user.slice/user-{os.getuid()}.slice'
493
- if user_slice.exists() and os.access(user_slice, os.W_OK):
494
- return True
495
- # If running as root (uid 0), cgroup v2 is always usable.
496
- if os.getuid() == 0:
524
+ # Authoritative writability probe: try to create and remove a throwaway
525
+ # cgroup directory under the root, mirroring what nsjail does. This
526
+ # correctly reports False on a read-only /sys/fs/cgroup (the common
527
+ # containerized case) so the backend falls back to rlimit limits
528
+ # instead of selecting a cgroup path that is guaranteed to fail.
529
+ probe = cgroup_mount / f'.langbot-box-probe-{os.getpid()}'
530
+ try:
531
+ probe.mkdir(mode=0o700)
532
+ except Exception:
533
+ return False
534
+ else:
535
+ try:
536
+ probe.rmdir()
537
+ except Exception:
538
+ pass
497
539
  return True
498
- # Conservative: if we can't confirm writability, report unavailable.
499
- return False
500
540
 
501
541
  async def _kill_session_processes(self, session_dir: pathlib.Path) -> None:
502
542
  """Best-effort kill of nsjail processes associated with a session dir.
@@ -93,20 +93,62 @@ async def test_start_session_creates_directories(backend, tmp_base):
93
93
  @pytest.mark.anyio
94
94
  async def test_start_session_with_host_path(backend, tmp_base):
95
95
  tmp_base.mkdir(parents=True, exist_ok=True)
96
+ host_path = str(tmp_base / 'rw_host')
96
97
  spec = BoxSpec(
97
98
  session_id='sess2',
98
99
  cmd='ls',
99
- host_path='/some/path',
100
+ host_path=host_path,
100
101
  host_path_mode=BoxHostMountMode.READ_WRITE,
101
102
  mount_path='/project',
102
103
  )
103
104
 
104
105
  info = await backend.start_session(spec)
105
- assert info.host_path == '/some/path'
106
+ assert info.host_path == host_path
106
107
  assert info.host_path_mode == BoxHostMountMode.READ_WRITE
107
108
  assert info.mount_path == '/project'
108
109
 
109
110
 
111
+ @pytest.mark.anyio
112
+ async def test_start_session_creates_missing_rw_host_path(backend, tmp_base):
113
+ """Regression: a read-write host_path that does not yet exist must be
114
+ created by start_session, otherwise nsjail's --bindmount source is missing
115
+ and the command exits 255 with no output (SaaS MCP shared-workspace bug)."""
116
+ tmp_base.mkdir(parents=True, exist_ok=True)
117
+ host_path = tmp_base / 'never_created' / 'workspace'
118
+ assert not host_path.exists()
119
+
120
+ spec = BoxSpec(
121
+ session_id='sess-mkdir',
122
+ cmd='ls',
123
+ host_path=str(host_path),
124
+ host_path_mode=BoxHostMountMode.READ_WRITE,
125
+ mount_path='/workspace',
126
+ )
127
+
128
+ await backend.start_session(spec)
129
+ assert host_path.is_dir()
130
+
131
+
132
+ @pytest.mark.anyio
133
+ async def test_start_session_does_not_create_ro_host_path(backend, tmp_base):
134
+ """A missing read-only host_path is a caller error and must NOT be silently
135
+ created — it should surface rather than mount an empty dir."""
136
+ tmp_base.mkdir(parents=True, exist_ok=True)
137
+ host_path = tmp_base / 'ro_missing'
138
+ assert not host_path.exists()
139
+
140
+ spec = BoxSpec(
141
+ session_id='sess-ro',
142
+ cmd='ls',
143
+ host_path=str(host_path),
144
+ host_path_mode=BoxHostMountMode.READ_ONLY,
145
+ mount_path='/project',
146
+ )
147
+
148
+ await backend.start_session(spec)
149
+ assert not host_path.exists()
150
+
151
+
110
152
  # ── stop_session ──────────────────────────────────────────────────────
111
153
 
112
154
  @pytest.mark.anyio
@@ -301,6 +343,9 @@ def test_build_resource_limits_cgroup(backend):
301
343
 
302
344
  args = backend._build_resource_limits(spec)
303
345
 
346
+ # Bug regression: cgroup v2 mode MUST opt in explicitly, otherwise nsjail
347
+ # falls back to the v1 layout and aborts on a v2-only host.
348
+ assert '--use_cgroupv2' in args
304
349
  assert '--cgroup_mem_max' in args
305
350
  mem_idx = args.index('--cgroup_mem_max')
306
351
  assert args[mem_idx + 1] == str(1024 * 1024 * 1024)
@@ -326,6 +371,7 @@ def test_build_resource_limits_rlimit_fallback(backend):
326
371
  assert args[nproc_idx + 1] == '128'
327
372
 
328
373
  # cgroup flags should NOT be present.
374
+ assert '--use_cgroupv2' not in args
329
375
  assert '--cgroup_mem_max' not in args
330
376
 
331
377
 
@@ -376,36 +422,42 @@ def test_detect_cgroup_v2_no_mount():
376
422
  assert NsjailBackend._detect_cgroup_v2() is False
377
423
 
378
424
 
379
- def test_detect_cgroup_v2_root_user():
380
- def always_exists(self):
381
- return True
425
+ def test_detect_cgroup_v2_writable():
426
+ """When the cgroup v2 root is writable (mkdir succeeds), report True.
427
+
428
+ This mirrors the only thing nsjail actually needs: the ability to create a
429
+ child cgroup under /sys/fs/cgroup. Being root is irrelevant on its own.
430
+ """
431
+ def fake_exists(self):
432
+ path = str(self)
433
+ return path == '/sys/fs/cgroup' or path.endswith('cgroup.controllers')
382
434
 
383
435
  with (
384
- mock.patch('os.getuid', return_value=0),
385
- mock.patch.object(pathlib.Path, 'exists', always_exists),
436
+ mock.patch.object(pathlib.Path, 'exists', fake_exists),
437
+ mock.patch.object(pathlib.Path, 'mkdir', return_value=None),
438
+ mock.patch.object(pathlib.Path, 'rmdir', return_value=None),
386
439
  ):
387
440
  assert NsjailBackend._detect_cgroup_v2() is True
388
441
 
389
442
 
390
- def test_detect_cgroup_v2_user_slice_must_be_writable():
443
+ def test_detect_cgroup_v2_readonly_root_returns_false():
444
+ """A read-only /sys/fs/cgroup (the default containerized case) must report
445
+ False so the backend falls back to rlimit limits instead of selecting a
446
+ cgroup path that nsjail cannot use. Root does NOT override a RO mount."""
391
447
  def fake_exists(self):
392
448
  path = str(self)
393
- return path == '/sys/fs/cgroup' or path.endswith('cgroup.controllers') or 'user.slice' in path
449
+ return path == '/sys/fs/cgroup' or path.endswith('cgroup.controllers')
394
450
 
395
451
  with (
396
- mock.patch('os.getuid', return_value=1000),
452
+ mock.patch('os.getuid', return_value=0),
397
453
  mock.patch.object(pathlib.Path, 'exists', fake_exists),
398
- mock.patch('os.access', return_value=False),
454
+ mock.patch.object(
455
+ pathlib.Path, 'mkdir',
456
+ side_effect=OSError('Read-only file system'),
457
+ ),
399
458
  ):
400
459
  assert NsjailBackend._detect_cgroup_v2() is False
401
460
 
402
- with (
403
- mock.patch('os.getuid', return_value=1000),
404
- mock.patch.object(pathlib.Path, 'exists', fake_exists),
405
- mock.patch('os.access', return_value=True),
406
- ):
407
- assert NsjailBackend._detect_cgroup_v2() is True
408
-
409
461
 
410
462
  # ── cleanup_orphaned_containers ───────────────────────────────────────
411
463
 
File without changes