diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7a0305307..541459357 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.62.1" + ".": "4.63.0" } diff --git a/.stats.yml b/.stats.yml index 2fc39385e..0151c5a10 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-ff407aa10917e62f2b0c12d1ad2c4f1258ed083bd45753c70eaaf5b1cf8356ae.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-de1981b64ac229493473670d618500c6362c195f1057eb7de00bd1bc9184fbd5.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index cdf113343..a9677f6d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 4.63.0 (2024-09-20) + +Full Changelog: [v4.62.1...v4.63.0](https://github.com/openai/openai-node/compare/v4.62.1...v4.63.0) + +### Features + +* **client:** send retry count header ([#1087](https://github.com/openai/openai-node/issues/1087)) ([7bcebc0](https://github.com/openai/openai-node/commit/7bcebc0e3965c2decd1dffb1e67f5197260ca89e)) + + +### Chores + +* **types:** improve type name for embedding models ([#1089](https://github.com/openai/openai-node/issues/1089)) ([d6966d9](https://github.com/openai/openai-node/commit/d6966d9872a14b7fbee85a7bb1fae697852b8ce0)) + ## 4.62.1 (2024-09-18) Full Changelog: [v4.62.0...v4.62.1](https://github.com/openai/openai-node/compare/v4.62.0...v4.62.1) diff --git a/README.md b/README.md index 55e6c291d..b2a3bc4b4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ You can import in Deno via: ```ts -import OpenAI from 'https://deno.land/x/openai@v4.62.1/mod.ts'; +import OpenAI from 'https://deno.land/x/openai@v4.63.0/mod.ts'; ``` diff --git a/api.md b/api.md index 7fb8f86a6..f38ab69be 100644 --- a/api.md +++ b/api.md @@ -64,6 +64,7 @@ Types: - CreateEmbeddingResponse - Embedding +- EmbeddingModel Methods: diff --git a/package.json b/package.json index 146f1e6f9..831169e2d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openai", - "version": "4.62.1", + "version": "4.63.0", "description": "The official TypeScript library for the OpenAI API", "author": "OpenAI ", "types": "dist/index.d.ts", diff --git a/scripts/build-deno b/scripts/build-deno index ef51b1e45..f006e3f3f 100755 --- a/scripts/build-deno +++ b/scripts/build-deno @@ -16,7 +16,7 @@ This is a build produced from https://github.com/openai/openai-node – please g Usage: \`\`\`ts -import OpenAI from "https://deno.land/x/openai@v4.62.1/mod.ts"; +import OpenAI from "https://deno.land/x/openai@v4.63.0/mod.ts"; const client = new OpenAI(); \`\`\` diff --git a/src/core.ts b/src/core.ts index 90714d3ce..877ae8de1 100644 --- a/src/core.ts +++ b/src/core.ts @@ -308,7 +308,10 @@ export abstract class APIClient { return null; } - buildRequest(options: FinalRequestOptions): { req: RequestInit; url: string; timeout: number } { + buildRequest( + options: FinalRequestOptions, + { retryCount = 0 }: { retryCount?: number } = {}, + ): { req: RequestInit; url: string; timeout: number } { const { method, path, query, headers: headers = {} } = options; const body = @@ -340,7 +343,7 @@ export abstract class APIClient { headers[this.idempotencyHeader] = options.idempotencyKey; } - const reqHeaders = this.buildHeaders({ options, headers, contentLength }); + const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount }); const req: RequestInit = { method, @@ -359,10 +362,12 @@ export abstract class APIClient { options, headers, contentLength, + retryCount, }: { options: FinalRequestOptions; headers: Record; contentLength: string | null | undefined; + retryCount: number; }): Record { const reqHeaders: Record = {}; if (contentLength) { @@ -378,6 +383,8 @@ export abstract class APIClient { delete reqHeaders['content-type']; } + reqHeaders['x-stainless-retry-count'] = String(retryCount); + this.validateHeaders(reqHeaders, headers); return reqHeaders; @@ -429,13 +436,14 @@ export abstract class APIClient { retriesRemaining: number | null, ): Promise { const options = await optionsInput; + const maxRetries = options.maxRetries ?? this.maxRetries; if (retriesRemaining == null) { - retriesRemaining = options.maxRetries ?? this.maxRetries; + retriesRemaining = maxRetries; } await this.prepareOptions(options); - const { req, url, timeout } = this.buildRequest(options); + const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); await this.prepareRequest(req, { url, options }); diff --git a/src/index.ts b/src/index.ts index b52406f6c..7fed1dc8c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -276,6 +276,7 @@ export namespace OpenAI { export import Embeddings = API.Embeddings; export import CreateEmbeddingResponse = API.CreateEmbeddingResponse; export import Embedding = API.Embedding; + export import EmbeddingModel = API.EmbeddingModel; export import EmbeddingCreateParams = API.EmbeddingCreateParams; export import Files = API.Files; diff --git a/src/resources/embeddings.ts b/src/resources/embeddings.ts index f72b9308a..6d8e670a7 100644 --- a/src/resources/embeddings.ts +++ b/src/resources/embeddings.ts @@ -77,6 +77,8 @@ export interface Embedding { object: 'embedding'; } +export type EmbeddingModel = 'text-embedding-ada-002' | 'text-embedding-3-small' | 'text-embedding-3-large'; + export interface EmbeddingCreateParams { /** * Input text to embed, encoded as a string or array of tokens. To embed multiple @@ -96,7 +98,7 @@ export interface EmbeddingCreateParams { * [Model overview](https://platform.openai.com/docs/models/overview) for * descriptions of them. */ - model: (string & {}) | 'text-embedding-ada-002' | 'text-embedding-3-small' | 'text-embedding-3-large'; + model: (string & {}) | EmbeddingModel; /** * The number of dimensions the resulting output embeddings should have. Only @@ -121,5 +123,6 @@ export interface EmbeddingCreateParams { export namespace Embeddings { export import CreateEmbeddingResponse = EmbeddingsAPI.CreateEmbeddingResponse; export import Embedding = EmbeddingsAPI.Embedding; + export import EmbeddingModel = EmbeddingsAPI.EmbeddingModel; export import EmbeddingCreateParams = EmbeddingsAPI.EmbeddingCreateParams; } diff --git a/src/resources/index.ts b/src/resources/index.ts index a78808584..68bd88a31 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -22,7 +22,13 @@ export { CompletionCreateParamsStreaming, Completions, } from './completions'; -export { CreateEmbeddingResponse, Embedding, EmbeddingCreateParams, Embeddings } from './embeddings'; +export { + CreateEmbeddingResponse, + Embedding, + EmbeddingModel, + EmbeddingCreateParams, + Embeddings, +} from './embeddings'; export { FileContent, FileDeleted, diff --git a/src/version.ts b/src/version.ts index 1cfad9ed4..ee209cb0e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '4.62.1'; // x-release-please-version +export const VERSION = '4.63.0'; // x-release-please-version diff --git a/tests/index.test.ts b/tests/index.test.ts index cd5f2a0a9..a6fa97199 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -241,6 +241,31 @@ describe('retries', () => { expect(count).toEqual(3); }); + test('retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new OpenAI({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + + expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toEqual('2'); + expect(count).toEqual(3); + }); + test('retry on 429 with retry-after', async () => { let count = 0; const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise => {