Skip to content

Repository files navigation

Remote Pi

Remote Pi 在开发机上运行 Pi Agent,并通过受 Bearer 配对码保护的 HTTP/WebSocket API 提供 Web UI 和 Android 原生客户端。默认只监听 127.0.0.1

作为 npm 全局命令安装

要求 Node.js 20.10 或更高版本:

npm install -g pi2web
pi2web

npm 包名为 pi2web,全局命令同名(pi2web)。安装时会准备 better-sqlite3node-pty 两个原生模块:多数平台直接使用预编译产物,没有预编译产物的平台需要本机具备 Python 3 与 C/C++ 工具链(Linux build-essential、macOS Xcode Command Line Tools、Windows Visual Studio Build Tools)。

启动后访问终端显示的地址(默认 http://127.0.0.1:11318)。服务首次启动只在终端显示一次配对码;Web UI 必须由用户手动输入配对码,不会从 URL 或服务端自动注入。连接成功后页面会询问是否保存到 localStorage;只有用户明确确认后才会保存,请仅在可信设备上使用。

常用选项:

pi2web --host 127.0.0.1 --port 11318
pi2web --data-dir ~/.pi/remote-pi
pi2web --rotate-access-token   # 旧配对码立即失效,输出新配对码
pi2web --help

服务器会同时提供 API、WebSocket 和 Web UI,无需另起静态文件服务器。请勿直接暴露到公网;远程访问建议使用 SSH tunnel、Tailscale、devtunnel 或配置 HTTPS 的可信反向代理。

配对失败有速率限制:同一来源地址在 60 秒窗口内累计 10 次失败后会被锁定,锁定时间从 60 秒起按次翻倍,最长 15 分钟,HTTP 返回 429Retry-After,WebSocket 升级同样受限;一次成功配对立即清除该地址的计数。注意限流按 TCP 来源地址统计,通过 devtunnel、Cloudflare Tunnel 或反向代理访问时所有客户端共用同一个计数桶。Remote Pi 不校验 Origin / Host,因此可以直接配合内网穿透使用。

Agent 完成邮件通知(MailDispatch)

如果启动时同时配置 MailDispatch 消息 API endpoint、API key 环境变量和通知邮箱,Pi 发出 agent_settled(不会再自动重试、自动 compact 或执行排队的 follow-up)后,Remote Pi 可以提交事务邮件。MailDispatch 返回 202 后邮件进入其持久队列;实际投递由 MailDispatch worker 完成。

export REMOTE_PI_MAILDISPATCH_KEY='md_live_...'
pi2web \
  --maildispatch-endpoint https://mail.example.com/api/v1/messages \
  --maildispatch-api-key-env REMOTE_PI_MAILDISPATCH_KEY \
  --maildispatch-notify-to owner@example.com \
  --maildispatch-sender-id system

前三个选项必须同时提供,否则 Remote Pi 会拒绝启动。--maildispatch-sender-id 可选;省略时由 MailDispatch 按 API key 和服务配置选择 sender。API key 只从指定环境变量读取,避免出现在命令行参数和进程列表中,并且至少需要 MailDispatch 的 mail:send scope。邮件通知失败只写入 Remote Pi 标准错误,不会改变 Agent 任务状态。

导航栏的“配置”窗口可以启用或关闭邮件通知,并设置:

  • 聚合等待时间:首个任务完成后等待指定秒数,期间完成的其他任务合并到同一封邮件;0 表示立即发送。
  • 是否包含 Agent 最终回复。
  • 是否包含 Session 名称和工作路径。

如果后两项都关闭,邮件正文只说明一个或多个 Agent 任务已经完成。邮件设置保存在 Remote Pi 的 SQLite 元数据数据库中,对所有浏览器客户端和 Agent 生效,服务重启后继续保留。

本地语音摘要与语音输入(实验性)

Windows 下的 Speaches 中文语音服务器启动、模型下载和故障排查见 VOICE_SERVER_SETUP.md。只需要在线 TTS 时,也可以使用 packages/edge-tts-server 中的原生 Python 服务,不需要 Docker。

Remote Pi 可以连接两个 OpenAI-compatible 服务:一个 LLM endpoint 把 Agent 最终输出压缩成适合朗读的短摘要,一个语音 endpoint 负责 TTS,并可选提供 STT。语音默认关闭,只有配置 --voice-base-url 才会启用;--voice-stt-model 是可选项。

# 示例模型 ID 需要替换为 Speaches 中实际下载的模型
export SUMMARY_API_KEY=...
pi2web \
  --voice-base-url http://127.0.0.1:8000/v1 \
  --voice-stt-model <stt-model-id> \
  --voice-tts-model <tts-model-id> \
  --voice-tts-voice <voice-id> \
  --voice-summary-base-url https://llm.example.com/v1 \
  --voice-summary-model <summary-model-id> \
  --voice-summary-api-key-env SUMMARY_API_KEY \
  --voice-language zh-CN

工作方式:

  • Pi 发出 agent_settled 后,Remote Pi 取得最后一条 Assistant 文本,移除代码块、长链接和 Markdown,再限制摘要输入长度。
  • 摘要 LLM 使用流式 Chat Completions;Remote Pi 在完整句子出现后立即调用流式 TTS,因此无需等待整段摘要完成。
  • Web UI 中点击“启用语音”后,会播放服务端推送的 PCM16 或 MP3 音频;新的 Agent 运行会取消该 Agent 尚未完成的播报。
  • 多个 Session 接近同时完成时,语音摘要会进入全局队列依次播放,不会重叠;有 Session 名称时以“会话{name}已完成:”开头。
  • 只有配置 --voice-stt-model 时,Web UI 才显示麦克风按钮;识别文字只插入输入框,不会自动发送。
  • API key 通过 --voice-api-key-env--voice-summary-api-key-env 指定环境变量名,避免把密钥放入命令行参数。

语音流目前通过已认证的 Agent WebSocket 发送,只会实时投递,不写入 Session 或事件 replay。浏览器麦克风通常要求 HTTPS 安全上下文(localhost 例外)。Android 客户端的流式 PCM 播放和录音 UI 尚未接入。

Edge TTS(仅语音合成)

项目提供了一个基于 Python edge-ttsaiohttp 的轻量本地服务。它直接返回 MP3,不需要 Docker 或 FFmpeg:

cd packages/edge-tts-server
python -m venv .venv
# Windows: .venv\\Scripts\\Activate.ps1
# Linux/macOS: source .venv/bin/activate
python -m pip install -e .
remote-pi-edge-tts

pi2web \
  --voice-base-url http://127.0.0.1:5050/v1 \
  --voice-tts-model edge-tts \
  --voice-tts-voice zh-CN-XiaoxiaoNeural \
  --voice-tts-format mp3 \
  --voice-summary-base-url https://llm.example.com/v1 \
  --voice-summary-model <summary-model-id> \
  --voice-summary-api-key-env SUMMARY_API_KEY

语音摘要、语音合成和语音识别的每次请求都有超时保护,默认 120000 毫秒,可用 --voice-request-timeout <ms> 调整;超时后播报会降级为文本提示,不会阻塞后续 Agent 的播报队列。

该模式不配置 --voice-stt-model,因此只启用 Agent 摘要播报,不启用语音识别。Edge TTS 使用非官方消费者服务,适合本地和实验性使用。

本地开发

项目 Review 中发现的问题、修复状态和暂缓的 Android 项目见 PROJECT_REVIEW_ISSUES.md

npm install
npm run check
npm test
npm run dev -- --port 11318

数据持久化

Remote Pi 的服务端元数据保存在 ~/.pi/remote-pi/remote-pi.db SQLite 数据库中:

  • workspaces:Workspace ID、名称、根目录和创建时间。
  • agents:Agent 与 Workspace/Session 的映射、cwd、状态、创建/最后活动时间以及 Archive 状态。
  • sessions:用于 Session 列表、排序和分页的轻量索引,包括名称、文件路径、消息数量、文件 mtime/size 和最后活动时间。
  • auth.json:配对码的 SHA-256 hash、创建和轮换时间;认证数据仍单独保存,不保存配对码明文,文件权限为 0600

数据库使用 WAL、短事务、部分索引和批量延迟更新。Session 活动时间不会随每个 streaming token 写入,而是在完整消息、Agent 完成和 Session 信息变化时合并持久化。旧版 workspaces.jsonagents.jsonagents_archive.json 不会被读取、迁移或继续写入。

Terminal 只保存在服务进程内存中,不写入数据库。刷新浏览器可以重新连接仍在运行的 Terminal;Remote Pi 服务退出或重启时会终止全部 Terminal。

完整对话由 Pi 的 SessionManager 以 JSONL 管理,默认位于 ~/.pi/agent/sessions/<编码后的-cwd>/,其中包含会话消息、分支、模型及 thinking level 等 Session 条目。SQLite 只保存可重建的 Session 索引,不复制完整消息。模型配置、Provider 认证和 Pi 设置也继续复用 ~/.pi/agent。浏览器选择的服务地址、Workspace/Agent 和事件游标另存在浏览器 localStorage;配对码仅在用户明确同意后才会存入其中。

Remote Pi 启动时从 SQLite 恢复 Agent 元数据,恢复后的 Agent 状态为 unloaded,不会创建 Pi AgentSession 或初始化扩展。读取该 Agent 的消息、Session、能力,或者向其发送命令时才按需启动;并发请求共享同一次启动。“停止 Agent”只释放运行中的 Session 并保留 Agent 元数据,再次使用时会按需启动。

Web UI 的 Agent 列表支持右键 Archive。Archive 只设置数据库记录的 archived_at,不会移动、重命名或删除 Pi 的任何 Session 文件;归档记录不会在当前 UI 中显示。

发布包可本地检查:

npm pack --dry-run
npm install -g ./pi2web-0.2.0.tgz

Web UI

Web 端覆盖 Android 客户端的主要浏览器可实现能力:

  • Workspace 添加、目录浏览、文本文件分页及二进制提示。
  • Workspace 目录右键在交互式 Terminal 中打开;Terminal 与 Agent 显示在同一列表,支持刷新重连、清屏和关闭。
  • 创建/恢复 Session、Agent 列表、停止与 abort;Agent 右键 Archive。
  • Prompt、steer、follow-up 和流式对话。
  • 折叠消息、Thinking、Tool、Retry 和 Extension UI 事件。
  • Session 命名、Tree Navigate、Undo/Fork、Compact。
  • 模型和 Thinking level 切换。
  • 输入 @ 浏览并引用 Workspace 文件或目录。
  • WebSocket sequence 去重、断线指数退避、增量 replay/snapshot 恢复。
  • 浏览器允许通知时,对所有已知 Agent 提供完成通知。

Terminal 是以 Remote Pi 进程用户身份运行的完整宿主机 Shell。Workspace 路径只决定初始 cwd,并不是安全沙箱;Shell 可以访问 Workspace 之外的文件及继承到的环境变量。获得配对码的人实际上也获得了该用户的 Shell 权限,请勿将服务直接暴露到不可信网络。每个服务进程最多同时运行 8 个 Terminal,每个 Terminal 只保留最近 512 KiB 输出用于浏览器重连。

浏览器安全模型与 Android 不同:配对码默认仅保存在当前页面的 JS 内存中;连接成功后会询问是否保存,只有用户确认才写入 localStorage。服务地址、当前 Workspace/Agent 和事件 sequence cursor 会保存在 localStorage。浏览器通知要求 HTTPS 安全上下文(localhost 可使用 HTTP);通过局域网 IP 的 HTTP 地址访问时无法启用。自定义 Pi TUI Component 无法在浏览器通用渲染。

API

除 Web 静态资源、/health/api/v1/auth/login 外,请求均需 Authorization: Bearer <token>。响应为 { data }{ error: { code, message, requestId } }

  • GET /health
  • POST /api/v1/auth/login
  • GET /api/v1/system/status
  • GET/POST /api/v1/mail-notifications
  • GET/POST /api/v1/workspaces
  • GET /api/v1/workspaces/:id/tree|file|stat
  • GET /api/v1/sessions
  • GET/POST /api/v1/agents
  • GET/DELETE /api/v1/agents/:id
  • GET/POST /api/v1/terminals
  • GET/DELETE /api/v1/terminals/:id
  • Terminal WebSocket /api/v1/terminals/:id/ws 支持输入、窗口 resize、输出快照和退出事件。
  • Agent 的 statemessagescapabilitiessessionpromptsteerfollow-upabortcompactmodelthinkingsession-namenavigateforkarchiveextension-response 接口。
  • WebSocket /api/v1/ws 支持 sequence、replay、snapshot、fromNow 和 Agent command。

Android App

android/ 是 Kotlin + Jetpack Compose 原生客户端。构建和连接说明见 android/README.md,完整功能见 ANDROID_APP_FEATURES.md

运行时使用真实 @earendil-works/pi-coding-agent SDK,并复用 Pi CLI 的 ~/.pi/agent 模型、认证和设置。MockBackend 只用于自动化测试。

License

MIT © sxwxs。完整条款见 LICENSE

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages