Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 12869f2

Browse files
authored
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
1 parent 4923837 commit 12869f2

File tree

8 files changed

+49
-49
lines changed

8 files changed

+49
-49
lines changed

app/controllers/discourse_ai/admin/ai_tools_controller.rb

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Admin
55
class AiToolsController < ::Admin::AdminController
66
requires_plugin ::DiscourseAi::PLUGIN_NAME
77

8-
before_action :find_ai_tool, only: %i[show update destroy]
8+
before_action :find_ai_tool, only: %i[test show update destroy]
99

1010
def index
1111
ai_tools = AiTool.all
@@ -17,7 +17,7 @@ def show
1717
end
1818

1919
def create
20-
ai_tool = AiTool.new(ai_tool_params.except(:rag_uploads))
20+
ai_tool = AiTool.new(ai_tool_params)
2121
ai_tool.created_by_id = current_user.id
2222

2323
if ai_tool.save
@@ -29,7 +29,7 @@ def create
2929
end
3030

3131
def update
32-
if @ai_tool.update(ai_tool_params.except(:rag_uploads))
32+
if @ai_tool.update(ai_tool_params)
3333
RagDocumentFragment.update_target_uploads(@ai_tool, attached_upload_ids)
3434
render_serialized(@ai_tool, AiCustomToolSerializer)
3535
else
@@ -46,18 +46,13 @@ def destroy
4646
end
4747

4848
def test
49-
if params[:id].present?
50-
ai_tool = AiTool.find(params[:id])
51-
else
52-
ai_tool = AiTool.new(ai_tool_params.except(:rag_uploads))
53-
end
54-
49+
@ai_tool.assign_attributes(ai_tool_params) if params[:ai_tool]
5550
parameters = params[:parameters].to_unsafe_h
5651

5752
# we need an llm so we have a tokenizer
5853
# but will do without if none is available
5954
llm = LlmModel.first&.to_llm
60-
runner = ai_tool.runner(parameters, llm: llm, bot_user: current_user, context: {})
55+
runner = @ai_tool.runner(parameters, llm: llm, bot_user: current_user, context: {})
6156
result = runner.invoke
6257

6358
if result.is_a?(Hash) && result[:error]
@@ -74,24 +69,27 @@ def test
7469
private
7570

7671
def attached_upload_ids
77-
ai_tool_params[:rag_uploads].to_a.map { |h| h[:id] }
72+
params[:ai_tool][:rag_uploads].to_a.map { |h| h[:id] }
7873
end
7974

8075
def find_ai_tool
81-
@ai_tool = AiTool.find(params[:id])
76+
@ai_tool = AiTool.find(params[:id].to_i)
8277
end
8378

8479
def ai_tool_params
85-
params.require(:ai_tool).permit(
86-
:name,
87-
:description,
88-
:script,
89-
:summary,
90-
:rag_chunk_tokens,
91-
:rag_chunk_overlap_tokens,
92-
rag_uploads: [:id],
93-
parameters: [:name, :type, :description, :required, enum: []],
94-
)
80+
params
81+
.require(:ai_tool)
82+
.permit(
83+
:name,
84+
:description,
85+
:script,
86+
:summary,
87+
:rag_chunk_tokens,
88+
:rag_chunk_overlap_tokens,
89+
rag_uploads: [:id],
90+
parameters: [:name, :type, :description, :required, enum: []],
91+
)
92+
.except(:rag_uploads)
9593
end
9694
end
9795
end

assets/javascripts/discourse/components/ai-tool-editor.gjs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,13 @@ export default class AiToolEditor extends Component {
232232
{{/if}}
233233

234234
<div class="control-group ai-tool-editor__action_panel">
235-
<DButton
236-
@action={{this.openTestModal}}
237-
@label="discourse_ai.tools.test"
238-
class="ai-tool-editor__test-button"
239-
/>
235+
{{#unless @model.isNew}}
236+
<DButton
237+
@action={{this.openTestModal}}
238+
@label="discourse_ai.tools.test"
239+
class="ai-tool-editor__test-button"
240+
/>
241+
{{/unless}}
240242

241243
<DButton
242244
@action={{this.save}}

assets/javascripts/discourse/components/modal/ai-tool-test-modal.gjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export default class AiToolTestModal extends Component {
2525
this.isLoading = true;
2626
try {
2727
const response = await ajax(
28-
"/admin/plugins/discourse-ai/ai-tools/test.json",
28+
`/admin/plugins/discourse-ai/ai-tools/${this.args.model.tool.id}/test.json`,
2929
{
3030
type: "POST",
3131
data: JSON.stringify({

config/routes.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@
5555
only: %i[index create show update destroy],
5656
path: "ai-tools",
5757
controller: "discourse_ai/admin/ai_tools",
58-
) { post :test, on: :collection }
58+
)
59+
60+
post "/ai-tools/:id/test", to: "discourse_ai/admin/ai_tools#test"
5961

6062
post "/ai-personas/:id/create-user", to: "discourse_ai/admin/ai_personas#create_user"
6163

lib/ai_bot/tool_runner.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ def rag_search(query, filenames: nil, limit: 10)
149149
limit: limit,
150150
offset: 0,
151151
)
152+
152153
fragments =
153154
RagDocumentFragment.where(id: fragment_ids, upload_id: upload_refs).pluck(
154155
:id,
@@ -174,8 +175,9 @@ def attach_truncate(mini_racer_context)
174175
def attach_index(mini_racer_context)
175176
mini_racer_context.attach(
176177
"_index_search",
177-
->(query, options) do
178+
->(*params) do
178179
begin
180+
query, options = params
179181
self.running_attached_function = true
180182
options ||= {}
181183
options = options.symbolize_keys

lib/embeddings/vector_representations/base.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ def asymmetric_rag_fragment_similarity_search(
205205
FROM
206206
#{rag_fragments_table_name}
207207
INNER JOIN
208-
rag_document_fragments ON rag_document_fragments.id = rag_document_fragment_id
208+
rag_document_fragments ON
209+
rag_document_fragments.id = rag_document_fragment_id AND
210+
rag_document_fragments.target_id = :target_id AND
211+
rag_document_fragments.target_type = :target_type
209212
WHERE
210213
model_id = #{id} AND strategy_id = #{@strategy.id}
211214
ORDER BY

spec/requests/admin/ai_tools_controller_spec.rb

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,8 @@
137137

138138
describe "#test" do
139139
it "runs an existing tool and returns the result" do
140-
post "/admin/plugins/discourse-ai/ai-tools/test.json",
140+
post "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}/test.json",
141141
params: {
142-
id: ai_tool.id,
143142
parameters: {
144143
input: "Hello, World!",
145144
},
@@ -149,43 +148,36 @@
149148
expect(response.parsed_body["output"]).to eq("input" => "Hello, World!")
150149
end
151150

152-
it "runs a new unsaved tool and returns the result" do
153-
post "/admin/plugins/discourse-ai/ai-tools/test.json",
151+
it "accept changes to the ai_tool parameters that redefine stuff" do
152+
post "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}/test.json",
154153
params: {
155154
ai_tool: {
156-
name: "New Tool",
157-
description: "A new test tool",
158-
script: "function invoke(params) { return 'New test result: ' + params.input; }",
159-
parameters: [
160-
{ name: "input", type: "string", description: "Input for the new test tool" },
161-
],
155+
script: "function invoke(params) { return 'hi there'; }",
162156
},
163157
parameters: {
164-
input: "Test input",
158+
input: "Hello, World!",
165159
},
166160
}
167161

168162
expect(response.status).to eq(200)
169-
expect(response.parsed_body["output"]).to eq("New test result: Test input")
163+
expect(response.parsed_body["output"]).to eq("hi there")
170164
end
171165

172166
it "returns an error for invalid tool_id" do
173-
post "/admin/plugins/discourse-ai/ai-tools/test.json",
167+
post "/admin/plugins/discourse-ai/ai-tools/-1/test.json",
174168
params: {
175-
id: -1,
176169
parameters: {
177170
input: "Hello, World!",
178171
},
179172
}
180173

181-
expect(response.status).to eq(400)
182-
expect(response.parsed_body["errors"]).to include("Couldn't find AiTool with 'id'=-1")
174+
expect(response.status).to eq(404)
183175
end
184176

185177
it "handles exceptions during tool execution" do
186178
ai_tool.update!(script: "function invoke(params) { throw new Error('Test error'); }")
187179

188-
post "/admin/plugins/discourse-ai/ai-tools/test.json",
180+
post "/admin/plugins/discourse-ai/ai-tools/#{ai_tool.id}/test.json",
189181
params: {
190182
id: ai_tool.id,
191183
parameters: {

spec/system/ai_bot/tool_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ def ensure_can_run_test
4949
expect(page.first(".parameter-row__required-toggle").checked?).to eq(true)
5050
expect(page.first(".parameter-row__enum-toggle").checked?).to eq(false)
5151

52-
ensure_can_run_test
52+
# not allowed to test yet
53+
expect(page).not_to have_button(".ai-tool-editor__test-button")
5354

5455
expect(page).not_to have_button(".ai-tool-editor__delete")
5556
find(".ai-tool-editor__save").click

0 commit comments

Comments
 (0)