@rogeecn/pi-retry
Normalize unrecognized transient provider errors (e.g. HTTP/2 PROTOCOL_ERROR from cliproxyapi) so pi's agent-level auto-retry kicks in instead of stopping.
Package details
Install @rogeecn/pi-retry from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@rogeecn/pi-retry- Package
@rogeecn/pi-retry- Version
1.0.3- Published
- Oct 8, 2026
- Downloads
- 850/mo · 19/wk
- Author
- rogeecn
- License
- MIT
- Types
- extension
- Size
- 12.6 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@rogeecn/pi-retry
Make pi's agent-level auto-retry cover transient provider errors it doesn't recognize —
such as Go HTTP/2 PROTOCOL_ERROR failures from cliproxyapi-style relays — without
modifying pi itself. Implemented with the official pi extension mechanism, so it survives
pi upgrades.
The problem
pi decides whether to auto-retry a failed assistant turn by matching the error message
against a regex whitelist (isRetryableAssistantError): overloaded, 429/5xx,
rate limit, timeout, terminated, socket hang up, fetch failed, ... Anything that
matches none of these ends the run immediately.
A typical unmatched error (cliproxyapi → chatgpt.com backend, Go HTTP/2):
[System Error] Post "https://chatgpt.com/backend-api/codex/responses":
stream error: stream ID 1; PROTOCOL_ERROR; received from peer
This matches nothing in the whitelist, so pi stops instead of retrying.
How it works
On the message_end extension event, when a finalized assistant message has
stopReason: "error" and its errorMessage matches one of the configured patterns,
pi-retry appends a whitelist word (default terminated) to the error message. The
original text is preserved; the appended marker makes the error retryable, and pi then
retries with exponential backoff per your retry settings (retry.maxRetries,
retry.baseDelayMs, retry.maxAgentDelayMs).
Errors on pi's non-retryable blacklist (usage limit, quota exceeded, billing,
insufficient_quota, ...) still never retry — the blacklist takes precedence — so a
misconfigured pattern cannot cause paid retries.
Install
As a pi package (settings.json packages):
"packages": [
"npm:@rogeecn/pi-retry"
]
Or drop the extension into ~/.pi/agent/extensions/pi-retry/ (only index.ts is needed).
Configuration
Config file resolution order:
PI_RETRY_CONFIGenvironment variable (supports~and relative paths)- Project-level
.pi/pi-retry.jsonin the current working directory (if it exists) - User-level
~/.pi/agent/pi-retry.json(default)
{
"enabled": true,
"notify": true,
"append": "terminated",
"patterns": [
"PROTOCOL_ERROR",
"stream error: stream ID"
]
}
| Field | Default | Meaning |
|---|---|---|
enabled |
true |
Master switch |
notify |
true |
Show a UI notice when an error is normalized |
append |
"terminated" |
Whitelist word appended to the error message |
patterns |
see above | Case-insensitive regexes; a match triggers normalization |
Changes take effect after /retry reload — no pi restart needed.
Commands
| Command | Action |
|---|---|
/retry |
Show status, resolved config path, and patterns |
/retry on / /retry off |
Enable/disable (persisted to the resolved config file) |
/retry reload |
Hot-reload the config file |
/retry test <text> |
Check whether an error message would be normalized |
License
MIT