# pi-task-timer

[English](./README.md) | 简体中文

一个用于 [Pi](https://github.com/earendil-works/pi) 的任务计时扩展，在页脚显示 Agent 每次任务的运行时间，并通过 `/time_profile` 按需查看最近任务的时间分析。

## 安装

```bash
pi install npm:@jy02414216/pi-task-timer
```

临时试用而不写入 Pi 设置：

```bash
pi -e npm:@jy02414216/pi-task-timer
```

卸载：

```bash
pi remove npm:@jy02414216/pi-task-timer
```

## 本地开发

```bash
pi -e ./packages/pi-task-timer
```

修改已加载的本地扩展后，可以在 Pi 中执行 `/reload` 重新加载。

## 功能

- Agent 开始工作时，每秒更新已用时间。
- Agent 完全结束后，保留本次任务总耗时。
- 页脚与报告采用相同的最后一次模型响应状态：正常结束显示 `✓`，中止显示警告色 `■ … · Aborted`，模型错误显示错误色 `✗ … · Model error`；重试成功后恢复正常样式。
- `/time_profile` 查看最近一个已结束任务的时间构成、工具耗时排名和失败耗时。
- 退出、重载、切换 Session 或导航分支时，自动清理计时器和分析记录。

## 时间分析

完成一个任务后输入：

```text
/time_profile
```

报告及命令提示统一使用英文，以只读文本显示在聊天区，不加入模型上下文，也不会触发模型请求。支持 TUI 和带 UI 的 RPC 客户端；页脚计时仅在 TUI 中显示。

报告包括：

- 任务总耗时，以及 LLM 阶段、Tool 活跃、其他/未归类时间与占比。
- 工具按累计耗时降序排列，显示次数和累计耗时；只有多次调用才显示平均耗时。
- 只有发生失败才显示失败调用总次数、耗时及对应工具的失败明细。

正常报告示例：

```text
Time Profile · 10.18s · 2 turns

LLM     8.04s  79.0%
Tools   2.08s  20.4%
Other    66ms   0.6%

Tools
fetch_content   1 call   2.08s
```

正常报告不显示 `Ended`、零失败信息或统计口径说明；中止、模型错误、LLM/Tool 重叠、不完整记录和内存上限提示仅在发生时显示。详细口径见下节。

当前任务仍在执行时，展示上一任务并明确提示；尚无已结束任务时，只显示说明。命令不接受参数，不提供 session 累计、token/cost、重复操作检测或 waste 分析。

### 统计口径

- **Task**：通常从 `before_agent_start` 开始，覆盖启动准备时间；未经过该事件的任务（例如扩展主动触发的模型调用）由 `agent_start` 兜底启动。统一在 `agent_settled` 结束，自动重试和自动续跑不重置任务，也不重复创建页脚计时器。
- **LLM 阶段**：从 `turn_start` 到 assistant 的 `message_end`，包括请求准备、等待和生成，不是纯模型推理时间。工具内部的模型调用不单独拆分。
- **Tool 活跃**：工具起止区间的并集，并行和嵌套区间只计一次。工具内的人机交互等待也属于工具时间。
- **Other（其他/未归类）**：总耗时减去已记录 LLM/Tool 时间区间的并集，例如事件回调、阶段切换或轮次之间的重试等待；当前不进一步细分来源。若 LLM 和 Tool 有重叠，会另外提示，不能直接相加占比。
- **工具累计耗时**：该工具各调用耗时之和，包含并行及父子工具重叠，可能大于任务总耗时。平均耗时仅使用起止完整的调用。
- **调用标识**：同时核对 `toolCallId`、工具名和父调用 ID，并按实际轮次保存记录。不同轮次正常复用同一身份仍分别计数；同一接收轮次的重复起止事件去重。唯一未结束调用可以在后续轮次配对结束事件。
- **失败**：以 Pi 的 `tool_execution_end.isError` 为准，不解析工具输出或自行推断命令是否失败。失败累计耗时同样可能重叠。
- **不完整记录**：缺失起点或终点时，不猜测耗时；报告会提示不完整。新轮次出现无起点的结束事件时，单独保留该事件及其明确的失败信息，不把它当作历史重复事件丢弃。未归类时间不强行算入 LLM。
- **配对歧义**：不同工具名或父调用可以区分相同 ID。如果同一完整身份跨轮次出现多个未结束调用，则保留开始记录，并在本任务内隔离该身份：不猜测结束顺序，也不归属这些不确定的耗时或失败；其他身份和后续任务不受影响。因此不完整报告中的耗时和失败次数仅代表可确定的部分。事件缺少轮次来源，无法保证还原所有异常事件序列。

### 性能与隐私

- 平时仅监听任务、轮次和工具起止事件，使用单调时钟记录少量字段；不监听逐 token 或工具流式更新。
- 仅在输入 `/time_profile` 后动态加载分析模块，执行聚合、区间合并、排序和报告格式化。
- 不保存 prompt、工具参数或输出，不读取 Session 历史，不增加网络请求、磁盘写入或计时器。
- 内存只保留当前任务和最近一个已结束任务；每个任务最多记录 10,000 条轮次/工具记录，达到上限后明确提示部分统计。
- 不持久化，不恢复旧任务。重载、重启、切换 Session 或导航分支后，需要完成一个新任务才能查看报告。

轻量事件记录仍有少量开销，不承诺零开销；原有页脚每秒更新保持不变。

## License

[MIT](./LICENSE)
