@@ -131,6 +131,74 @@ func TestParseCodexSSEError(t *testing.T) {
131131 t .Fatalf ("expected non-error event to be ignored" )
132132 }
133133 })
134+
135+ t .Run ("usage_limit_reached with resets_at preserves retryAfter" , func (t * testing.T ) {
136+ resetAt := time .Now ().Add (5 * time .Minute ).Unix ()
137+ line := []byte (`{"type":"error","error":{"type":"usage_limit_reached","code":"usage_limit_reached","message":"usage limit reached","resets_at":` + itoa (resetAt ) + `,"resets_in_seconds":60}}` )
138+ got , ok := parseCodexSSEError (line )
139+ if ! ok {
140+ t .Fatalf ("expected parser to handle usage_limit_reached SSE error" )
141+ }
142+ if got .code != http .StatusTooManyRequests {
143+ t .Fatalf ("status = %d, want %d" , got .code , http .StatusTooManyRequests )
144+ }
145+ ra := got .RetryAfter ()
146+ if ra == nil {
147+ t .Fatalf ("expected retryAfter to be set, got nil" )
148+ }
149+ if * ra < 4 * time .Minute || * ra > 6 * time .Minute {
150+ t .Fatalf ("retryAfter = %v, want ~5m" , * ra )
151+ }
152+ })
153+
154+ t .Run ("usage_limit_reached with resets_in_seconds only" , func (t * testing.T ) {
155+ line := []byte (`{"type":"error","error":{"type":"usage_limit_reached","code":"usage_limit_reached","message":"usage limit reached","resets_in_seconds":120}}` )
156+ got , ok := parseCodexSSEError (line )
157+ if ! ok {
158+ t .Fatalf ("expected parser to handle usage_limit_reached SSE error" )
159+ }
160+ ra := got .RetryAfter ()
161+ if ra == nil {
162+ t .Fatalf ("expected retryAfter to be set, got nil" )
163+ }
164+ if * ra != 120 * time .Second {
165+ t .Fatalf ("retryAfter = %v, want %v" , * ra , 120 * time .Second )
166+ }
167+ })
168+
169+ t .Run ("response.failed usage_limit_reached preserves retryAfter" , func (t * testing.T ) {
170+ line := []byte (`{"type":"response.failed","response":{"error":{"type":"usage_limit_reached","code":"usage_limit_reached","message":"usage limit reached","resets_in_seconds":90}}}` )
171+ got , ok := parseCodexSSEError (line )
172+ if ! ok {
173+ t .Fatalf ("expected parser to handle response.failed usage_limit_reached" )
174+ }
175+ if got .code != http .StatusTooManyRequests {
176+ t .Fatalf ("status = %d, want %d" , got .code , http .StatusTooManyRequests )
177+ }
178+ ra := got .RetryAfter ()
179+ if ra == nil {
180+ t .Fatalf ("expected retryAfter to be set, got nil" )
181+ }
182+ if * ra != 90 * time .Second {
183+ t .Fatalf ("retryAfter = %v, want %v" , * ra , 90 * time .Second )
184+ }
185+ })
186+
187+ t .Run ("usage_limit_reached with past resets_at falls back to resets_in_seconds" , func (t * testing.T ) {
188+ resetAt := time .Now ().Add (- 1 * time .Minute ).Unix ()
189+ line := []byte (`{"type":"error","error":{"type":"usage_limit_reached","code":"usage_limit_reached","message":"usage limit reached","resets_at":` + itoa (resetAt ) + `,"resets_in_seconds":45}}` )
190+ got , ok := parseCodexSSEError (line )
191+ if ! ok {
192+ t .Fatalf ("expected parser to handle usage_limit_reached SSE error" )
193+ }
194+ ra := got .RetryAfter ()
195+ if ra == nil {
196+ t .Fatalf ("expected retryAfter to be set, got nil" )
197+ }
198+ if * ra != 45 * time .Second {
199+ t .Fatalf ("retryAfter = %v, want %v" , * ra , 45 * time .Second )
200+ }
201+ })
134202}
135203
136204func itoa (v int64 ) string {
0 commit comments