Skip to content

fix: stop codex harness retry loop draining tokens on exhausted rate-limit reconnects#41385

Merged
pelikhan merged 5 commits into
mainfrom
copilot/retry-loop-drained-tokens-2
Jun 25, 2026
Merged

fix: stop codex harness retry loop draining tokens on exhausted rate-limit reconnects#41385
pelikhan merged 5 commits into
mainfrom
copilot/retry-loop-drained-tokens-2

Conversation

Copilot AI commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

When a codex session hit a TPM rate limit, its internal reconnect loop exhausted all 5 attempts (Reconnecting... 1/55/5), then exited non-zero with hasOutput=true. The harness didn't recognise "Rate limit reached for gpt-4o-mini..." as a rate-limit error (pattern only matched rate_limit_exceeded / 429 Too Many Requests / RateLimitError), so it classified the failure as "partial execution" and retried 3 more times — each consuming a full TPM budget, running for ~15 min/attempt, totalling 63+ minutes.

Changes

  • Expand RATE_LIMIT_ERROR_PATTERN — adds Rate limit reached to catch the human-readable format codex emits in reconnect/error JSON lines.

  • Detect exhausted reconnects as non-retryable — new RECONNECT_EXHAUSTED_PATTERN uses a backreference to match Reconnecting... N/N (both numbers identical = last attempt, e.g. 5/5) while ignoring intermediate attempts (1/5, 3/5). When this appears together with a rate-limit error, the harness stops retrying:

    // "1/5", "3/5" → still retrying internally, harness should still retry if needed
    // "5/5"        → all reconnects spent; fresh run hits same limit immediately
    const RECONNECT_EXHAUSTED_PATTERN = /Reconnecting\.\.\.\s+(\d+)\/\1\b/;
    
  • Add maxRunsExceeded to codex non-retryable guardclaude_harness.cjs already checked this; codex_harness.cjs was missing it.


pr-sous-chef: requested branch update for review freshness.
Run: https://github.com/github/gh-aw/actions/runs/28152194350

Generated by 👨‍🍳 PR Sous Chef · 79.1 AIC · ⌖ 1.4 AIC · ⊞ 17.1K ·

Copilot AI linked an issue Jun 25, 2026 that may be closed by this pull request
…limit reconnects

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix retry loop that drains all tokens fix: stop codex harness retry loop draining tokens on exhausted rate-limit reconnects Jun 25, 2026
Copilot AI requested a review from pelikhan June 25, 2026 06:07
@pelikhan pelikhan marked this pull request as ready for review June 25, 2026 06:27
Copilot AI review requested due to automatic review settings June 25, 2026 06:27
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #41385 does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts the Codex CLI harness retry logic to avoid wasting tokens/time when Codex hits a TPM rate limit and exhausts its own internal reconnect attempts, and to align Codex’s non-retryable guard conditions with other harnesses.

Changes:

  • Expand Codex rate-limit detection to also match the human-readable "Rate limit reached ..." message format.
  • Stop harness-level retries when Codex output shows both a rate-limit error and an exhausted internal reconnect sequence (Reconnecting... N/N).
  • Treat max_runs_exceeded as a non-retryable guard condition for Codex, matching existing behavior in other harnesses, and add/extend tests for these scenarios.
Show a summary per file
File Description
actions/setup/js/codex_harness.cjs Expands rate-limit matching and adds an “exhausted reconnects + rate limit” non-retryable break, plus maxRunsExceeded handling.
actions/setup/js/codex_harness.test.cjs Updates retry-policy tests to cover the new rate-limit string format, exhausted reconnect detection, and max_runs_exceeded.

Copilot's findings

Tip

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

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment thread actions/setup/js/codex_harness.test.cjs Outdated
Comment on lines 412 to 413
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached/i;
const SERVER_ERROR_PATTERN = /InternalServerError|ServiceUnavailableError|500 Internal Server Error|503 Service Unavailable/i;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated in commit 8f2536b: the test helper now calls isRateLimitError and isServerError directly, so the retry behavior tests stay aligned with production detection logic.

@github-actions github-actions Bot mentioned this pull request Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 97/100 — Excellent

