2023-05-16 13:38:21 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2024-01-04 08:44:07 -05:00
|
|
|
RSpec.describe DiscourseAi::AiBot::Bot do
|
|
|
|
subject(:bot) { described_class.as(bot_user) }
|
2023-09-14 17:02:37 -04:00
|
|
|
|
2024-03-05 10:48:28 -05:00
|
|
|
fab!(:admin)
|
2024-06-18 13:32:14 -04:00
|
|
|
fab!(:gpt_4) { Fabricate(:llm_model, name: "gpt-4") }
|
|
|
|
fab!(:fake) { Fabricate(:llm_model, name: "fake", provider: "fake") }
|
2024-02-02 15:09:34 -05:00
|
|
|
|
2023-10-23 02:00:58 -04:00
|
|
|
before do
|
2024-06-18 13:32:14 -04:00
|
|
|
toggle_enabled_bots(bots: [gpt_4])
|
2023-10-23 02:00:58 -04:00
|
|
|
SiteSetting.ai_bot_enabled = true
|
|
|
|
end
|
|
|
|
|
2024-06-18 13:32:14 -04:00
|
|
|
let(:bot_user) { DiscourseAi::AiBot::EntryPoint.find_user_from_model("gpt-4") }
|
2023-05-16 13:38:21 -04:00
|
|
|
|
2024-01-04 08:44:07 -05:00
|
|
|
let!(:user) { Fabricate(:user) }
|
|
|
|
|
|
|
|
let(:function_call) { <<~TEXT }
|
|
|
|
Let me try using a function to get more info:<function_calls>
|
|
|
|
<invoke>
|
|
|
|
<tool_name>categories</tool_name>
|
|
|
|
</invoke>
|
|
|
|
</function_calls>
|
|
|
|
TEXT
|
|
|
|
|
|
|
|
let(:response) { "As expected, your forum has multiple tags" }
|
|
|
|
|
|
|
|
let(:llm_responses) { [function_call, response] }
|
|
|
|
|
|
|
|
describe "#reply" do
|
2024-02-02 15:09:34 -05:00
|
|
|
it "sets top_p and temperature params" do
|
|
|
|
# full integration test so we have certainty it is passed through
|
|
|
|
|
|
|
|
DiscourseAi::Completions::Endpoints::Fake.delays = []
|
|
|
|
DiscourseAi::Completions::Endpoints::Fake.last_call = nil
|
|
|
|
|
2024-06-18 13:32:14 -04:00
|
|
|
toggle_enabled_bots(bots: [fake])
|
2024-02-02 15:09:34 -05:00
|
|
|
Group.refresh_automatic_groups!
|
|
|
|
|
2024-06-18 13:32:14 -04:00
|
|
|
bot_user = DiscourseAi::AiBot::EntryPoint.find_user_from_model("fake")
|
2024-02-02 15:09:34 -05:00
|
|
|
AiPersona.create!(
|
|
|
|
name: "TestPersona",
|
|
|
|
top_p: 0.5,
|
|
|
|
temperature: 0.4,
|
|
|
|
system_prompt: "test",
|
|
|
|
description: "test",
|
|
|
|
allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]],
|
|
|
|
)
|
|
|
|
|
|
|
|
personaClass = DiscourseAi::AiBot::Personas::Persona.find_by(user: admin, name: "TestPersona")
|
|
|
|
|
|
|
|
bot = DiscourseAi::AiBot::Bot.as(bot_user, persona: personaClass.new)
|
|
|
|
bot.reply(
|
|
|
|
{ conversation_context: [{ type: :user, content: "test" }] },
|
|
|
|
) do |_partial, _cancel, _placeholder|
|
|
|
|
# we just need the block so bot has something to call with results
|
|
|
|
end
|
|
|
|
|
|
|
|
last_call = DiscourseAi::Completions::Endpoints::Fake.last_call
|
|
|
|
expect(last_call[:model_params][:top_p]).to eq(0.5)
|
|
|
|
expect(last_call[:model_params][:temperature]).to eq(0.4)
|
|
|
|
end
|
|
|
|
|
2024-01-04 08:44:07 -05:00
|
|
|
context "when using function chaining" do
|
|
|
|
it "yields a loading placeholder while proceeds to invoke the command" do
|
2024-05-07 07:55:46 -04:00
|
|
|
tool = DiscourseAi::AiBot::Tools::ListCategories.new({}, bot_user: nil, llm: nil)
|
2024-01-04 08:44:07 -05:00
|
|
|
partial_placeholder = +(<<~HTML)
|
|
|
|
<details>
|
|
|
|
<summary>#{tool.summary}</summary>
|
|
|
|
<p></p>
|
|
|
|
</details>
|
2024-01-09 07:20:28 -05:00
|
|
|
<span></span>
|
2024-01-04 16:15:34 -05:00
|
|
|
|
2024-01-04 08:44:07 -05:00
|
|
|
HTML
|
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
context = { conversation_context: [{ type: :user, content: "Does my site has tags?" }] }
|
2024-01-04 08:44:07 -05:00
|
|
|
|
|
|
|
DiscourseAi::Completions::Llm.with_prepared_responses(llm_responses) do
|
|
|
|
bot.reply(context) do |_bot_reply_post, cancel, placeholder|
|
|
|
|
expect(placeholder).to eq(partial_placeholder) if placeholder
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-05-16 13:38:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|