diff --git a/src/xyz/didx/ai/AiHandler.scala b/src/xyz/didx/ai/AiHandler.scala index 1e71245..cfdc494 100644 --- a/src/xyz/didx/ai/AiHandler.scala +++ b/src/xyz/didx/ai/AiHandler.scala @@ -32,19 +32,25 @@ object AiHandler { case ChatState.Onboarding => IO(Try { val result: OnboardingResult = OnboardingHandler.getResponse(input, conversationId, telNo) + scribe.info( + s"Got response from OnboardingHandler::getResponse, for conversationId: $conversationId" + ) val (messageToUser, nextState) = result match { case OnboardingResult(_, Some(fullName), Some(email), Some(cellphone)) => - // Results are records. Store in onboardingResults Map, and move to confirmation state - onboardingResults.update(conversationId, result) + scribe.info( + s"Recorded onboarding result for conversationId: $conversationId" + ) + + onboardingResults.update(conversationId, result) // Store in onboardingResults Map - val response = "Thank you. Please confirm if the following recorded data is correct:\n\n" + - s"Name: ${result.fullName.getOrElse("None")}\n" + - s"Email: ${result.email.getOrElse("None")}\n" + - s"Cellphone: ${result.cellphone.getOrElse("None")}" + val response = ConfirmOnboardingHandler.getConfirmationMessage(result) - (response, ChatState.ConfirmOnboardingResult) + (response, ChatState.ConfirmOnboardingResult) // move to confirmation state - case OnboardingResult(_, _, _, _) => // In case data is not yet fully captured, remain in same state + case OnboardingResult(_, _, _, _) => + scribe.info( + s"Data is not yet fully captured, remain in same state for conversationId: $conversationId" + ) (result.nextMessageToUser, state) } (messageToUser, nextState) @@ -56,9 +62,12 @@ object AiHandler { onboardingResultOpt match case None => ("Something went wrong retrieving recorded results. Let's try again!", ChatState.Onboarding) case Some(onboardingResult) => - val confirmationResult = ConfirmOnboardingHandler.getConfirmation(input, onboardingResult, conversationId) - confirmationResult.confirmed match - case None => (confirmationResult.nextMessageToUser, state) + val confirmationResult = ConfirmOnboardingHandler.getConfirmation(input, conversationId) + confirmationResult.userHasConfirmedOptionalBool match + case None => ( + ConfirmOnboardingHandler.getReconfirmationMessage(onboardingResult), + ChatState.ConfirmOnboardingResult + ) case Some(true) => ( "Great, you are now ready to query the available Yoma opportunities! What would you like to do?", ChatState.QueryingOpportunities diff --git a/src/xyz/didx/ai/handler/ConfirmOnboardingResult.scala b/src/xyz/didx/ai/handler/ConfirmOnboardingResult.scala index 60939eb..9b74e9d 100644 --- a/src/xyz/didx/ai/handler/ConfirmOnboardingResult.scala +++ b/src/xyz/didx/ai/handler/ConfirmOnboardingResult.scala @@ -10,22 +10,16 @@ import xyz.didx.ai.model.OnboardingResult import xyz.didx.ai.model.AgentScript object ConfirmOnboardingHandler { - // Define a map from conversationId to JvmPromptBuilder - private val builders: mutable.Map[String, PromptBuilder] = mutable.Map() - def getConfirmation( input: String, - onboardingResult: OnboardingResult, conversationId: String ): ConfirmedOnboardingResult = { scribe.info( s"Get ConfirmOnboardingResult response for message: $input, for conversationId: $conversationId" ) - // Get the builder for this conversationId, or create a new one if it doesn't exist - val builder = builders.getOrElseUpdate( - conversationId, - AgentScript.createConfirmationBuilder(onboardingResult) - ) + + // Get the prompt builder for this script + val builder = AgentScript.createConfirmationBuilder() // Add the user message to the builder builder.addUserMessage(input) @@ -40,4 +34,18 @@ object ConfirmOnboardingHandler { conversationId = Some(ConversationId(conversationId)) ) } + + def getConfirmationMessage(result: OnboardingResult): String = + "Thank you. Please confirm if the following recorded data is correct:\n\n" + + s"Name: ${result.fullName.getOrElse("None")}\n" + + s"Email: ${result.email.getOrElse("None")}\n" + + s"Cellphone: ${result.cellphone.getOrElse("None")}" + + def getReconfirmationMessage(result: OnboardingResult): String = + "Apologies, we couldn't infer if you confirmed or not. " + + "Please indicate \"yes\" or \"no\" if the following is correct:\n\n" + + s"Name: ${result.fullName.getOrElse("None")}\n" + + s"Email: ${result.email.getOrElse("None")}\n" + + s"Cellphone: ${result.cellphone.getOrElse("None")}" + } diff --git a/src/xyz/didx/ai/model/AgentScript.scala b/src/xyz/didx/ai/model/AgentScript.scala index 010f442..209e8b1 100644 --- a/src/xyz/didx/ai/model/AgentScript.scala +++ b/src/xyz/didx/ai/model/AgentScript.scala @@ -16,27 +16,21 @@ object AgentScript { "Name; Email; Cellphone. " } - val endMessage = "When receiving your first message from a user, begin asking for the info you still need. " + - "They can give one attribute at a time, or all at once. " + - "If a user has already given their name, email or cellphone in the chat, or if you already know it, then you shouldn't ask them again." + - "Be friendly." + val endMessage = "Prompt the user until you have the required info. " + + "If a user has already given their name, email or cellphone in the chat, then you shouldn't ask them again. " + + "Be friendly. When receiving a first message from a user, ask for the info you still need." val fullMessage = s"$baseMessage $conditionalMessage $endMessage" new JvmPromptBuilder().addSystemMessage(fullMessage) } - def createConfirmationBuilder(onboardingResult: OnboardingResult): PromptBuilder = { + def createConfirmationBuilder(): PromptBuilder = { val baseMessage = - "You are Yoma, an onboarding assistant! " + - "Your job is to receive confirmation from the user, whether the data we've recorded for that user is correct. " + - "We have the following data for them:\n" + - s"Name: ${onboardingResult.fullName.getOrElse("None")}\n" + - s"Email: ${onboardingResult.email.getOrElse("None")}\n" + - s"Cellphone: ${onboardingResult.cellphone.getOrElse("None")}\n" + - "Send this recorded data to the user, and ask them to please confirm if it's correct or not. " + - "They might respond with something like yes, indeed, correct, of course, :+1+, a thumbs up emoji, or other slang like shap - all of this would confirm their data (confirmed = True) " + - "If they respond with something like no, not correct, incorrect, of course not, :-1+, a thumbs down emoji, or other slang like wtf - all of this would confirm their data is incorrect (confirmed = False)" + - "If they give an unclear, blank, neutral or irrelevant response, we'll consider this to be confirmed = None, in which case you will kindly prompt them again!" + "Your job is to receive confirmation from the user - whether the data we've recorded is correct or not. " + + "They might respond with: yes, indeed, correct, of course, :+1+, a thumbs up emoji, slang like shap, or other general confirmation - all of this would confirm their data (confirmed = True). " + + "If they respond with: no, not correct, incorrect, of course not, :-1+, a thumbs down emoji, slang like wtf, or other general rejection - all of this would confirm their data is incorrect (confirmed = False). " + + "If they give an unclear, blank, neutral or irrelevant response, we'll consider this to be confirmed = None. " + + "Process their response and provide us with an Optional[Boolean]. confirmed = True, False, or None. " new JvmPromptBuilder().addSystemMessage(baseMessage) } diff --git a/src/xyz/didx/ai/model/ChatResult.scala b/src/xyz/didx/ai/model/ChatResult.scala index 468a5b6..a737b4a 100644 --- a/src/xyz/didx/ai/model/ChatResult.scala +++ b/src/xyz/didx/ai/model/ChatResult.scala @@ -13,6 +13,8 @@ case class OnboardingResult( case class ConfirmedOnboardingResult( @Description("The next message that you want to send to the user") nextMessageToUser: String, - @Description("User has confirmed that the recorded data is correct") confirmed: Option[Boolean] = None + @Description( + "True, False, or None, to indicate whether user has confirmed or not" + ) userHasConfirmedOptionalBool: Option[Boolean] = None ) derives SerialDescriptor, Decoder