|
70 | 70 | stub_const('RubyLLM::OverloadedError', Class.new(RubyLLM::Error)) |
71 | 71 | stub_const('RubyLLM::RateLimitError', Class.new(RubyLLM::Error)) |
72 | 72 | stub_const('RubyLLM::ContextLengthExceededError', Class.new(RubyLLM::Error)) |
| 73 | + stub_const('RubyLLM::ModelNotFoundError', Class.new(StandardError)) |
73 | 74 | RubyLLM.singleton_class.attr_accessor :config |
74 | 75 | RubyLLM.config = global_ruby_config |
75 | 76 |
|
|
83 | 84 | allow(context).to receive(:chat) |
84 | 85 | .with(model: 'gemini-2.5-flash-lite', provider: anything) |
85 | 86 | .and_return(critique_chat) |
| 87 | + allow(context).to receive(:chat) |
| 88 | + .with(model: 'gemini-3.6-flash', provider: anything) |
| 89 | + .and_raise(RubyLLM::ModelNotFoundError) |
| 90 | + allow(context).to receive(:chat) |
| 91 | + .with(model: 'gemini-3.6-flash', provider: anything, assume_model_exists: true) |
| 92 | + .and_return(generate_chat) |
86 | 93 | context_configs << context_config |
87 | 94 | contexts << context |
88 | 95 | context |
|
107 | 114 | expect(context_configs.first.gemini_api_base).to eq('https://llm.example.test') |
108 | 115 | end |
109 | 116 |
|
110 | | - it 'uses generate model and temperature for the generate pass' do |
| 117 | + it 'uses a known model without bypassing the registry' do |
111 | 118 | reviewer = described_class.new(config: config, logger: logger) |
112 | 119 | result = reviewer.generate(system_prompt: 'system prompt', user_prompt: 'user prompt') |
113 | 120 |
|
114 | 121 | expect(result).to eq('generate body') |
115 | | - expect(contexts.first).to have_received(:chat).with(model: 'gemini-2.5-pro', provider: :gemini) |
| 122 | + expect(contexts.first) |
| 123 | + .to have_received(:chat) |
| 124 | + .with(model: 'gemini-2.5-pro', provider: :gemini) |
116 | 125 | expect(generate_chat).to have_received(:with_temperature).with(0.3) |
117 | 126 | end |
118 | 127 |
|
|
121 | 130 | result = reviewer.critique(system_prompt: 'system prompt', user_prompt: 'user prompt') |
122 | 131 |
|
123 | 132 | expect(result).to eq('critique body') |
124 | | - expect(contexts.first).to have_received(:chat).with(model: 'gemini-2.5-flash-lite', provider: :gemini) |
| 133 | + expect(contexts.first) |
| 134 | + .to have_received(:chat) |
| 135 | + .with(model: 'gemini-2.5-flash-lite', provider: :gemini) |
125 | 136 | expect(critique_chat).to have_received(:with_temperature).with(0.0) |
126 | 137 | end |
127 | 138 |
|
|
135 | 146 | expect(context_configs.first).not_to equal(context_configs.last) |
136 | 147 | end |
137 | 148 |
|
| 149 | + it 'retries an unknown model with an explicit provider' do |
| 150 | + allow(config).to receive(:generate_model).and_return('gemini-3.6-flash') |
| 151 | + log_output = StringIO.new |
| 152 | + reviewer = described_class.new(config: config, logger: Logger.new(log_output)) |
| 153 | + |
| 154 | + reviewer.generate(system_prompt: 'system prompt', user_prompt: 'user prompt') |
| 155 | + |
| 156 | + expect(contexts.first) |
| 157 | + .to have_received(:chat) |
| 158 | + .with(model: 'gemini-3.6-flash', provider: :gemini) |
| 159 | + expect(contexts.first) |
| 160 | + .to have_received(:chat) |
| 161 | + .with(model: 'gemini-3.6-flash', provider: :gemini, assume_model_exists: true) |
| 162 | + expect(log_output.string).to include( |
| 163 | + 'LLM generate: model not found in RubyLLM registry; ' \ |
| 164 | + 'using fallback with incomplete model metadata ' \ |
| 165 | + '(model=gemini-3.6-flash, provider=gemini)' |
| 166 | + ) |
| 167 | + end |
| 168 | + |
138 | 169 | it 'sets the RubyLLM request timeout from LLM_TIMEOUT' do |
139 | 170 | reviewer = described_class.new(config: config, logger: logger) |
140 | 171 |
|
|
0 commit comments