mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-06-19 06:43:54 +08:00
567 lines
20 KiB
Ruby
Vendored
567 lines
20 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe DiscourseAi::AiBot::BotController do
|
|
fab!(:user)
|
|
fab!(:pm_topic, :private_message_topic)
|
|
fab!(:pm_post) { Fabricate(:post, topic: pm_topic) }
|
|
fab!(:pm_post2) { Fabricate(:post, topic: pm_topic) }
|
|
fab!(:pm_post3) { Fabricate(:post, topic: pm_topic) }
|
|
|
|
before do
|
|
enable_current_plugin
|
|
sign_in(user)
|
|
end
|
|
|
|
describe "#show_debug_info" do
|
|
fab!(:debug_bot_model) { Fabricate(:llm_model, name: "debug-bot-model") }
|
|
fab!(:debug_bot_user) do
|
|
enable_current_plugin
|
|
toggle_enabled_bots(bots: [debug_bot_model])
|
|
debug_bot_model.reload.user
|
|
end
|
|
|
|
fab!(:pm_topic) { Fabricate(:private_message_topic, user: user, recipient: debug_bot_user) }
|
|
fab!(:pm_post) { Fabricate(:post, topic: pm_topic, user: debug_bot_user) }
|
|
fab!(:pm_post2) { Fabricate(:post, topic: pm_topic, user: debug_bot_user) }
|
|
fab!(:pm_post3) { Fabricate(:post, topic: pm_topic, user: user) }
|
|
|
|
before { SiteSetting.ai_bot_enabled = true }
|
|
|
|
it "returns a 403 when the user cannot debug the AI bot conversation" do
|
|
get "/discourse-ai/ai-bot/post/#{pm_post.id}/show-debug-info"
|
|
expect(response.status).to eq(403)
|
|
end
|
|
|
|
it "does not disclose hidden whisper audit logs" do
|
|
debug_group = Fabricate(:group)
|
|
debug_group.add(user)
|
|
SiteSetting.ai_bot_debugging_allowed_groups = debug_group.id.to_s
|
|
SiteSetting.whispers_allowed_groups = Group::AUTO_GROUPS[:staff].to_s
|
|
|
|
visible_bot_post = Fabricate(:post, user: debug_bot_user)
|
|
hidden_whisper_post =
|
|
Fabricate(
|
|
:post,
|
|
topic: visible_bot_post.topic,
|
|
user: Fabricate(:admin),
|
|
post_type: Post.types[:whisper],
|
|
)
|
|
later_regular_post = Fabricate(:post, topic: visible_bot_post.topic, user: user)
|
|
|
|
visible_bot_log =
|
|
AiApiAuditLog.create!(
|
|
post_id: visible_bot_post.id,
|
|
provider_id: 1,
|
|
topic_id: visible_bot_post.topic_id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "bot request",
|
|
raw_response_payload: "bot response",
|
|
request_tokens: 1,
|
|
response_tokens: 2,
|
|
created_at: 2.minutes.ago,
|
|
)
|
|
|
|
hidden_bot_log =
|
|
AiApiAuditLog.create!(
|
|
post_id: hidden_whisper_post.id,
|
|
provider_id: 1,
|
|
topic_id: hidden_whisper_post.topic_id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "hidden bot request",
|
|
raw_response_payload: "hidden bot response",
|
|
request_tokens: 3,
|
|
response_tokens: 4,
|
|
created_at: 1.minute.ago,
|
|
)
|
|
|
|
hidden_translation_log =
|
|
AiApiAuditLog.create!(
|
|
post_id: hidden_whisper_post.id,
|
|
provider_id: 1,
|
|
topic_id: hidden_whisper_post.topic_id,
|
|
feature_name: "translation",
|
|
raw_request_payload: "hidden translation request",
|
|
raw_response_payload: "hidden translation response",
|
|
request_tokens: 5,
|
|
response_tokens: 6,
|
|
created_at: Time.zone.now,
|
|
)
|
|
|
|
get "/discourse-ai/ai-bot/post/#{later_regular_post.id}/show-debug-info"
|
|
show_debug_info_status = response.status
|
|
show_debug_info_body = response.parsed_body.deep_dup
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{hidden_translation_log.id}"
|
|
hidden_translation_status = response.status
|
|
hidden_translation_body = response.parsed_body.deep_dup
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{hidden_bot_log.id}"
|
|
hidden_bot_status = response.status
|
|
hidden_bot_body = response.parsed_body.deep_dup
|
|
|
|
aggregate_failures do
|
|
expect(show_debug_info_status).to eq(200)
|
|
expect(show_debug_info_body["id"]).to eq(visible_bot_log.id)
|
|
expect(show_debug_info_body["raw_request_payload"]).to eq("bot request")
|
|
expect(show_debug_info_body["raw_response_payload"]).to eq("bot response")
|
|
|
|
expect(hidden_translation_status).to eq(403)
|
|
expect(hidden_translation_body["errors"]).to include(I18n.t("invalid_access"))
|
|
|
|
expect(hidden_bot_status).to eq(403)
|
|
expect(hidden_bot_body["errors"]).to include(I18n.t("invalid_access"))
|
|
end
|
|
end
|
|
|
|
it "returns debug info if the user can debug the AI bot conversation" do
|
|
user = pm_topic.topic_allowed_users.first.user
|
|
sign_in(user)
|
|
|
|
log1 =
|
|
AiApiAuditLog.create!(
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "request",
|
|
raw_response_payload: "response",
|
|
request_tokens: 1,
|
|
response_tokens: 2,
|
|
)
|
|
|
|
log2 =
|
|
AiApiAuditLog.create!(
|
|
post_id: pm_post.id,
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "request",
|
|
raw_response_payload: "response",
|
|
request_tokens: 1,
|
|
response_tokens: 2,
|
|
)
|
|
|
|
log3 =
|
|
AiApiAuditLog.create!(
|
|
post_id: pm_post2.id,
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "request",
|
|
raw_response_payload: "response",
|
|
request_tokens: 1,
|
|
response_tokens: 2,
|
|
)
|
|
|
|
Group.refresh_automatic_groups!
|
|
SiteSetting.ai_bot_debugging_allowed_groups = user.groups.first.id.to_s
|
|
|
|
get "/discourse-ai/ai-bot/post/#{pm_post.id}/show-debug-info"
|
|
expect(response.status).to eq(200)
|
|
|
|
expect(response.parsed_body["id"]).to eq(log2.id)
|
|
expect(response.parsed_body["next_log_id"]).to eq(log3.id)
|
|
expect(response.parsed_body["prev_log_id"]).to eq(log1.id)
|
|
expect(response.parsed_body["topic_id"]).to eq(pm_topic.id)
|
|
|
|
expect(response.parsed_body["request_tokens"]).to eq(1)
|
|
expect(response.parsed_body["response_tokens"]).to eq(2)
|
|
expect(response.parsed_body["raw_request_payload"]).to eq("request")
|
|
expect(response.parsed_body["raw_response_payload"]).to eq("response")
|
|
|
|
get "/discourse-ai/ai-bot/post/#{pm_post3.id}/show-debug-info"
|
|
expect(response.status).to eq(200)
|
|
expect(response.parsed_body["request_tokens"]).to eq(1)
|
|
expect(response.parsed_body["response_tokens"]).to eq(2)
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{log1.id}"
|
|
expect(response.status).to eq(200)
|
|
expect(response.parsed_body["id"]).to eq(log1.id)
|
|
end
|
|
|
|
context "with conversation totals and spending" do
|
|
fab!(:llm_model) do
|
|
Fabricate(
|
|
:llm_model,
|
|
input_cost: 3.0,
|
|
output_cost: 6.0,
|
|
cached_input_cost: 1.0,
|
|
cache_write_cost: 2.0,
|
|
)
|
|
end
|
|
|
|
fab!(:other_llm_model) do
|
|
Fabricate(
|
|
:llm_model,
|
|
name: "other-model",
|
|
input_cost: 10.0,
|
|
output_cost: 20.0,
|
|
cached_input_cost: 5.0,
|
|
cache_write_cost: 8.0,
|
|
)
|
|
end
|
|
|
|
let(:allowed_user) { pm_topic.topic_allowed_users.first.user }
|
|
|
|
before do
|
|
sign_in(allowed_user)
|
|
Group.refresh_automatic_groups!
|
|
SiteSetting.ai_bot_debugging_allowed_groups = allowed_user.groups.first.id.to_s
|
|
end
|
|
|
|
it "computes per-turn spending and conversation totals across multiple models" do
|
|
log_a =
|
|
AiApiAuditLog.create!(
|
|
post_id: pm_post.id,
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
llm_id: llm_model.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "req",
|
|
raw_response_payload: "res",
|
|
request_tokens: 1_000_000,
|
|
response_tokens: 500_000,
|
|
cache_read_tokens: 200_000,
|
|
cache_write_tokens: 100_000,
|
|
)
|
|
|
|
AiApiAuditLog.create!(
|
|
post_id: pm_post2.id,
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
llm_id: other_llm_model.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "req",
|
|
raw_response_payload: "res",
|
|
request_tokens: 2_000_000,
|
|
response_tokens: 1_000_000,
|
|
)
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{log_a.id}"
|
|
expect(response.status).to eq(200)
|
|
|
|
body = response.parsed_body
|
|
expected_turn_spending =
|
|
(1_000_000 * 3.0 + 500_000 * 6.0 + 200_000 * 1.0 + 100_000 * 2.0) / 1_000_000.0
|
|
expect(body["spending"]).to be_within(0.000001).of(expected_turn_spending)
|
|
|
|
expect(body["conversation_request_tokens"]).to eq(3_000_000)
|
|
expect(body["conversation_response_tokens"]).to eq(1_500_000)
|
|
expect(body["conversation_cache_read_tokens"]).to eq(200_000)
|
|
expect(body["conversation_cache_write_tokens"]).to eq(100_000)
|
|
|
|
expected_conversation_spending =
|
|
expected_turn_spending + (2_000_000 * 10.0 + 1_000_000 * 20.0) / 1_000_000.0
|
|
expect(body["conversation_spending"]).to be_within(0.000001).of(
|
|
expected_conversation_spending,
|
|
)
|
|
end
|
|
|
|
it "returns nil spending when the log has no llm_model" do
|
|
log_a =
|
|
AiApiAuditLog.create!(
|
|
post_id: pm_post.id,
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "req",
|
|
raw_response_payload: "res",
|
|
request_tokens: 100,
|
|
response_tokens: 200,
|
|
)
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{log_a.id}"
|
|
expect(response.status).to eq(200)
|
|
|
|
body = response.parsed_body
|
|
expect(body["spending"]).to be_nil
|
|
expect(body["conversation_request_tokens"]).to eq(100)
|
|
expect(body["conversation_response_tokens"]).to eq(200)
|
|
expect(body["conversation_spending"]).to be_nil
|
|
end
|
|
|
|
it "returns nil conversation fields when topic_id is absent" do
|
|
log_a =
|
|
AiApiAuditLog.create!(
|
|
provider_id: 1,
|
|
llm_id: llm_model.id,
|
|
feature_name: "ai_bot",
|
|
raw_request_payload: "req",
|
|
raw_response_payload: "res",
|
|
request_tokens: 100,
|
|
response_tokens: 200,
|
|
)
|
|
SiteSetting.ai_bot_debugging_allowed_groups = Group::AUTO_GROUPS[:admins].to_s
|
|
sign_in(Fabricate(:admin))
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{log_a.id}"
|
|
# no topic means the endpoint 404s, so assert via serializer directly
|
|
serialized = AiApiAuditLogSerializer.new(log_a, root: false).as_json
|
|
expect(serialized[:conversation_request_tokens]).to be_nil
|
|
expect(serialized[:conversation_response_tokens]).to be_nil
|
|
expect(serialized[:conversation_cache_read_tokens]).to be_nil
|
|
expect(serialized[:conversation_cache_write_tokens]).to be_nil
|
|
expect(serialized[:conversation_spending]).to be_nil
|
|
end
|
|
end
|
|
|
|
it "returns topic-level debug info for any feature for a post in the conversation" do
|
|
user = pm_topic.topic_allowed_users.first.user
|
|
sign_in(user)
|
|
|
|
log =
|
|
AiApiAuditLog.create!(
|
|
provider_id: 1,
|
|
topic_id: pm_topic.id,
|
|
feature_name: "translation",
|
|
raw_request_payload: "request",
|
|
raw_response_payload: "response",
|
|
request_tokens: 1,
|
|
response_tokens: 2,
|
|
)
|
|
|
|
Group.refresh_automatic_groups!
|
|
SiteSetting.ai_bot_debugging_allowed_groups = user.groups.first.id.to_s
|
|
|
|
get "/discourse-ai/ai-bot/post/#{pm_post.id}/show-debug-info"
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(response.parsed_body["id"]).to eq(log.id)
|
|
|
|
get "/discourse-ai/ai-bot/show-debug-info/#{log.id}"
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(response.parsed_body["id"]).to eq(log.id)
|
|
end
|
|
end
|
|
|
|
describe "#stop_streaming_response" do
|
|
let(:redis_stream_key) { "gpt_cancel:#{pm_post.id}" }
|
|
|
|
before do
|
|
SiteSetting.ai_bot_enabled = true
|
|
Discourse.redis.setex(redis_stream_key, 60, 1)
|
|
end
|
|
|
|
it "returns a 403 when the user cannot see the PM" do
|
|
post "/discourse-ai/ai-bot/post/#{pm_post.id}/stop-streaming"
|
|
|
|
expect(response.status).to eq(403)
|
|
end
|
|
|
|
it "returns a 403 when the user can see the PM but is not in ai_bot_allowed_groups" do
|
|
allowed_user = pm_topic.topic_allowed_users.first.user
|
|
sign_in(allowed_user)
|
|
|
|
SiteSetting.ai_bot_allowed_groups = Group::AUTO_GROUPS[:staff].to_s
|
|
|
|
post "/discourse-ai/ai-bot/post/#{pm_post.id}/stop-streaming"
|
|
|
|
expect(response.status).to eq(403)
|
|
expect(Discourse.redis.get(redis_stream_key)).to eq("1")
|
|
end
|
|
|
|
it "returns a 403 when ai_bot_enabled is false" do
|
|
allowed_user = pm_topic.topic_allowed_users.first.user
|
|
sign_in(allowed_user)
|
|
|
|
SiteSetting.ai_bot_enabled = false
|
|
|
|
post "/discourse-ai/ai-bot/post/#{pm_post.id}/stop-streaming"
|
|
|
|
expect(response.status).to eq(403)
|
|
expect(Discourse.redis.get(redis_stream_key)).to eq("1")
|
|
end
|
|
|
|
it "deletes the key using to track the streaming" do
|
|
allowed_user = pm_topic.topic_allowed_users.first.user
|
|
sign_in(allowed_user)
|
|
|
|
Group.refresh_automatic_groups!
|
|
SiteSetting.ai_bot_allowed_groups = allowed_user.groups.first.id.to_s
|
|
|
|
post "/discourse-ai/ai-bot/post/#{pm_post.id}/stop-streaming"
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(Discourse.redis.get(redis_stream_key)).to be_nil
|
|
end
|
|
end
|
|
|
|
describe "#retry_response" do
|
|
fab!(:bot_user, :user)
|
|
let!(:llm_model) { Fabricate(:llm_model, user: bot_user) }
|
|
let!(:ai_agent) do
|
|
Fabricate(
|
|
:ai_agent,
|
|
user: bot_user,
|
|
default_llm_id: llm_model.id,
|
|
allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]],
|
|
)
|
|
end
|
|
let(:agent) { ai_agent.class_instance.new }
|
|
let(:bot) { DiscourseAi::Agents::Bot.as(bot_user, agent: agent) }
|
|
|
|
let!(:prompt_post) do
|
|
Fabricate(:post, topic: pm_topic, user: user, raw: "Hello @#{bot_user.username}")
|
|
end
|
|
|
|
let!(:reply_post) do
|
|
DiscourseAi::Completions::Llm.with_prepared_responses(["first try"]) do
|
|
DiscourseAi::AiBot::Playground.new(bot).reply_to(prompt_post)
|
|
end
|
|
|
|
pm_topic.reload.posts.last
|
|
end
|
|
|
|
before do
|
|
Group.refresh_automatic_groups!
|
|
SiteSetting.ai_bot_enabled = true
|
|
SiteSetting.ai_bot_allowed_groups = Group::AUTO_GROUPS[:trust_level_0].to_s
|
|
AiAgent.agent_cache.flush!
|
|
|
|
tl0_group =
|
|
Group.find_by(name: "trust_level_0") || Group.find(Group::AUTO_GROUPS[:trust_level_0])
|
|
GroupUser.find_or_create_by!(user: user, group: tl0_group)
|
|
user.reload
|
|
|
|
pm_topic.topic_allowed_users.find_or_create_by!(user: user)
|
|
|
|
unless pm_topic.topic_allowed_users.exists?(user: bot_user)
|
|
pm_topic.topic_allowed_users.create!(user: bot_user)
|
|
end
|
|
end
|
|
|
|
it "returns 403 when ai_bot_enabled is false" do
|
|
SiteSetting.ai_bot_enabled = false
|
|
|
|
post "/discourse-ai/ai-bot/post/#{reply_post.id}/retry"
|
|
|
|
expect(response.status).to eq(403)
|
|
end
|
|
|
|
it "returns 403 when user is not in ai_bot_allowed_groups" do
|
|
SiteSetting.ai_bot_allowed_groups = Group::AUTO_GROUPS[:admins].to_s
|
|
|
|
post "/discourse-ai/ai-bot/post/#{reply_post.id}/retry"
|
|
|
|
expect(response.status).to eq(403)
|
|
end
|
|
|
|
it "streams a replacement into the existing bot reply" do
|
|
retry_text = "second attempt"
|
|
messages = nil
|
|
|
|
DiscourseAi::Completions::Llm.with_prepared_responses([retry_text]) do
|
|
post "/discourse-ai/ai-bot/post/#{reply_post.id}/retry"
|
|
|
|
messages =
|
|
MessageBus.track_publish("discourse-ai/ai-bot/topic/#{reply_post.topic_id}") do
|
|
Jobs::CreateAiReply.new.execute(
|
|
post_id: prompt_post.id,
|
|
bot_user_id: bot_user.id,
|
|
agent_id: reply_post.custom_fields[DiscourseAi::AiBot::POST_AI_AGENT_ID_FIELD].to_i,
|
|
reply_post_id: reply_post.id,
|
|
)
|
|
end
|
|
end
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(reply_post.reload.raw).to eq(retry_text)
|
|
expect(messages.first.data).to include(post_id: reply_post.id, raw: "")
|
|
expect(reply_post.custom_fields[DiscourseAi::AiBot::POST_AI_AGENT_ID_FIELD].to_i).to eq(
|
|
agent.id,
|
|
)
|
|
end
|
|
|
|
it "returns a 404 when there is no previous non-bot prompt" do
|
|
lone_topic = Fabricate(:private_message_topic)
|
|
lone_topic.topic_allowed_users.create!(user: user)
|
|
lone_topic.topic_allowed_users.create!(user: bot_user)
|
|
bot_only_post = Fabricate(:post, topic: lone_topic, user: bot_user)
|
|
|
|
post "/discourse-ai/ai-bot/post/#{bot_only_post.id}/retry"
|
|
|
|
expect(response.status).to eq(404)
|
|
end
|
|
|
|
it "allows retrying if LLM model has a negative id (seeded)" do
|
|
seeded_llm_model = Fabricate(:llm_model, id: -9999, user: bot_user, name: "second-model")
|
|
|
|
bot = DiscourseAi::Agents::Bot.as(bot_user, agent: agent, model: seeded_llm_model)
|
|
DiscourseAi::Completions::Llm.with_prepared_responses(["first try"], llm: seeded_llm_model) do
|
|
DiscourseAi::AiBot::Playground.new(bot).reply_to(prompt_post)
|
|
end
|
|
|
|
reply = pm_topic.reload.posts.last
|
|
original_llm_id = reply.custom_fields[DiscourseAi::AiBot::POST_AI_LLM_MODEL_ID_FIELD]
|
|
|
|
expect(original_llm_id.to_i).to eq(-9999)
|
|
|
|
retry_text = "retry with original model"
|
|
|
|
DiscourseAi::Completions::Llm.with_prepared_responses([retry_text], llm: seeded_llm_model) do
|
|
post "/discourse-ai/ai-bot/post/#{reply.id}/retry"
|
|
|
|
job_args = Jobs::CreateAiReply.jobs.last["args"].first
|
|
expect(job_args["llm_model_id"]).to eq(-9999)
|
|
|
|
Jobs::CreateAiReply.new.execute(job_args.symbolize_keys)
|
|
end
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(reply.reload.raw).to eq(retry_text)
|
|
end
|
|
|
|
it "uses the original LLM model when retrying even if agent default changed" do
|
|
second_bot_user = Fabricate(:user)
|
|
second_llm_model = Fabricate(:llm_model, user: second_bot_user, name: "second-model")
|
|
|
|
pm_topic.topic_allowed_users.find_or_create_by!(user: second_bot_user)
|
|
|
|
original_llm_name = reply_post.custom_fields[DiscourseAi::AiBot::POST_AI_LLM_NAME_FIELD]
|
|
original_llm_id = reply_post.custom_fields[DiscourseAi::AiBot::POST_AI_LLM_MODEL_ID_FIELD]
|
|
|
|
expect(original_llm_name).to be_present
|
|
expect(original_llm_id.to_i).to eq(llm_model.id)
|
|
|
|
ai_agent.update!(default_llm_id: second_llm_model.id)
|
|
AiAgent.agent_cache.flush!
|
|
|
|
retry_text = "retry with original model"
|
|
|
|
DiscourseAi::Completions::Llm.with_prepared_responses([retry_text], llm: llm_model) do
|
|
post "/discourse-ai/ai-bot/post/#{reply_post.id}/retry"
|
|
|
|
job_args = Jobs::CreateAiReply.jobs.last["args"].first
|
|
expect(job_args["llm_model_id"]).to eq(llm_model.id)
|
|
|
|
Jobs::CreateAiReply.new.execute(job_args.symbolize_keys)
|
|
end
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(reply_post.reload.raw).to eq(retry_text)
|
|
expect(reply_post.custom_fields[DiscourseAi::AiBot::POST_AI_LLM_NAME_FIELD]).to eq(
|
|
original_llm_name,
|
|
)
|
|
expect(reply_post.custom_fields[DiscourseAi::AiBot::POST_AI_LLM_MODEL_ID_FIELD].to_i).to eq(
|
|
original_llm_id.to_i,
|
|
)
|
|
end
|
|
end
|
|
|
|
describe "#show_bot_username" do
|
|
it "returns the username_lower of the selected bot" do
|
|
gpt_35_bot = Fabricate(:llm_model, name: "gpt-3.5-turbo")
|
|
|
|
SiteSetting.ai_bot_enabled = true
|
|
toggle_enabled_bots(bots: [gpt_35_bot])
|
|
|
|
expected_username =
|
|
DiscourseAi::AiBot::EntryPoint.find_user_from_model("gpt-3.5-turbo").username_lower
|
|
|
|
get "/discourse-ai/ai-bot/bot-username", params: { username: gpt_35_bot.name }
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(response.parsed_body["bot_username"]).to eq(expected_username)
|
|
end
|
|
end
|
|
end
|