Skip to content

Commit 31ddda8

Browse files
committedAug 16, 2023
v4.0.0
1 parent 37de535 commit 31ddda8

File tree

11 files changed

+563
-86
lines changed

11 files changed

+563
-86
lines changed
 

‎api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Methods:
6060
- <code title="get /files/{file_id}">client.files.<a href="./src/resources/files.ts">retrieve</a>(fileId) -> FileObject</code>
6161
- <code title="get /files">client.files.<a href="./src/resources/files.ts">list</a>() -> FileObjectsPage</code>
6262
- <code title="delete /files/{file_id}">client.files.<a href="./src/resources/files.ts">del</a>(fileId) -> FileDeleted</code>
63-
- <code title="get /files/{file_id}/content">client.files.<a href="./src/resources/files.ts">retrieveFileContent</a>(fileId) -> string</code>
63+
- <code title="get /files/{file_id}/content">client.files.<a href="./src/resources/files.ts">retrieveContent</a>(fileId) -> string</code>
6464

6565
# Images
6666

‎ecosystem-tests/cli.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ function parseArgs() {
130130
default: 1,
131131
description: 'number of parallel jobs to run',
132132
},
133+
retry: {
134+
type: 'number',
135+
default: 0,
136+
description: 'number of times to retry failing jobs',
137+
},
133138
parallel: {
134139
type: 'boolean',
135140
default: false,
@@ -202,6 +207,7 @@ async function main() {
202207
while (queue.length) {
203208
const project = queue.shift();
204209
if (!project) break;
210+
205211
let stdout, stderr;
206212
try {
207213
runningProjects.add(project);
@@ -212,6 +218,7 @@ async function main() {
212218
__filename,
213219
project,
214220
'--skip-pack',
221+
`--retry=${args.retry}`,
215222
...(args.live ? ['--live'] : []),
216223
...(args.verbose ? ['--verbose'] : []),
217224
...(args.deploy ? ['--deploy'] : []),
@@ -245,7 +252,7 @@ async function main() {
245252
console.error('\n');
246253

247254
try {
248-
await fn();
255+
await withRetry(fn, project, state.retry)
249256
console.error(`✅ - Successfully ran ${project}`);
250257
} catch (err) {
251258
if (err && (err as any).shortMessage) {
@@ -268,6 +275,18 @@ async function main() {
268275
process.exit(0);
269276
}
270277

278+
async function withRetry(fn: () => Promise<void>, identifier: string, retryAmount: number): Promise<void> {
279+
do {
280+
try {
281+
return await fn()
282+
} catch (err) {
283+
console.error(`${identifier} failed due to ${err}; retries left ${retryAmount}`)
284+
}
285+
286+
retryAmount--;
287+
} while (retryAmount > 0)
288+
}
289+
271290
function centerPad(text: string, width = text.length, char = ' '): string {
272291
return text.padStart(Math.floor((width + text.length) / 2), char).padEnd(width, char);
273292
}

‎ecosystem-tests/vercel-edge/package-lock.json

+485-62
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎ecosystem-tests/vercel-edge/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"vercel": "vercel"
1212
},
1313
"dependencies": {
14-
"ai": "2.1.9",
14+
"ai": "2.1.34",
1515
"next": "13.4.6",
1616
"react": "18.2.0",
1717
"react-dom": "18.2.0"

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openai",
3-
"version": "4.0.0-beta.12",
3+
"version": "4.0.0",
44
"description": "Client library for the OpenAI API",
55
"author": "OpenAI <support@openai.com>",
66
"types": "dist/index.d.ts",

‎src/core.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,10 @@ export abstract class APIClient {
322322
return new APIPromise(this.makeRequest(options, remainingRetries));
323323
}
324324

325-
private async makeRequest<T>(
325+
private async makeRequest(
326326
optionsInput: PromiseOrValue<FinalRequestOptions>,
327327
retriesRemaining: number | null,
328-
): Promise<{ response: Response; options: FinalRequestOptions; controller: AbortController }> {
328+
): Promise<APIResponseProps> {
329329
const options = await optionsInput;
330330
if (retriesRemaining == null) {
331331
retriesRemaining = options.maxRetries ?? this.maxRetries;
@@ -462,11 +462,11 @@ export abstract class APIClient {
462462
return false;
463463
}
464464

465-
private async retryRequest<Req extends {}, Rsp>(
466-
options: FinalRequestOptions<Req>,
465+
private async retryRequest(
466+
options: FinalRequestOptions,
467467
retriesRemaining: number,
468468
responseHeaders?: Headers | undefined,
469-
): Promise<Rsp> {
469+
): Promise<APIResponseProps> {
470470
retriesRemaining -= 1;
471471

472472
// About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
@@ -479,7 +479,7 @@ export abstract class APIClient {
479479
const timeout = this.calculateRetryTimeoutSeconds(retriesRemaining, retryAfter, maxRetries) * 1000;
480480
await sleep(timeout);
481481

482-
return this.request(options, retriesRemaining);
482+
return this.makeRequest(options, retriesRemaining);
483483
}
484484

485485
private calculateRetryTimeoutSeconds(

‎src/index.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,27 @@ export interface ClientOptions {
7676
organization?: string | null;
7777
}
7878

79-
/** Instantiate the API Client. */
79+
/** API Client for interfacing with the OpenAI API. */
8080
export class OpenAI extends Core.APIClient {
8181
apiKey: string;
8282
organization?: string | null;
8383

8484
private _options: ClientOptions;
8585

86+
/**
87+
* API Client for interfacing with the OpenAI API.
88+
*
89+
* @param {string} [opts.apiKey=process.env['OPENAI_API_KEY']] - The API Key to send to the API.
90+
* @param {string} [opts.baseURL] - Override the default base URL for the API.
91+
* @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
92+
* @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.
93+
* @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
94+
* @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
95+
* @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.
96+
* @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.
97+
* @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.
98+
* @param {string | null} [opts.organization]
99+
*/
86100
constructor({
87101
apiKey = Core.readEnv('OPENAI_API_KEY'),
88102
organization = Core.readEnv('OPENAI_ORG_ID') ?? null,

‎src/resources/files.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class Files extends APIResource {
4141
/**
4242
* Returns the contents of the specified file
4343
*/
44-
retrieveFileContent(fileId: string, options?: Core.RequestOptions): Core.APIPromise<string> {
44+
retrieveContent(fileId: string, options?: Core.RequestOptions): Core.APIPromise<string> {
4545
return this.get(`/files/${fileId}/content`, {
4646
...options,
4747
headers: { Accept: 'application/json', ...options?.headers },

‎src/version.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const VERSION = '4.0.0-beta.12';
1+
export const VERSION = '4.0.0';

‎tests/api-resources/files.test.ts

+6-10
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import { Response } from 'node-fetch';
66
const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010' });
77

88
describe('resource files', () => {
9-
// Prism tests are broken
10-
test.skip('create: only required params', async () => {
9+
test('create: only required params', async () => {
1110
const responsePromise = openai.files.create({
1211
file: await toFile(Buffer.from('# my file contents'), 'README.md'),
1312
purpose: 'string',
@@ -21,8 +20,7 @@ describe('resource files', () => {
2120
expect(dataAndResponse.response).toBe(rawResponse);
2221
});
2322

24-
// Prism tests are broken
25-
test.skip('create: required and optional params', async () => {
23+
test('create: required and optional params', async () => {
2624
const response = await openai.files.create({
2725
file: await toFile(Buffer.from('# my file contents'), 'README.md'),
2826
purpose: 'string',
@@ -83,9 +81,8 @@ describe('resource files', () => {
8381
);
8482
});
8583

86-
// Prism tests are broken
87-
test.skip('retrieveFileContent', async () => {
88-
const responsePromise = openai.files.retrieveFileContent('string');
84+
test('retrieveContent', async () => {
85+
const responsePromise = openai.files.retrieveContent('string');
8986
const rawResponse = await responsePromise.asResponse();
9087
expect(rawResponse).toBeInstanceOf(Response);
9188
const response = await responsePromise;
@@ -95,11 +92,10 @@ describe('resource files', () => {
9592
expect(dataAndResponse.response).toBe(rawResponse);
9693
});
9794

98-
// Prism tests are broken
99-
test.skip('retrieveFileContent: request options instead of params are passed correctly', async () => {
95+
test('retrieveContent: request options instead of params are passed correctly', async () => {
10096
// ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error
10197
await expect(
102-
openai.files.retrieveFileContent('string', { path: '/_stainless_unknown_path' }),
98+
openai.files.retrieveContent('string', { path: '/_stainless_unknown_path' }),
10399
).rejects.toThrow(OpenAI.NotFoundError);
104100
});
105101
});

‎tests/index.test.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import OpenAI from 'openai';
44
import { APIUserAbortError } from 'openai';
55
import { Headers } from 'openai/core';
6-
import { Response, fetch as defaultFetch } from 'openai/_shims/fetch';
6+
import { Response, fetch as defaultFetch, type RequestInit, type RequestInfo } from 'openai/_shims/fetch';
77

88
describe('instantiate client', () => {
99
const env = process.env;
@@ -188,3 +188,28 @@ describe('request building', () => {
188188
});
189189
});
190190
});
191+
192+
describe('retries', () => {
193+
test('single retry', async () => {
194+
let count = 0;
195+
const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise<Response> => {
196+
if (!count++)
197+
return new Promise((resolve, reject) =>
198+
signal?.addEventListener('abort', () => reject(new Error('timed out'))),
199+
);
200+
return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } });
201+
};
202+
203+
const client = new OpenAI({ apiKey: 'my api key', timeout: 2000, fetch: testFetch });
204+
205+
expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 });
206+
expect(count).toEqual(2);
207+
expect(
208+
await client
209+
.request({ path: '/foo', method: 'get' })
210+
.asResponse()
211+
.then((r) => r.text()),
212+
).toEqual(JSON.stringify({ a: 1 }));
213+
expect(count).toEqual(3);
214+
}, 10000);
215+
});

0 commit comments

Comments
 (0)
Please sign in to comment.