Analyzed 10 test(s) in actions/setup/js/codex_harness.test.cjs: 10 design, 0 implementation, 0 guideline violation(s).

📊 Metrics & Test Classification (10 tests analyzed)
Metric Value
New/modified tests analyzed 10
✅ Design tests (behavioral contracts) 10 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 9 (90%)
Duplicate test clusters 0
Test inflation detected NO (73 test additions / 43 production additions = 1.70:1 < 2:1 threshold)
🚨 Coding-guideline violations 0
Test File Classification Issues Detected
"does not retry when maximum LLM invocations are exceeded" codex_harness.test.cjs ✅ Design
"retries on rate limit with 'Rate limit reached for' without exhausted reconnects" codex_harness.test.cjs ✅ Design
"does not retry when rate-limit reconnects are exhausted (N/N pattern)" codex_harness.test.cjs ✅ Design
"retries when reconnects are exhausted but no rate-limit error is present" codex_harness.test.cjs ✅ Design
isReconnectExhaustedError: "returns true when output contains Reconnecting N/N pattern" codex_harness.test.cjs ✅ Design
isReconnectExhaustedError: "returns true for last reconnect embedded in JSON output" codex_harness.test.cjs ✅ Design
isReconnectExhaustedError: "returns false when reconnect attempt is not the last" codex_harness.test.cjs ✅ Design
isReconnectExhaustedError: "returns false when output has no reconnect messages" codex_harness.test.cjs ✅ Design
isReconnectExhaustedError: "returns true for multi-digit N/N" codex_harness.test.cjs ✅ Design
isReconnectExhaustedError: "returns false for N/M where N !== M" codex_harness.test.cjs ✅ Design

Go: 0 (*_test.go); JavaScript: 10 (*.test.cjs). No other languages detected.

Scoring breakdown:

  • Behavioral coverage: 10/10 × 40 = 40 pts
  • Error/edge coverage: 9/10 × 30 = 27 pts
  • Low duplication: 0 clusters × −5 = 20 pts
  • Proportional growth: 1.70:1 ratio (under threshold) = 10 pts

Verdict

Check passed. 0% implementation tests (threshold: 30%). All 10 new tests verify observable behavioral contracts — no mocks, no internal-only assertions, and excellent edge case coverage including the critical exhausted-reconnect/rate-limit boundary and multi-digit N/N regex handling.

References: §28151305743

🧪 Test quality analysis by Test Quality Sentinel · 81 AIC · ⌖ 21.4 AIC · ⊞ 8.4K ·

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 97/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 10 new tests verify behavioral contracts with good edge case coverage.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnose and /tdd — approving with minor suggestions.

📋 Key Themes & Highlights

Root-Cause Analysis (/diagnose)

The fix correctly targets the actual failure: the harness was pattern-matching too narrowly and re-running sessions that had already drained their TPM budget. Both changes address the root cause:

  • Pattern expansion: Rate limit reached covers the human-readable reconnect-error format Codex emits in addition to the three existing machine-readable forms.
  • Exhausted-reconnect gate: the RECONNECT_EXHAUSTED_PATTERN backreference (\d+\/\1) is an elegant, correct way to distinguish "last attempt" from "intermediate attempt" without parsing the counter fraction explicitly.
  • maxRunsExceeded parity: the codex_harness was silently ignoring a guard that claude_harness already handled — good catch.

Test Coverage (/tdd)

Seven focused tests were added covering: new rate-limit format (with and without exhausted reconnects), reconnect-exhaustion alone without rate-limit (still retryable), multi-digit N/N, N/M mismatch, and maxRunsExceeded. The matrix is solid.

Minor gaps flagged inline:

  1. isRateLimitError unit-test suite — not extended with the new "Rate limit reached for" variant; only covered via the integration shouldRetry helper.
  2. RATE_LIMIT_ERROR_PATTERN duplication — the test helper re-declares the regex locally rather than calling the imported isRateLimitError; future pattern changes need two edits.
  3. Pattern specificityRate limit reached is slightly broader than needed; Rate limit reached for would anchor to the observed Codex message format.

