Skip to content

Add --wait flag for rate limit retry#168

Merged
umputun merged 4 commits intomasterfrom
wait-on-limit
Mar 1, 2026
Merged

Add --wait flag for rate limit retry#168
umputun merged 4 commits intomasterfrom
wait-on-limit

Conversation

@umputun
Copy link
Copy Markdown
Owner

@umputun umputun commented Mar 1, 2026

Summary
Add --wait CLI flag and wait_on_limit config option that enable automatic retry when rate limits are detected instead of exiting. When a limit pattern matches and wait is configured, ralphex waits the specified duration and retries indefinitely until success or context cancellation.

Related to #166, #157, #47

Changes

  • LimitPatternError type in executor package, checked before error patterns in all three executors (claude, codex, custom)
  • claude_limit_patterns and codex_limit_patterns config options with parsing, validation, and merge support
  • wait_on_limit duration config option and --wait CLI flag (CLI takes precedence)
  • runWithLimitRetry() wrapper in runner that handles retry logic for all executor calls
  • Documentation updates in CLAUDE.md, README.md, and llms.txt

Design

  • Limit patterns intentionally overlap with error patterns — wait_on_limit acts as the toggle between retry and exit behavior
  • Retries indefinitely; user kills via Ctrl+C (context cancellation respected during wait)
  • sleepWithContext ensures clean shutdown during wait periods

Add LimitPatternError type for rate limit detection, checked before
error patterns in all three executors (claude, codex, custom).
Enables callers to distinguish rate limits from other errors via
errors.As() for retry logic.
Copilot AI review requested due to automatic review settings March 1, 2026 02:26
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.02%. Comparing base (4ed0bbb) to head (9e7ca1a).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #168      +/-   ##
==========================================
+ Coverage   76.53%   77.02%   +0.49%     
==========================================
  Files          40       40              
  Lines        5433     5520      +87     
==========================================
+ Hits         4158     4252      +94     
+ Misses        941      934       -7     
  Partials      334      334              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Mar 1, 2026

Deploying ralphex with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9e7ca1a
Status: ✅  Deploy successful!
Preview URL: https://471f3bef.ralphex.pages.dev
Branch Preview URL: https://wait-on-limit.ralphex.pages.dev

View logs

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds configurable “rate limit detection + wait-and-retry” behavior to ralphex, allowing long-running sessions to pause on provider limits instead of exiting, driven by a new --wait flag / wait_on_limit config and new “limit pattern” matchers in executors.

Changes:

  • Introduces LimitPatternError and LimitPatterns handling in Claude/Codex/Custom executors (checked before error patterns).
  • Adds config support for claude_limit_patterns, codex_limit_patterns, and wait_on_limit (with merge/validation), plus a --wait CLI override.
  • Adds runWithLimitRetry() in the runner to wait with context cancellation and retry indefinitely on limit matches; expands tests + docs.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/processor/runner.go Adds waitOnLimit and wraps executor calls with runWithLimitRetry(); logs limit/error pattern matches.
pkg/processor/runner_test.go Adds unit tests for limit matching behavior and retry/cancel semantics.
pkg/processor/export_test.go Exposes runner internals (WaitOnLimit, runWithLimitRetry) for tests.
pkg/executor/executor.go Adds LimitPatternError, LimitPatterns for Claude, and renames checkErrorPatternsmatchPattern.
pkg/executor/executor_test.go Updates pattern-matching tests and adds coverage for limit matching precedence.
pkg/executor/codex.go Adds LimitPatterns and checks them before error patterns.
pkg/executor/codex_test.go Adds tests for Codex limit-pattern detection and precedence.
pkg/executor/custom.go Adds LimitPatterns and checks them before error patterns.
pkg/executor/custom_test.go Adds tests for Custom executor limit-pattern detection and precedence.
pkg/config/values.go Parses/merges new limit pattern lists and wait_on_limit duration with validation.
pkg/config/values_test.go Adds tests for parsing/merging limit patterns and wait_on_limit.
pkg/config/config.go Wires parsed values into runtime config, including WaitOnLimit(Set).
pkg/config/defaults/config Documents and provides defaults for limit patterns and wait_on_limit.
cmd/ralphex/main.go Adds --wait CLI flag and applies it as a config override.
cmd/ralphex/main_test.go Adds tests asserting CLI --wait precedence behavior.
README.md Documents --wait, limit pattern config options, and precedence/behavior.
CLAUDE.md Updates developer documentation for new limit-pattern and wait/retry behavior.
llms.txt Updates examples and configuration notes for --wait / limit retry.
docs/plans/completed/20260228-wait-on-limit.md Adds completed implementation plan documenting design and acceptance criteria.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/ralphex/main.go
Comment on lines 1009 to +1013
}
if o.Wait > 0 {
cfg.WaitOnLimit = o.Wait
cfg.WaitOnLimitSet = true
}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--wait accepts a time.Duration, so negative values (e.g. --wait=-30m) will parse successfully, but are silently ignored because overrides only apply when o.Wait > 0. This makes CLI behavior inconsistent with config parsing (which errors on negative wait_on_limit) and can surprise users. Consider validating o.Wait >= 0 (and erroring if negative) in validateFlags, and optionally allowing --wait=0s to explicitly disable an inherited config value if you want full precedence semantics.

Copilot uses AI. Check for mistakes.
Comment thread pkg/processor/runner.go
limitErr.Pattern, toolName, r.waitOnLimit)

if err := r.sleepWithContext(ctx, r.waitOnLimit); err != nil {
return executor.Result{Error: fmt.Errorf("interrupted during limit wait: %w", ctx.Err())}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When sleepWithContext returns an error, runWithLimitRetry wraps ctx.Err() instead of the returned err, which drops the original context (currently it prefixes with "sleep interrupted"). Wrapping err directly will preserve the full error chain/message and is more robust if sleepWithContext ever changes to return different errors.

Suggested change
return executor.Result{Error: fmt.Errorf("interrupted during limit wait: %w", ctx.Err())}
return executor.Result{Error: fmt.Errorf("interrupted during limit wait: %w", err)}

Copilot uses AI. Check for mistakes.
Comment thread pkg/config/defaults/config Outdated
Comment on lines +187 to +188
# empty or omitted = disabled (limit patterns fall through to error pattern exit behavior)
# wait_on_limit =
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The template comment says "empty or omitted = disabled", but with the current merge semantics an empty wait_on_limit = in a local config file will not override a non-empty global value (because WaitOnLimitSet remains false). Consider clarifying here that wait_on_limit = 0s is the way to explicitly disable/override an inherited global setting.

Suggested change
# empty or omitted = disabled (limit patterns fall through to error pattern exit behavior)
# wait_on_limit =
# omit or leave empty to inherit any configured global value; set to 0s to explicitly disable
# example (explicitly disable/override inherited setting): wait_on_limit = 0s

Copilot uses AI. Check for mistakes.
Add claude_limit_patterns, codex_limit_patterns, and wait_on_limit
config options with parsing, validation, and merge support.
Limit patterns are checked before error patterns when wait is configured.
Add --wait flag (duration) that enables automatic retry when rate
limits are detected. Wire limit patterns from config to executors,
add runWithLimitRetry wrapper for all executor calls in runner.
Retries indefinitely until success or context cancellation.
Update CLAUDE.md, README.md, and llms.txt with --wait flag,
limit patterns, and retry behavior documentation.
@umputun umputun merged commit 00e5907 into master Mar 1, 2026
3 checks passed
@umputun umputun deleted the wait-on-limit branch March 1, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants