anthropic 1.16.2 → 1.17.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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +38 -10
  4. data/lib/anthropic/helpers/messages.rb +87 -2
  5. data/lib/anthropic/helpers/streaming/message_stream.rb +54 -29
  6. data/lib/anthropic/models/beta/beta_code_execution_tool_20250522.rb +2 -1
  7. data/lib/anthropic/models/beta/beta_code_execution_tool_20250825.rb +2 -1
  8. data/lib/anthropic/models/beta/beta_memory_tool_20250818.rb +2 -1
  9. data/lib/anthropic/models/beta/beta_output_config.rb +22 -4
  10. data/lib/anthropic/models/beta/beta_server_tool_use_block.rb +25 -25
  11. data/lib/anthropic/models/beta/beta_tool.rb +2 -1
  12. data/lib/anthropic/models/beta/beta_tool_bash_20241022.rb +2 -1
  13. data/lib/anthropic/models/beta/beta_tool_bash_20250124.rb +2 -1
  14. data/lib/anthropic/models/beta/beta_tool_computer_use_20241022.rb +2 -1
  15. data/lib/anthropic/models/beta/beta_tool_computer_use_20250124.rb +2 -1
  16. data/lib/anthropic/models/beta/beta_tool_computer_use_20251124.rb +2 -1
  17. data/lib/anthropic/models/beta/beta_tool_search_tool_bm25_20251119.rb +2 -1
  18. data/lib/anthropic/models/beta/beta_tool_search_tool_regex_20251119.rb +2 -1
  19. data/lib/anthropic/models/beta/beta_tool_text_editor_20241022.rb +2 -1
  20. data/lib/anthropic/models/beta/beta_tool_text_editor_20250124.rb +2 -1
  21. data/lib/anthropic/models/beta/beta_tool_text_editor_20250429.rb +2 -1
  22. data/lib/anthropic/models/beta/beta_tool_text_editor_20250728.rb +2 -1
  23. data/lib/anthropic/models/beta/beta_web_fetch_tool_20250910.rb +2 -1
  24. data/lib/anthropic/models/beta/beta_web_search_tool_20250305.rb +2 -1
  25. data/lib/anthropic/models/beta/beta_web_search_tool_result_error_code.rb +1 -0
  26. data/lib/anthropic/models/beta/message_count_tokens_params.rb +10 -5
  27. data/lib/anthropic/models/beta/message_create_params.rb +10 -5
  28. data/lib/anthropic/models/beta/messages/batch_create_params.rb +10 -5
  29. data/lib/anthropic/models/json_output_format.rb +23 -0
  30. data/lib/anthropic/models/message.rb +12 -0
  31. data/lib/anthropic/models/message_count_tokens_params.rb +9 -1
  32. data/lib/anthropic/models/message_create_params.rb +9 -1
  33. data/lib/anthropic/models/messages/batch_create_params.rb +9 -1
  34. data/lib/anthropic/models/model.rb +6 -0
  35. data/lib/anthropic/models/output_config.rb +20 -0
  36. data/lib/anthropic/models/text_block.rb +8 -0
  37. data/lib/anthropic/models/tool.rb +9 -1
  38. data/lib/anthropic/models/tool_bash_20250124.rb +9 -1
  39. data/lib/anthropic/models/tool_text_editor_20250124.rb +9 -1
  40. data/lib/anthropic/models/tool_text_editor_20250429.rb +9 -1
  41. data/lib/anthropic/models/tool_text_editor_20250728.rb +9 -1
  42. data/lib/anthropic/models/web_search_tool_20250305.rb +9 -1
  43. data/lib/anthropic/models/web_search_tool_request_error.rb +1 -0
  44. data/lib/anthropic/models/web_search_tool_result_error.rb +1 -0
  45. data/lib/anthropic/models.rb +4 -0
  46. data/lib/anthropic/resources/beta/messages.rb +26 -14
  47. data/lib/anthropic/resources/messages.rb +15 -4
  48. data/lib/anthropic/version.rb +1 -1
  49. data/lib/anthropic.rb +2 -0
  50. data/rbi/anthropic/models/beta/beta_code_execution_tool_20250522.rbi +2 -0
  51. data/rbi/anthropic/models/beta/beta_code_execution_tool_20250825.rbi +2 -0
  52. data/rbi/anthropic/models/beta/beta_memory_tool_20250818.rbi +2 -0
  53. data/rbi/anthropic/models/beta/beta_output_config.rbi +32 -6
  54. data/rbi/anthropic/models/beta/beta_server_tool_use_block.rbi +48 -36
  55. data/rbi/anthropic/models/beta/beta_tool.rbi +2 -0
  56. data/rbi/anthropic/models/beta/beta_tool_bash_20241022.rbi +2 -0
  57. data/rbi/anthropic/models/beta/beta_tool_bash_20250124.rbi +2 -0
  58. data/rbi/anthropic/models/beta/beta_tool_computer_use_20241022.rbi +2 -0
  59. data/rbi/anthropic/models/beta/beta_tool_computer_use_20250124.rbi +2 -0
  60. data/rbi/anthropic/models/beta/beta_tool_computer_use_20251124.rbi +2 -0
  61. data/rbi/anthropic/models/beta/beta_tool_search_tool_bm25_20251119.rbi +2 -0
  62. data/rbi/anthropic/models/beta/beta_tool_search_tool_regex_20251119.rbi +2 -0
  63. data/rbi/anthropic/models/beta/beta_tool_text_editor_20241022.rbi +2 -0
  64. data/rbi/anthropic/models/beta/beta_tool_text_editor_20250124.rbi +2 -0
  65. data/rbi/anthropic/models/beta/beta_tool_text_editor_20250429.rbi +2 -0
  66. data/rbi/anthropic/models/beta/beta_tool_text_editor_20250728.rbi +2 -0
  67. data/rbi/anthropic/models/beta/beta_web_fetch_tool_20250910.rbi +2 -0
  68. data/rbi/anthropic/models/beta/beta_web_search_tool_20250305.rbi +2 -0
  69. data/rbi/anthropic/models/beta/beta_web_search_tool_result_error_code.rbi +5 -0
  70. data/rbi/anthropic/models/beta/message_count_tokens_params.rbi +12 -6
  71. data/rbi/anthropic/models/beta/message_create_params.rbi +12 -6
  72. data/rbi/anthropic/models/beta/messages/batch_create_params.rbi +12 -6
  73. data/rbi/anthropic/models/json_output_format.rbi +37 -0
  74. data/rbi/anthropic/models/message.rbi +5 -0
  75. data/rbi/anthropic/models/message_count_tokens_params.rbi +11 -0
  76. data/rbi/anthropic/models/message_create_params.rbi +11 -0
  77. data/rbi/anthropic/models/messages/batch_create_params.rbi +11 -0
  78. data/rbi/anthropic/models/output_config.rbi +40 -0
  79. data/rbi/anthropic/models/tool.rbi +11 -0
  80. data/rbi/anthropic/models/tool_bash_20250124.rbi +12 -1
  81. data/rbi/anthropic/models/tool_text_editor_20250124.rbi +12 -1
  82. data/rbi/anthropic/models/tool_text_editor_20250429.rbi +12 -1
  83. data/rbi/anthropic/models/tool_text_editor_20250728.rbi +12 -1
  84. data/rbi/anthropic/models/web_search_tool_20250305.rbi +11 -0
  85. data/rbi/anthropic/models/web_search_tool_request_error.rbi +5 -0
  86. data/rbi/anthropic/models/web_search_tool_result_error.rbi +5 -0
  87. data/rbi/anthropic/models.rbi +4 -0
  88. data/rbi/anthropic/resources/beta/messages.rbi +21 -9
  89. data/rbi/anthropic/resources/messages.rbi +9 -0
  90. data/sig/anthropic/models/beta/beta_output_config.rbs +10 -3
  91. data/sig/anthropic/models/beta/beta_server_tool_use_block.rbs +21 -17
  92. data/sig/anthropic/models/beta/beta_web_search_tool_result_error_code.rbs +2 -0
  93. data/sig/anthropic/models/json_output_format.rbs +16 -0
  94. data/sig/anthropic/models/message_count_tokens_params.rbs +7 -0
  95. data/sig/anthropic/models/message_create_params.rbs +7 -0
  96. data/sig/anthropic/models/messages/batch_create_params.rbs +9 -0
  97. data/sig/anthropic/models/output_config.rbs +13 -0
  98. data/sig/anthropic/models/tool.rbs +7 -0
  99. data/sig/anthropic/models/tool_bash_20250124.rbs +9 -2
  100. data/sig/anthropic/models/tool_text_editor_20250124.rbs +9 -2
  101. data/sig/anthropic/models/tool_text_editor_20250429.rbs +9 -2
  102. data/sig/anthropic/models/tool_text_editor_20250728.rbs +9 -2
  103. data/sig/anthropic/models/web_search_tool_20250305.rbs +7 -0
  104. data/sig/anthropic/models/web_search_tool_request_error.rbs +2 -0
  105. data/sig/anthropic/models/web_search_tool_result_error.rbs +2 -0
  106. data/sig/anthropic/models.rbs +4 -0
  107. data/sig/anthropic/resources/messages.rbs +3 -0
  108. metadata +22 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f79aa8143b09a8650a0e0a6c0a779ac5e172b68e495f3891f670a5c4fb5f47d