Positive Highlights

  • ✅ Backreference regex is ReDoS-safe (no nested quantifiers)
  • ✅ Guard ordering is correct: maxRunsExceeded checked before reconnect-exhaustion, so no ambiguous overlap
  • ✅ New non-retryable path logs clearly, matching the style of other break sites
  • ✅ PR description is exemplary — concrete reproduction, exact log lines, and a commented code snippet explaining the regex semantics

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 68.1 AIC · ⌖ 8.78 AIC · ⊞ 6.5K

Comment thread actions/setup/js/codex_harness.test.cjs Outdated
function shouldRetry(result, attempt) {
if (result.exitCode === 0) return false;
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError/i;
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached/i;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] shouldRetry re-declares RATE_LIMIT_ERROR_PATTERN as a local constant instead of calling the imported isRateLimitError. This is a latent drift risk: if the production pattern changes again, the update must be made in both places.

💡 Suggestion

Replace lines 412 and 419 with:

const isRateLimit = isRateLimitError(result.output);

This keeps the helper honest — it tests the same function that main() actually calls, and the pattern is maintained in exactly one place.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applied in commit 8f2536b: shouldRetry now uses isRateLimitError(result.output) instead of a local rate-limit regex copy.

expect(shouldRetry(result, 0)).toBe(false);
});

it("retries on rate limit with format 'Rate limit reached for' without exhausted reconnects", () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The new "Rate limit reached for ..." format is tested here through the shouldRetry integration helper, but the dedicated isRateLimitError unit-test block (lines 88–110) was not extended to cover this variant. That block already has cases for each of the other three alternatives.

💡 Suggested addition to the isRateLimitError describe block
it("returns true for 'Rate limit reached for' human-readable message", () => {
  expect(
    isRateLimitError(
      "Rate limit reached for gpt-4o-mini in organization org-xxx on tokens per min (TPM): " +
      "Limit 200000, Used 166655, Requested 35398. Please try again in 615ms."
    )
  ).toBe(true);
});

Keeping each alternative in the unit test makes the contract of isRateLimitError self-documenting and ensures regression detection stays close to the function under test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added in commit 8f2536b: the isRateLimitError unit-test block now includes a dedicated case for the human-readable Rate limit reached for ... on tokens per min message.

Comment thread actions/setup/js/codex_harness.cjs Outdated
// ("429 Too Many Requests"), the client-side exception class ("RateLimitError"), and
// the human-readable message Codex emits inside "Reconnecting..." / error lines:
// "Rate limit reached for <model> in organization <org> on tokens per min (TPM): ..."
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached/i;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/diagnose] Rate limit reached is a more general phrase than the other three alternatives, which are all tied to specific OpenAI error codes or HTTP verbs. There is a small risk that a non-rate-limit message (e.g., from a proxy or another API) containing this phrase triggers a false positive, causing the harness to back off unnecessarily.

💡 Consider a tighter anchor

The Codex-emitted format appears to be Rate limit reached for <model>. Anchoring on Rate limit reached for rather than just Rate limit reached reduces the false-positive surface while still covering all observed messages:

const RATE_LIMIT_ERROR_PATTERN =
  /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached for /i;

The trailing space ensures the phrase is followed by a model name, not just any word. Low priority — the current pattern is correct for the observed Codex format — but worth noting.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Implemented in commit 8f2536b: the production pattern is now tightened to Rate limit reached for .+ on tokens per min to reduce false positives from generic prose.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

REQUEST_CHANGES — two correctness issues and one test coverage gap must be addressed

The maxRunsExceeded addition and RECONNECT_EXHAUSTED_PATTERN backreference logic are sound. However there are two blocking issues with the rate-limit classification and one test design problem that must be addressed before merge.

Blocking findings

1. Rate limit reached is too broad for a phrase used in non-retry suppression (harness line 66)

Plain-English phrases like "Rate limit reached" appear in application code, docs, and prompts agents routinely touch. Adding this phrase to a pattern whose false positives stop retrying — not just add retries — is disproportionately risky. Should be anchored to the specific provider message structure (Rate limit reached for .+ on tokens per min).

2. Hard-stopping on exhausted reconnects discards the backoff window (harness line 505)

