ruby_llm 0.1.0.pre → 0.1.0.pre3
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/.github/workflows/gem-push.yml +9 -3
- data/.github/workflows/test.yml +32 -0
- data/.gitignore +58 -0
- data/.overcommit.yml +26 -0
- data/.rspec +3 -0
- data/.rubocop.yml +3 -0
- data/Gemfile +5 -0
- data/README.md +68 -13
- data/Rakefile +4 -2
- data/bin/console +6 -3
- data/lib/ruby_llm/active_record/acts_as.rb +31 -18
- data/lib/ruby_llm/client.rb +32 -16
- data/lib/ruby_llm/configuration.rb +5 -3
- data/lib/ruby_llm/conversation.rb +3 -0
- data/lib/ruby_llm/message.rb +13 -4
- data/lib/ruby_llm/model_capabilities/anthropic.rb +81 -0
- data/lib/ruby_llm/model_capabilities/base.rb +35 -0
- data/lib/ruby_llm/model_capabilities/openai.rb +121 -0
- data/lib/ruby_llm/model_info.rb +42 -0
- data/lib/ruby_llm/providers/anthropic.rb +254 -0
- data/lib/ruby_llm/providers/base.rb +21 -2
- data/lib/ruby_llm/providers/openai.rb +189 -0
- data/lib/ruby_llm/railtie.rb +3 -0
- data/lib/ruby_llm/tool.rb +75 -0
- data/lib/ruby_llm/version.rb +3 -1
- data/lib/ruby_llm.rb +35 -3
- data/ruby_llm.gemspec +42 -31
- metadata +142 -17
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLLM
|
4
|
+
# Represents a tool/function that can be called by an LLM
|
5
|
+
class Tool
|
6
|
+
attr_reader :name, :description, :parameters, :handler
|
7
|
+
|
8
|
+
def self.from_method(method_object, description: nil, parameter_descriptions: {})
|
9
|
+
method_params = {}
|
10
|
+
method_object.parameters.each do |param_type, param_name|
|
11
|
+
next unless %i[req opt key keyreq].include?(param_type)
|
12
|
+
|
13
|
+
method_params[param_name] = {
|
14
|
+
type: 'string',
|
15
|
+
description: parameter_descriptions[param_name] || param_name.to_s.tr('_', ' '),
|
16
|
+
required: %i[req keyreq].include?(param_type)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
new(
|
21
|
+
name: method_object.name.to_s,
|
22
|
+
description: description || "Executes the #{method_object.name} operation",
|
23
|
+
parameters: method_params
|
24
|
+
) do |args|
|
25
|
+
# Create an instance if it's an instance method
|
26
|
+
instance = if method_object.owner.instance_methods.include?(method_object.name)
|
27
|
+
method_object.owner.new
|
28
|
+
else
|
29
|
+
method_object.owner
|
30
|
+
end
|
31
|
+
|
32
|
+
# Call the method with the arguments
|
33
|
+
if args.is_a?(Hash)
|
34
|
+
instance.method(method_object.name).call(**args)
|
35
|
+
else
|
36
|
+
instance.method(method_object.name).call(args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(name:, description:, parameters: {}, &block)
|
42
|
+
@name = name
|
43
|
+
@description = description
|
44
|
+
@parameters = parameters
|
45
|
+
@handler = block
|
46
|
+
|
47
|
+
validate!
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(args)
|
51
|
+
validated_args = validate_args!(args)
|
52
|
+
handler.call(validated_args)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def validate!
|
58
|
+
raise ArgumentError, 'Name must be a string' unless name.is_a?(String)
|
59
|
+
raise ArgumentError, 'Description must be a string' unless description.is_a?(String)
|
60
|
+
raise ArgumentError, 'Parameters must be a hash' unless parameters.is_a?(Hash)
|
61
|
+
raise ArgumentError, 'Block must be provided' unless handler.respond_to?(:call)
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_args!(args)
|
65
|
+
args = args.transform_keys(&:to_sym)
|
66
|
+
required_params = parameters.select { |_, v| v[:required] }.keys
|
67
|
+
|
68
|
+
required_params.each do |param|
|
69
|
+
raise ArgumentError, "Missing required parameter: #{param}" unless args.key?(param.to_sym)
|
70
|
+
end
|
71
|
+
|
72
|
+
args
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/ruby_llm/version.rb
CHANGED
data/lib/ruby_llm.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'zeitwerk'
|
2
4
|
require 'faraday'
|
3
5
|
require 'json'
|
6
|
+
require 'securerandom'
|
7
|
+
require 'logger'
|
4
8
|
|
9
|
+
# Main module for RubyLLM functionality
|
5
10
|
module RubyLLM
|
6
11
|
class Error < StandardError; end
|
7
12
|
|
8
13
|
class << self
|
9
|
-
|
14
|
+
attr_writer :configuration
|
15
|
+
|
16
|
+
def configuration
|
17
|
+
@configuration ||= Configuration.new
|
18
|
+
end
|
10
19
|
|
11
20
|
def configure
|
12
|
-
self.configuration ||= Configuration.new
|
13
21
|
yield(configuration) if block_given?
|
14
22
|
end
|
15
23
|
|
@@ -20,17 +28,41 @@ module RubyLLM
|
|
20
28
|
def loader
|
21
29
|
@loader ||= begin
|
22
30
|
loader = Zeitwerk::Loader.for_gem
|
31
|
+
|
32
|
+
# Add lib directory to the load path
|
33
|
+
loader.push_dir(File.expand_path('..', __dir__))
|
34
|
+
|
35
|
+
# Configure custom inflections
|
23
36
|
loader.inflector.inflect(
|
37
|
+
'ruby_llm' => 'RubyLLM',
|
24
38
|
'llm' => 'LLM',
|
25
39
|
'openai' => 'OpenAI',
|
26
40
|
'api' => 'API'
|
27
41
|
)
|
42
|
+
|
43
|
+
# Ignore Rails-specific files and specs
|
44
|
+
loader.ignore("#{__dir__}/ruby_llm/railtie.rb")
|
45
|
+
loader.ignore("#{__dir__}/ruby_llm/active_record")
|
46
|
+
loader.ignore(File.expand_path('../spec', __dir__).to_s)
|
47
|
+
|
48
|
+
# Log autoloading in debug mode
|
49
|
+
loader.logger = Logger.new($stdout) if ENV['RUBY_LLM_DEBUG']
|
50
|
+
loader.enable_reloading if ENV['RUBY_LLM_DEBUG']
|
51
|
+
|
28
52
|
loader.setup
|
53
|
+
loader.eager_load
|
29
54
|
loader
|
30
55
|
end
|
31
56
|
end
|
32
57
|
end
|
33
58
|
end
|
34
59
|
|
35
|
-
#
|
60
|
+
# Initialize loader
|
36
61
|
RubyLLM.loader
|
62
|
+
|
63
|
+
# Load Rails integration if Rails is defined
|
64
|
+
if defined?(Rails)
|
65
|
+
require 'active_support'
|
66
|
+
require 'ruby_llm/railtie'
|
67
|
+
require 'ruby_llm/active_record/acts_as'
|
68
|
+
end
|
data/ruby_llm.gemspec
CHANGED
@@ -1,48 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'lib/ruby_llm/version'
|
2
4
|
|
3
5
|
Gem::Specification.new do |spec|
|
4
|
-
spec.name =
|
6
|
+
spec.name = 'ruby_llm'
|
5
7
|
spec.version = RubyLLM::VERSION
|
6
|
-
spec.authors = [
|
7
|
-
spec.email = [
|
8
|
-
|
9
|
-
spec.summary =
|
10
|
-
spec.description =
|
11
|
-
|
12
|
-
|
13
|
-
spec.
|
14
|
-
spec.
|
15
|
-
|
16
|
-
|
17
|
-
spec.metadata[
|
18
|
-
spec.metadata[
|
19
|
-
spec.metadata[
|
20
|
-
spec.metadata[
|
8
|
+
spec.authors = ['Carmine Paolino']
|
9
|
+
spec.email = ['carmine@paolino.me']
|
10
|
+
|
11
|
+
spec.summary = 'The Ruby LLM client library - unified interface for OpenAI, Anthropic, and other LLM providers'
|
12
|
+
spec.description = 'Complete Ruby library for working with Large Language Models (LLMs). ' \
|
13
|
+
'Supports OpenAI, Anthropic, and others with a consistent interface. ' \
|
14
|
+
'Features include tool usage, token tracking, and seamless Rails integration.'
|
15
|
+
spec.homepage = 'https://github.com/crmne/ruby_llm'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
|
18
|
+
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
20
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
21
|
+
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
22
|
+
spec.metadata['documentation_uri'] = 'https://rubydoc.info/gems/ruby_llm'
|
23
|
+
spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
|
21
24
|
|
22
25
|
# Specify which files should be added to the gem when it is released.
|
23
26
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
-
spec.files = Dir.chdir(File.expand_path(
|
27
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
28
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
29
|
end
|
27
|
-
spec.bindir =
|
30
|
+
spec.bindir = 'exe'
|
28
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
-
spec.require_paths = [
|
32
|
+
spec.require_paths = ['lib']
|
30
33
|
|
31
34
|
# Runtime dependencies
|
32
|
-
spec.add_dependency
|
33
|
-
spec.add_dependency
|
34
|
-
spec.add_dependency
|
35
|
+
spec.add_dependency 'faraday', '>= 2.0'
|
36
|
+
spec.add_dependency 'faraday-multipart', '>= 1.0'
|
37
|
+
spec.add_dependency 'zeitwerk', '>= 2.6'
|
35
38
|
|
36
39
|
# Rails integration dependencies
|
37
|
-
spec.add_development_dependency
|
38
|
-
spec.add_development_dependency
|
40
|
+
spec.add_development_dependency 'activerecord', '>= 6.0', '< 9.0'
|
41
|
+
spec.add_development_dependency 'activesupport', '>= 6.0', '< 9.0'
|
39
42
|
|
40
43
|
# Development dependencies
|
41
|
-
spec.add_development_dependency
|
42
|
-
spec.add_development_dependency
|
43
|
-
spec.add_development_dependency
|
44
|
-
spec.add_development_dependency
|
45
|
-
spec.add_development_dependency
|
46
|
-
spec.add_development_dependency
|
47
|
-
spec.add_development_dependency
|
44
|
+
spec.add_development_dependency 'bundler', '>= 2.0'
|
45
|
+
spec.add_development_dependency 'dotenv'
|
46
|
+
spec.add_development_dependency 'irb'
|
47
|
+
spec.add_development_dependency 'overcommit', '>= 0.66'
|
48
|
+
spec.add_development_dependency 'pry', '>= 0.14'
|
49
|
+
spec.add_development_dependency 'rake', '>= 13.0'
|
50
|
+
spec.add_development_dependency 'rdoc'
|
51
|
+
spec.add_development_dependency 'reline'
|
52
|
+
spec.add_development_dependency 'rspec', '~> 3.12'
|
53
|
+
spec.add_development_dependency 'rubocop', '>= 1.0'
|
54
|
+
spec.add_development_dependency 'rubocop-rake', '>= 0.6'
|
55
|
+
spec.add_development_dependency 'rubocop-rspec', '>= 3.4'
|
56
|
+
spec.add_development_dependency 'simplecov', '>= 0.21'
|
57
|
+
spec.add_development_dependency 'webmock', '~> 3.18'
|
58
|
+
spec.add_development_dependency 'yard', '>= 0.9'
|
48
59
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_llm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carmine Paolino
|
@@ -52,7 +52,7 @@ dependencies:
|
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '2.6'
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
|
-
name:
|
55
|
+
name: activerecord
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - ">="
|
@@ -72,7 +72,7 @@ dependencies:
|
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '9.0'
|
74
74
|
- !ruby/object:Gem::Dependency
|
75
|
-
name:
|
75
|
+
name: activesupport
|
76
76
|
requirement: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
78
|
- - ">="
|
@@ -105,6 +105,62 @@ dependencies:
|
|
105
105
|
- - ">="
|
106
106
|
- !ruby/object:Gem::Version
|
107
107
|
version: '2.0'
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: dotenv
|
110
|
+
requirement: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
type: :development
|
116
|
+
prerelease: false
|
117
|
+
version_requirements: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
- !ruby/object:Gem::Dependency
|
123
|
+
name: irb
|
124
|
+
requirement: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
type: :development
|
130
|
+
prerelease: false
|
131
|
+
version_requirements: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
- !ruby/object:Gem::Dependency
|
137
|
+
name: overcommit
|
138
|
+
requirement: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0.66'
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0.66'
|
150
|
+
- !ruby/object:Gem::Dependency
|
151
|
+
name: pry
|
152
|
+
requirement: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0.14'
|
157
|
+
type: :development
|
158
|
+
prerelease: false
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0.14'
|
108
164
|
- !ruby/object:Gem::Dependency
|
109
165
|
name: rake
|
110
166
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,6 +175,48 @@ dependencies:
|
|
119
175
|
- - ">="
|
120
176
|
- !ruby/object:Gem::Version
|
121
177
|
version: '13.0'
|
178
|
+
- !ruby/object:Gem::Dependency
|
179
|
+
name: rdoc
|
180
|
+
requirement: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
type: :development
|
186
|
+
prerelease: false
|
187
|
+
version_requirements: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
- !ruby/object:Gem::Dependency
|
193
|
+
name: reline
|
194
|
+
requirement: !ruby/object:Gem::Requirement
|
195
|
+
requirements:
|
196
|
+
- - ">="
|
197
|
+
- !ruby/object:Gem::Version
|
198
|
+
version: '0'
|
199
|
+
type: :development
|
200
|
+
prerelease: false
|
201
|
+
version_requirements: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
- !ruby/object:Gem::Dependency
|
207
|
+
name: rspec
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
209
|
+
requirements:
|
210
|
+
- - "~>"
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '3.12'
|
213
|
+
type: :development
|
214
|
+
prerelease: false
|
215
|
+
version_requirements: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - "~>"
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: '3.12'
|
122
220
|
- !ruby/object:Gem::Dependency
|
123
221
|
name: rubocop
|
124
222
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,19 +232,33 @@ dependencies:
|
|
134
232
|
- !ruby/object:Gem::Version
|
135
233
|
version: '1.0'
|
136
234
|
- !ruby/object:Gem::Dependency
|
137
|
-
name:
|
235
|
+
name: rubocop-rake
|
138
236
|
requirement: !ruby/object:Gem::Requirement
|
139
237
|
requirements:
|
140
238
|
- - ">="
|
141
239
|
- !ruby/object:Gem::Version
|
142
|
-
version: '0.
|
240
|
+
version: '0.6'
|
143
241
|
type: :development
|
144
242
|
prerelease: false
|
145
243
|
version_requirements: !ruby/object:Gem::Requirement
|
146
244
|
requirements:
|
147
245
|
- - ">="
|
148
246
|
- !ruby/object:Gem::Version
|
149
|
-
version: '0.
|
247
|
+
version: '0.6'
|
248
|
+
- !ruby/object:Gem::Dependency
|
249
|
+
name: rubocop-rspec
|
250
|
+
requirement: !ruby/object:Gem::Requirement
|
251
|
+
requirements:
|
252
|
+
- - ">="
|
253
|
+
- !ruby/object:Gem::Version
|
254
|
+
version: '3.4'
|
255
|
+
type: :development
|
256
|
+
prerelease: false
|
257
|
+
version_requirements: !ruby/object:Gem::Requirement
|
258
|
+
requirements:
|
259
|
+
- - ">="
|
260
|
+
- !ruby/object:Gem::Version
|
261
|
+
version: '3.4'
|
150
262
|
- !ruby/object:Gem::Dependency
|
151
263
|
name: simplecov
|
152
264
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,36 +274,36 @@ dependencies:
|
|
162
274
|
- !ruby/object:Gem::Version
|
163
275
|
version: '0.21'
|
164
276
|
- !ruby/object:Gem::Dependency
|
165
|
-
name:
|
277
|
+
name: webmock
|
166
278
|
requirement: !ruby/object:Gem::Requirement
|
167
279
|
requirements:
|
168
|
-
- - "
|
280
|
+
- - "~>"
|
169
281
|
- !ruby/object:Gem::Version
|
170
|
-
version: '
|
282
|
+
version: '3.18'
|
171
283
|
type: :development
|
172
284
|
prerelease: false
|
173
285
|
version_requirements: !ruby/object:Gem::Requirement
|
174
286
|
requirements:
|
175
|
-
- - "
|
287
|
+
- - "~>"
|
176
288
|
- !ruby/object:Gem::Version
|
177
|
-
version: '
|
289
|
+
version: '3.18'
|
178
290
|
- !ruby/object:Gem::Dependency
|
179
|
-
name:
|
291
|
+
name: yard
|
180
292
|
requirement: !ruby/object:Gem::Requirement
|
181
293
|
requirements:
|
182
294
|
- - ">="
|
183
295
|
- !ruby/object:Gem::Version
|
184
|
-
version: '0.
|
296
|
+
version: '0.9'
|
185
297
|
type: :development
|
186
298
|
prerelease: false
|
187
299
|
version_requirements: !ruby/object:Gem::Requirement
|
188
300
|
requirements:
|
189
301
|
- - ">="
|
190
302
|
- !ruby/object:Gem::Version
|
191
|
-
version: '0.
|
192
|
-
description:
|
193
|
-
|
194
|
-
|
303
|
+
version: '0.9'
|
304
|
+
description: Complete Ruby library for working with Large Language Models (LLMs).
|
305
|
+
Supports OpenAI, Anthropic, and others with a consistent interface. Features include
|
306
|
+
tool usage, token tracking, and seamless Rails integration.
|
195
307
|
email:
|
196
308
|
- carmine@paolino.me
|
197
309
|
executables: []
|
@@ -199,6 +311,12 @@ extensions: []
|
|
199
311
|
extra_rdoc_files: []
|
200
312
|
files:
|
201
313
|
- ".github/workflows/gem-push.yml"
|
314
|
+
- ".github/workflows/test.yml"
|
315
|
+
- ".gitignore"
|
316
|
+
- ".overcommit.yml"
|
317
|
+
- ".rspec"
|
318
|
+
- ".rubocop.yml"
|
319
|
+
- Gemfile
|
202
320
|
- README.md
|
203
321
|
- Rakefile
|
204
322
|
- bin/console
|
@@ -209,8 +327,15 @@ files:
|
|
209
327
|
- lib/ruby_llm/configuration.rb
|
210
328
|
- lib/ruby_llm/conversation.rb
|
211
329
|
- lib/ruby_llm/message.rb
|
330
|
+
- lib/ruby_llm/model_capabilities/anthropic.rb
|
331
|
+
- lib/ruby_llm/model_capabilities/base.rb
|
332
|
+
- lib/ruby_llm/model_capabilities/openai.rb
|
333
|
+
- lib/ruby_llm/model_info.rb
|
334
|
+
- lib/ruby_llm/providers/anthropic.rb
|
212
335
|
- lib/ruby_llm/providers/base.rb
|
336
|
+
- lib/ruby_llm/providers/openai.rb
|
213
337
|
- lib/ruby_llm/railtie.rb
|
338
|
+
- lib/ruby_llm/tool.rb
|
214
339
|
- lib/ruby_llm/version.rb
|
215
340
|
- ruby_llm.gemspec
|
216
341
|
homepage: https://github.com/crmne/ruby_llm
|