# pi-retry

[English](./README.md) | [中文](./README.zh-CN.md)

**为 [pi](https://pi.dev) 的 provider 错误与流卡死提供重试提示。**

npm 包名：[`@geebos/pi-retry`](https://www.npmjs.com/package/@geebos/pi-retry)

本项目 fork 自
[narumiruna/pi-extensions](https://github.com/narumiruna/pi-extensions)
中的 `pi-retry`（位于 `deprecated/pi-retry`）。上游包因当前 Pi 版本已内置 provider 重试、
Codex websocket 续期和可配置超时而被标记为 deprecated，但本 fork 保留了仍然有用的能力
（错误分类与卡死看门狗），并新增了**可配置的重试关键字 pattern**，让你不用改代码就能
扩展哪些错误算可重试。

## 功能特性

- 检测以 `stopReason: "error"` 结束的 assistant 消息。
- 内置匹配可重试的 provider 错误：
  - `Unknown error (no error details in response)`
  - Codex `websocket_connection_limit_reached`（60 分钟 websocket 上限）
  - 明确包含 `You can retry your request` 的 Codex 后端错误
- **自定义重试关键字 pattern** —— 通过 `/plugin:retry` 添加自己的 RegExp 源，命中后与内置匹配同等对待。
- 追加 Pi 的 retryable-provider-error 提示，让 Pi 内置重试路径继续本轮。
- 在 Pi 重试开启时监控 provider 请求与 assistant 流事件，检测卡死；超时后 abort 并把中止改写成可重试的 provider 错误。
- 状态栏显示 `receiving` / `retrying`。
- 支持 `--retry-stall-timeout-ms <ms>` 和 `PI_RETRY_STALL_TIMEOUT_MS=<ms>`。

## 安装

```bash
pi install npm:@geebos/pi-retry
```

不永久安装、先试试：

```bash
pi -e npm:@geebos/pi-retry
```

在仓库根目录本地试用：

```bash
pi -e .
```

Pi 的 agent 级重试策略需要开启（默认开启）：

```json
{
  "retry": {
    "enabled": true
  }
}
```

当该策略被关闭时，`pi-retry` 会给出警告，但不会自动修改该设置。

## 工作原理

当 assistant 消息以 `stopReason: "error"` 结束时，扩展先按内置 pattern 匹配错误信息，
再匹配你配置的自定义 pattern。命中后追加 Pi 的 retryable-provider-error 提示，让 Pi 内置
重试路径继续本轮。

重试次数、预算与指数退避都由 Pi 控制。`pi-retry` 只做错误分类与卡死检测，不实现独立的
重试循环。扩展在会话开始与每次 provider 请求前读取 Pi 的全局及受信项目设置。

当 Pi 重试策略开启时，每次 provider 请求后会启动卡死看门狗。provider 响应与 assistant 流
事件会刷新 `receiving` 状态栏。如果 90 秒内没有收到 provider 响应或流事件，扩展会短暂显示
`retrying`、调用 `ctx.abort()`，并把中止改写成可重试的 provider 错误。

配置看门狗：

```bash
pi -e npm:@geebos/pi-retry --retry-stall-timeout-ms 10000
PI_RETRY_STALL_TIMEOUT_MS=10000 pi -e npm:@geebos/pi-retry
```

用 `0`、`off` 或 `false` 可关闭看门狗。

## 配置：`/plugin:retry`

添加、列出、删除自定义重试关键字 pattern（JavaScript RegExp 源）。pattern 对错误信息做
大小写不敏感匹配，命中后与内置可重试错误同等对待。

```text
/plugin:retry                      列出已配置的 pattern
/plugin:retry add <pattern>        新增 pattern，如 /plugin:retry add rate.?limit
/plugin:retry remove <pattern|n>   按文本或列表序号删除 pattern
/plugin:retry clear                清空所有已配置的 pattern
```

新增时会校验 pattern（必须是可编译的 RegExp 源），并持久化到
`~/.pi/agent/extensions/pi-retry/config.json`。每次错误匹配都会重新读取该文件，改动即时生效。

```json
{
  "patterns": ["rate.?limit", "upstream.*timed out"]
}
```

## 使用场景

- 减少瞬时 provider 故障后的人工重启。
- 从明确可重试的 Codex 后端错误或 websocket 连接上限中恢复。
- 为只有你的 provider 才会产生的错误添加自己的重试规则。
- 提升长时间 Pi coding agent 会话的可靠性。

## 包结构

```txt
pi-retry/
├── .github/workflows/
│   └── publish-npm.yml
├── src/
│   ├── index.ts
│   ├── command.ts
│   ├── config.ts
│   └── retry.ts
├── test/
│   ├── support.ts
│   ├── retry.test.ts
│   ├── config.test.ts
│   └── command.test.ts
├── README.md
├── README.zh-CN.md
├── LICENSE
├── tsconfig.json
└── package.json
```

## 发布

推送版本 tag 会触发 npm 发布 workflow：

```bash
git tag v0.0.1
git push origin v0.0.1
```

手动重新发布已有 tag：Actions → **Publish to npm** → **Run workflow** → 填入 `v0.0.1`。

### npm Trusted Publishing（无需 token）

workflow 使用 [Trusted Publishing](https://docs.npmjs.com/trusted-publishers)（OIDC），
**不要**设置 `NPM_TOKEN`。

在 npmjs.com → **@geebos/pi-retry** → **Settings** → **Trusted Publisher** 配置一次：

| 字段 | 值 |
| --- | --- |
| Provider | GitHub Actions |
| Organization or user | `geebos` |
| Repository | `pi-retry` |
| Workflow filename | `publish-npm.yml` |
| Allowed actions | `npm publish` |

要求：Node 24 / npm ≥ 11.5.1（workflow 中已设置）、`permissions.id-token: write`。

## 致谢

Fork 自 [`narumiruna/pi-extensions`](https://github.com/narumiruna/pi-extensions)
（`deprecated/pi-retry`），并扩展了可配置的重试关键字 pattern。

## License

[MIT](./LICENSE)
