From bfdf6e97ddedc901580b1d357d577a8826351133 Mon Sep 17 00:00:00 2001 From: merefield Date: Tue, 19 Sep 2023 09:06:36 +0100 Subject: [PATCH 1/2] Add optional inner thought output in PMs --- app/jobs/regular/chatbot_reply_job.rb | 5 ++-- config/locales/server.en.yml | 1 + config/settings.yml | 3 ++ lib/discourse_chatbot/bots/open_ai_agent.rb | 18 ++++++----- .../post/post_reply_creator.rb | 30 +++++++++++-------- lib/discourse_chatbot/reply_creator.rb | 4 ++- plugin.rb | 4 +-- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/app/jobs/regular/chatbot_reply_job.rb b/app/jobs/regular/chatbot_reply_job.rb index a770443..f52498a 100644 --- a/app/jobs/regular/chatbot_reply_job.rb +++ b/app/jobs/regular/chatbot_reply_job.rb @@ -39,6 +39,7 @@ def execute(opts) elsif type == ::DiscourseChatbot::POST && post message_body = nil is_private_msg = post.topic.private_message? + opts.merge!(is_private_msg: is_private_msg) permitted_categories = SiteSetting.chatbot_permitted_categories.split('|') @@ -79,13 +80,13 @@ def execute(opts) else bot = ::DiscourseChatbot::OpenAIBot.new end - message_body = bot.ask(opts) + reply_and_thoughts = bot.ask(opts) rescue => e Rails.logger.error ("OpenAIBot: There was a problem, but will retry til limit: #{e}") fail e end end - opts.merge!(message_body: message_body) + opts.merge!(reply_and_thoughts) if type == ::DiscourseChatbot::POST reply_creator = ::DiscourseChatbot::PostReplyCreator.new(opts) else diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index e14b586..3df5286 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -15,6 +15,7 @@ en: chatbot_max_look_behind: "Maximum number of Posts or Chat Messages bot will consider as prompt for completion, the more the more impressive may be its response, but the more costly the interaction will be." chatbot_strip_quotes: "Determine if quotes are stripped and not sent within prompts (doesn't affect OP)" chatbot_permitted_in_private_messages: "Allow Chatbot to interact in Private Messages" + chatbot_include_inner_thoughts_in_private_messages: "EXPERIMENTAL: Get Chatbot to post its background thinking on Private Messages (Agent only)" chatbot_permitted_in_chat: "Allow Chatbot to interact in Chat" chatbot_can_trigger_from_whisper: "Allow Chatbot to be triggered from a whisper (get creative!)" chatbot_permitted_all_categories: "Allow Chatbot to interact in any Category" diff --git a/config/settings.yml b/config/settings.yml index e0dec02..1ade49e 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -5,6 +5,9 @@ plugins: chatbot_permitted_in_private_messages: default: true client: true + chatbot_include_inner_thoughts_in_private_messages: + default: false + client: false chatbot_permitted_in_chat: default: true client: true diff --git a/lib/discourse_chatbot/bots/open_ai_agent.rb b/lib/discourse_chatbot/bots/open_ai_agent.rb index 462ca75..ac5ee4f 100644 --- a/lib/discourse_chatbot/bots/open_ai_agent.rb +++ b/lib/discourse_chatbot/bots/open_ai_agent.rb @@ -80,10 +80,10 @@ def generate_response # Iteration: #{iteration} ------------------------------- EOS - res = create_chat_completion(@chat_history + @internal_thoughts) + res = create_chat_completion(@chat_history + @inner_thoughts) finish_reason = res["choices"][0]["finish_reason"] - if finish_reason == 'stop' || @internal_thoughts.length > 5 + if finish_reason == 'stop' || @inner_thoughts.length > 5 final_thought = final_thought_answer final_res = create_chat_completion( @chat_history + [final_thought], @@ -102,12 +102,12 @@ def generate_response def handle_function_call(res) first_message = res["choices"][0]["message"] - @internal_thoughts << first_message.to_hash + @inner_thoughts << first_message.to_hash func_name = first_message["function_call"]["name"] args_str = first_message["function_call"]["arguments"] result = call_function(func_name, args_str) res_msg = { 'role' => 'function', 'name' => func_name, 'content' => I18n.t("chatbot.prompt.agent.handle_function_call.answer", result: result) } - @internal_thoughts << res_msg + @inner_thoughts << res_msg end def call_function(func_name, args_str) @@ -128,7 +128,7 @@ def call_function(func_name, args_str) def final_thought_answer thoughts = I18n.t("chatbot.prompt.agent.final_thought_answer.opener") - @internal_thoughts.each do |thought| + @inner_thoughts.each do |thought| if thought.key?('function_call') thoughts += I18n.t("chatbot.prompt.agent.final_thought_answer.thought_declaration", function_name: thought['function_call']['name'], arguments: thought['function_call']['arguments']) else @@ -148,14 +148,16 @@ def get_response(prompt) system_message = { "role": "system", "content": I18n.t("chatbot.prompt.system.agent", current_date_time: DateTime.current) } prompt.unshift(system_message) - @internal_thoughts = [] + @inner_thoughts = [] @chat_history += prompt res = generate_response - @chat_history << res["choices"][0]["message"].to_hash - res["choices"][0]["message"]["content"] + { + reply: res["choices"][0]["message"]["content"], + inner_thoughts: @inner_thoughts.to_s + } end def ask(opts) diff --git a/lib/discourse_chatbot/post/post_reply_creator.rb b/lib/discourse_chatbot/post/post_reply_creator.rb index 5be795e..f9c1818 100644 --- a/lib/discourse_chatbot/post/post_reply_creator.rb +++ b/lib/discourse_chatbot/post/post_reply_creator.rb @@ -9,30 +9,36 @@ def initialize(options = {}) def create ::DiscourseChatbot.progress_debug_message("5. Creating a new Post...") + begin default_opts = { - raw: @message_body, topic_id: @topic_or_channel_id, post_alert_options: { skip_send_email: true }, skip_validations: true } - default_opts.merge!(reply_to_post_number: @reply_to_post_number) unless SiteSetting.chatbot_can_trigger_from_whisper + if SiteSetting.chatbot_bot_type == "agent" && SiteSetting.chatbot_include_inner_thoughts_in_private_messages && @is_private_msg + default_opts.merge!(raw: '[details="Inner Thoughts"]
' + @inner_thoughts + '
[/details]') - begin new_post = PostCreator.create!(@author, default_opts) + end - is_private_msg = new_post.topic.private_message? + default_opts.merge!(reply_to_post_number: @reply_to_post_number) unless SiteSetting.chatbot_can_trigger_from_whisper + default_opts.merge!(raw: @message_body) - if is_private_msg - presence = PresenceChannel.new("/discourse-presence/reply/#{@topic_or_channel_id}") - presence.leave(user_id: @author.id, client_id: "12345") - end + new_post = PostCreator.create!(@author, default_opts) - ::DiscourseChatbot.progress_debug_message("6. The Post has been created successfully") - rescue => e - ::DiscourseChatbot.progress_debug_message("Problem with the bot Post: #{e}") - Rails.logger.error ("AI Bot: There was a problem: #{e}") + is_private_msg = new_post.topic.private_message? + + if is_private_msg + presence = PresenceChannel.new("/discourse-presence/reply/#{@topic_or_channel_id}") + presence.leave(user_id: @author.id, client_id: "12345") end + + ::DiscourseChatbot.progress_debug_message("6. The Post has been created successfully") + rescue => e + ::DiscourseChatbot.progress_debug_message("Problem with the bot Post: #{e}") + Rails.logger.error ("AI Bot: There was a problem: #{e}") + end end end end diff --git a/lib/discourse_chatbot/reply_creator.rb b/lib/discourse_chatbot/reply_creator.rb index 3db24a2..b30b658 100644 --- a/lib/discourse_chatbot/reply_creator.rb +++ b/lib/discourse_chatbot/reply_creator.rb @@ -8,7 +8,9 @@ def initialize(options = {}) @reply_to = options[:reply_to_message_or_post_id] @reply_to_post_number = options[:original_post_number] @topic_or_channel_id = options[:topic_or_channel_id] - @message_body = options[:message_body] + @message_body = options[:reply] + @is_private_msg = options[:is_private_msg] + @inner_thoughts = options[:inner_thoughts] if @message_body.blank? @message_body = '...' end diff --git a/plugin.rb b/plugin.rb index 76ae3c4..8db0709 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-chatbot # about: a plugin that allows you to have a conversation with a configurable chatbot in Discourse Chat, Topics and Private Messages -# version: 0.44 +# version: 0.45 # authors: merefield # url: https://github.com/merefield/discourse-chatbot @@ -24,7 +24,7 @@ module ::DiscourseChatbot POST_TYPES_REGULAR_ONLY = [1] POST_TYPES_INC_WHISPERS = [1, 4] EMBEDDING_MODEL = "text-embedding-ada-002".freeze - EMBEDDING_CHAR_LIMIT = 13250 + EMBEDDING_CHAR_LIMIT = 12500 def progress_debug_message(message) if SiteSetting.chatbot_enable_verbose_console_response_progress_logging From 05711552268cb9c4704bba670e960c9c72368c7a Mon Sep 17 00:00:00 2001 From: merefield Date: Tue, 19 Sep 2023 11:13:03 +0100 Subject: [PATCH 2/2] fix test --- spec/lib/bot/open_ai_agent_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/bot/open_ai_agent_spec.rb b/spec/lib/bot/open_ai_agent_spec.rb index 49d0c62..5958deb 100644 --- a/spec/lib/bot/open_ai_agent_spec.rb +++ b/spec/lib/bot/open_ai_agent_spec.rb @@ -20,6 +20,6 @@ ::DiscourseChatbot::OpenAIAgent.any_instance.expects(:create_chat_completion).with(second_query).returns(llm_interim_response) ::DiscourseChatbot::OpenAIAgent.any_instance.expects(:create_chat_completion).with(final_query, false).returns(llm_final_response) - expect(agent.get_response(query)).to eq(llm_final_response["choices"][0]["message"]["content"]) + expect(agent.get_response(query)[:reply]).to eq(llm_final_response["choices"][0]["message"]["content"]) end end