You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
it("returns true for OpenAI TPM-limit wording",()=>{
96
+
expect(isTokenPerMinuteRateLimitError("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);
97
+
});
98
+
99
+
it("returns false for generic rate-limit wording",()=>{
it("retries on rate limit with format 'Rate limit reached for' without exhausted reconnects",()=>{
514
+
it("does not retry on token-per-minute rate limit wording",()=>{
498
515
constresult={
499
516
exitCode: 1,
500
517
hasOutput: false,
501
518
output: '{"type":"error","message":"Rate limit reached for gpt-4o-mini in organization org-xxx on tokens per min (TPM): Limit 200000, Used 50000, Requested 35000. Please try again in 615ms."}',
502
519
};
503
-
expect(shouldRetry(result,0)).toBe(true);
520
+
expect(shouldRetry(result,0)).toBe(false);
521
+
});
522
+
523
+
it("does not retry on token-per-minute rate limit wording even with partial output",()=>{
524
+
constresult={
525
+
exitCode: 1,
526
+
hasOutput: true,
527
+
output: '{"type":"error","message":"Rate limit reached for gpt-4o-mini in organization org-xxx on tokens per min (TPM): Limit 200000, Used 50000, Requested 35000. Please try again in 615ms."}',
528
+
};
529
+
expect(shouldRetry(result,0)).toBe(false);
504
530
});
505
531
506
-
it("does not retry when rate-limit reconnects are exhausted (N/N pattern)",()=>{
532
+
it("does not retry when rate-limit reconnects are exhausted (non-TPM rate limit)",()=>{
507
533
// Simulates the real log format: multiple Reconnecting... lines appear in
508
534
// the output as codex retries the stream. The final "5/5" line is what
509
535
// triggers the exhausted-reconnect detection; intermediate lines (1/5, 2/5)
510
536
// confirm that the function ignores non-final attempts.
511
537
constoutput=
512
-
'{"type":"error","message":"Reconnecting... 1/5 (stream disconnected before completion: Rate limit reached for gpt-4o-mini on tokens per min (TPM): Limit 200000, Used 166655, Requested 35398. Please try again in 615ms.)"}\n'+
513
-
'{"type":"error","message":"Reconnecting... 2/5 (stream disconnected before completion: Rate limit reached for gpt-4o-mini on tokens per min (TPM): Limit 200000, Used 166655, Requested 35398. Please try again in 615ms.)"}\n'+
514
-
'{"type":"error","message":"Reconnecting... 5/5 (stream disconnected before completion: Rate limit reached for gpt-4o-mini on tokens per min (TPM): Limit 200000, Used 166655, Requested 35398. Please try again in 615ms.)"}';
538
+
'{"type":"error","message":"Reconnecting... 1/5 (stream disconnected before completion: RateLimitError)"}\n'+
539
+
'{"type":"error","message":"Reconnecting... 2/5 (stream disconnected before completion: RateLimitError)"}\n'+
540
+
'{"type":"error","message":"Reconnecting... 5/5 (stream disconnected before completion: RateLimitError)"}';
it("detects goal already active for unfinished-goal wording",()=>{
96
+
constresult=detectNonRetryableHarnessGuard("cannot create a new goal because this thread has an unfinished goal; complete the existing goal first");
97
+
expect(result.goalAlreadyActive).toBe(true);
98
+
});
99
+
100
+
it("detects goal already active for unfinished-goal wording (JSON-wrapped)",()=>{
101
+
constresult=detectNonRetryableHarnessGuard('{"type":"error","message":"cannot create a new goal because this thread has an unfinished goal; complete the existing goal first"}');
102
+
expect(result.goalAlreadyActive).toBe(true);
103
+
});
104
+
95
105
it("detects max_runs_exceeded by JSON error type",()=>{
Copy file name to clipboardExpand all lines: docs/src/content/docs/reference/engines.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -296,6 +296,12 @@ The value must be a bare filename — no directory separators, no `..`, and no s
296
296
> [!NOTE]
297
297
> `engine.harness` is currently only applied during Copilot engine execution. Setting it on other engines has no effect.
298
298
299
+
### Harness Retry Count
300
+
301
+
Built-in harness scripts (`copilot_harness.cjs`, `claude_harness.cjs`, `codex_harness.cjs`) currently use a fixed retry budget of **3 retries** after the initial run (4 total attempts).
302
+
303
+
To specify a different retry count, provide a custom harness script and implement your own retry policy there. At present, `engine.harness` customization is only applied for the Copilot engine.
0 commit comments