npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-pattern-retry

v0.1.0

Published

Pi extension: keep agent sessions alive across provider rate-limits, quota exhaustion, and transient auth failures by re-injecting continuation messages on an escalating retry schedule.

Readme

pi-pattern-retry

npm version License: MIT

Keep your Pi Agent session alive across provider rate-limits, quota exhaustion, and transient auth failures. pi-pattern-retry watches provider responses and agent errors, matches them against configurable patterns (regex / substring), and re-injects a continuation message at escalating intervals — 30s → 1m → 5m → 15m → 30m → 1h → 4h → 5h → 12h → 24h by default — so the agent picks up where it left off.

Designed alongside todo-enforcer: same retry-scheduler idea, separate package, ships independently.

Install

pi install npm:pi-pattern-retry

Then restart your Pi session. The plugin ships with sensible defaults — no config file is required to get started.

What it does

Two trigger sources feed one matcher:

| Event | What it inspects | |---------------------------|------------------------------------------------------------------| | after_provider_response | HTTP status — catches 401 / 403 / 429 / 5xx | | agent_end | last assistant message's errorMessage — catches transport text |

A match schedules one timer per (sessionId, patternName). When the timer fires:

  1. If the conversation has progressed (branch grew, excluding our own injections), reset attempt counter and stop.
  2. Otherwise inject pi.sendUserMessage(<your template>) so the agent retries.
  3. Advance to the next delay in the schedule. When the schedule is exhausted, the pattern stays inert until /pattern-retry-reset.

Duplicate triggers (e.g. both events firing for the same failure) are debounced — the already-live timer wins.

Default patterns

Shipped with three patterns pre-seeded. Override or replace via config file.

| Name | Trigger | Schedule (seconds) | |------------------------|----------------------|------------------------------------------------------------------------| | llm-429-quota | HTTP 429 | 30, 60, 300, 900, 1800, 3600, 14400, 18000, 43200, 86400 (10 steps) | | llm-401-403-auth | HTTP 401 / 403 | 60, 300, 1800 (3 steps) | | litellm-weekly-limit | errorMessage contains "Weekly/Monthly Limit Exhausted" | 3600, 14400, 43200, 86400 |

Configuration

Global file: ~/.pattern-retry.json. Project override: <cwd>/.pattern-retry.json. Project keys override global; arrays replace, they do not merge.

{
  "enabled": true,
  "patterns": [
    {
      "name": "llm-429-quota",
      "match": { "source": "providerStatus", "kind": "regex", "value": "^429$" },
      "scheduleSec": [30, 60, 300, 900, 1800, 3600, 14400, 18000, 43200, 86400],
      "message": "Provider returned {{status}} (attempt {{attempt}}/{{maxAttempts}}). Retrying after {{lastDelaySec}}s.",
      "stopOnProgress": true,
      "notify": ["webhook", "dashboard"]
    },
    {
      "name": "litellm-weekly-limit",
      "match": {
        "source": "errorMessage",
        "kind": "contains",
        "value": "Weekly/Monthly Limit Exhausted"
      },
      "scheduleSec": [3600, 14400, 43200, 86400],
      "message": "Hit weekly LLM quota. Resuming attempt {{attempt}}."
    }
  ],
  "notifyTargets": {
    "webhook":   { "enabled": false, "url": "", "headers": {}, "timeoutMs": 10000 },
    "dashboard": { "enabled": false, "endpoint": "" }
  }
}

Match semantics

  • kind: "contains" — case-sensitive substring match.
  • kind: "regex" — compiled with new RegExp(value); no implicit flags. For case-insensitive, encode flags in the pattern itself.
  • source: "providerStatus" — matched against the decimal status string (e.g. "429").
  • source: "errorMessage" — matched against the assistant message's errorMessage string. If absent/empty, the pattern does not match.

A malformed regex degrades to a logged warning — other patterns continue to work.

Template variables

| Variable | Value | |--------------------|----------------------------------------------------------------| | {{status}} | HTTP status from providerStatus, or 0 | | {{statusText}} | Human label (e.g. "Too Many Requests") | | {{reason}} | Match-source snippet | | {{patternName}} | The matched pattern's name | | {{attempt}} | 1-indexed current attempt | | {{maxAttempts}} | scheduleSec.length | | {{lastDelaySec}} | Delay that elapsed before this fire | | {{nextDelaySec}} | Next delay if any, else 0 |

Missing variables interpolate to empty string.

Commands

  • /pattern-retry-status — show each pattern's attempt/max, exhausted, and scheduled flags.
  • /pattern-retry-reset [patternName|all] — cancel timer(s) and reset attempt counter.
  • /pattern-retry-toggle — flip the global enabled flag.
  • /pattern-retry-log [N] — tail the last N lines (default 50, max 500) of the central log file straight into the session.

Troubleshooting / Logs

Every meaningful decision is appended to a single central log file:

~/.pi/logs/extensions/pattern-retry.log

This is the shared convention across all pi extensions — written via the rotated, size-capped (25 MB, 80% trim) createPluginLogger. Each line is:

<iso-timestamp> [pattern-retry] <LEVEL> <event> <json-details>

Events you can grep for:

| Event | Means | |--------------------------------|------------------------------------------------------------------------| | session-start | Session bound to pattern-retry; sessionId + cwd recorded | | config-loaded / config-load failed | Result of merging ~/.pattern-retry.json + project override | | trigger:matched | A provider/error trigger arrived; lists matched pattern names | | trigger:skipped-disabled / trigger:skipped-no-session | Trigger dropped — explains why | | schedule:armed | Timer set; attempt, delaySec, trigger metadata | | schedule:skip-idempotent | Duplicate trigger dropped because a live timer already exists | | schedule:skip-exhausted / schedule:exhausted | All attempts used up | | timer:elapsed | Scheduled delay elapsed; about to fire | | fire:injected | Continuation message sent via pi.sendUserMessage | | fire:reset-on-progress | Agent advanced before timer fired → attempt counter reset, no send | | cancel:pattern / cancel:session | /pattern-retry-reset or session shutdown | | command:toggle / command:reset / command:reset-all | Audit trail for user commands | | notify:<event>:<target> | A configured notify target fired (V1: log-only) |

When something looks wrong:

tail -f ~/.pi/logs/extensions/pattern-retry.log
# or from inside a session:
/pattern-retry-log 200

The file is the source of truth — every fire, skip, reset, and exhaustion is there with the sessionId and pattern name attached, so you can reconstruct exactly what happened and why.

Notify hooks (V1: no-op)

Each pattern may carry notify?: ("webhook" | "dashboard")[]. V1 logs one line per enabled target — real HTTP/WebSocket senders ship in V2 (see flow/plans/pattern-retry-future.md upstream).

The notifyHooks() signature is the public contract — V2 swaps the implementation without changing callers.

How it differs from todo-enforcer

| Plugin | Trigger | Use case | |---------------------|----------------------------------|-------------------------------------------------| | todo-enforcer | Idle agent with pending todos | Nudge the agent to keep working on its list | | pi-pattern-retry | Provider error / quota signal | Resume after an external rate-limit or outage |

They share the retry-scheduler pattern (copy-adapted), not code — install one without the other.

License

MIT