From 7d943be7b204e9bbf408cb0843bb95a47629676d Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 24 Aug 2023 07:20:24 +1000 Subject: [PATCH] FIX: automatic bot titles missing sometime (#151) This fixes 2 big issues: 1. No matter how hard you try, grounding anthropic title prompt is just too hard. This works around by only looking at the last sentence it returns and treating as title 2. Non English locales would be stuck with "generic" title, this ensures every bot message gets a title, using a custom field to track Also, slightly tunes some anthropic prompts. --- lib/modules/ai_bot/anthropic_bot.rb | 2 +- lib/modules/ai_bot/bot.rb | 6 ++- lib/modules/ai_bot/entry_point.rb | 6 +++ .../jobs/regular/update_ai_bot_pm_title.rb | 2 +- lib/shared/inference/function_list.rb | 12 +++++- .../regular/update_ai_bot_pm_title_spec.rb | 43 +++++++++++++++++++ 6 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 spec/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title_spec.rb diff --git a/lib/modules/ai_bot/anthropic_bot.rb b/lib/modules/ai_bot/anthropic_bot.rb index 799b0932..b9f7a072 100644 --- a/lib/modules/ai_bot/anthropic_bot.rb +++ b/lib/modules/ai_bot/anthropic_bot.rb @@ -39,7 +39,7 @@ module DiscourseAi DiscourseAi::Inference::AnthropicCompletions.perform!( prompt, model_for, - temperature: 0.7, + temperature: 0.4, max_tokens: 40, ).dig(:completion) end diff --git a/lib/modules/ai_bot/bot.rb b/lib/modules/ai_bot/bot.rb index 36b40350..d0159e78 100644 --- a/lib/modules/ai_bot/bot.rb +++ b/lib/modules/ai_bot/bot.rb @@ -63,12 +63,14 @@ module DiscourseAi def update_pm_title(post) prompt = title_prompt(post) - new_title = get_updated_title(prompt) + new_title = get_updated_title(prompt).strip.split("\n").last PostRevisor.new(post.topic.first_post, post.topic).revise!( bot_user, title: new_title.sub(/\A"/, "").sub(/"\Z/, ""), ) + post.topic.custom_fields.delete(DiscourseAi::AiBot::EntryPoint::REQUIRE_TITLE_UPDATE) + post.topic.save_custom_fields end def max_commands_per_reply=(val) @@ -254,6 +256,8 @@ module DiscourseAi def title_prompt(post) [build_message(bot_user.username, <<~TEXT)] + You are titlebot. Given a topic you will figure out a title. + You will never respond with anything but a topic title. Suggest a 7 word title for the following topic without quoting any of it: #{post.topic.posts[1..-1].map(&:raw).join("\n\n")[0..prompt_limit]} diff --git a/lib/modules/ai_bot/entry_point.rb b/lib/modules/ai_bot/entry_point.rb index f2dae10a..cdbc8e89 100644 --- a/lib/modules/ai_bot/entry_point.rb +++ b/lib/modules/ai_bot/entry_point.rb @@ -3,6 +3,8 @@ module DiscourseAi module AiBot class EntryPoint + REQUIRE_TITLE_UPDATE = "discourse-ai-title-update" + GPT4_ID = -110 GPT3_5_TURBO_ID = -111 CLAUDE_V2_ID = -112 @@ -81,6 +83,10 @@ module DiscourseAi bot_id = post.topic.topic_allowed_users.where(user_id: bot_ids).first&.user_id if bot_id + if post.post_number == 1 + post.topic.custom_fields[REQUIRE_TITLE_UPDATE] = true + post.topic.save_custom_fields + end Jobs.enqueue(:create_ai_reply, post_id: post.id, bot_user_id: bot_id) Jobs.enqueue_in( 5.minutes, diff --git a/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title.rb b/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title.rb index 5e70338d..2ba7a9c3 100644 --- a/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title.rb +++ b/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title.rb @@ -9,7 +9,7 @@ module ::Jobs return unless bot = DiscourseAi::AiBot::Bot.as(bot_user) return unless post = Post.includes(:topic).find_by(id: args[:post_id]) - return unless post.topic.title.start_with?(I18n.t("discourse_ai.ai_bot.default_pm_prefix")) + return unless post.topic.custom_fields[DiscourseAi::AiBot::EntryPoint::REQUIRE_TITLE_UPDATE] bot.update_pm_title(post) end diff --git a/lib/shared/inference/function_list.rb b/lib/shared/inference/function_list.rb index f1aa3fe0..fab9b0e6 100644 --- a/lib/shared/inference/function_list.rb +++ b/lib/shared/inference/function_list.rb @@ -69,6 +69,8 @@ module ::DiscourseAi - When you run a command/function you will gain access to real information in a subsequant call! - NEVER EVER pretend to know stuff, you ALWAYS lean on functions to discover the truth! - You have direct access to data on this forum using !functions + - You are not a lier, liers are bad bots, you are a good bot! + - You always prefer to say "I don't know" as opposed to inventing a lie! { PROMPT @@ -111,8 +113,14 @@ module ::DiscourseAi echo(message: string [required]) } - You can execute with: - !echo(message: "hello world") + Human: please echo out "hello" + + Assistant: !echo(message: "hello") + + Human: please say "hello" + + Assistant: !echo(message: "hello") + PROMPT prompt diff --git a/spec/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title_spec.rb b/spec/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title_spec.rb new file mode 100644 index 00000000..1916c268 --- /dev/null +++ b/spec/lib/modules/ai_bot/jobs/regular/update_ai_bot_pm_title_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +RSpec.describe Jobs::UpdateAiBotPmTitle do + let(:user) { Fabricate(:admin) } + let(:bot_user) { User.find(DiscourseAi::AiBot::EntryPoint::CLAUDE_V2_ID) } + + it "will properly update title on bot PMs" do + SiteSetting.ai_bot_allowed_groups = Group::AUTO_GROUPS[:staff] + + Jobs.run_immediately! + + WebMock + .stub_request(:post, "https://api.anthropic.com/v1/complete") + .with(body: /You are a helpful Discourse assistant/) + .to_return(status: 200, body: "data: {\"completion\": \"Hello back at you\"}", headers: {}) + + WebMock + .stub_request(:post, "https://api.anthropic.com/v1/complete") + .with(body: /Suggest a 7 word title/) + .to_return( + status: 200, + body: "{\"completion\": \"A great title would be:\n\nMy amazing title\n\n\"}", + headers: { + }, + ) + + post = + create_post( + user: user, + raw: "Hello there", + title: "does not matter should be updated", + archetype: Archetype.private_message, + target_usernames: bot_user.username, + ) + + expect(post.reload.topic.title).to eq("My amazing title") + + WebMock.reset! + + Jobs::UpdateAiBotPmTitle.new.execute(bot_user_id: bot_user.id, post_id: post.id) + # should be a no op cause title is updated + end +end