Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## [Unreleased]

### Fixed
- `Raix::Configuration` no longer defaults `temperature` to `0.0`. The default was being injected into every request payload, which OpenRouter rejects with `404 No endpoints found that can handle the requested parameters` when routed to providers whose `supported_parameters` list omits `temperature` (notably Anthropic's Claude 4.7 family) and `provider.require_parameters: true` is set — which Raix sets automatically whenever `json: true` is passed to `chat_completion`. Callers that want a specific temperature should set one explicitly (`self.temperature = 0.0` on the including class, or `Raix.configure { |c| c.temperature = 0.0 }` globally); when unset, Raix now omits the parameter and the provider's own server-side default applies. `max_tokens`, `max_completion_tokens`, and `model` defaults are unchanged.

## [2.0.4] - 2026-05-19

### Fixed
Expand Down
11 changes: 9 additions & 2 deletions lib/raix/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,19 @@ def self.attr_accessor_with_fallback(method_name)
DEFAULT_MAX_TOKENS = 1000
DEFAULT_MAX_COMPLETION_TOKENS = 16_384
DEFAULT_MODEL = "meta-llama/llama-3.3-8b-instruct:free"
DEFAULT_TEMPERATURE = 0.0
DEFAULT_MAX_TOOL_CALLS = 25

# Initializes a new instance of the Configuration class with default values.
#
# Note: temperature is intentionally not defaulted. Setting a non-nil
# temperature here would force it into every request payload, and some
# providers (e.g. Anthropic's Claude 4.7 family on OpenRouter) do not list
# `temperature` in their supported parameters. Combined with
# `provider.require_parameters: true` (which Raix sets when `json: true`),
# an injected default of 0.0 causes OpenRouter to reject the request with
# "No endpoints found that can handle the requested parameters." Callers
# who want a specific temperature should set one explicitly.
def initialize(fallback: nil)
self.temperature = DEFAULT_TEMPERATURE
self.max_completion_tokens = DEFAULT_MAX_COMPLETION_TOKENS
self.max_tokens = DEFAULT_MAX_TOKENS
self.model = DEFAULT_MODEL
Expand Down
96 changes: 96 additions & 0 deletions spec/raix/default_temperature_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# frozen_string_literal: true

# Regression coverage: Raix must not inject a default `temperature` into the
# request when the caller hasn't set one.
#
# Some OpenRouter-routed providers (notably Anthropic's Claude 4.7 family) do
# not list `temperature` in their `supported_parameters`. When `json: true`
# adds `provider.require_parameters: true` to the payload, an unsolicited
# `temperature: 0.0` from a Raix default causes OpenRouter to return
# "No endpoints found that can handle the requested parameters" (404).
class TemperatureDefaultProbe
include Raix::ChatCompletion
end

RSpec.describe Raix::ChatCompletion, "default temperature handling" do
let(:instance) { TemperatureDefaultProbe.new }

let(:fake_response_message) do
instance_double(
"RubyLLM::Message",
content: "ok",
tool_calls: nil,
tool_call?: false,
input_tokens: 1,
output_tokens: 1,
model_id: "anthropic/claude-opus-4-7",
raw: nil
)
end

let(:fake_chat) do
instance_double(
"RubyLLM::Chat",
with_instructions: nil,
add_message: nil,
with_temperature: nil,
with_params: nil,
with_tool: nil,
ask: fake_response_message,
complete: fake_response_message
)
end

before { allow(RubyLLM).to receive(:chat).and_return(fake_chat) }

it "does not call with_temperature when no temperature is set anywhere" do
instance.send(:ruby_llm_request,
params: {},
model: "anthropic/claude-opus-4-7",
messages: [{ role: "user", content: "hi" }])

expect(fake_chat).not_to have_received(:with_temperature)
end

it "does not include temperature in additional params when unset" do
instance.send(:ruby_llm_request,
params: {},
model: "anthropic/claude-opus-4-7",
messages: [{ role: "user", content: "hi" }])

expect(fake_chat).not_to have_received(:with_params) { |kwargs|
kwargs.key?(:temperature)
}
end

it "still forwards an explicitly-set temperature (including 0.0)" do
instance.temperature = 0.0
instance.chat_completion(messages: [{ user: "hi" }])

expect(fake_chat).to have_received(:with_temperature).with(0.0)
end

it "forwards a class-level configured temperature" do
klass = Class.new do
include Raix::ChatCompletion
configure { |config| config.temperature = 0.3 }
end
klass.new.chat_completion(messages: [{ user: "hi" }])

expect(fake_chat).to have_received(:with_temperature).with(0.3)
end
end

RSpec.describe Raix::Configuration, "temperature default" do
it "leaves temperature unset on a fresh configuration" do
expect(described_class.new.temperature).to be_nil
end

it "still defaults max_tokens, max_completion_tokens, and model" do
config = described_class.new

expect(config.max_tokens).to eq(Raix::Configuration::DEFAULT_MAX_TOKENS)
expect(config.max_completion_tokens).to eq(Raix::Configuration::DEFAULT_MAX_COMPLETION_TOKENS)
expect(config.model).to eq(Raix::Configuration::DEFAULT_MODEL)
end
end
Loading