@anthropic-ai/sdk 0.68.0 → 0.70.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 (124) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/client.d.mts +13 -3
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +13 -3
  5. package/client.d.ts.map +1 -1
  6. package/client.js +4 -1
  7. package/client.js.map +1 -1
  8. package/client.mjs +4 -1
  9. package/client.mjs.map +1 -1
  10. package/helpers/beta/json-schema.d.mts +12 -0
  11. package/helpers/beta/json-schema.d.mts.map +1 -1
  12. package/helpers/beta/json-schema.d.ts +12 -0
  13. package/helpers/beta/json-schema.d.ts.map +1 -1
  14. package/helpers/beta/json-schema.js +34 -0
  15. package/helpers/beta/json-schema.js.map +1 -1
  16. package/helpers/beta/json-schema.mjs +33 -0
  17. package/helpers/beta/json-schema.mjs.map +1 -1
  18. package/helpers/beta/zod.d.mts +13 -2
  19. package/helpers/beta/zod.d.mts.map +1 -1
  20. package/helpers/beta/zod.d.ts +13 -2
  21. package/helpers/beta/zod.d.ts.map +1 -1
  22. package/helpers/beta/zod.js +30 -1
  23. package/helpers/beta/zod.js.map +1 -1
  24. package/helpers/beta/zod.mjs +29 -1
  25. package/helpers/beta/zod.mjs.map +1 -1
  26. package/internal/types.d.mts +4 -4
  27. package/internal/types.d.mts.map +1 -1
  28. package/internal/types.d.ts +4 -4
  29. package/internal/types.d.ts.map +1 -1
  30. package/internal/utils/values.d.mts +1 -0
  31. package/internal/utils/values.d.mts.map +1 -1
  32. package/internal/utils/values.d.ts +1 -0
  33. package/internal/utils/values.d.ts.map +1 -1
  34. package/internal/utils/values.js +8 -1
  35. package/internal/utils/values.js.map +1 -1
  36. package/internal/utils/values.mjs +6 -0
  37. package/internal/utils/values.mjs.map +1 -1
  38. package/lib/BetaMessageStream.d.mts +11 -9
  39. package/lib/BetaMessageStream.d.mts.map +1 -1
  40. package/lib/BetaMessageStream.d.ts +11 -9
  41. package/lib/BetaMessageStream.d.ts.map +1 -1
  42. package/lib/BetaMessageStream.js +14 -9
  43. package/lib/BetaMessageStream.js.map +1 -1
  44. package/lib/BetaMessageStream.mjs +14 -9
  45. package/lib/BetaMessageStream.mjs.map +1 -1
  46. package/lib/beta-parser.d.mts +22 -0
  47. package/lib/beta-parser.d.mts.map +1 -0
  48. package/lib/beta-parser.d.ts +22 -0
  49. package/lib/beta-parser.d.ts.map +1 -0
  50. package/lib/beta-parser.js +59 -0
  51. package/lib/beta-parser.js.map +1 -0
  52. package/lib/beta-parser.mjs +55 -0
  53. package/lib/beta-parser.mjs.map +1 -0
  54. package/lib/transform-json-schema.d.mts +3 -0
  55. package/lib/transform-json-schema.d.mts.map +1 -0
  56. package/lib/transform-json-schema.d.ts +3 -0
  57. package/lib/transform-json-schema.d.ts.map +1 -0
  58. package/lib/transform-json-schema.js +114 -0
  59. package/lib/transform-json-schema.js.map +1 -0
  60. package/lib/transform-json-schema.mjs +111 -0
  61. package/lib/transform-json-schema.mjs.map +1 -0
  62. package/package.json +1 -1
  63. package/resources/beta/beta.d.mts +2 -2
  64. package/resources/beta/beta.d.mts.map +1 -1
  65. package/resources/beta/beta.d.ts +2 -2
  66. package/resources/beta/beta.d.ts.map +1 -1
  67. package/resources/beta/beta.js.map +1 -1
  68. package/resources/beta/beta.mjs.map +1 -1
  69. package/resources/beta/index.d.mts +1 -1
  70. package/resources/beta/index.d.mts.map +1 -1
  71. package/resources/beta/index.d.ts +1 -1
  72. package/resources/beta/index.d.ts.map +1 -1
  73. package/resources/beta/index.js.map +1 -1
  74. package/resources/beta/index.mjs.map +1 -1
  75. package/resources/beta/messages/batches.d.mts +6 -6
  76. package/resources/beta/messages/batches.d.ts +6 -6
  77. package/resources/beta/messages/batches.js +6 -6
  78. package/resources/beta/messages/batches.mjs +6 -6
  79. package/resources/beta/messages/index.d.mts +1 -1
  80. package/resources/beta/messages/index.d.mts.map +1 -1
  81. package/resources/beta/messages/index.d.ts +1 -1
  82. package/resources/beta/messages/index.d.ts.map +1 -1
  83. package/resources/beta/messages/index.js.map +1 -1
  84. package/resources/beta/messages/index.mjs.map +1 -1
  85. package/resources/beta/messages/messages.d.mts +60 -10
  86. package/resources/beta/messages/messages.d.mts.map +1 -1
  87. package/resources/beta/messages/messages.d.ts +60 -10
  88. package/resources/beta/messages/messages.d.ts.map +1 -1
  89. package/resources/beta/messages/messages.js +31 -4
  90. package/resources/beta/messages/messages.js.map +1 -1
  91. package/resources/beta/messages/messages.mjs +31 -4
  92. package/resources/beta/messages/messages.mjs.map +1 -1
  93. package/resources/messages/batches.d.mts +6 -6
  94. package/resources/messages/batches.d.ts +6 -6
  95. package/resources/messages/batches.js +6 -6
  96. package/resources/messages/batches.mjs +6 -6
  97. package/resources/messages/messages.d.mts +3 -2
  98. package/resources/messages/messages.d.mts.map +1 -1
  99. package/resources/messages/messages.d.ts +3 -2
  100. package/resources/messages/messages.d.ts.map +1 -1
  101. package/resources/messages/messages.js +1 -1
  102. package/resources/messages/messages.js.map +1 -1
  103. package/resources/messages/messages.mjs +1 -1
  104. package/resources/messages/messages.mjs.map +1 -1
  105. package/src/client.ts +20 -4
  106. package/src/helpers/beta/json-schema.ts +43 -0
  107. package/src/helpers/beta/zod.ts +40 -3
  108. package/src/internal/types.ts +4 -4
  109. package/src/internal/utils/values.ts +7 -0
  110. package/src/lib/BetaMessageStream.ts +32 -25
  111. package/src/lib/beta-parser.ts +105 -0
  112. package/src/lib/transform-json-schema.ts +124 -0
  113. package/src/resources/beta/beta.ts +2 -0
  114. package/src/resources/beta/index.ts +1 -0
  115. package/src/resources/beta/messages/batches.ts +6 -6
  116. package/src/resources/beta/messages/index.ts +1 -0
  117. package/src/resources/beta/messages/messages.ts +108 -18
  118. package/src/resources/messages/batches.ts +6 -6
  119. package/src/resources/messages/messages.ts +3 -2
  120. package/src/version.ts +1 -1
  121. package/version.d.mts +1 -1
  122. package/version.d.ts +1 -1
  123. package/version.js +1 -1
  124. package/version.mjs +1 -1
