diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ce65b73e4..448d10afc 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "5.3.0"
+ ".": "5.4.0"
}
diff --git a/.stats.yml b/.stats.yml
index c9e264655..feda32cff 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 111
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-3ae9c18dd7ccfc3ac5206f24394665f563a19015cfa8847b2801a2694d012abc.yml
-openapi_spec_hash: 48175b03b58805cd5c80793c66fd54e5
-config_hash: 4caff63b74a41f71006987db702f2918
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-9e41d2d5471d2c28bff0d616f4476f5b0e6c541ef4cb51bdaaef5fdf5e13c8b2.yml
+openapi_spec_hash: 86f765e18d00e32cf2ce9db7ab84d946
+config_hash: fd2af1d5eff0995bb7dc02ac9a34851d
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1446910c6..a3b2d6ccb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,25 @@
# Changelog
+## 5.4.0 (2025-06-16)
+
+Full Changelog: [v5.3.0...v5.4.0](https://github.com/openai/openai-node/compare/v5.3.0...v5.4.0)
+
+### Features
+
+* **api:** add reusable prompt IDs ([c720bb3](https://github.com/openai/openai-node/commit/c720bb3fb909cdef1cc679df38357f046d3d2756))
+* **client:** add support for endpoint-specific base URLs ([05f558b](https://github.com/openai/openai-node/commit/05f558bcdd362ae56000fe515a24593363d59e83))
+
+
+### Bug Fixes
+
+* publish script — handle NPM errors correctly ([a803cce](https://github.com/openai/openai-node/commit/a803cce6d44116eaba34f2bd7cb0f5d8f5c72be8))
+
+
+### Chores
+
+* **client:** refactor imports ([9eb4470](https://github.com/openai/openai-node/commit/9eb44703432d7e22290564013f8e1798c82918a3))
+* **internal:** add pure annotations, make base APIResource abstract ([418eb02](https://github.com/openai/openai-node/commit/418eb02e3ebe3ef58d851405f9eb5cae275194b4))
+
## 5.3.0 (2025-06-10)
Full Changelog: [v5.2.0...v5.3.0](https://github.com/openai/openai-node/compare/v5.2.0...v5.3.0)
diff --git a/api.md b/api.md
index 269566a57..4e2de3252 100644
--- a/api.md
+++ b/api.md
@@ -677,6 +677,7 @@ Types:
- ResponseOutputRefusal
- ResponseOutputText
- ResponseOutputTextAnnotationAddedEvent
+- ResponsePrompt
- ResponseQueuedEvent
- ResponseReasoningDeltaEvent
- ResponseReasoningDoneEvent
diff --git a/bin/publish-npm b/bin/publish-npm
index 2505decac..fa2243d24 100644
--- a/bin/publish-npm
+++ b/bin/publish-npm
@@ -7,15 +7,35 @@ npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN"
yarn build
cd dist
+# Get package name and version from package.json
+PACKAGE_NAME="$(jq -r -e '.name' ./package.json)"
+VERSION="$(jq -r -e '.version' ./package.json)"
+
# Get latest version from npm
#
-# If the package doesn't exist, yarn will return
-# {"type":"error","data":"Received invalid response from npm."}
-# where .data.version doesn't exist so LAST_VERSION will be an empty string.
-LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')"
-
-# Get current version from package.json
-VERSION="$(node -p "require('./package.json').version")"
+# If the package doesn't exist, npm will return:
+# {
+# "error": {
+# "code": "E404",
+# "summary": "Unpublished on 2025-06-05T09:54:53.528Z",
+# "detail": "'the_package' is not in this registry..."
+# }
+# }
+NPM_INFO="$(npm view "$PACKAGE_NAME" version --json 2>/dev/null || true)"
+
+# Check if we got an E404 error
+if echo "$NPM_INFO" | jq -e '.error.code == "E404"' > /dev/null 2>&1; then
+ # Package doesn't exist yet, no last version
+ LAST_VERSION=""
+elif echo "$NPM_INFO" | jq -e '.error' > /dev/null 2>&1; then
+ # Report other errors
+ echo "ERROR: npm returned unexpected data:"
+ echo "$NPM_INFO"
+ exit 1
+else
+ # Success - get the version
+ LAST_VERSION=$(echo "$NPM_INFO" | jq -r '.') # strip quotes
+fi
# Check if current version is pre-release (e.g. alpha / beta / rc)
CURRENT_IS_PRERELEASE=false
diff --git a/jsr.json b/jsr.json
index d079c8f25..4d018d709 100644
--- a/jsr.json
+++ b/jsr.json
@@ -1,6 +1,6 @@
{
"name": "@openai/openai",
- "version": "5.3.0",
+ "version": "5.4.0",
"exports": {
".": "./index.ts",
"./helpers/zod": "./helpers/zod.ts",
diff --git a/package.json b/package.json
index 56e5b2352..0aeb9e260 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "openai",
- "version": "5.3.0",
+ "version": "5.4.0",
"description": "The official TypeScript library for the OpenAI API",
"author": "OpenAI ",
"types": "dist/index.d.ts",
@@ -45,7 +45,7 @@
"publint": "^0.2.12",
"ts-jest": "^29.1.0",
"ts-node": "^10.5.0",
- "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz",
+ "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz",
"tsconfig-paths": "^4.0.0",
"typescript": "5.8.3",
"ws": "^8.18.0",
diff --git a/scripts/build b/scripts/build
index beb4da8f7..1ee175252 100755
--- a/scripts/build
+++ b/scripts/build
@@ -31,7 +31,7 @@ fi
node scripts/utils/make-dist-package-json.cjs > dist/package.json
# build to .js/.mjs/.d.ts files
-npm exec tsc-multi
+./node_modules/.bin/tsc-multi
# we need to patch index.js so that `new module.exports()` works for cjs backwards
# compat. No way to get that from index.ts because it would cause compile errors
# when building .mjs
diff --git a/src/client.ts b/src/client.ts
index 9ebdf8f02..f33e13ead 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -5,7 +5,6 @@ import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestIni
import { uuid4 } from './internal/utils/uuid';
import { validatePositiveInteger, isAbsoluteURL, safeJSON } from './internal/utils/values';
import { sleep } from './internal/utils/sleep';
-import { type Logger, type LogLevel, parseLogLevel } from './internal/utils/log';
export type { Logger, LogLevel } from './internal/utils/log';
import { castToError, isAbortError } from './internal/errors';
import type { APIResponseProps } from './internal/parse';
@@ -20,10 +19,6 @@ import { AbstractPage, type CursorPageParams, CursorPageResponse, PageResponse }
import * as Uploads from './core/uploads';
import * as API from './resources/index';
import { APIPromise } from './core/api-promise';
-import { type Fetch } from './internal/builtin-types';
-import { isRunningInBrowser } from './internal/detect-platform';
-import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
-import { FinalRequestOptions, RequestOptions } from './internal/request-options';
import {
Batch,
BatchCreateParams,
@@ -79,9 +74,6 @@ import {
ModerationTextInput,
Moderations,
} from './resources/moderations';
-import { readEnv } from './internal/utils/env';
-import { formatRequestDetails, loggerFor } from './internal/utils/log';
-import { isEmptyObj } from './internal/utils/values';
import { Audio, AudioModel, AudioResponseFormat } from './resources/audio/audio';
import { Beta } from './resources/beta/beta';
import { Chat } from './resources/chat/chat';
@@ -174,6 +166,19 @@ import {
ChatCompletionUserMessageParam,
ChatCompletionsPage,
} from './resources/chat/completions/completions';
+import { type Fetch } from './internal/builtin-types';
+import { isRunningInBrowser } from './internal/detect-platform';
+import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
+import { FinalRequestOptions, RequestOptions } from './internal/request-options';
+import { readEnv } from './internal/utils/env';
+import {
+ type LogLevel,
+ type Logger,
+ formatRequestDetails,
+ loggerFor,
+ parseLogLevel,
+} from './internal/utils/log';
+import { isEmptyObj } from './internal/utils/values';
export interface ClientOptions {
/**
@@ -367,6 +372,13 @@ export class OpenAI {
});
}
+ /**
+ * Check whether the base URL is set to its default.
+ */
+ #baseURLOverridden(): boolean {
+ return this.baseURL !== 'https://api.openai.com/v1';
+ }
+
protected defaultQuery(): Record | undefined {
return this._options.defaultQuery;
}
@@ -400,11 +412,16 @@ export class OpenAI {
return Errors.APIError.generate(status, error, message, headers);
}
- buildURL(path: string, query: Record | null | undefined): string {
+ buildURL(
+ path: string,
+ query: Record | null | undefined,
+ defaultBaseURL?: string | undefined,
+ ): string {
+ const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL;
const url =
isAbsoluteURL(path) ?
new URL(path)
- : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
+ : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
const defaultQuery = this.defaultQuery();
if (!isEmptyObj(defaultQuery)) {
@@ -768,9 +785,9 @@ export class OpenAI {
{ retryCount = 0 }: { retryCount?: number } = {},
): { req: FinalizedRequestInit; url: string; timeout: number } {
const options = { ...inputOptions };
- const { method, path, query } = options;
+ const { method, path, query, defaultBaseURL } = options;
- const url = this.buildURL(path!, query as Record);
+ const url = this.buildURL(path!, query as Record, defaultBaseURL);
if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
options.timeout = options.timeout ?? this.timeout;
const { bodyHeaders, body } = this.buildBody({ options });
diff --git a/src/core/resource.ts b/src/core/resource.ts
index 8ba97f70a..d9a191e58 100644
--- a/src/core/resource.ts
+++ b/src/core/resource.ts
@@ -2,7 +2,7 @@
import type { OpenAI } from '../client';
-export class APIResource {
+export abstract class APIResource {
protected _client: OpenAI;
constructor(client: OpenAI) {
diff --git a/src/internal/headers.ts b/src/internal/headers.ts
index 5cc03ce32..c724a9d22 100644
--- a/src/internal/headers.ts
+++ b/src/internal/headers.ts
@@ -1,5 +1,7 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+import { isReadonlyArray } from './utils/values';
+
type HeaderValue = string | undefined | null;
export type HeadersLike =
| Headers
@@ -9,7 +11,7 @@ export type HeadersLike =
| null
| NullableHeaders;
-const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders');
+const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders');
/**
* @internal
@@ -25,8 +27,6 @@ export type NullableHeaders = {
nulls: Set;
};
-const isArray = Array.isArray as (val: unknown) => val is readonly unknown[];
-
function* iterateHeaders(headers: HeadersLike): IterableIterator {
if (!headers) return;
@@ -43,7 +43,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator;
if (headers instanceof Headers) {
iter = headers.entries();
- } else if (isArray(headers)) {
+ } else if (isReadonlyArray(headers)) {
iter = headers;
} else {
shouldClear = true;
@@ -52,7 +52,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator String(v);
export const formatters: Record string> = {
RFC1738: (v: PropertyKey) => String(v).replace(/%20/g, '+'),
- RFC3986: (v: PropertyKey) => String(v),
+ RFC3986: default_formatter,
};
export const RFC1738 = 'RFC1738';
export const RFC3986 = 'RFC3986';
diff --git a/src/internal/qs/stringify.ts b/src/internal/qs/stringify.ts
index 67497561a..7e71387f5 100644
--- a/src/internal/qs/stringify.ts
+++ b/src/internal/qs/stringify.ts
@@ -1,8 +1,7 @@
-import { encode, is_buffer, maybe_map } from './utils';
-import { default_format, formatters } from './formats';
+import { encode, is_buffer, maybe_map, has } from './utils';
+import { default_format, default_formatter, formatters } from './formats';
import type { NonNullableProperties, StringifyOptions } from './types';
-
-const has = Object.prototype.hasOwnProperty;
+import { isArray } from '../utils/values';
const array_prefix_generators = {
brackets(prefix: PropertyKey) {
@@ -17,13 +16,11 @@ const array_prefix_generators = {
},
};
-const is_array = Array.isArray;
-const push = Array.prototype.push;
const push_to_array = function (arr: any[], value_or_array: any) {
- push.apply(arr, is_array(value_or_array) ? value_or_array : [value_or_array]);
+ Array.prototype.push.apply(arr, isArray(value_or_array) ? value_or_array : [value_or_array]);
};
-const to_ISO = Date.prototype.toISOString;
+let toISOString;
const defaults = {
addQueryPrefix: false,
@@ -38,11 +35,11 @@ const defaults = {
encoder: encode,
encodeValuesOnly: false,
format: default_format,
- formatter: formatters[default_format],
+ formatter: default_formatter,
/** @deprecated */
indices: false,
serializeDate(date) {
- return to_ISO.call(date);
+ return (toISOString ??= Function.prototype.call.bind(Date.prototype.toISOString))(date);
},
skipNulls: false,
strictNullHandling: false,
@@ -105,7 +102,7 @@ function inner_stringify(
obj = filter(prefix, obj);
} else if (obj instanceof Date) {
obj = serializeDate?.(obj);
- } else if (generateArrayPrefix === 'comma' && is_array(obj)) {
+ } else if (generateArrayPrefix === 'comma' && isArray(obj)) {
obj = maybe_map(obj, function (value) {
if (value instanceof Date) {
return serializeDate?.(value);
@@ -148,14 +145,14 @@ function inner_stringify(
}
let obj_keys;
- if (generateArrayPrefix === 'comma' && is_array(obj)) {
+ if (generateArrayPrefix === 'comma' && isArray(obj)) {
// we need to join elements in
if (encodeValuesOnly && encoder) {
// @ts-expect-error values only
obj = maybe_map(obj, encoder);
}
obj_keys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }];
- } else if (is_array(filter)) {
+ } else if (isArray(filter)) {
obj_keys = filter;
} else {
const keys = Object.keys(obj);
@@ -165,9 +162,9 @@ function inner_stringify(
const encoded_prefix = encodeDotInKeys ? String(prefix).replace(/\./g, '%2E') : String(prefix);
const adjusted_prefix =
- commaRoundTrip && is_array(obj) && obj.length === 1 ? encoded_prefix + '[]' : encoded_prefix;
+ commaRoundTrip && isArray(obj) && obj.length === 1 ? encoded_prefix + '[]' : encoded_prefix;
- if (allowEmptyArrays && is_array(obj) && obj.length === 0) {
+ if (allowEmptyArrays && isArray(obj) && obj.length === 0) {
return adjusted_prefix + '[]';
}
@@ -184,7 +181,7 @@ function inner_stringify(
// @ts-ignore
const encoded_key = allowDots && encodeDotInKeys ? (key as any).replace(/\./g, '%2E') : key;
const key_prefix =
- is_array(obj) ?
+ isArray(obj) ?
typeof generateArrayPrefix === 'function' ?
generateArrayPrefix(adjusted_prefix, encoded_key)
: adjusted_prefix
@@ -205,7 +202,7 @@ function inner_stringify(
skipNulls,
encodeDotInKeys,
// @ts-ignore
- generateArrayPrefix === 'comma' && encodeValuesOnly && is_array(obj) ? null : encoder,
+ generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder,
filter,
sort,
allowDots,
@@ -244,7 +241,7 @@ function normalize_stringify_options(
let format = default_format;
if (typeof opts.format !== 'undefined') {
- if (!has.call(formatters, opts.format)) {
+ if (!has(formatters, opts.format)) {
throw new TypeError('Unknown format option provided.');
}
format = opts.format;
@@ -252,7 +249,7 @@ function normalize_stringify_options(
const formatter = formatters[format];
let filter = defaults.filter;
- if (typeof opts.filter === 'function' || is_array(opts.filter)) {
+ if (typeof opts.filter === 'function' || isArray(opts.filter)) {
filter = opts.filter;
}
@@ -316,7 +313,7 @@ export function stringify(object: any, opts: StringifyOptions = {}) {
if (typeof options.filter === 'function') {
filter = options.filter;
obj = filter('', obj);
- } else if (is_array(options.filter)) {
+ } else if (isArray(options.filter)) {
filter = options.filter;
obj_keys = filter;
}
diff --git a/src/internal/qs/utils.ts b/src/internal/qs/utils.ts
index 113b18fb9..4cd56579c 100644
--- a/src/internal/qs/utils.ts
+++ b/src/internal/qs/utils.ts
@@ -1,10 +1,13 @@
import { RFC1738 } from './formats';
import type { DefaultEncoder, Format } from './types';
+import { isArray } from '../utils/values';
-const has = Object.prototype.hasOwnProperty;
-const is_array = Array.isArray;
+export let has = (obj: object, key: PropertyKey): boolean => (
+ (has = (Object as any).hasOwn ?? Function.prototype.call.bind(Object.prototype.hasOwnProperty)),
+ has(obj, key)
+);
-const hex_table = (() => {
+const hex_table = /* @__PURE__ */ (() => {
const array = [];
for (let i = 0; i < 256; ++i) {
array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());
@@ -20,7 +23,7 @@ function compact_queue>(queue: Array<{ obj: T; pro
const obj = item.obj[item.prop];
- if (is_array(obj)) {
+ if (isArray(obj)) {
const compacted: unknown[] = [];
for (let j = 0; j < obj.length; ++j) {
@@ -56,13 +59,10 @@ export function merge(
}
if (typeof source !== 'object') {
- if (is_array(target)) {
+ if (isArray(target)) {
target.push(source);
} else if (target && typeof target === 'object') {
- if (
- (options && (options.plainObjects || options.allowPrototypes)) ||
- !has.call(Object.prototype, source)
- ) {
+ if ((options && (options.plainObjects || options.allowPrototypes)) || !has(Object.prototype, source)) {
target[source] = true;
}
} else {
@@ -77,14 +77,14 @@ export function merge(
}
let mergeTarget = target;
- if (is_array(target) && !is_array(source)) {
+ if (isArray(target) && !isArray(source)) {
// @ts-ignore
mergeTarget = array_to_object(target, options);
}
- if (is_array(target) && is_array(source)) {
+ if (isArray(target) && isArray(source)) {
source.forEach(function (item, i) {
- if (has.call(target, i)) {
+ if (has(target, i)) {
const targetItem = target[i];
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') {
target[i] = merge(targetItem, item, options);
@@ -101,7 +101,7 @@ export function merge(
return Object.keys(source).reduce(function (acc, key) {
const value = source[key];
- if (has.call(acc, key)) {
+ if (has(acc, key)) {
acc[key] = merge(acc[key], value, options);
} else {
acc[key] = value;
@@ -254,7 +254,7 @@ export function combine(a: any, b: any) {
}
export function maybe_map(val: T[], fn: (v: T) => T) {
- if (is_array(val)) {
+ if (isArray(val)) {
const mapped = [];
for (let i = 0; i < val.length; i += 1) {
mapped.push(fn(val[i]!));
diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts
index 78daa4199..7ee5c622d 100644
--- a/src/internal/request-options.ts
+++ b/src/internal/request-options.ts
@@ -21,6 +21,7 @@ export type RequestOptions = {
fetchOptions?: MergedRequestInit;
signal?: AbortSignal | undefined | null;
idempotencyKey?: string;
+ defaultBaseURL?: string | undefined;
__metadata?: Record;
__binaryResponse?: boolean | undefined;
diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts
index fbc48b298..2f7271164 100644
--- a/src/internal/uploads.ts
+++ b/src/internal/uploads.ts
@@ -90,7 +90,7 @@ export const multipartFormRequestOptions = async (
return { ...opts, body: await createForm(opts.body, fetch) };
};
-const supportsFormDataMap = new WeakMap>();
+const supportsFormDataMap = /** @__PURE__ */ new WeakMap>();
/**
* node-fetch doesn't support the global FormData object in recent node versions. Instead of sending
diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts
index 1aec41276..e1df9cef6 100644
--- a/src/internal/utils/log.ts
+++ b/src/internal/utils/log.ts
@@ -58,7 +58,7 @@ const noopLogger = {
debug: noop,
};
-let cachedLoggers = new WeakMap();
+let cachedLoggers = /** @__PURE__ */ new WeakMap();
export function loggerFor(client: OpenAI): Logger {
const logger = client.logger;
diff --git a/src/internal/utils/path.ts b/src/internal/utils/path.ts
index 0dceb10f1..122066855 100644
--- a/src/internal/utils/path.ts
+++ b/src/internal/utils/path.ts
@@ -60,4 +60,4 @@ export const createPathTagFunction = (pathEncoder = encodeURIPath) =>
/**
* URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced.
*/
-export const path = createPathTagFunction(encodeURIPath);
+export const path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
diff --git a/src/internal/utils/values.ts b/src/internal/utils/values.ts
index aee03b055..801974e84 100644
--- a/src/internal/utils/values.ts
+++ b/src/internal/utils/values.ts
@@ -9,6 +9,9 @@ export const isAbsoluteURL = (url: string): boolean => {
return startsWithSchemeRegexp.test(url);
};
+export let isArray = (val: unknown): val is unknown[] => ((isArray = Array.isArray), isArray(val));
+export let isReadonlyArray = isArray as (val: unknown) => val is readonly unknown[];
+
/** Returns an object if the given value isn't an object, otherwise returns as-is */
export function maybeObj(x: unknown): object {
if (typeof x !== 'object') {
diff --git a/src/resources/chat/completions/completions.ts b/src/resources/chat/completions/completions.ts
index 583deccf8..a88e27e98 100644
--- a/src/resources/chat/completions/completions.ts
+++ b/src/resources/chat/completions/completions.ts
@@ -291,7 +291,7 @@ export interface ChatCompletion {
* When this parameter is set, the response body will include the `service_tier`
* utilized.
*/
- service_tier?: 'auto' | 'default' | 'flex' | null;
+ service_tier?: 'auto' | 'default' | 'flex' | 'scale' | null;
/**
* This fingerprint represents the backend configuration that the model runs with.
@@ -542,7 +542,7 @@ export interface ChatCompletionChunk {
* When this parameter is set, the response body will include the `service_tier`
* utilized.
*/
- service_tier?: 'auto' | 'default' | 'flex' | null;
+ service_tier?: 'auto' | 'default' | 'flex' | 'scale' | null;
/**
* This fingerprint represents the backend configuration that the model runs with.
@@ -1464,7 +1464,7 @@ export interface ChatCompletionCreateParamsBase {
* When this parameter is set, the response body will include the `service_tier`
* utilized.
*/
- service_tier?: 'auto' | 'default' | 'flex' | null;
+ service_tier?: 'auto' | 'default' | 'flex' | 'scale' | null;
/**
* Not supported with latest reasoning models `o3` and `o4-mini`.
diff --git a/src/resources/fine-tuning/jobs/jobs.ts b/src/resources/fine-tuning/jobs/jobs.ts
index 1c43289e4..7e8f672e5 100644
--- a/src/resources/fine-tuning/jobs/jobs.ts
+++ b/src/resources/fine-tuning/jobs/jobs.ts
@@ -25,7 +25,7 @@ export class Jobs extends APIResource {
* Response includes details of the enqueued job including job status and the name
* of the fine-tuned models once complete.
*
- * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning)
+ * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization)
*
* @example
* ```ts
@@ -42,7 +42,7 @@ export class Jobs extends APIResource {
/**
* Get info about a fine-tuning job.
*
- * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning)
+ * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/model-optimization)
*
* @example
* ```ts
@@ -449,7 +449,8 @@ export interface JobCreateParams {
* [preference](https://platform.openai.com/docs/api-reference/fine-tuning/preference-input)
* format.
*
- * See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning)
+ * See the
+ * [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization)
* for more details.
*/
training_file: string;
@@ -508,7 +509,8 @@ export interface JobCreateParams {
* Your dataset must be formatted as a JSONL file. You must upload your file with
* the purpose `fine-tune`.
*
- * See the [fine-tuning guide](https://platform.openai.com/docs/guides/fine-tuning)
+ * See the
+ * [fine-tuning guide](https://platform.openai.com/docs/guides/model-optimization)
* for more details.
*/
validation_file?: string | null;
diff --git a/src/resources/images.ts b/src/resources/images.ts
index fdc51abe3..23b7d1507 100644
--- a/src/resources/images.ts
+++ b/src/resources/images.ts
@@ -237,6 +237,20 @@ export interface ImageEditParams {
*/
n?: number | null;
+ /**
+ * The compression level (0-100%) for the generated images. This parameter is only
+ * supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and
+ * defaults to 100.
+ */
+ output_compression?: number | null;
+
+ /**
+ * The format in which the generated images are returned. This parameter is only
+ * supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. The
+ * default value is `png`.
+ */
+ output_format?: 'png' | 'jpeg' | 'webp' | null;
+
/**
* The quality of the image that will be generated. `high`, `medium` and `low` are
* only supported for `gpt-image-1`. `dall-e-2` only supports `standard` quality.
diff --git a/src/resources/responses/responses.ts b/src/resources/responses/responses.ts
index a443f101a..1cb0788e0 100644
--- a/src/resources/responses/responses.ts
+++ b/src/resources/responses/responses.ts
@@ -358,14 +358,13 @@ export interface Response {
incomplete_details: Response.IncompleteDetails | null;
/**
- * Inserts a system (or developer) message as the first item in the model's
- * context.
+ * A system (or developer) message inserted into the model's context.
*
* When using along with `previous_response_id`, the instructions from a previous
* response will not be carried over to the next response. This makes it simple to
* swap out system (or developer) messages in new responses.
*/
- instructions: string | null;
+ instructions: string | Array | null;
/**
* Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -469,6 +468,12 @@ export interface Response {
*/
previous_response_id?: string | null;
+ /**
+ * Reference to a prompt template and its variables.
+ * [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
+ */
+ prompt?: ResponsePrompt | null;
+
/**
* **o-series models only**
*
@@ -496,7 +501,7 @@ export interface Response {
* When this parameter is set, the response body will include the `service_tier`
* utilized.
*/
- service_tier?: 'auto' | 'default' | 'flex' | null;
+ service_tier?: 'auto' | 'default' | 'flex' | 'scale' | null;
/**
* The status of the response generation. One of `completed`, `failed`,
@@ -3483,6 +3488,29 @@ export interface ResponseOutputTextAnnotationAddedEvent {
type: 'response.output_text_annotation.added';
}
+/**
+ * Reference to a prompt template and its variables.
+ * [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
+ */
+export interface ResponsePrompt {
+ /**
+ * The unique identifier of the prompt template to use.
+ */
+ id: string;
+
+ /**
+ * Optional map of values to substitute in for variables in your prompt. The
+ * substitution values can either be strings, or other Response input types like
+ * images or files.
+ */
+ variables?: Record | null;
+
+ /**
+ * Optional version of the prompt template.
+ */
+ version?: string | null;
+}
+
/**
* Emitted when a response is queued and waiting to be processed.
*/
@@ -4612,8 +4640,7 @@ export interface ResponseCreateParamsBase {
include?: Array | null;
/**
- * Inserts a system (or developer) message as the first item in the model's
- * context.
+ * A system (or developer) message inserted into the model's context.
*
* When using along with `previous_response_id`, the instructions from a previous
* response will not be carried over to the next response. This makes it simple to
@@ -4650,6 +4677,12 @@ export interface ResponseCreateParamsBase {
*/
previous_response_id?: string | null;
+ /**
+ * Reference to a prompt template and its variables.
+ * [Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
+ */
+ prompt?: ResponsePrompt | null;
+
/**
* **o-series models only**
*
@@ -4677,7 +4710,7 @@ export interface ResponseCreateParamsBase {
* When this parameter is set, the response body will include the `service_tier`
* utilized.
*/
- service_tier?: 'auto' | 'default' | 'flex' | null;
+ service_tier?: 'auto' | 'default' | 'flex' | 'scale' | null;
/**
* Whether to store the generated model response for later retrieval via API.
@@ -4922,6 +4955,7 @@ export declare namespace Responses {
type ResponseOutputRefusal as ResponseOutputRefusal,
type ResponseOutputText as ResponseOutputText,
type ResponseOutputTextAnnotationAddedEvent as ResponseOutputTextAnnotationAddedEvent,
+ type ResponsePrompt as ResponsePrompt,
type ResponseQueuedEvent as ResponseQueuedEvent,
type ResponseReasoningDeltaEvent as ResponseReasoningDeltaEvent,
type ResponseReasoningDoneEvent as ResponseReasoningDoneEvent,
diff --git a/src/version.ts b/src/version.ts
index b17877a92..0e5f6f831 100644
--- a/src/version.ts
+++ b/src/version.ts
@@ -1 +1 @@
-export const VERSION = '5.3.0'; // x-release-please-version
+export const VERSION = '5.4.0'; // x-release-please-version
diff --git a/tests/api-resources/images.test.ts b/tests/api-resources/images.test.ts
index ba62d993c..2fcfd34c8 100644
--- a/tests/api-resources/images.test.ts
+++ b/tests/api-resources/images.test.ts
@@ -54,6 +54,8 @@ describe('resource images', () => {
mask: await toFile(Buffer.from('# my file contents'), 'README.md'),
model: 'string',
n: 1,
+ output_compression: 100,
+ output_format: 'png',
quality: 'high',
response_format: 'url',
size: '1024x1024',
diff --git a/tests/api-resources/responses/responses.test.ts b/tests/api-resources/responses/responses.test.ts
index f1480f8c3..afe5a293a 100644
--- a/tests/api-resources/responses/responses.test.ts
+++ b/tests/api-resources/responses/responses.test.ts
@@ -30,6 +30,7 @@ describe('resource responses', () => {
metadata: { foo: 'string' },
parallel_tool_calls: true,
previous_response_id: 'previous_response_id',
+ prompt: { id: 'id', variables: { foo: 'string' }, version: 'version' },
reasoning: { effort: 'low', generate_summary: 'auto', summary: 'auto' },
service_tier: 'auto',
store: true,
diff --git a/tests/index.test.ts b/tests/index.test.ts
index 401cc5c6e..e61902eea 100644
--- a/tests/index.test.ts
+++ b/tests/index.test.ts
@@ -310,6 +310,28 @@ describe('instantiate client', () => {
const client = new OpenAI({ apiKey: 'My API Key' });
expect(client.baseURL).toEqual('https://api.openai.com/v1');
});
+
+ test('in request options', () => {
+ const client = new OpenAI({ apiKey: 'My API Key' });
+ expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual(
+ 'http://localhost:5000/option/foo',
+ );
+ });
+
+ test('in request options overridden by client options', () => {
+ const client = new OpenAI({ apiKey: 'My API Key', baseURL: 'http://localhost:5000/client' });
+ expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual(
+ 'http://localhost:5000/client/foo',
+ );
+ });
+
+ test('in request options overridden by env variable', () => {
+ process.env['OPENAI_BASE_URL'] = 'http://localhost:5000/env';
+ const client = new OpenAI({ apiKey: 'My API Key' });
+ expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual(
+ 'http://localhost:5000/env/foo',
+ );
+ });
});
test('maxRetries option is correctly set', () => {
diff --git a/tsc-multi.json b/tsc-multi.json
index 170bac7a4..384ddac5b 100644
--- a/tsc-multi.json
+++ b/tsc-multi.json
@@ -1,7 +1,15 @@
{
"targets": [
- { "extname": ".js", "module": "commonjs", "shareHelpers": "internal/tslib.js" },
- { "extname": ".mjs", "module": "esnext", "shareHelpers": "internal/tslib.mjs" }
+ {
+ "extname": ".js",
+ "module": "commonjs",
+ "shareHelpers": "internal/tslib.js"
+ },
+ {
+ "extname": ".mjs",
+ "module": "esnext",
+ "shareHelpers": "internal/tslib.mjs"
+ }
],
"projects": ["tsconfig.build.json"]
}
diff --git a/yarn.lock b/yarn.lock
index 110f00260..e95b98c26 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3302,9 +3302,9 @@ ts-node@^10.5.0:
v8-compile-cache-lib "^3.0.0"
yn "3.1.1"
-"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz":
- version "1.1.4"
- resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz#cbed459a9e902f5295ec3daaf1c7aa3b10427e55"
+"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz":
+ version "1.1.8"
+ resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz#f544b359b8f05e607771ffacc280e58201476b04"
dependencies:
debug "^4.3.7"
fast-glob "^3.3.2"