client.mjs 27 KB

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