discourse-ai/spec/requests/admin/ai_tools_controller_spec.rb
Sam 12869f2146
FIX: testing tool was not showing rag results (#867)
This changeset contains 4 fixes:

1. We were allowing running tests on unsaved tools,
this is problematic cause uploads are not yet associated or indexed
leading to confusing results. We now only show the test button when
tool is saved.


2. We were not properly scoping rag document fragements, this
meant that personas and ai tools could get results from other
unrelated tools, just to be filtered out later


3. index.search showed options as "optional" but implementation
required the second option

4. When testing tools searching through document fragments was
not working at all cause we did not properly load the tool
2024-10-25 16:01:25 +11:00

193 lines
5.6 KiB
Ruby

# frozen_string_literal: true
RSpec.describe DiscourseAi::Admin::AiToolsController do
fab!(:admin)
fab!(:ai_tool) do
AiTool.create!(
name: "Test Tool",
description: "A test tool",
script: "function invoke(params) { return params; }",
parameters: [
{
name: "unit",
type: "string",
description: "the unit of measurement celcius c or fahrenheit f",
enum: %w[c f],
required: true,
},
],
summary: "Test tool summary",
created_by_id: -1,
)
end
before do
sign_in(admin)
SiteSetting.ai_embeddings_enabled = true
end
describe "GET #index" do
it "returns a success response" do
get "/admin/plugins/discourse-ai/ai-tools.json"
expect(response).to be_successful
expect(response.parsed_body["ai_tools"].length).to eq(AiTool.count)
expect(response.parsed_body["meta"]["presets"].length).to be > 0
end
end
describe "GET #show" do
it "returns a success response" do
get "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}.json"
expect(response).to be_successful
expect(response.parsed_body["ai_tool"]["name"]).to eq(ai_tool.name)
end
end
describe "POST #create" do
let(:valid_attributes) do
{
name: "Test Tool",
description: "A test tool",
parameters: [{ name: "query", type: "string", description: "perform a search" }],
script: "function invoke(params) { return params; }",
summary: "Test tool summary",
}
end
it "creates a new AiTool" do
expect {
post "/admin/plugins/discourse-ai/ai-tools.json",
params: { ai_tool: valid_attributes }.to_json,
headers: {
"CONTENT_TYPE" => "application/json",
}
}.to change(AiTool, :count).by(1)
expect(response).to have_http_status(:created)
expect(response.parsed_body["ai_tool"]["name"]).to eq("Test Tool")
end
context "when the parameter is a enum" do
it "creates the tool with the correct parameters" do
attrs = valid_attributes
attrs[:parameters] = [attrs[:parameters].first.merge(enum: %w[c f])]
expect {
post "/admin/plugins/discourse-ai/ai-tools.json",
params: { ai_tool: valid_attributes }.to_json,
headers: {
"CONTENT_TYPE" => "application/json",
}
}.to change(AiTool, :count).by(1)
expect(response).to have_http_status(:created)
expect(response.parsed_body.dig("ai_tool", "parameters", 0, "enum")).to contain_exactly(
"c",
"f",
)
end
end
end
describe "PUT #update" do
it "updates the requested ai_tool" do
put "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}.json",
params: {
ai_tool: {
name: "Updated Tool",
},
}
expect(response).to be_successful
expect(ai_tool.reload.name).to eq("Updated Tool")
end
context "when updating an enum parameters" do
it "updates the enum fixed values" do
put "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}.json",
params: {
ai_tool: {
parameters: [
{
name: "unit",
type: "string",
description: "the unit of measurement celcius c or fahrenheit f",
enum: %w[g d],
},
],
},
}
expect(response).to be_successful
expect(ai_tool.reload.parameters.dig(0, "enum")).to contain_exactly("g", "d")
end
end
end
describe "DELETE #destroy" do
it "destroys the requested ai_tool" do
expect { delete "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}.json" }.to change(
AiTool,
:count,
).by(-1)
expect(response).to have_http_status(:no_content)
end
end
describe "#test" do
it "runs an existing tool and returns the result" do
post "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}/test.json",
params: {
parameters: {
input: "Hello, World!",
},
}
expect(response.status).to eq(200)
expect(response.parsed_body["output"]).to eq("input" => "Hello, World!")
end
it "accept changes to the ai_tool parameters that redefine stuff" do
post "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}/test.json",
params: {
ai_tool: {
script: "function invoke(params) { return 'hi there'; }",
},
parameters: {
input: "Hello, World!",
},
}
expect(response.status).to eq(200)
expect(response.parsed_body["output"]).to eq("hi there")
end
it "returns an error for invalid tool_id" do
post "/admin/plugins/discourse-ai/ai-tools/-1/test.json",
params: {
parameters: {
input: "Hello, World!",
},
}
expect(response.status).to eq(404)
end
it "handles exceptions during tool execution" do
ai_tool.update!(script: "function invoke(params) { throw new Error('Test error'); }")
post "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}/test.json",
params: {
id: ai_tool.id,
parameters: {
input: "Hello, World!",
},
}
expect(response.status).to eq(400)
expect(response.parsed_body["errors"].to_s).to include("Error executing the tool")
end
end
end