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
2 changes: 1 addition & 1 deletion config/locales/client.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ en:
provider_quantizations: "Order of provider quantizations (comma delimited list eg: fp16,fp8)"
disable_streaming: "Disable streaming completions (convert streaming to non streaming requests)"
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)"
thinking_tokens: "Number of tokens used for thinking"
reasoning_tokens: "Number of tokens used for reasoning"
Expand Down
10 changes: 10 additions & 0 deletions lib/personas/tools/researcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ def invoke(&blk)
limit: max_results,
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

blk.call details
Expand Down
29 changes: 16 additions & 13 deletions lib/utils/research/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def self.word_to_date(str)
::Search.word_to_date(str)
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
register_filter(/\Astatus:open\z/i) do |relation, _, _|
Expand Down Expand Up @@ -206,16 +206,17 @@ def self.word_to_date(str)
end

def initialize(term, guardian: nil, limit: nil, offset: nil)
@term = term.to_s
@guardian = guardian || Guardian.new
@limit = limit
@offset = offset
@filters = []
@valid = true
@order = :latest_post
@topic_ids = nil
@invalid_filters = []
@term = term.to_s.strip

@term = process_filters(@term)
process_filters(@term)
end

def set_order!(order)
Expand Down Expand Up @@ -248,12 +249,16 @@ def search
end

if @topic_ids.present?
filtered =
original_filtered.where(
"posts.topic_id IN (?) OR posts.id IN (?)",
@topic_ids,
filtered.select("posts.id"),
)
if original_filtered == filtered
filtered = original_filtered.where("posts.topic_id IN (?)", @topic_ids)
else
filtered =
original_filtered.where(
"posts.topic_id IN (?) OR posts.id IN (?)",
@topic_ids,
filtered.select("posts.id"),
)
end
end

filtered = filtered.limit(@limit) if @limit.to_i > 0
Expand All @@ -275,7 +280,7 @@ def search
private

def process_filters(term)
return "" if term.blank?
return if term.blank?

term
.to_s
Expand All @@ -293,10 +298,8 @@ def process_filters(term)
end
end

found ? nil : word
invalid_filters << word if !found
end
.compact
.join(" ")
end
end
end
Expand Down
27 changes: 27 additions & 0 deletions spec/lib/personas/tools/researcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,23 @@

fab!(:topic_with_tags) { Fabricate(:topic, category: category, tags: [tag_research, tag_data]) }
fab!(:post) { Fabricate(:post, topic: topic_with_tags) }
fab!(:another_post) { Fabricate(:post) }

before { SiteSetting.ai_bot_enabled = true }

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
researcher =
described_class.new(
Expand Down Expand Up @@ -63,6 +76,20 @@
expect(researcher.options[:max_results]).to eq(50)
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
# Stage 2 topics, each with 2 posts
topics = Array.new(2) { Fabricate(:topic, category: category, tags: [tag_research]) }
Expand Down
Loading