omniai-anthropic 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 81f979cca2281d6d2462bfd301d9112d2347c6db184b77ff5aaad73e4fb141ef
4
- data.tar.gz: 906591303f337817e2f086169fe382d69e26a98674aad3feaedcb239e1087161
3
+ metadata.gz: 2b6103ed1e3c87ab2d1f2767dc4dce991756eefb558886ab8436632083058aba
4
+ data.tar.gz: aa75e2707afdb2bdffb7f74716e1afa31c027141dbfd114c45a77c00abe52045
5
5
  SHA512:
6
- metadata.gz: 5510b9cafbeea22e709f515eb0179ec6cb49e251fdd1391b6a1527f06908d2582ca22c56b06af3aee4cbb80ad63cb9aac047c0ed706eefa84cc69eb90c0ec0c2
7
- data.tar.gz: 3ea6790fad0c04efc10f987125e64755e5a53416e5652440f65d660a7c276206bbc62d632c0c475555ba151bf2eae7103682aea71fea13388b3ef602a540ce0e
6
+ metadata.gz: b06128d930cd70b61d2cea0ee2bb0318342d9114f7c9fe46ddaf8a1778f3570cb6e49748efd3a626d95daac9df1ecaf5680bb05180c500a4933e95fd682c942e
7
+ data.tar.gz: a18cce1b18ca45810dc9677856ef96e8af5d5faa71bf6160a981a5584d1f76157f45679481fc69e946d2837681cb9a40d8860fa6f52e879206c0af44612f5095
data/Gemfile CHANGED
@@ -5,7 +5,6 @@ source 'https://rubygems.org'
5
5
  gemspec
6
6
 
7
7
  gem 'rake'
8
-
9
8
  gem 'rspec'
10
9
  gem 'rspec_junit_formatter'
11
10
  gem 'rubocop'
@@ -13,3 +12,4 @@ gem 'rubocop-rake'
13
12
  gem 'rubocop-rspec'
14
13
  gem 'simplecov'
15
14
  gem 'webmock'
15
+ gem 'yard'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ module Anthropic
5
+ class Chat
6
+ module Response
7
+ # A completion returned by the API.
8
+ class Completion < OmniAI::Chat::Response::Completion
9
+ # @return [Array<OmniAI::Chat::Response::MessageChoice>]
10
+ def choices
11
+ @choices ||= begin
12
+ role = @data['role']
13
+
14
+ @data['content'].map do |data, index|
15
+ OmniAI::Chat::Response::MessageChoice.new(data: {
16
+ 'index' => index,
17
+ 'message' => {
18
+ 'role' => role,
19
+ 'content' => data['text'],
20
+ },
21
+ })
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAI
4
+ module Anthropic
5
+ class Chat
6
+ module Response
7
+ # A stream given when streaming.
8
+ class Stream < OmniAI::Chat::Response::Stream
9
+ module Type
10
+ PING = 'ping'
11
+ MESSAGE_START = 'message_start'
12
+ MESSAGE_STOP = 'message_stop'
13
+ MESSAGE_DELTA = 'message_delta'
14
+ CONTENT_BLOCK_START = 'content_block_start'
15
+ CONTENT_BLOCK_STOP = 'content_block_stop'
16
+ CONTENT_BLOCK_DELTA = 'content_block_delta'
17
+ end
18
+
19
+ # Process the stream into chunks by event.
20
+ class Builder
21
+ attr_reader :id, :model, :role, :content, :index
22
+
23
+ # @return [OmniAI::Chat::Chunk]
24
+ def chunk
25
+ OmniAI::Chat::Response::Chunk.new(data: {
26
+ 'id' => @id,
27
+ 'model' => @model,
28
+ 'choices' => [{
29
+ 'index' => @index,
30
+ 'delta' => {
31
+ 'role' => @role,
32
+ 'content' => @content,
33
+ },
34
+ }],
35
+ })
36
+ end
37
+
38
+ # Handler for Type::MESSAGE_START
39
+ #
40
+ # @param data [Hash]
41
+ def message_start(data)
42
+ @id = data['id']
43
+ @model = data['model']
44
+ @role = data['role']
45
+ end
46
+
47
+ # Handler for Type::MESSAGE_STOP
48
+ #
49
+ # @param data [Hash]
50
+ def message_stop(_)
51
+ @id = nil
52
+ @model = nil
53
+ @role = nil
54
+ end
55
+
56
+ # Handler for Type::CONTENT_BLOCK_START
57
+ #
58
+ # @param data [Hash]
59
+ def content_block_start(data)
60
+ @index = data['index']
61
+ end
62
+
63
+ # Handler for Type::CONTENT_BLOCK_STOP
64
+ #
65
+ # @param data [Hash]
66
+ def content_block_stop(_)
67
+ @index = nil
68
+ end
69
+
70
+ # Handler for Type::CONTENT_BLOCK_DELTA
71
+ #
72
+ # @param data [Hash]
73
+ def content_block_delta(data)
74
+ return unless data['delta']['type'].eql?('text_delta')
75
+
76
+ @content = data['delta']['text']
77
+ end
78
+ end
79
+
80
+ # @yield [OmniAI::Chat::Chunk]
81
+ def stream!(&block)
82
+ builder = Builder.new
83
+
84
+ @response.body.each do |chunk|
85
+ @parser.feed(chunk) do |type, data|
86
+ process(type:, data: JSON.parse(data), builder:, &block)
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ # @param type [String]
94
+ # @param data [Hash]
95
+ # @param builder [Builder]
96
+ def process(type:, data:, builder:, &)
97
+ case type
98
+ when Type::MESSAGE_START then builder.message_start(data)
99
+ when Type::CONTENT_BLOCK_START then builder.content_block_start(data)
100
+ when Type::CONTENT_BLOCK_STOP then builder.content_block_stop(data)
101
+ when Type::MESSAGE_STOP then builder.message_stop(data)
102
+ when Type::CONTENT_BLOCK_DELTA
103
+ builder.content_block_delta(data)
104
+ yield(builder.chunk)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -31,24 +31,38 @@ module OmniAI
31
31
  def payload
