# frozen_string_literal: true RSpec.describe DiscourseAi::AiBot::EntryPoint do describe "#inject_into" do describe "subscribes to the post_created event" do fab!(:admin) fab!(:bot_allowed_group) { Fabricate(:group) } fab!(:gpt_4) { Fabricate(:llm_model, name: "gpt-4") } let(:gpt_bot) { gpt_4.reload.user } fab!(:claude_2) { Fabricate(:llm_model, name: "claude-2") } let(:post_args) do { title: "Dear AI, I want to ask a question", raw: "Hello, Can you please tell me a story?", archetype: Archetype.private_message, target_usernames: [gpt_bot.username].join(","), } end before do toggle_enabled_bots(bots: [gpt_4, claude_2]) SiteSetting.ai_bot_enabled = true SiteSetting.ai_bot_allowed_groups = bot_allowed_group.id bot_allowed_group.add(admin) end it "adds a can_debug_ai_bot_conversations method to current user" do SiteSetting.ai_bot_debugging_allowed_groups = bot_allowed_group.id.to_s serializer = CurrentUserSerializer.new(admin, scope: Guardian.new(admin)) serializer = serializer.as_json expect(serializer[:current_user][:can_debug_ai_bot_conversations]).to eq(true) end it "adds mentionables to current_user_serializer" do Group.refresh_automatic_groups! persona = Fabricate( :ai_persona, mentionable: true, enabled: true, allowed_group_ids: [bot_allowed_group.id], ) persona.create_user! serializer = CurrentUserSerializer.new(admin, scope: Guardian.new(admin)) serializer = serializer.as_json bots = serializer[:current_user][:ai_enabled_chat_bots] persona_bot = bots.find { |bot| bot["id"] == persona.user_id } expect(persona_bot["username"]).to eq(persona.user.username) expect(persona_bot["mentionable"]).to eq(true) end it "includes user ids for all personas in the serializer" do Group.refresh_automatic_groups! persona = Fabricate(:ai_persona, enabled: true, allowed_group_ids: [bot_allowed_group.id]) persona.create_user! serializer = CurrentUserSerializer.new(admin, scope: Guardian.new(admin)) serializer = serializer.as_json bots = serializer[:current_user][:ai_enabled_chat_bots] persona_bot = bots.find { |bot| bot["id"] == persona.user_id } expect(persona_bot["username"]).to eq(persona.user.username) expect(persona_bot["mentionable"]).to eq(false) end it "queues a job to generate a reply by the AI" do expect { PostCreator.create!(admin, post_args) }.to change( Jobs::CreateAiReply.jobs, :size, ).by(1) end it "does not queue a job for small actions" do post = PostCreator.create!(admin, post_args) expect { post.topic.add_moderator_post( admin, "this is a small action", post_type: Post.types[:small_action], ) }.not_to change(Jobs::CreateAiReply.jobs, :size) expect { post.topic.add_moderator_post( admin, "this is a small action", post_type: Post.types[:moderator_action], ) }.not_to change(Jobs::CreateAiReply.jobs, :size) expect { post.topic.add_moderator_post( admin, "this is a small action", post_type: Post.types[:whisper], ) }.not_to change(Jobs::CreateAiReply.jobs, :size) end it "includes the bot's user_id" do claude_bot = DiscourseAi::AiBot::EntryPoint.find_user_from_model("claude-2") claude_post_attrs = post_args.merge(target_usernames: [claude_bot.username].join(",")) expect { PostCreator.create!(admin, claude_post_attrs) }.to change( Jobs::CreateAiReply.jobs, :size, ).by(1) job_args = Jobs::CreateAiReply.jobs.last["args"].first expect(job_args["bot_user_id"]).to eq(claude_bot.id) end context "when the post is not from a PM" do it "does nothing" do expect { PostCreator.create!(admin, post_args.merge(archetype: Archetype.default)) }.not_to change(Jobs::CreateAiReply.jobs, :size) end end context "when the bot doesn't have access to the PM" do it "does nothing" do user_2 = Fabricate(:user) expect { PostCreator.create!(admin, post_args.merge(target_usernames: [user_2.username])) }.not_to change(Jobs::CreateAiReply.jobs, :size) end end context "when the user is not allowed to interact with the bot" do it "does nothing" do bot_allowed_group.remove(admin) expect { PostCreator.create!(admin, post_args) }.not_to change( Jobs::CreateAiReply.jobs, :size, ) end end context "when the post was created by the bot" do it "does nothing" do gpt_topic_id = PostCreator.create!(admin, post_args).topic_id reply_args = post_args.except(:archetype, :target_usernames, :title).merge(topic_id: gpt_topic_id) expect { PostCreator.create!(gpt_bot, reply_args) }.not_to change( Jobs::CreateAiReply.jobs, :size, ) end end end end end