sam

I want to make a PR to discourse/discourse-ai that changes the behavior of ai bot.

  • When a user replies directly to another user on an ai bot PM, do not reply as bot
  • When a user replies to another persona on the PM, reply as other persona

Can you help me create this PR, I am going to need tests as well.

Start by searching through the repo so you find the names of all the files involved, then read the important files.

gpt4t_bot GitHub Helper
GitHub code search

Searched for 'ai bot PM reply' in discourse/discourse-ai

GitHub code search

Searched for 'reply as other persona' in discourse/discourse-ai

GitHub file content

Retrieved content of lib/ai_bot/playground.rb, lib/ai_bot/entry_point.rb, spec/lib/modules/ai_bot/playground_spec.rb, spec/lib/modules/ai_bot/entry_point_spec.rb from discourse/discourse-ai@main

Based on the requirement to change the behavior of the AI bot in the discourse/discourse-ai repository as per your specifications, I found the relevant files involved in handling replies in the AI bot Private Messages (PMs). Below are the summaries and recommendations for modification:

Relevant Files

  1. playground.rb (lib/ai_bot/playground.rb)

    • This file contains the core logic for replying in PMs using the AI bot. The method schedule_reply determines when and how AI bot or other personas should reply to PMs based on the conditions outlined in your request.
    • Modification Suggestion:
      • Modify schedule_reply to check if the reply is directly to another user or to another persona. This can be determined by analyzing the mentions and topic_allowed_users to distinguish replies to users from replies to personas.
      • Implement additional logic within schedule_reply to skip AI bot replies when a user replies directly to another user in an AI bot PM.
      • Implement logic to reply as another persona when a user mentions or replies to another persona in the PM.
  2. entry_point.rb (lib/ai_bot/entry_point.rb)

    • This file is primarily responsible for initializing the AI bot and handling the injection of AI bot functionalities into topics and posts.
    • Modification Suggestion:
      • While this file may not require direct modification for your requirements, it’s critical to ensure that any changes in playground.rb are compatible with the bot initialization and event handling described in this file.
  3. playground_spec.rb (spec/lib/modules/ai_bot/playground_spec.rb)

    • Contains specs/tests for the AI bot’s playground logic.
    • Modification Suggestion:
      • Write new tests for scenarios where a user replies directly to another user in an AI bot PM (expectation: AI bot should not reply).
      • Write new tests for scenarios where a user replies to another persona in an AI bot PM (expectation: reply as the other persona).
  4. entry_point_spec.rb (spec/lib/modules/ai_bot/entry_point_spec.rb)

    • Contains tests for the entry point of the AI bot, ensuring initialization and global settings are applied correctly.
    • Modification Suggestion:
      • Ensure that any new functionalities or modifications in the AI bot behavior are accompanied by corresponding tests in this file to ensure the changes do not impact bot initialization and configuration adversely.

Approach to Implementing Changes and Tests

  • For implementing the changes, focus on the schedule_reply method in the playground.rb file. Ensure that your logic correctly identifies the context of the reply (direct user reply vs. reply to persona) and alters the behavior of the AI bot accordingly.
  • For writing tests, refer to the existing structure and patterns in playground_spec.rb. Create test cases that mimic the scenarios outlined in your requirements (direct replies to users vs. replies to other personas) and validate the expected outcomes.

Before starting the implementation, it’s advisable to map out the precise logic and conditions for identifying replies to users vs. personas. This will ensure that the changes are accurately targeted and effective. Additionally, continuously run the existing and new tests to ensure that modifications do not introduce regressions or unintended behavior changes in the AI bot functionality.

sam

OK start with the changes to schedule_reply please.

gpt4t_bot GitHub Helper

To address the requirements for modifying the AI bot’s behavior in response to user replies within private messages (PMs), here is a proposed approach to adapt the schedule_reply method in the lib/ai_bot/playground.rb file. This method will be adjusted to incorporate the logic needed to differentiate between replies directly to another user and replies to another persona within an AI bot PM. Based on this differentiation, the AI bot will either abstain from responding (in the case of direct user replies) or it will reply as another persona (when the reply is directed at a persona).

Below is an example of how you might adapt the schedule_reply method to accommodate these requirements. Please note that this is a high-level outline intended to guide the implementation. Actual code might require adjustments based on the complete context of the application and additional logic in the playground.rb file.