32
32
  OmniAI::Anthropic.config.chat_options.merge({
33
33
  model: @model,
34
- messages: messages.filter { |message| !message[:role].eql?(OmniAI::Chat::Role::SYSTEM) },
34
+ messages: messages.filter { |message| !message[:role].eql?(Role::SYSTEM) },
35
35
  system:,
36
36
  stream: @stream.nil? ? nil : !@stream.nil?,
37
37
  temperature: @temperature,
38
+ tools: tools_payload,
38
39
  }).compact
39
40
  end
40
41
 
41
42
  # @return [String, nil]
42
43
  def system
43
- messages = self.messages.filter { |message| message[:role].eql?(OmniAI::Chat::Role::SYSTEM) }
44
- messages << { role: OmniAI::Chat::Role::SYSTEM, content: OmniAI::Chat::JSON_PROMPT } if @format.eql?(:json)
44
+ messages = self.messages.filter { |message| message[:role].eql?(Role::SYSTEM) }
45
+ messages << { role: Role::SYSTEM, content: JSON_PROMPT } if @format.eql?(:json)
45
46
 
46
47
  messages.map { |message| message[:content] }.join("\n\n") if messages.any?
47
48
  end
48
49
 
49
50
  # @return [String]
50
51
  def path
51
- "/#{OmniAI::Anthropic::Client::VERSION}/messages"
52
+ "/#{Client::VERSION}/messages"
53
+ end
54
+
55
+ private
56
+
57
+ # @return [Array<Hash>, nil]
58
+ def tools_payload
59
+ @tools&.map do |tool|
60
+ {
61
+ name: tool.name,
62
+ description: tool.description,
63
+ input_schema: tool.parameters&.prepare,
64
+ }.compact
65
+ end
52
66
  end
53
67
  end
54
68
  end
@@ -57,10 +57,11 @@ module OmniAI
57
57
  # @param format [Symbol] optional :text or :json
58
58
  # @param temperature [Float, nil] optional
59
59
  # @param stream [Proc, nil] optional
60
+ # @param tools [Array<OmniAI::Tool>, nil] optional
60
61
  #
61
62
  # @return [OmniAI::Chat::Completion]
62
- def chat(messages, model: Chat::Model::CLAUDE_HAIKU, temperature: nil, format: nil, stream: nil)
63
- Chat.process!(messages, model:, temperature:, format:, stream:, client: self)
63
+ def chat(messages, model: Chat::Model::CLAUDE_HAIKU, temperature: nil, format: nil, stream: nil, tools: nil)
64
+ Chat.process!(messages, model:, temperature:, format:, stream:, tools:, client: self)
64
65
  end
65
66
  end
66
67
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAI
4
4
  module Anthropic
5
- VERSION = '1.4.0'
5
+ VERSION = '1.5.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniai-anthropic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-04 00:00:00.000000000 Z
11
+ date: 2024-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: event_stream_parser
@@ -63,8 +63,8 @@ files:
63
63
  - README.md
64
64
  - lib/omniai/anthropic.rb
