@anthropic-ai/sdk 0.5.10 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +48 -20
  3. package/_shims/ReadableStream.d.ts +38 -0
  4. package/_shims/ReadableStream.js +5 -0
  5. package/_shims/ReadableStream.mjs +7 -0
  6. package/_shims/ReadableStream.node.d.ts +6 -0
  7. package/_shims/ReadableStream.node.d.ts.map +1 -0
  8. package/_shims/ReadableStream.node.js +14 -0
  9. package/_shims/ReadableStream.node.js.map +1 -0
  10. package/_shims/ReadableStream.node.mjs +3 -0
  11. package/_shims/ReadableStream.node.mjs.map +1 -0
  12. package/_shims/fetch.d.ts +8 -1
  13. package/_shims/fetch.node.d.ts +11 -1
  14. package/core.d.ts +77 -28
  15. package/core.d.ts.map +1 -1
  16. package/core.js +180 -61
  17. package/core.js.map +1 -1
  18. package/core.mjs +174 -61
  19. package/core.mjs.map +1 -1
  20. package/index.d.mts +2 -0
  21. package/index.d.ts +2 -0
  22. package/index.d.ts.map +1 -1
  23. package/index.js.map +1 -1
  24. package/index.mjs.map +1 -1
  25. package/package.json +1 -1
  26. package/resources/completions.d.ts +115 -191
  27. package/resources/completions.d.ts.map +1 -1
  28. package/resources/completions.js.map +1 -1
  29. package/resources/completions.mjs.map +1 -1
  30. package/resources/index.d.ts +7 -1
  31. package/resources/index.d.ts.map +1 -1
  32. package/resources/index.js.map +1 -1
  33. package/resources/index.mjs.map +1 -1
  34. package/src/_shims/ReadableStream.d.ts +38 -0
  35. package/src/_shims/ReadableStream.js +5 -0
  36. package/src/_shims/ReadableStream.mjs +7 -0
  37. package/src/_shims/ReadableStream.node.ts +6 -0
  38. package/src/_shims/fetch.d.ts +8 -1
  39. package/src/_shims/fetch.node.d.ts +11 -1
  40. package/src/core.ts +245 -83
  41. package/src/index.ts +2 -0
  42. package/src/resources/completions.ts +120 -202
  43. package/src/resources/index.ts +7 -1
  44. package/src/streaming.ts +9 -15
  45. package/src/version.ts +1 -1
  46. package/streaming.d.ts +3 -7
  47. package/streaming.d.ts.map +1 -1
  48. package/streaming.js +8 -5
  49. package/streaming.js.map +1 -1
  50. package/streaming.mjs +7 -4
  51. package/streaming.mjs.map +1 -1
  52. package/version.d.ts +1 -1
  53. package/version.d.ts.map +1 -1
  54. package/version.js +1 -1
  55. package/version.js.map +1 -1
  56. package/version.mjs +1 -1
  57. package/version.mjs.map +1 -1
package/src/core.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  type RequestInit,
11
11
  type Response,
12
12
  } from './_shims/fetch.js';
13
+ export { type Response };
13
14
  import { isMultipartBody } from './uploads';