@@ -64,15 +64,15 @@ type OverloadedParameters<T> =
64
64
  * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition
65
65
  */
66
66
  /** @ts-ignore For users with \@types/node */
67
- type UndiciTypesRequestInit = NotAny<import('../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit>;
67
+ type UndiciTypesRequestInit = NotAny<import('undici-types').RequestInit> | NotAny<import('undici-types').RequestInit> | NotAny<import('../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit>;
68
68
  /** @ts-ignore For users with undici */
69
- type UndiciRequestInit = NotAny<import('../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici/index.d.ts').RequestInit>;
69
+ type UndiciRequestInit = NotAny<import('undici').RequestInit> | NotAny<import('undici').RequestInit> | NotAny<import('../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici/index.d.ts').RequestInit>;
70
70
  /** @ts-ignore For users with \@types/bun */
71
71
  type BunRequestInit = globalThis.FetchRequestInit;
72
72
  /** @ts-ignore For users with node-fetch@2 */
73
- type NodeFetch2RequestInit = NotAny<import('../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit>;
73
+ type NodeFetch2RequestInit = NotAny<import('node-fetch').RequestInit> | NotAny<import('node-fetch').RequestInit> | NotAny<import('../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit>;
74
74
  /** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */
75
- type NodeFetch3RequestInit = NotAny<import('../node_modules/node-fetch').RequestInit> | NotAny<import('../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/node-fetch').RequestInit>;
75
+ type NodeFetch3RequestInit = NotAny<import('node-fetch.js').RequestInit> | NotAny<import('node-fetch.js').RequestInit> | NotAny<import('../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/node-fetch').RequestInit>;
76
76
  /** @ts-ignore For users who use Deno */
77
77
  type FetchRequestInit = NonNullable<OverloadedParameters<typeof fetch>[1]>;
78
78
  /* eslint-enable */
@@ -103,3 +103,10 @@ export const safeJSON = (text: string) => {
103
103
  return undefined;
104
104
  }
105
105
  };
106
+
107
+ // Gets a value from an object, deletes the key, and returns the value (or undefined if not found)
108
+ export const pop = <T extends Record<string, any>, K extends string>(obj: T, key: K): T[K] => {
109
+ const value = obj[key];
110
+ delete obj[key];
111
+ return value;
112
+ };
@@ -1,22 +1,24 @@
1
- import { isAbortError } from '../internal/errors';
1
+ import { partialParse } from '../_vendor/partial-json-parser/parser';
2
2
  import { AnthropicError, APIUserAbortError } from '../error';
3
+ import { isAbortError } from '../internal/errors';
4
+ import { type RequestOptions } from '../internal/request-options';
3
5
  import {
4
6
  type BetaContentBlock,
5
- Messages as BetaMessages,
7
+ type BetaMCPToolUseBlock,
6
8
  type BetaMessage,
7
- type BetaRawMessageStreamEvent as BetaMessageStreamEvent,
8
9
  type BetaMessageParam,
9
- type MessageCreateParams as BetaMessageCreateParams,
10
- type MessageCreateParamsBase as BetaMessageCreateParamsBase,
10
+ Messages as BetaMessages,
11
+ type BetaRawMessageStreamEvent as BetaMessageStreamEvent,
12
+ type BetaServerToolUseBlock,
11
13
  type BetaTextBlock,
12
14
  type BetaTextCitation,
13
15
  type BetaToolUseBlock,
14
- type BetaServerToolUseBlock,
15
- type BetaMCPToolUseBlock,
16
+ type MessageCreateParams,
17
+ type MessageCreateParamsBase,
18
+ MessageCreateParamsStreaming,
16
19
  } from '../resources/beta/messages/messages';
17
20
  import { Stream } from '../streaming';
18
- import { partialParse } from '../_vendor/partial-json-parser/parser';
19
- import { type RequestOptions } from '../internal/request-options';
21
+ import { maybeParseBetaMessage, type ParsedBetaMessage } from './beta-parser';
20
22
 
21
23
  export interface MessageStreamEvents {
22
24
  connect: () => void;
@@ -47,10 +49,11 @@ function tracksToolInput(content: BetaContentBlock): content is TracksToolInput
47
49
  return content.type === 'tool_use' || content.type === 'server_tool_use' || content.type === 'mcp_tool_use';
48
50
  }
49
51
 
50
- export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent> {
52
+ export class BetaMessageStream<ParsedT = null> implements AsyncIterable<BetaMessageStreamEvent> {
51
53
  messages: BetaMessageParam[] = [];
52
- receivedMessages: BetaMessage[] = [];
54
+ receivedMessages: ParsedBetaMessage<ParsedT>[] = [];
53
55
  #currentMessageSnapshot: BetaMessage | undefined;
56
+ #params: MessageCreateParams | null = null;
54
57
 
55
58
  controller: AbortController = new AbortController();
56
59
 
@@ -71,7 +74,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
71
74
  #response: Response | null | undefined;
72
75
  #request_id: string | null | undefined;
73
76
 
74
- constructor() {
77
+ constructor(params: MessageCreateParamsBase | null) {
75
78
  this.#connectedPromise = new Promise<Response | null>((resolve, reject) => {
76
79
  this.#resolveConnectedPromise = resolve;
77
80
  this.#rejectConnectedPromise = reject;
@@ -88,6 +91,8 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
88
91
  // any promise-returning method.
89
92
  this.#connectedPromise.catch(() => {});
90
93
  this.#endPromise.catch(() => {});
94
+
95
+ this.#params = params;
91
96
  }
92
97
 
93
98
  get response(): Response | null | undefined {
@@ -109,7 +114,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
109
114
  * as no `Response` is available.
110
115
  */
111
116
  async withResponse(): Promise<{
112
- data: BetaMessageStream;
117
+ data: BetaMessageStream<ParsedT>;
113
118
  response: Response;
114
119
  request_id: string | null | undefined;
115
120
  }> {
@@ -133,20 +138,21 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
133
138
  * in this context.
134
139
  */
135
140
  static fromReadableStream(stream: ReadableStream): BetaMessageStream {
136
- const runner = new BetaMessageStream();
141
+ const runner = new BetaMessageStream(null);
137
142
  runner._run(() => runner._fromReadableStream(stream));
138
143
  return runner;
139
144
  }
140
145
 
141
- static createMessage(
146
+ static createMessage<ParsedT>(
142
147
  messages: BetaMessages,
143
- params: BetaMessageCreateParamsBase,
148
+ params: MessageCreateParamsBase,
144
149
  options?: RequestOptions,
145
- ): BetaMessageStream {
146
- const runner = new BetaMessageStream();
150
+ ): BetaMessageStream<ParsedT> {
151
+ const runner = new BetaMessageStream<ParsedT>(params as MessageCreateParamsStreaming);
147
152
  for (const message of params.messages) {
148
153
  runner._addMessageParam(message);
149
154
  }
155
+ runner.#params = { ...params, stream: true };
150
156
  runner._run(() =>
151
157
  runner._createMessage(
152
158
  messages,
@@ -168,7 +174,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
168
174
  this.messages.push(message);
169
175
  }
170
176
 
171
- protected _addMessage(message: BetaMessage, emit = true) {
177
+ protected _addMessage(message: ParsedBetaMessage<ParsedT>, emit = true) {
172
178
  this.receivedMessages.push(message);
173
179
  if (emit) {
174
180
  this._emit('message', message);
@@ -177,7 +183,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
177
183
 
178
184
  protected async _createMessage(
179
185
  messages: BetaMessages,
180
- params: BetaMessageCreateParams,
186
+ params: MessageCreateParams,
181
187
  options?: RequestOptions,
182
188
  ): Promise<void> {
183
189
  const signal = options?.signal;
@@ -306,7 +312,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
306
312
  return this.#currentMessageSnapshot;
307
313
  }
308
314
 
309
- #getFinalMessage(): BetaMessage {
315
+ #getFinalMessage(): ParsedBetaMessage<ParsedT> {
310
316
  if (this.receivedMessages.length === 0) {
311
317
  throw new AnthropicError('stream ended without producing a Message with role=assistant');
312
318
  }
@@ -316,8 +322,9 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
316
322
  /**
317
323
  * @returns a promise that resolves with the the final assistant Message response,
318
324
  * or rejects if an error occurred or the stream ended prematurely without producing a Message.
325
+ * If structured outputs were used, this will be a ParsedMessage with a `parsed` field.
319
326
  */
320
- async finalMessage(): Promise<BetaMessage> {
327
+ async finalMessage(): Promise<ParsedBetaMessage<ParsedT>> {
321
328
  await this.done();
322
329
  return this.#getFinalMessage();
323
330
  }
@@ -472,7 +479,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
472
479
  }
473
480
  case 'message_stop': {
474
481
  this._addMessageParam(messageSnapshot);
475
- this._addMessage(messageSnapshot, true);
482
+ this._addMessage(maybeParseBetaMessage(messageSnapshot, this.#params), true);
476
483
  break;
477
484
  }
478
485
  case 'content_block_stop': {
@@ -488,7 +495,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
488
495
  break;
489
496
  }
490
497
  }
491
- #endRequest(): BetaMessage {
498
+ #endRequest(): ParsedBetaMessage<ParsedT> {
492
499
  if (this.ended) {
493
500
  throw new AnthropicError(`stream has ended, this shouldn't happen`);
494
501
  }
@@ -497,7 +504,7 @@ export class BetaMessageStream implements AsyncIterable<BetaMessageStreamEvent>
497
504
  throw new AnthropicError(`request ended without sending any chunks`);
498
505
  }
499
506
  this.#currentMessageSnapshot = undefined;
500
- return snapshot;
507
+ return maybeParseBetaMessage(snapshot, this.#params);
501
508
  }
502
509
 
503
510
  protected async _fromReadableStream(
@@ -0,0 +1,105 @@
1
+ import { AnthropicError } from '../core/error';
2
+ import {
3
+ BetaContentBlock,
4
+ BetaJSONOutputFormat,
5
+ BetaMessage,
6
+ BetaTextBlock,
7
+ MessageCreateParams,
8
+ } from '../resources/beta/messages/messages';
9
+
10
+ // vendored from typefest just to make things look a bit nicer on hover
11
+ type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
12
+
13
+ export type BetaParseableMessageCreateParams = Simplify<
14
+ Omit<MessageCreateParams, 'output_format'> & {
15
+ output_format?: BetaJSONOutputFormat | AutoParseableBetaOutputFormat<any> | null;
16
+ }
17
+ >;
18
+
19
+ export type ExtractParsedContentFromBetaParams<Params extends BetaParseableMessageCreateParams> =
20
+ Params['output_format'] extends AutoParseableBetaOutputFormat<infer P> ? P : null;
21
+
22
+ export type AutoParseableBetaOutputFormat<ParsedT> = BetaJSONOutputFormat & {
23
+ parse(content: string): ParsedT;
24
+ };
25
+
26
+ export type ParsedBetaMessage<ParsedT> = BetaMessage & {
27
+ content: Array<ParsedBetaContentBlock<ParsedT>>;
28
+ parsed_output: ParsedT | null;
29
+ };
30
+
31
+ export type ParsedBetaContentBlock<ParsedT> =
32
+ | (BetaTextBlock & { parsed: ParsedT | null })
33
+ | Exclude<BetaContentBlock, BetaTextBlock>;
34
+
35
+ export function maybeParseBetaMessage<Params extends BetaParseableMessageCreateParams | null>(
36
+ message: BetaMessage,
37
+ params: Params,
38
+ ): ParsedBetaMessage<ExtractParsedContentFromBetaParams<NonNullable<Params>>> {
39
+ if (!params || !('parse' in (params.output_format ?? {}))) {
40
+ return {
41
+ ...message,
42
+ content: message.content.map((block) => {
43
+ if (block.type === 'text') {
44
+ return {
45
+ ...block,
46
+ parsed: null,
47
+ };
48
+ }
49
+ return block;
50
+ }),
51
+ parsed_output: null,
52
+ } as ParsedBetaMessage<ExtractParsedContentFromBetaParams<NonNullable<Params>>>;
53
+ }
54
+
55
+ return parseBetaMessage(message, params);
56
+ }
57
+
58
+ export function parseBetaMessage<Params extends BetaParseableMessageCreateParams>(
59
+ message: BetaMessage,
60
+ params: Params,
61
+ ): ParsedBetaMessage<ExtractParsedContentFromBetaParams<Params>> {
62
+ let firstParsed: ReturnType<typeof parseBetaOutputFormat<Params>> | null = null;
63
+
64
+ const content: Array<ParsedBetaContentBlock<ExtractParsedContentFromBetaParams<Params>>> =
65
+ message.content.map((block) => {
66
+ if (block.type === 'text') {
67
+ const parsed = parseBetaOutputFormat(params, block.text);
68
+
69
+ if (firstParsed === null) {
70
+ firstParsed = parsed;
71
+ }
72
+
73
+ return {
74
+ ...block,
75
+ parsed,
76
+ };
77
+ }
78
+ return block;
79
+ });
80
+
81
+ return {
82
+ ...message,
83
+ content,
84
+ parsed_output: firstParsed,
85
+ } as ParsedBetaMessage<ExtractParsedContentFromBetaParams<Params>>;
86
+ }
87
+
88
+ function parseBetaOutputFormat<Params extends BetaParseableMessageCreateParams>(
89
+ params: Params,
90
+ content: string,
91
+ ): ExtractParsedContentFromBetaParams<Params> | null {
92
+ if (params.output_format?.type !== 'json_schema') {
93
+ return null;
94
+ }
95
+
96
+ try {
97
+ if ('parse' in params.output_format) {
98
+ return params.output_format.parse(content);
99
+ }
100
+
101
+ return JSON.parse(content);
102
+ } catch (error) {
103
+ throw new AnthropicError(`Failed to parse structured output: ${error}`);
104
+ }
105
+ }
@@ -0,0 +1,124 @@
1
+ import { pop } from '../internal/utils';
2
+
3
+ // Supported string formats
4
+ const SUPPORTED_STRING_FORMATS = new Set([
5
+ 'date-time',
6
+ 'time',
7
+ 'date',
8
+ 'duration',
9
+ 'email',
10
+ 'hostname',
11
+ 'uri',
12
+ 'ipv4',
13
+ 'ipv6',
14
+ 'uuid',
15
+ ]);
16
+
17
+ export type JSONSchema = Record<string, any>;
18
+
19
+ function deepClone<T>(obj: T): T {
20
+ return JSON.parse(JSON.stringify(obj));
21
+ }
22
+
23
+ export function transformJSONSchema(jsonSchema: JSONSchema): JSONSchema {
24
+ const workingCopy = deepClone(jsonSchema);
25
+ return _transformJSONSchema(workingCopy);
26
+ }
27
+
28
+ function _transformJSONSchema(jsonSchema: JSONSchema): JSONSchema {
29
+ const strictSchema: JSONSchema = {};
30
+
31
+ const ref = pop(jsonSchema, '$ref');
32
+ if (ref !== undefined) {
33
+ strictSchema['$ref'] = ref;
34
+ return strictSchema;
35
+ }
36
+
37
+ const defs = pop(jsonSchema, '$defs');
38
+ if (defs !== undefined) {
39
+ const strictDefs: Record<string, any> = {};
40
+ strictSchema['$defs'] = strictDefs;
41
+ for (const [name, defSchema] of Object.entries(defs)) {
42
+ strictDefs[name] = _transformJSONSchema(defSchema as JSONSchema);
43
+ }
44
+ }
45
+
46
+ const type = pop(jsonSchema, 'type');
47
+ const anyOf = pop(jsonSchema, 'anyOf');
48
+ const oneOf = pop(jsonSchema, 'oneOf');
49
+ const allOf = pop(jsonSchema, 'allOf');
50
+
51
+ if (Array.isArray(anyOf)) {
52
+ strictSchema['anyOf'] = anyOf.map((variant) => _transformJSONSchema(variant as JSONSchema));
53
+ } else if (Array.isArray(oneOf)) {
54
+ strictSchema['anyOf'] = oneOf.map((variant) => _transformJSONSchema(variant as JSONSchema));
55
+ } else if (Array.isArray(allOf)) {
56
+ strictSchema['allOf'] = allOf.map((entry) => _transformJSONSchema(entry as JSONSchema));
57
+ } else {
58
+ if (type === undefined) {
59
+ throw new Error('JSON schema must have a type defined if anyOf/oneOf/allOf are not used');
60
+ }
61
+ strictSchema['type'] = type;
62
+ }
63
+
64
+ const description = pop(jsonSchema, 'description');
65
+ if (description !== undefined) {
66
+ strictSchema['description'] = description;
67
+ }
68
+
69
+ const title = pop(jsonSchema, 'title');
70
+ if (title !== undefined) {
71
+ strictSchema['title'] = title;
72
+ }
73
+
74
+ if (type === 'object') {
75
+ const properties = pop(jsonSchema, 'properties') || {};
76
+
77
+ strictSchema['properties'] = Object.fromEntries(
78
+ Object.entries(properties).map(([key, propSchema]) => [
79
+ key,
80
+ _transformJSONSchema(propSchema as JSONSchema),
81
+ ]),
82
+ );
83
+
84
+ pop(jsonSchema, 'additionalProperties');
85
+ strictSchema['additionalProperties'] = false;
86
+
87
+ const required = pop(jsonSchema, 'required');
88
+ if (required !== undefined) {
89
+ strictSchema['required'] = required;
90
+ }
91
+ } else if (type === 'string') {
92
+ const format = pop(jsonSchema, 'format');
93
+ if (format !== undefined && SUPPORTED_STRING_FORMATS.has(format)) {
94
+ strictSchema['format'] = format;
95
+ } else if (format !== undefined) {
96
+ jsonSchema['format'] = format;
97
+ }
98
+ } else if (type === 'array') {
99
+ const items = pop(jsonSchema, 'items');
100
+ if (items !== undefined) {
101
+ strictSchema['items'] = _transformJSONSchema(items as JSONSchema);
102
+ }
103
+
104
+ const minItems = pop(jsonSchema, 'minItems');
105
+ if (minItems !== undefined && (minItems === 0 || minItems === 1)) {
106
+ strictSchema['minItems'] = minItems;
107
+ } else if (minItems !== undefined) {
108
+ jsonSchema['minItems'] = minItems;
109
+ }
110
+ }
111
+
112
+ if (Object.keys(jsonSchema).length > 0) {
113
+ const existingDescription = strictSchema['description'];
114
+ strictSchema['description'] =
115
+ (existingDescription ? existingDescription + '\n\n' : '') +
116
+ '{' +
117
+ Object.entries(jsonSchema)
118
+ .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
119
+ .join(', ') +
120
+ '}';
121
+ }
122
+
123
+ return strictSchema;
124
+ }
@@ -77,6 +77,7 @@ import {
77
77
  BetaFileImageSource,
78
78
  BetaImageBlockParam,
79
79
  BetaInputJSONDelta,
80
+ BetaJSONOutputFormat,
80
81
  BetaInputTokensClearAtLeast,
81
82
  BetaInputTokensTrigger,
82
83
  BetaMCPToolResultBlock,
@@ -393,6 +394,7 @@ export declare namespace Beta {
393
394
  type BetaFileImageSource as BetaFileImageSource,
394
395
  type BetaImageBlockParam as BetaImageBlockParam,
395
396
  type BetaInputJSONDelta as BetaInputJSONDelta,
397
+ type BetaJSONOutputFormat as BetaJSONOutputFormat,
396
398
  type BetaInputTokensClearAtLeast as BetaInputTokensClearAtLeast,
397
399
  type BetaInputTokensTrigger as BetaInputTokensTrigger,
398
400
  type BetaMCPToolResultBlock as BetaMCPToolResultBlock,
@@ -87,6 +87,7 @@ export {
87
87
  type BetaFileImageSource,
88
88
  type BetaImageBlockParam,
89
89
  type BetaInputJSONDelta,
90
+ type BetaJSONOutputFormat,
90
91
  type BetaInputTokensClearAtLeast,
91
92
  type BetaInputTokensTrigger,
92
93
  type BetaMCPToolResultBlock,
@@ -20,7 +20,7 @@ export class Batches extends APIResource {
20
20
  * can take up to 24 hours to complete.
21
21
  *
22
22
  * Learn more about the Message Batches API in our
23
- * [user guide](/en/docs/build-with-claude/batch-processing)
23
+ * [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
24
24
  *
25
25
  * @example
26
26
  * ```ts
@@ -59,7 +59,7 @@ export class Batches extends APIResource {
59
59
  * `results_url` field in the response.
60
60
  *
61
61
  * Learn more about the Message Batches API in our
62
- * [user guide](/en/docs/build-with-claude/batch-processing)
62
+ * [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
63
63
  *
64
64
  * @example
65
65
  * ```ts
@@ -89,7 +89,7 @@ export class Batches extends APIResource {
89
89
  * returned first.
90
90
  *
91
91
  * Learn more about the Message Batches API in our
92
- * [user guide](/en/docs/build-with-claude/batch-processing)
92
+ * [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
93
93
  *
94
94
  * @example
95
95
  * ```ts
@@ -121,7 +121,7 @@ export class Batches extends APIResource {
121
121
  * like to delete an in-progress batch, you must first cancel it.
122
122
  *
123
123
  * Learn more about the Message Batches API in our
124
- * [user guide](/en/docs/build-with-claude/batch-processing)
124
+ * [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
125
125
  *
126
126
  * @example
127
127
  * ```ts
@@ -158,7 +158,7 @@ export class Batches extends APIResource {
158
158
  * non-interruptible.
159
159
  *
160
160
  * Learn more about the Message Batches API in our
161
- * [user guide](/en/docs/build-with-claude/batch-processing)
161
+ * [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
162
162
  *
163
163
  * @example
164
164
  * ```ts
@@ -191,7 +191,7 @@ export class Batches extends APIResource {
191
191
  * requests. Use the `custom_id` field to match results to requests.
192
192
  *
193
193
  * Learn more about the Message Batches API in our
194
- * [user guide](/en/docs/build-with-claude/batch-processing)
194
+ * [user guide](https://docs.claude.com/en/docs/build-with-claude/batch-processing)
195
195
  *
196
196
  * @example
197
197
  * ```ts
@@ -80,6 +80,7 @@ export {
80
80
  type BetaFileImageSource,
81
81
  type BetaImageBlockParam,
82
82
  type BetaInputJSONDelta,
83
+ type BetaJSONOutputFormat,
83
84
  type BetaInputTokensClearAtLeast,
84
85
  type BetaInputTokensTrigger,
85
86
  type BetaMCPToolResultBlock,