FIX: improve researcher tool - fix topic filters (#1368)

* Small fix, reasoning is now available on Claude 4 models

* fix invalid filters should raise, topic filter not working

* fix spec so we are consistent
This commit is contained in:
Sam 2025-05-26 16:00:44 +10:00 committed by GitHub
parent 2d6ec5e1e6
commit 70b0db2871
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 14 deletions

View File

@ -540,7 +540,7 @@ en:
provider_quantizations: "Order of provider quantizations (comma delimited list eg: fp16,fp8)" provider_quantizations: "Order of provider quantizations (comma delimited list eg: fp16,fp8)"
disable_streaming: "Disable streaming completions (convert streaming to non streaming requests)" disable_streaming: "Disable streaming completions (convert streaming to non streaming requests)"
reasoning_effort: "Reasoning effort (only applicable to reasoning models)" reasoning_effort: "Reasoning effort (only applicable to reasoning models)"
enable_reasoning: "Enable reasoning (only applicable to Sonnet 3.7)" enable_reasoning: "Enable reasoning (only applicable to reasoning models)"
enable_thinking: "Enable thinking (only on applicable models eg: flash 2.5)" enable_thinking: "Enable thinking (only on applicable models eg: flash 2.5)"
thinking_tokens: "Number of tokens used for thinking" thinking_tokens: "Number of tokens used for thinking"
reasoning_tokens: "Number of tokens used for reasoning" reasoning_tokens: "Number of tokens used for reasoning"

View File

@ -85,6 +85,16 @@ module DiscourseAi
limit: max_results, limit: max_results,
guardian: guardian, guardian: guardian,
) )
if filter.invalid_filters.present?
return(
{
error:
"Invalid filter fragment: #{filter.invalid_filters.join(" ")}\n\n#{self.class.filter_description}",
}
)
end
@result_count = filter.search.count @result_count = filter.search.count
blk.call details blk.call details

View File

@ -17,7 +17,7 @@ module DiscourseAi
::Search.word_to_date(str) ::Search.word_to_date(str)
end end
attr_reader :term, :filters, :order, :guardian, :limit, :offset attr_reader :term, :filters, :order, :guardian, :limit, :offset, :invalid_filters
# Define all filters at class level # Define all filters at class level
register_filter(/\Astatus:open\z/i) do |relation, _, _| register_filter(/\Astatus:open\z/i) do |relation, _, _|
@ -206,7 +206,6 @@ module DiscourseAi
end end
def initialize(term, guardian: nil, limit: nil, offset: nil) def initialize(term, guardian: nil, limit: nil, offset: nil)
@term = term.to_s
@guardian = guardian || Guardian.new @guardian = guardian || Guardian.new
@limit = limit @limit = limit
@offset = offset @offset = offset
@ -214,8 +213,10 @@ module DiscourseAi
@valid = true @valid = true
@order = :latest_post @order = :latest_post
@topic_ids = nil @topic_ids = nil
@invalid_filters = []
@term = term.to_s.strip
@term = process_filters(@term) process_filters(@term)
end end
def set_order!(order) def set_order!(order)
@ -248,12 +249,16 @@ module DiscourseAi
end end
if @topic_ids.present? if @topic_ids.present?
filtered = if original_filtered == filtered
original_filtered.where( filtered = original_filtered.where("posts.topic_id IN (?)", @topic_ids)
"posts.topic_id IN (?) OR posts.id IN (?)", else
@topic_ids, filtered =
filtered.select("posts.id"), original_filtered.where(
) "posts.topic_id IN (?) OR posts.id IN (?)",
@topic_ids,
filtered.select("posts.id"),
)
end
end end
filtered = filtered.limit(@limit) if @limit.to_i > 0 filtered = filtered.limit(@limit) if @limit.to_i > 0
@ -275,7 +280,7 @@ module DiscourseAi
private private
def process_filters(term) def process_filters(term)
return "" if term.blank? return if term.blank?
term term
.to_s .to_s
@ -293,10 +298,8 @@ module DiscourseAi
end end
end end
found ? nil : word invalid_filters << word if !found
end end
.compact
.join(" ")
end end
end end
end end

View File

@ -17,10 +17,23 @@ RSpec.describe DiscourseAi::Personas::Tools::Researcher do
fab!(:topic_with_tags) { Fabricate(:topic, category: category, tags: [tag_research, tag_data]) } fab!(:topic_with_tags) { Fabricate(:topic, category: category, tags: [tag_research, tag_data]) }
fab!(:post) { Fabricate(:post, topic: topic_with_tags) } fab!(:post) { Fabricate(:post, topic: topic_with_tags) }
fab!(:another_post) { Fabricate(:post) }
before { SiteSetting.ai_bot_enabled = true } before { SiteSetting.ai_bot_enabled = true }
describe "#invoke" do describe "#invoke" do
it "can correctly filter to a topic id" do
researcher =
described_class.new(
{ dry_run: true, filter: "topic:#{topic_with_tags.id}", goals: "analyze topic content" },
bot_user: bot_user,
llm: llm,
context: DiscourseAi::Personas::BotContext.new(user: user, post: post),
)
results = researcher.invoke(&progress_blk)
expect(results[:number_of_posts]).to eq(1)
end
it "returns filter information and result count" do it "returns filter information and result count" do
researcher = researcher =
described_class.new( described_class.new(
@ -63,6 +76,20 @@ RSpec.describe DiscourseAi::Personas::Tools::Researcher do
expect(researcher.options[:max_results]).to eq(50) expect(researcher.options[:max_results]).to eq(50)
end end
it "returns error for invalid filter fragments" do
researcher =
described_class.new(
{ filter: "invalidfilter tag:research", goals: "analyze content" },
bot_user: bot_user,
llm: llm,
context: DiscourseAi::Personas::BotContext.new(user: user, post: post),
)
results = researcher.invoke(&progress_blk)
expect(results[:error]).to include("Invalid filter fragment")
end
it "returns correct results for non-dry-run with filtered posts" do it "returns correct results for non-dry-run with filtered posts" do
# Stage 2 topics, each with 2 posts # Stage 2 topics, each with 2 posts
topics = Array.new(2) { Fabricate(:topic, category: category, tags: [tag_research]) } topics = Array.new(2) { Fabricate(:topic, category: category, tags: [tag_research]) }