module DiscourseAi
  module AiBot
    class Playground
      def self.schedule_reply(post)
        return if is_bot_user_id?(post.user_id)

        bot_ids = DiscourseAi::AiBot::EntryPoint::BOT_USER_IDS
        mentionables = AiPersona.mentionables(user: post.user)

        # Identify if the reply is to another user directly or to a persona
        direct_reply_to_user = post.reply_to_user.present?
        mentioned_persona = nil

        if post.topic.private_message?
          mentioned_persona = if mentionables.present?
            # extracting mentions from the post
            mentions = post.raw_mentions

            # Find if a mentioned user is a persona
            mentionables.find { |mentionable| mentions.include?(mentionable[:username].downcase) }
          end
        end

        # Conditions to modify behavior based on the target of the reply
        if direct_reply_to_user
          # If this is a direct user reply in an AI bot PM, do not schedule a reply from the bot.
          return
        elsif mentioned_persona
          # This section is entered if a reply is to another persona; here we need to schedule a reply as another persona
          bot_user = User.find(mentioned_persona[:user_id])
          bot = DiscourseAi::AiBot::Bot.as(bot_user, persona: mentioned_persona.class_instance.new)
          new(bot).update_playground_with(post)
        else
          # Default behavior (existing behavior) if not replying directly to a user or mentioning a persona
          default_bot_reply(post, bot_ids, mentionables)
        end
      end

      private

      # This method encapsulates the existing behavior to allow for clear separation of the new conditional logic
      def self.default_bot_reply(post, bot_ids, mentionables)
        # Existing logic to handle replies in AI bot PMs
      end

      # Existing methods not shown for brevity
    end
  end
end

Steps for Implementation:

  1. Integration: Integrate this outlined logic into the existing schedule_reply method, ensuring it works cohesively with any existing conditions and actions.
  2. Testing: After integration, create or update tests to reflect the new behavior. This will involve modifying playground_spec.rb to simulate scenarios where users reply directly to another user or to a persona within an AI bot PM.
  3. Review and Refine: Test the modified method in development or a test environment to validate its correctness. Pay close attention to edge cases or any situations where the context of the reply might not be recognized as expected.

This approach allows for a clear distinction between different types of replies in PMs and adjusts the AI bot’s behavior to either respond or not, based on the identified reply context.

sam

but if we are replying to a bot it is fine we can continue …

gpt4t_bot GitHub Helper

Given the clarification that replying to a bot (including AI bot personas) should continue the conversation seamlessly, we need to adjust the previously proposed changes to the schedule_reply method. This adjustment ensures that:

  1. Replies directly to other non-bot users in an AI bot PM don’t trigger a bot response.
  2. Replies to bot users (including persona bots and other AI bots) proceed with a bot-generated reply, preserving the flow of the conversation.

Here’s a refined approach to adapt the schedule_reply method in the lib/ai_bot/playground.rb file:

module DiscourseAi
  module AiBot
    class Playground
      def self.schedule_reply(post)
        return if is_bot_user_id?(post.user_id)

        bot_ids = DiscourseAi::AiBot::EntryPoint::BOT_USER_IDS
        mentionables = AiPersona.mentionables(user: post.user)

        if post.topic.private_message?
          mentioned_users = post.raw_mentions.map(&:downcase)

          # Identifies if the reply is directly to a non-bot user by checking mentionables and bot_ids
          direct_reply_to_non_bot_user = mentioned_users.present? &&
                                          !(mentioned_users & mentionables.map { |m| m[:username].downcase }).empty? &&
                                          !(mentioned_users & User.where(id: bot_ids).pluck(:username).map(&:downcase)).empty?

          if direct_reply_to_non_bot_user
            # If this is a direct reply to a non-bot user in an AI bot PM, do not schedule a bot reply.
            return
          end

          # For all other cases, including no direct mentions or mentions of bots/personas, proceed with regular bot scheduling
          bot_user = determine_bot_user(post, bot_ids, mentionables)
          bot = DiscourseAi::AiBot::Bot.as(bot_user)

          new(bot).update_playground_with(post)
        end
      end

      private

      def self.determine_bot_user(post, bot_ids, mentionables)
        # Logic to determine the appropriate bot user based on mentions or default to the AI bot.
        # This method returns the bot User object.

        # Example implementation, adjust based on actual bot selection logic:
        mentioned_bot_id = (post.raw_mentions & User.where(id: bot_ids).pluck(:username)).first
        return User.find_by(username: mentioned_bot_id) if mentioned_bot_id

        # If no specific bot is mentioned, select based on other criteria or defaults
        default_bot_user_id = bot_ids.include?(post.topic.custom_fields["ai_persona_id"]) ? post.topic.custom_fields["ai_persona_id"].to_i : bot_ids.first
        User.find_by(id: default_bot_user_id)
      end

      # Existing methods not shown for brevity
    end
  end
end