65
65
  - lib/omniai/anthropic/chat.rb
66
- - lib/omniai/anthropic/chat/completion.rb
67
- - lib/omniai/anthropic/chat/stream.rb
66
+ - lib/omniai/anthropic/chat/response/completion.rb
67
+ - lib/omniai/anthropic/chat/response/stream.rb
68
68
  - lib/omniai/anthropic/client.rb
69
69
  - lib/omniai/anthropic/config.rb
70
70
  - lib/omniai/anthropic/version.rb
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  requirements: []
93
- rubygems_version: 3.5.3
93
+ rubygems_version: 3.5.14
94
94
  signing_key:
95
95
  specification_version: 4
96
96
  summary: A generalized framework for interacting with Anthropic
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OmniAI
4
- module Anthropic
5
- class Chat
6
- # A completion returned by the API.
7
- class Completion < OmniAI::Chat::Completion
8
- # @return [Array<OmniAI::Chat::MessageChoice>]
9
- def choices
10
- @choices ||= begin
11
- role = @data['role']
12
-
13
- @data['content'].map do |data, index|
14
- OmniAI::Chat::MessageChoice.for(data: {
15
- 'index' => index,
16
- 'message' => { 'role' => role, 'content' => data['text'] },
17
- })
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OmniAI
4
- module Anthropic
5
- class Chat
6
- # A stream given when streaming.
7
- class Stream < OmniAI::Chat::Stream
8
- module Type
9
- PING = 'ping'
10
- MESSAGE_START = 'message_start'
11
- MESSAGE_STOP = 'message_stop'
12
- MESSAGE_DELTA = 'message_delta'
13
- CONTENT_BLOCK_START = 'content_block_start'
14
- CONTENT_BLOCK_STOP = 'content_block_stop'
15
- CONTENT_BLOCK_DELTA = 'content_block_delta'
16
- end
17
-
18
- # Process the stream into chunks by event.
19
- class Builder
20
- attr_reader :id, :model, :role, :content, :index
21
-
22
- # @return [OmniAI::Chat::Chunk]
23
- def chunk
24
- OmniAI::Chat::Chunk.new(data: {
25
- 'id' => @id,
26
- 'model' => @model,
27
- 'choices' => [{
28
- 'index' => @index,
29
- 'delta' => { 'role' => @role, 'content' => @content },
30
- }],
31
- })
32
- end
33
-
34
- # Handler for Type::MESSAGE_START
35
- #
36
- # @param data [Hash]
37
- def message_start(data)
38
- @id = data['id']
39
- @model = data['model']
40
- @role = data['role']
41
- end
42
-
43
- # Handler for Type::MESSAGE_STOP
44
- #
45
- # @param data [Hash]
46
- def message_stop(_)
47
- @id = nil
48
- @model = nil
49
- @role = nil
50
- end
51
-
52
- # Handler for Type::CONTENT_BLOCK_START
53
- #
54
- # @param data [Hash]
55
- def content_block_start(data)
56
- @index = data['index']
57
- end
58
-
59
- # Handler for Type::CONTENT_BLOCK_STOP
60
- #
61
- # @param data [Hash]
62
- def content_block_stop(_)
63
- @index = nil
64
- end
65
-
66
- # Handler for Type::CONTENT_BLOCK_DELTA
67
- #
68
- # @param data [Hash]
69
- def content_block_delta(data)
70
- return unless data['delta']['type'].eql?('text_delta')
71
-
72
- @content = data['delta']['text']
73
- end
74
- end
75
-
76
- # @yield [OmniAI::Chat::Chunk]
77
- def stream!(&block)
78
- builder = Builder.new
79
-
80
- @response.body.each do |chunk|
81
- @parser.feed(chunk) do |type, data|
82
- process(type:, data: JSON.parse(data), builder:, &block)
83
- end
84
- end
85
- end
86
-
87
- private
88
-
89
- # @param type [String]
90
- # @param data [Hash]
91
- # @param builder [Builder]
92
- def process(type:, data:, builder:, &)
93
- case type
94
- when Type::MESSAGE_START then builder.message_start(data)
95
- when Type::CONTENT_BLOCK_START then builder.content_block_start(data)
96
- when Type::CONTENT_BLOCK_STOP then builder.content_block_stop(data)
97
- when Type::MESSAGE_STOP then builder.message_stop(data)
98
- when Type::CONTENT_BLOCK_DELTA
99
- builder.content_block_delta(data)
100
- yield(builder.chunk)
101
- end
102
- end
103
- end
104
- end
105
- end
106
- end