# Pi Local Trace Viewer

[English](./README.md)

这是一个面向 [Pi coding agent](https://pi.dev) 的本地只读执行链路 Viewer。它捕获完整的 LLM 请求与最终响应、工具请求与最终结果，并在独立浏览器进程中展示，不向 prompt 注入调试输出。

插件刻意忽略流式 token delta 和工具执行中间进度，只关注有语义的请求/响应链路。

## 安装

从 npm 安装：

```bash
pi install npm:pi-local-trace-viewer
```

从 GitHub 安装：

```bash
pi install git:github.com/xwcq/pi-local-trace-viewer
```

仅在本次 Pi 运行中试用：

```bash
pi -e npm:pi-local-trace-viewer
```

Pi 插件与 Pi 拥有相同的系统访问权限，安装第三方插件前应检查源码。

## 使用

正常启动 Pi。Viewer 默认作为独立的 localhost 进程启动并自动打开。

```text
/trace-viewer status
/trace-viewer open
/trace-viewer on
/trace-viewer off
```

`on` 和 `off` 会立即更新当前 session，并把状态持久化到全局配置 `~/.pi/agent/trace-viewer.json`，因此后续 session 会继承该状态。如果持久化失败，Pi 会继续运行，并提示只有当前 session 已切换。

禁用状态下启动的新 session 不会拉起或自动打开 Viewer。在活跃 session 中关闭观测会停止捕获新事件，但已打开的 Viewer 会保留到 session 结束，供查看历史数据；重新开启时会按需启动 Viewer。

插件不会注册 `/trace`，以避免和其他 trace 插件发生命令冲突。

## Viewer 展示什么

左侧树把一条用户消息和生成最终用户可见回答所需的全部工作组织为一次 Interaction：

```text
Interaction N（用户输入前几个字…）
└── ReAct Round 1
    ├── LLM request
    ├── LLM response
    ├── Tool request
    └── Tool response
```

当模型在最终回答前多次请求工具时，一个 Interaction 会包含多个 ReAct Round。新的用户消息或 steering 消息会开始新的 Interaction。

右侧将 system、user、assistant、tool-call 和 tool-result 渲染为结构化消息卡片。文本使用 Markdown 展示，元数据和非文本内容保留 JSON。选择 Interaction 时，完整执行链中的所有卡片默认收起，避免汇总视图过长。在单个事件、ReAct Round 和调用视图中，LLM request 仍默认收起，因为它通常包含完整历史对话和较长的系统提示词；LLM response、tool request 和 tool response 仍默认展开。

捕获的事件包括：

- `llm.request`：完整 provider 请求 payload
- `llm.response`：最终 assistant 消息，包括结构化 tool call
- `tool.request`：工具名、call ID 和参数
- `tool.response`：最终结果和错误状态
- 用于还原执行树的 Interaction、turn、run 和 warning 边界

插件不会捕获 LLM token delta，也不会记录 `tool_execution_update` 中间进度。

## 存储

持久化 Pi session 的 trace 与 Pi 自身 session 存储在一起：

```text
<sessionDir>/traces/<sessionId>/
├── metadata.json
└── runs/<timestamp>_<runId>/
    ├── events.jsonl
    └── viewer.log
```

`events.jsonl` 是追加写的 JSON Lines：每个完整行都是一个事件对象，不是 JSON 数组。崩溃后留下的不完整末行会在回放时被忽略。

内存态 Pi session 可以实时查看，但不会自动落盘；仍可通过浏览器导出捕获的数据。

默认保留策略会删除超过 14 天的最旧非活跃 run，或者在项目 trace 总量超过 1 GiB 时按时间清理。当前活跃 run 永远不会被删除。

## 配置

全局配置读取 `~/.pi/agent/trace-viewer.json`。项目配置 `.pi/trace-viewer.json` 可以覆盖其他字段，但全局 `enabled: false` 是总开关，项目不能重新开启。当全局 `enabled` 缺失或为 `true` 时，项目仍可在本地关闭捕获。

```json
{
  "enabled": true,
  "autoOpen": true,
  "persistence": true,
  "contentMode": "full",
  "viewerPort": 0,
  "retentionDays": 14,
  "maxProjectBytes": 1073741824,
  "maxQueueBytes": 8388608
}
```

端口 `0` 表示自动选择可用端口。若指定端口被占用，用户会收到 Viewer 启动失败提示，但 Pi 和可用的 trace 持久化会继续运行。

## 隐私与安全

这是本地调试工具，会按设计展示完整内容且不脱敏。如果 API key 或其他秘密出现在 prompt、provider payload、工具参数、工具输出或错误中，它们也会被写入 trace。

- 插件不会直接读取 Pi 的认证文件。
- Viewer 只监听 `127.0.0.1`。
- trace 数据和 WebSocket 路由需要每次 run 随机生成的 token。
- Viewer 静态资源全部在本地。
- 插件不会上传 trace，正常运行不产生外部网络请求。
- Viewer 永远只读，不能发送消息、调用工具、中断 Pi 或修改请求与响应。

应将 trace 文件和截图视为敏感数据。分享诊断信息前请阅读 [SECURITY.md](./SECURITY.md)。

## 故障隔离

观测能力永远是弱依赖。Viewer 启动、端口监听、浏览器拉起、IPC 拥塞、存储、清理、渲染和退出错误都会被捕获和提示，不会传播到 Pi 的 LLM 或工具执行链路。Viewer 会尝试启动两次，仍失败时 Pi 继续运行。

## 开发

需要 Node.js 22.19 或更高版本以及 Pi。

```bash
git clone https://github.com/xwcq/pi-local-trace-viewer.git
cd pi-local-trace-viewer
npm install --ignore-scripts
npm test
npm run check
pi -e "$PWD"
```

测试仅使用模拟事件，不需要 provider API key，也不会产生模型费用。

## License

[MIT](./LICENSE)
