fix(captain): scope model routing to app provider
This commit is contained in:
+20
-25
@@ -1,4 +1,8 @@
|
||||
require_relative 'provider_model_catalog'
|
||||
|
||||
module Llm::Models
|
||||
extend Llm::ProviderModelCatalog
|
||||
|
||||
CONFIG = YAML.load_file(Rails.root.join('config/llm.yml')).freeze
|
||||
OPENAI_ONLY_FEATURES = %w[audio_transcription help_center_search].freeze
|
||||
|
||||
@@ -16,18 +20,23 @@ module Llm::Models
|
||||
end
|
||||
|
||||
def default_model_for(feature)
|
||||
default_model = features.dig(feature.to_s, 'default')
|
||||
return default_model if supported_model?(default_model)
|
||||
installation_default = installation_model
|
||||
return installation_default if valid_model_for?(feature, installation_default)
|
||||
|
||||
feature_default = features.dig(feature.to_s, 'default')
|
||||
return feature_default if valid_model_for?(feature, feature_default)
|
||||
|
||||
models_for(feature).first
|
||||
end
|
||||
|
||||
def models_for(feature)
|
||||
(configured_models_for(feature) + provider_models_for(feature)).uniq
|
||||
def models_for(feature, provider: provider_for_feature(feature))
|
||||
(configured_models_for(feature, provider: provider) + provider_models_for(feature, provider: provider)).uniq
|
||||
end
|
||||
|
||||
def valid_model_for?(feature, model_name)
|
||||
models_for(feature).include?(model_name.to_s)
|
||||
def valid_model_for?(feature, model_name, provider: provider_for_feature(feature))
|
||||
return false if model_name.blank?
|
||||
|
||||
models_for(feature, provider: provider).include?(model_name.to_s)
|
||||
end
|
||||
|
||||
def model_config(model_name)
|
||||
@@ -53,8 +62,10 @@ module Llm::Models
|
||||
feature = features[feature_key.to_s]
|
||||
return nil unless feature
|
||||
|
||||
provider = provider_for_feature(feature_key)
|
||||
|
||||
{
|
||||
models: models_for(feature_key).map do |model_name|
|
||||
models: models_for(feature_key, provider: provider).map do |model_name|
|
||||
model = model_config(model_name)
|
||||
{
|
||||
id: model_name,
|
||||
@@ -64,29 +75,13 @@ module Llm::Models
|
||||
credit_multiplier: model['credit_multiplier']
|
||||
}
|
||||
end,
|
||||
default: feature['default']
|
||||
default: default_model_for(feature_key),
|
||||
provider: provider
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def configured_models_for(feature)
|
||||
(features.dig(feature.to_s, 'models') || []).select { |model_name| supported_model?(model_name) }
|
||||
end
|
||||
|
||||
def provider_models_for(feature)
|
||||
return [] if openai_only_feature?(feature)
|
||||
|
||||
provider = Llm::Config.current_provider
|
||||
return [] if provider == Llm::Config::DEFAULT_PROVIDER
|
||||
|
||||
RubyLLM.models.by_provider(provider).chat_models.map(&:id)
|
||||
end
|
||||
|
||||
def openai_only_feature?(feature)
|
||||
OPENAI_ONLY_FEATURES.include?(feature.to_s)
|
||||
end
|
||||
|
||||
def ruby_llm_model_config(model_name)
|
||||
model = ruby_llm_model(model_name)
|
||||
return unless model
|
||||
|
||||
@@ -2,6 +2,9 @@ require 'ruby_llm'
|
||||
|
||||
module Llm::ProviderConfig
|
||||
PROVIDER_CONFIG_PREFIX = 'CAPTAIN_LLM'.freeze
|
||||
PROVIDER_CONFIG_KEY = 'CAPTAIN_LLM_PROVIDER'.freeze
|
||||
MODEL_CONFIG_KEY = 'CAPTAIN_LLM_MODEL'.freeze
|
||||
LEGACY_OPENAI_MODEL_CONFIG_KEY = 'CAPTAIN_OPEN_AI_MODEL'.freeze
|
||||
|
||||
LEGACY_CONFIG_KEYS = {
|
||||
openai_api_key: 'CAPTAIN_OPEN_AI_API_KEY',
|
||||
@@ -22,20 +25,22 @@ module Llm::ProviderConfig
|
||||
end
|
||||
end
|
||||
|
||||
def provider_config_keys
|
||||
(['CAPTAIN_LLM_PROVIDER'] + provider_config_options.values).uniq
|
||||
def provider_config_keys(provider = nil)
|
||||
([PROVIDER_CONFIG_KEY, MODEL_CONFIG_KEY] + provider_config_options(provider).values).uniq
|
||||
end
|
||||
|
||||
def provider_config_options
|
||||
provider_options.keys.each_with_object({}) do |provider, result|
|
||||
provider_configuration_options(provider).each do |option|
|
||||
def provider_config_options(provider = nil)
|
||||
providers = provider.present? ? [provider.to_s] : provider_options.keys
|
||||
|
||||
providers.each_with_object({}) do |provider_name, result|
|
||||
provider_configuration_options(provider_name).each do |option|
|
||||
result[option] = installation_config_name(option)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def current_provider
|
||||
provider = InstallationConfig.find_by(name: 'CAPTAIN_LLM_PROVIDER')&.value.presence
|
||||
provider = InstallationConfig.find_by(name: PROVIDER_CONFIG_KEY)&.value.presence
|
||||
return provider if provider_options.key?(provider)
|
||||
|
||||
Llm::Config::DEFAULT_PROVIDER
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
module Llm::ProviderModelCatalog
|
||||
def installation_model(provider: provider_for_feature(nil))
|
||||
model = InstallationConfig.find_by(name: Llm::ProviderConfig::MODEL_CONFIG_KEY)&.value.presence
|
||||
return model if model_provider?(model, provider)
|
||||
|
||||
legacy_model = InstallationConfig.find_by(name: Llm::ProviderConfig::LEGACY_OPENAI_MODEL_CONFIG_KEY)&.value.presence
|
||||
return legacy_model if provider == Llm::Config::DEFAULT_PROVIDER && model_provider?(legacy_model, provider)
|
||||
end
|
||||
|
||||
def provider_default_model_options(provider = Llm::Config.current_provider)
|
||||
models_for_provider(provider).index_with do |model_name|
|
||||
model = model_config(model_name)
|
||||
model['display_name'] || model_name
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def provider_for_feature(feature)
|
||||
return Llm::Config::DEFAULT_PROVIDER if openai_only_feature?(feature)
|
||||
|
||||
Llm::Config.current_provider
|
||||
end
|
||||
|
||||
def configured_models_for(feature, provider:)
|
||||
(features.dig(feature.to_s, 'models') || []).select do |model_name|
|
||||
supported_model?(model_name) && model_provider?(model_name, provider)
|
||||
end
|
||||
end
|
||||
|
||||
def provider_models_for(feature, provider:)
|
||||
return [] if openai_only_feature?(feature)
|
||||
return [] if provider == Llm::Config::DEFAULT_PROVIDER
|
||||
|
||||
models_for_provider(provider)
|
||||
end
|
||||
|
||||
def models_for_provider(provider)
|
||||
configured_provider_models = models.filter_map do |model_name, config|
|
||||
model_name if config['provider'] == provider.to_s && chat_model?(model_name)
|
||||
end
|
||||
|
||||
(configured_provider_models + ruby_llm_provider_models(provider)).uniq
|
||||
end
|
||||
|
||||
def ruby_llm_provider_models(provider)
|
||||
return [] if provider.to_s == Llm::Config::DEFAULT_PROVIDER
|
||||
|
||||
RubyLLM.models.by_provider(provider.to_s).chat_models.map(&:id)
|
||||
end
|
||||
|
||||
def chat_model?(model_name)
|
||||
Llm::Models::OPENAI_ONLY_FEATURES.none? { |feature| features.dig(feature, 'models')&.include?(model_name) }
|
||||
end
|
||||
|
||||
def model_provider?(model_name, provider)
|
||||
provider_for(model_name) == provider.to_s
|
||||
end
|
||||
|
||||
def openai_only_feature?(feature)
|
||||
Llm::Models::OPENAI_ONLY_FEATURES.include?(feature.to_s)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user