Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
938a155
feat(box): add sandbox_exec tool loop for local-agent calculations
huanghuoguoguo Mar 19, 2026
c0a43a8
feat(box): add host workspace mounting and sandbox_exec guidance
huanghuoguoguo Mar 19, 2026
262a892
feat(box): add BoxProfile with resource limits and improved output tr…
huanghuoguoguo Mar 20, 2026
94f8148
feat(box): add obs
huanghuoguoguo Mar 20, 2026
64e312c
refactor(box): unify box service lifecycle and local runtime
huanghuoguoguo Mar 20, 2026
1e93a03
refactor(box): remove legacy in-process runtime code and clean up smells
huanghuoguoguo Mar 20, 2026
b64da58
feat: add test
huanghuoguoguo Mar 20, 2026
06ceaf3
fix: fix box intergration test
huanghuoguoguo Mar 20, 2026
fec8d03
feat(box/mcp): integrate MCP stdio with Box sandbox — auto-isolation,…
huanghuoguoguo Mar 21, 2026
094eeda
feat(box/mcp): instance-based orphan cleanup, error classification, s…
huanghuoguoguo Mar 21, 2026
70b114f
refactor: use rpc
huanghuoguoguo Mar 21, 2026
3b5647b
fix: import
huanghuoguoguo Mar 21, 2026
c0c8efb
refactor(box): clean up sandbox subsystem code quality and efficiency
huanghuoguoguo Mar 22, 2026
64dd19f
fix: ruff
huanghuoguoguo Mar 22, 2026
a1ec492
refactor(sandbox): keep box logic out of pipeline and localagent
huanghuoguoguo Mar 22, 2026
a07923b
fix: ruff
huanghuoguoguo Mar 22, 2026
206bf96
refactor(box): move box runtime to langbot-plugin-sdk
huanghuoguoguo Mar 22, 2026
4449697
fix: ruff
huanghuoguoguo Mar 22, 2026
f24357c
feat: enhance sandbox api
huanghuoguoguo Mar 24, 2026
4f0193e
refactor(box): derive paths from shared host root
huanghuoguoguo Mar 24, 2026
aa67309
fix(box): tighten sandbox exposure and restore box integration coverage
huanghuoguoguo Mar 24, 2026
eabc0c0
refactor(types): remove quoted annotations under postponed evaluation
huanghuoguoguo Mar 24, 2026
df952d5
feat(box): unify native agent tools around exec/read/write/edit
huanghuoguoguo Mar 24, 2026
2bd028d
chore(sandbox): move MCP loader changes to follow-up branch
huanghuoguoguo Mar 26, 2026
067d50e
feat(box): add session workspace quota enforcement and SDK quota meta…
huanghuoguoguo Mar 26, 2026
fa3c02e
feat(skills): add Agent Skills management system (#1917)
fdc310 Apr 8, 2026
a1a408d
feat(sandbox): add MCP box integration on top of sandbox base (#2083)
huanghuoguoguo Apr 8, 2026
1bdd991
refactor(mcp): extract box stdio runtime helper
huanghuoguoguo Apr 8, 2026
22f9f8f
refactor(box): introduce reusable workspace session helper
huanghuoguoguo Apr 8, 2026
fc35892
refactor(box): run Box Runtime as subprocess inside LangBot container
huanghuoguoguo Apr 9, 2026
c5f0e3a
fix(web): prevent first-emission snapshot from swallowing unsaved cha…
RockChinQ Apr 14, 2026
860c50d
style(web): align plugin list header button heights
RockChinQ Apr 14, 2026
5126c46
docs(review): update Box architecture review documents
RockChinQ Apr 17, 2026
a732f1d
feat(web): improve login error layout and add Terms of Service link
RockChinQ Apr 17, 2026
e58b4c1
refactor(web): replace all hardcoded SVG icons with lucide-react
RockChinQ Apr 17, 2026
62b8eda
fix(web): stop polling plugin tasks when no active installs
RockChinQ Apr 17, 2026
9d5609a
fix(deps): update langbot-plugin version and add new dependencies
RockChinQ Apr 17, 2026
08f9ac5
refactor: use Space API for release checks and stop idle polling
RockChinQ Apr 17, 2026
3e2ed6f
feat(box): add --standalone-box flag and 3-way transport decision for…
RockChinQ Apr 17, 2026
41228f5
refactor(box): use single port with path-based routing for Box WS
RockChinQ Apr 17, 2026
0f15b6c
feat(web): show Box runtime status in plugin debug info popover
RockChinQ Apr 17, 2026
b51a221
fix(web): remove ephemeral sandbox count from Box status display
RockChinQ Apr 17, 2026
69dd1fb
feat(box): configurable sandbox scope and unified skill containers
RockChinQ Apr 18, 2026
725117a
feat(web): show active sandbox details in Box status popover
RockChinQ Apr 18, 2026
f339544
feat(box): add startup and availability logging for sandbox tools
RockChinQ Apr 18, 2026
4f81d39
feat(box): support custom sandbox container image via config.yaml
RockChinQ Apr 18, 2026
fc2ce44
feat(box): add heartbeat and reconnection for Box runtime connector
RockChinQ Apr 18, 2026
368f269
feat(web): move runtime status to dashboard, clean up plugin debug po…
RockChinQ Apr 19, 2026
8a70747
refactor(web): compact system status into a single card alongside met…
RockChinQ Apr 19, 2026
cd8c6ff
feat: show connector error details for Plugin and Box runtime status
RockChinQ Apr 19, 2026
e30e2b2
fix(web): auto-refresh system status and show disconnect errors in re…
RockChinQ Apr 19, 2026
1eec771
fix(box): handle RPC failure in get_status/get_sessions gracefully
RockChinQ Apr 19, 2026
078cf1d
fix(box): add persistent reconnection loop with exponential backoff
RockChinQ Apr 19, 2026
fed8aab
fix(box): detect disconnect when handler.run() returns normally
RockChinQ Apr 19, 2026
bd436b7
fix(web): refresh system status card when clicking Refresh Data button
RockChinQ Apr 19, 2026
7eb661c
fix(web): fix system status card stuck in loading state
RockChinQ Apr 19, 2026
c35e4d5
fix: use 'name' instead of 'value' for select options in sandbox scop…
RockChinQ Apr 19, 2026
69f0f2b
feat(web): show active sandbox details in dashboard Box status popover
RockChinQ Apr 19, 2026
8f47027
feat(box): add global sandbox scope option
RockChinQ Apr 19, 2026
609eb58
refactor(web): replace popover with dialog for system status details
RockChinQ Apr 19, 2026
10a2772
fix(web): widen system status dialog and fix scroll border issue
RockChinQ Apr 19, 2026
fa74c75
feat(web): add tooltips for truncated fields in system status dialog
RockChinQ Apr 19, 2026
d8336bf
fix(web): fix models dialog provider type select and split add/scan p…
RockChinQ Apr 19, 2026
2395a18
fix(web): auto-scan on popover open and remove redundant scan button/…
RockChinQ Apr 19, 2026
c1340c2
fix(web): tighten scan popover layout and add rescan button
RockChinQ Apr 19, 2026
44e2c8b
fix(web): reduce top spacing in scan popover
RockChinQ Apr 19, 2026
dc1ba9a
fix(web): remove all top spacing from scan tab content
RockChinQ Apr 19, 2026
11920b5
fix(tests): update tests for unified skill exec path and renamed crea…
RockChinQ Apr 19, 2026
1bdf62e
feat(web): show sandbox TTL countdown in system status dialog
RockChinQ Apr 19, 2026
3bd0ce2
Implement feature X to enhance user experience and optimize performance
RockChinQ Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,28 @@ services:
networks:
- langbot_network

langbot_box:
image: rockchin/langbot:latest
container_name: langbot_box
volumes:
- ./data/box:/workspaces
# Mount container runtime socket for Box sandbox backend.
# Uncomment the one that matches your container runtime:
# - /var/run/podman/podman.sock:/var/run/podman/podman.sock # Podman
- /var/run/docker.sock:/var/run/docker.sock # Docker
restart: on-failure
environment:
- TZ=Asia/Shanghai
command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.box", "--mode", "ws"]
networks:
- langbot_network

langbot:
image: rockchin/langbot:latest
container_name: langbot
volumes:
- ./data:/app/data
- ./data/box:/workspaces
restart: on-failure
environment:
- TZ=Asia/Shanghai
Expand Down
383 changes: 383 additions & 0 deletions docs/review/box-architecture.md

Large diffs are not rendered by default.

152 changes: 152 additions & 0 deletions docs/review/box-issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Box 系统架构问题清单

> 更新日期: 2026-04-16
> 分支: `feat/sandbox` (LangBot + langbot-plugin-sdk)

---

## P0 — 合并前建议修复

### 1. policy.py 是死代码

- **位置**: `pkg/box/policy.py` (98 行)
- **现状**: `SandboxPolicy`、`ToolPolicy`、`ElevatedPolicy` 三个类已定义,但全项目无任何导入或调用
- **影响**: 三层安全策略(sandbox 模式/工具白名单/权限提升)完全未生效,当前的实际策略是 "Box 可用就暴露全部 4 个 native tool,不可用就全部隐藏"
- **建议**: 要么删除死代码,要么接入 NativeToolLoader 调用链

### 2. WebSocket relay 无认证

- **位置**: SDK `box/server.py` `create_ws_relay_app()` + `handle_managed_process_ws()`
- **现状**: 任何能访问 5410 端口的客户端都可以 attach managed process 的 stdin/stdout
- **影响**: 网络内的攻击者可直接向 MCP Server 发送任意指令
- **建议**: 至少加 token 认证(从 RPC 通道获取临时 token,WS 连接时验证)

### 3. Box 无重连机制

- **位置**: `pkg/box/connector.py` `_make_connection_callback()` — Handler 创建时未设置 `disconnect_callback`
- **现状**: 连接断开后 Handler loop 直接退出,Box 功能永久不可用直到应用重启
- **对比**: Plugin 在 WS 模式下有 `sleep(3) -> re-initialize` 自动重连
- **建议**: 参考 Plugin 的 `runtime_disconnect_callback`,至少 WS 模式加重连

### 4. Box 无心跳

- **位置**: `pkg/box/connector.py` — 无 `heartbeat_loop()` 方法
- **现状**: 初始握手后无定期探活,连接断开只能在下次 RPC 调用时被动发现
- **对比**: Plugin 有 20s 间隔的 ping loop
- **建议**: 加 30s 间隔心跳,失败时触发重连

### 5. security.py 根路径未拦截

- **位置**: SDK `box/security.py` `BLOCKED_HOST_PATHS_POSIX`
- **现状**: 黑名单中没有 `/`,`host_path="/"` 可通过校验并挂载整个主机文件系统
- **建议**: 将 `/` 加入黑名单,或改用白名单策略

---

## P1 — 合并后优先跟进

### 6. Session 数量无上限

- **位置**: SDK `box/runtime.py` `_get_or_create_session()`
- **现状**: `_sessions` dict 无容量限制,恶意或异常调用可创建无限 session
- **建议**: 加 `max_sessions` 配置项,达到上限时拒绝新建或清理最老 session

### 7. Quota 检查存在 TOCTOU

- **位置**: `pkg/box/service.py` `_enforce_workspace_quota()`
- **现状**: 应用层先读磁盘大小再执行命令,两步之间有竞态窗口
- **建议**: 短期用 Docker `--storage-opt size=` 做内核级限制;长期用 Redis 原子计数器做预留式配额

### 8. 全局锁持有期间执行慢操作

- **位置**: SDK `box/runtime.py` `_get_or_create_session()` — `self._lock` 下调用 `backend.start_session()` (即 `docker run`)
- **影响**: `docker run` 可能耗时数秒(含镜像拉取),期间阻塞所有并发请求
- **建议**: 在 `_lock` 下仅做状态检查和 session 注册,容器创建在锁外执行

### 9. Session 清理是机会性的

- **位置**: SDK `box/runtime.py` `_reap_expired_sessions_locked()` — 仅在 `_get_or_create_session()` 时调用
- **影响**: 如果长时间无新 session 请求,过期 session(含容器)不会被清理
- **建议**: 加一个独立的 `asyncio.create_task` 定时清理(如每 60s 一次)

### 10. 缺少 Windows 兼容处理

- **位置**: `pkg/box/connector.py` — 无 `win32` 分支
- **现状**: Windows 的 asyncio ProactorEventLoop 不支持 subprocess stdio pipe
- **对比**: Plugin 专门加了 Win32 分支(subprocess + WS 通信)
- **建议**: 加 Windows 分支,或在文档/代码中明确声明不支持

### 11. server.py 直接访问 runtime 私有字段

- **位置**: SDK `box/server.py:139` — `handle_managed_process_ws` 直接读 `runtime._sessions`
- **影响**: 绕过锁和封装,在并发场景下可能读到不一致状态
- **建议**: 在 BoxRuntime 上增加公共方法(如 `get_session_managed_process(session_id)`)

### 12. nsjail image 字段与兼容性检查冲突

- **位置**: SDK `box/nsjail_backend.py:148` 设 `image='host'`;`runtime.py:284` 检查 `image` 字段一致性
- **影响**: 用 nsjail 后端时,如果调用方 BoxSpec 指定了 `image='python:3.11-slim'`(默认值),存储的 `image='host'` 与后续请求的默认值不匹配,永远冲突
- **建议**: nsjail 后端的兼容性检查应跳过 `image` 字段,或统一忽略 image 当 backend 不支持自定义镜像时

---

## P2 — 后续迭代

### 13. 重复的 `_is_path_under` 函数

- **位置**: `pkg/box/service.py` 行 30 和行 36 — 同名函数定义两次
- **建议**: 删除重复定义

### 14. Skill 激活协议无递归保护

- **位置**: `pkg/skill/activation.py`
- **影响**: LLM 在第二次调用中可再次输出 `[ACTIVATE_SKILL:]` 标记,触发无限循环
- **建议**: 加 `max_activation_depth` 检查

### 15. localagent.py 工具循环无迭代上限

- **位置**: `pkg/provider/runners/localagent.py` `while pending_tool_calls` 循环
- **影响**: 恶意或混乱的 LLM 可无限产生 tool call,消耗资源
- **建议**: 加 `max_tool_iterations` 配置项(如默认 50 次)

### 16. localagent.py 中的死代码

- **位置**: `pkg/provider/runners/localagent.py:29-35` — `SANDBOX_EXEC_TOOL_NAME` 和 `SANDBOX_EXEC_SYSTEM_GUIDANCE`
- **现状**: 旧命名方案的遗留常量,从未被引用(实际使用 `EXEC_TOOL_NAME` from native.py)
- **建议**: 删除

### 17. @loader_class 装饰器未使用

- **位置**: `pkg/provider/tools/loader.py` — `preregistered_loaders` 列表和 `@loader_class` 装饰器
- **现状**: MCPLoader 和 PluginToolLoader 的 `@loader_class` 被注释掉,ToolManager 手动实例化所有 loader
- **建议**: 要么启用装饰器自动注册,要么删除未用的机制

### 18. 工具名冲突风险

- **位置**: `pkg/provider/tools/toolmgr.py` `execute_func_call()` — 按优先级 native -> plugin -> mcp -> skill_authoring 分发
- **影响**: 如果 plugin 或 MCP 有名为 `exec`/`read`/`write`/`edit` 的工具,会被 native loader 静默遮蔽
- **建议**: 加命名空间前缀或冲突检测告警

### 19. workspace quota 检查阻塞事件循环

- **位置**: `pkg/box/service.py` `_get_workspace_size_bytes()` — 使用同步 `os.scandir` 递归遍历
- **影响**: 大工作区可能阻塞 asyncio event loop
- **建议**: 用 `asyncio.to_thread()` 包装,或用 `aiofiles` 异步扫描

### 20. client.py 反序列化不一致

- **位置**: SDK `box/client.py:118-126` — `execute()` 手动逐字段构建 `BoxExecutionResult`
- **对比**: `start_managed_process()` 使用 `model_validate(data)` 自动反序列化
- **建议**: 统一使用 `model_validate`

### 21. 错误类型还原基于字符串前缀匹配

- **位置**: SDK `box/client.py:59-82` `_translate_action_error()`
- **影响**: 如果 server 端错误消息格式变化,client 会回退到通用 `BoxError`
- **建议**: 在 ActionResponse 中增加结构化的错误类型字段

### 22. 前端无 Box 相关 UI

- **位置**: `web/src/` — 无任何 Box 组件、类型定义或 API 调用
- **现状**: 后端有 3 个 REST API(`/api/v1/box/{status,sessions,errors}`)但前端未接入
- **建议**: 后续迭代加 Box 状态面板(至少展示可用性、活跃 session、最近错误)
Loading
Loading