Class: Boxcars::Engines

Inherits:
Object
  • Object
show all
Defined in:
lib/boxcars/engines.rb

Overview

Factory class for creating engine instances based on model names Provides convenient shortcuts and aliases for different AI models

Constant Summary collapse

VALID_ANSWER_REMOVE_IN =
"3.0"
DEFAULT_MODEL =
"gemini-2.5-flash"
DEPRECATED_MODEL_ALIASES =
{
  # Generic provider aliases are convenient but ambiguous and make pruning harder.
  "anthropic" => { replacement: "sonnet", remove_in: "3.0", reason: "generic provider alias" },
  "groq" => { replacement: "llama-3.3-70b-versatile", remove_in: "3.0", reason: "generic provider alias" },
  "deepseek" => { replacement: "deepseek-r1-distill-llama-70b", remove_in: "3.0",
                  reason: "provider-specific shortcut alias" },
  "mistral" => { replacement: "mistral-saba-24b", remove_in: "3.0", reason: "provider-specific shortcut alias" },
  "online" => { replacement: "sonar", remove_in: "3.0", reason: "ambiguous alias" },
  "huge" => { replacement: "sonar-pro", remove_in: "3.0", reason: "ambiguous alias" },
  "online_huge" => { replacement: "sonar-pro", remove_in: "3.0", reason: "ambiguous alias" },
  "sonar-huge" => { replacement: "sonar-pro", remove_in: "3.0", reason: "legacy alias spelling" },
  "sonar_huge" => { replacement: "sonar-pro", remove_in: "3.0", reason: "legacy alias spelling" },
  "sonar_pro" => { replacement: "sonar-pro", remove_in: "3.0", reason: "legacy alias spelling" },
  "flash" => { replacement: "gemini-2.5-flash", remove_in: "3.0", reason: "generic alias" },
  "gemini-flash" => { replacement: "gemini-2.5-flash", remove_in: "3.0", reason: "generic alias" },
  "gemini-pro" => { replacement: "gemini-2.5-pro", remove_in: "3.0", reason: "generic alias" },
  "cerebras" => { replacement: "gpt-oss-120b", remove_in: "3.0", reason: "generic provider alias" },
  "qwen" => { replacement: "Qwen/Qwen2.5-VL-72B-Instruct", remove_in: "3.0", reason: "provider-specific shortcut alias" }
}.freeze

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.emit_deprecation_warningsObject

Returns the value of attribute emit_deprecation_warnings.



35
36
37
# File 'lib/boxcars/engines.rb', line 35

def emit_deprecation_warnings
  @emit_deprecation_warnings
end

.strict_deprecated_aliasesObject

Returns the value of attribute strict_deprecated_aliases.



35
36
37
# File 'lib/boxcars/engines.rb', line 35

def strict_deprecated_aliases
  @strict_deprecated_aliases
end

Class Method Details

.deprecated_alias?(model) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/boxcars/engines.rb', line 91

def self.deprecated_alias?(model)
  !deprecated_alias_info(model).nil?
end

.deprecated_alias_info(model) ⇒ Object



87
88
89
# File 'lib/boxcars/engines.rb', line 87

def self.deprecated_alias_info(model)
  DEPRECATED_MODEL_ALIASES[model.to_s]
end

.deprecation_warnings_enabled?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/boxcars/engines.rb', line 158

def self.deprecation_warnings_enabled?
  emit_deprecation_warnings && Boxcars.configuration.emit_deprecation_warnings
end

.emit_alias_deprecation_warning(model) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/boxcars/engines.rb', line 124

def self.emit_alias_deprecation_warning(model)
  model_name = model.to_s
  info = deprecated_alias_info(model_name)
  return unless info

  replacement = info[:replacement]
  remove_in = info[:remove_in]
  reason = info[:reason]
  message = "Deprecated model alias #{model_name.inspect} (#{reason}); use #{replacement.inspect} instead"
  message += " (planned removal in v#{remove_in})" if remove_in

  raise Boxcars::ArgumentError, "#{message}. Set an explicit model name." if strict_deprecated_aliases_enabled?

  return unless deprecation_warnings_enabled?
  return if @warned_aliases[model_name]

  if Boxcars.logger
    Boxcars.logger.warn(message)
  else
    warn(message)
  end

  @warned_aliases[model_name] = true
end

.engine(model: nil, **kw_args) ⇒ Boxcars::Engine

Create an engine instance based on the model name

Parameters:

  • model (String) (defaults to: nil)

    The model name or alias

  • kw_args (Hash)

    Additional arguments to pass to the engine

Returns:



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
# File 'lib/boxcars/engines.rb', line 42

