Sam a3c827efcc
FEATURE: allow personas to supply top_p and temperature params (#459)
* FEATURE: allow personas to supply top_p and temperature params

Code assistance generally are more focused at a lower temperature
This amends it so SQL Helper runs at 0.2 temperature vs the more
common default across LLMs of 1.0.

Reduced temperature leads to more focused, concise and predictable
answers for the SQL Helper

* fix tests

* This is not perfect, but far better than what we do today

Instead of fishing for

1. Draft sequence
2. Draft body

We skip (2), this means the composer "only" needs 1 http request to
open, we also want to eliminate (1) but it is a bit of a trickier
core change, may figure out how to pull it off (defer it to first draft save)

Value of bot drafts < value of opening bot conversations really fast
2024-02-03 07:09:34 +11:00

87 lines
2.7 KiB
Ruby

# frozen_string_literal: true
RSpec.describe DiscourseAi::AiBot::Bot do
subject(:bot) { described_class.as(bot_user) }
fab!(:admin) { Fabricate(:admin) }
before do
SiteSetting.ai_bot_enabled_chat_bots = "gpt-4"
SiteSetting.ai_bot_enabled = true
end
let(:bot_user) { User.find(DiscourseAi::AiBot::EntryPoint::GPT4_ID) }
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
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
SiteSetting.ai_bot_enabled_chat_bots = "fake"
SiteSetting.ai_bot_enabled = true
Group.refresh_automatic_groups!
bot_user = User.find(DiscourseAi::AiBot::EntryPoint::FAKE_ID)
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
context "when using function chaining" do
it "yields a loading placeholder while proceeds to invoke the command" do
tool = DiscourseAi::AiBot::Tools::ListCategories.new({})
partial_placeholder = +(<<~HTML)
<details>
<summary>#{tool.summary}</summary>
<p></p>
</details>
<span></span>
HTML
context = { conversation_context: [{ type: :user, content: "Does my site has tags?" }] }
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
end
end
end