打包、WebUI 构建与跨平台

对应源码

主题源码
Python 包和构建钩子pyproject.toml、hatch_build.py
WebUI 构建配置webui/package.json、webui/vite.config.ts
WebUI 静态资源接入nanobot/web/
平台相关 Toolnanobot/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/dist

Python 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 中页面 404nanobot/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.toml
  • webui/package.json
  • webui/vite.config.ts
  • nanobot/web/
  • nanobot/agent/tools/shell.py
  • nanobot/agent/tools/sandbox.py

测试与发布检查:

  • tests/test_package_version.py
  • tests/cli/test_commands.py
  • tests/tools/test_exec_platform.py
  • tests/webui/
  • webui/src/**/*.test.ts

具体测试函数会随实现调整;定位时仍应以当前 rg --files tests webui 结果为准。

自检

  1. 为什么只提交 webui/src 改动可能不足以发布?
  2. Vite dev proxy 与生产静态资源有什么不同?
  3. bwrap 在 Windows 上的真实行为是什么?
  4. 新增模板文件后,除了 Python 测试还应检查什么?

下一部分:扩展开发导航