@ai0x0/codex-ts 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -0
- package/dist/core/src/codex_thread.d.ts +8 -0
- package/dist/core/src/codex_thread.d.ts.map +1 -1
- package/dist/core/src/codex_thread.js +4 -0
- package/dist/core/src/codex_thread.js.map +1 -1
- package/dist/core/src/session/retry.d.ts +59 -0
- package/dist/core/src/session/retry.d.ts.map +1 -0
- package/dist/core/src/session/retry.js +124 -0
- package/dist/core/src/session/retry.js.map +1 -0
- package/dist/core/src/session/turn.d.ts +8 -0
- package/dist/core/src/session/turn.d.ts.map +1 -1
- package/dist/core/src/session/turn.js +101 -59
- package/dist/core/src/session/turn.js.map +1 -1
- package/dist/core/tests/suite/retry.test.d.ts +2 -0
- package/dist/core/tests/suite/retry.test.d.ts.map +1 -0
- package/dist/core/tests/suite/retry.test.js +173 -0
- package/dist/core/tests/suite/retry.test.js.map +1 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @ai0x0/codex-ts
|
|
2
|
+
|
|
3
|
+
A TypeScript port of the codex-rs agent core — runs the Codex sampling loop
|
|
4
|
+
(Responses API streaming + tool calls + auto-compaction) directly in Node or the
|
|
5
|
+
browser, with no spawned process.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CodexThread } from "@ai0x0/codex-ts";
|
|
9
|
+
|
|
10
|
+
const thread = new CodexThread({
|
|
11
|
+
apiKey: "…",
|
|
12
|
+
baseUrl: "https://api.openai.com/v1",
|
|
13
|
+
model: "gpt-5.4",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const turnId = await thread.submit({
|
|
17
|
+
type: "UserInput",
|
|
18
|
+
items: [{ type: "text", text: "hello" }],
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
for (;;) {
|
|
22
|
+
const { msg } = await thread.nextEvent();
|
|
23
|
+
if (msg.type === "AgentMessage") console.log(msg.event.message);
|
|
24
|
+
if (msg.type === "TurnComplete") break;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Retries
|
|
29
|
+
|
|
30
|
+
Transient Responses failures are retried automatically with exponential
|
|
31
|
+
backoff — mirrors codex-rs's stream retry loop (`responses_retry.rs`).
|
|
32
|
+
|
|
33
|
+
A failure is **retried** when it happens **before any visible output has
|
|
34
|
+
streamed** and is transient:
|
|
35
|
+
|
|
36
|
+
- a network error (fetch rejects: connection reset, DNS, CORS-masked failure…);
|
|
37
|
+
- an HTTP `408`, `409`, `429`, or any `5xx` (e.g. a `502` during a deploy
|
|
38
|
+
window);
|
|
39
|
+
- the SSE stream dropping before the first text delta.
|
|
40
|
+
|
|
41
|
+
A failure is **not retried** when:
|
|
42
|
+
|
|
43
|
+
- visible output has already streamed (a re-stream would duplicate text);
|
|
44
|
+
- the error is terminal — `4xx` other than the above (e.g. `400`, `401`), or the
|
|
45
|
+
turn was interrupted (`AbortError`);
|
|
46
|
+
- the retry budget (`maxRetries`) is exhausted.
|
|
47
|
+
|
|
48
|
+
Each retry waits an exponential backoff — `200ms × 2^(n-1)` with ±10% jitter —
|
|
49
|
+
honoring a server `Retry-After` header when present. A `Warning` event
|
|
50
|
+
(`Reconnecting... n/m`) is emitted before each attempt so the UI can surface it.
|
|
51
|
+
|
|
52
|
+
### Configuration
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const thread = new CodexThread({
|
|
56
|
+
apiKey: "…",
|
|
57
|
+
model: "gpt-5.4",
|
|
58
|
+
// Max retries for transient request/stream failures. Default: 5.
|
|
59
|
+
// Pass 0 to disable retries entirely.
|
|
60
|
+
maxRetries: 5,
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Option | Default | Meaning |
|
|
65
|
+
| ------------ | ------- | ---------------------------------------------------------- |
|
|
66
|
+
| `maxRetries` | `5` | Max retry attempts after the initial request. `0` disables. |
|
|
67
|
+
|
|
68
|
+
The same budget covers both the initial request and a stream that drops before
|
|
69
|
+
any output; `Retry-After` overrides the computed backoff for that attempt.
|
|
@@ -88,6 +88,14 @@ export interface CodexThreadConfig {
|
|
|
88
88
|
* Omit to disable auto-compaction entirely.
|
|
89
89
|
*/
|
|
90
90
|
autoCompactTokenLimit?: number | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Max retries for transient Responses request/stream failures — network
|
|
93
|
+
* errors, 5xx / 408 / 409 / 429, or a stream dropped before any visible
|
|
94
|
+
* output. Each retry waits an exponential backoff (200ms × 2^(n-1) ± 10%
|
|
95
|
+
* jitter), honoring a server Retry-After when present. mirrors codex-rs
|
|
96
|
+
* stream/request_max_retries. Defaults to 5; pass 0 to disable retries.
|
|
97
|
+
*/
|
|
98
|
+
maxRetries?: number | undefined;
|
|
91
99
|
}
|
|
92
100
|
export declare class CodexThread {
|
|
93
101
|
private readonly config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex_thread.d.ts","sourceRoot":"","sources":["../../../core/src/codex_thread.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,KAAK,EAEL,EAAE,EAGH,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,SAAS,EAAuB,MAAM,kCAAkC,CAAC;AAMlF,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAG9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8CjD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACvC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACrC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAC3E;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"codex_thread.d.ts","sourceRoot":"","sources":["../../../core/src/codex_thread.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,KAAK,EAEL,EAAE,EAGH,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,SAAS,EAAuB,MAAM,kCAAkC,CAAC;AAMlF,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAG9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA8CjD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACvC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACrC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAC3E;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAkBD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;IAEtD,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAG1B;IAEJ,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IAExC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB,CAAgC;gBAE5C,MAAM,EAAE,iBAAiB;IAiCrC,sDAAsD;IACtD,IAAI,EAAE,IAAI,MAAM,CAA0B;IAE1C;;;;;;;;;OASG;WACU,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IASpE;;;OAGG;IACG,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA0HrC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC;IAIjC,OAAO,CAAC,SAAS;CAGlB"}
|
|
@@ -82,6 +82,7 @@ export class CodexThread {
|
|
|
82
82
|
loadSkillContent: config.loadSkillContent,
|
|
83
83
|
agentsMd: config.agentsMd,
|
|
84
84
|
autoCompactTokenLimit: config.autoCompactTokenLimit,
|
|
85
|
+
maxRetries: config.maxRetries,
|
|
85
86
|
};
|
|
86
87
|
this.threadId = config.threadId ?? nextId();
|
|
87
88
|
// Resolve ThreadStore: explicit > ioBackend shorthand > in-memory
|
|
@@ -176,6 +177,9 @@ export class CodexThread {
|
|
|
176
177
|
...(this.config.autoCompactTokenLimit !== undefined
|
|
177
178
|
? { autoCompactTokenLimit: this.config.autoCompactTokenLimit }
|
|
178
179
|
: {}),
|
|
180
|
+
...(this.config.maxRetries !== undefined
|
|
181
|
+
? { maxRetries: this.config.maxRetries }
|
|
182
|
+
: {}),
|
|
179
183
|
};
|
|
180
184
|
const abortController = new AbortController();
|
|
181
185
|
this.currentTurnAbort = abortController;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex_thread.js","sourceRoot":"","sources":["../../../core/src/codex_thread.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAClF,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,GACX,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AASlD,MAAM,UAAU;IACN,GAAG,GAAQ,EAAE,CAAC;IACd,OAAO,GAAuC,EAAE,CAAC;IACjD,MAAM,GAAG,KAAK,CAAC;IAEvB,IAAI,CAAC,KAAQ;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,MAAM;YAAE,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;;YACtC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAG,CAAC;QAClD,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACxD,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC1B,IAAI,KAAK,CAAC,IAAI;oBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;;oBACpD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,iFAAiF;AAEjF,IAAI,IAAI,GAAG,CAAC,CAAC;AACb,SAAS,MAAM;IACb,OAAO,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACnE,CAAC;
|
|
1
|
+
{"version":3,"file":"codex_thread.js","sourceRoot":"","sources":["../../../core/src/codex_thread.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mirrors codex-rs/core/src/responses_retry.rs + codex-rs/core/src/util.rs::backoff
|
|
3
|
+
*
|
|
4
|
+
* Shared retry decisions for Responses API requests: which failures are
|
|
5
|
+
* transient (retryable), and how long to back off between attempts.
|
|
6
|
+
*
|
|
7
|
+
* Unlike codex-rs (which can re-stream in place into a TUI), codex-ts emits
|
|
8
|
+
* AgentMessageContentDelta events live, so the turn loop only retries failures
|
|
9
|
+
* that happen BEFORE any visible output was streamed — see runTurn. The decision
|
|
10
|
+
* helpers here are agnostic to that policy.
|
|
11
|
+
*/
|
|
12
|
+
/** Default retry budget for transient Responses failures (mirrors the spirit of
|
|
13
|
+
* codex-rs stream_max_retries; the host can override via CodexThreadConfig). */
|
|
14
|
+
export declare const DEFAULT_MAX_RETRIES = 5;
|
|
15
|
+
/**
|
|
16
|
+
* Exponential backoff with jitter, in milliseconds.
|
|
17
|
+
* delay = INITIAL_DELAY_MS * BACKOFF_FACTOR^(attempt-1) * jitter(0.9..1.1).
|
|
18
|
+
* `attempt` is 1-based (first retry = 1).
|
|
19
|
+
*/
|
|
20
|
+
export declare function backoff(attempt: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* A non-2xx Responses API response, carrying the status and (when present) the
|
|
23
|
+
* server-requested Retry-After delay so the retry loop can honor it.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ResponsesApiError extends Error {
|
|
26
|
+
readonly status: number;
|
|
27
|
+
readonly retryAfterMs: number | undefined;
|
|
28
|
+
constructor(status: number, body: string, retryAfterMs?: number | undefined);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Whether an HTTP status is a transient failure worth retrying. Mirrors the
|
|
32
|
+
* retryable set in codex-rs (timeouts / 5xx / unexpected status); 4xx are
|
|
33
|
+
* terminal except 408 (request timeout), 409 (conflict) and 429 (rate limit).
|
|
34
|
+
*/
|
|
35
|
+
export declare function isRetryableStatus(status: number): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Classify a thrown error as retryable. Aborts (interrupts) are terminal;
|
|
38
|
+
* ResponsesApiError defers to its status; anything else (network TypeError,
|
|
39
|
+
* dropped stream, JSON/IO error) is treated as a transient connection failure —
|
|
40
|
+
* mirrors codex-rs CodexErr::is_retryable (ConnectionFailed / Stream / Io → true).
|
|
41
|
+
*/
|
|
42
|
+
export declare function isRetryableError(error: unknown): boolean;
|
|
43
|
+
export declare function isAbortError(error: unknown): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Delay before the next attempt: honor a server Retry-After when the error
|
|
46
|
+
* carries one (e.g. 429), otherwise exponential backoff.
|
|
47
|
+
*/
|
|
48
|
+
export declare function computeRetryDelay(error: unknown, attempt: number): number;
|
|
49
|
+
/**
|
|
50
|
+
* Parse a Retry-After header (delta-seconds or HTTP-date) into milliseconds.
|
|
51
|
+
* Returns undefined when absent or unparseable.
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseRetryAfter(headers: Headers): number | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Abortable sleep. Rejects with an AbortError if the signal fires first, so a
|
|
56
|
+
* mid-backoff interrupt cancels the turn promptly.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sleep(ms: number, signal?: AbortSignal | undefined): Promise<void>;
|
|
59
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../../core/src/session/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH;iFACiF;AACjF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;gBAE9B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS;CAM5E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQxD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMpD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CASzE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAcpE;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mirrors codex-rs/core/src/responses_retry.rs + codex-rs/core/src/util.rs::backoff
|
|
3
|
+
*
|
|
4
|
+
* Shared retry decisions for Responses API requests: which failures are
|
|
5
|
+
* transient (retryable), and how long to back off between attempts.
|
|
6
|
+
*
|
|
7
|
+
* Unlike codex-rs (which can re-stream in place into a TUI), codex-ts emits
|
|
8
|
+
* AgentMessageContentDelta events live, so the turn loop only retries failures
|
|
9
|
+
* that happen BEFORE any visible output was streamed — see runTurn. The decision
|
|
10
|
+
* helpers here are agnostic to that policy.
|
|
11
|
+
*/
|
|
12
|
+
// mirrors codex-rs util.rs: INITIAL_DELAY_MS = 200, BACKOFF_FACTOR = 2.0,
|
|
13
|
+
// jitter uniform in [0.9, 1.1).
|
|
14
|
+
const INITIAL_DELAY_MS = 200;
|
|
15
|
+
const BACKOFF_FACTOR = 2;
|
|
16
|
+
/** Default retry budget for transient Responses failures (mirrors the spirit of
|
|
17
|
+
* codex-rs stream_max_retries; the host can override via CodexThreadConfig). */
|
|
18
|
+
export const DEFAULT_MAX_RETRIES = 5;
|
|
19
|
+
/**
|
|
20
|
+
* Exponential backoff with jitter, in milliseconds.
|
|
21
|
+
* delay = INITIAL_DELAY_MS * BACKOFF_FACTOR^(attempt-1) * jitter(0.9..1.1).
|
|
22
|
+
* `attempt` is 1-based (first retry = 1).
|
|
23
|
+
*/
|
|
24
|
+
export function backoff(attempt) {
|
|
25
|
+
const exp = BACKOFF_FACTOR ** Math.max(0, attempt - 1);
|
|
26
|
+
const base = INITIAL_DELAY_MS * exp;
|
|
27
|
+
const jitter = 0.9 + Math.random() * 0.2;
|
|
28
|
+
return Math.round(base * jitter);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A non-2xx Responses API response, carrying the status and (when present) the
|
|
32
|
+
* server-requested Retry-After delay so the retry loop can honor it.
|
|
33
|
+
*/
|
|
34
|
+
export class ResponsesApiError extends Error {
|
|
35
|
+
status;
|
|
36
|
+
retryAfterMs;
|
|
37
|
+
constructor(status, body, retryAfterMs) {
|
|
38
|
+
super(`Responses API ${status}: ${body}`);
|
|
39
|
+
this.name = "ResponsesApiError";
|
|
40
|
+
this.status = status;
|
|
41
|
+
this.retryAfterMs = retryAfterMs;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Whether an HTTP status is a transient failure worth retrying. Mirrors the
|
|
46
|
+
* retryable set in codex-rs (timeouts / 5xx / unexpected status); 4xx are
|
|
47
|
+
* terminal except 408 (request timeout), 409 (conflict) and 429 (rate limit).
|
|
48
|
+
*/
|
|
49
|
+
export function isRetryableStatus(status) {
|
|
50
|
+
return status === 408 || status === 409 || status === 429 || status >= 500;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Classify a thrown error as retryable. Aborts (interrupts) are terminal;
|
|
54
|
+
* ResponsesApiError defers to its status; anything else (network TypeError,
|
|
55
|
+
* dropped stream, JSON/IO error) is treated as a transient connection failure —
|
|
56
|
+
* mirrors codex-rs CodexErr::is_retryable (ConnectionFailed / Stream / Io → true).
|
|
57
|
+
*/
|
|
58
|
+
export function isRetryableError(error) {
|
|
59
|
+
if (isAbortError(error)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (error instanceof ResponsesApiError) {
|
|
63
|
+
return isRetryableStatus(error.status);
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
export function isAbortError(error) {
|
|
68
|
+
return (error instanceof DOMException &&
|
|
69
|
+
error.name === "AbortError") ||
|
|
70
|
+
(error instanceof Error && error.name === "AbortError");
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Delay before the next attempt: honor a server Retry-After when the error
|
|
74
|
+
* carries one (e.g. 429), otherwise exponential backoff.
|
|
75
|
+
*/
|
|
76
|
+
export function computeRetryDelay(error, attempt) {
|
|
77
|
+
if (error instanceof ResponsesApiError &&
|
|
78
|
+
error.retryAfterMs !== undefined &&
|
|
79
|
+
error.retryAfterMs >= 0) {
|
|
80
|
+
return error.retryAfterMs;
|
|
81
|
+
}
|
|
82
|
+
return backoff(attempt);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse a Retry-After header (delta-seconds or HTTP-date) into milliseconds.
|
|
86
|
+
* Returns undefined when absent or unparseable.
|
|
87
|
+
*/
|
|
88
|
+
export function parseRetryAfter(headers) {
|
|
89
|
+
const raw = headers.get("retry-after");
|
|
90
|
+
if (!raw) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const seconds = Number(raw);
|
|
94
|
+
if (Number.isFinite(seconds)) {
|
|
95
|
+
return Math.max(0, seconds * 1000);
|
|
96
|
+
}
|
|
97
|
+
const dateMs = Date.parse(raw);
|
|
98
|
+
if (Number.isFinite(dateMs)) {
|
|
99
|
+
return Math.max(0, dateMs - Date.now());
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Abortable sleep. Rejects with an AbortError if the signal fires first, so a
|
|
105
|
+
* mid-backoff interrupt cancels the turn promptly.
|
|
106
|
+
*/
|
|
107
|
+
export function sleep(ms, signal) {
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
if (signal?.aborted) {
|
|
110
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const timer = setTimeout(() => {
|
|
114
|
+
signal?.removeEventListener("abort", onAbort);
|
|
115
|
+
resolve();
|
|
116
|
+
}, ms);
|
|
117
|
+
const onAbort = () => {
|
|
118
|
+
clearTimeout(timer);
|
|
119
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
120
|
+
};
|
|
121
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../../core/src/session/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,14 @@ export interface TurnConfig {
|
|
|
41
41
|
* Omit to disable auto-compaction.
|
|
42
42
|
*/
|
|
43
43
|
autoCompactTokenLimit?: number | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Max retries for transient Responses request/stream failures — network
|
|
46
|
+
* errors, 5xx / 408 / 409 / 429, or a stream dropped before any visible
|
|
47
|
+
* output. Each retry waits an exponential backoff (200ms × 2^(n-1) ± 10%
|
|
48
|
+
* jitter), honoring a server Retry-After when present. mirrors codex-rs
|
|
49
|
+
* stream/request_max_retries. Defaults to DEFAULT_MAX_RETRIES (5).
|
|
50
|
+
*/
|
|
51
|
+
maxRetries?: number | undefined;
|
|
44
52
|
/**
|
|
45
53
|
* Turn-scoped context messages prepended to `input` ahead of history,
|
|
46
54
|
* mirroring codex-rs's contextual user fragments: user_instructions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../core/src/session/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../core/src/session/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAC;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,oCAAoC,CAAC;AAe5C,KAAK,WAAW,GAAG,gBAAgB,CAAC;AAIpC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACrC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IAC3E;;;;;;;;OAQG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;CAC1C;AAID,MAAM,WAAW,UAAU;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,MAAM,EAAE,QAAQ,EAAE,CAAC;CACpB;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EAAE,EACtB,OAAO,EAAE,WAAW,EAAE,EACtB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,UAAU,EAClB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,EAClC,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS;AACnC;oDACoD;AACpD,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,GACpC,OAAO,CAAC;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAC,CAsRvC"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { toolSpecToRequestJson } from "../../../tools/src/tool_spec.js";
|
|
13
13
|
import { extractSkillMentions, renderSkillInjection } from "../skills.js";
|
|
14
14
|
import { parseSseStream } from "./sse.js";
|
|
15
|
+
import { computeRetryDelay, DEFAULT_MAX_RETRIES, isRetryableError, parseRetryAfter, ResponsesApiError, sleep, } from "./retry.js";
|
|
15
16
|
import { runInlineAutoCompactTask } from "../compact.js";
|
|
16
17
|
import { AutoCompactWindow } from "../state/auto_compact_window.js";
|
|
17
18
|
export async function runTurn(turnId, userItems, history, config, router, pendingInputs, emitEvent, liveThread,
|
|
@@ -60,6 +61,7 @@ abortSignal) {
|
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
const tools = router.toolSpecs().map(toolSpecToRequestJson);
|
|
64
|
+
const maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
63
65
|
let lastAgentMessage = "";
|
|
64
66
|
let itemIdCounter = 0;
|
|
65
67
|
// ── Auto-compaction window tracker (mirrors AutoCompactWindow in codex-rs) ──
|
|
@@ -87,74 +89,114 @@ abortSignal) {
|
|
|
87
89
|
};
|
|
88
90
|
if (config.instructions)
|
|
89
91
|
body["instructions"] = config.instructions;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
body: JSON.stringify(body),
|
|
97
|
-
signal: abortSignal ?? null,
|
|
98
|
-
});
|
|
99
|
-
if (!res.ok || !res.body) {
|
|
100
|
-
const text = res.body ? await res.text() : "(no body)";
|
|
101
|
-
throw new Error(`Responses API ${res.status}: ${text}`);
|
|
102
|
-
}
|
|
103
|
-
// ── Parse SSE stream ────────────────────────────────────────────────────
|
|
92
|
+
// ── Sample from the model (retry transient failures) ────────────────────
|
|
93
|
+
// mirrors codex-rs's stream retry loop (responses_retry.rs): a network
|
|
94
|
+
// error / 5xx / 429 / dropped stream is retried with exponential backoff.
|
|
95
|
+
// Unlike codex-rs (which re-streams in place into a TUI) codex-ts emits
|
|
96
|
+
// deltas live, so we only retry while NO visible output has streamed yet —
|
|
97
|
+
// re-streaming after that would duplicate text downstream.
|
|
104
98
|
const functionCalls = [];
|
|
105
99
|
const partialArgs = new Map();
|
|
106
100
|
let assistantText = "";
|
|
107
101
|
let currentItemId = `item-${++itemIdCounter}`;
|
|
108
102
|
let inputTokensThisRound = 0;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
case "response.function_call_arguments.delta": {
|
|
132
|
-
const partial = partialArgs.get(String(raw["call_id"] ?? ""));
|
|
133
|
-
if (partial)
|
|
134
|
-
partial.args += String(raw["delta"] ?? "");
|
|
135
|
-
break;
|
|
103
|
+
let retryAttempt = 0;
|
|
104
|
+
for (;;) {
|
|
105
|
+
// A retry re-streams from scratch → reset per-attempt accumulators.
|
|
106
|
+
functionCalls.length = 0;
|
|
107
|
+
partialArgs.clear();
|
|
108
|
+
assistantText = "";
|
|
109
|
+
currentItemId = `item-${++itemIdCounter}`;
|
|
110
|
+
inputTokensThisRound = 0;
|
|
111
|
+
let emittedOutput = false;
|
|
112
|
+
try {
|
|
113
|
+
const res = await (config.fetch ?? fetch)(`${config.baseUrl}/responses`, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: {
|
|
116
|
+
"Content-Type": "application/json",
|
|
117
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify(body),
|
|
120
|
+
signal: abortSignal ?? null,
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok || !res.body) {
|
|
123
|
+
const text = res.body ? await res.text() : "(no body)";
|
|
124
|
+
throw new ResponsesApiError(res.status, text, parseRetryAfter(res.headers));
|
|
136
125
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
126
|
+
// ── Parse SSE stream ──────────────────────────────────────────────
|
|
127
|
+
for await (const raw of parseSseStream(res.body)) {
|
|
128
|
+
switch (raw["type"]) {
|
|
129
|
+
case "response.output_item.added": {
|
|
130
|
+
const item = raw["item"];
|
|
131
|
+
if (item?.["type"] === "function_call") {
|
|
132
|
+
const cid = String(item["call_id"]);
|
|
133
|
+
partialArgs.set(cid, { name: String(item["name"]), args: "" });
|
|
134
|
+
}
|
|
135
|
+
else if (item?.["type"] === "message") {
|
|
136
|
+
currentItemId = String(item["id"] ?? currentItemId);
|
|
137
|
+
}
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case "response.output_text.delta": {
|
|
141
|
+
const delta = String(raw["delta"] ?? "");
|
|
142
|
+
assistantText += delta;
|
|
143
|
+
// Visible output has streamed — past this point a retry would
|
|
144
|
+
// duplicate text, so failures below are no longer retryable.
|
|
145
|
+
emittedOutput = true;
|
|
146
|
+
emitEvent({
|
|
147
|
+
type: "AgentMessageContentDelta",
|
|
148
|
+
event: { turn_id: turnId, item_id: currentItemId, delta },
|
|
149
|
+
});
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "response.function_call_arguments.delta": {
|
|
153
|
+
const partial = partialArgs.get(String(raw["call_id"] ?? ""));
|
|
154
|
+
if (partial)
|
|
155
|
+
partial.args += String(raw["delta"] ?? "");
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "response.output_item.done": {
|
|
159
|
+
const item = raw["item"];
|
|
160
|
+
if (item?.["type"] === "function_call") {
|
|
161
|
+
functionCalls.push({
|
|
162
|
+
call_id: String(item["call_id"]),
|
|
163
|
+
name: String(item["name"]),
|
|
164
|
+
arguments: String(item["arguments"] ?? "{}"),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
case "response.done": {
|
|
170
|
+
// mirrors ensure_server_observed_prefill_from_usage in auto_compact_window.rs
|
|
171
|
+
const resp = raw["response"];
|
|
172
|
+
const usage = resp?.["usage"];
|
|
173
|
+
if (typeof usage?.["input_tokens"] === "number") {
|
|
174
|
+
inputTokensThisRound = usage["input_tokens"];
|
|
175
|
+
compactWindow.ensureServerObservedPrefill(inputTokensThisRound);
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
145
179
|
}
|
|
146
|
-
break;
|
|
147
180
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
181
|
+
break; // stream consumed successfully → leave the retry loop
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
// An interrupt is terminal — never retry past a cancellation.
|
|
185
|
+
if (abortSignal?.aborted)
|
|
186
|
+
throw err;
|
|
187
|
+
// Stop retrying once visible output streamed (would duplicate), the
|
|
188
|
+
// budget is spent, or the error is not transient.
|
|
189
|
+
if (emittedOutput ||
|
|
190
|
+
retryAttempt >= maxRetries ||
|
|
191
|
+
!isRetryableError(err)) {
|
|
192
|
+
throw err;
|
|
157
193
|
}
|
|
194
|
+
retryAttempt += 1;
|
|
195
|
+
emitEvent({
|
|
196
|
+
type: "Warning",
|
|
197
|
+
event: { message: `Reconnecting... ${retryAttempt}/${maxRetries}` },
|
|
198
|
+
});
|
|
199
|
+
await sleep(computeRetryDelay(err, retryAttempt), abortSignal);
|
|
158
200
|
}
|
|
159
201
|
}
|
|
160
202
|
// ── Persist assistant message ────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn.js","sourceRoot":"","sources":["../../../../core/src/session/turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAQ1E,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"turn.js","sourceRoot":"","sources":["../../../../core/src/session/turn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.test.d.ts","sourceRoot":"","sources":["../../../../core/tests/suite/retry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { CodexThread } from "../../src/codex_thread.js";
|
|
3
|
+
import { backoff, computeRetryDelay, isRetryableError, isRetryableStatus, parseRetryAfter, ResponsesApiError, } from "../../src/session/retry.js";
|
|
4
|
+
import { evAssistantMessage, evCompleted, evResponseCreated, makeSseResponse, sse, sseFlat, waitForEvent, } from "../common/lib.js";
|
|
5
|
+
function okSse() {
|
|
6
|
+
return makeSseResponse(sseFlat([
|
|
7
|
+
evResponseCreated("r1"),
|
|
8
|
+
evAssistantMessage("ok"),
|
|
9
|
+
evCompleted("r1"),
|
|
10
|
+
]));
|
|
11
|
+
}
|
|
12
|
+
// A non-2xx Response (no body) — turn.ts wraps it in a ResponsesApiError.
|
|
13
|
+
function errorResponse(status) {
|
|
14
|
+
return {
|
|
15
|
+
ok: false,
|
|
16
|
+
status,
|
|
17
|
+
body: null,
|
|
18
|
+
headers: new Headers(),
|
|
19
|
+
text: async () => `err ${status}`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// A 200 stream that yields one visible text delta, then drops mid-stream. Pull-
|
|
23
|
+
// based so the delta is delivered before the error (controller.error() would
|
|
24
|
+
// otherwise discard a synchronously-enqueued chunk).
|
|
25
|
+
function streamThenError() {
|
|
26
|
+
const deltaSse = sse([
|
|
27
|
+
evResponseCreated("r1"),
|
|
28
|
+
{ type: "response.output_text.delta", delta: "partial" },
|
|
29
|
+
]);
|
|
30
|
+
let stage = 0;
|
|
31
|
+
return {
|
|
32
|
+
ok: true,
|
|
33
|
+
status: 200,
|
|
34
|
+
headers: new Headers(),
|
|
35
|
+
body: new ReadableStream({
|
|
36
|
+
pull(controller) {
|
|
37
|
+
if (stage === 0) {
|
|
38
|
+
controller.enqueue(new TextEncoder().encode(deltaSse));
|
|
39
|
+
stage = 1;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
controller.error(new Error("stream dropped"));
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
text: async () => deltaSse,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
describe("retry helpers", () => {
|
|
50
|
+
it("backoff grows exponentially within the jitter band", () => {
|
|
51
|
+
expect(backoff(1)).toBeGreaterThanOrEqual(180);
|
|
52
|
+
expect(backoff(1)).toBeLessThanOrEqual(220);
|
|
53
|
+
expect(backoff(2)).toBeGreaterThanOrEqual(360);
|
|
54
|
+
expect(backoff(2)).toBeLessThanOrEqual(440);
|
|
55
|
+
expect(backoff(3)).toBeGreaterThanOrEqual(720);
|
|
56
|
+
expect(backoff(3)).toBeLessThanOrEqual(880);
|
|
57
|
+
});
|
|
58
|
+
it("classifies retryable HTTP statuses", () => {
|
|
59
|
+
for (const status of [408, 409, 429, 500, 502, 503, 504]) {
|
|
60
|
+
expect(isRetryableStatus(status)).toBe(true);
|
|
61
|
+
}
|
|
62
|
+
for (const status of [200, 400, 401, 403, 404, 422]) {
|
|
63
|
+
expect(isRetryableStatus(status)).toBe(false);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it("classifies retryable errors", () => {
|
|
67
|
+
expect(isRetryableError(new ResponsesApiError(502, "x"))).toBe(true);
|
|
68
|
+
expect(isRetryableError(new ResponsesApiError(400, "x"))).toBe(false);
|
|
69
|
+
expect(isRetryableError(new TypeError("Failed to fetch"))).toBe(true);
|
|
70
|
+
expect(isRetryableError(new DOMException("Aborted", "AbortError"))).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
it("parses Retry-After seconds and ignores when absent", () => {
|
|
73
|
+
expect(parseRetryAfter(new Headers({ "retry-after": "2" }))).toBe(2000);
|
|
74
|
+
expect(parseRetryAfter(new Headers())).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
it("computeRetryDelay honors Retry-After, else backs off", () => {
|
|
77
|
+
expect(computeRetryDelay(new ResponsesApiError(429, "x", 1500), 1)).toBe(1500);
|
|
78
|
+
const d = computeRetryDelay(new TypeError("net"), 1);
|
|
79
|
+
expect(d).toBeGreaterThanOrEqual(180);
|
|
80
|
+
expect(d).toBeLessThanOrEqual(220);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("turn retries", () => {
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
vi.unstubAllGlobals();
|
|
86
|
+
});
|
|
87
|
+
it("retries a transient network error then succeeds", async () => {
|
|
88
|
+
const fetchMock = vi
|
|
89
|
+
.fn()
|
|
90
|
+
.mockRejectedValueOnce(new TypeError("Failed to fetch"))
|
|
91
|
+
.mockResolvedValue(okSse());
|
|
92
|
+
const codex = new CodexThread({
|
|
93
|
+
apiKey: "k",
|
|
94
|
+
baseUrl: "https://example.test/v1",
|
|
95
|
+
fetch: fetchMock,
|
|
96
|
+
model: "m",
|
|
97
|
+
maxRetries: 3,
|
|
98
|
+
});
|
|
99
|
+
await codex.submit({ items: [{ text: "hi", type: "text" }], type: "UserInput" });
|
|
100
|
+
await waitForEvent(codex, (m) => m.type === "TurnComplete");
|
|
101
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
102
|
+
});
|
|
103
|
+
it("retries a 502 then succeeds", async () => {
|
|
104
|
+
const fetchMock = vi
|
|
105
|
+
.fn()
|
|
106
|
+
.mockResolvedValueOnce(errorResponse(502))
|
|
107
|
+
.mockResolvedValue(okSse());
|
|
108
|
+
const codex = new CodexThread({
|
|
109
|
+
apiKey: "k",
|
|
110
|
+
baseUrl: "https://example.test/v1",
|
|
111
|
+
fetch: fetchMock,
|
|
112
|
+
model: "m",
|
|
113
|
+
maxRetries: 3,
|
|
114
|
+
});
|
|
115
|
+
await codex.submit({ items: [{ text: "hi", type: "text" }], type: "UserInput" });
|
|
116
|
+
await waitForEvent(codex, (m) => m.type === "TurnComplete");
|
|
117
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
118
|
+
});
|
|
119
|
+
it("does not retry a non-retryable 400", async () => {
|
|
120
|
+
const fetchMock = vi.fn().mockResolvedValue(errorResponse(400));
|
|
121
|
+
const codex = new CodexThread({
|
|
122
|
+
apiKey: "k",
|
|
123
|
+
baseUrl: "https://example.test/v1",
|
|
124
|
+
fetch: fetchMock,
|
|
125
|
+
model: "m",
|
|
126
|
+
maxRetries: 3,
|
|
127
|
+
});
|
|
128
|
+
await codex.submit({ items: [{ text: "hi", type: "text" }], type: "UserInput" });
|
|
129
|
+
await waitForEvent(codex, (m) => m.type === "Error");
|
|
130
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
131
|
+
});
|
|
132
|
+
it("gives up after maxRetries and surfaces the error", async () => {
|
|
133
|
+
const fetchMock = vi.fn().mockRejectedValue(new TypeError("down"));
|
|
134
|
+
const codex = new CodexThread({
|
|
135
|
+
apiKey: "k",
|
|
136
|
+
baseUrl: "https://example.test/v1",
|
|
137
|
+
fetch: fetchMock,
|
|
138
|
+
model: "m",
|
|
139
|
+
maxRetries: 2,
|
|
140
|
+
});
|
|
141
|
+
await codex.submit({ items: [{ text: "hi", type: "text" }], type: "UserInput" });
|
|
142
|
+
await waitForEvent(codex, (m) => m.type === "Error");
|
|
143
|
+
// initial attempt + 2 retries
|
|
144
|
+
expect(fetchMock).toHaveBeenCalledTimes(3);
|
|
145
|
+
});
|
|
146
|
+
it("does not retry once visible output has streamed", async () => {
|
|
147
|
+
const fetchMock = vi.fn().mockResolvedValue(streamThenError());
|
|
148
|
+
const codex = new CodexThread({
|
|
149
|
+
apiKey: "k",
|
|
150
|
+
baseUrl: "https://example.test/v1",
|
|
151
|
+
fetch: fetchMock,
|
|
152
|
+
model: "m",
|
|
153
|
+
maxRetries: 5,
|
|
154
|
+
});
|
|
155
|
+
await codex.submit({ items: [{ text: "hi", type: "text" }], type: "UserInput" });
|
|
156
|
+
await waitForEvent(codex, (m) => m.type === "Error");
|
|
157
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
158
|
+
});
|
|
159
|
+
it("disables retries when maxRetries is 0", async () => {
|
|
160
|
+
const fetchMock = vi.fn().mockRejectedValue(new TypeError("down"));
|
|
161
|
+
const codex = new CodexThread({
|
|
162
|
+
apiKey: "k",
|
|
163
|
+
baseUrl: "https://example.test/v1",
|
|
164
|
+
fetch: fetchMock,
|
|
165
|
+
model: "m",
|
|
166
|
+
maxRetries: 0,
|
|
167
|
+
});
|
|
168
|
+
await codex.submit({ items: [{ text: "hi", type: "text" }], type: "UserInput" });
|
|
169
|
+
await waitForEvent(codex, (m) => m.type === "Error");
|
|
170
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=retry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.test.js","sourceRoot":"","sources":["../../../../core/tests/suite/retry.test.ts"],"names":[],"mappings":"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"}
|