The harness has INITIAL_DELAY_MS / MAX_DELAY_MS backoff expressly to let transient limits expire before a fresh run. By breaking unconditionally, we discard that recovery path. For the 15-min session scenario in the PR description the TPM tokens from the first 14 minutes are outside the rolling window by the time a retried attempt reaches the same point. Stopping after exactly 0 further attempts converts timing-based failures into permanent failures. At minimum this tradeoff needs documentation; ideally it allows exactly one more attempt after a long delay.

3. Test helper copies pattern constants instead of calling exported helpers (test line 412)

After this PR both copies are in sync, but the sync is manual. Subsequent pattern changes will silently leave the tests testing stale logic. The helper should use the exported isRateLimitError() / isServerError() functions.

🔎 Code quality review by PR Code Quality Reviewer · 99.6 AIC · ⌖ 7.54 AIC · ⊞ 5.2K

Comment thread actions/setup/js/codex_harness.cjs Outdated
// ("429 Too Many Requests"), the client-side exception class ("RateLimitError"), and
// the human-readable message Codex emits inside "Reconnecting..." / error lines:
// "Rate limit reached for <model> in organization <org> on tokens per min (TPM): ..."
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached/i;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rate limit reached broadens the pattern to match arbitrary task output, enabling false rate-limit classification that silently suppresses retries.

💡 Details and suggested fix

The previous alternatives (rate_limit_exceeded, 429 Too Many Requests, RateLimitError) are structured tokens — an OpenAI error type field, an HTTP status string, a client exception class name — that are extremely unlikely to appear in agent-generated content. The new phrase Rate limit reached is common English and will appear whenever an agent works on code, scripts, prompts, or docs that discuss rate limiting.

Because isRateLimit feeds the new exhausted-reconnect guard (isRateLimit && isReconnectExhaustedError(result.output)), a false positive here silently converts a retryable transient failure into a permanent non-retry. The operator sees a confusing log line ("rate-limit with exhausted reconnects") for a failure that had nothing to do with rate limits.

Suggested fix — anchor to the actual provider TPM message format:

// Too broad — matches arbitrary prose:
const RATE_LIMIT_ERROR_PATTERN =
  /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached/i;

// Anchored to the specific OpenAI TPM phrase codex emits:
const RATE_LIMIT_ERROR_PATTERN =
  /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached for .+ on tokens per min/i;

This pins the match to Rate limit reached for <model> in organization <org> on tokens per min (TPM):, which won't appear in typical task output.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in commit 8f2536b by narrowing the new human-readable match to Rate limit reached for .+ on tokens per min, keeping detection specific to the provider TPM format.

