mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 13:19:39 +02:00
137 lines
4.2 KiB
Ruby
137 lines
4.2 KiB
Ruby
|
require "test_helper"
|
||
|
|
||
|
class Provider::OpenaiTest < ActiveSupport::TestCase
|
||
|
include LLMInterfaceTest
|
||
|
|
||
|
setup do
|
||
|
@subject = @openai = Provider::Openai.new(ENV.fetch("OPENAI_ACCESS_TOKEN", "test-openai-token"))
|
||
|
@subject_model = "gpt-4o"
|
||
|
@chat = chats(:two)
|
||
|
end
|
||
|
|
||
|
test "openai errors are automatically raised" do
|
||
|
VCR.use_cassette("openai/chat/error") do
|
||
|
response = @openai.chat_response(UserMessage.new(
|
||
|
chat: @chat,
|
||
|
content: "Error test",
|
||
|
ai_model: "invalid-model-that-will-trigger-api-error"
|
||
|
))
|
||
|
|
||
|
assert_not response.success?
|
||
|
assert_kind_of Provider::Openai::Error, response.error
|
||
|
end
|
||
|
end
|
||
|
|
||
|
test "basic chat response" do
|
||
|
VCR.use_cassette("openai/chat/basic_response") do
|
||
|
message = @chat.messages.create!(
|
||
|
type: "UserMessage",
|
||
|
content: "This is a chat test. If it's working, respond with a single word: Yes",
|
||
|
ai_model: @subject_model
|
||
|
)
|
||
|
|
||
|
response = @subject.chat_response(message)
|
||
|
|
||
|
assert response.success?
|
||
|
assert_equal 1, response.data.messages.size
|
||
|
assert_includes response.data.messages.first.content, "Yes"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
test "streams basic chat response" do
|
||
|
VCR.use_cassette("openai/chat/basic_response") do
|
||
|
collected_chunks = []
|
||
|
|
||
|
mock_streamer = proc do |chunk|
|
||
|
collected_chunks << chunk
|
||
|
end
|
||
|
|
||
|
message = @chat.messages.create!(
|
||
|
type: "UserMessage",
|
||
|
content: "This is a chat test. If it's working, respond with a single word: Yes",
|
||
|
ai_model: @subject_model
|
||
|
)
|
||
|
|
||
|
@subject.chat_response(message, streamer: mock_streamer)
|
||
|
|
||
|
tool_call_chunks = collected_chunks.select { |chunk| chunk.type == "function_request" }
|
||
|
text_chunks = collected_chunks.select { |chunk| chunk.type == "output_text" }
|
||
|
response_chunks = collected_chunks.select { |chunk| chunk.type == "response" }
|
||
|
|
||
|
assert_equal 1, text_chunks.size
|
||
|
assert_equal 1, response_chunks.size
|
||
|
assert_equal 0, tool_call_chunks.size
|
||
|
assert_equal "Yes", text_chunks.first.data
|
||
|
assert_equal "Yes", response_chunks.first.data.messages.first.content
|
||
|
end
|
||
|
end
|
||
|
|
||
|
test "chat response with tool calls" do
|
||
|
VCR.use_cassette("openai/chat/tool_calls") do
|
||
|
response = @subject.chat_response(
|
||
|
tool_call_message,
|
||
|
instructions: "Use the tools available to you to answer the user's question.",
|
||
|
available_functions: [ PredictableToolFunction.new(@chat) ]
|
||
|
)
|
||
|
|
||
|
assert response.success?
|
||
|
assert_equal 1, response.data.functions.size
|
||
|
assert_equal 1, response.data.messages.size
|
||
|
assert_includes response.data.messages.first.content, PredictableToolFunction.expected_test_result
|
||
|
end
|
||
|
end
|
||
|
|
||
|
test "streams chat response with tool calls" do
|
||
|
VCR.use_cassette("openai/chat/tool_calls") do
|
||
|
collected_chunks = []
|
||
|
|
||
|
mock_streamer = proc do |chunk|
|
||
|
collected_chunks << chunk
|
||
|
end
|
||
|
|
||
|
@subject.chat_response(
|
||
|
tool_call_message,
|
||
|
instructions: "Use the tools available to you to answer the user's question.",
|
||
|
available_functions: [ PredictableToolFunction.new(@chat) ],
|
||
|
streamer: mock_streamer
|
||
|
)
|
||
|
|
||
|
text_chunks = collected_chunks.select { |chunk| chunk.type == "output_text" }
|
||
|
text_chunks = collected_chunks.select { |chunk| chunk.type == "output_text" }
|
||
|
tool_call_chunks = collected_chunks.select { |chunk| chunk.type == "function_request" }
|
||
|
response_chunks = collected_chunks.select { |chunk| chunk.type == "response" }
|
||
|
|
||
|
assert_equal 1, tool_call_chunks.count
|
||
|
assert text_chunks.count >= 1
|
||
|
assert_equal 1, response_chunks.count
|
||
|
|
||
|
assert_includes response_chunks.first.data.messages.first.content, PredictableToolFunction.expected_test_result
|
||
|
end
|
||
|
end
|
||
|
|
||
|
private
|
||
|
def tool_call_message
|
||
|
UserMessage.new(chat: @chat, content: "What is my net worth?", ai_model: @subject_model)
|
||
|
end
|
||
|
|
||
|
class PredictableToolFunction < Assistant::Function
|
||
|
class << self
|
||
|
def expected_test_result
|
||
|
"$124,200"
|
||
|
end
|
||
|
|
||
|
def name
|
||
|
"get_net_worth"
|
||
|
end
|
||
|
|
||
|
def description
|
||
|
"Gets user net worth data"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def call(params = {})
|
||
|
self.class.expected_test_result
|
||
|
end
|
||
|
end
|
||
|
end
|