4
- data.tar.gz: 80176ee66b3a15cd52163e81537501e024f2dd4afb9584ae0718bfb48b64514d
3
+ metadata.gz: 2a48217d29048fbc0ea335a5b04b3bec6e8756d529231a8772e226d9680c18ed
4
+ data.tar.gz: a526e4b123b10883760189437147958f1bfdcf0fcedc7fe6087339ebd1f8e04c
5
5
  SHA512:
6
- metadata.gz: 26965b0ee08e4d4438b51fb2c94bebb9197aaa8c84717c4640eddf30f768ba26e1ef35ae426bda9d60779907699adb284b51086eecc8a8af8f58a738fa6a9f25
7
- data.tar.gz: 6e7d9d37889bd28c4f75b0c3de756dde2de61764857a74022206620484b2296484483d23fbe1d4d13956c1bf2d2e6f67d7d73719254180adc1943e15532b1aed
6
+ metadata.gz: 17a4deb6105e189cd657e4f90b71a984cf01aab50448deaf80ac6e73cff38c2f038d346e669fdd00d5b44fe99d2f412dcdbfcbf7b0974828d54de954cb267086
7
+ data.tar.gz: 7d01b98fc7ae9247cc3b6de9055ef7e4ce3ae5c8e613bb5c87caf8fdc063d93922ee7c8e284503a38803dcd5f3e0ac2076227276bcbf3dfb378b66cec75dc259
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.17.0 (2026-01-29)
4
+
5
+ Full Changelog: [v1.16.3...v1.17.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.16.3...v1.17.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** add support for Structured Outputs in the Messages API ([06e1fd9](https://github.com/anthropics/anthropic-sdk-ruby/commit/06e1fd93f073462f887a933af1dbca17138980c7))
10
+ * **api:** migrate sending message format in output_config rather than output_format ([13ac36e](https://github.com/anthropics/anthropic-sdk-ruby/commit/13ac36e97e8898d46b802c540b7dba7272247108))
11
+ * **client:** migrate output config ([#784](https://github.com/anthropics/anthropic-sdk-ruby/issues/784)) ([d055b2b](https://github.com/anthropics/anthropic-sdk-ruby/commit/d055b2b172ad951cf6b20bea709c8bd3b4f345c6))
12
+
13
+
14
+ ### Chores
15
+
16
+ * add cgi gem as explicit dependency ([b9ef072](https://github.com/anthropics/anthropic-sdk-ruby/commit/b9ef072be4d8ecd4f12e90403183b0ced5cb360f))
17
+ * **client:** mark claude-3-5-haiku as deprecated ([2ed73fd](https://github.com/anthropics/anthropic-sdk-ruby/commit/2ed73fde07fa480ff55d67b47442deebb76bc1e5))
18
+ * **internal:** update `actions/checkout` version ([2f82126](https://github.com/anthropics/anthropic-sdk-ruby/commit/2f8212603e7a6b7a96afaa3cfd19a55a0853f49c))
19
+ * **internal:** use different example values for some enums ([13d8b68](https://github.com/anthropics/anthropic-sdk-ruby/commit/13d8b68d290c11497faed22e2eda1778187bf2ec))
20
+
21
+ ## 1.16.3 (2026-01-05)
22
+
23
+ Full Changelog: [v1.16.2...v1.16.3](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.16.2...v1.16.3)
24
+
25
+ ### Bug Fixes
26
+
27
+ * Use proper module name for structured output parsing ([#769](https://github.com/anthropics/anthropic-sdk-ruby/issues/769)) ([fdbe433](https://github.com/anthropics/anthropic-sdk-ruby/commit/fdbe433cbcbe5a8611410338f7e0d47a727575be))
28
+
29
+
30
+ ### Chores
31
+
32
+ * **ci:** Add Claude Code GitHub Workflow ([#772](https://github.com/anthropics/anthropic-sdk-ruby/issues/772)) ([6ebfa59](https://github.com/anthropics/anthropic-sdk-ruby/commit/6ebfa59913de26aece1d946a0cfaad168cd5f632))
33
+
3
34
  ## 1.16.2 (2025-12-18)
4
35
 
5
36
  Full Changelog: [v1.16.1...v1.16.2](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.16.1...v1.16.2)
data/README.md CHANGED
@@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application
15
15
  <!-- x-release-please-start-version -->
16
16
 
17
17
  ```ruby
18
- gem "anthropic", "~> 1.16.2"
18
+ gem "anthropic", "~> 1.17.0"
19
19
  ```
20
20
 
21
21
  <!-- x-release-please-end -->
@@ -39,7 +39,7 @@ anthropic = Anthropic::Client.new(
39
39
  message = anthropic.messages.create(
40
40
  max_tokens: 1024,
41
41
  messages: [{role: "user", content: "Hello, Claude"}],
42
- model: :"claude-opus-4-5-20251101"
42
+ model: "claude-sonnet-4-5-20250929"
43
43
  )
44
44
 
45
45
  puts(message.content)
@@ -53,7 +53,7 @@ We provide support for streaming responses using Server-Sent Events (SSE).
53
53
  stream = anthropic.messages.stream(
54
54
  max_tokens: 1024,
55
55
  messages: [{role: "user", content: "Hello, Claude"}],
56
- model: :"claude-opus-4-5-20251101"
56
+ model: "claude-sonnet-4-5-20250929"
57
57
  )
58
58
 
59
59
  stream.each do |message|
@@ -109,6 +109,34 @@ client.beta.messages.tool_runner(
109
109
  ).each_message { puts _1.content }
110
110
  ```
111
111
 
112
+ ### Structured Outputs
113
+
114
+ Constrain Claude's responses to follow a specific JSON schema using the `output_config` parameter:
115
+
116
+ ```ruby
117
+ class FamousNumber < Anthropic::BaseModel
118
+ required :value, Float
119
+ optional :reason, String, doc: "why is this number mathematically significant?"
120
+ end
121
+
122
+ class Output < Anthropic::BaseModel
123
+ required :numbers, Anthropic::ArrayOf[FamousNumber], min_length: 3, max_length: 5
124
+ end
125
+
126
+ message = anthropic.messages.create(
127
+ model: "claude-sonnet-4-5-20250929",
128
+ max_tokens: 1024,
129
+ messages: [{role: "user", content: "give me some famous numbers"}],
130
+ output_config: {format: Output}
131
+ )
132
+
133
+ # Access the parsed response
134
+ message.parsed_output
135
+ # => #<Output numbers=[#<FamousNumber value=3.14159... reason="Pi is...">...]>
136
+ ```
137
+
138
+ For streaming and more examples, see [helpers.md](helpers.md#structured-outputs).
139
+
112
140
  ### Pagination
113
141
 
114
142
  List methods in the Anthropic API are paginated.
@@ -168,7 +196,7 @@ begin
168
196
  message = anthropic.messages.create(
169
197
  max_tokens: 1024,
170
198
  messages: [{role: "user", content: "Hello, Claude"}],
171
- model: :"claude-opus-4-5-20251101"
199
+ model: "claude-sonnet-4-5-20250929"
172
200
  )
173
201
  rescue Anthropic::Errors::APIConnectionError => e
174
202
  puts("The server could not be reached")
@@ -215,7 +243,7 @@ anthropic = Anthropic::Client.new(
215
243
  anthropic.messages.create(
216
244
  max_tokens: 1024,
217
245
  messages: [{role: "user", content: "Hello, Claude"}],
218
- model: :"claude-opus-4-5-20251101",
246
+ model: "claude-sonnet-4-5-20250929",
219
247
  request_options: {max_retries: 5}
220
248
  )
221
249
  ```
@@ -234,7 +262,7 @@ anthropic = Anthropic::Client.new(
234
262
  anthropic.messages.create(
235
263
  max_tokens: 1024,
236
264
  messages: [{role: "user", content: "Hello, Claude"}],
237
- model: :"claude-opus-4-5-20251101",
265
+ model: "claude-sonnet-4-5-20250929",
238
266
  request_options: {timeout: 5}
239
267
  )
240
268
  ```
@@ -330,7 +358,7 @@ message =
330
358
  anthropic.messages.create(
331
359
  max_tokens: 1024,
332
360
  messages: [{role: "user", content: "Hello, Claude"}],
333
- model: :"claude-opus-4-5-20251101",
361
+ model: "claude-sonnet-4-5-20250929",
334
362
  request_options: {
335
363
  extra_query: {my_query_parameter: value},
336
364
  extra_body: {my_body_parameter: value},
@@ -379,7 +407,7 @@ You can provide typesafe request parameters like so:
379
407
  anthropic.messages.create(
380
408
  max_tokens: 1024,
381
409
  messages: [Anthropic::MessageParam.new(role: "user", content: "Hello, Claude")],
382
- model: :"claude-opus-4-5-20251101"
410
+ model: "claude-sonnet-4-5-20250929"
383
411
  )
384
412
  ```
385
413
 
@@ -390,14 +418,14 @@ Or, equivalently:
390
418
  anthropic.messages.create(
391
419
  max_tokens: 1024,
392
420
  messages: [{role: "user", content: "Hello, Claude"}],
393
- model: :"claude-opus-4-5-20251101"
421
+ model: "claude-sonnet-4-5-20250929"
394
422
  )
395
423
 
396
424
  # You can also splat a full Params class:
397
425
  params = Anthropic::MessageCreateParams.new(
398
426
  max_tokens: 1024,
399
427
  messages: [Anthropic::MessageParam.new(role: "user", content: "Hello, Claude")],
400
- model: :"claude-opus-4-5-20251101"
428
+ model: "claude-sonnet-4-5-20250929"
401
429
  )
402
430
  anthropic.messages.create(**params)
403
431
  ```
@@ -13,11 +13,26 @@ module Anthropic
13
13
  #
14
14
  # @param strict [Boolean, nil]
15
15
  #
16
+ # @param is_beta [Boolean]
17
+ #
16
18
  # @return [Hash{String=>Class}, Hash{String=>Class}]
17
- def distill_input_schema_models!(data, strict:)
19
+ def distill_input_schema_models!(data, strict:, is_beta: false)
18
20
  tools = {}
19
21
  models = {}
20
22
 
23
+ # Check for invalid output_config type before pattern matching
24
+ if data.key?(:output_config) && !data[:output_config].is_a?(Hash)
25
+ raise ArgumentError,
26
+ "output_config must be a Hash, got #{data[:output_config].class}"
27
+ end
28
+
29
+ # Check for conflicting output_format and output_config[:format] before pattern matching
30
+ if data.key?(:output_format) && data.dig(:output_config, :format)
31
+ raise ArgumentError,
32
+ "Both output_format and output_config[:format] were provided. " \
33
+ "Please use only output_config[:format] (output_format is deprecated)."
34
+ end
35
+
21
36
  case data
22
37
  in {tools: Array => tool_array}
23
38
  mapped = tool_array.map do |tool|
@@ -54,13 +69,39 @@ module Anthropic
54
69
  end
55
70
  end
56
71
  tool_array.replace(mapped)
72
+ # GA: output_config with BaseModel class as format
73
+ in {output_config: {format: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model} => output_config}
74
+ name = model_name(model.name)
75
+ models.store(name, model)
76
+ schema = model.to_json_schema
77
+ Anthropic::Helpers::InputSchema::SupportedSchemas.transform_schema!(schema)
78
+ output_config.update(format: {type: :json_schema, schema:})
79
+ inject_structured_output_beta_header!(data) if is_beta
80
+ # GA: output_config.format.schema as BaseModel class
81
+ in {output_config: {format: {schema: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model} => format_} => _output_config}
82
+ name = model_name(model.name)
83
+ models.store(name, model)
84
+ schema = model.to_json_schema
85
+ Anthropic::Helpers::InputSchema::SupportedSchemas.transform_schema!(schema)
86
+ format_.update(type: :json_schema, schema:)
87
+ inject_structured_output_beta_header!(data) if is_beta
88
+ # Beta: output_format as BaseModel class (deprecated)
57
89
  in {output_format: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model}
90
+ transform_output_format_to_output_config!(data, model:, models:, is_beta:)
91
+ # rubocop:disable Lint/DuplicateBranch
92
+ in {output_format: {schema: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model}}
93
+ # This branch handles output_format: {schema: Model} vs output_format: Model above
94
+ transform_output_format_to_output_config!(data, model:, models:, is_beta:)
95
+ # rubocop:enable Lint/DuplicateBranch
96
+ in {output_config: {format: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model}}
97
+ # New API: output_config.format with model class
58
98
  name = model_name(model.name)
59
99
  models.store(name, model)
60
100
  schema = model.to_json_schema
61
101
  Anthropic::Helpers::InputSchema::SupportedSchemas.transform_schema!(schema)
62
102
  data.update(output_format: {type: :json_schema, schema: schema})
63
- in {output_format: {schema: Anthropic::Helpers::StructuredOutput::JsonSchemaConverter => model} => output_format}
103
+ # Beta: output_format.schema as BaseModel class (deprecated)
104
+ in {output_format: {schema: Anthropic::Helpers::InputSchema::JsonSchemaConverter => model} => output_format}
64
105
  name = model_name(model.name)
65
106
  models.store(name, model)
66
107
  schema = model.to_json_schema
@@ -108,6 +149,50 @@ module Anthropic
108
149
  raw
109
150
  end
110
151
 
152
+ # @api private
153
+ #
154
+ # Transform deprecated output_format to output_config.format
155
+ #
156
+ # @param data [Hash{Symbol=>Object}]
157
+ # @param model [Class]
158
+ # @param models [Hash{String=>Class}]
159
+ # @param is_beta [Boolean]
160
+ private def transform_output_format_to_output_config!(data, model:, models:, is_beta:)
161
+ warn(
162
+ "[DEPRECATION] output_format is deprecated. Use output_config[:format] instead.",
163
+ category: :deprecated
164
+ )
165
+ # Error if output_config exists but is not a hash
166
+ if data.key?(:output_config) && !data[:output_config].is_a?(Hash)
167
+ raise ArgumentError,
168
+ "output_config must be a Hash, got #{data[:output_config].class}"
169
+ end
170
+ # Error if both params are provided
171
+ if data&.dig(:output_config, :format)
172
+ raise ArgumentError,
173
+ "Both output_format and output_config[:format] were provided. " \
174
+ "Please use only output_config[:format] (output_format is deprecated)."
175
+ end
176
+ name = model_name(model.name)
177
+ models.store(name, model)
178
+ schema = model.to_json_schema
179
+ Anthropic::Helpers::InputSchema::SupportedSchemas.transform_schema!(schema)
180
+ output_config = data[:output_config].to_h
181
+ output_config.store(:format, type: :json_schema, schema: schema)
182
+ data.delete(:output_format)
183
+ data[:output_config] = output_config
184
+ inject_structured_output_beta_header!(data) if is_beta
185
+ end
186
+
187
+ # @api private
188
+ #
189
+ # Inject the structured outputs beta header into the request data
190
+ #
191
+ # @param data [Hash{Symbol=>Object}]
192
+ private def inject_structured_output_beta_header!(data)
193
+ data[:betas] = data[:betas].to_a.dup.push("structured-outputs-2025-12-15").uniq
194
+ end
195
+
111
196
  # @api private
112
197
  #
113
198
  # @param classname [String]
@@ -63,7 +63,7 @@ module Anthropic
63
63
  # @return [Anthropic::Models::Message, Anthropic::Models::Beta::BetaMessage]
64
64
  def accumulated_message
65
65
  until_done
66
- parse_tool_uses!(@accumated_message_snapshot)
66
+ parse_content_blocks!(@accumated_message_snapshot)
67
67
  @accumated_message_snapshot
68
68
  end
69
69
 
@@ -217,47 +217,72 @@ module Anthropic
217
217
 
218
218
  # @api private
219
219
  #
220
- # Parse tool use blocks in the message using the provided tool models.
220
+ # Parse tool use blocks and text blocks with structured output in the message.
221
221
  #
222
222
  # @param message [Anthropic::Models::Message] The message to parse
223
223
  #
224
- # @return [Anthropic::Models::Message] The message with parsed tool uses
225
- private def parse_tool_uses!(message)
224
+ # @return [Anthropic::Models::Message] The message with parsed content
225
+ private def parse_content_blocks!(message)
226
226
  return message unless message&.content
227
227
 
228
228
  # rubocop:disable Metrics/BlockLength
229
229
  message.content.each_with_index do |content, index|
230
- next unless content.type == :tool_use
230
+ case content.type
231
+ when :tool_use
232
+ next unless (tool = @tools[content.name])
231
233
 
232
- next unless (tool = @tools[content.name])
234
+ parsed =
235
+ begin
236
+ parsed_input = if content.input.is_a?(String)
237
+ JSON.parse(content.input, symbolize_names: true)
238
+ else
239
+ content.input
240
+ end
233
241
 
234
- parsed =
235
- begin
236
- parsed_input = if content.input.is_a?(String)
237
- JSON.parse(content.input, symbolize_names: true)
242
+ Anthropic::Internal::Type::Converter.coerce(tool, parsed_input)
243
+ rescue StandardError => e
244
+ e
245
+ end
246
+
247
+ cls =
248
+ case content
249
+ in Anthropic::ContentBlock
250
+ Anthropic::Models::ToolUseBlock
238
251
  else
239
- content.input
252
+ Anthropic::Models::BetaToolUseBlock
240
253
  end
254
+ message.content[index] = cls.new(
255
+ id: content.id,
256
+ input: content.input,
257
+ name: content.name,
258
+ type: content.type,
259
+ parsed: parsed
260
+ )
261
+ when :text
262
+ next unless (model = @models.first&.last)
241
263
 
242
- Anthropic::Internal::Type::Converter.coerce(tool, parsed_input)
243
- rescue StandardError => e
244
- e
245
- end
264
+ parsed =
265
+ begin
266
+ json = JSON.parse(content.text, symbolize_names: true)
267
+ Anthropic::Internal::Type::Converter.coerce(model, json)
268
+ rescue StandardError => e
269
+ {error: e.message}
270
+ end
246
271
 
247
- cls =
248
- case content
249
- in Anthropic::ContentBlock
250
- Anthropic::Models::ToolUseBlock
251
- else
252
- Anthropic::Models::BetaToolUseBlock
253
- end
254
- message.content[index] = cls.new(
255
- id: content.id,
256
- input: content.input,
257
- name: content.name,
258
- type: content.type,
259
- parsed: parsed
260
- )
272
+ cls =
273
+ case content
274
+ in Anthropic::ContentBlock
275
+ Anthropic::Models::TextBlock
276
+ else
277
+ Anthropic::Models::BetaTextBlock
278
+ end
279
+ message.content[index] = cls.new(
280
+ citations: content.citations,
281
+ text: content.text,
282
+ type: content.type,
283
+ parsed: parsed
284
+ )
285
+ end
261
286
  end
262
287
  # rubocop:enable Metrics/BlockLength
263
288
 
@@ -37,6 +37,7 @@ module Anthropic
37
37
  optional :defer_loading, Anthropic::Internal::Type::Boolean
38
38
 
39
39
  # @!attribute strict
40
+ # When true, guarantees schema validation on tool names and inputs
40
41
  #
41
42
  # @return [Boolean, nil]
42
43
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -51,7 +52,7 @@ module Anthropic
51
52
  #
52
53
  # @param defer_loading [Boolean] If true, tool will not be included in initial system prompt. Only loaded when re
53
54
  #
54
- # @param strict [Boolean]
55
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
55
56
  #
56
57
  # @param name [Symbol, :code_execution] Name of the tool.
57
58
  #
@@ -37,6 +37,7 @@ module Anthropic
37
37
  optional :defer_loading, Anthropic::Internal::Type::Boolean
38
38
 
39
39
  # @!attribute strict
40
+ # When true, guarantees schema validation on tool names and inputs
40
41
  #
41
42
  # @return [Boolean, nil]
42
43
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -51,7 +52,7 @@ module Anthropic
51
52
  #
52
53
  # @param defer_loading [Boolean] If true, tool will not be included in initial system prompt. Only loaded when re
53
54
  #
54
- # @param strict [Boolean]
55
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
55
56
  #
56
57
  # @param name [Symbol, :code_execution] Name of the tool.
57
58
  #
@@ -43,6 +43,7 @@ module Anthropic
43
43
  Anthropic::Internal::Type::ArrayOf[Anthropic::Internal::Type::HashOf[Anthropic::Internal::Type::Unknown]]
44
44
 
45
45
  # @!attribute strict
46
+ # When true, guarantees schema validation on tool names and inputs
46
47
  #
47
48
  # @return [Boolean, nil]
48
49
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -59,7 +60,7 @@ module Anthropic
59
60
  #
60
61
  # @param input_examples [Array<Hash{Symbol=>Object}>]
61
62
  #
62
- # @param strict [Boolean]
63
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
63
64
  #
64
65
  # @param name [Symbol, :memory] Name of the tool.
65
66
  #
@@ -5,15 +5,33 @@ module Anthropic
5
5
  module Beta
6
6
  class BetaOutputConfig < Anthropic::Internal::Type::BaseModel
7
7
  # @!attribute effort
8
- # All possible effort levels.
8
+ # How much effort the model should put into its response. Higher effort levels may
9
+ # result in more thorough analysis but take longer.
10
+ #
11
+ # Valid values are `low`, `medium`, or `high`.
9
12
  #
10
13
  # @return [Symbol, Anthropic::Models::Beta::BetaOutputConfig::Effort, nil]
11
14
  optional :effort, enum: -> { Anthropic::Beta::BetaOutputConfig::Effort }, nil?: true
12
15
 
13
- # @!method initialize(effort: nil)
14
- # @param effort [Symbol, Anthropic::Models::Beta::BetaOutputConfig::Effort, nil] All possible effort levels.
16
+ # @!attribute format_
17
+ # A schema to specify Claude's output format in responses. See
18
+ # [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs)
19
+ #
20
+ # @return [Anthropic::Models::Beta::BetaJSONOutputFormat, nil]
21
+ optional :format_, -> { Anthropic::Beta::BetaJSONOutputFormat }, api_name: :format, nil?: true
22
+
23
+ # @!method initialize(effort: nil, format_: nil)
24
+ # Some parameter documentations has been truncated, see
25
+ # {Anthropic::Models::Beta::BetaOutputConfig} for more details.
26
+ #
27
+ # @param effort [Symbol, Anthropic::Models::Beta::BetaOutputConfig::Effort, nil] How much effort the model should put into its response. Higher effort levels may
28
+ #
29
+ # @param format_ [Anthropic::Models::Beta::BetaJSONOutputFormat, nil] A schema to specify Claude's output format in responses. See [structured outputs
15
30
 
16
- # All possible effort levels.
31
+ # How much effort the model should put into its response. Higher effort levels may
32
+ # result in more thorough analysis but take longer.
33
+ #
34
+ # Valid values are `low`, `medium`, or `high`.
17
35
  #
18
36
  # @see Anthropic::Models::Beta::BetaOutputConfig#effort
19
37
  module Effort
@@ -9,12 +9,6 @@ module Anthropic
9
9
  # @return [String]
10
10
  required :id, String
11
11
 
12
- # @!attribute caller_
13
- # Tool invocation directly from the model.
14
- #
15
- # @return [Anthropic::Models::Beta::BetaDirectCaller, Anthropic::Models::Beta::BetaServerToolCaller]
16
- required :caller_, union: -> { Anthropic::Beta::BetaServerToolUseBlock::Caller }, api_name: :caller
17
-
18
12
  # @!attribute input
19
13
  #
20
14
  # @return [Object]
@@ -30,17 +24,39 @@ module Anthropic
30
24
  # @return [Symbol, :server_tool_use]
31
25
  required :type, const: :server_tool_use
32
26
 
33
- # @!method initialize(id:, caller_:, input:, name:, type: :server_tool_use)
34
- # @param id [String]
27
+ # @!attribute caller_
28
+ # Tool invocation directly from the model.
35
29
  #
36
- # @param caller_ [Anthropic::Models::Beta::BetaDirectCaller, Anthropic::Models::Beta::BetaServerToolCaller] Tool invocation directly from the model.
30
+ # @return [Anthropic::Models::Beta::BetaDirectCaller, Anthropic::Models::Beta::BetaServerToolCaller, nil]
31
+ optional :caller_, union: -> { Anthropic::Beta::BetaServerToolUseBlock::Caller }, api_name: :caller
32
+
33
+ # @!method initialize(id:, input:, name:, caller_: nil, type: :server_tool_use)
34
+ # @param id [String]
37
35
  #
38
36
  # @param input [Object]
39
37
  #
40
38
  # @param name [Symbol, Anthropic::Models::Beta::BetaServerToolUseBlock::Name]
41
39
  #
40
+ # @param caller_ [Anthropic::Models::Beta::BetaDirectCaller, Anthropic::Models::Beta::BetaServerToolCaller] Tool invocation directly from the model.
41
+ #
42
42
  # @param type [Symbol, :server_tool_use]
43
43
 
44
+ # @see Anthropic::Models::Beta::BetaServerToolUseBlock#name
45
+ module Name
46
+ extend Anthropic::Internal::Type::Enum
47
+
48
+ WEB_SEARCH = :web_search
49
+ WEB_FETCH = :web_fetch
50
+ CODE_EXECUTION = :code_execution
51
+ BASH_CODE_EXECUTION = :bash_code_execution
52
+ TEXT_EDITOR_CODE_EXECUTION = :text_editor_code_execution
53
+ TOOL_SEARCH_TOOL_REGEX = :tool_search_tool_regex
54
+ TOOL_SEARCH_TOOL_BM25 = :tool_search_tool_bm25
55
+
56
+ # @!method self.values
57
+ # @return [Array<Symbol>]
58
+ end
59
+
44
60
  # Tool invocation directly from the model.
45
61
  #
46
62
  # @see Anthropic::Models::Beta::BetaServerToolUseBlock#caller_
@@ -58,22 +74,6 @@ module Anthropic
58
74
  # @!method self.variants
59
75
  # @return [Array(Anthropic::Models::Beta::BetaDirectCaller, Anthropic::Models::Beta::BetaServerToolCaller)]
60
76
  end
61
-
62
- # @see Anthropic::Models::Beta::BetaServerToolUseBlock#name
63
- module Name
64
- extend Anthropic::Internal::Type::Enum
65
-
66
- WEB_SEARCH = :web_search
67
- WEB_FETCH = :web_fetch
68
- CODE_EXECUTION = :code_execution
69
- BASH_CODE_EXECUTION = :bash_code_execution
70
- TEXT_EDITOR_CODE_EXECUTION = :text_editor_code_execution
71
- TOOL_SEARCH_TOOL_REGEX = :tool_search_tool_regex
72
- TOOL_SEARCH_TOOL_BM25 = :tool_search_tool_bm25
73
-
74
- # @!method self.values
75
- # @return [Array<Symbol>]
76
- end
77
77
  end
78
78
  end
79
79
 
@@ -58,6 +58,7 @@ module Anthropic
58
58
  Anthropic::Internal::Type::ArrayOf[Anthropic::Internal::Type::HashOf[Anthropic::Internal::Type::Unknown]]
59
59
 
60
60
  # @!attribute strict
61
+ # When true, guarantees schema validation on tool names and inputs
61
62
  #
62
63
  # @return [Boolean, nil]
63
64
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -85,7 +86,7 @@ module Anthropic
85
86
  #
86
87
  # @param input_examples [Array<Hash{Symbol=>Object}>]
87
88
  #
88
- # @param strict [Boolean]
89
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
89
90
  #
90
91
  # @param type [Symbol, Anthropic::Models::Beta::BetaTool::Type, nil]
91
92
 
@@ -43,6 +43,7 @@ module Anthropic
43
43
  Anthropic::Internal::Type::ArrayOf[Anthropic::Internal::Type::HashOf[Anthropic::Internal::Type::Unknown]]
44
44
 
45
45
  # @!attribute strict
46
+ # When true, guarantees schema validation on tool names and inputs
46
47
  #
47
48
  # @return [Boolean, nil]
48
49
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -59,7 +60,7 @@ module Anthropic
59
60
  #
60
61
  # @param input_examples [Array<Hash{Symbol=>Object}>]
61
62
  #
62
- # @param strict [Boolean]
63
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
63
64
  #
64
65
  # @param name [Symbol, :bash] Name of the tool.
65
66
  #
@@ -43,6 +43,7 @@ module Anthropic
43
43
  Anthropic::Internal::Type::ArrayOf[Anthropic::Internal::Type::HashOf[Anthropic::Internal::Type::Unknown]]
44
44
 
45
45
  # @!attribute strict
46
+ # When true, guarantees schema validation on tool names and inputs
46
47
  #
47
48
  # @return [Boolean, nil]
48
49
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -59,7 +60,7 @@ module Anthropic
59
60
  #
60
61
  # @param input_examples [Array<Hash{Symbol=>Object}>]
61
62
  #
62
- # @param strict [Boolean]
63
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
63
64
  #
64
65
  # @param name [Symbol, :bash] Name of the tool.
65
66
  #
@@ -61,6 +61,7 @@ module Anthropic
61
61
  Anthropic::Internal::Type::ArrayOf[Anthropic::Internal::Type::HashOf[Anthropic::Internal::Type::Unknown]]
62
62
 
63
63
  # @!attribute strict
64
+ # When true, guarantees schema validation on tool names and inputs
64
65
  #
65
66
  # @return [Boolean, nil]
66
67
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -83,7 +84,7 @@ module Anthropic
83
84
  #
84
85
  # @param input_examples [Array<Hash{Symbol=>Object}>]
85
86
  #
86
- # @param strict [Boolean]
87
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
87
88
  #
88
89
  # @param name [Symbol, :computer] Name of the tool.
89
90
  #
@@ -61,6 +61,7 @@ module Anthropic
61
61
  Anthropic::Internal::Type::ArrayOf[Anthropic::Internal::Type::HashOf[Anthropic::Internal::Type::Unknown]]
62
62
 
63
63
  # @!attribute strict
64
+ # When true, guarantees schema validation on tool names and inputs
64
65
  #
65
66
  # @return [Boolean, nil]
66
67
  optional :strict, Anthropic::Internal::Type::Boolean
@@ -83,7 +84,7 @@ module Anthropic
83
84
  #
84
85
  # @param input_examples [Array<Hash{Symbol=>Object}>]
85
86
  #
86
- # @param strict [Boolean]
87
+ # @param strict [Boolean] When true, guarantees schema validation on tool names and inputs
87
88
  #
88
89
  # @param name [Symbol, :computer] Name of the tool.
89
90
  #