14
15
  export {
15
16
  maybeMultipartFormRequestOptions,
@@ -22,6 +23,106 @@ const MAX_RETRIES = 2;
22
23
 
23
24
  export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;
24
25
 
26
+ type PromiseOrValue<T> = T | Promise<T>;
27
+
28
+ type APIResponseProps = {
29
+ response: Response;
30
+ options: FinalRequestOptions;
31
+ controller: AbortController;
32
+ };
33
+
34
+ async function defaultParseResponse<T>(props: APIResponseProps): Promise<T> {
35
+ const { response } = props;
36
+ if (props.options.stream) {
37
+ // Note: there is an invariant here that isn't represented in the type system
38
+ // that if you set `stream: true` the response type must also be `Stream<T>`
39
+ return new Stream(response, props.controller) as any;
40
+ }
41
+
42
+ const contentType = response.headers.get('content-type');
43
+ if (contentType?.includes('application/json')) {
44
+ const json = await response.json();
45
+
46
+ debug('response', response.status, response.url, response.headers, json);
47
+
48
+ return json as T;
49
+ }
50
+
51
+ // TODO handle blob, arraybuffer, other content types, etc.
52
+ const text = await response.text();
53
+ debug('response', response.status, response.url, response.headers, text);
54
+ return text as T;
55
+ }
56
+
57
+ /**
58
+ * A subclass of `Promise` providing additional helper methods
59
+ * for interacting with the SDK.
60
+ */
61
+ export class APIPromise<T> extends Promise<T> {
62
+ private parsedPromise: Promise<T> | undefined;
63
+
64
+ constructor(
65
+ private responsePromise: Promise<APIResponseProps>,
66
+ private parseResponse: (props: APIResponseProps) => PromiseOrValue<T> = defaultParseResponse,
67
+ ) {
68
+ super((resolve) => {
69
+ // this is maybe a bit weird but this has to be a no-op to not implicitly
70
+ // parse the response body; instead .then, .catch, .finally are overridden
71
+ // to parse the response
72
+ resolve(null as any);
73
+ });
74
+ }
75
+
76
+ _thenUnwrap<U>(transform: (data: T) => U): APIPromise<U> {
77
+ return new APIPromise(this.responsePromise, async (props) => transform(await this.parseResponse(props)));
78
+ }
79
+
80
+ /**
81
+ * Gets the raw `Response` instance instead of parsing the response
82
+ * data.
83
+ *
84
+ * If you want to parse the response body but still get the `Response`
85
+ * instance, you can use {@link withResponse()}.
86
+ */
87
+ asResponse(): Promise<Response> {
88
+ return this.responsePromise.then((p) => p.response);
89
+ }
90
+ /**
91
+ * Gets the parsed response data and the raw `Response` instance.
92
+ *
93
+ * If you just want to get the raw `Response` instance without parsing it,
94
+ * you can use {@link asResponse()}.
95
+ */
96
+ async withResponse(): Promise<{ data: T; response: Response }> {
97
+ const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
98
+ return { data, response };
99
+ }
100
+
101
+ private parse(): Promise<T> {
102
+ if (!this.parsedPromise) {
103
+ this.parsedPromise = this.responsePromise.then(this.parseResponse);
104
+ }
105
+ return this.parsedPromise;
106
+ }
107
+
108
+ override then<TResult1 = T, TResult2 = never>(
109
+ onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
110
+ onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
111
+ ): Promise<TResult1 | TResult2> {
112
+ return this.parse().then(onfulfilled, onrejected);
113
+ }
114
+
115
+ override catch<TResult = never>(
116
+ onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
117
+ ): Promise<T | TResult> {
118
+ return this.parse().catch(onrejected);
119
+ }
120
+
121
+ override finally(onfinally?: (() => void) | undefined | null): Promise<T> {
122
+ return this.parse().finally(onfinally);
123
+ }
124
+ }
125
+
25
126
  export abstract class APIClient {
26
127
  baseURL: string;
27
128
  maxRetries: number;
@@ -85,27 +186,39 @@ export abstract class APIClient {
85
186
  return `stainless-node-retry-${uuid4()}`;
86
187
  }
87
188
 
88
- get<Req extends {}, Rsp>(path: string, opts?: RequestOptions<Req>): Promise<Rsp> {
89
- return this.request({ method: 'get', path, ...opts });
189
+ get<Req extends {}, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
190
+ return this.methodRequest('get', path, opts);
191
+ }
192
+
193
+ post<Req extends {}, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
194
+ return this.methodRequest('post', path, opts);
90
195
  }
91
- post<Req extends {}, Rsp>(path: string, opts?: RequestOptions<Req>): Promise<Rsp> {
92
- return this.request({ method: 'post', path, ...opts });
196
+
197
+ patch<Req extends {}, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
198
+ return this.methodRequest('patch', path, opts);
93
199
  }
94
- patch<Req extends {}, Rsp>(path: string, opts?: RequestOptions<Req>): Promise<Rsp> {
95
- return this.request({ method: 'patch', path, ...opts });
200
+
201
+ put<Req extends {}, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
202
+ return this.methodRequest('put', path, opts);
96
203
  }
97
- put<Req extends {}, Rsp>(path: string, opts?: RequestOptions<Req>): Promise<Rsp> {
98
- return this.request({ method: 'put', path, ...opts });
204
+
205
+ delete<Req extends {}, Rsp>(path: string, opts?: PromiseOrValue<RequestOptions<Req>>): APIPromise<Rsp> {
206
+ return this.methodRequest('delete', path, opts);
99
207
  }
100
- delete<Req extends {}, Rsp>(path: string, opts?: RequestOptions<Req>): Promise<Rsp> {
101
- return this.request({ method: 'delete', path, ...opts });
208
+
209
+ private methodRequest<Req extends {}, Rsp>(
210
+ method: HTTPMethod,
211
+ path: string,
212
+ opts?: PromiseOrValue<RequestOptions<Req>>,
213
+ ): APIPromise<Rsp> {
214
+ return this.request(Promise.resolve(opts).then((opts) => ({ method, path, ...opts })));
102
215
  }
103
216
 
104
217
  getAPIList<Item, PageClass extends AbstractPage<Item> = AbstractPage<Item>>(
105
218
  path: string,
106
219
  Page: new (...args: any[]) => PageClass,
107
220
  opts?: RequestOptions<any>,
108
- ): PagePromise<PageClass> {
221
+ ): PagePromise<PageClass, Item> {
109
222
  return this.requestAPIList(Page, { method: 'get', path, ...opts });
110
223
  }
111
224
 
@@ -199,14 +312,27 @@ export abstract class APIClient {
199
312
  return APIError.generate(status, error, message, headers);
200
313
  }
201
314
 
202
- async request<Req extends {}, Rsp>(
203
- options: FinalRequestOptions<Req>,
204
- retriesRemaining = options.maxRetries ?? this.maxRetries,
205
- ): Promise<APIResponse<Rsp>> {
315
+ request<Req extends {}, Rsp>(
316
+ options: PromiseOrValue<FinalRequestOptions<Req>>,
317
+ remainingRetries: number | null = null,
318
+ ): APIPromise<Rsp> {
319
+ return new APIPromise(this.makeRequest(options, remainingRetries));
320
+ }
321
+
322
+ private async makeRequest<T>(
323
+ optionsInput: PromiseOrValue<FinalRequestOptions>,
324
+ retriesRemaining: number | null,
325
+ ): Promise<{ response: Response; options: FinalRequestOptions; controller: AbortController }> {
326
+ const options = await optionsInput;
327
+ if (retriesRemaining == null) {
328
+ retriesRemaining = options.maxRetries ?? this.maxRetries;
329
+ }
330
+
206
331
  const { req, url, timeout } = this.buildRequest(options);
332
+
207
333
  await this.prepareRequest(req, { url });
208
334
 
209
- this.debug('request', url, options, req.headers);
335
+ debug('request', url, options, req.headers);
210
336
 
211
337
  if (options.signal?.aborted) {
212
338
  throw new APIUserAbortError();
@@ -239,48 +365,21 @@ export abstract class APIClient {
239
365
  const errJSON = safeJSON(errText);
240
366
  const errMessage = errJSON ? undefined : errText;
241
367
 
242
- this.debug('response', response.status, url, responseHeaders, errMessage);
368
+ debug('response', response.status, url, responseHeaders, errMessage);
243
369
 
244
370
  const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);
245
371
  throw err;
246
372
  }
247
373
 
248
- if (options.stream) {
249
- // Note: there is an invariant here that isn't represented in the type system
250
- // that if you set `stream: true` the response type must also be `Stream<T>`
251
- return new Stream(response, controller) as any;
252
- }
253
-
254
- const contentType = response.headers.get('content-type');
255
- if (contentType?.includes('application/json')) {
256
- const json = await response.json();
257
-
258
- if (typeof json === 'object' && json != null) {
259
- /** @deprecated – we expect to change this interface in the near future. */
260
- Object.defineProperty(json, 'responseHeaders', {
261
- enumerable: false,
262
- writable: false,
263
- value: responseHeaders,
264
- });
265
- }
266
-
267
- this.debug('response', response.status, url, responseHeaders, json);
268
-
269
- return json as APIResponse<Rsp>;
270
- }
271
-
272
- // TODO handle blob, arraybuffer, other content types, etc.
273
- const text = response.text();
274
- this.debug('response', response.status, url, responseHeaders, text);
275
- return text as Promise<any>;
374
+ return { response, options, controller };
276
375
  }
277
376
 
278
377
  requestAPIList<Item = unknown, PageClass extends AbstractPage<Item> = AbstractPage<Item>>(
279
378
  Page: new (...args: ConstructorParameters<typeof AbstractPage>) => PageClass,
280
379
  options: FinalRequestOptions,
281
- ): PagePromise<PageClass> {
282
- const requestPromise = this.request(options) as Promise<APIResponse<unknown>>;
283
- return new PagePromise(this, requestPromise, options, Page);
380
+ ): PagePromise<PageClass, Item> {
381
+ const request = this.makeRequest(options, null);
382
+ return new PagePromise<PageClass, Item>(this, request, Page);
284
383
  }
285
384
 
286
385
  buildURL<Req>(path: string, query: Req | undefined): string {
@@ -408,12 +507,6 @@ export abstract class APIClient {
408
507
  private getUserAgent(): string {
409
508
  return `${this.constructor.name}/JS ${VERSION}`;
410
509
  }
411
-
412
- private debug(action: string, ...args: any[]) {
413
- if (typeof process !== 'undefined' && process.env['DEBUG'] === 'true') {
414
- console.log(`${this.constructor.name}:DEBUG:${action}`, ...args);
415
- }
416
- }
417
510
  }
418
511
 
419
512
  export class APIResource {
@@ -443,9 +536,14 @@ export abstract class AbstractPage<Item> implements AsyncIterable<Item> {
443
536
  #client: APIClient;
444
537
  protected options: FinalRequestOptions;
445
538
 
446
- constructor(client: APIClient, response: APIResponse<unknown>, options: FinalRequestOptions) {
539
+ protected response: Response;
540
+ protected body: unknown;
541
+
542
+ constructor(client: APIClient, response: Response, body: unknown, options: FinalRequestOptions) {
447
543
  this.#client = client;
448
544
  this.options = options;
545
+ this.response = response;
546
+ this.body = body;
449
547
  }
450
548
 
451
549
  /**
@@ -502,35 +600,33 @@ export abstract class AbstractPage<Item> implements AsyncIterable<Item> {
502
600
  }
503
601
  }
504
602
 
603
+ /**
604
+ * This subclass of Promise will resolve to an instantiated Page once the request completes.
605
+ *
606
+ * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg:
607
+ *
608
+ * for await (const item of client.items.list()) {
609
+ * console.log(item)
610
+ * }
611
+ */
505
612
  export class PagePromise<
506
613
  PageClass extends AbstractPage<Item>,
507
614
  Item = ReturnType<PageClass['getPaginatedItems']>[number],
508
615
  >
509
- extends Promise<PageClass>
616
+ extends APIPromise<PageClass>
510
617
  implements AsyncIterable<Item>
511
618
  {
512
- /**
513
- * This subclass of Promise will resolve to an instantiated Page once the request completes.
514
- */
515
619
  constructor(
516
620
  client: APIClient,
517
- requestPromise: Promise<APIResponse<unknown>>,
518
- options: FinalRequestOptions,
621
+ request: Promise<APIResponseProps>,
519
622
  Page: new (...args: ConstructorParameters<typeof AbstractPage>) => PageClass,
520
623
  ) {
521
- super((resolve, reject) =>
522
- requestPromise.then((response) => resolve(new Page(client, response, options))).catch(reject),
624
+ super(
625
+ request,
626
+ async (props) => new Page(client, props.response, await defaultParseResponse(props), props.options),
523
627
  );
524
628
  }
525
629
 
526
- /**
527
- * Enable subclassing Promise.
528
- * Ref: https://stackoverflow.com/a/60328122
529
- */
530
- static get [Symbol.species]() {
531
- return Promise;
532
- }
533
-
534
630
  /**
535
631
  * Allow auto-paginating iteration on an unawaited list call, eg:
536
632
  *
@@ -617,11 +713,6 @@ export type FinalRequestOptions<Req extends {} = Record<string, unknown> | Reada
617
713
  path: string;
618
714
  };
619
715
 
620
- export type APIResponse<T> = T & {
621
- /** @deprecated - we plan to add a different way to access raw response information shortly. */
622
- responseHeaders: Headers;
623
- };
624
-
625
716
  declare const Deno: any;
626
717
  declare const EdgeRuntime: any;
627
718
  type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown';
@@ -635,12 +726,13 @@ type PlatformName =
635
726
  | 'Android'
636
727
  | `Other:${string}`
637
728
  | 'Unknown';
729
+ type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari';
638
730
  type PlatformProperties = {
639
731
  'X-Stainless-Lang': 'js';
640
732
  'X-Stainless-Package-Version': string;
641
733
  'X-Stainless-OS': PlatformName;
642
734
  'X-Stainless-Arch': Arch;
643
- 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | 'unknown';
735
+ 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown';
644
736
  'X-Stainless-Runtime-Version': string;
645
737
  };
646
738
  const getPlatformProperties = (): PlatformProperties => {
@@ -675,7 +767,20 @@ const getPlatformProperties = (): PlatformProperties => {
675
767
  'X-Stainless-Runtime-Version': process.version,
676
768
  };
677
769
  }
678
- // TODO add support for Cloudflare workers, browsers, etc.
770
+
771
+ const browserInfo = getBrowserInfo();
772
+ if (browserInfo) {
773
+ return {
774
+ 'X-Stainless-Lang': 'js',
775
+ 'X-Stainless-Package-Version': VERSION,
776
+ 'X-Stainless-OS': 'Unknown',
777
+ 'X-Stainless-Arch': 'unknown',
778
+ 'X-Stainless-Runtime': `browser:${browserInfo.browser}`,
779
+ 'X-Stainless-Runtime-Version': browserInfo.version,
780
+ };
781
+ }
782
+
783
+ // TODO add support for Cloudflare workers, etc.
679
784
  return {
680
785
  'X-Stainless-Lang': 'js',
681
786
  'X-Stainless-Package-Version': VERSION,
@@ -686,6 +791,44 @@ const getPlatformProperties = (): PlatformProperties => {
686
791
  };
687
792
  };
688
793
 
794
+ type BrowserInfo = {
795
+ browser: Browser;
796
+ version: string;
797
+ };
798
+
799
+ declare const navigator: { userAgent: string } | undefined;
800
+
801
+ // Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts
802
+ function getBrowserInfo(): BrowserInfo | null {
803
+ if (!navigator || typeof navigator === 'undefined') {
804
+ return null;
805
+ }
806
+
807
+ // NOTE: The order matters here!
808
+ const browserPatterns = [
809
+ { key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
810
+ { key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
811
+ { key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ },
812
+ { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
813
+ { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
814
+ { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ },
815
+ ];
816
+
817
+ // Find the FIRST matching browser
818
+ for (const { key, pattern } of browserPatterns) {
819
+ const match = pattern.exec(navigator.userAgent);
820
+ if (match) {
821
+ const major = match[1] || 0;
822
+ const minor = match[2] || 0;
823
+ const patch = match[3] || 0;
824
+
825
+ return { browser: key, version: `${major}.${minor}.${patch}` };
826
+ }
827
+ }
828
+
829
+ return null;
830
+ }
831
+
689
832
  const normalizeArch = (arch: string): Arch => {
690
833
  // Node docs:
691
834
  // - https://nodejs.org/api/process.html#processarch
@@ -767,14 +910,16 @@ export const ensurePresent = <T>(value: T | null | undefined): T => {
767
910
  /**
768
911
  * Read an environment variable.
769
912
  *
770
- * Will return an empty string if the environment variable doesn't exist or cannot be accessed.
913
+ * Will return undefined if the environment variable doesn't exist or cannot be accessed.
771
914
  */
772
915
  export const readEnv = (env: string): string | undefined => {
773
- if (typeof process === 'undefined') {
774
- return undefined;
916
+ if (typeof process !== 'undefined') {
917
+ return process.env?.[env] ?? undefined;
775
918
  }
776
-
777
- return process.env[env] ?? undefined;
919
+ if (typeof Deno !== 'undefined') {
920
+ return Deno.env?.get?.(env);
921
+ }
922
+ return undefined;
778
923
  };
779
924
 
780
925
  export const coerceInteger = (value: unknown): number => {
@@ -830,6 +975,12 @@ export function hasOwn(obj: Object, key: string): boolean {
830
975
  return Object.prototype.hasOwnProperty.call(obj, key);
831
976
  }
832
977
 
978
+ export function debug(action: string, ...args: any[]) {
979
+ if (typeof process !== 'undefined' && process.env['DEBUG'] === 'true') {
980
+ console.log(`Anthropic:DEBUG:${action}`, ...args);
981
+ }
982
+ }
983
+
833
984
  /**
834
985
  * https://stackoverflow.com/a/2117523
835
986
  */
@@ -841,6 +992,17 @@ const uuid4 = () => {
841
992
  });
842
993
  };
843
994
 
995
+ export const isRunningInBrowser = () => {
996
+ return (
997
+ // @ts-ignore
998
+ typeof window !== 'undefined' &&
999
+ // @ts-ignore
1000
+ typeof window.document !== 'undefined' &&
1001
+ // @ts-ignore
1002
+ typeof navigator !== 'undefined'
1003
+ );
1004
+ };
1005
+
844
1006
  export interface HeadersProtocol {
845
1007
  get: (header: string) => string | null | undefined;
846
1008
  }
package/src/index.ts CHANGED
@@ -209,6 +209,8 @@ export namespace Anthropic {
209
209
  export import Completions = API.Completions;
210
210
  export import Completion = API.Completion;
211
211
  export import CompletionCreateParams = API.CompletionCreateParams;
212
+ export import CompletionCreateParamsNonStreaming = API.CompletionCreateParamsNonStreaming;
213
+ export import CompletionCreateParamsStreaming = API.CompletionCreateParamsStreaming;
212
214
  }
213
215
 
214
216
  export default Anthropic;