分层
apps/desktop
桌面前端,Next.js + assistant-ui。 主要目录:
Rust 宿主负责 Rust 侧的事:窗口与自定义标题栏、系统钥匙串、
sidecar 子进程的拉起与回收,以及把业务表的读写以 host RPC 的形式
提供给 sidecar。
业务数据不直接由 sidecar 写文件或开 SQLite 连接,而是通过 stdout 上的
host RPC 交给宿主执行。这是为什么在没有 Rust 宿主时
(例如
bun run smoke)sidecar 会回退到本地 SQLite 存储。apps/sidecar/pi-agent
Agent 运行时,Bun + TypeScript。入口src/index.ts,
对外是 stdin/stdout 上的 NDJSON 协议,按域分目录:
apps/mobile
Expo SDK 57 + React Native 0.86。无后端—— 经桌面远程网关的/ws 连 sidecar,配对码换 token 存 Keychain/Keystore。
详见 远程与移动端。
packages
- pi-protocol:前后端共享的跨端契约定义。桌面前端、sidecar 与移动端 都从这里取类型,避免三端各写一套。
- shared:桌面侧的共享工具与组件。
plugins
见 插件与工作台。数据流向:一次工具调用
1
前端发出请求
会话流渲染时,前端通过 NDJSON 向 sidecar 发一条消息。
2
sidecar 决定调什么
agent 循环把消息交给模型,模型返回工具调用。
sidecar 按当前会话模式与权限档位检查这次调用是否放行。
3
可能要问你
如果需要审批,sidecar 推一条审批事件给前端,
前端弹审批卡。你的选择回传 sidecar。
4
执行并落库
工具在 sidecar 内执行。涉及业务表的写入通过 stdout 上的 host RPC
交给 Rust 宿主执行,宿主访问系统钥匙串与 SQLite。
5
回推事件
工具结果与流式增量以事件形式推回前端,
渲染成对话流里的一次工具调用记录,并落检查点。
为什么把 agent 拆成独立进程
- 界面不卡:长任务和大量工具输出不会阻塞渲染进程;
- 崩溃隔离:sidecar 出问题不会带走整个窗口;
- 多端复用:移动端和网页端接的是同一个 WS 端点与同一套运行时, 不需要第二份实现;
- 可独立测试:
bun run smoke能在没有 GUI 的环境里跑完整的协议握手。
站在别人的肩膀上
会话转录、上下文压缩、子代理等核心设计移植/参考自 Earendil Works 的 pi-agent。 代码注释里大量出现的PI-Desktop 同设计 标注就指向这些出处。
下一步
在这个分层之上加你自己的东西。
