feat: Harden model override preferences (5/6) (#14846)

## Description

Hardens the Captain model override preferences API so account-level
overrides follow the same feature-router contract used by runtime LLM
calls. The API now permits model and feature keys from `llm.yml`,
removes blank model overrides, rejects invalid saved model combinations,
and returns each feature's effective model, provider, and source for UI
clients.

Fixes https://linear.app/chatwoot/issue/CW-7425/test-new-models

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

Verified the account preferences API and account model validation
behavior for valid overrides, invalid model values, unknown feature
keys, blank override removal, and effective model/provider/source
payload metadata.

- `eval "$(rbenv init -)" && bundle exec rspec
spec/controllers/api/v1/accounts/captain/preferences_controller_spec.rb
spec/models/account_spec.rb
spec/models/concerns/captain_featurable_spec.rb
spec/lib/llm/feature_router_spec.rb`
- `eval "$(rbenv init -)" && bundle exec rubocop
app/controllers/api/v1/accounts/captain/preferences_controller.rb
app/models/concerns/account_settings_schema.rb
app/models/concerns/captain_featurable.rb
spec/controllers/api/v1/accounts/captain/preferences_controller_spec.rb
spec/models/account_spec.rb
spec/models/concerns/captain_featurable_spec.rb
spec/lib/llm/feature_router_spec.rb`
- `git diff --check`

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
This commit is contained in:
Sony Mathew
2026-06-25 17:38:11 +05:30
committed by GitHub
parent 4e26c5b4bb
commit b8b62ad0f1
11 changed files with 344 additions and 8 deletions

View File

@@ -4,6 +4,7 @@ module CaptainFeaturable
extend ActiveSupport::Concern
included do
before_validation :normalize_captain_models
validate :validate_captain_models
# Dynamically define accessor methods for each captain feature
@@ -46,11 +47,27 @@ module CaptainFeaturable
return if captain_models.blank?
captain_models.each do |feature_key, model_name|
next if model_name.blank?
unless Llm::Models.feature?(feature_key)
errors.add(:captain_models, "'#{feature_key}' is not a known feature")
next
end
next if Llm::Models.valid_model_for?(feature_key, model_name)
allowed_models = Llm::Models.models_for(feature_key)
errors.add(:captain_models, "'#{model_name}' is not a valid model for #{feature_key}. Allowed: #{allowed_models.join(', ')}")
end
end
def normalize_captain_models
return unless captain_models.is_a?(Hash)
normalized_models = captain_models.each_with_object({}) do |(feature_key, model_name), result|
next if model_name.blank?
result[feature_key.to_s] = model_name.to_s
end
self.captain_models = normalized_models.presence
end
end