FIX: custom tools incorrectly setting all fields to blank enum (#1385)

Previous to this change, enum was set to [] which broke all non
enum tools
This commit is contained in:
Sam 2025-05-30 17:12:24 +10:00 committed by GitHub
parent 77ae426d95
commit b5d393b4bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 70 additions and 5 deletions

View File

@ -22,6 +22,8 @@ class AiTool < ActiveRecord::Base
message: I18n.t("discourse_ai.tools.name.characters"),
}
validate :validate_parameters_enum
def signature
{
name: function_call_name,
@ -57,6 +59,30 @@ class AiTool < ActiveRecord::Base
end
end
def validate_parameters_enum
return unless parameters.is_a?(Array)
parameters.each_with_index do |param, index|
next if !param.is_a?(Hash) || !param.key?("enum")
enum_values = param["enum"]
if enum_values.empty?
errors.add(
:parameters,
"Parameter '#{param["name"]}' at index #{index}: enum cannot be empty",
)
next
end
if enum_values.uniq.length != enum_values.length
errors.add(
:parameters,
"Parameter '#{param["name"]}' at index #{index}: enum values must be unique",
)
end
end
end
def self.preamble
<<~JS
/**

View File

@ -30,11 +30,16 @@ export default class AiToolEditorForm extends Component {
get formData() {
const parameters = (this.args.editingModel.parameters ?? []).map(
(parameter) => ({
...parameter,
isEnum: !!parameter.enum?.length,
enum: (parameter.enum ??= []),
})
(parameter) => {
const mappedParameter = {
...parameter,
};
parameter.isEnum = parameter.enum && parameter.enum.length > 0;
if (!parameter.isEnum) {
delete mappedParameter.enum;
}
return mappedParameter;
}
);
return {

View File

@ -92,6 +92,40 @@ RSpec.describe DiscourseAi::Admin::AiToolsController do
)
end
end
context "when enum validation fails" do
it "fails to create tool with empty enum" do
attrs = valid_attributes
attrs[:parameters] = [attrs[:parameters].first.merge(enum: [])]
expect {
post "/admin/plugins/discourse-ai/ai-tools.json",
params: { ai_tool: attrs }.to_json,
headers: {
"CONTENT_TYPE" => "application/json",
}
}.not_to change(AiTool, :count)
expect(response).to have_http_status(:unprocessable_entity)
expect(response.parsed_body["errors"]).to include(match(/enum cannot be empty/))
end
it "fails to create tool with duplicate enum values" do
attrs = valid_attributes
attrs[:parameters] = [attrs[:parameters].first.merge(enum: %w[c f c])]
expect {
post "/admin/plugins/discourse-ai/ai-tools.json",
params: { ai_tool: attrs }.to_json,
headers: {
"CONTENT_TYPE" => "application/json",
}
}.not_to change(AiTool, :count)
expect(response).to have_http_status(:unprocessable_entity)
expect(response.parsed_body["errors"]).to include(match(/enum values must be unique/))
end
end
end
describe "PUT #update" do