// rate-limit error. Each reconnect attempt immediately failed with the same limit,
// so a fresh harness run will encounter the same rate-limit at the same point in the
// session and drain the token budget further without making progress.
if (isRateLimit && isReconnectExhaustedError(result.output)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hard-stopping on exhausted reconnects is permanent — it discards the backoff delay that could have allowed the TPM window to roll over.

💡 Details

The harness's exponential backoff (INITIAL_DELAY_MS = 5000, max MAX_DELAY_MS = 60000) between attempts was designed precisely to let transient limits expire before a fresh run. OpenAI TPM windows are 1-minute rolling windows. By the time a first codex attempt finishes (~15 min per the PR description), runs 60 s of backoff, and reaches attempt 2, the earliest tokens consumed are well outside the window — the token budget has substantially rolled over.

Attempt 1 — t=0:  runs 15 min, hits exhausted reconnect at t=15 min
            break → harness exits entirely
            ← NEW BEHAVIOR: all backoff opportunity is discarded

vs the old behavior (wrongly retrying three times) vs the better behaviour (retry once after max backoff):

Attempt 1 — t=0:  runs 15 min, hits rate-limit with exhausted reconnect
Backoff:    t=15: wait MAX_DELAY_MS (60 s) — TPM window rolls over
Attempt 2 — t=16: fresh run, window is partially cleared, succeeds (or fails cleanly)

Suggested alternative: instead of break, apply a fixed long-delay sleep (e.g., 2× the TPM window = 120 s) then allow exactly one more attempt, rather than zero. If that also exhausts reconnects, then break.

At minimum, document the tradeoff: if the failure is truly non-retryable (rate limit exceeds session budget regardless of timing), the current change is correct. If the failure is timing-based (instantaneous limit with rolling window), the current change silently discards the recovery path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Kept current behavior intentionally. This PR targets the token-drain failure mode where exhausted reconnects repeatedly consume budget without recovery. We now stop only when both conditions are present (rate-limit + exhausted N/N reconnects), while keeping normal transient retries in place for non-exhausted reconnects and other transient failures.

Comment thread actions/setup/js/codex_harness.test.cjs Outdated
function shouldRetry(result, attempt) {
if (result.exitCode === 0) return false;
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError/i;
const RATE_LIMIT_ERROR_PATTERN = /rate_limit_exceeded|429 Too Many Requests|RateLimitError|Rate limit reached/i;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Test helper re-defines RATE_LIMIT_ERROR_PATTERN locally instead of using the exported isRateLimitError(), so tests can pass while production logic silently diverges.

💡 Details and suggested fix

The shouldRetry test helper at this line owns a private copy of RATE_LIMIT_ERROR_PATTERN (and SERVER_ERROR_PATTERN). This PR just updated both the module constant and the test copy simultaneously — but that discipline is entirely manual. The next time someone extends the module's pattern, tests will stay green even though the helper's pattern no longer matches production behaviour.

The module already exports isRateLimitError and isServerError. The helper should delegate to those:

function shouldRetry(result, attempt) {
  if (result.exitCode === 0) return false;
  // ← no local RATE_LIMIT_ERROR_PATTERN / SERVER_ERROR_PATTERN needed
  if (attempt === 0 && isAuthenticationFailedError(result.output)) return false;
  if (isMissingApiKeyError(result.output)) return false;
  if (hasNumerousPermissionDeniedIssues(result.output)) return false;
  const nonRetryableGuard = detectNonRetryableHarnessGuard(result.output);
  if (nonRetryableGuard.aiCreditsExceeded || nonRetryableGuard.awfAPIProxyBlockingRequests ||
      nonRetryableGuard.goalAlreadyActive || nonRetryableGuard.maxRunsExceeded) return false;
  const isRateLimit = isRateLimitError(result.output);        // ← use export
  if (isRateLimit && isReconnectExhaustedError(result.output)) return false;
  const isTransient = isRateLimit || isServerError(result.output); // ← use export
  return attempt < MAX_RETRIES && (result.hasOutput || isTransient);
}

This makes the test helper a true adapter over the same decision functions production uses, closing the divergence risk.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in commit 8f2536b: the helper no longer re-defines rate-limit/server patterns and now delegates to exported isRateLimitError and isServerError functions.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

@github-actions

Copy link
Copy Markdown
Contributor

@copilot review all comments and address unresolved review feedback.

Generated by 👨‍🍳 PR Sous Chef · 79.1 AIC · ⌖ 1.4 AIC · ⊞ 17.1K ·

@github-actions

Copy link
Copy Markdown
Contributor

@copilot please rerun checks on the updated branch and post a short blocker summary if anything still fails.

Generated by 👨‍🍳 PR Sous Chef · 79.1 AIC · ⌖ 1.4 AIC · ⊞ 17.1K ·

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Completed. I ran the PR finisher pass, addressed the in-scope review threads, and pushed commit 8f2536b with the requested test/runtime alignment updates.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

@copilot review all comments and address unresolved review feedback.

Generated by 👨‍🍳 PR Sous Chef · 73.8 AIC · ⌖ 0.98 AIC · ⊞ 17.1K ·

@github-actions

Copy link
Copy Markdown
Contributor

Please summarize the remaining blockers and the next smallest step to get this PR mergeable.

Generated by 👨‍🍳 PR Sous Chef · 73.8 AIC · ⌖ 0.98 AIC · ⊞ 17.1K ·

@pelikhan pelikhan merged commit c359523 into main Jun 25, 2026
14 checks passed
@pelikhan pelikhan deleted the copilot/retry-loop-drained-tokens-2 branch June 25, 2026 12:14
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.

retry loop drained all tokens #2

3 participants