Key Adjustments:

  • The condition direct_reply_to_non_bot_user is introduced to determine if the reply is specifically directed (mentioned) to non-bot users. This effectively bypasses the bot response if the condition is true.
  • The determine_bot_user method serves to explicitly choose the bot user that should reply. This method can be tailored further to incorporate complex logic for selecting among multiple bots/personas based on mentions or other criteria.

Next Steps:

  1. Integration and Testing: Replace or modify the existing schedule_reply method with the adjusted logic provided above, ensuring it fits seamlessly with existing code. Update or add tests in playground_spec.rb to cover the new logic paths—particularly ensuring that replies to non-bot users in PMs don’t trigger bot responses, while replies to bots/personas do.
  2. Refinement: After implementing, conduct thorough testing to confirm the behavior aligns with the desired outcomes across various scenarios including direct replies to bots, personas, and non-bot users in PMs.
  3. Deployment: Once satisfied with the implementation and testing, consider deploying the changes to a staging or production environment for real-world validation, keeping a close watch for any unexpected behaviors or issues.

This approach ensures a nuanced handling of user interactions within PMs, promoting a natural flow of conversation with bot personas while preventing unnecessary bot responses to direct, non-bot user interactions.

sam

OK assume I made the changes I needed, make an integration test that confirms the new behavior

gpt4t_bot GitHub Helper

Assuming you’ve implemented the necessary changes to the schedule_reply method in the lib/ai_bot/playground.rb file, the next step is to create an integration test that validates the new behavior of the AI bot. This test will confirm that:

  1. The AI bot does not reply to direct user replies in an AI bot PM.
  2. The AI bot or the designated persona correctly replies when the user’s message is intended for it.

Let’s outline an integration test scenario using RSpec, located in spec/lib/modules/ai_bot/playground_spec.rb, which confirms these behaviors:

require 'rails_helper'

RSpec.describe DiscourseAi::AiBot::Playground do
  fab!(:bot_user) { User.find(-110) } # Assuming -110 is a bot's user ID for the sake of the example
  fab!(:persona_user) { Fabricate(:user) } # Assuming this user is configured as a persona
  fab!(:regular_user) { Fabricate(:user) }
  let(:ai_bot_playground) { DiscourseAi::AiBot::Playground }

  before do
    SiteSetting.ai_bot_enabled = true
    # Additional setup as necessary for enabling AI bot, personas, etc.
  end

  describe '#schedule_reply behavior' do
    let!(:pm) do
      Fabricate(
        :private_message_topic,
        user: regular_user,
        topic_allowed_users: [
          Fabricate.build(:topic_allowed_user, user: regular_user),
          Fabricate.build(:topic_allowed_user, user: bot_user),
          Fabricate.build(:topic_allowed_user, user: persona_user)
        ]
      )
    end

    it 'does not reply to a direct reply to a regular user' do
      original_post_count = pm.posts.count

      # Simulate a post by a regular user directly replying to another regular user
      PostCreator.create!(
        regular_user,
        raw: "Thanks for your input, @#{regular_user.username}",
        topic_id: pm.id
      )

      # Assuming background jobs run synchronously for the sake of this example
      expect(pm.reload.posts.count).to eq(original_post_count + 1) # Only the user's new post, no bot reply
    end

    it 'replies to a direct mention of a persona bot in PM' do
      original_post_count = pm.posts.count

      # Simulate a post mentioning the persona bot
      PostCreator.create!(
        regular_user,
        raw: "Hey @#{persona_user.username}, can you give me more information?",
        topic_id: pm.id
      )

      # Assuming background jobs run synchronously for the sake of this example
      expect(pm.reload.posts.count).to eq(original_post_count + 2) # Includes the new post and bot's (persona's) reply
    end
  end
end

Key Points in This Example:

  • This test suite contains two scenarios. One where a regular user replies to another regular user should not trigger a bot reply. The other, where a regular user mentions a persona, should result in a reply from the bot configured as that persona.
  • The fab!(:bot_user) and fab!(:persona_user) lines presume specific user setups. You’ll need to adjust these to match your actual bot and persona user configurations.
  • The test assumes that the background jobs, which typically handle bot replies, run synchronously or are otherwise triggered within the scope of the test. Depending on your test environment setup, you might need to tweak this assumption (e.g., by explicitly running jobs or using tools like the sidekiq/testing inline mode for Sidekiq).

Next Steps:

  1. Run the Test: Execute this test suite to verify the implementation meets the expected behavior. Adjust the test or implementation as necessary based on the outcomes observed.
  2. Expand Test Coverage: Consider adding more tests to cover additional scenarios or edge cases that could arise from your specific implementation details.
  3. Review and Refine: Analyze test results for potential improvements or optimizations in both the test and the AI bot functionality to ensure robust and predictable behavior.