Skip to content

Commit 5b4cb45

Browse files
committed
Add specs for model filtering and chat functionalities
1 parent d3a1078 commit 5b4cb45

File tree

3 files changed

+166
-0
lines changed

3 files changed

+166
-0
lines changed

spec/ruby_llm/chat_functions_spec.rb

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require 'dotenv/load'
5+
6+
RSpec.describe RubyLLM::Chat do
7+
include_context 'with configured RubyLLM'
8+
9+
describe '#with_tool unsupported functions' do
10+
it "raises UnsupportedFunctionsError when model doesn't support functions" do # rubocop:disable RSpec/ExampleLength
11+
# Create a non-function-calling model by patching the supports_functions attribute
12+
model = RubyLLM.models.find('gpt-4o-mini')
13+
allow(model).to receive(:supports_functions).and_return(false)
14+
15+
chat = described_class.new(model: 'gpt-4o-mini')
16+
# Replace the model with our modified version
17+
chat.instance_variable_set(:@model, model)
18+
19+
expect do
20+
chat.with_tool(RubyLLM::Tool)
21+
end.to raise_error(RubyLLM::UnsupportedFunctionsError, /doesn't support function calling/)
22+
end
23+
end
24+
25+
describe '#with_tools' do
26+
it 'adds multiple tools at once' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
27+
chat = described_class.new
28+
29+
tool1 = Class.new(RubyLLM::Tool) do
30+
def name = 'tool1'
31+
end
32+
33+
tool2 = Class.new(RubyLLM::Tool) do
34+
def name = 'tool2'
35+
end
36+
37+
chat.with_tools(tool1.new, tool2.new)
38+
39+
expect(chat.tools.keys).to include(:tool1, :tool2)
40+
expect(chat.tools.size).to eq(2)
41+
end
42+
end
43+
44+
describe '#with_model' do
45+
it 'changes the model and returns self' do # rubocop:disable RSpec/MultipleExpectations
46+
chat = described_class.new(model: 'gpt-4o-mini')
47+
result = chat.with_model('claude-3-5-haiku-20241022')
48+
49+
expect(chat.model.id).to eq('claude-3-5-haiku-20241022')
50+
expect(result).to eq(chat) # Should return self for chaining
51+
end
52+
end
53+
54+
describe '#with_temperature' do
55+
it 'sets the temperature and returns self' do # rubocop:disable RSpec/MultipleExpectations
56+
chat = described_class.new
57+
result = chat.with_temperature(0.8)
58+
59+
expect(chat.instance_variable_get(:@temperature)).to eq(0.8)
60+
expect(result).to eq(chat) # Should return self for chaining
61+
end
62+
end
63+
64+
describe '#each' do
65+
it 'iterates through messages' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
66+
chat = described_class.new
67+
chat.add_message(role: :user, content: 'Message 1')
68+
chat.add_message(role: :assistant, content: 'Message 2')
69+
70+
messages = chat.map do |msg|
71+
msg
72+
end
73+
74+
expect(messages.size).to eq(2)
75+
expect(messages[0].content).to eq('Message 1')
76+
expect(messages[1].content).to eq('Message 2')
77+
end
78+
end
79+
end

spec/ruby_llm/models_spec.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,65 @@
101101
end
102102
end
103103
end
104+
105+
describe '#embedding_models' do
106+
it 'filters to only embedding models' do # rubocop:disable RSpec/MultipleExpectations
107+
embedding_models = RubyLLM.models.embedding_models
108+
109+
expect(embedding_models).to be_a(described_class)
110+
expect(embedding_models.all).to all(have_attributes(type: 'embedding'))
111+
expect(embedding_models.all).not_to be_empty
112+
end
113+
end
114+
115+
describe '#audio_models' do
116+
it 'filters to only audio models' do # rubocop:disable RSpec/MultipleExpectations
117+
audio_models = RubyLLM.models.audio_models
118+
119+
expect(audio_models).to be_a(described_class)
120+
expect(audio_models.all).to all(have_attributes(type: 'audio'))
121+
end
122+
end
123+
124+
describe '#image_models' do
125+
it 'filters to only image models' do # rubocop:disable RSpec/MultipleExpectations
126+
image_models = RubyLLM.models.image_models
127+
128+
expect(image_models).to be_a(described_class)
129+
expect(image_models.all).to all(have_attributes(type: 'image'))
130+
expect(image_models.all).not_to be_empty
131+
end
132+
end
133+
134+
describe '#by_family' do
135+
it 'filters models by family' do # rubocop:disable RSpec/MultipleExpectations
136+
# Use a family we know exists
137+
family = RubyLLM.models.all.first.family
138+
family_models = RubyLLM.models.by_family(family)
139+
140+
expect(family_models).to be_a(described_class)
141+
expect(family_models.all).to all(have_attributes(family: family))
142+
expect(family_models.all).not_to be_empty
143+
end
144+
end
145+
146+
describe '#save_models' do
147+
it 'saves models to the models.json file' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
148+
temp_file = Tempfile.new(['models', '.json'])
149+
allow(described_class).to receive(:models_file).and_return(temp_file.path)
150+
151+
models = RubyLLM.models
152+
models.save_models
153+
154+
# Verify file was written with valid JSON
155+
saved_content = File.read(temp_file.path)
156+
expect { JSON.parse(saved_content) }.not_to raise_error
157+
158+
# Verify model data was saved
159+
parsed_models = JSON.parse(saved_content)
160+
expect(parsed_models.size).to eq(models.all.size)
161+
162+
temp_file.unlink
163+
end
164+
end
104165
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require 'dotenv/load'
5+
6+
RSpec.describe RubyLLM::Providers::OpenAI::Capabilities do # rubocop:disable RSpec/SpecFilePathFormat
7+
describe '.normalize_temperature' do
8+
it 'forces temperature to 1.0 for O1 models' do
9+
o1_models = %w[o1 o1-mini o1-preview o3-mini]
10+
11+
o1_models.each do |model|
12+
result = described_class.normalize_temperature(0.7, model)
13+
expect(result).to eq(1.0)
14+
end
15+
end
16+
17+
it 'preserves temperature for non-O1 models' do
18+
non_o1_models = ['gpt-4', 'gpt-4o', 'claude-3-opus']
19+
20+
non_o1_models.each do |model|
21+
result = described_class.normalize_temperature(0.7, model)
22+
expect(result).to eq(0.7)
23+
end
24+
end
25+
end
26+
end

0 commit comments

Comments
 (0)