anthropic 1.7.0 → 1.9.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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +1 -1
  4. data/lib/anthropic/helpers/input_schema/array_of.rb +41 -0
  5. data/lib/anthropic/helpers/input_schema/base_model.rb +86 -0
  6. data/lib/anthropic/helpers/input_schema/boolean.rb +29 -0
  7. data/lib/anthropic/helpers/input_schema/enum_of.rb +63 -0
  8. data/lib/anthropic/helpers/input_schema/json_schema_converter.rb +199 -0
  9. data/lib/anthropic/helpers/input_schema/parsed_json.rb +39 -0
  10. data/lib/anthropic/helpers/input_schema/property_mapping.rb +47 -0
  11. data/lib/anthropic/helpers/input_schema/union_of.rb +56 -0
  12. data/lib/anthropic/helpers/input_schema.rb +16 -0
  13. data/lib/anthropic/helpers/streaming/message_stream.rb +41 -1
  14. data/lib/anthropic/input_schema.rb +10 -0
  15. data/lib/anthropic/internal/stream.rb +2 -1
  16. data/lib/anthropic/internal/transport/base_client.rb +1 -2
  17. data/lib/anthropic/internal/transport/pooled_net_requester.rb +1 -9
  18. data/lib/anthropic/internal/type/base_model.rb +2 -9
  19. data/lib/anthropic/internal/util.rb +2 -2
  20. data/lib/anthropic/models/beta/beta_bash_code_execution_output_block.rb +25 -0
  21. data/lib/anthropic/models/beta/beta_bash_code_execution_output_block_param.rb +25 -0
  22. data/lib/anthropic/models/beta/beta_bash_code_execution_result_block.rb +44 -0
  23. data/lib/anthropic/models/beta/beta_bash_code_execution_result_block_param.rb +44 -0
  24. data/lib/anthropic/models/beta/beta_bash_code_execution_tool_result_block.rb +43 -0
  25. data/lib/anthropic/models/beta/beta_bash_code_execution_tool_result_block_param.rb +53 -0
  26. data/lib/anthropic/models/beta/beta_bash_code_execution_tool_result_error.rb +39 -0
  27. data/lib/anthropic/models/beta/beta_bash_code_execution_tool_result_error_param.rb +39 -0
  28. data/lib/anthropic/models/beta/beta_citation_config.rb +19 -0
  29. data/lib/anthropic/models/beta/beta_code_execution_tool_20250825.rb +40 -0
  30. data/lib/anthropic/models/beta/beta_content_block.rb +8 -1
  31. data/lib/anthropic/models/beta/beta_content_block_param.rb +9 -1
  32. data/lib/anthropic/models/beta/beta_document_block.rb +56 -0
  33. data/lib/anthropic/models/beta/beta_message.rb +2 -2
  34. data/lib/anthropic/models/beta/beta_message_param.rb +3 -3
  35. data/lib/anthropic/models/beta/beta_raw_content_block_start_event.rb +10 -3
  36. data/lib/anthropic/models/beta/beta_request_document_block.rb +2 -2
  37. data/lib/anthropic/models/beta/beta_server_tool_usage.rb +9 -1
  38. data/lib/anthropic/models/beta/beta_server_tool_use_block.rb +3 -0
  39. data/lib/anthropic/models/beta/beta_server_tool_use_block_param.rb +3 -0
  40. data/lib/anthropic/models/beta/beta_text_editor_code_execution_create_result_block.rb +25 -0
  41. data/lib/anthropic/models/beta/beta_text_editor_code_execution_create_result_block_param.rb +26 -0
  42. data/lib/anthropic/models/beta/beta_text_editor_code_execution_str_replace_result_block.rb +49 -0
  43. data/lib/anthropic/models/beta/beta_text_editor_code_execution_str_replace_result_block_param.rb +50 -0
  44. data/lib/anthropic/models/beta/beta_text_editor_code_execution_tool_result_block.rb +47 -0
  45. data/lib/anthropic/models/beta/beta_text_editor_code_execution_tool_result_block_param.rb +57 -0
  46. data/lib/anthropic/models/beta/beta_text_editor_code_execution_tool_result_error.rb +45 -0
  47. data/lib/anthropic/models/beta/beta_text_editor_code_execution_tool_result_error_param.rb +46 -0
  48. data/lib/anthropic/models/beta/beta_text_editor_code_execution_view_result_block.rb +61 -0
  49. data/lib/anthropic/models/beta/beta_text_editor_code_execution_view_result_block_param.rb +62 -0
  50. data/lib/anthropic/models/beta/beta_tool_result_block_param.rb +6 -4
  51. data/lib/anthropic/models/beta/beta_tool_union.rb +5 -1
  52. data/lib/anthropic/models/beta/beta_web_fetch_block.rb +42 -0
  53. data/lib/anthropic/models/beta/beta_web_fetch_block_param.rb +42 -0
  54. data/lib/anthropic/models/beta/beta_web_fetch_tool_20250910.rb +82 -0
  55. data/lib/anthropic/models/beta/beta_web_fetch_tool_result_block.rb +43 -0
  56. data/lib/anthropic/models/beta/beta_web_fetch_tool_result_block_param.rb +53 -0
  57. data/lib/anthropic/models/beta/beta_web_fetch_tool_result_error_block.rb +25 -0
  58. data/lib/anthropic/models/beta/beta_web_fetch_tool_result_error_block_param.rb +25 -0
  59. data/lib/anthropic/models/beta/beta_web_fetch_tool_result_error_code.rb +25 -0
  60. data/lib/anthropic/models/beta/message_count_tokens_params.rb +9 -30
  61. data/lib/anthropic/models/beta/message_create_params.rb +3 -26
  62. data/lib/anthropic/models/beta/messages/batch_create_params.rb +6 -36
  63. data/lib/anthropic/models/beta/messages/beta_message_batch.rb +1 -4
  64. data/lib/anthropic/models/beta_error_response.rb +7 -1
  65. data/lib/anthropic/models/document_block_param.rb +2 -2
  66. data/lib/anthropic/models/error_response.rb +7 -1
  67. data/lib/anthropic/models/message_count_tokens_params.rb +1 -24
  68. data/lib/anthropic/models/message_create_params.rb +1 -24
  69. data/lib/anthropic/models/messages/batch_create_params.rb +2 -28
  70. data/lib/anthropic/models/tool_result_block_param.rb +6 -4
  71. data/lib/anthropic/models/tool_use_block.rb +8 -0
  72. data/lib/anthropic/resources/beta/messages.rb +3 -3
  73. data/lib/anthropic/resources/messages.rb +85 -1
  74. data/lib/anthropic/version.rb +1 -1
  75. data/lib/anthropic.rb +39 -0
  76. data/rbi/anthropic/errors.rbi +2 -2
  77. data/rbi/anthropic/helpers/input_schema/array_of.rbi +16 -0
  78. data/rbi/anthropic/helpers/input_schema/base_model.rbi +21 -0
  79. data/rbi/anthropic/helpers/input_schema/boolean.rbi +11 -0
  80. data/rbi/anthropic/helpers/input_schema/enum_of.rbi +30 -0
  81. data/rbi/anthropic/helpers/input_schema/json_schema_converter.rbi +89 -0
  82. data/rbi/anthropic/helpers/input_schema/union_of.rbi +23 -0
  83. data/rbi/anthropic/helpers/structured_output.rbi +16 -0
  84. data/rbi/anthropic/input_schema.rbi +12 -0
  85. data/rbi/anthropic/models/beta/beta_bash_code_execution_output_block.rbi +33 -0
  86. data/rbi/anthropic/models/beta/beta_bash_code_execution_output_block_param.rbi +34 -0
  87. data/rbi/anthropic/models/beta/beta_bash_code_execution_result_block.rbi +72 -0
  88. data/rbi/anthropic/models/beta/beta_bash_code_execution_result_block_param.rbi +77 -0
  89. data/rbi/anthropic/models/beta/beta_bash_code_execution_tool_result_block.rbi +86 -0
  90. data/rbi/anthropic/models/beta/beta_bash_code_execution_tool_result_block_param.rbi +110 -0
  91. data/rbi/anthropic/models/beta/beta_bash_code_execution_tool_result_error.rbi +101 -0
  92. data/rbi/anthropic/models/beta/beta_bash_code_execution_tool_result_error_param.rbi +101 -0
  93. data/rbi/anthropic/models/beta/beta_citation_config.rbi +30 -0
  94. data/rbi/anthropic/models/beta/beta_code_execution_tool_20250825.rbi +72 -0
  95. data/rbi/anthropic/models/beta/beta_content_block.rbi +3 -0
  96. data/rbi/anthropic/models/beta/beta_content_block_param.rbi +3 -0
  97. data/rbi/anthropic/models/beta/beta_document_block.rbi +95 -0
  98. data/rbi/anthropic/models/beta/beta_message.rbi +3 -0
  99. data/rbi/anthropic/models/beta/beta_raw_content_block_start_event.rbi +6 -0
  100. data/rbi/anthropic/models/beta/beta_request_document_block.rbi +5 -3
  101. data/rbi/anthropic/models/beta/beta_server_tool_usage.rbi +17 -2
  102. data/rbi/anthropic/models/beta/beta_server_tool_use_block.rbi +15 -0
  103. data/rbi/anthropic/models/beta/beta_server_tool_use_block_param.rbi +15 -0
  104. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_create_result_block.rbi +41 -0
  105. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_create_result_block_param.rbi +41 -0
  106. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_str_replace_result_block.rbi +73 -0
  107. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_str_replace_result_block_param.rbi +73 -0
  108. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_tool_result_block.rbi +90 -0
  109. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_tool_result_block_param.rbi +118 -0
  110. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_tool_result_error.rbi +110 -0
  111. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_tool_result_error_param.rbi +110 -0
  112. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_view_result_block.rbi +118 -0
  113. data/rbi/anthropic/models/beta/beta_text_editor_code_execution_view_result_block_param.rbi +118 -0
  114. data/rbi/anthropic/models/beta/beta_tool_result_block_param.rbi +2 -1
  115. data/rbi/anthropic/models/beta/beta_tool_union.rbi +3 -1
  116. data/rbi/anthropic/models/beta/beta_web_fetch_block.rbi +67 -0
  117. data/rbi/anthropic/models/beta/beta_web_fetch_block_param.rbi +71 -0
  118. data/rbi/anthropic/models/beta/beta_web_fetch_tool_20250910.rbi +125 -0
  119. data/rbi/anthropic/models/beta/beta_web_fetch_tool_result_block.rbi +81 -0
  120. data/rbi/anthropic/models/beta/beta_web_fetch_tool_result_block_param.rbi +109 -0
  121. data/rbi/anthropic/models/beta/beta_web_fetch_tool_result_error_block.rbi +51 -0
  122. data/rbi/anthropic/models/beta/beta_web_fetch_tool_result_error_block_param.rbi +50 -0
  123. data/rbi/anthropic/models/beta/beta_web_fetch_tool_result_error_code.rbi +70 -0
  124. data/rbi/anthropic/models/beta/message_count_tokens_params.rbi +17 -53
  125. data/rbi/anthropic/models/beta/message_create_params.rbi +14 -52
  126. data/rbi/anthropic/models/beta/messages/batch_create_params.rbi +14 -52
  127. data/rbi/anthropic/models/beta_error_response.rbi +10 -2
  128. data/rbi/anthropic/models/document_block_param.rbi +7 -3
  129. data/rbi/anthropic/models/error_response.rbi +10 -2
  130. data/rbi/anthropic/models/message_count_tokens_params.rbi +2 -48
  131. data/rbi/anthropic/models/message_create_params.rbi +2 -48
  132. data/rbi/anthropic/models/messages/batch_create_params.rbi +2 -48
  133. data/rbi/anthropic/models/tool_result_block_param.rbi +2 -1
  134. data/rbi/anthropic/resources/beta/messages.rbi +12 -75
  135. data/rbi/anthropic/resources/messages.rbi +3 -72
  136. data/sig/anthropic/models/beta/beta_bash_code_execution_output_block.rbs +23 -0
  137. data/sig/anthropic/models/beta/beta_bash_code_execution_output_block_param.rbs +23 -0
  138. data/sig/anthropic/models/beta/beta_bash_code_execution_result_block.rbs +44 -0
  139. data/sig/anthropic/models/beta/beta_bash_code_execution_result_block_param.rbs +44 -0
  140. data/sig/anthropic/models/beta/beta_bash_code_execution_tool_result_block.rbs +44 -0
  141. data/sig/anthropic/models/beta/beta_bash_code_execution_tool_result_block_param.rbs +49 -0
  142. data/sig/anthropic/models/beta/beta_bash_code_execution_tool_result_error.rbs +48 -0
  143. data/sig/anthropic/models/beta/beta_bash_code_execution_tool_result_error_param.rbs +48 -0
  144. data/sig/anthropic/models/beta/beta_citation_config.rbs +17 -0
  145. data/sig/anthropic/models/beta/beta_code_execution_tool_20250825.rbs +34 -0
  146. data/sig/anthropic/models/beta/beta_content_block.rbs +3 -0
  147. data/sig/anthropic/models/beta/beta_content_block_param.rbs +3 -0
  148. data/sig/anthropic/models/beta/beta_document_block.rbs +49 -0
  149. data/sig/anthropic/models/beta/beta_raw_content_block_start_event.rbs +3 -0
  150. data/sig/anthropic/models/beta/beta_request_document_block.rbs +4 -8
  151. data/sig/anthropic/models/beta/beta_server_tool_usage.rbs +12 -3
  152. data/sig/anthropic/models/beta/beta_server_tool_use_block.rbs +9 -1
  153. data/sig/anthropic/models/beta/beta_server_tool_use_block_param.rbs +9 -1
  154. data/sig/anthropic/models/beta/beta_text_editor_code_execution_create_result_block.rbs +29 -0
  155. data/sig/anthropic/models/beta/beta_text_editor_code_execution_create_result_block_param.rbs +29 -0
  156. data/sig/anthropic/models/beta/beta_text_editor_code_execution_str_replace_result_block.rbs +49 -0
  157. data/sig/anthropic/models/beta/beta_text_editor_code_execution_str_replace_result_block_param.rbs +49 -0
  158. data/sig/anthropic/models/beta/beta_text_editor_code_execution_tool_result_block.rbs +46 -0
  159. data/sig/anthropic/models/beta/beta_text_editor_code_execution_tool_result_block_param.rbs +51 -0
  160. data/sig/anthropic/models/beta/beta_text_editor_code_execution_tool_result_error.rbs +53 -0
  161. data/sig/anthropic/models/beta/beta_text_editor_code_execution_tool_result_error_param.rbs +53 -0
  162. data/sig/anthropic/models/beta/beta_text_editor_code_execution_view_result_block.rbs +61 -0
  163. data/sig/anthropic/models/beta/beta_text_editor_code_execution_view_result_block_param.rbs +61 -0
  164. data/sig/anthropic/models/beta/beta_tool_result_block_param.rbs +1 -0
  165. data/sig/anthropic/models/beta/beta_tool_union.rbs +2 -0
  166. data/sig/anthropic/models/beta/beta_web_fetch_block.rbs +39 -0
  167. data/sig/anthropic/models/beta/beta_web_fetch_block_param.rbs +39 -0
  168. data/sig/anthropic/models/beta/beta_web_fetch_tool_20250910.rbs +59 -0
  169. data/sig/anthropic/models/beta/beta_web_fetch_tool_result_block.rbs +44 -0
  170. data/sig/anthropic/models/beta/beta_web_fetch_tool_result_block_param.rbs +49 -0
  171. data/sig/anthropic/models/beta/beta_web_fetch_tool_result_error_block.rbs +29 -0
  172. data/sig/anthropic/models/beta/beta_web_fetch_tool_result_error_block_param.rbs +29 -0
  173. data/sig/anthropic/models/beta/beta_web_fetch_tool_result_error_code.rbs +32 -0
  174. data/sig/anthropic/models/beta/message_count_tokens_params.rbs +2 -0
  175. data/sig/anthropic/models/beta_error_response.rbs +13 -2
  176. data/sig/anthropic/models/document_block_param.rbs +4 -8
  177. data/sig/anthropic/models/error_response.rbs +13 -2
  178. data/sig/anthropic/models/tool_result_block_param.rbs +1 -0
  179. metadata +107 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66fd9539680e78df8e330ac6a5c6efc4848f35c6878eb56ef0b491511562ecf1
4
- data.tar.gz: 43ef2cdd7fd4f7d95d889115dbf302edb8355681283aec9b76f80f7b1734ee67
3
+ metadata.gz: 9508f2174591353cfaa66f66d1ec7d72fbd3dced9f88e64aae101ad0b370ec51
4
+ data.tar.gz: 4e10f3b7dcdfe9e1fc2bf5efec9bb8578d63f2d49a0ed36b08db2153109a0ada
5
5
  SHA512:
6
- metadata.gz: 55fb0db67745e8506eb2a2ae9708908cf72f1f16eb795d1a4279962864d25e5f972b3be3f53cdacb0293ef17c9c8e84a65643158604c1e50de28fc44aaa7e494
7
- data.tar.gz: 1d479ce6f1b913816cf60d1778f039d874ce701077d1ed6187c9df5e7ba3ce0254da280753c55607343b64ef62aae72c72540a3e28ce5de49a7117b14e326bca
6
+ metadata.gz: b5eeb2c0701c8ab45b86c58f28c4fd49344ae4b9ac1539486ba282ce3b9154cd3b7e8466fb933b61206f18ef2024f50de8366d5aa89336e86307e2ab22a8f1c2
7
+ data.tar.gz: c6f369c9cd95b5501e4416dd8c46ba936f2b09134ccb1a7fec65e7a7948b0e734db46bc3836dee43deac948c4fd216162a5395301c71b837e6277cdbabbbc7a9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.0 (2025-09-10)
4
+
5
+ Full Changelog: [v1.8.0...v1.9.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.8.0...v1.9.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** adds support for Documents in tool results ([91e23c1](https://github.com/anthropics/anthropic-sdk-ruby/commit/91e23c14525ba91fa63eab1ab901c7d8782aa6b3))
10
+ * **api:** adds support for web_fetch_20250910 tool ([631783d](https://github.com/anthropics/anthropic-sdk-ruby/commit/631783ddbbcc0aab95172b3dd4d6cbd29e0ec507))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * unnecessarily long multipart boundary length ([#124](https://github.com/anthropics/anthropic-sdk-ruby/issues/124)) ([69aa4c8](https://github.com/anthropics/anthropic-sdk-ruby/commit/69aa4c8c918b3d401933efaba6440164c6eb6962))
16
+
17
+ ## 1.8.0 (2025-09-02)
18
+
19
+ Full Changelog: [v1.7.0...v1.8.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.7.0...v1.8.0)
20
+
21
+ ### Features
22
+
23
+ * **client:** adds support for code-execution-2025-08-26 tool ([28e554e](https://github.com/anthropics/anthropic-sdk-ruby/commit/28e554ec75e8c34d20ef1e021672f9a02d5be3ec))
24
+ * input schemas ([#660](https://github.com/anthropics/anthropic-sdk-ruby/issues/660)) ([3e062c0](https://github.com/anthropics/anthropic-sdk-ruby/commit/3e062c03b0fc964877095a34cb69de9ba63dfa19))
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * bump sorbet version and fix new type errors from the breaking change ([3c4f15d](https://github.com/anthropics/anthropic-sdk-ruby/commit/3c4f15d8f4115d6da6d8589856e7654162f91110))
30
+ * correctly raise errors encountered during streaming ([be9bc45](https://github.com/anthropics/anthropic-sdk-ruby/commit/be9bc45d96ac227fd5648281199a7c8dd234897d))
31
+
32
+
33
+ ### Chores
34
+
35
+ * add json schema comment for rubocop.yml ([3fce402](https://github.com/anthropics/anthropic-sdk-ruby/commit/3fce4021da72749b127adacee9436327d4b03f60))
36
+
3
37
  ## 1.7.0 (2025-08-13)
4
38
 
5
39
  Full Changelog: [v1.6.0...v1.7.0](https://github.com/anthropics/anthropic-sdk-ruby/compare/v1.6.0...v1.7.0)
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.7.0"
18
+ gem "anthropic", "~> 1.9.0"
19
19
  ```
20
20
 
21
21
  <!-- x-release-please-end -->
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # @generic Elem
7
+ #
8
+ # @example
9
+ # example = Anthropic::ArrayOf[Integer]
10
+ #
11
+ # @example
12
+ # example = Anthropic::ArrayOf[Integer, nil?: true, doc: "hi there!"]
13
+ class ArrayOf < Anthropic::Internal::Type::ArrayOf
14
+ include Anthropic::Helpers::InputSchema::JsonSchemaConverter
15
+
16
+ # @api private
17
+ #
18
+ # @param state [Hash{Symbol=>Object}]
19
+ #
20
+ # @option state [Hash{Object=>String}] :defs
21
+ #
22
+ # @option state [Array<String>] :path
23
+ #
24
+ # @return [Hash{Symbol=>Object}]
25
+ def to_json_schema_inner(state:)
26
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.cache_def!(state, type: self) do
27
+ state.fetch(:path) << "[]"
28
+ items = Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_json_schema_inner(
29
+ item_type,
30
+ state: state
31
+ )
32
+ items = Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_nilable(items) if nilable?
33
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.assoc_meta!(items, meta: @meta)
34
+
35
+ {type: "array", items: items}
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # Represents a response from Anthropic's API where the model's output has been structured according to a schema predefined by the user.
7
+ #
8
+ # This class is specifically used when making requests with the `input_schema` parameter.
9
+ #
10
+ # See {examples/input_schemas.rb} for a complete example of use
11
+ class BaseModel < Anthropic::Internal::Type::BaseModel
12
+ extend Anthropic::Helpers::InputSchema::JsonSchemaConverter
13
+
14
+ class << self
15
+ # @return [Hash{Symbol=>Object}]
16
+ def to_json_schema = Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_json_schema(self)
17
+
18
+ # @api private
19
+ #
20
+ # @param state [Hash{Symbol=>Object}]
21
+ #
22
+ # @option state [Hash{Object=>String}] :defs
23
+ #
24
+ # @option state [Array<String>] :path
25
+ #
26
+ # @return [Hash{Symbol=>Object}]
27
+ def to_json_schema_inner(state:)
28
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.cache_def!(state, type: self) do
29
+ path = state.fetch(:path)
30
+ properties = fields.to_h do |name, field|
31
+ type, nilable, meta = field.fetch_values(:type, :nilable, :meta)
32
+ new_state = {**state, path: [*path, ".#{name}"]}
33
+
34
+ schema =
35
+ case type
36
+ in Anthropic::Helpers::InputSchema::JsonSchemaConverter
37
+ type.to_json_schema_inner(state: new_state)
38
+ else
39
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_json_schema_inner(
40
+ type,
41
+ state: new_state
42
+ )
43
+ end
44
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.assoc_meta!(schema, meta: meta)
45
+ schema = Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_nilable(schema) if nilable
46
+
47
+ [name, schema]
48
+ end
49
+
50
+ {
51
+ type: "object",
52
+ properties: properties,
53
+ required: fields.select { _2.fetch(:required) }.keys.map(&:to_s),
54
+ additionalProperties: false
55
+ }.tap { _1.store(:description, @doc_string) unless @doc_string.nil? }
56
+ end
57
+ end
58
+ end
59
+
60
+ class << self
61
+ def required(name_sym, type_info, *args)
62
+ spec = process_field_args(args)
63
+ super(name_sym, type_info, spec)
64
+ end
65
+
66
+ def optional(name_sym, type_info, *args)
67
+ spec = process_field_args(args)
68
+ super(name_sym, type_info, spec)
69
+ end
70
+
71
+ attr_reader :doc_string
72
+
73
+ # @param description [String]
74
+ def doc(description)
75
+ @doc_string = description
76
+ end
77
+
78
+ private def process_field_args(args)
79
+ # Only accept hash format for descriptions.
80
+ args.grep(Hash).first.to_h
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # @abstract
7
+ #
8
+ # Ruby does not have a "boolean" Class, this is something for models to refer to.
9
+ class Boolean < Anthropic::Internal::Type::Boolean
10
+ extend Anthropic::Helpers::InputSchema::JsonSchemaConverter
11
+
12
+ # rubocop:disable Lint/UnusedMethodArgument
13
+
14
+ # @api private
15
+ #
16
+ # @param state [Hash{Symbol=>Object}]
17
+ #
18
+ # @option state [Hash{Object=>String}] :defs
19
+ #
20
+ # @option state [Array<String>] :path
21
+ #
22
+ # @return [Hash{Symbol=>Object}]
23
+ def self.to_json_schema_inner(state:) = {type: "boolean"}
24
+
25
+ # rubocop:enable Lint/UnusedMethodArgument
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # @generic Value
7
+ #
8
+ # @example
9
+ # example = Anthropic::EnumOf[:foo, :bar, :zoo]
10
+ #
11
+ # @example
12
+ # example = Anthropic::EnumOf[1, 2, 3]
13
+ class EnumOf
14
+ include Anthropic::Internal::Type::Enum
15
+ include Anthropic::Helpers::InputSchema::JsonSchemaConverter
16
+
17
+ # @api private
18
+ #
19
+ # @param state [Hash{Symbol=>Object}]
20
+ #
21
+ # @option state [Hash{Object=>String}] :defs
22
+ #
23
+ # @option state [Array<String>] :path
24
+ #
25
+ # @return [Hash{Symbol=>Object}]
26
+ def to_json_schema_inner(state:)
27
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.cache_def!(state, type: self) do
28
+ types = values.map do
29
+ case _1
30
+ in NilClass
31
+ "null"
32
+ in true | false
33
+ "boolean"
34
+ in Integer
35
+ "integer"
36
+ in Float
37
+ "number"
38
+ in Symbol
39
+ "string"
40
+ end
41
+ end
42
+ .uniq
43
+
44
+ {
45
+ type: types.length == 1 ? types.first : types,
46
+ enum: values.map { _1.is_a?(Symbol) ? _1.to_s : _1 }
47
+ }
48
+ end
49
+ end
50
+
51
+ private_class_method :new
52
+
53
+ def self.[](...) = new(...)
54
+
55
+ # @return [Array<generic<Value>>]
56
+ attr_reader :values
57
+
58
+ # @param values [Array<generic<Value>>]
59
+ def initialize(*values) = (@values = values.map { _1.is_a?(String) ? _1.to_sym : _1 })
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # To customize the JSON schema conversion for a type, implement the `JsonSchemaConverter` interface.
7
+ module JsonSchemaConverter
8
+ # @api private
9
+ POINTERS = Object.new.tap do
10
+ _1.define_singleton_method(:inspect) do
11
+ "#<#{Anthropic::Helpers::InputSchema::JsonSchemaConverter}::POINTERS>"
12
+ end
13
+ end.freeze
14
+ # @api private
15
+ NO_REF = Object.new.tap do
16
+ _1.define_singleton_method(:inspect) do
17
+ "#<#{Anthropic::Helpers::InputSchema::JsonSchemaConverter}::NO_REF>"
18
+ end
19
+ end.freeze
20
+
21
+ # rubocop:disable Lint/UnusedMethodArgument
22
+
23
+ # The exact JSON schema produced is subject to improvement between minor release versions.
24
+ #
25
+ # @param state [Hash{Symbol=>Object}]
26
+ #
27
+ # @option state [Hash{Object=>String}] :defs
28
+ #
29
+ # @option state [Array<String>] :path
30
+ #
31
+ # @return [Hash{Symbol=>Object}]
32
+ def to_json_schema_inner(state:) = (raise NotImplementedError)
33
+
34
+ # rubocop:enable Lint/UnusedMethodArgument
35
+
36
+ # Internal helpers methods.
37
+ class << self
38
+ # @api private
39
+ #
40
+ # @param schema [Hash{Symbol=>Object}]
41
+ #
42
+ # @return [Hash{Symbol=>Object}]
43
+ def to_nilable(schema)
44
+ null = "null"
45
+ case schema
46
+ in {"$ref": String} | {allOf: _}
47
+ # For references (simple or with allOf pattern for descriptions),
48
+ # wrap in anyOf with null. The allOf pattern is used when we need
49
+ # to add a description to a $ref (JSON Schema doesn't allow
50
+ # additional properties alongside $ref).
51
+ {anyOf: [schema, {type: null}]}
52
+ in {anyOf: schemas}
53
+ null = {type: null}
54
+ schemas.any? { _1 == null || _1 == {type: ["null"]} } ? schema : {anyOf: [*schemas, null]}
55
+ in {type: String => type}
56
+ type == null ? schema : schema.update(type: [type, null])
57
+ in {type: Array => types}
58
+ types.include?(null) ? schema : schema.update(type: [*types, null])
59
+ end
60
+ end
61
+
62
+ # @api private
63
+ #
64
+ # @param schema [Hash{Symbol=>Object}]
65
+ def assoc_meta!(schema, meta:)
66
+ xformed = meta.transform_keys(Anthropic::Helpers::InputSchema::PROPERTY_MAPPING)
67
+ schema.merge!(xformed)
68
+ end
69
+
70
+ # @api private
71
+ #
72
+ # @param state [Hash{Symbol=>Object}]
73
+ #
74
+ # @option state [Hash{Object=>String}] :defs
75
+ #
76
+ # @option state [Array<String>] :path
77
+ #
78
+ # @param type [Object]
79
+ #
80
+ # @param blk [Proc]
81
+ #
82
+ def cache_def!(state, type:, &blk)
83
+ defs, path = state.fetch_values(:defs, :path)
84
+ if (stored = defs[type])
85
+ pointers = stored.fetch(Anthropic::Helpers::InputSchema::JsonSchemaConverter::POINTERS)
86
+ pointers.first.except(Anthropic::Helpers::InputSchema::JsonSchemaConverter::NO_REF).tap do
87
+ pointers << _1
88
+ end
89
+ else
90
+ ref_path = String.new
91
+ ref = {"$ref": ref_path}
92
+ stored = {
93
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter::POINTERS => [ref]
94
+ }
95
+ defs.store(type, stored)
96
+ schema = blk.call
97
+ ref_path.replace("#/$defs/#{path.join('/')}")
98
+ stored.update(schema)
99
+ ref
100
+ end
101
+ end
102
+
103
+ # @api private
104
+ #
105
+ # @param type [Anthropic::Helpers::InputSchema::JsonSchemaConverter, Class]
106
+ #
107
+ # @return [Hash{Symbol=>Object}]
108
+ def to_json_schema(type)
109
+ defs = {}
110
+ state = {defs: defs, path: []}
111
+ schema = Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_json_schema_inner(
112
+ type,
113
+ state: state
114
+ )
115
+ reused_defs = {}
116
+ defs.each_value do |acc|
117
+ sch = acc.except(Anthropic::Helpers::InputSchema::JsonSchemaConverter::POINTERS)
118
+ pointers = acc.fetch(Anthropic::Helpers::InputSchema::JsonSchemaConverter::POINTERS)
119
+
120
+ no_refs, refs = pointers.partition do
121
+ _1.delete(Anthropic::Helpers::InputSchema::JsonSchemaConverter::NO_REF)
122
+ end
123
+
124
+ case refs
125
+ in [ref]
126
+ ref.replace(ref.except(:$ref).merge(sch))
127
+ in [_, ref, *]
128
+ reused_defs.store(ref.fetch(:$ref), sch)
129
+ refs.each do
130
+ next if (meta = _1.except(:$ref)).empty?
131
+ # JSON Schema does not allow keyword properties to be defined alongside a $ref.
132
+ # If we have a keyword property associated with a $ref, it must be wrapped in an allOf.
133
+ _1.replace(allOf: [_1.slice(:$ref), meta])
134
+ end
135
+ else
136
+ end
137
+ no_refs.each { _1.replace(_1.except(:$ref).merge(sch)) }
138
+ end
139
+
140
+ xformed = reused_defs.transform_keys { _1.delete_prefix("#/$defs/") }
141
+ xformed.empty? ? schema : {"$defs": xformed}.update(schema)
142
+ end
143
+
144
+ # @api private
145
+ #
146
+ # @param type [Anthropic::Helpers::InputSchema::JsonSchemaConverter, Class]
147
+ #
148
+ # @param state [Hash{Symbol=>Object}]
149
+ #
150
+ # @option state [Hash{Object=>String}] :defs
151
+ #
152
+ # @option state [Array<String>] :path
153
+ #
154
+ # @return [Hash{Symbol=>Object}]
155
+ def to_json_schema_inner(type, state:)
156
+ case type
157
+ in {"$ref": String}
158
+ return type
159
+ in Anthropic::Helpers::InputSchema::JsonSchemaConverter
160
+ return type.to_json_schema_inner(state: state)
161
+ in Class
162
+ case type
163
+ in -> { _1 <= NilClass }
164
+ return {type: "null"}
165
+ in -> { _1 <= Integer }
166
+ return {type: "integer"}
167
+ in -> { _1 <= Float }
168
+ return {type: "number"}
169
+ in -> { _1 <= Symbol || _1 <= String }
170
+ return {type: "string"}
171
+ else
172
+ end
173
+ in _ if Anthropic::Internal::Util.primitive?(type)
174
+ return {const: type.is_a?(Symbol) ? type.to_s : type}
175
+ else
176
+ end
177
+
178
+ models = %w[
179
+ NilClass
180
+ String
181
+ Symbol
182
+ Integer
183
+ Float
184
+ Anthropic::Boolean
185
+ Anthropic::ArrayOf
186
+ Anthropic::EnumOf
187
+ Anthropic::UnionOf
188
+ Anthropic::BaseModel
189
+ ]
190
+ # rubocop:disable Layout/LineLength
191
+ message = "#{type} does not implement the #{Anthropic::Helpers::InputSchema::JsonSchemaConverter} interface. Please use one of the supported types: #{models}"
192
+ # rubocop:enable Layout/LineLength
193
+ raise ArgumentError.new(message)
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # @abstract
7
+ #
8
+ # Like Anthropic::Internal::Type::Unknown, but for parsed JSON values, which can be incomplete or malformed.
9
+ class ParsedJson < Anthropic::Internal::Type::Unknown
10
+ class << self
11
+ # @api private
12
+ #
13
+ # No coercion needed for Unknown type.
14
+ #
15
+ # @param value [Object]
16
+ #
17
+ # @param state [Hash{Symbol=>Object}] .
18
+ #
19
+ # @option state [Boolean] :translate_names
20
+ #
21
+ # @option state [Boolean] :strictness
22
+ #
23
+ # @option state [Hash{Symbol=>Object}] :exactness
24
+ #
25
+ # @option state [Class<StandardError>] :error
26
+ #
27
+ # @option state [Integer] :branched
28
+ #
29
+ # @return [Object]
30
+ def coerce(value, state:)
31
+ (state[:error] = value) if value.is_a?(StandardError)
32
+
33
+ super
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # rubocop:disable Style/MutableConstant
7
+ PROPERTY_MAPPING = {
8
+ # Numeric properties:
9
+ minimum: :minimum,
10
+ maximum: :maximum,
11
+ exclusive_minimum: :exclusiveMinimum,
12
+ exclusive_maximum: :exclusiveMaximum,
13
+ multiple_of: :multipleOf,
14
+
15
+ # String properties:
16
+ min_length: :minLength,
17
+ max_length: :maxLength,
18
+ pattern: :pattern,
19
+ format: :format,
20
+ content_media_type: :contentMediaType,
21
+ content_encoding: :contentEncoding,
22
+
23
+ # Array properties:
24
+ min_items: :minItems,
25
+ max_items: :maxItems,
26
+ unique_items: :uniqueItems,
27
+ prefix_items: :prefixItems,
28
+ contains: :contains,
29
+ min_contains: :minContains,
30
+ max_contains: :maxContains,
31
+
32
+ # Object properties:
33
+ pattern_properties: :patternProperties,
34
+ dependent_schemas: :dependentSchemas,
35
+ dependent_required: :dependentRequired,
36
+ property_names: :propertyNames,
37
+
38
+ # Metadata:
39
+ default: :default,
40
+ examples: :examples,
41
+
42
+ doc: :description
43
+ }
44
+ # rubocop:enable Style/MutableConstant
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ module InputSchema
6
+ # @generic Member
7
+ #
8
+ # @example
9
+ # example = Anthropic::UnionOf[Float, Anthropic::ArrayOf[Integer]]
10
+ class UnionOf
11
+ include Anthropic::Internal::Type::Union
12
+ include Anthropic::Helpers::InputSchema::JsonSchemaConverter
13
+
14
+ # @api private
15
+ #
16
+ # @param state [Hash{Symbol=>Object}]
17
+ #
18
+ # @option state [Hash{Object=>String}] :defs
19
+ #
20
+ # @option state [Array<String>] :path
21
+ #
22
+ # @return [Hash{Symbol=>Object}]
23
+ def to_json_schema_inner(state:)
24
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.cache_def!(state, type: self) do
25
+ path = state.fetch(:path)
26
+ mergeable_keys = {[:anyOf] => 0, [:type] => 0}
27
+ schemas = variants.to_enum.with_index.map do
28
+ new_state = {**state, path: [*path, "?.#{_2}"]}
29
+ Anthropic::Helpers::InputSchema::JsonSchemaConverter.to_json_schema_inner(
30
+ _1,
31
+ state: new_state
32
+ )
33
+ end
34
+
35
+ schemas.each do |schema|
36
+ mergeable_keys.each_key { mergeable_keys[_1] += 1 if schema.keys == _1 }
37
+ end
38
+ mergeable = mergeable_keys.any? { _1.last == schemas.length }
39
+ mergeable ? Anthropic::Internal::Util.deep_merge(*schemas, concat: true) : {anyOf: schemas}
40
+ end
41
+ end
42
+
43
+ private_class_method :new
44
+
45
+ def self.[](...) = new(...)
46
+
47
+ # @param variants [Array<generic<Member>>]
48
+ def initialize(*variants)
49
+ variants.each do |v|
50
+ v.is_a?(Proc) ? variant(v) : variant(-> { v })
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anthropic
4
+ module Helpers
5
+ # Helpers for the structured output API.
6
+ #
7
+ # see https://platform.Anthropic.com/docs/guides/structured-outputs
8
+ # see https://json-schema.org
9
+ #
10
+ # Based on the DSL in {Anthropic::Internal::Type}, but currently only support the limited subset of JSON schema types used in structured output APIs.
11
+ #
12
+ # Supported types: {NilClass} {String} {Symbol} {Integer} {Float} {Anthropic::Boolean}, {Anthropic::EnumOf}, {Anthropic::UnionOf}, {Anthropic::ArrayOf}, {Anthropic::BaseModel}
13
+ module InputSchema
14
+ end
15
+ end
16
+ end