message responder backend now works
This commit is contained in:
parent
4fcf12287f
commit
cd7790f39a
|
@ -10,7 +10,13 @@ module ::Jobs
|
|||
persona_id = args[:persona_id]
|
||||
|
||||
begin
|
||||
persona =
|
||||
if args[:skip_persona_security_check]
|
||||
persona = AiPersona.all_personas.find { |persona| persona.id == persona_id }
|
||||
else
|
||||
persona = DiscourseAi::AiBot::Personas::Persona.find_by(user: post.user, id: persona_id)
|
||||
end
|
||||
|
||||
raise DiscourseAi::AiBot::Bot::BOT_NOT_FOUND if persona.nil?
|
||||
|
||||
bot = DiscourseAi::AiBot::Bot.as(bot_user, persona: persona.new)
|
||||
|
|
|
@ -132,6 +132,7 @@ class AiPersona < ActiveRecord::Base
|
|||
vision_max_pixels = self.vision_max_pixels
|
||||
rag_conversation_chunks = self.rag_conversation_chunks
|
||||
question_consolidator_llm = self.question_consolidator_llm
|
||||
role = self.role
|
||||
role_whispers = self.role_whispers
|
||||
|
||||
persona_class = DiscourseAi::AiBot::Personas::Persona.system_personas_by_id[self.id]
|
||||
|
@ -184,6 +185,10 @@ class AiPersona < ActiveRecord::Base
|
|||
role_whispers
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :role do
|
||||
role
|
||||
end
|
||||
|
||||
return persona_class
|
||||
end
|
||||
|
||||
|
@ -275,6 +280,10 @@ class AiPersona < ActiveRecord::Base
|
|||
question_consolidator_llm
|
||||
end
|
||||
|
||||
define_singleton_method :role do
|
||||
role
|
||||
end
|
||||
|
||||
define_singleton_method :role_whispers do
|
||||
role_whispers
|
||||
end
|
||||
|
|
|
@ -5,6 +5,23 @@ module DiscourseAi
|
|||
module Personas
|
||||
class Persona
|
||||
class << self
|
||||
def as_bot
|
||||
if self.respond_to?(:user_id) && self.respond_to?(:default_llm)
|
||||
if self.default_llm
|
||||
user = User.find_by(id: user_id)
|
||||
DiscourseAi::AiBot::Bot.new(user, self.new, self.default_llm) if user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def role
|
||||
"bot"
|
||||
end
|
||||
|
||||
def role_whispers
|
||||
false
|
||||
end
|
||||
|
||||
def rag_conversation_chunks
|
||||
10
|
||||
end
|
||||
|
|
|
@ -18,9 +18,30 @@ module DiscourseAi
|
|||
user_id.to_i <= 0
|
||||
end
|
||||
|
||||
def self.find_responder_persona(post)
|
||||
if post.post_number == 1 && post.topic && post.topic.archetype == Archetype.private_message
|
||||
# only supported responder for PMs is based on role_group_ids
|
||||
group_ids = post.topic.allowed_groups.pluck(:id)
|
||||
|
||||
info =
|
||||
group_ids
|
||||
.lazy
|
||||
.map { |group_id| AiPersona.message_responder_for(group_id: group_id) }
|
||||
.find { |found| !found.nil? }
|
||||
|
||||
AiPersona.all_personas.find { |persona| persona.id == info[:id] } if info && info[:id]
|
||||
end
|
||||
end
|
||||
|
||||
def self.schedule_reply(post)
|
||||
return if is_bot_user_id?(post.user_id)
|
||||
|
||||
if responder_persona_class = find_responder_persona(post)
|
||||
bot = responder_persona_class.as_bot
|
||||
new(bot).schedule_bot_reply(post, skip_persona_security_check: true) if bot
|
||||
return
|
||||
end
|
||||
|
||||
bot_ids = DiscourseAi::AiBot::EntryPoint::BOT_USER_IDS
|
||||
mentionables = AiPersona.mentionables(user: post.user)
|
||||
|
||||
|
@ -126,11 +147,12 @@ module DiscourseAi
|
|||
FROM upload_references ref
|
||||
WHERE ref.target_type = 'Post' AND ref.target_id = posts.id
|
||||
) as upload_ids",
|
||||
"post_number",
|
||||
)
|
||||
|
||||
result = []
|
||||
|
||||
context.reverse_each do |raw, username, custom_prompt, upload_ids|
|
||||
context.reverse_each do |raw, username, custom_prompt, upload_ids, post_number|
|
||||
custom_prompt_translation =
|
||||
Proc.new do |message|
|
||||
# We can't keep backwards-compatibility for stored functions.
|
||||
|
@ -151,8 +173,14 @@ module DiscourseAi
|
|||
if custom_prompt.present?
|
||||
custom_prompt.each(&custom_prompt_translation)
|
||||
else
|
||||
content = raw
|
||||
if post_number == 1 && bot.persona.class.role.include?("responder")
|
||||
title = Topic.where("id = ?", post.topic_id).pluck(:title).first
|
||||
content = "# #{title}\n\n#{content}"
|
||||
end
|
||||
|
||||
context = {
|
||||
content: raw,
|
||||
content: content,
|
||||
type: (available_bot_usernames.include?(username) ? :model : :user),
|
||||
}
|
||||
|
||||
|
@ -188,8 +216,11 @@ module DiscourseAi
|
|||
reply = +""
|
||||
start = Time.now
|
||||
|
||||
post_type =
|
||||
post.post_type == Post.types[:whisper] ? Post.types[:whisper] : Post.types[:regular]
|
||||
post_type = Post.types[:regular]
|
||||
|
||||
if post.post_type == Post.types[:whisper] || bot.persona.class.role_whispers
|
||||
post_type = Post.types[:whisper]
|
||||
end
|
||||
|
||||
context = {
|
||||
site_url: Discourse.base_url,
|
||||
|
@ -208,7 +239,7 @@ module DiscourseAi
|
|||
reply_user = User.find_by(id: bot.persona.class.user_id) || reply_user
|
||||
end
|
||||
|
||||
stream_reply = post.topic.private_message?
|
||||
stream_reply = post.topic.private_message? && !bot.persona.role.include?("responder")
|
||||
|
||||
# we need to ensure persona user is allowed to reply to the pm
|
||||
if post.topic.private_message?
|
||||
|
@ -309,6 +340,19 @@ module DiscourseAi
|
|||
.concat(DiscourseAi::AiBot::EntryPoint::BOTS.map(&:second))
|
||||
end
|
||||
|
||||
def schedule_bot_reply(post, skip_persona_security_check: false)
|
||||
persona_id =
|
||||
DiscourseAi::AiBot::Personas::Persona.system_personas[bot.persona.class] ||
|
||||
bot.persona.class.id
|
||||
::Jobs.enqueue(
|
||||
:create_ai_reply,
|
||||
post_id: post.id,
|
||||
bot_user_id: bot.bot_user.id,
|
||||
persona_id: persona_id,
|
||||
skip_persona_security_check: skip_persona_security_check,
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def publish_final_update(reply_post)
|
||||
|
@ -347,18 +391,6 @@ module DiscourseAi
|
|||
end
|
||||
end
|
||||
|
||||
def schedule_bot_reply(post)
|
||||
persona_id =
|
||||
DiscourseAi::AiBot::Personas::Persona.system_personas[bot.persona.class] ||
|
||||
bot.persona.class.id
|
||||
::Jobs.enqueue(
|
||||
:create_ai_reply,
|
||||
post_id: post.id,
|
||||
bot_user_id: bot.bot_user.id,
|
||||
persona_id: persona_id,
|
||||
)
|
||||
end
|
||||
|
||||
def context(topic)
|
||||
{
|
||||
site_url: Discourse.base_url,
|
||||
|
|
|
@ -530,4 +530,60 @@ RSpec.describe DiscourseAi::AiBot::Playground do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "message_responder role" do
|
||||
fab!(:group) do
|
||||
Fabricate(:group, name: "test-group", messageable_level: Group::ALIAS_LEVELS[:everyone])
|
||||
end
|
||||
|
||||
it "can reply with a whisper to group PM" do
|
||||
Jobs.run_immediately!
|
||||
|
||||
persona =
|
||||
AiPersona.create!(
|
||||
name: "Responder Persona",
|
||||
description: "A responder",
|
||||
system_prompt: "You are a responder",
|
||||
enabled: true,
|
||||
role: "message_responder",
|
||||
role_group_ids: [group.id],
|
||||
role_whispers: true,
|
||||
default_llm: "anthropic:claude-2",
|
||||
)
|
||||
|
||||
persona.create_user!
|
||||
|
||||
post = nil
|
||||
|
||||
prompts = nil
|
||||
DiscourseAi::Completions::Llm.with_prepared_responses(
|
||||
["An amazing post just for you"],
|
||||
) do |_, _, _prompts|
|
||||
post =
|
||||
create_post(
|
||||
title: "an amazing title",
|
||||
raw: "Howdy I need help!!",
|
||||
archetype: Archetype.private_message,
|
||||
target_group_names: [group.name],
|
||||
)
|
||||
prompts = _prompts
|
||||
end
|
||||
|
||||
expect(prompts.length).to eq(1)
|
||||
expect(prompts[0].messages[0][:content]).to eq("You are a responder")
|
||||
expect(prompts[0].messages[1][:content]).to eq("# An amazing title\n\nHowdy I need help!!")
|
||||
|
||||
reply = post.topic.posts.find_by(post_number: 2)
|
||||
|
||||
expect(reply.post_type).to eq(Post.types[:whisper])
|
||||
expect(reply.raw).to eq("An amazing post just for you")
|
||||
|
||||
# should be done responding at this point so llm will not be called
|
||||
create_post(
|
||||
raw: "should ignore posts that are not first on message",
|
||||
topic: post.topic,
|
||||
user: post.user,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue