discourse-ai/spec/lib/modules/ai_bot/anthropic_bot_spec.rb

111 lines
3.5 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
module ::DiscourseAi
module AiBot
describe AnthropicBot do
def bot_user
User.find(EntryPoint::CLAUDE_V2_ID)
end
before do
SiteSetting.ai_bot_enabled_chat_bots = "claude-2"
SiteSetting.ai_bot_enabled = true
end
let(:bot) { described_class.new(bot_user) }
let(:post) { Fabricate(:post) }
describe "system message" do
it "includes the full command framework" do
FEATURE: UI to update ai personas on admin page (#290) Introduces a UI to manage customizable personas (admin only feature) Part of the change was some extensive internal refactoring: - AIBot now has a persona set in the constructor, once set it never changes - Command now takes in bot as a constructor param, so it has the correct persona and is not generating AIBot objects on the fly - Added a .prettierignore file, due to the way ALE is configured in nvim it is a pre-req for prettier to work - Adds a bunch of validations on the AIPersona model, system personas (artist/creative etc...) are all seeded. We now ensure - name uniqueness, and only allow certain properties to be touched for system personas. - (JS note) the client side design takes advantage of nested routes, the parent route for personas gets all the personas via this.store.findAll("ai-persona") then child routes simply reach into this model to find a particular persona. - (JS note) data is sideloaded into the ai-persona model the meta property supplied from the controller, resultSetMeta - This removes ai_bot_enabled_personas and ai_bot_enabled_chat_commands, both should be controlled from the UI on a per persona basis - Fixes a long standing bug in token accounting ... we were doing to_json.length instead of to_json.to_s.length - Amended it so {commands} are always inserted at the end unconditionally, no need to add it to the template of the system message as it just confuses things - Adds a concept of required_commands to stock personas, these are commands that must be configured for this stock persona to show up. - Refactored tests so we stop requiring inference_stubs, it was very confusing to need it, added to plugin.rb for now which at least is clearer - Migrates the persona selector to gjs --------- Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com> Co-authored-by: Martin Brennan <martin@discourse.org>
2023-11-21 16:56:43 +11:00
prompt = bot.system_prompt(post, allow_commands: true)
expect(prompt).to include("read")
expect(prompt).to include("search_query")
end
end
describe "parsing a reply prompt" do
it "can correctly predict that a completion needs to be cancelled" do
functions = DiscourseAi::AiBot::Bot::FunctionCalls.new
# note anthropic API has a silly leading space, we need to make sure we can handle that
prompt = +<<~REPLY.strip
hello world
!search(search_query: "hello world", random_stuff: 77)
!search(search_query: "hello world 2", random_stuff: 77
REPLY
bot.populate_functions(partial: nil, reply: prompt, functions: functions, done: false)
expect(functions.found?).to eq(true)
expect(functions.cancel_completion?).to eq(false)
prompt << ")\n"
bot.populate_functions(partial: nil, reply: prompt, functions: functions, done: false)
expect(functions.found?).to eq(true)
expect(functions.cancel_completion?).to eq(false)
prompt << "a test test"
bot.populate_functions(partial: nil, reply: prompt, functions: functions, done: false)
expect(functions.cancel_completion?).to eq(true)
end
it "can correctly detect commands from a prompt" do
functions = DiscourseAi::AiBot::Bot::FunctionCalls.new
# note anthropic API has a silly leading space, we need to make sure we can handle that
prompt = <<~REPLY
hello world
!search(search_query: "hello world", random_stuff: 77)
!random(search_query: "hello world", random_stuff: 77)
!read(topic_id: 109)
!read(random: 109)
REPLY
expect(functions.found?).to eq(false)
bot.populate_functions(partial: nil, reply: prompt, functions: functions, done: false)
expect(functions.found?).to eq(true)
bot.populate_functions(partial: nil, reply: prompt, functions: functions, done: true)
expect(functions.to_a).to eq(
[
{ name: "search", arguments: "{\"search_query\":\"hello world\"}" },
{ name: "read", arguments: "{\"topic_id\":\"109\"}" },
],
)
end
end
describe "#update_with_delta" do
describe "get_delta" do
it "can properly remove first leading space" do
context = {}
reply = +""
reply << bot.get_delta({ completion: " Hello" }, context)
reply << bot.get_delta({ completion: " World" }, context)
expect(reply).to eq("Hello World")
end
it "can properly remove Assistant prefix" do
context = {}
reply = +""
reply << bot.get_delta({ completion: "Hello " }, context)
expect(reply).to eq("Hello ")
reply << bot.get_delta({ completion: "world" }, context)
expect(reply).to eq("Hello world")
end
end
end
end
end
end