From 34302213aee65772d80fd625f6fa7ae0301ad94c Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Thu, 21 May 2026 13:21:03 +0800 Subject: [PATCH] refactor(box): launch box runtime via the lbp CLI subcommand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror the plugin runtime: box is now started through the same CLI entry point (langbot_plugin.cli) instead of the box module directly. - docker-compose.yaml: langbot_box command runs `langbot_plugin.cli ... box` (WebSocket is the default transport, no flag needed — matches `rt`). - box/connector.py: both subprocess launch sites (_start_local_stdio and the Windows _start_subprocess_then_ws path) invoke `langbot_plugin.cli.__init__ box`, using `-s` for the stdio transport. - docs/review: update stale `-m langbot_plugin.box[.server]` references. Pairs with the SDK change that removes box's direct-launch entry points (python -m langbot_plugin.box / .box.server) and the legacy --mode flag. --- docker/docker-compose.yaml | 7 ++++++- docs/review/box-architecture.md | 2 +- docs/review/box-vs-plugin-runtime.md | 2 +- src/langbot/pkg/box/connector.py | 10 ++++++++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index cfc58ba3..3fccee39 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -43,7 +43,12 @@ services: # The Box runtime does NOT read box.local.* from config.yaml or env; it # receives its configuration from LangBot via the INIT RPC action. # Do not add LANGBOT_BOX_* / BOX__* here — they would be silently ignored. - command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.box", "--mode", "ws"] + # Launched through the same CLI entry point as the plugin runtime + # (`langbot_plugin.cli.__init__ `). WebSocket is the default + # control transport — mirrors `rt`, which also runs with no flag. Pass + # `-s` / `--stdio-control` only for the stdio mode LangBot uses outside + # containers. + command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "box"] networks: - langbot_network diff --git a/docs/review/box-architecture.md b/docs/review/box-architecture.md index d2ff5b12..5b4f82ca 100644 --- a/docs/review/box-architecture.md +++ b/docs/review/box-architecture.md @@ -142,7 +142,7 @@ BoxService 管理与 Box Runtime 的通信连接: -- **本地 stdio**: Unix/macOS 默认路径,fork `python -m langbot_plugin.box --port {port}` 子进程 +- **本地 stdio**: Unix/macOS 默认路径,fork `python -m langbot_plugin.cli.__init__ box -s --ws-control-port {port}` 子进程(与 plugin runtime 统一走 `lbp` CLI 入口) - **本地 subprocess + WS**: Windows 本地(asyncio ProactorEventLoop 不支持 stdio pipe) - **远程 WebSocket**: Docker 部署 / `box.runtime.endpoint` 显式配置时,连接 `ws://{host}:{port}/rpc/ws` - **同步等待**: `asyncio.Event` + `wait_for(timeout=30s)` 模式确认连接 diff --git a/docs/review/box-vs-plugin-runtime.md b/docs/review/box-vs-plugin-runtime.md index 66e644ea..622a425f 100644 --- a/docs/review/box-vs-plugin-runtime.md +++ b/docs/review/box-vs-plugin-runtime.md @@ -75,7 +75,7 @@ else: ``` connector._start_local_stdio() ├─ connected = asyncio.Event() - ├─ ctrl = StdioClientController(python, ['-m', 'langbot_plugin.box.server', '--port', N]) + ├─ ctrl = StdioClientController(python, ['-m', 'langbot_plugin.cli.__init__', 'box', '-s', '--ws-control-port', N]) ├─ _ctrl_task = create_task(ctrl.run(callback)) │ callback: │ handler = Handler(connection) ← 基础 Handler, 无 disconnect_callback diff --git a/src/langbot/pkg/box/connector.py b/src/langbot/pkg/box/connector.py index 61c269ea..deda0b89 100644 --- a/src/langbot/pkg/box/connector.py +++ b/src/langbot/pkg/box/connector.py @@ -181,7 +181,10 @@ class BoxRuntimeConnector(ManagedRuntimeConnector): ctrl = StdioClientController( command=python_path, - args=['-m', 'langbot_plugin.box.server', '--stdio-control', '--ws-control-port', str(self._relay_port)], + # Launched through the same CLI entry point as the plugin runtime + # (cli.__init__ ); `-s` selects the stdio transport, + # mirroring `rt -s`. + args=['-m', 'langbot_plugin.cli.__init__', 'box', '-s', '--ws-control-port', str(self._relay_port)], env=env, ) self._ctrl_task = asyncio.create_task( @@ -207,10 +210,13 @@ class BoxRuntimeConnector(ManagedRuntimeConnector): env['LANGBOT_BOX_CONFIG'] = json.dumps(self._filtered_box_config) python_path = sys.executable + # Launched through the same CLI entry point as the plugin runtime + # (cli.__init__ ); no flag => WebSocket transport. self.runtime_subprocess = await asyncio.create_subprocess_exec( python_path, '-m', - 'langbot_plugin.box.server', + 'langbot_plugin.cli.__init__', + 'box', '--ws-control-port', str(self._relay_port), env=env,