Skip to content

Commit a466ff7

Browse files
stainless-app[bot]stainless-bot
authored andcommitted
feat(client): allow overriding retry count header (#1098)
1 parent ecdb4e9 commit a466ff7

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

Diff for: src/core.ts

+15-3
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,11 @@ export abstract class APIClient {
383383
delete reqHeaders['content-type'];
384384
}
385385

386-
reqHeaders['x-stainless-retry-count'] = String(retryCount);
386+
// Don't set the retry count header if it was already set or removed by the caller. We check `headers`,
387+
// which can contain nulls, instead of `reqHeaders` to account for the removal case.
388+
if (getHeader(headers, 'x-stainless-retry-count') === undefined) {
389+
reqHeaders['x-stainless-retry-count'] = String(retryCount);
390+
}
387391

388392
this.validateHeaders(reqHeaders, headers);
389393

@@ -1170,7 +1174,15 @@ export const isHeadersProtocol = (headers: any): headers is HeadersProtocol => {
11701174
return typeof headers?.get === 'function';
11711175
};
11721176

1173-
export const getRequiredHeader = (headers: HeadersLike, header: string): string => {
1177+
export const getRequiredHeader = (headers: HeadersLike | Headers, header: string): string => {
1178+
const foundHeader = getHeader(headers, header);
1179+
if (foundHeader === undefined) {
1180+
throw new Error(`Could not find ${header} header`);
1181+
}
1182+
return foundHeader;
1183+
};
1184+
1185+
export const getHeader = (headers: HeadersLike | Headers, header: string): string | undefined => {
11741186
const lowerCasedHeader = header.toLowerCase();
11751187
if (isHeadersProtocol(headers)) {
11761188
// to deal with the case where the header looks like Stainless-Event-Id
@@ -1196,7 +1208,7 @@ export const getRequiredHeader = (headers: HeadersLike, header: string): string
11961208
}
11971209
}
11981210

1199-
throw new Error(`Could not find ${header} header`);
1211+
return undefined;
12001212
};
12011213

12021214
/**

Diff for: tests/index.test.ts

+58
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,64 @@ describe('retries', () => {
266266
expect(count).toEqual(3);
267267
});
268268

269+
test('omit retry count header', async () => {
270+
let count = 0;
271+
let capturedRequest: RequestInit | undefined;
272+
const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise<Response> => {
273+
count++;
274+
if (count <= 2) {
275+
return new Response(undefined, {
276+
status: 429,
277+
headers: {
278+
'Retry-After': '0.1',
279+
},
280+
});
281+
}
282+
capturedRequest = init;
283+
return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } });
284+
};
285+
const client = new OpenAI({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 });
286+
287+
expect(
288+
await client.request({
289+
path: '/foo',
290+
method: 'get',
291+
headers: { 'X-Stainless-Retry-Count': null },
292+
}),
293+
).toEqual({ a: 1 });
294+
295+
expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count');
296+
});
297+
298+
test('overwrite retry count header', async () => {
299+
let count = 0;
300+
let capturedRequest: RequestInit | undefined;
301+
const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise<Response> => {
302+
count++;
303+
if (count <= 2) {
304+
return new Response(undefined, {
305+
status: 429,
306+
headers: {
307+
'Retry-After': '0.1',
308+
},
309+
});
310+
}
311+
capturedRequest = init;
312+
return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } });
313+
};
314+
const client = new OpenAI({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 });
315+
316+
expect(
317+
await client.request({
318+
path: '/foo',
319+
method: 'get',
320+
headers: { 'X-Stainless-Retry-Count': '42' },
321+
}),
322+
).toEqual({ a: 1 });
323+
324+
expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toBe('42');
325+
});
326+
269327
test('retry on 429 with retry-after', async () => {
270328
let count = 0;
271329
const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise<Response> => {

0 commit comments

Comments
 (0)