forked from crmne/ruby_llm
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchat_error_spec.rb
More file actions
94 lines (78 loc) · 3.18 KB
/
chat_error_spec.rb
File metadata and controls
94 lines (78 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# frozen_string_literal: true
require 'spec_helper'
RSpec::Matchers.define :include_words do |*words|
match do |actual|
words.all? { |word| actual.downcase.include?(word.downcase) }
end
failure_message do |actual|
"expected '#{actual}' to include all words: #{words.join(', ')}"
end
end
RSpec::Matchers.define :look_like_json do
match do |actual|
actual.strip.start_with?('{') || actual.strip.start_with?('[')
end
failure_message do |actual|
"expected '#{actual}' to look like JSON"
end
failure_message_when_negated do |actual|
"expected '#{actual}' not to look like JSON"
end
end
RSpec.describe RubyLLM::Chat do
include_context 'with configured RubyLLM'
describe 'error handling' do
CHAT_MODELS.each do |model_info|
model = model_info[:model]
provider = model_info[:provider]
context "with #{provider}/#{model}" do
let(:chat) { RubyLLM.chat(model: model, provider: provider) }
before do
# Sabotage the API key after initialization
RubyLLM::Provider.remote_providers.each_key do |slug|
RubyLLM.config.public_send("#{slug}_api_key=", 'invalid-key')
end
end
it 'raises appropriate auth error' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
skip('Only valid for remote providers') if RubyLLM::Provider.providers[provider].local?
expect { chat.ask('Hello') }.to raise_error do |error|
expect(error).to be_a(RubyLLM::Error)
expect(error.class.ancestors).to include(RubyLLM::Error)
expect(error.response).to be_present
expect(error.message).to be_present
# Error should be human readable
expect(error.message).not_to look_like_json
# Should be properly capitalized readable text
expect(error.message).to match(/^[A-Za-z]/)
end
end
end
end
end
describe 'real error scenarios' do
CHAT_MODELS.each do |model_info|
model = model_info[:model]
provider = model_info[:provider]
context "#{provider}/#{model}" do # rubocop:disable RSpec/ContextWording
let(:chat) { RubyLLM.chat(model: model, provider: provider) }
it 'handles context length exceeded errors' do # rubocop:disable RSpec/ExampleLength,RSpec/MultipleExpectations
skip('Ollama does not throw an error for context length exceeded') if provider == :ollama
# Configure Psych to allow large input (JRuby's ext provider SnakeYAML has a low limit by default)
Psych::Parser.code_point_limit = 20_000_000 if Psych::Parser.respond_to?(:code_point_limit=)
# Create a huge conversation
massive_text = 'a' * 1_000_000
# Create a few copies in the conversation
5.times do
chat.add_message(role: :user, content: massive_text)
chat.add_message(role: :assistant, content: massive_text)
end
expect { chat.ask('Hi') }.to raise_error(RubyLLM::Error) do |e|
# Basic error format checks
expect(e.message).not_to look_like_json
expect(e.message).to match(/^[A-Za-z]/)
end
end
end
end
end
end