Module: Kward::ModelInfo
- Defined in:
- lib/kward/model/model_info.rb
Constant Summary collapse
- DEFAULT_OPENAI_MODEL =
"gpt-5.5"- DEFAULT_OPENROUTER_MODEL =
"openai/gpt-5.5"- DEFAULT_COPILOT_MODEL =
"gpt-5-mini"- DEFAULT_REASONING_EFFORT =
"medium"- OPENAI_MODEL_CHOICES =
%w[gpt-5.5 gpt-5.4 gpt-5.4-mini gpt-5.3-codex-spark].freeze
- OPENROUTER_MODEL_CHOICES =
OPENAI_MODEL_CHOICES.map { |model| "openai/#{model}" }.freeze
- COPILOT_MODEL_CHOICES =
%w[ gpt-5-mini gpt-5.3-codex gpt-5.4 gpt-5.4-mini gpt-5.5 claude-haiku-4.5 claude-opus-4.5 claude-opus-4.7 claude-opus-4.8 claude-sonnet-4.5 claude-sonnet-4.6 gemini-2.5-pro gemini-3-flash-preview gemini-3.1-pro-preview gemini-3.5-flash oswe-vscode-prime ].freeze
- REASONING_EFFORT_CHOICES =
[ ["low", "Low"], ["medium", "Medium"], ["high", "High"], ["xhigh", "Extra High"] ].freeze
- IMAGE_UNSUPPORTED_MODELS =
[ /(?:\A|\/)gpt-5\.3-codex-spark\z/ ].freeze
- OPENAI_CONTEXT_WINDOWS =
[ [/\Agpt-5\.5/, 400_000], [/\Agpt-5-codex/, 400_000], [/\Agpt-5\.3-codex-spark/, 128_000], [/\Agpt-5\.3-codex/, 400_000], [/\Agpt-5\.2-codex/, 400_000], [/\Agpt-5/, 400_000], [/\Agpt-4\.1/, 1_047_576], [/\Agpt-4o/, 128_000], [/\Ao3/, 200_000], [/\Ao4/, 200_000], [/\Agpt-4/, 128_000], [/\Agpt-3\.5-turbo/, 16_385] ].freeze
Class Method Summary collapse
- .boolean_value(value, default: false) ⇒ Object
- .config_key_for_provider(provider) ⇒ Object
- .config_provider_for_provider(provider) ⇒ Object
- .config_values_for_selection(provider, model) ⇒ Object
- .context_window(provider, id) ⇒ Object
- .model_for(provider, config:, override_model: nil, env: ENV) ⇒ Object
- .normalize(model, current_provider: nil, current_model: nil, current_reasoning_effort: nil) ⇒ Object
- .normalize_copilot_model(id) ⇒ Object
- .provider_config_value(provider) ⇒ Object
- .provider_label(provider) ⇒ Object
- .reasoning_config_key_for_provider(provider) ⇒ Object
- .reasoning_effort(config:, env: ENV, provider: nil) ⇒ Object
- .reasoning_supported?(provider, id) ⇒ Boolean
- .stringify_keys(value) ⇒ Object
- .supports_images?(_provider, id) ⇒ Boolean
Class Method Details
.boolean_value(value, default: false) ⇒ Object
177 178 179 180 181 182 |
# File 'lib/kward/model/model_info.rb', line 177 def boolean_value(value, default: false) return default if value.nil? return value if value == true || value == false value.to_s == "true" end |
.config_key_for_provider(provider) ⇒ Object
117 118 119 120 121 122 123 |
# File 'lib/kward/model/model_info.rb', line 117 def config_key_for_provider(provider) case provider.to_s when "OpenRouter" then "openrouter_model" when "Copilot" then "copilot_model" else "openai_model" end end |
.config_provider_for_provider(provider) ⇒ Object
133 134 135 |
# File 'lib/kward/model/model_info.rb', line 133 def config_provider_for_provider(provider) provider_config_value(provider) end |
.config_values_for_selection(provider, model) ⇒ Object
137 138 139 140 141 142 |
# File 'lib/kward/model/model_info.rb', line 137 def config_values_for_selection(provider, model) { config_key_for_provider(provider) => model, "provider" => config_provider_for_provider(provider) } end |
.context_window(provider, id) ⇒ Object
144 145 146 147 148 149 |
# File 'lib/kward/model/model_info.rb', line 144 def context_window(provider, id) return nil unless provider == "Codex" match = OPENAI_CONTEXT_WINDOWS.find { |pattern, _window| id.to_s.match?(pattern) } match&.last end |
.model_for(provider, config:, override_model: nil, env: ENV) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/kward/model/model_info.rb', line 57 def model_for(provider, config:, override_model: nil, env: ENV) return override_model if override_model case provider when "OpenRouter" env["OPENROUTER_MODEL"] || ConfigFiles.config_value(config, "openrouter_model", "model") || DEFAULT_OPENROUTER_MODEL when "Copilot" normalize_copilot_model(env["COPILOT_MODEL"] || ConfigFiles.config_value(config, "copilot_model", "model") || DEFAULT_COPILOT_MODEL) else env["OPENAI_MODEL"] || ConfigFiles.config_value(config, "openai_model", "model") || DEFAULT_OPENAI_MODEL end end |
.normalize(model, current_provider: nil, current_model: nil, current_reasoning_effort: nil) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/kward/model/model_info.rb', line 159 def normalize(model, current_provider: nil, current_model: nil, current_reasoning_effort: nil) model = stringify_keys(model || {}) provider = model["provider"] id = model["id"] || model["model"] reasoning = boolean_value(model["reasoning"], default: reasoning_supported?(provider, id)) reasoning_effort = model["reasoningEffort"] || model["reasoning_effort"] || (current_reasoning_effort if reasoning) { provider: provider, id: id, name: model["name"] || id, model: model["model"] || id, reasoning: reasoning, reasoningEffort: reasoning_effort, contextWindow: model["contextWindow"] || model["context_window"] || context_window(provider, id), current: boolean_value(model["current"], default: provider == current_provider && id == current_model) }.compact end |
.normalize_copilot_model(id) ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/kward/model/model_info.rb', line 70 def normalize_copilot_model(id) text = id.to_s.strip return DEFAULT_COPILOT_MODEL if text.empty? text = text.delete_prefix("copilot/") { "claude-haiku-4-5" => "claude-haiku-4.5", "claude-opus-4-5" => "claude-opus-4.5", "claude-opus-4-6" => "claude-opus-4.6", "claude-opus-4-6-fast" => "claude-opus-4.6-fast", "claude-opus-4-7" => "claude-opus-4.7", "claude-opus-4-8" => "claude-opus-4.8", "claude-sonnet-4-5" => "claude-sonnet-4.5", "claude-sonnet-4-6" => "claude-sonnet-4.6", "gemini-3.1-pro" => "gemini-3.1-pro-preview", "gemini-3-flash" => "gemini-3-flash-preview" }.fetch(text, text) end |
.provider_config_value(provider) ⇒ Object
109 110 111 112 113 114 115 |
# File 'lib/kward/model/model_info.rb', line 109 def provider_config_value(provider) case provider.to_s when "OpenRouter" then "openrouter" when "Copilot" then "copilot" else "codex" end end |
.provider_label(provider) ⇒ Object
100 101 102 103 104 105 106 107 |
# File 'lib/kward/model/model_info.rb', line 100 def provider_label(provider) case provider.to_s.downcase when "openrouter" then "OpenRouter" when "copilot" then "Copilot" when "codex", "openai" then "Codex" else provider.to_s end end |
.reasoning_config_key_for_provider(provider) ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/kward/model/model_info.rb', line 125 def reasoning_config_key_for_provider(provider) case provider.to_s when "OpenRouter" then "openrouter_reasoning_effort" when "Copilot" then "copilot_reasoning_effort" else "openai_reasoning_effort" end end |
.reasoning_effort(config:, env: ENV, provider: nil) ⇒ Object
89 90 91 92 93 94 95 96 97 98 |
# File 'lib/kward/model/model_info.rb', line 89 def reasoning_effort(config:, env: ENV, provider: nil) case provider.to_s when "OpenRouter" env["OPENROUTER_REASONING_EFFORT"] || ConfigFiles.config_value(config, "openrouter_reasoning_effort", "reasoning_effort", "thinking_level") || DEFAULT_REASONING_EFFORT when "Copilot" env["COPILOT_REASONING_EFFORT"] || ConfigFiles.config_value(config, "copilot_reasoning_effort", "reasoning_effort", "thinking_level") || DEFAULT_REASONING_EFFORT else env["OPENAI_REASONING_EFFORT"] || ConfigFiles.config_value(config, "openai_reasoning_effort", "reasoning_effort", "thinking_level") || DEFAULT_REASONING_EFFORT end end |
.reasoning_supported?(provider, id) ⇒ Boolean
155 156 157 |
# File 'lib/kward/model/model_info.rb', line 155 def reasoning_supported?(provider, id) provider == "Codex" || provider == "OpenRouter" || (provider == "Copilot" && id.to_s.match?(/\Agpt-5(?:\.|-|\z)/)) end |
.stringify_keys(value) ⇒ Object
184 185 186 |
# File 'lib/kward/model/model_info.rb', line 184 def stringify_keys(value) value.each_with_object({}) { |(key, item), result| result[key.to_s] = item } end |
.supports_images?(_provider, id) ⇒ Boolean
151 152 153 |
# File 'lib/kward/model/model_info.rb', line 151 def supports_images?(_provider, id) IMAGE_UNSUPPORTED_MODELS.none? { |pattern| id.to_s.match?(pattern) } end |