2023-11-23 10:58:54 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
require_relative "dialect_context"
|
2023-11-23 10:58:54 -05:00
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
RSpec.describe DiscourseAi::Completions::Dialects::ChatGpt do
|
|
|
|
let(:model_name) { "gpt-4" }
|
|
|
|
let(:context) { DialectContext.new(described_class, model_name) }
|
2023-11-23 10:58:54 -05:00
|
|
|
|
|
|
|
describe "#translate" do
|
|
|
|
it "translates a prompt written in our generic format to the ChatGPT format" do
|
|
|
|
open_ai_version = [
|
2024-01-12 12:36:44 -05:00
|
|
|
{ role: "system", content: context.system_insts },
|
|
|
|
{ role: "user", content: context.simple_user_input },
|
2023-11-23 10:58:54 -05:00
|
|
|
]
|
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
translated = context.system_user_scenario
|
2023-11-23 10:58:54 -05:00
|
|
|
|
|
|
|
expect(translated).to contain_exactly(*open_ai_version)
|
|
|
|
end
|
|
|
|
|
2024-01-15 21:48:00 -05:00
|
|
|
it "will retain usernames for unicode usernames, correctly in mixed mode" do
|
|
|
|
prompt =
|
|
|
|
DiscourseAi::Completions::Prompt.new(
|
|
|
|
"You are a bot",
|
|
|
|
messages: [
|
|
|
|
{ id: "👻", type: :user, content: "Message1" },
|
|
|
|
{ type: :model, content: "Ok" },
|
|
|
|
{ id: "joe", type: :user, content: "Message2" },
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
translated = context.dialect(prompt).translate
|
|
|
|
|
|
|
|
expect(translated).to eq(
|
|
|
|
[
|
|
|
|
{ role: "system", content: "You are a bot" },
|
|
|
|
{ role: "user", content: "👻: Message1" },
|
|
|
|
{ role: "assistant", content: "Ok" },
|
|
|
|
{ role: "user", content: "joe: Message2" },
|
|
|
|
],
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
it "translates tool_call and tool messages" do
|
|
|
|
expect(context.multi_turn_scenario).to eq(
|
2023-12-18 16:06:01 -05:00
|
|
|
[
|
2024-01-12 12:36:44 -05:00
|
|
|
{ role: "system", content: context.system_insts },
|
|
|
|
{ role: "user", content: "This is a message by a user", name: "user1" },
|
|
|
|
{ role: "assistant", content: "I'm a previous bot reply, that's why there's no user" },
|
|
|
|
{ role: "user", name: "user1", content: "This is a new message by a user" },
|
2024-01-05 15:08:10 -05:00
|
|
|
{
|
|
|
|
role: "assistant",
|
|
|
|
content: nil,
|
|
|
|
tool_calls: [
|
|
|
|
{
|
|
|
|
type: "function",
|
|
|
|
function: {
|
|
|
|
name: "get_weather",
|
|
|
|
arguments: { location: "Sydney", unit: "c" }.to_json,
|
|
|
|
},
|
|
|
|
id: "tool_id",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2024-01-12 12:36:44 -05:00
|
|
|
{ role: "tool", content: "I'm a tool result".to_json, tool_call_id: "tool_id" },
|
2023-12-18 16:06:01 -05:00
|
|
|
],
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "trims content if it's getting too long" do
|
2024-01-12 12:36:44 -05:00
|
|
|
translated = context.long_user_input_scenario
|
2023-12-18 16:06:01 -05:00
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
expect(translated.last[:role]).to eq("user")
|
|
|
|
expect(translated.last[:content].length).to be < context.long_message_text.length
|
2023-12-18 16:06:01 -05:00
|
|
|
end
|
2024-01-15 02:51:14 -05:00
|
|
|
|
|
|
|
it "always preserves system message when trimming" do
|
|
|
|
# gpt-4 is 8k tokens so last message totally blows everything
|
|
|
|
prompt = DiscourseAi::Completions::Prompt.new("You are a bot")
|
|
|
|
prompt.push(type: :user, content: "a " * 100)
|
|
|
|
prompt.push(type: :model, content: "b " * 100)
|
|
|
|
prompt.push(type: :user, content: "zjk " * 10_000)
|
|
|
|
|
|
|
|
translated = context.dialect(prompt).translate
|
|
|
|
|
|
|
|
expect(translated.length).to eq(2)
|
|
|
|
expect(translated.first).to eq(content: "You are a bot", role: "system")
|
|
|
|
expect(translated.last[:role]).to eq("user")
|
|
|
|
expect(translated.last[:content].length).to be < (8000 * 4)
|
|
|
|
end
|
2023-12-18 16:06:01 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "#tools" do
|
|
|
|
it "returns a list of available tools" do
|
2024-01-02 09:21:13 -05:00
|
|
|
open_ai_tool_f = {
|
|
|
|
function: {
|
2024-01-12 12:36:44 -05:00
|
|
|
description: context.tools.first[:description],
|
|
|
|
name: context.tools.first[:name],
|
2024-01-02 09:21:13 -05:00
|
|
|
parameters: {
|
|
|
|
properties:
|
2024-01-12 12:36:44 -05:00
|
|
|
context.tools.first[:parameters].reduce({}) do |memo, p|
|
2024-01-02 09:21:13 -05:00
|
|
|
memo[p[:name]] = { description: p[:description], type: p[:type] }
|
|
|
|
|
|
|
|
memo[p[:name]][:enum] = p[:enum] if p[:enum]
|
|
|
|
|
|
|
|
memo
|
|
|
|
end,
|
|
|
|
required: %w[location unit],
|
|
|
|
type: "object",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
type: "function",
|
|
|
|
}
|
2023-12-18 16:06:01 -05:00
|
|
|
|
2024-01-12 12:36:44 -05:00
|
|
|
expect(context.dialect_tools).to contain_exactly(open_ai_tool_f)
|
2023-12-18 16:06:01 -05:00
|
|
|
end
|
|
|
|
end
|
2023-11-23 10:58:54 -05:00
|
|
|
end
|