anthropic 1.1.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +123 -0
- data/README.md +32 -16
- data/lib/anthropic/client.rb +5 -2
- data/lib/anthropic/errors.rb +22 -0
- data/lib/anthropic/helpers/bedrock/client.rb +34 -4
- data/lib/anthropic/helpers/streaming/events.rb +141 -0
- data/lib/anthropic/helpers/streaming/message_stream.rb +238 -0
- data/lib/anthropic/helpers/streaming.rb +37 -0
- data/lib/anthropic/helpers/vertex/client.rb +4 -1
- data/lib/anthropic/internal/stream.rb +4 -2
- data/lib/anthropic/internal/transport/base_client.rb +29 -3
- data/lib/anthropic/internal/type/array_of.rb +7 -1
- data/lib/anthropic/internal/type/base_model.rb +80 -24
- data/lib/anthropic/internal/type/base_stream.rb +3 -1
- data/lib/anthropic/internal/type/boolean.rb +7 -1
- data/lib/anthropic/internal/type/converter.rb +69 -34
- data/lib/anthropic/internal/type/enum.rb +16 -5
- data/lib/anthropic/internal/type/file_input.rb +6 -1
- data/lib/anthropic/internal/type/hash_of.rb +7 -1
- data/lib/anthropic/internal/type/union.rb +26 -16
- data/lib/anthropic/internal/type/unknown.rb +7 -1
- data/lib/anthropic/internal/util.rb +8 -9
- data/lib/anthropic/models/anthropic_beta.rb +3 -0
- data/lib/anthropic/models/beta/beta_base64_pdf_block.rb +1 -65
- data/lib/anthropic/models/beta/beta_citation_char_location.rb +7 -1
- data/lib/anthropic/models/beta/beta_citation_content_block_location.rb +7 -1
- data/lib/anthropic/models/beta/beta_citation_page_location.rb +7 -1
- data/lib/anthropic/models/beta/beta_citation_search_result_location.rb +55 -0
- data/lib/anthropic/models/beta/beta_citation_search_result_location_param.rb +55 -0
- data/lib/anthropic/models/beta/beta_citations_delta.rb +5 -3
- data/lib/anthropic/models/beta/beta_content_block.rb +5 -5
- data/lib/anthropic/models/beta/beta_content_block_param.rb +20 -17
- data/lib/anthropic/models/beta/beta_message.rb +6 -2
- data/lib/anthropic/models/beta/beta_message_param.rb +3 -3
- data/lib/anthropic/models/beta/beta_raw_content_block_start_event.rb +7 -7
- data/lib/anthropic/models/beta/beta_request_document_block.rb +75 -0
- data/lib/anthropic/models/beta/beta_search_result_block_param.rb +55 -0
- data/lib/anthropic/models/beta/beta_text_block.rb +2 -2
- data/lib/anthropic/models/beta/beta_text_block_param.rb +2 -2
- data/lib/anthropic/models/beta/beta_text_citation.rb +3 -1
- data/lib/anthropic/models/beta/beta_text_citation_param.rb +3 -1
- data/lib/anthropic/models/beta/beta_tool.rb +7 -1
- data/lib/anthropic/models/beta/beta_tool_result_block_param.rb +6 -4
- data/lib/anthropic/models/beta/beta_tool_text_editor_20250728.rb +49 -0
- data/lib/anthropic/models/beta/beta_tool_union.rb +9 -7
- data/lib/anthropic/models/beta/message_count_tokens_params.rb +18 -10
- data/lib/anthropic/models/beta/message_create_params.rb +9 -3
- data/lib/anthropic/models/beta/messages/batch_create_params.rb +9 -3
- data/lib/anthropic/models/citation_char_location.rb +7 -1
- data/lib/anthropic/models/citation_content_block_location.rb +7 -1
- data/lib/anthropic/models/citation_page_location.rb +7 -1
- data/lib/anthropic/models/citation_search_result_location_param.rb +51 -0
- data/lib/anthropic/models/citations_delta.rb +5 -3
- data/lib/anthropic/models/citations_search_result_location.rb +51 -0
- data/lib/anthropic/models/content_block.rb +5 -5
- data/lib/anthropic/models/content_block_param.rb +14 -11
- data/lib/anthropic/models/message.rb +6 -2
- data/lib/anthropic/models/message_count_tokens_params.rb +9 -3
- data/lib/anthropic/models/message_count_tokens_tool.rb +5 -1
- data/lib/anthropic/models/message_create_params.rb +9 -3
- data/lib/anthropic/models/message_param.rb +3 -3
- data/lib/anthropic/models/messages/batch_create_params.rb +9 -3
- data/lib/anthropic/models/model.rb +10 -21
- data/lib/anthropic/models/raw_content_block_start_event.rb +7 -7
- data/lib/anthropic/models/search_result_block_param.rb +51 -0
- data/lib/anthropic/models/text_block.rb +2 -2
- data/lib/anthropic/models/text_block_param.rb +2 -2
- data/lib/anthropic/models/text_citation.rb +3 -1
- data/lib/anthropic/models/text_citation_param.rb +3 -1
- data/lib/anthropic/models/tool.rb +7 -1
- data/lib/anthropic/models/tool_result_block_param.rb +6 -4
- data/lib/anthropic/models/tool_text_editor_20250429.rb +36 -0
- data/lib/anthropic/models/tool_text_editor_20250728.rb +45 -0
- data/lib/anthropic/models/tool_union.rb +5 -1
- data/lib/anthropic/models/tool_use_block.rb +6 -0
- data/lib/anthropic/models.rb +14 -4
- data/lib/anthropic/resources/beta/messages.rb +73 -6
- data/lib/anthropic/resources/messages.rb +68 -7
- data/lib/anthropic/streaming.rb +5 -0
- data/lib/anthropic/version.rb +1 -1
- data/lib/anthropic.rb +14 -0
- data/rbi/anthropic/errors.rbi +16 -0
- data/rbi/anthropic/helpers/bedrock/client.rbi +17 -6
- data/rbi/anthropic/helpers/streaming/events.rbi +95 -0
- data/rbi/anthropic/helpers/streaming/message_stream.rbi +73 -0
- data/rbi/anthropic/helpers/vertex/client.rbi +17 -6
- data/rbi/anthropic/internal/transport/base_client.rbi +1 -1
- data/rbi/anthropic/internal/type/base_stream.rbi +8 -1
- data/rbi/anthropic/internal/type/boolean.rbi +2 -0
- data/rbi/anthropic/internal/type/converter.rbi +69 -15
- data/rbi/anthropic/internal/type/union.rbi +14 -2
- data/rbi/anthropic/internal/type/unknown.rbi +2 -0
- data/rbi/anthropic/internal/util.rbi +2 -0
- data/rbi/anthropic/models/anthropic_beta.rbi +2 -0
- data/rbi/anthropic/models/beta/beta_base64_pdf_block.rbi +1 -128
- data/rbi/anthropic/models/beta/beta_citation_char_location.rbi +6 -0
- data/rbi/anthropic/models/beta/beta_citation_content_block_location.rbi +6 -0
- data/rbi/anthropic/models/beta/beta_citation_page_location.rbi +6 -0
- data/rbi/anthropic/models/beta/beta_citation_search_result_location.rbi +78 -0
- data/rbi/anthropic/models/beta/beta_citation_search_result_location_param.rbi +79 -0
- data/rbi/anthropic/models/beta/beta_citations_delta.rbi +4 -2
- data/rbi/anthropic/models/beta/beta_content_block.rbi +3 -3
- data/rbi/anthropic/models/beta/beta_content_block_param.rbi +8 -7
- data/rbi/anthropic/models/beta/beta_message.rbi +11 -3
- data/rbi/anthropic/models/beta/beta_raw_content_block_start_event.rbi +6 -6
- data/rbi/anthropic/models/beta/beta_request_document_block.rbi +140 -0
- data/rbi/anthropic/models/beta/beta_search_result_block_param.rbi +91 -0
- data/rbi/anthropic/models/beta/beta_text_block.rbi +2 -1
- data/rbi/anthropic/models/beta/beta_text_block_param.rbi +6 -3
- data/rbi/anthropic/models/beta/beta_text_citation.rbi +2 -1
- data/rbi/anthropic/models/beta/beta_text_citation_param.rbi +2 -1
- data/rbi/anthropic/models/beta/beta_tool.rbi +14 -5
- data/rbi/anthropic/models/beta/beta_tool_result_block_param.rbi +2 -1
- data/rbi/anthropic/models/beta/beta_tool_text_editor_20250728.rbi +82 -0
- data/rbi/anthropic/models/beta/beta_tool_union.rbi +6 -5
- data/rbi/anthropic/models/beta/message_count_tokens_params.rbi +44 -27
- data/rbi/anthropic/models/beta/message_create_params.rbi +38 -22
- data/rbi/anthropic/models/beta/messages/batch_create_params.rbi +38 -22
- data/rbi/anthropic/models/citation_char_location.rbi +6 -0
- data/rbi/anthropic/models/citation_content_block_location.rbi +6 -0
- data/rbi/anthropic/models/citation_page_location.rbi +6 -0
- data/rbi/anthropic/models/citation_search_result_location_param.rbi +74 -0
- data/rbi/anthropic/models/citations_delta.rbi +4 -2
- data/rbi/anthropic/models/citations_search_result_location.rbi +74 -0
- data/rbi/anthropic/models/content_block.rbi +3 -3
- data/rbi/anthropic/models/content_block_param.rbi +6 -5
- data/rbi/anthropic/models/message.rbi +11 -3
- data/rbi/anthropic/models/message_count_tokens_params.rbi +22 -2
- data/rbi/anthropic/models/message_count_tokens_tool.rbi +2 -0
- data/rbi/anthropic/models/message_create_params.rbi +22 -2
- data/rbi/anthropic/models/messages/batch_create_params.rbi +22 -2
- data/rbi/anthropic/models/model.rbi +4 -8
- data/rbi/anthropic/models/raw_content_block_start_event.rbi +6 -6
- data/rbi/anthropic/models/search_result_block_param.rbi +77 -0
- data/rbi/anthropic/models/text_block.rbi +2 -1
- data/rbi/anthropic/models/text_block_param.rbi +6 -3
- data/rbi/anthropic/models/text_citation.rbi +2 -1
- data/rbi/anthropic/models/text_citation_param.rbi +2 -1
- data/rbi/anthropic/models/tool.rbi +16 -5
- data/rbi/anthropic/models/tool_result_block_param.rbi +5 -1
- data/rbi/anthropic/models/tool_text_editor_20250429.rbi +62 -0
- data/rbi/anthropic/models/tool_text_editor_20250728.rbi +72 -0
- data/rbi/anthropic/models/tool_union.rbi +2 -0
- data/rbi/anthropic/models.rbi +12 -0
- data/rbi/anthropic/resources/beta/messages.rbi +39 -18
- data/rbi/anthropic/resources/messages.rbi +318 -3
- data/rbi/anthropic/streaming.rbi +5 -0
- data/sig/anthropic/errors.rbs +9 -0
- data/sig/anthropic/helpers/streaming/events.rbs +117 -0
- data/sig/anthropic/helpers/streaming/message_stream.rbs +57 -0
- data/sig/anthropic/internal/transport/base_client.rbs +1 -1
- data/sig/anthropic/internal/type/base_stream.rbs +4 -0
- data/sig/anthropic/internal/type/converter.rbs +24 -1
- data/sig/anthropic/internal/type/union.rbs +2 -2
- data/sig/anthropic/models/anthropic_beta.rbs +2 -0
- data/sig/anthropic/models/beta/beta_base64_pdf_block.rbs +1 -58
- data/sig/anthropic/models/beta/beta_citation_char_location.rbs +5 -0
- data/sig/anthropic/models/beta/beta_citation_content_block_location.rbs +5 -0
- data/sig/anthropic/models/beta/beta_citation_page_location.rbs +5 -0
- data/sig/anthropic/models/beta/beta_citation_search_result_location.rbs +54 -0
- data/sig/anthropic/models/beta/beta_citation_search_result_location_param.rbs +54 -0
- data/sig/anthropic/models/beta/beta_citations_delta.rbs +1 -0
- data/sig/anthropic/models/beta/beta_content_block.rbs +2 -2
- data/sig/anthropic/models/beta/beta_content_block_param.rbs +9 -8
- data/sig/anthropic/models/beta/beta_raw_content_block_start_event.rbs +2 -2
- data/sig/anthropic/models/beta/beta_request_document_block.rbs +66 -0
- data/sig/anthropic/models/beta/beta_search_result_block_param.rbs +53 -0
- data/sig/anthropic/models/beta/beta_text_citation.rbs +1 -0
- data/sig/anthropic/models/beta/beta_text_citation_param.rbs +1 -0
- data/sig/anthropic/models/beta/beta_tool.rbs +14 -3
- data/sig/anthropic/models/beta/beta_tool_result_block_param.rbs +1 -0
- data/sig/anthropic/models/beta/beta_tool_text_editor_20250728.rbs +39 -0
- data/sig/anthropic/models/beta/beta_tool_union.rbs +5 -4
- data/sig/anthropic/models/beta/message_count_tokens_params.rbs +5 -4
- data/sig/anthropic/models/citation_char_location.rbs +5 -0
- data/sig/anthropic/models/citation_content_block_location.rbs +5 -0
- data/sig/anthropic/models/citation_page_location.rbs +5 -0
- data/sig/anthropic/models/citation_search_result_location_param.rbs +50 -0
- data/sig/anthropic/models/citations_delta.rbs +1 -0
- data/sig/anthropic/models/citations_search_result_location.rbs +50 -0
- data/sig/anthropic/models/content_block.rbs +2 -2
- data/sig/anthropic/models/content_block_param.rbs +6 -5
- data/sig/anthropic/models/message_count_tokens_tool.rbs +2 -0
- data/sig/anthropic/models/model.rbs +4 -10
- data/sig/anthropic/models/raw_content_block_start_event.rbs +2 -2
- data/sig/anthropic/models/search_result_block_param.rbs +49 -0
- data/sig/anthropic/models/text_citation.rbs +1 -0
- data/sig/anthropic/models/text_citation_param.rbs +1 -0
- data/sig/anthropic/models/tool.rbs +14 -3
- data/sig/anthropic/models/tool_result_block_param.rbs +4 -1
- data/sig/anthropic/models/tool_text_editor_20250429.rbs +30 -0
- data/sig/anthropic/models/tool_text_editor_20250728.rbs +35 -0
- data/sig/anthropic/models/tool_union.rbs +2 -0
- data/sig/anthropic/models.rbs +10 -0
- data/sig/anthropic/streaming.rbs +3 -0
- metadata +44 -3
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Anthropic
|
|
4
|
+
module Helpers
|
|
5
|
+
module Streaming
|
|
6
|
+
# @api private
|
|
7
|
+
#
|
|
8
|
+
# MessageStream provides a Ruby Enumerable interface over Server-Sent Events from
|
|
9
|
+
# the Anthropic API, yielding a mix of raw streaming events and higher-level typed
|
|
10
|
+
# events while maintaining accumulated message state throughout the stream lifecycle.
|
|
11
|
+
#
|
|
12
|
+
#
|
|
13
|
+
# @generic Elem
|
|
14
|
+
class MessageStream
|
|
15
|
+
include Anthropic::Internal::Type::BaseStream
|
|
16
|
+
|
|
17
|
+
# @api private
|
|
18
|
+
#
|
|
19
|
+
# Consumes raw stream events and yields a mix of raw and higher-level typed events while
|
|
20
|
+
# maintaining accumulated message state. This is what's called when you run `each` on the
|
|
21
|
+
# stream.
|
|
22
|
+
#
|
|
23
|
+
# @return [Enumerable<generic<Elem>>]
|
|
24
|
+
private def iterator
|
|
25
|
+
@iterator ||= Anthropic::Internal::Util.chain_fused(@stream) do |y|
|
|
26
|
+
@raw_stream.each do |raw_event|
|
|
27
|
+
@accumated_message_snapshot = accumulate_event(
|
|
28
|
+
event: raw_event,
|
|
29
|
+
current_snapshot: @accumated_message_snapshot
|
|
30
|
+
)
|
|
31
|
+
events_to_yield = build_events(event: raw_event, message_snapshot: @accumated_message_snapshot)
|
|
32
|
+
events_to_yield.each(&y)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @api public
|
|
38
|
+
#
|
|
39
|
+
# Blocks until the stream has been consumed
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
def until_done = each {} # rubocop:disable Lint/EmptyBlock
|
|
43
|
+
|
|
44
|
+
# @api public
|
|
45
|
+
#
|
|
46
|
+
# Returns an enumerable of text deltas from the streaming response.
|
|
47
|
+
#
|
|
48
|
+
# @return [Enumerable<String>]
|
|
49
|
+
def text
|
|
50
|
+
Anthropic::Internal::Util.chain_fused(@iterator) do |y|
|
|
51
|
+
@iterator.each do |event|
|
|
52
|
+
if event.type == :content_block_delta && event.delta.type == :text_delta
|
|
53
|
+
y << event.delta.text
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @api public
|
|
60
|
+
#
|
|
61
|
+
# Returns the complete accumulated Message object after stream completion.
|
|
62
|
+
#
|
|
63
|
+
# @return [Anthropic::Models::Message]
|
|
64
|
+
def accumulated_message
|
|
65
|
+
until_done
|
|
66
|
+
@accumated_message_snapshot
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @api public
|
|
70
|
+
#
|
|
71
|
+
# Returns all text content blocks concatenated into a single string.
|
|
72
|
+
# NOTE: Currently the API will only respond with a single content block.
|
|
73
|
+
#
|
|
74
|
+
# Will raise an error if no `text` content blocks were returned.
|
|
75
|
+
# @return [String]
|
|
76
|
+
def accumulated_text
|
|
77
|
+
message = accumulated_message
|
|
78
|
+
text_blocks = []
|
|
79
|
+
message.content.each do |block|
|
|
80
|
+
if block.type == :text
|
|
81
|
+
text_blocks << block.text
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if text_blocks.empty?
|
|
86
|
+
raise RuntimeError.new("Expected to have received at least 1 text block")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
text_blocks.join
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @api private
|
|
93
|
+
#
|
|
94
|
+
# Builds up a complete Message object as streaming events arrive.
|
|
95
|
+
#
|
|
96
|
+
# @param event [Anthropic::Models::RawMessageStreamEvent] the raw streaming event to process
|
|
97
|
+
# @param current_snapshot [Anthropic::Models::Message, nil] current accumulated message state
|
|
98
|
+
#
|
|
99
|
+
# @return [Anthropic::Models::Message] updated message snapshot with event applied
|
|
100
|
+
private def accumulate_event(event:, current_snapshot:)
|
|
101
|
+
unless event in Anthropic::Models::RawMessageStreamEvent
|
|
102
|
+
message = "Expected event to be a variant of RawMessageStreamEvent, got #{event.class}"
|
|
103
|
+
raise ArgumentError.new(message)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if current_snapshot.nil?
|
|
107
|
+
return event.message if event.type == :message_start
|
|
108
|
+
|
|
109
|
+
message = "Unexpected event order, got \"#{event.type}\" before \":message_start\""
|
|
110
|
+
raise RuntimeError.new(message)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
case event
|
|
114
|
+
in Anthropic::Models::RawMessageStartEvent
|
|
115
|
+
# Use the converter to create a new, isolated copy of the message object.
|
|
116
|
+
# This ensures proper type validation and prevents shared object references
|
|
117
|
+
# that could lead to unintended mutations during streaming accumulation.
|
|
118
|
+
# Matches the Python SDK's approach of explicitly constructing Message objects.
|
|
119
|
+
return Anthropic::Internal::Type::Converter.coerce(Anthropic::Models::Message, event.message)
|
|
120
|
+
in Anthropic::Models::RawContentBlockStartEvent
|
|
121
|
+
current_snapshot.content = (current_snapshot.content || []) + [event.content_block]
|
|
122
|
+
in Anthropic::Models::RawContentBlockDeltaEvent
|
|
123
|
+
content = current_snapshot.content[event.index]
|
|
124
|
+
|
|
125
|
+
case (delta = event.delta)
|
|
126
|
+
in Anthropic::Models::TextDelta if content.type == :text
|
|
127
|
+
content.text += delta.text
|
|
128
|
+
in Anthropic::Models::InputJSONDelta if content.type == :tool_use
|
|
129
|
+
json_buf = content.json_buf.to_s
|
|
130
|
+
json_buf += delta.partial_json
|
|
131
|
+
|
|
132
|
+
content.input = json_buf
|
|
133
|
+
content.json_buf = json_buf
|
|
134
|
+
in Anthropic::Models::CitationsDelta if content.type == :text
|
|
135
|
+
content.citations ||= []
|
|
136
|
+
content.citations << delta.citation
|
|
137
|
+
in Anthropic::Models::ThinkingDelta if content.type == :thinking
|
|
138
|
+
content.thinking += delta.thinking
|
|
139
|
+
in Anthropic::Models::SignatureDelta if content.type == :thinking
|
|
140
|
+
content.signature = delta.signature
|
|
141
|
+
else
|
|
142
|
+
end
|
|
143
|
+
in Anthropic::Models::RawMessageDeltaEvent
|
|
144
|
+
current_snapshot.stop_reason = event.delta.stop_reason
|
|
145
|
+
current_snapshot.stop_sequence = event.delta.stop_sequence
|
|
146
|
+
current_snapshot.usage.output_tokens = event.usage.output_tokens
|
|
147
|
+
else
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
current_snapshot
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @api private
|
|
154
|
+
#
|
|
155
|
+
# Determines which events to yield for a given raw streaming event.
|
|
156
|
+
#
|
|
157
|
+
# May transform events into higher-level types (TextEvent, InputJsonEvent),
|
|
158
|
+
# pass through raw events unchanged, or produce multiple events.
|
|
159
|
+
#
|
|
160
|
+
# @param event [Anthropic::Models::RawMessageStreamEvent] the raw event to process
|
|
161
|
+
# @param message_snapshot [Anthropic::Models::Message] current accumulated message state
|
|
162
|
+
#
|
|
163
|
+
# @return [Array<Object>] events to yield (mix of raw and typed events)
|
|
164
|
+
private def build_events(event:, message_snapshot:)
|
|
165
|
+
events_to_yield = []
|
|
166
|
+
|
|
167
|
+
case event
|
|
168
|
+
in Anthropic::Models::RawMessageStopEvent
|
|
169
|
+
events_to_yield << MessageStopEvent.new(
|
|
170
|
+
type: :message_stop,
|
|
171
|
+
message: message_snapshot
|
|
172
|
+
)
|
|
173
|
+
in Anthropic::Models::RawContentBlockDeltaEvent
|
|
174
|
+
events_to_yield << event
|
|
175
|
+
content_block = message_snapshot.content[event.index]
|
|
176
|
+
|
|
177
|
+
case (delta = event.delta)
|
|
178
|
+
in Anthropic::Models::TextDelta if content_block.type == :text
|
|
179
|
+
events_to_yield << Anthropic::Streaming::TextEvent.new(
|
|
180
|
+
type: :text,
|
|
181
|
+
text: delta.text,
|
|
182
|
+
snapshot: content_block.text
|
|
183
|
+
)
|
|
184
|
+
in Anthropic::Models::InputJSONDelta if content_block.type == :tool_use
|
|
185
|
+
events_to_yield << Anthropic::Streaming::InputJsonEvent.new(
|
|
186
|
+
type: :input_json,
|
|
187
|
+
partial_json: delta.partial_json,
|
|
188
|
+
snapshot: content_block.input
|
|
189
|
+
)
|
|
190
|
+
in Anthropic::Models::CitationsDelta if content_block.type == :text
|
|
191
|
+
events_to_yield << Anthropic::Streaming::CitationEvent.new(
|
|
192
|
+
type: :citation,
|
|
193
|
+
citation: delta.citation,
|
|
194
|
+
snapshot: content_block.citations || []
|
|
195
|
+
)
|
|
196
|
+
in Anthropic::Models::ThinkingDelta if content_block.type == :thinking
|
|
197
|
+
events_to_yield << Anthropic::Streaming::ThinkingEvent.new(
|
|
198
|
+
type: :thinking,
|
|
199
|
+
thinking: delta.thinking,
|
|
200
|
+
snapshot: content_block.thinking
|
|
201
|
+
)
|
|
202
|
+
in Anthropic::Models::SignatureDelta if content_block.type == :thinking
|
|
203
|
+
events_to_yield << Anthropic::Streaming::SignatureEvent.new(
|
|
204
|
+
type: :signature,
|
|
205
|
+
signature: content_block.signature
|
|
206
|
+
)
|
|
207
|
+
else
|
|
208
|
+
end
|
|
209
|
+
in Anthropic::Models::RawContentBlockStopEvent
|
|
210
|
+
content_block = message_snapshot.content[event.index]
|
|
211
|
+
|
|
212
|
+
events_to_yield << ContentBlockStopEvent.new(
|
|
213
|
+
type: :content_block_stop,
|
|
214
|
+
index: event.index,
|
|
215
|
+
content_block: content_block
|
|
216
|
+
)
|
|
217
|
+
else
|
|
218
|
+
events_to_yield << event
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
events_to_yield
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @api private
|
|
225
|
+
#
|
|
226
|
+
# @param raw_stream [Anthropic::Internal::Type::BaseStream]
|
|
227
|
+
def initialize(raw_stream:)
|
|
228
|
+
# The underlying Server-Sent Event stream from the Anthropic API.
|
|
229
|
+
@raw_stream = raw_stream
|
|
230
|
+
# Accumulated message state that builds up as events are processed.
|
|
231
|
+
@accumated_message_snapshot = nil
|
|
232
|
+
# Lazy enumerable that transforms raw events into consumable events.
|
|
233
|
+
@iterator = iterator
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Anthropic
|
|
4
|
+
module Helpers
|
|
5
|
+
module Streaming
|
|
6
|
+
extend Anthropic::Internal::Util::SorbetRuntimeSupport
|
|
7
|
+
|
|
8
|
+
define_sorbet_constant!(:RawMessageEvent) do
|
|
9
|
+
T.type_alias do
|
|
10
|
+
T.any(
|
|
11
|
+
Anthropic::Models::RawMessageStartEvent,
|
|
12
|
+
Anthropic::Models::RawMessageDeltaEvent,
|
|
13
|
+
Anthropic::Models::RawMessageStopEvent,
|
|
14
|
+
Anthropic::Models::RawContentBlockStartEvent,
|
|
15
|
+
Anthropic::Models::RawContentBlockDeltaEvent,
|
|
16
|
+
Anthropic::Models::RawContentBlockStopEvent
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
define_sorbet_constant!(:StreamEvent) do
|
|
22
|
+
T.type_alias do
|
|
23
|
+
T.any(
|
|
24
|
+
Anthropic::Streaming::RawMessageEvent,
|
|
25
|
+
Anthropic::Streaming::TextEvent,
|
|
26
|
+
Anthropic::Streaming::CitationEvent,
|
|
27
|
+
Anthropic::Streaming::ThinkingEvent,
|
|
28
|
+
Anthropic::Streaming::SignatureEvent,
|
|
29
|
+
Anthropic::Streaming::InputJsonEvent,
|
|
30
|
+
Anthropic::Streaming::MessageStopEvent,
|
|
31
|
+
Anthropic::Streaming::ContentBlockStopEvent
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -82,7 +82,10 @@ module Anthropic
|
|
|
82
82
|
end
|
|
83
83
|
@project_id = project_id
|
|
84
84
|
|
|
85
|
-
base_url ||= ENV.fetch(
|
|
85
|
+
base_url ||= ENV.fetch(
|
|
86
|
+
"ANTHROPIC_VERTEX_BASE_URL",
|
|
87
|
+
@region.to_s == "global" ? "https://aiplatform.googleapis.com/v1" : "https://#{@region}-aiplatform.googleapis.com/v1"
|
|
88
|
+
)
|
|
86
89
|
|
|
87
90
|
super(
|
|
88
91
|
base_url: base_url,
|
|
@@ -23,13 +23,15 @@ module Anthropic
|
|
|
23
23
|
case msg
|
|
24
24
|
in {event: "completion", data: String => data}
|
|
25
25
|
decoded = JSON.parse(data, symbolize_names: true)
|
|
26
|
-
|
|
26
|
+
unwrapped = Anthropic::Internal::Util.dig(decoded, @unwrap)
|
|
27
|
+
y << Anthropic::Internal::Type::Converter.coerce(@model, unwrapped)
|
|
27
28
|
in {
|
|
28
29
|
event: "message_start" | "message_delta" | "message_stop" | "content_block_start" | "content_block_delta" | "content_block_stop",
|
|
29
30
|
data: String => data
|
|
30
31
|
}
|
|
31
32
|
decoded = JSON.parse(data, symbolize_names: true)
|
|
32
|
-
|
|
33
|
+
unwrapped = Anthropic::Internal::Util.dig(decoded, @unwrap)
|
|
34
|
+
y << Anthropic::Internal::Type::Converter.coerce(@model, unwrapped)
|
|
33
35
|
in {event: "ping"}
|
|
34
36
|
next
|
|
35
37
|
in {event: "error", data: String => data}
|
|
@@ -341,6 +341,23 @@ module Anthropic
|
|
|
341
341
|
(@initial_retry_delay * scale * jitter).clamp(0, @max_retry_delay)
|
|
342
342
|
end
|
|
343
343
|
|
|
344
|
+
# @api private
|
|
345
|
+
#
|
|
346
|
+
# Very private API, do not use
|
|
347
|
+
#
|
|
348
|
+
# @param request [Hash{Symbol=>Object}] .
|
|
349
|
+
#
|
|
350
|
+
# @option request [Symbol] :method
|
|
351
|
+
#
|
|
352
|
+
# @option request [URI::Generic] :url
|
|
353
|
+
#
|
|
354
|
+
# @option request [Hash{String=>String}] :headers
|
|
355
|
+
#
|
|
356
|
+
# @option request [Object] :body
|
|
357
|
+
#
|
|
358
|
+
# @return [Hash{Symbol, Object}]
|
|
359
|
+
private def transform_request(request) = request
|
|
360
|
+
|
|
344
361
|
# @api private
|
|
345
362
|
#
|
|
346
363
|
# @param request [Hash{Symbol=>Object}] .
|
|
@@ -365,7 +382,8 @@ module Anthropic
|
|
|
365
382
|
#
|
|
366
383
|
# @raise [Anthropic::Errors::APIError]
|
|
367
384
|
# @return [Array(Integer, Net::HTTPResponse, Enumerable<String>)]
|
|
368
|
-
|
|
385
|
+
def send_request(request, redirect_count:, retry_count:, send_retry_header:)
|
|
386
|
+
request = transform_request(request)
|
|
369
387
|
url, headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout)
|
|
370
388
|
input = {**request.except(:timeout), deadline: Anthropic::Internal::Util.monotonic_secs + timeout}
|
|
371
389
|
|
|
@@ -471,6 +489,7 @@ module Anthropic
|
|
|
471
489
|
self.class.validate!(req)
|
|
472
490
|
model = req.fetch(:model) { Anthropic::Internal::Type::Unknown }
|
|
473
491
|
opts = req[:options].to_h
|
|
492
|
+
unwrap = req[:unwrap]
|
|
474
493
|
Anthropic::RequestOptions.validate!(opts)
|
|
475
494
|
request = build_request(req.except(:options), opts)
|
|
476
495
|
url = request.fetch(:url)
|
|
@@ -487,11 +506,18 @@ module Anthropic
|
|
|
487
506
|
decoded = Anthropic::Internal::Util.decode_content(response, stream: stream)
|
|
488
507
|
case req
|
|
489
508
|
in {stream: Class => st}
|
|
490
|
-
st.new(
|
|
509
|
+
st.new(
|
|
510
|
+
model: model,
|
|
511
|
+
url: url,
|
|
512
|
+
status: status,
|
|
513
|
+
response: response,
|
|
514
|
+
unwrap: unwrap,
|
|
515
|
+
stream: decoded
|
|
516
|
+
)
|
|
491
517
|
in {page: Class => page}
|
|
492
518
|
page.new(client: self, req: req, headers: response, page_data: decoded)
|
|
493
519
|
else
|
|
494
|
-
unwrapped = Anthropic::Internal::Util.dig(decoded,
|
|
520
|
+
unwrapped = Anthropic::Internal::Util.dig(decoded, unwrap)
|
|
495
521
|
Anthropic::Internal::Type::Converter.coerce(model, unwrapped)
|
|
496
522
|
end
|
|
497
523
|
end
|
|
@@ -62,10 +62,14 @@ module Anthropic
|
|
|
62
62
|
#
|
|
63
63
|
# @param state [Hash{Symbol=>Object}] .
|
|
64
64
|
#
|
|
65
|
-
# @option state [Boolean
|
|
65
|
+
# @option state [Boolean] :translate_names
|
|
66
|
+
#
|
|
67
|
+
# @option state [Boolean] :strictness
|
|
66
68
|
#
|
|
67
69
|
# @option state [Hash{Symbol=>Object}] :exactness
|
|
68
70
|
#
|
|
71
|
+
# @option state [Class<StandardError>] :error
|
|
72
|
+
#
|
|
69
73
|
# @option state [Integer] :branched
|
|
70
74
|
#
|
|
71
75
|
# @return [Array<Object>, Object]
|
|
@@ -74,6 +78,7 @@ module Anthropic
|
|
|
74
78
|
|
|
75
79
|
unless value.is_a?(Array)
|
|
76
80
|
exactness[:no] += 1
|
|
81
|
+
state[:error] = TypeError.new("#{value.class} can't be coerced into #{Array}")
|
|
77
82
|
return value
|
|
78
83
|
end
|
|
79
84
|
|
|
@@ -143,6 +148,7 @@ module Anthropic
|
|
|
143
148
|
# @option spec [Boolean] :"nil?"
|
|
144
149
|
def initialize(type_info, spec = {})
|
|
145
150
|
@item_type_fn = Anthropic::Internal::Type::Converter.type_info(type_info || spec)
|
|
151
|
+
@meta = Anthropic::Internal::Type::Converter.meta_info(type_info, spec)
|
|
146
152
|
@nilable = spec.fetch(:nil?, false)
|
|
147
153
|
end
|
|
148
154
|
|
|
@@ -52,6 +52,7 @@ module Anthropic
|
|
|
52
52
|
#
|
|
53
53
|
# @option spec [Boolean] :"nil?"
|
|
54
54
|
private def add_field(name_sym, required:, type_info:, spec:)
|
|
55
|
+
meta = Anthropic::Internal::Type::Converter.meta_info(type_info, spec)
|
|
55
56
|
type_fn, info =
|
|
56
57
|
case type_info
|
|
57
58
|
in Proc | Anthropic::Internal::Type::Converter | Class
|
|
@@ -60,7 +61,7 @@ module Anthropic
|
|
|
60
61
|
[Anthropic::Internal::Type::Converter.type_info(type_info), type_info]
|
|
61
62
|
end
|
|
62
63
|
|
|
63
|
-
setter = "#{name_sym}="
|
|
64
|
+
setter = :"#{name_sym}="
|
|
64
65
|
api_name = info.fetch(:api_name, name_sym)
|
|
65
66
|
nilable = info.fetch(:nil?, false)
|
|
66
67
|
const = if required && !nilable
|
|
@@ -81,31 +82,65 @@ module Anthropic
|
|
|
81
82
|
required: required,
|
|
82
83
|
nilable: nilable,
|
|
83
84
|
const: const,
|
|
84
|
-
type_fn: type_fn
|
|
85
|
+
type_fn: type_fn,
|
|
86
|
+
meta: meta
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
define_method(setter)
|
|
89
|
+
define_method(setter) do |value|
|
|
90
|
+
target = type_fn.call
|
|
91
|
+
state = Anthropic::Internal::Type::Converter.new_coerce_state(translate_names: false)
|
|
92
|
+
coerced = Anthropic::Internal::Type::Converter.coerce(target, value, state: state)
|
|
93
|
+
status = @coerced.store(name_sym, state.fetch(:error) || true)
|
|
94
|
+
stored =
|
|
95
|
+
case [target, status]
|
|
96
|
+
in [Anthropic::Internal::Type::Converter | Symbol, true]
|
|
97
|
+
coerced
|
|
98
|
+
else
|
|
99
|
+
value
|
|
100
|
+
end
|
|
101
|
+
@data.store(name_sym, stored)
|
|
102
|
+
end
|
|
88
103
|
|
|
104
|
+
# rubocop:disable Style/CaseEquality
|
|
105
|
+
# rubocop:disable Metrics/BlockLength
|
|
89
106
|
define_method(name_sym) do
|
|
90
107
|
target = type_fn.call
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Anthropic::
|
|
97
|
-
|
|
108
|
+
|
|
109
|
+
case @coerced[name_sym]
|
|
110
|
+
in true | false if Anthropic::Internal::Type::Converter === target
|
|
111
|
+
@data.fetch(name_sym)
|
|
112
|
+
in ::StandardError => e
|
|
113
|
+
raise Anthropic::Errors::ConversionError.new(
|
|
114
|
+
on: self.class,
|
|
115
|
+
method: __method__,
|
|
116
|
+
target: target,
|
|
117
|
+
value: @data.fetch(name_sym),
|
|
118
|
+
cause: e
|
|
98
119
|
)
|
|
120
|
+
else
|
|
121
|
+
Kernel.then do
|
|
122
|
+
value = @data.fetch(name_sym) { const == Anthropic::Internal::OMIT ? nil : const }
|
|
123
|
+
state = Anthropic::Internal::Type::Converter.new_coerce_state(translate_names: false)
|
|
124
|
+
if (nilable || !required) && value.nil?
|
|
125
|
+
nil
|
|
126
|
+
else
|
|
127
|
+
Anthropic::Internal::Type::Converter.coerce(
|
|
128
|
+
target, value, state: state
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
rescue StandardError => e
|
|
132
|
+
raise Anthropic::Errors::ConversionError.new(
|
|
133
|
+
on: self.class,
|
|
134
|
+
method: __method__,
|
|
135
|
+
target: target,
|
|
136
|
+
value: value,
|
|
137
|
+
cause: e
|
|
138
|
+
)
|
|
139
|
+
end
|
|
99
140
|
end
|
|
100
|
-
rescue StandardError => e
|
|
101
|
-
cls = self.class.name.split("::").last
|
|
102
|
-
message = [
|
|
103
|
-
"Failed to parse #{cls}.#{__method__} from #{value.class} to #{target.inspect}.",
|
|
104
|
-
"To get the unparsed API response, use #{cls}[#{__method__.inspect}].",
|
|
105
|
-
"Cause: #{e.message}"
|
|
106
|
-
].join(" ")
|
|
107
|
-
raise Anthropic::Errors::ConversionError.new(message)
|
|
108
141
|
end
|
|
142
|
+
# rubocop:enable Metrics/BlockLength
|
|
143
|
+
# rubocop:enable Style/CaseEquality
|
|
109
144
|
end
|
|
110
145
|
|
|
111
146
|
# @api private
|
|
@@ -205,23 +240,28 @@ module Anthropic
|
|
|
205
240
|
#
|
|
206
241
|
# @param state [Hash{Symbol=>Object}] .
|
|
207
242
|
#
|
|
208
|
-
# @option state [Boolean
|
|
243
|
+
# @option state [Boolean] :translate_names
|
|
244
|
+
#
|
|
245
|
+
# @option state [Boolean] :strictness
|
|
209
246
|
#
|
|
210
247
|
# @option state [Hash{Symbol=>Object}] :exactness
|
|
211
248
|
#
|
|
249
|
+
# @option state [Class<StandardError>] :error
|
|
250
|
+
#
|
|
212
251
|
# @option state [Integer] :branched
|
|
213
252
|
#
|
|
214
253
|
# @return [self, Object]
|
|
215
254
|
def coerce(value, state:)
|
|
216
255
|
exactness = state.fetch(:exactness)
|
|
217
256
|
|
|
218
|
-
if value.is_a?(self
|
|
257
|
+
if value.is_a?(self)
|
|
219
258
|
exactness[:yes] += 1
|
|
220
259
|
return value
|
|
221
260
|
end
|
|
222
261
|
|
|
223
262
|
unless (val = Anthropic::Internal::Util.coerce_hash(value)).is_a?(Hash)
|
|
224
263
|
exactness[:no] += 1
|
|
264
|
+
state[:error] = TypeError.new("#{value.class} can't be coerced into #{Hash}")
|
|
225
265
|
return value
|
|
226
266
|
end
|
|
227
267
|
exactness[:yes] += 1
|
|
@@ -229,13 +269,15 @@ module Anthropic
|
|
|
229
269
|
keys = val.keys.to_set
|
|
230
270
|
instance = new
|
|
231
271
|
data = instance.to_h
|
|
272
|
+
status = instance.instance_variable_get(:@coerced)
|
|
232
273
|
|
|
233
274
|
# rubocop:disable Metrics/BlockLength
|
|
234
275
|
fields.each do |name, field|
|
|
235
276
|
mode, required, target = field.fetch_values(:mode, :required, :type)
|
|
236
277
|
api_name, nilable, const = field.fetch_values(:api_name, :nilable, :const)
|
|
278
|
+
src_name = state.fetch(:translate_names) ? api_name : name
|
|
237
279
|
|
|
238
|
-
unless val.key?(
|
|
280
|
+
unless val.key?(src_name)
|
|
239
281
|
if required && mode != :dump && const == Anthropic::Internal::OMIT
|
|
240
282
|
exactness[nilable ? :maybe : :no] += 1
|
|
241
283
|
else
|
|
@@ -244,9 +286,10 @@ module Anthropic
|
|
|
244
286
|
next
|
|
245
287
|
end
|
|
246
288
|
|
|
247
|
-
item = val.fetch(
|
|
248
|
-
keys.delete(
|
|
289
|
+
item = val.fetch(src_name)
|
|
290
|
+
keys.delete(src_name)
|
|
249
291
|
|
|
292
|
+
state[:error] = nil
|
|
250
293
|
converted =
|
|
251
294
|
if item.nil? && (nilable || !required)
|
|
252
295
|
exactness[nilable ? :yes : :maybe] += 1
|
|
@@ -260,6 +303,8 @@ module Anthropic
|
|
|
260
303
|
item
|
|
261
304
|
end
|
|
262
305
|
end
|
|
306
|
+
|
|
307
|
+
status.store(name, state.fetch(:error) || true)
|
|
263
308
|
data.store(name, converted)
|
|
264
309
|
end
|
|
265
310
|
# rubocop:enable Metrics/BlockLength
|
|
@@ -434,7 +479,18 @@ module Anthropic
|
|
|
434
479
|
# Create a new instance of a model.
|
|
435
480
|
#
|
|
436
481
|
# @param data [Hash{Symbol=>Object}, self]
|
|
437
|
-
def initialize(data = {})
|
|
482
|
+
def initialize(data = {})
|
|
483
|
+
@data = {}
|
|
484
|
+
@coerced = {}
|
|
485
|
+
Anthropic::Internal::Util.coerce_hash!(data).each do
|
|
486
|
+
if self.class.known_fields.key?(_1)
|
|
487
|
+
public_send(:"#{_1}=", _2)
|
|
488
|
+
else
|
|
489
|
+
@data.store(_1, _2)
|
|
490
|
+
@coerced.store(_1, false)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
end
|
|
438
494
|
|
|
439
495
|
class << self
|
|
440
496
|
# @api private
|
|
@@ -64,12 +64,14 @@ module Anthropic
|
|
|
64
64
|
# @param url [URI::Generic]
|
|
65
65
|
# @param status [Integer]
|
|
66
66
|
# @param response [Net::HTTPResponse]
|
|
67
|
+
# @param unwrap [Symbol, Integer, Array<Symbol, Integer>, Proc]
|
|
67
68
|
# @param stream [Enumerable<Object>]
|
|
68
|
-
def initialize(model:, url:, status:, response:, stream:)
|
|
69
|
+
def initialize(model:, url:, status:, response:, unwrap:, stream:)
|
|
69
70
|
@model = model
|
|
70
71
|
@url = url
|
|
71
72
|
@status = status
|
|
72
73
|
@response = response
|
|
74
|
+
@unwrap = unwrap
|
|
73
75
|
@stream = stream
|
|
74
76
|
@iterator = iterator
|
|
75
77
|
|
|
@@ -31,14 +31,20 @@ module Anthropic
|
|
|
31
31
|
class << self
|
|
32
32
|
# @api private
|
|
33
33
|
#
|
|
34
|
+
# Coerce value to Boolean if possible, otherwise return the original value.
|
|
35
|
+
#
|
|
34
36
|
# @param value [Boolean, Object]
|
|
35
37
|
#
|
|
36
38
|
# @param state [Hash{Symbol=>Object}] .
|
|
37
39
|
#
|
|
38
|
-
# @option state [Boolean
|
|
40
|
+
# @option state [Boolean] :translate_names
|
|
41
|
+
#
|
|
42
|
+
# @option state [Boolean] :strictness
|
|
39
43
|
#
|
|
40
44
|
# @option state [Hash{Symbol=>Object}] :exactness
|
|
41
45
|
#
|
|
46
|
+
# @option state [Class<StandardError>] :error
|
|
47
|
+
#
|
|
42
48
|
# @option state [Integer] :branched
|
|
43
49
|
#
|
|
44
50
|
# @return [Boolean, Object]
|