打包、WebUI 构建与跨平台
对应源码
| 主题 | 源码 |
|---|---|
| Python 包和构建钩子 | pyproject.toml、hatch_build.py |
| WebUI 构建配置 | webui/package.json、webui/vite.config.ts |
| WebUI 静态资源接入 | nanobot/web/ |
| 平台相关 Tool | nanobot/agent/tools/shell.py、sandbox.py |
| 构建与平台测试 | tests/test_package_version.py、tests/tools/test_exec_platform.py、tests/webui/、webui/src/tests/ |
学习目标
读完后,你应当能够:
- 解释 nanobot wheel 中为什么同时有 Python、模板、Skill、WebUI 和 Bridge 内容;
- 区分前端开发服务器与打包后的内嵌静态资源;
- 找到 Windows 与 Unix shell 行为差异;
- 在修改发布相关文件时选择正确验证命令。
前置知识
- 知道 wheel 是 Python 安装包;
- 知道 Vite 会把 React/TypeScript 构建成浏览器可加载的静态文件;
- 只需能看懂
pyproject.toml和package.json的基本字段,不要求先会写 React。
1. 产品不是只有 Python 文件
当前 pyproject.toml 使用 Hatchling 构建。wheel 包含:
nanobot/**/*.py- prompt templates
- 内置 skills
- 构建生成的
nanobot/web/dist - 其他显式资源
并通过 force-include 把仓库根部的 bridge/ 放入安装包中的 nanobot/bridge。后两者是构建产物/安装目标,干净源码树中不一定已经存在。
因此,下面两种改动都可能在源码运行正常、安装包运行失败:
- 新增资源但没有进入 wheel include;
- 修改 WebUI 源码但没有先生成
nanobot/web/dist。
2. WebUI 的两种运行模式
开发模式
webui/package.json 提供 dev。Vite 默认在 5173 端口运行,并把 /webui、/api、/auth 等 HTTP 路由代理到:
NANOBOT_API_URL未设置时默认为 http://127.0.0.1:8765。
WebSocket 客户端使用自己的连接地址,不应假设所有 WS 流量都经过 Vite HTTP proxy。
内嵌模式
webui/vite.config.ts 把生产构建输出到:
nanobot/web/distPython WebUI server 再从该目录提供静态资源。发布 wheel 必须包含这个目录。
flowchart LR A["webui/src<br/>React + TypeScript"] --> B["Vite build"] B --> C["nanobot/web/dist"] C --> D["Hatch wheel"] D --> E["安装后的 nanobot WebUI"] F["bridge/"] -->|"force-include"| D G["nanobot/**/*.py"] --> D H["templates / skills"] --> D
3. Bridge 的边界
Bridge 不是 AgentLoop 的一部分。它属于外部平台与 nanobot 通信的适配资源,打包规则确保安装后的运行时能找到它。
学习时应先回答“消息最终是否仍被转换为 InboundMessage”,再研究具体 Bridge 协议。不要因为 Bridge 随 wheel 发布,就把其平台逻辑塞进 core。
4. Python 与前端版本入口
关键文件:
pyproject.toml:Python 版本、依赖、console script、build include;webui/package.json:前端脚本与依赖;webui/vite.config.ts:开发代理和生产输出;nanobot/web/:Python 静态资源服务;nanobot/__init__.py:包版本入口;nanobot/cli/commands.py:CLI 命令入口。
当前 Python 要求以 pyproject.toml 的 requires-python 为准;开发规则要求 Node.js 22+ 运行仓库网站,但 nanobot WebUI 自己的包管理与脚本应以 webui/package.json 和仓库文档为准。
5. Windows 与 Unix 差异
Shell 启动
ExecTool._spawn():
- Windows 单行命令使用
asyncio.create_subprocess_shell(); - Windows 多行命令显式调用
powershell -NoProfile -Command; - Unix 默认选择 bash,或使用允许的
sh、bash、zsh; - Unix login shell 会读取对应 profile。
因此,文档和测试不能默认所有平台都支持 Bash quoting。
sandbox
- bwrap 只在非 Windows 路径包装;
- Windows 上记录警告并继续 unsandboxed;
- 父目录
fsync在 Windows 可能因不能打开目录而跳过。
路径和编码
- 源码大量使用
Path.resolve()、os.pathsep和路径归一化; - subprocess 输出以 UTF-8 解码,错误字节用 replacement;
- Session/配置 JSON 明确使用 UTF-8 和
ensure_ascii=False; - Windows 下不要把
\与转义字符混淆。
6. 修改后的最小验证
Python 核心
在 example/nanobot/code-EN 中:
pytest tests\对应测试文件.py若修改 package manifest 或资源路径,再构建 wheel,并检查内容,不只检查命令 exit code。
WebUI
在 example/nanobot/code-EN/webui 中,按项目锁文件和脚本运行:
bun run test
bun run build然后确认 nanobot/web/dist 被更新且 Python server 能提供入口文件。
全仓库检查
仓库规则明确禁止使用 ruff format,因为它会造成不必要的全库改写。只运行项目已定义、与改动范围对应的 lint/test/build。
本学习库当前不修改源码
这些命令用于后续实践。只阅读文档时,不需要为了形式运行完整构建。
7. 常见故障
| 现象 | 优先检查 |
|---|---|
| 源码 WebUI 正常,wheel 中页面 404 | nanobot/web/dist 是否构建并进入 wheel |
| 前端 API 正常,WebSocket 连接失败 | WS 实际地址,不要只看 Vite HTTP proxy |
| Windows 命令在 Linux 正常、在本机失败 | shell 选择、路径分隔符、quoting |
| 配置了 bwrap 但 Windows 仍可访问宿主资源 | 这是当前明确的 unsupported 路径 |
| 安装后找不到 Bridge 文件 | pyproject.toml 的 force-include 和 wheel 内容 |
| 中文路径或输出乱码 | subprocess 编码、终端编码、文件是否 UTF-8 |
8. 源码与测试
配置与源码:
pyproject.tomlwebui/package.jsonwebui/vite.config.tsnanobot/web/nanobot/agent/tools/shell.pynanobot/agent/tools/sandbox.py
测试与发布检查:
tests/test_package_version.pytests/cli/test_commands.pytests/tools/test_exec_platform.pytests/webui/webui/src/**/*.test.ts
具体测试函数会随实现调整;定位时仍应以当前 rg --files tests webui 结果为准。
自检
- 为什么只提交
webui/src改动可能不足以发布? - Vite dev proxy 与生产静态资源有什么不同?
- bwrap 在 Windows 上的真实行为是什么?
- 新增模板文件后,除了 Python 测试还应检查什么?
下一部分:扩展开发导航