intelligence 0.6.0 → 0.7.1
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/README.md +555 -0
- data/intelligence.gemspec +1 -1
- data/lib/intelligence/adapter/base.rb +13 -6
- data/lib/intelligence/adapter/class_methods.rb +15 -0
- data/lib/intelligence/adapter/module_methods.rb +41 -0
- data/lib/intelligence/adapter.rb +2 -2
- data/lib/intelligence/adapters/anthropic/adapter.rb +21 -19
- data/lib/intelligence/adapters/anthropic/chat_request_methods.rb +189 -0
- data/lib/intelligence/adapters/anthropic/{chat_methods.rb → chat_response_methods.rb} +8 -125
- data/lib/intelligence/adapters/cerebras.rb +17 -17
- data/lib/intelligence/adapters/generic/chat_methods.rb +12 -5
- data/lib/intelligence/adapters/generic.rb +1 -1
- data/lib/intelligence/adapters/google/adapter.rb +33 -22
- data/lib/intelligence/adapters/google/chat_request_methods.rb +233 -0
- data/lib/intelligence/adapters/google/chat_response_methods.rb +236 -0
- data/lib/intelligence/adapters/groq.rb +27 -28
- data/lib/intelligence/adapters/hyperbolic.rb +13 -13
- data/lib/intelligence/adapters/legacy/chat_methods.rb +1 -2
- data/lib/intelligence/adapters/mistral.rb +18 -18
- data/lib/intelligence/adapters/open_ai/adapter.rb +39 -32
- data/lib/intelligence/adapters/open_ai/chat_request_methods.rb +186 -0
- data/lib/intelligence/adapters/open_ai/{chat_methods.rb → chat_response_methods.rb} +60 -162
- data/lib/intelligence/adapters/open_ai.rb +1 -1
- data/lib/intelligence/adapters/open_router.rb +18 -18
- data/lib/intelligence/adapters/samba_nova.rb +13 -13
- data/lib/intelligence/adapters/together_ai.rb +21 -19
- data/lib/intelligence/conversation.rb +11 -10
- data/lib/intelligence/message.rb +44 -28
- data/lib/intelligence/message_content/base.rb +2 -9
- data/lib/intelligence/message_content/binary.rb +3 -3
- data/lib/intelligence/message_content/file.rb +3 -3
- data/lib/intelligence/message_content/text.rb +2 -2
- data/lib/intelligence/message_content/tool_call.rb +8 -4
- data/lib/intelligence/message_content/tool_result.rb +11 -6
- data/lib/intelligence/tool.rb +139 -0
- data/lib/intelligence/version.rb +1 -1
- data/lib/intelligence.rb +2 -1
- metadata +15 -10
- data/lib/intelligence/adapter/class_methods/construction.rb +0 -17
- data/lib/intelligence/adapter/module_methods/construction.rb +0 -43
- data/lib/intelligence/adapters/google/chat_methods.rb +0 -393
@@ -1,46 +1,48 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'chat_request_methods'
|
2
|
+
require_relative 'chat_response_methods'
|
2
3
|
|
3
4
|
module Intelligence
|
4
5
|
module Anthropic
|
5
6
|
class Adapter < Adapter::Base
|
6
7
|
|
7
|
-
|
8
|
+
schema do
|
8
9
|
|
9
10
|
# normalized properties for all endpoints
|
10
|
-
|
11
|
+
key
|
11
12
|
|
12
13
|
# anthropic specific properties for all endpoints
|
13
|
-
|
14
|
+
version String, default: '2023-06-01'
|
14
15
|
|
15
|
-
|
16
|
+
chat_options do
|
16
17
|
|
17
18
|
# normalized properties for anthropic generative text endpoint
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
model String
|
20
|
+
max_tokens Integer
|
21
|
+
temperature Float
|
22
|
+
top_k Integer
|
23
|
+
top_p Float
|
24
|
+
stop String, array: true, as: :stop_sequences
|
25
|
+
stream [ TrueClass, FalseClass ]
|
25
26
|
|
26
27
|
# anthropic variant of normalized properties for anthropic generative text endpoints
|
27
|
-
|
28
|
+
stop_sequences String, array: true
|
28
29
|
|
29
30
|
# anthropic specific properties for anthropic generative text endpoints
|
30
|
-
|
31
|
-
|
31
|
+
tool_choice do
|
32
|
+
type String
|
32
33
|
# the name parameter should only be set if type = 'tool'
|
33
|
-
|
34
|
+
name String
|
34
35
|
end
|
35
|
-
|
36
|
-
|
36
|
+
metadata do
|
37
|
+
user_id String
|
37
38
|
end
|
38
39
|
|
39
40
|
end
|
40
41
|
|
41
42
|
end
|
42
43
|
|
43
|
-
include
|
44
|
+
include ChatRequestMethods
|
45
|
+
include ChatResponseMethods
|
44
46
|
|
45
47
|
end
|
46
48
|
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
module Intelligence
|
2
|
+
module Anthropic
|
3
|
+
module ChatRequestMethods
|
4
|
+
|
5
|
+
CHAT_REQUEST_URI = "https://api.anthropic.com/v1/messages"
|
6
|
+
|
7
|
+
def chat_request_uri( options )
|
8
|
+
CHAT_REQUEST_URI
|
9
|
+
end
|
10
|
+
|
11
|
+
def chat_request_headers( options = nil )
|
12
|
+
options = @options.merge( build_options( options ) )
|
13
|
+
result = {}
|
14
|
+
|
15
|
+
key = options[ :key ]
|
16
|
+
version = options[ :version ] || "2023-06-01"
|
17
|
+
|
18
|
+
raise ArgumentError.new(
|
19
|
+
"An Anthropic key is required to build an Anthropic chat request."
|
20
|
+
) if key.nil?
|
21
|
+
|
22
|
+
result[ 'content-type' ] = 'application/json'
|
23
|
+
result[ 'x-api-key' ] = "#{key}"
|
24
|
+
result[ 'anthropic-version' ] = version unless version.nil?
|
25
|
+
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def chat_request_body( conversation, options = nil )
|
30
|
+
options = @options.merge( build_options( options ) )
|
31
|
+
result = options[ :chat_options ]&.compact || {}
|
32
|
+
|
33
|
+
system_message = to_anthropic_system_message( conversation[ :system_message ] )
|
34
|
+
result[ :system ] = system_message unless system_message.nil?
|
35
|
+
result[ :messages ] = []
|
36
|
+
|
37
|
+
messages = conversation[ :messages ]
|
38
|
+
length = messages&.length || 0
|
39
|
+
index = 0; while index < length
|
40
|
+
|
41
|
+
message = messages[ index ]
|
42
|
+
unless message.nil?
|
43
|
+
|
44
|
+
# The Anthropic API will not accept a sequence of messages where the role of two
|
45
|
+
# sequentian messages is the same.
|
46
|
+
#
|
47
|
+
# The purpose of this code is to identify such occurences and coalece them such
|
48
|
+
# that the first message in the sequence aggregates the contents of all subsequent
|
49
|
+
# messages with the same role.
|
50
|
+
look_ahead_index = index + 1; while look_ahead_index < length
|
51
|
+
ahead_message = messages[ look_ahead_index ]
|
52
|
+
unless ahead_message.nil?
|
53
|
+
if ahead_message[ :role ] == message[ :role ]
|
54
|
+
message[ :contents ] =
|
55
|
+
( message[ :contents ] || [] ) +
|
56
|
+
( ahead_message[ :contents ] || [] )
|
57
|
+
messages[ look_ahead_index ] = nil
|
58
|
+
look_ahead_index += 1
|
59
|
+
else
|
60
|
+
break
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
result_message = { role: message[ :role ] }
|
66
|
+
result_message_content = []
|
67
|
+
|
68
|
+
message[ :contents ]&.each do | content |
|
69
|
+
case content[ :type ]
|
70
|
+
when :text
|
71
|
+
result_message_content << { type: 'text', text: content[ :text ] }
|
72
|
+
when :binary
|
73
|
+
content_type = content[ :content_type ]
|
74
|
+
bytes = content[ :bytes ]
|
75
|
+
if content_type && bytes
|
76
|
+
mime_type = MIME::Types[ content_type ].first
|
77
|
+
if mime_type&.media_type == 'image'
|
78
|
+
result_message_content << {
|
79
|
+
type: 'image',
|
80
|
+
source: {
|
81
|
+
type: 'base64',
|
82
|
+
media_type: content_type,
|
83
|
+
data: Base64.strict_encode64( bytes )
|
84
|
+
}
|
85
|
+
}
|
86
|
+
else
|
87
|
+
raise UnsupportedContentError.new(
|
88
|
+
:anthropic,
|
89
|
+
'only support content of type image/*'
|
90
|
+
)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
raise UnsupportedContentError.new(
|
94
|
+
:anthropic,
|
95
|
+
'requires file content to include content type and (packed) bytes'
|
96
|
+
)
|
97
|
+
end
|
98
|
+
when :tool_call
|
99
|
+
result_message_content << {
|
100
|
+
type: 'tool_use',
|
101
|
+
id: content[ :tool_call_id ],
|
102
|
+
name: content[ :tool_name ],
|
103
|
+
input: content[ :tool_parameters ] || {}
|
104
|
+
}
|
105
|
+
when :tool_result
|
106
|
+
result_message_content << {
|
107
|
+
type: 'tool_result',
|
108
|
+
tool_use_id: content[ :tool_call_id ],
|
109
|
+
content: content[ :tool_result ]
|
110
|
+
}
|
111
|
+
else
|
112
|
+
raise InvalidContentError.new( :anthropic )
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
result_message[ :content ] = result_message_content
|
117
|
+
result[ :messages ] << result_message
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
index += 1
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
tools_attributes = chat_request_tools_attributes( conversation[ :tools ] )
|
126
|
+
result[ :tools ] = tools_attributes if tools_attributes && tools_attributes.length > 0
|
127
|
+
|
128
|
+
JSON.generate( result )
|
129
|
+
end
|
130
|
+
|
131
|
+
def chat_request_tools_attributes( tools )
|
132
|
+
properties_array_to_object = lambda do | properties |
|
133
|
+
return nil unless properties&.any?
|
134
|
+
object = {}
|
135
|
+
required = []
|
136
|
+
properties.each do | property |
|
137
|
+
name = property.delete( :name )
|
138
|
+
required << name if property.delete( :required )
|
139
|
+
if property[ :properties ]&.any?
|
140
|
+
property_properties, property_required =
|
141
|
+
properties_array_to_object.call( property[ :properties ] )
|
142
|
+
property[ :properties ] = property_properties
|
143
|
+
property[ :required ] = property_required if property_required.any?
|
144
|
+
end
|
145
|
+
object[ name ] = property
|
146
|
+
end
|
147
|
+
[ object, required.compact ]
|
148
|
+
end
|
149
|
+
|
150
|
+
tools&.map do | tool |
|
151
|
+
tool_attributes = {
|
152
|
+
name: tool[ :name ],
|
153
|
+
description: tool[ :description ],
|
154
|
+
input_schema: { type: 'object' }
|
155
|
+
}
|
156
|
+
|
157
|
+
if tool[ :properties ]&.any?
|
158
|
+
properties_object, properties_required =
|
159
|
+
properties_array_to_object.call( tool[ :properties ] )
|
160
|
+
input_schema = {
|
161
|
+
type: 'object',
|
162
|
+
properties: properties_object
|
163
|
+
}
|
164
|
+
input_schema[ :required ] = properties_required if properties_required.any?
|
165
|
+
tool_attributes[ :input_schema ] = input_schema
|
166
|
+
end
|
167
|
+
tool_attributes
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def to_anthropic_system_message( system_message )
|
174
|
+
return nil if system_message.nil?
|
175
|
+
|
176
|
+
# note: the current version of the anthropic api simply takes a string as the
|
177
|
+
# system message but the beta version requires an array of objects akin
|
178
|
+
# to message contents.
|
179
|
+
result = ''
|
180
|
+
system_message[ :contents ].each do | content |
|
181
|
+
result += content[ :text ] if content[ :type ] == :text
|
182
|
+
end
|
183
|
+
|
184
|
+
result.empty? ? nil : result
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -1,113 +1,6 @@
|
|
1
1
|
module Intelligence
|
2
2
|
module Anthropic
|
3
|
-
module
|
4
|
-
|
5
|
-
CHAT_REQUEST_URI = "https://api.anthropic.com/v1/messages"
|
6
|
-
|
7
|
-
def chat_request_uri( options )
|
8
|
-
CHAT_REQUEST_URI
|
9
|
-
end
|
10
|
-
|
11
|
-
def chat_request_headers( options = nil )
|
12
|
-
options = options ? self.class.configure( options ) : {}
|
13
|
-
options = @options.merge( options )
|
14
|
-
result = {}
|
15
|
-
|
16
|
-
key = options[ :key ]
|
17
|
-
version = options[ :version ] || "2023-06-01"
|
18
|
-
|
19
|
-
raise ArgumentError.new(
|
20
|
-
"An Anthropic key is required to build an Anthropic chat request."
|
21
|
-
) if key.nil?
|
22
|
-
|
23
|
-
result[ 'content-type' ] = 'application/json'
|
24
|
-
result[ 'x-api-key' ] = "#{key}"
|
25
|
-
result[ 'anthropic-version' ] = version unless version.nil?
|
26
|
-
|
27
|
-
result
|
28
|
-
end
|
29
|
-
|
30
|
-
def chat_request_body( conversation, options = nil )
|
31
|
-
options = options ? self.class.configure( options ) : {}
|
32
|
-
options = @options.merge( options )
|
33
|
-
result = options[ :chat_options ]&.compact || {}
|
34
|
-
|
35
|
-
system_message = translate_system_message( conversation[ :system_message ] )
|
36
|
-
result[ :system ] = system_message unless system_message.nil?
|
37
|
-
result[ :messages ] = []
|
38
|
-
|
39
|
-
messages = conversation[ :messages ]
|
40
|
-
length = messages&.length || 0
|
41
|
-
index = 0; while index < length
|
42
|
-
|
43
|
-
message = messages[ index ]
|
44
|
-
unless message.nil?
|
45
|
-
|
46
|
-
# The Anthropic API will not accept a sequence of messages where the role of two
|
47
|
-
# sequentian messages is the same.
|
48
|
-
#
|
49
|
-
# The purpose of this code is to identify such occurences and coalece them such
|
50
|
-
# that the first message in the sequence aggregates the contents of all subsequent
|
51
|
-
# messages with the same role.
|
52
|
-
look_ahead_index = index + 1; while look_ahead_index < length
|
53
|
-
ahead_message = messages[ look_ahead_index ]
|
54
|
-
unless ahead_message.nil?
|
55
|
-
if ahead_message[ :role ] == message[ :role ]
|
56
|
-
message[ :contents ] =
|
57
|
-
( message[ :contents ] || [] ) +
|
58
|
-
( ahead_message[ :contents ] || [] )
|
59
|
-
messages[ look_ahead_index ] = nil
|
60
|
-
look_ahead_index += 1
|
61
|
-
else
|
62
|
-
break
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
result_message = { role: message[ :role ] }
|
68
|
-
result_message_content = []
|
69
|
-
|
70
|
-
message[ :contents ]&.each do | content |
|
71
|
-
case content[ :type ]
|
72
|
-
when :text
|
73
|
-
result_message_content << { type: 'text', text: content[ :text ] }
|
74
|
-
when :binary
|
75
|
-
content_type = content[ :content_type ]
|
76
|
-
bytes = content[ :bytes ]
|
77
|
-
if content_type && bytes
|
78
|
-
mime_type = MIME::Types[ content_type ].first
|
79
|
-
if mime_type&.media_type == 'image'
|
80
|
-
result_message_content << {
|
81
|
-
type: 'image',
|
82
|
-
source: {
|
83
|
-
type: 'base64',
|
84
|
-
media_type: content_type,
|
85
|
-
data: Base64.strict_encode64( bytes )
|
86
|
-
}
|
87
|
-
}
|
88
|
-
else
|
89
|
-
raise UnsupportedContentError.new(
|
90
|
-
:anthropic,
|
91
|
-
'only support content of type image/*'
|
92
|
-
)
|
93
|
-
end
|
94
|
-
else
|
95
|
-
raise InvalidContentError.new( :anthropic )
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
result_message[ :content ] = result_message_content
|
101
|
-
result[ :messages ] << result_message
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
index += 1
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
JSON.generate( result )
|
110
|
-
end
|
3
|
+
module ChatResponseMethods
|
111
4
|
|
112
5
|
def chat_result_attributes( response )
|
113
6
|
return nil unless response.success?
|
@@ -130,6 +23,13 @@ module Intelligence
|
|
130
23
|
response_json[ :content ].each do | content |
|
131
24
|
if content[ :type ] == 'text'
|
132
25
|
result_content.push( { type: 'text', text: content[ :text ] } )
|
26
|
+
elsif content[ :type ] == 'tool_use'
|
27
|
+
result_content.push( {
|
28
|
+
type: :tool_call,
|
29
|
+
tool_call_id: content[ :id ],
|
30
|
+
tool_name: content[ :name ],
|
31
|
+
tool_parameters: content[ :input ]
|
32
|
+
} )
|
133
33
|
end
|
134
34
|
end
|
135
35
|
|
@@ -289,23 +189,6 @@ module Intelligence
|
|
289
189
|
|
290
190
|
private
|
291
191
|
|
292
|
-
def translate_system_message( system_message )
|
293
|
-
|
294
|
-
return nil if system_message.nil?
|
295
|
-
|
296
|
-
# note: the current version of the anthropic api simply takes a string as the
|
297
|
-
# system message but the beta version requires an array of objects akin
|
298
|
-
# to message contents.
|
299
|
-
|
300
|
-
result = ''
|
301
|
-
system_message[ :contents ].each do | content |
|
302
|
-
result += content[ :text ] if content[ :type ] == :text
|
303
|
-
end
|
304
|
-
|
305
|
-
result.empty? ? nil : result
|
306
|
-
|
307
|
-
end
|
308
|
-
|
309
192
|
def translate_end_result( end_result )
|
310
193
|
case end_result
|
311
194
|
when 'end_turn'
|
@@ -7,25 +7,25 @@ module Intelligence
|
|
7
7
|
|
8
8
|
chat_request_uri "https://api.cerebras.ai/v1/chat/completions"
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
schema do
|
11
|
+
key String
|
12
|
+
chat_options do
|
13
|
+
model String
|
14
|
+
max_tokens Integer
|
15
|
+
response_format do
|
16
|
+
type String, default: 'json_schema'
|
17
|
+
json_schema
|
18
18
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
seed Integer
|
20
|
+
stop array: true
|
21
|
+
stream [ TrueClass, FalseClass ]
|
22
|
+
temperature Float
|
23
|
+
top_p Float
|
24
|
+
tool_choice do
|
25
|
+
type String
|
26
|
+
mame String
|
27
27
|
end
|
28
|
-
|
28
|
+
user
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -21,8 +21,7 @@ module Intelligence
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def chat_request_headers( options = nil )
|
24
|
-
options = options
|
25
|
-
options = @options.merge( options )
|
24
|
+
options = @options.merge( build_options( options ) )
|
26
25
|
result = {}
|
27
26
|
|
28
27
|
key = options[ :key ]
|
@@ -37,8 +36,7 @@ module Intelligence
|
|
37
36
|
end
|
38
37
|
|
39
38
|
def chat_request_body( conversation, options = nil )
|
40
|
-
options = options
|
41
|
-
options = @options.merge( options )
|
39
|
+
options = @options.merge( build_options( options ) )
|
42
40
|
|
43
41
|
result = options[ :chat_options ]
|
44
42
|
result[ :messages ] = []
|
@@ -337,7 +335,16 @@ module Intelligence
|
|
337
335
|
end
|
338
336
|
end
|
339
337
|
|
340
|
-
|
338
|
+
private
|
339
|
+
|
340
|
+
def to_options( options, &block )
|
341
|
+
return {} unless options&.any?
|
342
|
+
@options_builder ||= DynamicSchema::Builder.new.define( &self.class.schema )
|
343
|
+
@options_builder.build( options, &block )
|
344
|
+
end
|
345
|
+
|
346
|
+
|
347
|
+
def system_message_to_s( system_message )
|
341
348
|
|
342
349
|
return nil if system_message.nil?
|
343
350
|
|
@@ -1,2 +1,2 @@
|
|
1
1
|
require_relative '../adapter'
|
2
|
-
require_relative 'generic/adapter'
|
2
|
+
require_relative 'generic/adapter'
|
@@ -1,44 +1,55 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'chat_request_methods'
|
2
|
+
require_relative 'chat_response_methods'
|
2
3
|
|
3
4
|
module Intelligence
|
4
5
|
module Google
|
5
6
|
class Adapter < Adapter::Base
|
6
7
|
|
7
|
-
|
8
|
+
schema do
|
8
9
|
|
9
10
|
# normalized properties for all endpoints
|
10
|
-
|
11
|
+
key String
|
11
12
|
|
12
|
-
|
13
|
+
chat_options as: :generationConfig do
|
13
14
|
|
14
15
|
# normalized properties for google generative text endpoint
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
model String
|
17
|
+
max_tokens Integer, as: :maxOutputTokens
|
18
|
+
n Integer, as: :candidateCount
|
19
|
+
temperature Float
|
20
|
+
top_k Integer, as: :topK
|
21
|
+
top_p Float, as: :topP
|
22
|
+
seed Integer
|
23
|
+
stop String, array: true, as: :stopSequences
|
24
|
+
stream [ TrueClass, FalseClass ]
|
25
|
+
|
26
|
+
frequency_penalty Float, as: :frequencyPenalty
|
27
|
+
presence_penalty Float, as: :presencePenalty
|
27
28
|
|
28
29
|
# google variant of normalized properties for google generative text endpoints
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
candidate_count Integer, as: :candidateCount
|
31
|
+
max_output_tokens Integer, as: :maxOutputTokens
|
32
|
+
stop_sequences String, array: true, as: :stopSequences
|
32
33
|
|
33
34
|
# google specific properties for google generative text endpoints
|
34
|
-
|
35
|
-
|
35
|
+
response_mime_type String, as: :responseMimeType
|
36
|
+
response_schema as: :responseSchema
|
37
|
+
|
38
|
+
# google specific tool configuration
|
39
|
+
tool_configuration as: :tool_config do
|
40
|
+
function_calling as: :function_calling_config do
|
41
|
+
mode Symbol, in: [ :auto, :any, :none ]
|
42
|
+
allowed_function_names String, array: true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
36
46
|
|
37
47
|
end
|
38
48
|
|
39
49
|
end
|
40
50
|
|
41
|
-
include
|
51
|
+
include ChatRequestMethods
|
52
|
+
include ChatResponseMethods
|
42
53
|
|
43
54
|
end
|
44
55
|
|