client.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. "use strict";
  2. // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
  3. var _OpenAI_instances, _a, _OpenAI_encoder, _OpenAI_baseURLOverridden;
  4. Object.defineProperty(exports, "__esModule", { value: true });
  5. exports.OpenAI = void 0;
  6. const tslib_1 = require("./internal/tslib.js");
  7. const uuid_1 = require("./internal/utils/uuid.js");
  8. const values_1 = require("./internal/utils/values.js");
  9. const sleep_1 = require("./internal/utils/sleep.js");
  10. const errors_1 = require("./internal/errors.js");
  11. const detect_platform_1 = require("./internal/detect-platform.js");
  12. const Shims = tslib_1.__importStar(require("./internal/shims.js"));
  13. const Opts = tslib_1.__importStar(require("./internal/request-options.js"));
  14. const qs = tslib_1.__importStar(require("./internal/qs/index.js"));
  15. const version_1 = require("./version.js");
  16. const Errors = tslib_1.__importStar(require("./core/error.js"));
  17. const Pagination = tslib_1.__importStar(require("./core/pagination.js"));
  18. const Uploads = tslib_1.__importStar(require("./core/uploads.js"));
  19. const API = tslib_1.__importStar(require("./resources/index.js"));
  20. const api_promise_1 = require("./core/api-promise.js");
  21. const batches_1 = require("./resources/batches.js");
  22. const completions_1 = require("./resources/completions.js");
  23. const embeddings_1 = require("./resources/embeddings.js");
  24. const files_1 = require("./resources/files.js");
  25. const images_1 = require("./resources/images.js");
  26. const models_1 = require("./resources/models.js");
  27. const moderations_1 = require("./resources/moderations.js");
  28. const videos_1 = require("./resources/videos.js");
  29. const webhooks_1 = require("./resources/webhooks.js");
  30. const audio_1 = require("./resources/audio/audio.js");
  31. const beta_1 = require("./resources/beta/beta.js");
  32. const chat_1 = require("./resources/chat/chat.js");
  33. const containers_1 = require("./resources/containers/containers.js");
  34. const conversations_1 = require("./resources/conversations/conversations.js");
  35. const evals_1 = require("./resources/evals/evals.js");
  36. const fine_tuning_1 = require("./resources/fine-tuning/fine-tuning.js");
  37. const graders_1 = require("./resources/graders/graders.js");
  38. const realtime_1 = require("./resources/realtime/realtime.js");
  39. const responses_1 = require("./resources/responses/responses.js");
  40. const uploads_1 = require("./resources/uploads/uploads.js");
  41. const vector_stores_1 = require("./resources/vector-stores/vector-stores.js");
  42. const detect_platform_2 = require("./internal/detect-platform.js");
  43. const headers_1 = require("./internal/headers.js");
  44. const env_1 = require("./internal/utils/env.js");
  45. const log_1 = require("./internal/utils/log.js");
  46. const values_2 = require("./internal/utils/values.js");
  47. /**
  48. * API Client for interfacing with the OpenAI API.
  49. */
  50. class OpenAI {
  51. /**
  52. * API Client for interfacing with the OpenAI API.
  53. *
  54. * @param {string | undefined} [opts.apiKey=process.env['OPENAI_API_KEY'] ?? undefined]
  55. * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null]
  56. * @param {string | null | undefined} [opts.project=process.env['OPENAI_PROJECT_ID'] ?? null]
  57. * @param {string | null | undefined} [opts.webhookSecret=process.env['OPENAI_WEBHOOK_SECRET'] ?? null]
  58. * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL'] ?? https://api.openai.com/v1] - Override the default base URL for the API.
  59. * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
  60. * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls.
  61. * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.
  62. * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.
  63. * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API.
  64. * @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API.
  65. * @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.
  66. */
  67. constructor({ baseURL = (0, env_1.readEnv)('OPENAI_BASE_URL'), apiKey = (0, env_1.readEnv)('OPENAI_API_KEY'), organization = (0, env_1.readEnv)('OPENAI_ORG_ID') ?? null, project = (0, env_1.readEnv)('OPENAI_PROJECT_ID') ?? null, webhookSecret = (0, env_1.readEnv)('OPENAI_WEBHOOK_SECRET') ?? null, ...opts } = {}) {
  68. _OpenAI_instances.add(this);
  69. _OpenAI_encoder.set(this, void 0);
  70. this.completions = new API.Completions(this);
  71. this.chat = new API.Chat(this);
  72. this.embeddings = new API.Embeddings(this);
  73. this.files = new API.Files(this);
  74. this.images = new API.Images(this);
  75. this.audio = new API.Audio(this);
  76. this.moderations = new API.Moderations(this);
  77. this.models = new API.Models(this);
  78. this.fineTuning = new API.FineTuning(this);
  79. this.graders = new API.Graders(this);
  80. this.vectorStores = new API.VectorStores(this);
  81. this.webhooks = new API.Webhooks(this);
  82. this.beta = new API.Beta(this);
  83. this.batches = new API.Batches(this);
  84. this.uploads = new API.Uploads(this);
  85. this.responses = new API.Responses(this);
  86. this.realtime = new API.Realtime(this);
  87. this.conversations = new API.Conversations(this);
  88. this.evals = new API.Evals(this);
  89. this.containers = new API.Containers(this);
  90. this.videos = new API.Videos(this);
  91. if (apiKey === undefined) {
  92. throw new Errors.OpenAIError('Missing credentials. Please pass an `apiKey`, or set the `OPENAI_API_KEY` environment variable.');
  93. }
  94. const options = {
  95. apiKey,
  96. organization,
  97. project,
  98. webhookSecret,
  99. ...opts,
  100. baseURL: baseURL || `https://api.openai.com/v1`,
  101. };
  102. if (!options.dangerouslyAllowBrowser && (0, detect_platform_2.isRunningInBrowser)()) {
  103. throw new Errors.OpenAIError("It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n");
  104. }
  105. this.baseURL = options.baseURL;
  106. this.timeout = options.timeout ?? _a.DEFAULT_TIMEOUT /* 10 minutes */;
  107. this.logger = options.logger ?? console;
  108. const defaultLogLevel = 'warn';
  109. // Set default logLevel early so that we can log a warning in parseLogLevel.
  110. this.logLevel = defaultLogLevel;
  111. this.logLevel =
  112. (0, log_1.parseLogLevel)(options.logLevel, 'ClientOptions.logLevel', this) ??
  113. (0, log_1.parseLogLevel)((0, env_1.readEnv)('OPENAI_LOG'), "process.env['OPENAI_LOG']", this) ??
  114. defaultLogLevel;
  115. this.fetchOptions = options.fetchOptions;
  116. this.maxRetries = options.maxRetries ?? 2;
  117. this.fetch = options.fetch ?? Shims.getDefaultFetch();
  118. tslib_1.__classPrivateFieldSet(this, _OpenAI_encoder, Opts.FallbackEncoder, "f");
  119. this._options = options;
  120. this.apiKey = typeof apiKey === 'string' ? apiKey : 'Missing Key';
  121. this.organization = organization;
  122. this.project = project;
  123. this.webhookSecret = webhookSecret;
  124. }
  125. /**
  126. * Create a new client instance re-using the same options given to the current client with optional overriding.
  127. */
  128. withOptions(options) {
  129. const client = new this.constructor({
  130. ...this._options,
  131. baseURL: this.baseURL,
  132. maxRetries: this.maxRetries,
  133. timeout: this.timeout,
  134. logger: this.logger,
  135. logLevel: this.logLevel,
  136. fetch: this.fetch,
  137. fetchOptions: this.fetchOptions,
  138. apiKey: this.apiKey,
  139. organization: this.organization,
  140. project: this.project,
  141. webhookSecret: this.webhookSecret,
  142. ...options,
  143. });
  144. return client;
  145. }
  146. defaultQuery() {
  147. return this._options.defaultQuery;
  148. }
  149. validateHeaders({ values, nulls }) {
  150. return;
  151. }
  152. async authHeaders(opts) {
  153. return (0, headers_1.buildHeaders)([{ Authorization: `Bearer ${this.apiKey}` }]);
  154. }
  155. stringifyQuery(query) {
  156. return qs.stringify(query, { arrayFormat: 'brackets' });
  157. }
  158. getUserAgent() {
  159. return `${this.constructor.name}/JS ${version_1.VERSION}`;
  160. }
  161. defaultIdempotencyKey() {
  162. return `stainless-node-retry-${(0, uuid_1.uuid4)()}`;
  163. }
  164. makeStatusError(status, error, message, headers) {
  165. return Errors.APIError.generate(status, error, message, headers);
  166. }
  167. async _callApiKey() {
  168. const apiKey = this._options.apiKey;
  169. if (typeof apiKey !== 'function')
  170. return false;
  171. let token;
  172. try {
  173. token = await apiKey();
  174. }
  175. catch (err) {
  176. if (err instanceof Errors.OpenAIError)
  177. throw err;
  178. throw new Errors.OpenAIError(`Failed to get token from 'apiKey' function: ${err.message}`,
  179. // @ts-ignore
  180. { cause: err });
  181. }
  182. if (typeof token !== 'string' || !token) {
  183. throw new Errors.OpenAIError(`Expected 'apiKey' function argument to return a string but it returned ${token}`);
  184. }
  185. this.apiKey = token;
  186. return true;
  187. }
  188. buildURL(path, query, defaultBaseURL) {
  189. const baseURL = (!tslib_1.__classPrivateFieldGet(this, _OpenAI_instances, "m", _OpenAI_baseURLOverridden).call(this) && defaultBaseURL) || this.baseURL;
  190. const url = (0, values_1.isAbsoluteURL)(path) ?
  191. new URL(path)
  192. : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
  193. const defaultQuery = this.defaultQuery();
  194. if (!(0, values_2.isEmptyObj)(defaultQuery)) {
  195. query = { ...defaultQuery, ...query };
  196. }
  197. if (typeof query === 'object' && query && !Array.isArray(query)) {
  198. url.search = this.stringifyQuery(query);
  199. }
  200. return url.toString();
  201. }
  202. /**
  203. * Used as a callback for mutating the given `FinalRequestOptions` object.
  204. */
  205. async prepareOptions(options) {
  206. await this._callApiKey();
  207. }
  208. /**
  209. * Used as a callback for mutating the given `RequestInit` object.
  210. *
  211. * This is useful for cases where you want to add certain headers based off of
  212. * the request properties, e.g. `method` or `url`.
  213. */
  214. async prepareRequest(request, { url, options }) { }
  215. get(path, opts) {
  216. return this.methodRequest('get', path, opts);
  217. }
  218. post(path, opts) {
  219. return this.methodRequest('post', path, opts);
  220. }
  221. patch(path, opts) {
  222. return this.methodRequest('patch', path, opts);
  223. }
  224. put(path, opts) {
  225. return this.methodRequest('put', path, opts);
  226. }
  227. delete(path, opts) {
  228. return this.methodRequest('delete', path, opts);
  229. }
  230. methodRequest(method, path, opts) {
  231. return this.request(Promise.resolve(opts).then((opts) => {
  232. return { method, path, ...opts };
  233. }));
  234. }
  235. request(options, remainingRetries = null) {
  236. return new api_promise_1.APIPromise(this, this.makeRequest(options, remainingRetries, undefined));
  237. }
  238. async makeRequest(optionsInput, retriesRemaining, retryOfRequestLogID) {
  239. const options = await optionsInput;
  240. const maxRetries = options.maxRetries ?? this.maxRetries;
  241. if (retriesRemaining == null) {
  242. retriesRemaining = maxRetries;
  243. }
  244. await this.prepareOptions(options);
  245. const { req, url, timeout } = await this.buildRequest(options, {
  246. retryCount: maxRetries - retriesRemaining,
  247. });
  248. await this.prepareRequest(req, { url, options });
  249. /** Not an API request ID, just for correlating local log entries. */
  250. const requestLogID = 'log_' + ((Math.random() * (1 << 24)) | 0).toString(16).padStart(6, '0');
  251. const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`;
  252. const startTime = Date.now();
  253. (0, log_1.loggerFor)(this).debug(`[${requestLogID}] sending request`, (0, log_1.formatRequestDetails)({
  254. retryOfRequestLogID,
  255. method: options.method,
  256. url,
  257. options,
  258. headers: req.headers,
  259. }));
  260. if (options.signal?.aborted) {
  261. throw new Errors.APIUserAbortError();
  262. }
  263. const controller = new AbortController();
  264. const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(errors_1.castToError);
  265. const headersTime = Date.now();
  266. if (response instanceof globalThis.Error) {
  267. const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
  268. if (options.signal?.aborted) {
  269. throw new Errors.APIUserAbortError();
  270. }
  271. // detect native connection timeout errors
  272. // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)"
  273. // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)"
  274. // others do not provide enough information to distinguish timeouts from other connection errors
  275. const isTimeout = (0, errors_1.isAbortError)(response) ||
  276. /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : ''));
  277. if (retriesRemaining) {
  278. (0, log_1.loggerFor)(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`);
  279. (0, log_1.loggerFor)(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, (0, log_1.formatRequestDetails)({
  280. retryOfRequestLogID,
  281. url,
  282. durationMs: headersTime - startTime,
  283. message: response.message,
  284. }));
  285. return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID);
  286. }
  287. (0, log_1.loggerFor)(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`);
  288. (0, log_1.loggerFor)(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, (0, log_1.formatRequestDetails)({
  289. retryOfRequestLogID,
  290. url,
  291. durationMs: headersTime - startTime,
  292. message: response.message,
  293. }));
  294. if (isTimeout) {
  295. throw new Errors.APIConnectionTimeoutError();
  296. }
  297. throw new Errors.APIConnectionError({ cause: response });
  298. }
  299. const specialHeaders = [...response.headers.entries()]
  300. .filter(([name]) => name === 'x-request-id')
  301. .map(([name, value]) => ', ' + name + ': ' + JSON.stringify(value))
  302. .join('');
  303. const responseInfo = `[${requestLogID}${retryLogStr}${specialHeaders}] ${req.method} ${url} ${response.ok ? 'succeeded' : 'failed'} with status ${response.status} in ${headersTime - startTime}ms`;
  304. if (!response.ok) {
  305. const shouldRetry = await this.shouldRetry(response);
  306. if (retriesRemaining && shouldRetry) {
  307. const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
  308. // We don't need the body of this response.
  309. await Shims.CancelReadableStream(response.body);
  310. (0, log_1.loggerFor)(this).info(`${responseInfo} - ${retryMessage}`);
  311. (0, log_1.loggerFor)(this).debug(`[${requestLogID}] response error (${retryMessage})`, (0, log_1.formatRequestDetails)({
  312. retryOfRequestLogID,
  313. url: response.url,
  314. status: response.status,
  315. headers: response.headers,
  316. durationMs: headersTime - startTime,
  317. }));
  318. return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers);
  319. }
  320. const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`;
  321. (0, log_1.loggerFor)(this).info(`${responseInfo} - ${retryMessage}`);
  322. const errText = await response.text().catch((err) => (0, errors_1.castToError)(err).message);
  323. const errJSON = (0, values_1.safeJSON)(errText);
  324. const errMessage = errJSON ? undefined : errText;
  325. (0, log_1.loggerFor)(this).debug(`[${requestLogID}] response error (${retryMessage})`, (0, log_1.formatRequestDetails)({
  326. retryOfRequestLogID,
  327. url: response.url,
  328. status: response.status,
  329. headers: response.headers,
  330. message: errMessage,
  331. durationMs: Date.now() - startTime,
  332. }));
  333. const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers);
  334. throw err;
  335. }
  336. (0, log_1.loggerFor)(this).info(responseInfo);
  337. (0, log_1.loggerFor)(this).debug(`[${requestLogID}] response start`, (0, log_1.formatRequestDetails)({
  338. retryOfRequestLogID,
  339. url: response.url,
  340. status: response.status,
  341. headers: response.headers,
  342. durationMs: headersTime - startTime,
  343. }));
  344. return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
  345. }
  346. getAPIList(path, Page, opts) {
  347. return this.requestAPIList(Page, { method: 'get', path, ...opts });
  348. }
  349. requestAPIList(Page, options) {
  350. const request = this.makeRequest(options, null, undefined);
  351. return new Pagination.PagePromise(this, request, Page);
  352. }
  353. async fetchWithTimeout(url, init, ms, controller) {
  354. const { signal, method, ...options } = init || {};
  355. if (signal)
  356. signal.addEventListener('abort', () => controller.abort());
  357. const timeout = setTimeout(() => controller.abort(), ms);
  358. const isReadableBody = (globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream) ||
  359. (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
  360. const fetchOptions = {
  361. signal: controller.signal,
  362. ...(isReadableBody ? { duplex: 'half' } : {}),
  363. method: 'GET',
  364. ...options,
  365. };
  366. if (method) {
  367. // Custom methods like 'patch' need to be uppercased
  368. // See https://github.com/nodejs/undici/issues/2294
  369. fetchOptions.method = method.toUpperCase();
  370. }
  371. try {
  372. // use undefined this binding; fetch errors if bound to something else in browser/cloudflare
  373. return await this.fetch.call(undefined, url, fetchOptions);
  374. }
  375. finally {
  376. clearTimeout(timeout);
  377. }
  378. }
  379. async shouldRetry(response) {
  380. // Note this is not a standard header.
  381. const shouldRetryHeader = response.headers.get('x-should-retry');
  382. // If the server explicitly says whether or not to retry, obey.
  383. if (shouldRetryHeader === 'true')
  384. return true;
  385. if (shouldRetryHeader === 'false')
  386. return false;
  387. // Retry on request timeouts.
  388. if (response.status === 408)
  389. return true;
  390. // Retry on lock timeouts.
  391. if (response.status === 409)
  392. return true;
  393. // Retry on rate limits.
  394. if (response.status === 429)
  395. return true;
  396. // Retry internal errors.
  397. if (response.status >= 500)
  398. return true;
  399. return false;
  400. }
  401. async retryRequest(options, retriesRemaining, requestLogID, responseHeaders) {
  402. let timeoutMillis;
  403. // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
  404. const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms');
  405. if (retryAfterMillisHeader) {
  406. const timeoutMs = parseFloat(retryAfterMillisHeader);
  407. if (!Number.isNaN(timeoutMs)) {
  408. timeoutMillis = timeoutMs;
  409. }
  410. }
  411. // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
  412. const retryAfterHeader = responseHeaders?.get('retry-after');
  413. if (retryAfterHeader && !timeoutMillis) {
  414. const timeoutSeconds = parseFloat(retryAfterHeader);
  415. if (!Number.isNaN(timeoutSeconds)) {
  416. timeoutMillis = timeoutSeconds * 1000;
  417. }
  418. else {
  419. timeoutMillis = Date.parse(retryAfterHeader) - Date.now();
  420. }
  421. }
  422. // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
  423. // just do what it says, but otherwise calculate a default
  424. if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
  425. const maxRetries = options.maxRetries ?? this.maxRetries;
  426. timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
  427. }
  428. await (0, sleep_1.sleep)(timeoutMillis);
  429. return this.makeRequest(options, retriesRemaining - 1, requestLogID);
  430. }
  431. calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
  432. const initialRetryDelay = 0.5;
  433. const maxRetryDelay = 8.0;
  434. const numRetries = maxRetries - retriesRemaining;
  435. // Apply exponential backoff, but not more than the max.
  436. const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);
  437. // Apply some jitter, take up to at most 25 percent of the retry time.
  438. const jitter = 1 - Math.random() * 0.25;
  439. return sleepSeconds * jitter * 1000;
  440. }
  441. async buildRequest(inputOptions, { retryCount = 0 } = {}) {
  442. const options = { ...inputOptions };
  443. const { method, path, query, defaultBaseURL } = options;
  444. const url = this.buildURL(path, query, defaultBaseURL);
  445. if ('timeout' in options)
  446. (0, values_1.validatePositiveInteger)('timeout', options.timeout);
  447. options.timeout = options.timeout ?? this.timeout;
  448. const { bodyHeaders, body } = this.buildBody({ options });
  449. const reqHeaders = await this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount });
  450. const req = {
  451. method,
  452. headers: reqHeaders,
  453. ...(options.signal && { signal: options.signal }),
  454. ...(globalThis.ReadableStream &&
  455. body instanceof globalThis.ReadableStream && { duplex: 'half' }),
  456. ...(body && { body }),
  457. ...(this.fetchOptions ?? {}),
  458. ...(options.fetchOptions ?? {}),
  459. };
  460. return { req, url, timeout: options.timeout };
  461. }
  462. async buildHeaders({ options, method, bodyHeaders, retryCount, }) {
  463. let idempotencyHeaders = {};
  464. if (this.idempotencyHeader && method !== 'get') {
  465. if (!options.idempotencyKey)
  466. options.idempotencyKey = this.defaultIdempotencyKey();
  467. idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey;
  468. }
  469. const headers = (0, headers_1.buildHeaders)([
  470. idempotencyHeaders,
  471. {
  472. Accept: 'application/json',
  473. 'User-Agent': this.getUserAgent(),
  474. 'X-Stainless-Retry-Count': String(retryCount),
  475. ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}),
  476. ...(0, detect_platform_1.getPlatformHeaders)(),
  477. 'OpenAI-Organization': this.organization,
  478. 'OpenAI-Project': this.project,
  479. },
  480. await this.authHeaders(options),
  481. this._options.defaultHeaders,
  482. bodyHeaders,
  483. options.headers,
  484. ]);
  485. this.validateHeaders(headers);
  486. return headers.values;
  487. }
  488. buildBody({ options: { body, headers: rawHeaders } }) {
  489. if (!body) {
  490. return { bodyHeaders: undefined, body: undefined };
  491. }
  492. const headers = (0, headers_1.buildHeaders)([rawHeaders]);
  493. if (
  494. // Pass raw type verbatim
  495. ArrayBuffer.isView(body) ||
  496. body instanceof ArrayBuffer ||
  497. body instanceof DataView ||
  498. (typeof body === 'string' &&
  499. // Preserve legacy string encoding behavior for now
  500. headers.values.has('content-type')) ||
  501. // `Blob` is superset of `File`
  502. (globalThis.Blob && body instanceof globalThis.Blob) ||
  503. // `FormData` -> `multipart/form-data`
  504. body instanceof FormData ||
  505. // `URLSearchParams` -> `application/x-www-form-urlencoded`
  506. body instanceof URLSearchParams ||
  507. // Send chunked stream (each chunk has own `length`)
  508. (globalThis.ReadableStream && body instanceof globalThis.ReadableStream)) {
  509. return { bodyHeaders: undefined, body: body };
  510. }
  511. else if (typeof body === 'object' &&
  512. (Symbol.asyncIterator in body ||
  513. (Symbol.iterator in body && 'next' in body && typeof body.next === 'function'))) {
  514. return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body) };
  515. }
  516. else {
  517. return tslib_1.__classPrivateFieldGet(this, _OpenAI_encoder, "f").call(this, { body, headers });
  518. }
  519. }
  520. }
  521. exports.OpenAI = OpenAI;
  522. _a = OpenAI, _OpenAI_encoder = new WeakMap(), _OpenAI_instances = new WeakSet(), _OpenAI_baseURLOverridden = function _OpenAI_baseURLOverridden() {
  523. return this.baseURL !== 'https://api.openai.com/v1';
  524. };
  525. OpenAI.OpenAI = _a;
  526. OpenAI.DEFAULT_TIMEOUT = 600000; // 10 minutes
  527. OpenAI.OpenAIError = Errors.OpenAIError;
  528. OpenAI.APIError = Errors.APIError;
  529. OpenAI.APIConnectionError = Errors.APIConnectionError;
  530. OpenAI.APIConnectionTimeoutError = Errors.APIConnectionTimeoutError;
  531. OpenAI.APIUserAbortError = Errors.APIUserAbortError;
  532. OpenAI.NotFoundError = Errors.NotFoundError;
  533. OpenAI.ConflictError = Errors.ConflictError;
  534. OpenAI.RateLimitError = Errors.RateLimitError;
  535. OpenAI.BadRequestError = Errors.BadRequestError;
  536. OpenAI.AuthenticationError = Errors.AuthenticationError;
  537. OpenAI.InternalServerError = Errors.InternalServerError;
  538. OpenAI.PermissionDeniedError = Errors.PermissionDeniedError;
  539. OpenAI.UnprocessableEntityError = Errors.UnprocessableEntityError;
  540. OpenAI.InvalidWebhookSignatureError = Errors.InvalidWebhookSignatureError;
  541. OpenAI.toFile = Uploads.toFile;
  542. OpenAI.Completions = completions_1.Completions;
  543. OpenAI.Chat = chat_1.Chat;
  544. OpenAI.Embeddings = embeddings_1.Embeddings;
  545. OpenAI.Files = files_1.Files;
  546. OpenAI.Images = images_1.Images;
  547. OpenAI.Audio = audio_1.Audio;
  548. OpenAI.Moderations = moderations_1.Moderations;
  549. OpenAI.Models = models_1.Models;
  550. OpenAI.FineTuning = fine_tuning_1.FineTuning;
  551. OpenAI.Graders = graders_1.Graders;
  552. OpenAI.VectorStores = vector_stores_1.VectorStores;
  553. OpenAI.Webhooks = webhooks_1.Webhooks;
  554. OpenAI.Beta = beta_1.Beta;
  555. OpenAI.Batches = batches_1.Batches;
  556. OpenAI.Uploads = uploads_1.Uploads;
  557. OpenAI.Responses = responses_1.Responses;
  558. OpenAI.Realtime = realtime_1.Realtime;
  559. OpenAI.Conversations = conversations_1.Conversations;
  560. OpenAI.Evals = evals_1.Evals;
  561. OpenAI.Containers = containers_1.Containers;
  562. OpenAI.Videos = videos_1.Videos;
  563. //# sourceMappingURL=client.js.map