Repository navigation
Features zh
English · 中文
对应 v0.12.0(
3a762b1)。按领域梳理 nanopi 实际实现了什么。 安装步骤和完整的 CLI 参数表见 README。
nanopi 是 Pi 的 Rust 精简移植——一个编码 agent,产物是单个静态 musl 二进制,无运行时依赖。
两套协议。 原生 Anthropic adapter,以及任意 OpenAI 兼容端点。Provider 抽象在 v0.6 落地。
Vendor 分发。 根据 base URL 和 model id 嗅探,为 anthropic、openai、deepseek、minimax、qwen、xiaomi、zai 各自适配,外加一个通用兜底。显式设置 api_kind 会覆盖嗅探结果——在网关让端点"看起来像别的东西"时需要它。
流式。 手写的 SSE 解析器,没用 reqwest-eventsource,为的是压住依赖树。
重试信封。 对 5xx、429 和瞬时错误做带 jitter 的指数退避,各 provider 统一。
思考级别。 模型支持时可配置 extended thinking 预算。
会话是 JSONL 追加写——选它是因为写到一半崩溃时文件仍然可用,而单个 JSON 文档做不到。
| 能力 | 方式 |
|---|---|
| 恢复最近会话 | --continue |
| 按 id 恢复 | --session <id> |
| 调用方指定 id | --session-id |
| 从某点分叉 |
--fork <id>,或 TUI 里 Esc-Esc 选一条历史用户消息 |
| 回放整个记录 |
/resume 把会话重新渲染进 scrollback |
| 导出 |
/export 默认输出完整 HTML(按扩展名也可 JSONL) |
| 导入 |
/import 读回 JSONL 会话 |
压缩。 基于 token 阈值的自动压缩会用 LLM 总结较早的上下文;/compact 手动触发。两条路径都会发出 session_before_compact 和 session_compact 钩子,matcher 匹配的是原因字符串(threshold 或 manual)。
分叉选择器会沿父链向上走,所以早先创建的分支不会被最新的挡住而消失。
七个,全部本地:read、write、edit、bash、grep、find、ls。
工具调用默认并行;tool_exec_mode = "sequential" 可切换为串行。
工具注册表会归一化被网关改写过的工具名。
TUI(stdin 是 TTY 时的默认模式)基于 ratatui,采用内联视口,保留终端 scrollback 而不是整屏接管。
- 多行编辑器 + Emacs 键位;
Ctrl+J换行 - fish 风格的按词合并撤销
- Markdown 渲染;
Ctrl+O展开最后一次工具输出 - 统一工具卡片——命令、输出、耗时在同一块内
- 三行状态栏,含上下文占比
- 工具专属的 spinner 文案和实时在途工具条
-
Esc取消运行中的工具;Esc Esc打开分叉选择器 - 输入历史跨会话保留
- 流式中途转向——生成过程中打字会注入当前这轮,而不是排队等下一轮(v0.11.0)
斜杠命令: /model /settings /keybindings /skills /tools /session /name /compact /fork /new /resume /export /import /copy /reload /hotkeys /quit /exit
已加载的 skills 会以 /skill:<name> 出现在同一个命令面板里,插件注册的命令也一样,并带上插件名。插件命令只在交互模式下可用——nanopi -p 没有面板,但该插件的工具在那边照样能用。
/tools 是清点页:先是模型可调用的工具(标 [builtin] 或 [plugin:<name>]),然后每个插件一行 Plugin grants,最后是 Watching events。它读的是活的 registry,不是启动时的快照,所以 /new、/resume 之后依然准确。
/reload 可热重载 skills、config、settings 和上下文文件,无需重启。但它刻意不重新读取 [[extensions]],并会明确说明这一点。
非交互 -p 模式遵循 Claude Code 语义,--output json 便于脚本化,也支持 prompt 从 stdin 管道传入。
五套彼此独立的机制,按能力从弱到强:
上下文文件。 AGENTS.md / CLAUDE.md 发现,与 Pi 对齐。-C 关闭。
Skills。 实现了 Agent Skills 规范。把 SKILL.md 放进 ~/.nanopi/skills/<name>/,用 /skill:<name> 调用,或让模型通过系统提示里自动追加的 <available_skills> 块自行发现。项目级 skills 需要信任。
Hooks。 在生命周期节点触发的 shell 命令,写在 config.toml 的 [hooks.*] 下,键名是 snake_case(settings.toml 仍然有效,但已是 legacy)。
| 类别 | 事件 |
|---|---|
| 工具调用 |
tool_execution_start、tool_execution_end
|
| Prompt |
before_agent_start、input
|
| 轮次 / 消息 |
turn_start、turn_end、message_end
|
| 会话 |
session_start、session_shutdown
|
| 压缩 |
session_before_compact、session_compact
|
十一个事件,全部用 PI 的命名。v0.12 把原先借用 Claude Code 的那四个改了名——pre_tool_use → tool_execution_start、post_tool_use → tool_execution_end、user_prompt_submit → input、session_end → session_shutdown——不留别名,也没有过渡期。用旧键名会导致配置加载失败,错误里点名新键。因为最坏的结果是 [[hooks.pre_tool_use]] 被静默忽略:用户以为自己给 bash 装了道闸,其实什么都没有,而且没有任何地方提示。
tool_execution_start 可以拦截调用或改写参数;tool_execution_end 可以改写结果内容;before_agent_start 和 input 可以中止本轮或改写 prompt。其余是 advisory——它们的 block 会被打印出来然后丢弃。细节见 生命周期 hooks。
WASM 插件(v0.11.0,v0.12.0 大幅拓宽)。跑在 wasmtime 里的沙箱组件,能力逐项 opt-in。v0.12 起插件还可以观察全部十一个生命周期事件,payload 和 shell hook 拿到的完全一致,但只能观察:handle-event 的返回值被丢弃。一句话:插件只看,hooks 才能拒。见 Plugin-Development-zh、Plugin-Capabilities-zh 和 插件事件订阅。
自定义系统提示。 --system-prompt 替换内置的身份/准则块,--append-system-prompt 追加。两者都接受字面文本或文件路径。不带 flag 时,nanopi 会发现 .nanopi/SYSTEM.md 和 .nanopi/APPEND_SYSTEM.md(先项目后全局)。
项目信任。 项目级资源——skills、SYSTEM.md、项目配置——都受信任决策管控,因为 clone 下来的仓库属于不可信输入。-a 为本次运行授信,-N 拒绝,持久化的决策覆盖后续运行。全局的同类文件不需要这道门:那是你自己的机器。
插件能力。 WASM 插件默认什么都拿不到。v0.12 把宿主导入从三个扩到了 九个,其中六个各有一道门:
| 导入 | 门 |
|---|---|
host-log、host-notify
|
无——输出不等于访问。用速率限制而非授权来兜(notify 每插件每轮 10 行) |
host-fs-read |
allow_fs,且 canonicalize 之后的路径必须仍在工作目录内 |
host-http-get |
allow_network 加 url_allowlist;空白名单拒绝一切 |
host-store-get / host-store-set
|
allow_store——插件给的是 key,文件位置由宿主决定,插件永远不指定路径 |
host-set-context |
allow_context——这段文字会被模型当成指令读,所以每次变更都会在 scrollback 里公告 |
host-call-tool |
allow_tools,按工具名逐个授权;[] 拒绝一切,而且你的 hooks 照样在这些调用上触发 |
host-send-user-message |
allow_send_message——唯一会花钱的能力,因此它单独出现就会告警 |
生命周期观察是第七道门 events,单独一页:插件事件订阅。几种危险组合会在启动时告警——events + allow_network、allow_store + allow_network、allow_context + allow_network、allow_tools 里含 bash,以及只要出现 allow_send_message。细节见 Plugin-Capabilities-zh。
--no-hooks 是紧急开关,一次性禁用所有钩子。
这是相对上游 Pi 的刻意分歧:Pi 的 extension 不带沙箱、在主进程内运行、拥有完整 Node 全局,也没有任何 URL 白名单。
两层——全局 ~/.nanopi/config.toml 和项目 <cwd>/.nanopi/config.toml——不同字段有三种不同的合并行为。见 Configuration-zh;"拼接 vs 覆盖"这个区别最容易踩坑。
Settings 和键位单独放在 settings.toml,可通过 /settings 和 /keybindings 选择器编辑,用 toml_edit 往返读写以保留注释。
首次运行向导(nanopi init,或在找不到凭据时自动触发):provider 选择列表、写入前先探测校验、API key 以 0600 权限写入 ~/.nanopi/api_key。
| 版本 | 内容 |
|---|---|
| v0.12.0 | 统一事件词汇——四个 hook 键改用 PI 命名,旧键直接报错;插件可订阅生命周期事件(world extension-events,只观察,由 events 授权);六个新宿主导入(host-store-*、host-notify、host-set-context、host-call-tool、host-send-user-message)及各自的门;/tools 新增 Plugin grants 和 Watching events 两段 |
| v0.11.0 | WASM 扩展,带门控的 host-fs-read / host-http-get,以及插件注册的斜杠命令;Pi 生命周期钩子;流式中途转向;可配置的工具执行模式 |
| v0.10.0 | 自定义系统提示;显式 api_kind 覆盖 vendor 嗅探;-p 模式下工具失败可读化;UPX 压缩发布(1.6 MB) |
| v0.9.x | 首次运行向导;/settings + /keybindings;8 vendor 分发;重试信封 |
| v0.9.0 | Skills(与 Pi 对齐);--skill / --no-skills;user_prompt_submit 钩子 |
| v0.8.x | 完整 ratatui TUI;/fork;--continue / --session;JSONL 会话 |
| v0.6 | Provider 抽象;Anthropic adapter;自动压缩;grep/find/ls;统一配置 |
| v0.5 | 工具(read/write/edit/bash);-p 模式;JSON 输出;钩子 |
| v0.1 | 单文件 OpenAI 流式 demo |
README 的版本表停在 v0.11.0;而在 v0.12.0 分支上,
VERSION和Cargo.toml仍写着0.11.0——版本号是随 release tag 才 bump 的。判断"手上这个构建是什么"以VERSION和Cargo.toml为准,判断"代码树里已经有什么"以本表为准。
-
musl + LTO +
panic=abort+ strip 换来小体积静态二进制;用 rustls 避开 OpenSSL 依赖 - 手写 SSE 解析器,压住依赖树
- JSONL 而非 JSON,追加写的会话文件能在写到一半崩溃时幸存
- WASM 插件而非进程内扩展——这正是能力门得以存在的前提
English
- Home
- Features
- Configuration
- Hooks
- Plugin Development
- Example Plugins
- Plugin Capabilities
- Plugin Events
- Debugging Plugins
中文
v0.12.0 · source of truth:
wit/nanopi-extension.wit