Skip to content

Commit a701051

Browse files
feat(client): add withOptions helper
1 parent 994d964 commit a701051

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/client.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,25 @@ export class OpenAI {
341341
this.project = project;
342342
}
343343

344+
/**
345+
* Create a new client instance re-using the same options given to the current client with optional overriding.
346+
*/
347+
withOptions(options: Partial<ClientOptions>): this {
348+
return new (this.constructor as any as new (props: ClientOptions) => typeof this)({
349+
...this._options,
350+
baseURL: this.baseURL,
351+
maxRetries: this.maxRetries,
352+
timeout: this.timeout,
353+
logger: this.logger,
354+
logLevel: this.logLevel,
355+
fetchOptions: this.fetchOptions,
356+
apiKey: this.apiKey,
357+
organization: this.organization,
358+
project: this.project,
359+
...options,
360+
});
361+
}
362+
344363
protected defaultQuery(): Record<string, string | undefined> | undefined {
345364
return this._options.defaultQuery;
346365
}

tests/index.test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,74 @@ describe('instantiate client', () => {
321321
expect(client2.maxRetries).toEqual(2);
322322
});
323323

324+
describe('withOptions', () => {
325+
test('creates a new client with overridden options', () => {
326+
const client = new OpenAI({ baseURL: 'http://localhost:5000/', maxRetries: 3, apiKey: 'My API Key' });
327+
328+
const newClient = client.withOptions({
329+
maxRetries: 5,
330+
baseURL: 'http://localhost:5001/',
331+
});
332+
333+
// Verify the new client has updated options
334+
expect(newClient.maxRetries).toEqual(5);
335+
expect(newClient.baseURL).toEqual('http://localhost:5001/');
336+
337+
// Verify the original client is unchanged
338+
expect(client.maxRetries).toEqual(3);
339+
expect(client.baseURL).toEqual('http://localhost:5000/');
340+
341+
// Verify it's a different instance
342+
expect(newClient).not.toBe(client);
343+
expect(newClient.constructor).toBe(client.constructor);
344+
});
345+
346+
test('inherits options from the parent client', () => {
347+
const client = new OpenAI({
348+
baseURL: 'http://localhost:5000/',
349+
defaultHeaders: { 'X-Test-Header': 'test-value' },
350+
defaultQuery: { 'test-param': 'test-value' },
351+
apiKey: 'My API Key',
352+
});
353+
354+
const newClient = client.withOptions({
355+
baseURL: 'http://localhost:5001/',
356+
});
357+
358+
// Test inherited options remain the same
359+
expect(newClient.buildURL('/foo', null)).toEqual('http://localhost:5001/foo?test-param=test-value');
360+
361+
const { req } = newClient.buildRequest({ path: '/foo', method: 'get' });
362+
expect(req.headers.get('x-test-header')).toEqual('test-value');
363+
});
364+
365+
test('respects runtime property changes when creating new client', () => {
366+
const client = new OpenAI({ baseURL: 'http://localhost:5000/', timeout: 1000, apiKey: 'My API Key' });
367+
368+
// Modify the client properties directly after creation
369+
client.baseURL = 'http://localhost:6000/';
370+
client.timeout = 2000;
371+
372+
// Create a new client with withOptions
373+
const newClient = client.withOptions({
374+
maxRetries: 10,
375+
});
376+
377+
// Verify the new client uses the updated properties, not the original ones
378+
expect(newClient.baseURL).toEqual('http://localhost:6000/');
379+
expect(newClient.timeout).toEqual(2000);
380+
expect(newClient.maxRetries).toEqual(10);
381+
382+
// Original client should still have its modified properties
383+
expect(client.baseURL).toEqual('http://localhost:6000/');
384+
expect(client.timeout).toEqual(2000);
385+
expect(client.maxRetries).not.toEqual(10);
386+
387+
// Verify URL building uses the updated baseURL
388+
expect(newClient.buildURL('/bar', null)).toEqual('http://localhost:6000/bar');
389+
});
390+
});
391+
324392
test('with environment variable arguments', () => {
325393
// set options via env var
326394
process.env['OPENAI_API_KEY'] = 'My API Key';

0 commit comments

Comments
 (0)