FIX: avoid storing corrupt prompts (#92)
``` prompt << build_message(bot_user.username, reply) ``` Would store a "cooked" prompt which is invalid, instead just store the raw values which are later passed to build_message Additionally: 1. Disable summary command which needs honing 2. Stop storing decorations (searched for X) in prompt which leads to straying 3. Ship username directly to model, avoiding "user: content" in prompts. This was causing GPT to stray
This commit is contained in:
parent
70c158cae1
commit
30778d8af8
|
@ -100,7 +100,7 @@ en:
|
|||
command_description:
|
||||
time: "Time in %{timezone} is %{time}"
|
||||
summarize: "Summarized <a href='%{url}'>%{title}</a>"
|
||||
image: "Prompt: %{prompt}"
|
||||
image: "%{prompt}"
|
||||
categories:
|
||||
one: "Found %{count} category"
|
||||
other: "Found %{count} categories"
|
||||
|
@ -115,6 +115,6 @@ en:
|
|||
other: "Found %{count} <a href='%{url}'>results</a> for '%{query}'"
|
||||
|
||||
summarization:
|
||||
configuration_hint:
|
||||
configuration_hint:
|
||||
one: "Configure the `%{setting}` setting first."
|
||||
other: "Configure these settings first: %{settings}"
|
||||
|
|
|
@ -25,7 +25,7 @@ module DiscourseAi
|
|||
attr_reader :bot_user
|
||||
|
||||
BOT_NOT_FOUND = Class.new(StandardError)
|
||||
MAX_COMPLETIONS = 3
|
||||
MAX_COMPLETIONS = 6
|
||||
|
||||
def self.as(bot_user)
|
||||
available_bots = [DiscourseAi::AiBot::OpenAiBot, DiscourseAi::AiBot::AnthropicBot]
|
||||
|
@ -79,6 +79,7 @@ module DiscourseAi
|
|||
end
|
||||
|
||||
redis_stream_key = nil
|
||||
partial_reply = +""
|
||||
reply = +(bot_reply_post ? bot_reply_post.raw.dup : "")
|
||||
start = Time.now
|
||||
|
||||
|
@ -87,7 +88,9 @@ module DiscourseAi
|
|||
functions = Functions.new
|
||||
|
||||
submit_prompt(prompt, prefer_low_cost: prefer_low_cost) do |partial, cancel|
|
||||
reply << get_delta(partial, context)
|
||||
current_delta = get_delta(partial, context)
|
||||
partial_reply << current_delta
|
||||
reply << current_delta
|
||||
populate_functions(partial, functions)
|
||||
|
||||
if redis_stream_key && !Discourse.redis.get(redis_stream_key)
|
||||
|
@ -135,7 +138,8 @@ module DiscourseAi
|
|||
bot_reply_post.post_custom_prompt ||= post.build_post_custom_prompt(custom_prompt: [])
|
||||
prompt = post.post_custom_prompt.custom_prompt || []
|
||||
|
||||
prompt << build_message(bot_user.username, reply)
|
||||
prompt << [partial_reply, bot_user.username]
|
||||
|
||||
post.post_custom_prompt.update!(custom_prompt: prompt)
|
||||
end
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ module DiscourseAi::AiBot::Commands
|
|||
end
|
||||
|
||||
def description_args
|
||||
{ prompt: @last_prompt || 0 }
|
||||
{ prompt: @last_prompt }
|
||||
end
|
||||
|
||||
def chain_next_response
|
||||
|
|
|
@ -20,7 +20,8 @@ module DiscourseAi::AiBot::Commands
|
|||
),
|
||||
Parameter.new(
|
||||
name: "user",
|
||||
description: "Filter search results to this username",
|
||||
description:
|
||||
"Filter search results to this username (only include if user explicitly asks to filter by user)",
|
||||
type: "string",
|
||||
),
|
||||
Parameter.new(
|
||||
|
@ -31,7 +32,8 @@ module DiscourseAi::AiBot::Commands
|
|||
),
|
||||
Parameter.new(
|
||||
name: "limit",
|
||||
description: "limit number of results returned",
|
||||
description:
|
||||
"limit number of results returned (generally prefer to just keep to default)",
|
||||
type: "integer",
|
||||
),
|
||||
Parameter.new(
|
||||
|
|
|
@ -87,12 +87,12 @@ module DiscourseAi
|
|||
end
|
||||
|
||||
def available_commands
|
||||
# note: Summarize command is not ready yet, leave it out for now
|
||||
@cmds ||=
|
||||
[
|
||||
Commands::CategoriesCommand,
|
||||
Commands::TimeCommand,
|
||||
Commands::SearchCommand,
|
||||
Commands::SummarizeCommand,
|
||||
].tap do |cmds|
|
||||
cmds << Commands::TagsCommand if SiteSetting.tagging_enabled
|
||||
cmds << Commands::ImageCommand if SiteSetting.ai_stability_api_key.present?
|
||||
|
@ -108,6 +108,16 @@ module DiscourseAi
|
|||
"gpt-3.5-turbo-16k"
|
||||
end
|
||||
|
||||
def clean_username(username)
|
||||
if username.match?(/\0[a-zA-Z0-9_-]{1,64}\z/)
|
||||
username
|
||||
else
|
||||
# not the best in the world, but this is what we have to work with
|
||||
# if sites enable unicode usernames this can get messy
|
||||
username.gsub(/[^a-zA-Z0-9_-]/, "_")[0..63]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def populate_functions(partial, functions)
|
||||
|
@ -133,9 +143,9 @@ module DiscourseAi
|
|||
|
||||
if function
|
||||
result[:name] = poster_username
|
||||
elsif !system && poster_username != bot_user.username
|
||||
elsif !system && poster_username != bot_user.username && poster_username.present?
|
||||
# Open AI restrict name to 64 chars and only A-Za-z._ (work around)
|
||||
result[:content] = "#{poster_username}: #{content}"
|
||||
result[:name] = clean_username(poster_username)
|
||||
end
|
||||
|
||||
result
|
||||
|
|
|
@ -80,7 +80,9 @@ RSpec.describe DiscourseAi::AiBot::Bot do
|
|||
expect(last.raw).not_to include("translation missing")
|
||||
expect(last.raw).to include("I found nothing")
|
||||
|
||||
expect(last.post_custom_prompt.custom_prompt.to_s).to include("I found nothing")
|
||||
expect(last.post_custom_prompt.custom_prompt).to eq(
|
||||
[["[]", "search", "function"], ["I found nothing, sorry", bot_user.username]],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,11 @@ require_relative "../../../../../support/openai_completions_inference_stubs"
|
|||
require_relative "../../../../../support/anthropic_completion_stubs"
|
||||
|
||||
RSpec.describe Jobs::CreateAiReply do
|
||||
before do
|
||||
# got to do this cause we include times in system message
|
||||
freeze_time
|
||||
end
|
||||
|
||||
describe "#execute" do
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
fab!(:post) { Fabricate(:post, topic: topic) }
|
||||
|
|
|
@ -14,6 +14,14 @@ RSpec.describe DiscourseAi::AiBot::OpenAiBot do
|
|||
|
||||
subject { described_class.new(bot_user) }
|
||||
|
||||
context "when cleaning usernames" do
|
||||
it "can properly clean usernames so OpenAI allows it" do
|
||||
subject.clean_username("test test").should eq("test_test")
|
||||
subject.clean_username("test.test").should eq("test_test")
|
||||
subject.clean_username("test😀test").should eq("test_test")
|
||||
end
|
||||
end
|
||||
|
||||
context "when the topic has one post" do
|
||||
fab!(:post_1) { Fabricate(:post, topic: topic, raw: post_body(1), post_number: 1) }
|
||||
|
||||
|
@ -23,7 +31,8 @@ RSpec.describe DiscourseAi::AiBot::OpenAiBot do
|
|||
post_1_message = prompt_messages[-1]
|
||||
|
||||
expect(post_1_message[:role]).to eq("user")
|
||||
expect(post_1_message[:content]).to eq("#{post_1.user.username}: #{post_body(1)}")
|
||||
expect(post_1_message[:content]).to eq(post_body(1))
|
||||
expect(post_1_message[:name]).to eq(post_1.user.username)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -51,13 +60,15 @@ RSpec.describe DiscourseAi::AiBot::OpenAiBot do
|
|||
|
||||
# negative cause we may have grounding prompts
|
||||
expect(prompt_messages[-3][:role]).to eq("user")
|
||||
expect(prompt_messages[-3][:content]).to eq("#{post_1.username}: #{post_body(1)}")
|
||||
expect(prompt_messages[-3][:content]).to eq(post_body(1))
|
||||
expect(prompt_messages[-3][:name]).to eq(post_1.username)
|
||||
|
||||
expect(prompt_messages[-2][:role]).to eq("assistant")
|
||||
expect(prompt_messages[-2][:content]).to eq(post_body(2))
|
||||
|
||||
expect(prompt_messages[-1][:role]).to eq("user")
|
||||
expect(prompt_messages[-1][:content]).to eq("#{post_3.username}: #{post_body(3)}")
|
||||
expect(prompt_messages[-1][:content]).to eq(post_body(3))
|
||||
expect(prompt_messages[-1][:name]).to eq(post_3.username)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue