ruby_llm 1.0.0 → 1.1.0rc1
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 +58 -19
- data/lib/ruby_llm/active_record/acts_as.rb +46 -7
- data/lib/ruby_llm/aliases.json +65 -0
- data/lib/ruby_llm/aliases.rb +56 -0
- data/lib/ruby_llm/chat.rb +11 -10
- data/lib/ruby_llm/configuration.rb +4 -0
- data/lib/ruby_llm/error.rb +15 -4
- data/lib/ruby_llm/models.json +1489 -283
- data/lib/ruby_llm/models.rb +57 -22
- data/lib/ruby_llm/provider.rb +44 -41
- data/lib/ruby_llm/providers/anthropic/capabilities.rb +8 -9
- data/lib/ruby_llm/providers/anthropic/chat.rb +31 -4
- data/lib/ruby_llm/providers/anthropic/streaming.rb +12 -6
- data/lib/ruby_llm/providers/anthropic.rb +4 -0
- data/lib/ruby_llm/providers/bedrock/capabilities.rb +168 -0
- data/lib/ruby_llm/providers/bedrock/chat.rb +108 -0
- data/lib/ruby_llm/providers/bedrock/models.rb +84 -0
- data/lib/ruby_llm/providers/bedrock/signing.rb +831 -0
- data/lib/ruby_llm/providers/bedrock/streaming/base.rb +46 -0
- data/lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb +63 -0
- data/lib/ruby_llm/providers/bedrock/streaming/message_processing.rb +79 -0
- data/lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb +90 -0
- data/lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb +91 -0
- data/lib/ruby_llm/providers/bedrock/streaming.rb +36 -0
- data/lib/ruby_llm/providers/bedrock.rb +83 -0
- data/lib/ruby_llm/providers/deepseek/chat.rb +17 -0
- data/lib/ruby_llm/providers/deepseek.rb +5 -0
- data/lib/ruby_llm/providers/gemini/capabilities.rb +50 -34
- data/lib/ruby_llm/providers/gemini/chat.rb +8 -15
- data/lib/ruby_llm/providers/gemini/images.rb +5 -10
- data/lib/ruby_llm/providers/gemini/models.rb +0 -8
- data/lib/ruby_llm/providers/gemini/streaming.rb +35 -76
- data/lib/ruby_llm/providers/gemini/tools.rb +12 -12
- data/lib/ruby_llm/providers/gemini.rb +4 -0
- data/lib/ruby_llm/providers/openai/capabilities.rb +154 -177
- data/lib/ruby_llm/providers/openai/streaming.rb +9 -13
- data/lib/ruby_llm/providers/openai.rb +4 -0
- data/lib/ruby_llm/streaming.rb +96 -0
- data/lib/ruby_llm/tool.rb +15 -7
- data/lib/ruby_llm/version.rb +1 -1
- data/lib/ruby_llm.rb +8 -3
- data/lib/tasks/browser_helper.rb +97 -0
- data/lib/tasks/capability_generator.rb +123 -0
- data/lib/tasks/capability_scraper.rb +224 -0
- data/lib/tasks/cli_helper.rb +22 -0
- data/lib/tasks/code_validator.rb +29 -0
- data/lib/tasks/model_updater.rb +66 -0
- data/lib/tasks/models.rake +28 -197
- data/lib/tasks/vcr.rake +97 -0
- metadata +42 -19
- data/.github/workflows/cicd.yml +0 -109
- data/.github/workflows/docs.yml +0 -53
- data/.gitignore +0 -58
- data/.overcommit.yml +0 -26
- data/.rspec +0 -3
- data/.rspec_status +0 -50
- data/.rubocop.yml +0 -10
- data/.yardopts +0 -12
- data/Gemfile +0 -32
- data/Rakefile +0 -9
- data/bin/console +0 -17
- data/bin/setup +0 -6
- data/ruby_llm.gemspec +0 -43
data/lib/tasks/models.rake
CHANGED
@@ -1,212 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# URLs to process
|
8
|
-
PROVIDER_DOCS = {
|
9
|
-
openai: {
|
10
|
-
models: 'https://platform.openai.com/docs/models',
|
11
|
-
pricing: 'https://platform.openai.com/docs/pricing'
|
12
|
-
},
|
13
|
-
gemini: {
|
14
|
-
models: 'https://ai.google.dev/gemini-api/docs/models/gemini',
|
15
|
-
pricing: 'https://ai.google.dev/gemini-api/docs/pricing'
|
16
|
-
},
|
17
|
-
deepseek: {
|
18
|
-
models: 'https://api-docs.deepseek.com/quick_start/pricing/'
|
19
|
-
},
|
20
|
-
anthropic: {
|
21
|
-
models: 'https://docs.anthropic.com/en/docs/about-claude/models/all-models'
|
22
|
-
}
|
23
|
-
}.freeze
|
24
|
-
|
25
|
-
def fetch_page(url) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
26
|
-
if url.include?('openai.com')
|
27
|
-
puts "Please visit #{url} and paste the content below (type 'END' on a new line when done):"
|
28
|
-
original_separator = $INPUT_RECORD_SEPARATOR
|
29
|
-
$/ = 'END'
|
30
|
-
content = $stdin.gets&.chomp
|
31
|
-
$/ = original_separator
|
32
|
-
|
33
|
-
raise "No content provided for #{url}" unless content
|
34
|
-
|
35
|
-
content
|
36
|
-
else
|
37
|
-
response = http_client.get(url)
|
38
|
-
html = Nokogiri::HTML(response.body)
|
39
|
-
|
40
|
-
# Remove script tags and comments
|
41
|
-
html.css('script').remove
|
42
|
-
html.xpath('//comment()').remove
|
43
|
-
|
44
|
-
# Extract text content
|
45
|
-
text = html.css('body').text
|
46
|
-
|
47
|
-
# Clean up whitespace
|
48
|
-
text.gsub!(/\s+/, ' ')
|
49
|
-
text.strip!
|
50
|
-
|
51
|
-
text
|
52
|
-
end
|
53
|
-
rescue StandardError => e
|
54
|
-
raise "Failed to fetch #{url}: #{e.message}"
|
55
|
-
end
|
56
|
-
|
57
|
-
def http_client
|
58
|
-
@http_client ||= Faraday.new do |f|
|
59
|
-
f.response :raise_error
|
60
|
-
f.response :logger, RubyLLM.logger, { headers: false, bodies: true }
|
61
|
-
end
|
62
|
-
end
|
3
|
+
require_relative 'model_updater'
|
4
|
+
require_relative 'capability_scraper'
|
5
|
+
require_relative 'capability_generator'
|
63
6
|
|
64
7
|
namespace :models do # rubocop:disable Metrics/BlockLength
|
65
|
-
desc 'Update available models from providers'
|
8
|
+
desc 'Update available models from providers (API keys needed)'
|
66
9
|
task :update do
|
67
|
-
|
68
|
-
|
69
|
-
# Configure API keys
|
70
|
-
RubyLLM.configure do |config|
|
71
|
-
config.openai_api_key = ENV.fetch('OPENAI_API_KEY')
|
72
|
-
config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY')
|
73
|
-
config.gemini_api_key = ENV.fetch('GEMINI_API_KEY')
|
74
|
-
config.deepseek_api_key = ENV.fetch('DEEPSEEK_API_KEY')
|
75
|
-
end
|
76
|
-
|
77
|
-
# Refresh models (now returns self instead of models array)
|
78
|
-
models = RubyLLM.models.refresh!.all
|
79
|
-
# Write to models.json
|
80
|
-
File.write(File.expand_path('../ruby_llm/models.json', __dir__), JSON.pretty_generate(models.map(&:to_h)))
|
81
|
-
|
82
|
-
puts "Updated models.json with #{models.size} models:"
|
83
|
-
RubyLLM::Provider.providers.each do |provider_sym, provider_module|
|
84
|
-
provider_name = provider_module.to_s.split('::').last
|
85
|
-
provider_models = models.select { |m| m.provider == provider_sym.to_s }
|
86
|
-
puts "#{provider_name} models: #{provider_models.size}"
|
87
|
-
end
|
10
|
+
ModelUpdater.new.run
|
88
11
|
end
|
89
12
|
|
90
|
-
desc 'Update
|
91
|
-
task :update_capabilities do
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
# Configure API keys
|
98
|
-
RubyLLM.configure do |config|
|
99
|
-
config.openai_api_key = ENV.fetch('OPENAI_API_KEY')
|
100
|
-
config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY')
|
101
|
-
config.gemini_api_key = ENV.fetch('GEMINI_API_KEY')
|
13
|
+
desc 'Update capabilities modules (GEMINI_API_KEY needed)'
|
14
|
+
task :update_capabilities, [:providers] do |_t, args|
|
15
|
+
gemini_key = ENV.fetch('GEMINI_API_KEY', nil)
|
16
|
+
unless gemini_key && !gemini_key.empty?
|
17
|
+
puts 'Error: GEMINI_API_KEY required'
|
18
|
+
exit(1)
|
102
19
|
end
|
103
20
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
PROVIDER_DOCS
|
109
|
-
end
|
110
|
-
|
111
|
-
# Process each provider
|
112
|
-
providers_to_process.each do |provider, urls| # rubocop:disable Metrics/BlockLength
|
113
|
-
puts "Processing #{provider}..."
|
114
|
-
|
115
|
-
# Initialize our AI assistants
|
116
|
-
#
|
117
|
-
gemini = RubyLLM.chat(model: 'gemini-2.0-flash').with_temperature(0)
|
118
|
-
claude = RubyLLM.chat(model: 'claude-3-7-sonnet-20250219').with_temperature(0)
|
119
|
-
|
120
|
-
# Read existing capabilities file if present
|
121
|
-
existing_file = "lib/ruby_llm/providers/#{provider}/capabilities.rb"
|
122
|
-
existing_code = File.read(existing_file) if File.exist?(existing_file)
|
123
|
-
|
124
|
-
begin
|
125
|
-
# Download documentation
|
126
|
-
docs = urls.map do |type, url|
|
127
|
-
puts " Getting #{type} documentation..."
|
128
|
-
content = fetch_page(url)
|
129
|
-
|
130
|
-
puts "\nHere's what I got:\n\n"
|
131
|
-
puts "#{content.slice(0, 500)}...\n\n"
|
132
|
-
|
133
|
-
loop do
|
134
|
-
print 'Does this content look correct? (y/n): '
|
135
|
-
answer = $stdin.gets&.chomp&.downcase
|
136
|
-
break if answer == 'y'
|
137
|
-
raise "Content verification failed for #{url}" if answer == 'n'
|
138
|
-
end
|
139
|
-
|
140
|
-
"#{type.to_s.upcase} DOCUMENTATION:\n\n#{content}"
|
141
|
-
end.join("\n\n")
|
142
|
-
|
143
|
-
# Extract relevant information with Gemini
|
144
|
-
puts ' Extracting model information...'
|
145
|
-
extraction_prompt = <<~PROMPT
|
146
|
-
Extract relevant model capabilities information from this documentation:
|
147
|
-
|
148
|
-
#{docs}
|
149
|
-
|
150
|
-
Focus on:
|
151
|
-
1. Available models and their IDs
|
152
|
-
2. Context window sizes
|
153
|
-
3. Maximum output tokens
|
154
|
-
4. Pricing information
|
155
|
-
5. Model capabilities (vision, function calling, etc)
|
156
|
-
|
157
|
-
Format the information clearly and concisely, focusing only on facts about the models.
|
158
|
-
PROMPT
|
159
|
-
|
160
|
-
model_info = gemini.ask(extraction_prompt).content
|
161
|
-
|
162
|
-
# Generate Ruby code with Claude
|
163
|
-
puts ' Generating Ruby code...'
|
164
|
-
code_prompt = <<~PROMPT
|
165
|
-
I need you to generate a Ruby module for #{provider}'s model capabilities.
|
166
|
-
Use this extracted model information:
|
167
|
-
|
168
|
-
#{model_info}
|
169
|
-
|
170
|
-
The module should go in lib/ruby_llm/providers/#{provider}/capabilities.rb and follow these conventions:
|
171
|
-
|
172
|
-
1. Include methods for determining context windows, token limits, pricing, and capabilities
|
173
|
-
2. Use consistent naming with other providers
|
174
|
-
3. Include detailed pricing information in a PRICES constant
|
175
|
-
4. Follow the existing structure in the codebase
|
176
|
-
5. Use Ruby idioms and clean code practices
|
177
|
-
6. Include module_function to make methods callable at module level
|
178
|
-
7. Include all necessary method documentation
|
179
|
-
|
180
|
-
Here's the existing implementation for reference (maintain similar structure and same method names):
|
181
|
-
|
182
|
-
#{existing_code}
|
183
|
-
|
184
|
-
Focus on accuracy and maintaining consistency with the existing codebase structure.
|
185
|
-
PROMPT
|
186
|
-
|
187
|
-
response = claude.ask(code_prompt)
|
188
|
-
|
189
|
-
# Extract Ruby code from Claude's response
|
190
|
-
puts " Extracting Ruby code from Claude's response..."
|
191
|
-
ruby_code = nil
|
192
|
-
|
193
|
-
# Look for Ruby code block
|
194
|
-
ruby_code = Regexp.last_match(1).strip if response.content =~ /```ruby\s*(.*?)```/m
|
195
|
-
|
196
|
-
# Verify we found Ruby code
|
197
|
-
raise "No Ruby code block found in Claude's response" if ruby_code.nil? || ruby_code.empty?
|
21
|
+
RubyLLM.configure do |c|
|
22
|
+
c.gemini_api_key = gemini_key
|
23
|
+
c.request_timeout = 300
|
24
|
+
end
|
198
25
|
|
199
|
-
|
200
|
-
file_path = "lib/ruby_llm/providers/#{provider}/capabilities.rb"
|
201
|
-
puts " Writing #{file_path}..."
|
26
|
+
target_providers = CapabilityScraper.parse_providers(args[:providers])
|
202
27
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
28
|
+
begin
|
29
|
+
scraper = CapabilityScraper.new(target_providers)
|
30
|
+
scraper.run do |provider, docs_html|
|
31
|
+
generator = CapabilityGenerator.new(provider, docs_html)
|
32
|
+
generator.generate_and_save
|
207
33
|
end
|
34
|
+
rescue StandardError => e
|
35
|
+
puts "Error: #{e.message}"
|
36
|
+
puts e.backtrace.first(5).join("\n")
|
37
|
+
ensure
|
38
|
+
puts 'Update process complete. Review generated files.'
|
208
39
|
end
|
209
|
-
|
210
|
-
puts "Done! Don't forget to review the generated code and run the tests."
|
211
40
|
end
|
212
41
|
end
|
42
|
+
|
43
|
+
task default: ['models:update']
|
data/lib/tasks/vcr.rake
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Helper functions at the top level
|
4
|
+
def record_all_cassettes(cassette_dir)
|
5
|
+
# Re-record all cassettes
|
6
|
+
FileUtils.rm_rf(cassette_dir)
|
7
|
+
FileUtils.mkdir_p(cassette_dir)
|
8
|
+
|
9
|
+
puts 'Recording cassettes for all providers...'
|
10
|
+
run_tests
|
11
|
+
puts 'Done recording. Please review the new cassettes.'
|
12
|
+
end
|
13
|
+
|
14
|
+
def record_for_providers(providers, cassette_dir) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
15
|
+
# Get the list of available providers from RubyLLM itself
|
16
|
+
all_providers = RubyLLM::Provider.providers.keys.map(&:to_s)
|
17
|
+
|
18
|
+
# Check for valid providers
|
19
|
+
if providers.empty?
|
20
|
+
puts "Please specify providers or 'all'. Example: rake vcr:record[openai,anthropic]"
|
21
|
+
puts "Available providers: #{all_providers.join(', ')}"
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
invalid_providers = providers - all_providers
|
26
|
+
if invalid_providers.any?
|
27
|
+
puts "Invalid providers: #{invalid_providers.join(', ')}"
|
28
|
+
puts "Available providers: #{all_providers.join(', ')}"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
# Find and delete matching cassettes
|
33
|
+
cassettes_to_delete = find_matching_cassettes(cassette_dir, providers)
|
34
|
+
|
35
|
+
if cassettes_to_delete.empty?
|
36
|
+
puts 'No cassettes found for the specified providers.'
|
37
|
+
puts 'Running tests to record new cassettes...'
|
38
|
+
else
|
39
|
+
delete_cassettes(cassettes_to_delete)
|
40
|
+
puts "\nRunning tests to record new cassettes..."
|
41
|
+
end
|
42
|
+
|
43
|
+
run_tests
|
44
|
+
|
45
|
+
puts "\nDone recording cassettes for #{providers.join(', ')}."
|
46
|
+
puts 'Please review the updated cassettes for sensitive information.'
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_matching_cassettes(dir, providers) # rubocop:disable Metrics/MethodLength
|
50
|
+
cassettes = []
|
51
|
+
|
52
|
+
Dir.glob("#{dir}/**/*.yml").each do |file|
|
53
|
+
basename = File.basename(file)
|
54
|
+
|
55
|
+
# Precise matching to avoid cross-provider confusion
|
56
|
+
providers.each do |provider|
|
57
|
+
# Match only exact provider prefixes
|
58
|
+
next unless basename =~ /^[^_]*_#{provider}_/ || # For first section like "chat_openai_"
|
59
|
+
basename =~ /_#{provider}_[^_]+_/ # For middle sections like "_openai_gpt4_"
|
60
|
+
|
61
|
+
cassettes << file
|
62
|
+
break
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
cassettes
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete_cassettes(cassettes)
|
70
|
+
puts "Deleting #{cassettes.size} cassettes for re-recording:"
|
71
|
+
cassettes.each do |file|
|
72
|
+
puts " - #{File.basename(file)}"
|
73
|
+
File.delete(file)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def run_tests
|
78
|
+
system('bundle exec rspec') || abort('Tests failed')
|
79
|
+
end
|
80
|
+
|
81
|
+
namespace :vcr do
|
82
|
+
desc 'Record VCR cassettes (rake vcr:record[all] or vcr:record[openai,anthropic])'
|
83
|
+
task :record, [:providers] do |_, args|
|
84
|
+
require 'fileutils'
|
85
|
+
require 'ruby_llm'
|
86
|
+
|
87
|
+
providers = (args[:providers] || '').downcase.split(',')
|
88
|
+
cassette_dir = 'spec/fixtures/vcr_cassettes'
|
89
|
+
FileUtils.mkdir_p(cassette_dir)
|
90
|
+
|
91
|
+
if providers.include?('all')
|
92
|
+
record_all_cassettes(cassette_dir)
|
93
|
+
else
|
94
|
+
record_for_providers(providers, cassette_dir)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_llm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carmine Paolino
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: base64
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: event_stream_parser
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,31 +96,21 @@ dependencies:
|
|
82
96
|
version: '2'
|
83
97
|
description: A delightful Ruby way to work with AI. Chat in text, analyze and generate
|
84
98
|
images, understand audio, and use tools through a unified interface to OpenAI, Anthropic,
|
85
|
-
Google, and DeepSeek. Built for developer happiness with
|
86
|
-
proper streaming, and Rails integration. No wrapping your
|
87
|
-
- just clean Ruby code that works.
|
99
|
+
Google, AWS Bedrock Anthropic, and DeepSeek. Built for developer happiness with
|
100
|
+
automatic token counting, proper streaming, and Rails integration. No wrapping your
|
101
|
+
head around multiple APIs - just clean Ruby code that works.
|
88
102
|
email:
|
89
103
|
- carmine@paolino.me
|
90
104
|
executables: []
|
91
105
|
extensions: []
|
92
106
|
extra_rdoc_files: []
|
93
107
|
files:
|
94
|
-
- ".github/workflows/cicd.yml"
|
95
|
-
- ".github/workflows/docs.yml"
|
96
|
-
- ".gitignore"
|
97
|
-
- ".overcommit.yml"
|
98
|
-
- ".rspec"
|
99
|
-
- ".rspec_status"
|
100
|
-
- ".rubocop.yml"
|
101
|
-
- ".yardopts"
|
102
|
-
- Gemfile
|
103
108
|
- LICENSE
|
104
109
|
- README.md
|
105
|
-
- Rakefile
|
106
|
-
- bin/console
|
107
|
-
- bin/setup
|
108
110
|
- lib/ruby_llm.rb
|
109
111
|
- lib/ruby_llm/active_record/acts_as.rb
|
112
|
+
- lib/ruby_llm/aliases.json
|
113
|
+
- lib/ruby_llm/aliases.rb
|
110
114
|
- lib/ruby_llm/chat.rb
|
111
115
|
- lib/ruby_llm/chunk.rb
|
112
116
|
- lib/ruby_llm/configuration.rb
|
@@ -127,8 +131,20 @@ files:
|
|
127
131
|
- lib/ruby_llm/providers/anthropic/models.rb
|
128
132
|
- lib/ruby_llm/providers/anthropic/streaming.rb
|
129
133
|
- lib/ruby_llm/providers/anthropic/tools.rb
|
134
|
+
- lib/ruby_llm/providers/bedrock.rb
|
135
|
+
- lib/ruby_llm/providers/bedrock/capabilities.rb
|
136
|
+
- lib/ruby_llm/providers/bedrock/chat.rb
|
137
|
+
- lib/ruby_llm/providers/bedrock/models.rb
|
138
|
+
- lib/ruby_llm/providers/bedrock/signing.rb
|
139
|
+
- lib/ruby_llm/providers/bedrock/streaming.rb
|
140
|
+
- lib/ruby_llm/providers/bedrock/streaming/base.rb
|
141
|
+
- lib/ruby_llm/providers/bedrock/streaming/content_extraction.rb
|
142
|
+
- lib/ruby_llm/providers/bedrock/streaming/message_processing.rb
|
143
|
+
- lib/ruby_llm/providers/bedrock/streaming/payload_processing.rb
|
144
|
+
- lib/ruby_llm/providers/bedrock/streaming/prelude_handling.rb
|
130
145
|
- lib/ruby_llm/providers/deepseek.rb
|
131
146
|
- lib/ruby_llm/providers/deepseek/capabilities.rb
|
147
|
+
- lib/ruby_llm/providers/deepseek/chat.rb
|
132
148
|
- lib/ruby_llm/providers/gemini.rb
|
133
149
|
- lib/ruby_llm/providers/gemini/capabilities.rb
|
134
150
|
- lib/ruby_llm/providers/gemini/chat.rb
|
@@ -149,11 +165,18 @@ files:
|
|
149
165
|
- lib/ruby_llm/providers/openai/tools.rb
|
150
166
|
- lib/ruby_llm/railtie.rb
|
151
167
|
- lib/ruby_llm/stream_accumulator.rb
|
168
|
+
- lib/ruby_llm/streaming.rb
|
152
169
|
- lib/ruby_llm/tool.rb
|
153
170
|
- lib/ruby_llm/tool_call.rb
|
154
171
|
- lib/ruby_llm/version.rb
|
172
|
+
- lib/tasks/browser_helper.rb
|
173
|
+
- lib/tasks/capability_generator.rb
|
174
|
+
- lib/tasks/capability_scraper.rb
|
175
|
+
- lib/tasks/cli_helper.rb
|
176
|
+
- lib/tasks/code_validator.rb
|
177
|
+
- lib/tasks/model_updater.rb
|
155
178
|
- lib/tasks/models.rake
|
156
|
-
-
|
179
|
+
- lib/tasks/vcr.rake
|
157
180
|
homepage: https://rubyllm.com
|
158
181
|
licenses:
|
159
182
|
- MIT
|
data/.github/workflows/cicd.yml
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
name: CI
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ "main" ]
|
6
|
-
paths:
|
7
|
-
- 'lib/**'
|
8
|
-
- 'spec/**'
|
9
|
-
- 'Gemfile'
|
10
|
-
- 'Rakefile'
|
11
|
-
- 'ruby_llm.gemspec'
|
12
|
-
pull_request:
|
13
|
-
branches: [ "main" ]
|
14
|
-
workflow_call:
|
15
|
-
|
16
|
-
jobs:
|
17
|
-
test:
|
18
|
-
runs-on: ubuntu-latest
|
19
|
-
strategy:
|
20
|
-
matrix:
|
21
|
-
ruby-version: ['3.1']
|
22
|
-
|
23
|
-
steps:
|
24
|
-
- uses: actions/checkout@v4
|
25
|
-
|
26
|
-
- name: Set up Ruby
|
27
|
-
uses: ruby/setup-ruby@v1
|
28
|
-
with:
|
29
|
-
ruby-version: ${{ matrix.ruby-version }}
|
30
|
-
bundler-cache: true
|
31
|
-
|
32
|
-
- name: Install dependencies
|
33
|
-
run: bundle install
|
34
|
-
|
35
|
-
- name: Check code format
|
36
|
-
run: bundle exec rubocop
|
37
|
-
|
38
|
-
- name: Run tests
|
39
|
-
env:
|
40
|
-
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
41
|
-
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
42
|
-
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
43
|
-
DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
|
44
|
-
run: bundle exec rspec
|
45
|
-
|
46
|
-
- name: Upload coverage to Codecov
|
47
|
-
uses: codecov/codecov-action@v5
|
48
|
-
env:
|
49
|
-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
50
|
-
with:
|
51
|
-
files: ./coverage/coverage.xml
|
52
|
-
fail_ci_if_error: false
|
53
|
-
|
54
|
-
publish:
|
55
|
-
name: Build + Publish
|
56
|
-
needs: test
|
57
|
-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
58
|
-
runs-on: ubuntu-latest
|
59
|
-
permissions:
|
60
|
-
contents: read
|
61
|
-
packages: write
|
62
|
-
|
63
|
-
steps:
|
64
|
-
- uses: actions/checkout@v4
|
65
|
-
|
66
|
-
- name: Set up Ruby
|
67
|
-
uses: ruby/setup-ruby@v1
|
68
|
-
with:
|
69
|
-
ruby-version: '3.3'
|
70
|
-
bundler-cache: true
|
71
|
-
|
72
|
-
- name: Publish to GPR
|
73
|
-
run: |
|
74
|
-
mkdir -p $HOME/.gem
|
75
|
-
touch $HOME/.gem/credentials
|
76
|
-
chmod 0600 $HOME/.gem/credentials
|
77
|
-
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
78
|
-
gem build *.gemspec
|
79
|
-
output=$(gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem 2>&1) || {
|
80
|
-
echo "$output"
|
81
|
-
if echo "$output" | grep -q "already been pushed"; then
|
82
|
-
echo "Version already exists, skipping"
|
83
|
-
exit 0
|
84
|
-
else
|
85
|
-
exit 1
|
86
|
-
fi
|
87
|
-
}
|
88
|
-
env:
|
89
|
-
GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
|
90
|
-
OWNER: ${{ github.repository_owner }}
|
91
|
-
|
92
|
-
- name: Publish to RubyGems
|
93
|
-
run: |
|
94
|
-
mkdir -p $HOME/.gem
|
95
|
-
touch $HOME/.gem/credentials
|
96
|
-
chmod 0600 $HOME/.gem/credentials
|
97
|
-
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
98
|
-
gem build *.gemspec
|
99
|
-
output=$(gem push *.gem 2>&1) || {
|
100
|
-
echo "$output"
|
101
|
-
if echo "$output" | grep -q "Repushing of gem versions is not allowed"; then
|
102
|
-
echo "Version already exists, skipping"
|
103
|
-
exit 0
|
104
|
-
else
|
105
|
-
exit 1
|
106
|
-
fi
|
107
|
-
}
|
108
|
-
env:
|
109
|
-
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
data/.github/workflows/docs.yml
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
name: Deploy docs
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [main]
|
6
|
-
paths:
|
7
|
-
- 'docs/**'
|
8
|
-
- '.github/workflows/docs.yml'
|
9
|
-
workflow_dispatch:
|
10
|
-
|
11
|
-
permissions:
|
12
|
-
contents: read
|
13
|
-
pages: write
|
14
|
-
id-token: write
|
15
|
-
|
16
|
-
concurrency:
|
17
|
-
group: "pages"
|
18
|
-
cancel-in-progress: false
|
19
|
-
|
20
|
-
jobs:
|
21
|
-
build:
|
22
|
-
runs-on: ubuntu-latest
|
23
|
-
steps:
|
24
|
-
- name: Checkout
|
25
|
-
uses: actions/checkout@v4
|
26
|
-
- name: Setup Ruby
|
27
|
-
uses: ruby/setup-ruby@v1
|
28
|
-
with:
|
29
|
-
ruby-version: '3.3'
|
30
|
-
bundler-cache: true
|
31
|
-
working-directory: docs
|
32
|
-
- name: Setup Pages
|
33
|
-
uses: actions/configure-pages@v4
|
34
|
-
- name: Build with Jekyll
|
35
|
-
working-directory: docs
|
36
|
-
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
|
37
|
-
env:
|
38
|
-
JEKYLL_ENV: production
|
39
|
-
- name: Upload artifact
|
40
|
-
uses: actions/upload-pages-artifact@v3
|
41
|
-
with:
|
42
|
-
path: docs/_site
|
43
|
-
|
44
|
-
deploy:
|
45
|
-
environment:
|
46
|
-
name: github-pages
|
47
|
-
url: ${{ steps.deployment.outputs.page_url }}
|
48
|
-
runs-on: ubuntu-latest
|
49
|
-
needs: build
|
50
|
-
steps:
|
51
|
-
- name: Deploy to GitHub Pages
|
52
|
-
id: deployment
|
53
|
-
uses: actions/deploy-pages@v4
|
data/.gitignore
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
/.config
|
4
|
-
/coverage/
|
5
|
-
/InstalledFiles
|
6
|
-
/pkg/
|
7
|
-
/spec/reports/
|
8
|
-
/spec/examples.txt
|
9
|
-
/test/tmp/
|
10
|
-
/test/version_tmp/
|
11
|
-
/tmp/
|
12
|
-
|
13
|
-
# Used by dotenv library to load environment variables.
|
14
|
-
.env
|
15
|
-
|
16
|
-
# Ignore Byebug command history file.
|
17
|
-
.byebug_history
|
18
|
-
|
19
|
-
## Specific to RubyMotion:
|
20
|
-
.dat*
|
21
|
-
.repl_history
|
22
|
-
build/
|
23
|
-
*.bridgesupport
|
24
|
-
build-iPhoneOS/
|
25
|
-
build-iPhoneSimulator/
|
26
|
-
|
27
|
-
## Specific to RubyMotion (use of CocoaPods):
|
28
|
-
#
|
29
|
-
# We recommend against adding the Pods directory to your .gitignore. However
|
30
|
-
# you should judge for yourself, the pros and cons are mentioned at:
|
31
|
-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
32
|
-
#
|
33
|
-
# vendor/Pods/
|
34
|
-
|
35
|
-
## Documentation cache and generated files:
|
36
|
-
/.yardoc/
|
37
|
-
/_yardoc/
|
38
|
-
/doc/
|
39
|
-
/rdoc/
|
40
|
-
|
41
|
-
## Environment normalization:
|
42
|
-
/.bundle/
|
43
|
-
/vendor/bundle
|
44
|
-
/lib/bundler/man/
|
45
|
-
|
46
|
-
# for a library or gem, you might want to ignore these files since the code is
|
47
|
-
# intended to run in multiple environments; otherwise, check them in:
|
48
|
-
Gemfile.lock
|
49
|
-
# .ruby-version
|
50
|
-
# .ruby-gemset
|
51
|
-
|
52
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
53
|
-
.rvmrc
|
54
|
-
|
55
|
-
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
56
|
-
# .rubocop-https?--*
|
57
|
-
|
58
|
-
repomix-output.txt
|
data/.overcommit.yml
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
PreCommit:
|
2
|
-
RuboCop:
|
3
|
-
enabled: true
|
4
|
-
auto_correct: true
|
5
|
-
on_warn: fail # Treat all warnings as failures
|
6
|
-
|
7
|
-
Flay:
|
8
|
-
enabled: true
|
9
|
-
|
10
|
-
RSpec:
|
11
|
-
enabled: false
|
12
|
-
command: ['bundle', 'exec', 'rspec']
|
13
|
-
on_warn: fail
|
14
|
-
|
15
|
-
TrailingWhitespace:
|
16
|
-
enabled: true
|
17
|
-
auto_correct: true
|
18
|
-
exclude:
|
19
|
-
- '**/db/structure.sql' # Ignore trailing whitespace in generated files
|
20
|
-
|
21
|
-
PostCheckout:
|
22
|
-
ALL: # Special hook name that customizes all hooks of this type
|
23
|
-
quiet: true # Change all post-checkout hooks to only display output on failure
|
24
|
-
|
25
|
-
IndexTags:
|
26
|
-
enabled: true # Generate a tags file with `ctags` each time HEAD changes
|