def self.engine(model: nil, **kw_args)
  model ||= Boxcars.configuration.default_model || DEFAULT_MODEL
  emit_alias_deprecation_warning(model)
  Boxcars.logger&.info { "running api with #{model}" }

  case model.to_s
  when /^(gpt-|o\d($|-))/
    Boxcars::Openai.new(model:, **kw_args)
  when "anthropic", "sonnet"
    Boxcars::Anthropic.new(model: "claude-sonnet-4-0", **kw_args)
  when "opus", "claude-opus-4-0"
    Boxcars::Anthropic.new(model: "claude-opus-4-0", **kw_args)
  when /claude-/
    Boxcars::Anthropic.new(model:, **kw_args)
  when "groq", "llama-3.3-70b-versatile"
    Boxcars::Groq.new(model: "llama-3.3-70b-versatile", **kw_args)
  when "deepseek"
    Boxcars::Groq.new(model: "deepseek-r1-distill-llama-70b", **kw_args)
  when "mistral"
    Boxcars::Groq.new(model: "mistral-saba-24b", **kw_args)
  when /^mistral-/, %r{^meta-llama/}, /^deepseek-/
    Boxcars::Groq.new(model:, **kw_args)
  when "online", "sonar"
    Boxcars::Perplexityai.new(model: "sonar", **kw_args)
  when "huge", "online_huge", "sonar-huge", "sonar_huge", "sonar-pro", "sonar_pro"
    Boxcars::Perplexityai.new(model: "sonar-pro", **kw_args)
  when "flash", "gemini-flash"
    Boxcars::GeminiAi.new(model: "gemini-2.5-flash", **kw_args)
  when "gemini-pro"
    Boxcars::GeminiAi.new(model: "gemini-2.5-pro", **kw_args)
  when /gemini-/
    Boxcars::GeminiAi.new(model:, **kw_args)
  when /-sonar-/
    Boxcars::Perplexityai.new(model:, **kw_args)
  when /^together-/
    Boxcars::Together.new(model: model[9..-1], **kw_args)
  when "cerebras"
    Boxcars::Cerebras.new(model: "gpt-oss-120b", **kw_args)
  when "qwen"
    Boxcars::Together.new(model: "Qwen/Qwen2.5-VL-72B-Instruct", **kw_args)
  else
    raise Boxcars::ArgumentError, "Unknown model: #{model}"
  end
end

.json_engine(model: nil, **kw_args) ⇒ Boxcars::Engine

Create an engine instance optimized for JSON responses

Parameters:

  • model (String) (defaults to: nil)

    The model name or alias

  • kw_args (Hash)

    Additional arguments to pass to the engine

Returns:



99
100
101
102
103
104
105
106
107
# File 'lib/boxcars/engines.rb', line 99

def self.json_engine(model: nil, **kw_args)
  default_options = { temperature: 0.1 }
  effective_model = model || Boxcars.configuration.default_model || DEFAULT_MODEL
  name = effective_model.to_s
  blocked = name.start_with?("gpt-5", "llama") || name.match?(/sonnet|opus|haiku|sonar/)
  default_options[:response_format] = { type: "json_object" } unless blocked
  options = default_options.merge(kw_args)
  engine(model:, **options)
end

.reset_deprecation_warnings!Object



149
150
151
152
# File 'lib/boxcars/engines.rb', line 149

def self.reset_deprecation_warnings!
  @warned_aliases = {}
  @warned_valid_answer = false
end

.strict_deprecated_aliases_enabled?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/boxcars/engines.rb', line 154

def self.strict_deprecated_aliases_enabled?
  strict_deprecated_aliases || Boxcars.configuration.strict_deprecated_model_aliases
end

.valid_answer?(answer) ⇒ Boolean

Deprecated.

Use ‘Boxcars::Result.valid_conduct_payload?` or `Boxcars::Result.extract`.

Deprecated. Validate the shape returned by ‘Boxcar#conduct`.

Parameters:

  • answer (Object)

    Conduct return value.

Returns:

  • (Boolean)

    True when answer is a hash containing a Boxcars::Result under :answer.



113
114
115
116
117
118
119
120
121
122
# File 'lib/boxcars/engines.rb', line 113

def self.valid_answer?(answer)
  unless @warned_valid_answer || !deprecation_warnings_enabled?
    Boxcars.warn(
      "Boxcars::Engines.valid_answer? is deprecated; use Boxcars::Result.valid_conduct_payload? " \
      "or Boxcars::Result.extract (planned removal in v#{VALID_ANSWER_REMOVE_IN})"
    )
    @warned_valid_answer = true
  end
  Boxcars::Result.valid_conduct_payload?(answer)
end