Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions app/models/ai_tool.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -57,6 +59,30 @@ def regenerate_rag_fragments
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
/**
Expand Down
15 changes: 10 additions & 5 deletions assets/javascripts/discourse/components/ai-tool-editor-form.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
34 changes: 34 additions & 0 deletions spec/requests/admin/ai_tools_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,40 @@
)
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
Expand Down
Loading