omniai-anthropic 1.9.8 → 2.0.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/lib/omniai/anthropic/chat/function_serializer.rb +3 -0
- data/lib/omniai/anthropic/chat/media_serializer.rb +1 -1
- data/lib/omniai/anthropic/chat/message_serializer.rb +9 -3
- data/lib/omniai/anthropic/chat/{payload_serializer.rb → response_serializer.rb} +10 -8
- data/lib/omniai/anthropic/chat/stream.rb +124 -58
- data/lib/omniai/anthropic/chat.rb +1 -1
- data/lib/omniai/anthropic/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed3bbf0fe24852928799eeeffc76163c4d45a68c2ae5070f46b57590e1da8b60
|
4
|
+
data.tar.gz: d330deaf3dfe93d3fd1d9c64b86656668708b3936f9bdbd6445abc3f7ed2bc98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92315dd5847588f9b344dc6111d5a0e5b4176cc72dba14c275de14d7cd0d7a2ba03a60608ba0d2cc8ba341cff566bcae838f762d807c0fdb2218cac1b3068650
|
7
|
+
data.tar.gz: 1db95ee64d3a6ad40f289a05dacc0d2154a0b0de016502864c4103834cc9a69568a591641bb4f94957cdf3ef93b147f5503776e228717ad55a6ac2b1869bb56f
|
@@ -6,6 +6,7 @@ module OmniAI
|
|
6
6
|
# Overrides function serialize / deserialize.
|
7
7
|
module FunctionSerializer
|
8
8
|
# @param function [OmniAI::Chat::Function]
|
9
|
+
#
|
9
10
|
# @return [Hash]
|
10
11
|
def self.serialize(function, *)
|
11
12
|
{
|
@@ -15,10 +16,12 @@ module OmniAI
|
|
15
16
|
end
|
16
17
|
|
17
18
|
# @param data [Hash]
|
19
|
+
#
|
18
20
|
# @return [OmniAI::Chat::Function]
|
19
21
|
def self.deserialize(data, *)
|
20
22
|
name = data["name"]
|
21
23
|
arguments = data["input"]
|
24
|
+
|
22
25
|
OmniAI::Chat::Function.new(name:, arguments:)
|
23
26
|
end
|
24
27
|
end
|
@@ -7,10 +7,12 @@ module OmniAI
|
|
7
7
|
module MessageSerializer
|
8
8
|
# @param message [OmniAI::Chat::Message]
|
9
9
|
# @param context [OmniAI::Context]
|
10
|
+
#
|
10
11
|
# @return [Hash]
|
11
12
|
def self.serialize(message, context:)
|
12
13
|
role = message.role
|
13
|
-
parts = arrayify(message.content) + arrayify(message.tool_call_list)
|
14
|
+
parts = arrayify(message.content) + arrayify(message.tool_call_list&.entries)
|
15
|
+
|
14
16
|
content = parts.map do |part|
|
15
17
|
case part
|
16
18
|
when String then { type: "text", text: part }
|
@@ -23,6 +25,7 @@ module OmniAI
|
|
23
25
|
|
24
26
|
# @param data [Hash]
|
25
27
|
# @param context [OmniAI::Context]
|
28
|
+
#
|
26
29
|
# @return [OmniAI::Chat::Message]
|
27
30
|
def self.deserialize(data, context:)
|
28
31
|
role = data["role"]
|
@@ -30,8 +33,11 @@ module OmniAI
|
|
30
33
|
ContentSerializer.deserialize(content, context:)
|
31
34
|
end
|
32
35
|
|
33
|
-
|
34
|
-
|
36
|
+
tool_call_parts = parts.select { |part| part.is_a?(OmniAI::Chat::ToolCall) }
|
37
|
+
non_tool_call_parts = parts.reject { |part| part.is_a?(OmniAI::Chat::ToolCall) }
|
38
|
+
|
39
|
+
tool_call_list = OmniAI::Chat::ToolCallList.new(entries: tool_call_parts) if tool_call_parts.any?
|
40
|
+
content = non_tool_call_parts if non_tool_call_parts.any?
|
35
41
|
|
36
42
|
OmniAI::Chat::Message.new(content:, role:, tool_call_list:)
|
37
43
|
end
|
@@ -3,26 +3,28 @@
|
|
3
3
|
module OmniAI
|
4
4
|
module Anthropic
|
5
5
|
class Chat
|
6
|
-
# Overrides
|
7
|
-
module
|
8
|
-
# @param
|
6
|
+
# Overrides response serialize / deserialize.
|
7
|
+
module ResponseSerializer
|
8
|
+
# @param response [OmniAI::Chat::Response]
|
9
9
|
# @param context [OmniAI::Context]
|
10
|
+
#
|
10
11
|
# @return [Hash]
|
11
|
-
def self.serialize(
|
12
|
-
usage =
|
13
|
-
choice =
|
12
|
+
def self.serialize(response, context:)
|
13
|
+
usage = response.usage.serialize(context:)
|
14
|
+
choice = response.choice.serialize(context:)
|
14
15
|
|
15
16
|
choice.merge({ usage: })
|
16
17
|
end
|
17
18
|
|
18
19
|
# @param data [Hash]
|
19
20
|
# @param context [OmniAI::Context]
|
20
|
-
#
|
21
|
+
#
|
22
|
+
# @return [OmniAI::Chat::Response]
|
21
23
|
def self.deserialize(data, context:)
|
22
24
|
usage = OmniAI::Chat::Usage.deserialize(data["usage"], context:) if data["usage"]
|
23
25
|
choice = OmniAI::Chat::Choice.deserialize(data, context:)
|
24
26
|
|
25
|
-
OmniAI::Chat::
|
27
|
+
OmniAI::Chat::Response.new(data:, choices: [choice], usage:)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -3,90 +3,156 @@
|
|
3
3
|
module OmniAI
|
4
4
|
module Anthropic
|
5
5
|
class Chat
|
6
|
-
#
|
6
|
+
# Combine chunks into a hash. For each chunk yield the text (delta) if a block is given and the chunk is text.
|
7
7
|
class Stream < OmniAI::Chat::Stream
|
8
8
|
module Type
|
9
|
-
PING = "ping"
|
10
9
|
MESSAGE_START = "message_start"
|
11
|
-
MESSAGE_STOP = "message_stop"
|
12
10
|
MESSAGE_DELTA = "message_delta"
|
11
|
+
MESSAGE_STOP = "message_stop"
|
13
12
|
CONTENT_BLOCK_START = "content_block_start"
|
14
|
-
CONTENT_BLOCK_STOP = "content_block_stop"
|
15
13
|
CONTENT_BLOCK_DELTA = "content_block_delta"
|
14
|
+
CONTENT_BLOCK_STOP = "content_block_stop"
|
16
15
|
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
return unless @content
|
17
|
+
module ContentBlockType
|
18
|
+
TEXT = "text"
|
19
|
+
TOOL_USE = "tool_use"
|
20
|
+
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
module ContentBlockDeltaType
|
23
|
+
TEXT_DELTA = "text_delta"
|
24
|
+
INPUT_JSON_DELTA = "input_json_delta"
|
25
|
+
end
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
# @yield [delta]
|
28
|
+
# @yieldparam delta [OmniAI::Chat::Delta]
|
29
|
+
#
|
30
|
+
# @return [Hash]
|
31
|
+
def stream!(&block)
|
32
|
+
@data = { "content" => [] }
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@message = nil
|
34
|
+
@chunks.each do |chunk|
|
35
|
+
parser.feed(chunk) do |type, data, id|
|
36
|
+
process!(type, data, id, &block)
|
37
|
+
end
|
41
38
|
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
# @param data [Hash]
|
46
|
-
def content_block_start(_data)
|
47
|
-
@content = nil
|
48
|
-
end
|
40
|
+
@data
|
41
|
+
end
|
49
42
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
43
|
+
protected
|
44
|
+
|
45
|
+
# @yield delta
|
46
|
+
# @yieldparam delta [OmniAI::Chat::Delta]
|
47
|
+
#
|
48
|
+
# @param type [String]
|
49
|
+
# @param data [Hash]
|
50
|
+
# @param id [String]
|
51
|
+
def process!(type, data, id, &)
|
52
|
+
log(type, data, id)
|
53
|
+
|
54
|
+
data = JSON.parse(data)
|
55
|
+
|
56
|
+
case data["type"]
|
57
|
+
when Type::MESSAGE_START then message_start(data)
|
58
|
+
when Type::MESSAGE_DELTA then message_delta(data)
|
59
|
+
when Type::MESSAGE_STOP then message_stop(data)
|
60
|
+
when Type::CONTENT_BLOCK_START then content_block_start(data)
|
61
|
+
when Type::CONTENT_BLOCK_DELTA then content_block_delta(data, &)
|
62
|
+
when Type::CONTENT_BLOCK_STOP then content_block_stop(data)
|
55
63
|
end
|
64
|
+
end
|
56
65
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
# Handler for Type::MESSAGE_START
|
67
|
+
#
|
68
|
+
# @param data [Hash]
|
69
|
+
def message_start(data)
|
70
|
+
@data = data["message"]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Handler for Type::MESSAGE_DELTA
|
74
|
+
#
|
75
|
+
# @param data [Hash]
|
76
|
+
def message_delta(data)
|
77
|
+
@data.merge!(data["delta"])
|
78
|
+
|
79
|
+
input_tokens = data.dig("usage", "input_tokens")
|
80
|
+
output_tokens = data.dig("usage", "output_tokens")
|
81
|
+
|
82
|
+
@data["usage"] ||= {}
|
83
|
+
@data["usage"]["input_tokens"] = input_tokens if input_tokens
|
84
|
+
@data["usage"]["output_tokens"] = output_tokens if output_tokens
|
85
|
+
end
|
86
|
+
|
87
|
+
# Handler for Type::MESSAGE_STOP
|
88
|
+
#
|
89
|
+
# @param _data [Hash]
|
90
|
+
def message_stop(_data)
|
91
|
+
# NOOP
|
92
|
+
end
|
93
|
+
|
94
|
+
# Handler for Type::CONTENT_BLOCK_START
|
95
|
+
#
|
96
|
+
# @param data [Hash]
|
97
|
+
def content_block_start(data)
|
98
|
+
index = data["index"]
|
99
|
+
@data["content"][index] = data["content_block"]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Handler for Type::CONTENT_BLOCK_DELTA
|
103
|
+
#
|
104
|
+
# @yield [delta]
|
105
|
+
# @yieldparam delta [OmniAI::Chat::Delta]
|
106
|
+
#
|
107
|
+
# @param data [Hash]
|
108
|
+
def content_block_delta(data, &)
|
109
|
+
case data["delta"]["type"]
|
110
|
+
when ContentBlockDeltaType::TEXT_DELTA
|
111
|
+
content_block_delta_for_text_delta(data, &)
|
112
|
+
when ContentBlockDeltaType::INPUT_JSON_DELTA
|
113
|
+
content_block_delta_for_input_json_delta(data, &)
|
62
114
|
end
|
63
115
|
end
|
64
116
|
|
65
|
-
|
117
|
+
# Handler for Type::CONTENT_BLOCK_DELTA w/ ContentBlockDeltaType::TEXT_DELTA
|
118
|
+
#
|
119
|
+
# @yield [delta]
|
120
|
+
# @yieldparam delta [OmniAI::Chat::Delta]
|
121
|
+
#
|
122
|
+
# @param data [Hash]
|
123
|
+
def content_block_delta_for_text_delta(data, &block)
|
124
|
+
index = data["index"]
|
125
|
+
text = data["delta"]["text"]
|
126
|
+
|
127
|
+
content = @data["content"][index]
|
128
|
+
content["text"] += data["delta"]["text"]
|
66
129
|
|
67
|
-
|
68
|
-
@builder ||= Builder.new
|
130
|
+
block&.call(OmniAI::Chat::Delta.new(text: text))
|
69
131
|
end
|
70
132
|
|
71
|
-
#
|
133
|
+
# Handler for Type::CONTENT_BLOCK_DELTA w/ ContentBlockDeltaType::INPUT_JSON_DELTA
|
134
|
+
#
|
135
|
+
# @yield [delta]
|
136
|
+
# @yieldparam delta [OmniAI::Chat::Delta]
|
137
|
+
#
|
72
138
|
# @param data [Hash]
|
73
|
-
|
74
|
-
|
75
|
-
|
139
|
+
def content_block_delta_for_input_json_delta(data)
|
140
|
+
content = @data["content"][data["index"]]
|
141
|
+
content["partial_json"] ||= ""
|
142
|
+
content["partial_json"] += data["delta"]["partial_json"]
|
143
|
+
end
|
76
144
|
|
77
|
-
|
145
|
+
# Handler for Type::CONTENT_BLOCK_STOP
|
146
|
+
#
|
147
|
+
# @param _data [Hash]
|
148
|
+
def content_block_stop(data)
|
149
|
+
index = data["index"]
|
150
|
+
content = @data["content"][index]
|
78
151
|
|
79
|
-
|
80
|
-
when Type::MESSAGE_START then builder.message_start(data)
|
81
|
-
when Type::CONTENT_BLOCK_START then builder.content_block_start(data)
|
82
|
-
when Type::CONTENT_BLOCK_STOP then builder.content_block_stop(data)
|
83
|
-
when Type::MESSAGE_STOP then builder.message_stop(data)
|
84
|
-
when Type::CONTENT_BLOCK_DELTA
|
85
|
-
builder.content_block_delta(data)
|
152
|
+
return unless content["partial_json"]
|
86
153
|
|
87
|
-
|
88
|
-
|
89
|
-
end
|
154
|
+
content["input"] = JSON.parse(content["partial_json"])
|
155
|
+
content.delete("partial_json")
|
90
156
|
end
|
91
157
|
end
|
92
158
|
end
|
@@ -61,7 +61,7 @@ module OmniAI
|
|
61
61
|
context.deserializers[:message] = MessageSerializer.method(:deserialize)
|
62
62
|
|
63
63
|
context.deserializers[:content] = ContentSerializer.method(:deserialize)
|
64
|
-
context.deserializers[:
|
64
|
+
context.deserializers[:response] = ResponseSerializer.method(:deserialize)
|
65
65
|
end
|
66
66
|
|
67
67
|
# @return [Hash]
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniai-anthropic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Sylvestre
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-03 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: event_stream_parser
|
@@ -29,14 +29,14 @@ dependencies:
|
|
29
29
|
requirements:
|
30
30
|
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '2.0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '2.0'
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: zeitwerk
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,7 +67,7 @@ files:
|
|
67
67
|
- lib/omniai/anthropic/chat/function_serializer.rb
|
68
68
|
- lib/omniai/anthropic/chat/media_serializer.rb
|
69
69
|
- lib/omniai/anthropic/chat/message_serializer.rb
|
70
|
-
- lib/omniai/anthropic/chat/
|
70
|
+
- lib/omniai/anthropic/chat/response_serializer.rb
|
71
71
|
- lib/omniai/anthropic/chat/stream.rb
|
72
72
|
- lib/omniai/anthropic/chat/text_serializer.rb
|
73
73
|
- lib/omniai/anthropic/chat/tool_call_result_serializer.rb
|