diff --git a/app/controllers/discourse_ai/admin/ai_spam_controller.rb b/app/controllers/discourse_ai/admin/ai_spam_controller.rb index 4d4a39175..aae13cd10 100644 --- a/app/controllers/discourse_ai/admin/ai_spam_controller.rb +++ b/app/controllers/discourse_ai/admin/ai_spam_controller.rb @@ -11,11 +11,20 @@ def show def update updated_params = {} - - updated_params[:llm_model_id] = allowed_params[:llm_model_id] if allowed_params.key?( - :llm_model_id, - ) - + if allowed_params.key?(:llm_model_id) + llm_model_id = updated_params[:llm_model_id] = allowed_params[:llm_model_id] + if llm_model_id.to_i < 0 && + !SiteSetting.ai_spam_detection_model_allowed_seeded_models_map.include?( + "custom:#{llm_model_id}", + ) + return( + render_json_error( + I18n.t("discourse_ai.llm.configuration.invalid_seeded_model"), + status: 422, + ) + ) + end + end updated_params[:data] = { custom_instructions: allowed_params[:custom_instructions], } if allowed_params.key?(:custom_instructions) diff --git a/app/serializers/ai_spam_serializer.rb b/app/serializers/ai_spam_serializer.rb index 69edfd4a5..179d828ce 100644 --- a/app/serializers/ai_spam_serializer.rb +++ b/app/serializers/ai_spam_serializer.rb @@ -16,9 +16,9 @@ def custom_instructions end def available_llms - DiscourseAi::Configuration::LlmEnumerator.values.map do |hash| - { id: hash[:value], name: hash[:name] } - end + DiscourseAi::Configuration::LlmEnumerator + .values(allowed_seeded_llms: SiteSetting.ai_spam_detection_model_allowed_seeded_models_map) + .map { |hash| { id: hash[:value], name: hash[:name] } } end def flagging_username diff --git a/lib/configuration/llm_enumerator.rb b/lib/configuration/llm_enumerator.rb index 76f5b913a..9cbae76bb 100644 --- a/lib/configuration/llm_enumerator.rb +++ b/lib/configuration/llm_enumerator.rb @@ -50,14 +50,19 @@ def self.valid_value?(val) true end - def self.values + def self.values(allowed_seeded_llms: nil) values = DB.query_hash(<<~SQL).map(&:symbolize_keys) SELECT display_name AS name, id AS value FROM llm_models SQL - values.each { |value_h| value_h[:value] = "custom:#{value_h[:value]}" } + if allowed_seeded_llms.is_a?(Array) + values = values.filter do |value_h| + value_h[:value] > 0 || allowed_seeded_llms.include?("custom:#{value_h[:value]}") + end + end + values.each { |value_h| value_h[:value] = "custom:#{value_h[:value]}" } values end diff --git a/spec/requests/admin/ai_spam_controller_spec.rb b/spec/requests/admin/ai_spam_controller_spec.rb index df8e9172b..5f82d306d 100644 --- a/spec/requests/admin/ai_spam_controller_spec.rb +++ b/spec/requests/admin/ai_spam_controller_spec.rb @@ -25,6 +25,30 @@ expect(AiModerationSetting.spam.data["custom_instructions"]).to eq("custom instructions") end + it "denies update for disallowed seeded llm" do + seeded_llm = Fabricate(:llm_model, id: -1) + + put "/admin/plugins/discourse-ai/ai-spam.json", + params: { + is_enabled: true, + llm_model_id: seeded_llm.id, + custom_instructions: "custom instructions", + } + + expect(response.status).to eq(422) + + SiteSetting.ai_spam_detection_model_allowed_seeded_models = seeded_llm.identifier + + put "/admin/plugins/discourse-ai/ai-spam.json", + params: { + is_enabled: true, + llm_model_id: seeded_llm.id, + custom_instructions: "custom instructions", + } + + expect(response.status).to eq(200) + end + it "can not enable spam detection without a model selected" do put "/admin/plugins/discourse-ai/ai-spam.json", params: { @@ -163,13 +187,32 @@ context "when logged in as admin" do before { sign_in(admin) } - it "returns the serialized spam settings" do + it "correctly filters seeded llms" do SiteSetting.ai_spam_detection_enabled = true + seeded_llm = Fabricate(:llm_model, id: -1, name: "seeded") get "/admin/plugins/discourse-ai/ai-spam.json" + expect(response.status).to eq(200) + json = response.parsed_body + # only includes fabricated model + expect(json["available_llms"].length).to eq(1) + + SiteSetting.ai_spam_detection_model_allowed_seeded_models = seeded_llm.identifier + + get "/admin/plugins/discourse-ai/ai-spam.json" expect(response.status).to eq(200) + json = response.parsed_body + expect(json["available_llms"].length).to eq(2) + end + + it "returns the serialized spam settings" do + SiteSetting.ai_spam_detection_enabled = true + + get "/admin/plugins/discourse-ai/ai-spam.json" + + expect(response.status).to eq(200) json = response.parsed_body expect(json["is_enabled"]).to eq(true) expect(json["selected_llm"]).to eq(nil)