Merge pull request #774 from basecamp/prevent-ai-recursion

Prevent recursion when invoking AI
This commit is contained in:
Jorge Manrubia
2025-07-21 10:39:59 +02:00
committed by GitHub
3 changed files with 29 additions and 3 deletions
+3 -1
View File
@@ -34,7 +34,9 @@ class Command::Ai::Parser
end
def commands_from_query(normalized_query, context)
parser = Command::Parser.new(context)
# The query should only contain supported /commands. If that's not the case,
# we don't want to fall back to AI again (potential stack overflow).
parser = Command::Parser.new(context, fall_back_to_ai: false)
if command_lines = normalized_query[:commands].presence
command_lines.collect { parser.parse(it) }
end
+15 -2
View File
@@ -3,8 +3,9 @@ class Command::Parser
delegate :user, :cards, :filter, :script_name, to: :context
def initialize(context)
def initialize(context, fall_back_to_ai: true)
@context = context
@fall_back_to_ai = fall_back_to_ai
end
def parse(string)
@@ -17,6 +18,10 @@ class Command::Parser
end
private
def fall_back_to_ai?
@fall_back_to_ai
end
def as_plain_text(string)
ActionText::Content.new(string).to_plain_text
end
@@ -100,7 +105,7 @@ class Command::Parser
elsif card = single_card_from(string)
Command::GoToCard.new(card_id: card.id)
else
Command::Ai::Parser.new(context).parse(string)
parse_with_fallback(string)
end
end
@@ -114,4 +119,12 @@ class Command::Parser
def single_card_from(string)
user.accessible_cards.find_by_id(string)
end
def parse_with_fallback(string)
if fall_back_to_ai?
Command::Ai::Parser.new(context).parse(string)
else
Command::Search.new(terms: string)
end
end
end
+11
View File
@@ -25,4 +25,15 @@ class Command::Ai::ParserTest < ActionDispatch::IntegrationTest
assert_equal [ collections(:writebook).id.to_s ], params[:collection_ids]
assert_equal [ tags(:web).id.to_s ], params[:tag_ids]
end
test "if the AI translator emitted an unknown command, this will result in a regular search (not on AI recursion)" do
Command::Ai::Translator.any_instance.stubs(:translate).returns(commands: [ "/missing" ])
command = parse_command "assign @kevin and close"
assert command.commands.one?
search_command = command.commands.first
assert search_command.is_a?(Command::Search)
assert_equal "/missing", search_command.terms
end
end