diff --git a/app/models/conversation.rb b/app/models/conversation.rb index bd6731863..5938507cb 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -1,4 +1,6 @@ class Conversation < ApplicationRecord + class InvalidStateError < StandardError; end + include Broadcastable belongs_to :user, class_name: "User" @@ -16,36 +18,31 @@ class Conversation < ApplicationRecord end def ask(question, **attributes) - raise ArgumentError, "Question cannot be blank" if question.blank? - - message = nil - with_lock do - return if thinking? - + atomically_create_message(**attributes, role: :user, content: question) do + raise(InvalidStateError, "Can't ask questions while thinking") if thinking? thinking! - message = messages.create!(**attributes, role: :user, content: question) end - - message.broadcast_create - broadcast_state_change - - message end def respond(answer, **attributes) - raise ArgumentError, "Answer cannot be blank" if answer.blank? - - message = nil - with_lock do - return unless thinking? - - message = messages.create!(**attributes, role: :assistant, content: answer) + atomically_create_message(**attributes, role: :assistant, content: answer) do + raise(InvalidStateError, "Can't respond when not thinking") unless thinking? ready! end - - message.broadcast_create - broadcast_state_change - - message end + + private + def atomically_create_message(**attributes) + message = nil + + with_lock do + yield + message = messages.create!(**attributes) + end + + message.broadcast_create + broadcast_state_change + + message + end end diff --git a/test/models/conversation_test.rb b/test/models/conversation_test.rb index 4780864dc..5691e7363 100644 --- a/test/models/conversation_test.rb +++ b/test/models/conversation_test.rb @@ -6,10 +6,17 @@ class ConversationTest < ActiveSupport::TestCase test "asking questions" do conversation = users(:kevin).conversation - assert_raises(ArgumentError) do + # You can't respond to a conversation while it's in the thinking state + assert_raises(Conversation::InvalidStateError) do + conversation.respond("Ok") + end + + assert_raises(ActiveRecord::RecordInvalid) do conversation.ask("") end + conversation.reload + assert conversation.ready?, "The conversation should be ready before a question is asked" message = nil @@ -28,10 +35,17 @@ class ConversationTest < ActiveSupport::TestCase test "responding to questions" do conversation = users(:david).conversation - assert_raises(ArgumentError) do + # You can't ask a question in a conversation that isn't ready + assert_raises(Conversation::InvalidStateError) do + conversation.ask("hi!") + end + + assert_raises(ActiveRecord::RecordInvalid) do conversation.respond("") end + conversation.reload + assert conversation.thinking?, "The conversation should be thinking before a response is made" message = nil