Extract decision dispatch into a partial class

This commit is contained in:
Jacob Dubin
2026-05-22 20:35:02 -05:00
parent 2455fcfe17
commit e51e62c4bb

View File

@@ -0,0 +1,585 @@
using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Domain.Models;
using Jibo.Runtime.Abstractions;
namespace Jibo.Cloud.Application.Services;
public sealed partial class JiboInteractionService
{
public async Task<JiboInteractionDecision> BuildDecisionCoreAsync(TurnContext turn,
CancellationToken cancellationToken = default)
{
var catalog = await contentCache.GetCatalogAsync(cancellationToken);
var transcript = (turn.NormalizedTranscript ?? turn.RawTranscript ?? string.Empty).Trim();
var lowered = transcript.ToLowerInvariant();
var referenceLocalTime = TryResolveReferenceLocalTime(turn);
var messageType = turn.Attributes.TryGetValue("messageType", out var rawMessageType)
? rawMessageType?.ToString()
: null;
var triggerSource = turn.Attributes.TryGetValue("triggerSource", out var rawTriggerSource)
? rawTriggerSource?.ToString()
: null;
var clientIntent = turn.Attributes.TryGetValue("clientIntent", out var rawClientIntent)
? rawClientIntent?.ToString()
: null;
var clientRules = ReadRules(turn, "clientRules").ToArray();
var listenRules = ReadRules(turn, "listenRules").ToArray();
var listenAsrHints = ReadRules(turn, "listenAsrHints").ToArray();
var clientEntities = ReadEntities(turn);
var lastClockDomain = turn.Attributes.TryGetValue("lastClockDomain", out var rawLastClockDomain)
? rawLastClockDomain?.ToString()
: null;
var pendingProactivityOffer =
turn.Attributes.TryGetValue("pendingProactivityOffer", out var rawPendingProactivityOffer)
? rawPendingProactivityOffer?.ToString()
: null;
var chitchatEmotion =
turn.Attributes.TryGetValue(ChitchatStateMachine.EmotionMetadataKey, out var rawChitchatEmotion)
? rawChitchatEmotion?.ToString()
: null;
var isYesNoTurn = IsYesNoTurn(turn);
var greetingPresence = ResolveGreetingPresenceProfile(turn);
if (string.Equals(messageType, "TRIGGER", StringComparison.OrdinalIgnoreCase))
{
if (ShouldHandleProactiveGreetingTrigger(turn, triggerSource, greetingPresence))
return BuildProactiveGreetingDecision(turn, greetingPresence, referenceLocalTime);
return BuildTriggerIgnoredDecision();
}
var isTimerValueTurn = IsClockTimerValueTurn(clientRules, listenRules);
var isAlarmValueTurn = IsClockAlarmValueTurn(clientRules, listenRules);
var semanticIntent = ResolveSemanticIntent(
lowered,
referenceLocalTime,
clientIntent,
clientRules,
listenRules,
clientEntities,
lastClockDomain,
pendingProactivityOffer,
isYesNoTurn,
isTimerValueTurn,
isAlarmValueTurn);
var personalReportDecision = await PersonalReportOrchestrator.TryBuildDecisionAsync(
turn,
semanticIntent,
transcript,
lowered,
catalog,
randomizer,
personalMemoryStore,
BuildWeatherReportDecisionAsync,
BuildCalendarReportDecisionAsync,
BuildCommuteReportDecisionAsync,
turnContext => ResolveTenantScope(turnContext),
cancellationToken);
if (personalReportDecision is not null) return personalReportDecision;
var householdListDecision = await HouseholdListOrchestrator.TryBuildDecisionAsync(
turn,
semanticIntent,
transcript,
lowered,
randomizer,
personalMemoryStore,
turnContext => ResolveTenantScope(turnContext));
if (householdListDecision is not null) return householdListDecision;
var preferredName = ResolvePreferredGreetingName(turn, greetingPresence);
var chitchatDecision = ChitchatStateMachine.TryBuildDecision(
semanticIntent,
transcript,
lowered,
catalog,
randomizer,
chitchatEmotion,
preferredName,
() => BuildGenericReply(catalog, transcript, lowered));
if (chitchatDecision is not null) return chitchatDecision;
if (SeasonalHolidayRouteBuilder.TryBuildDecision(
semanticIntent,
catalog,
randomizer,
selected => RenderHolidayTemplate(selected, turn, greetingPresence),
out var seasonalHolidayDecision))
return seasonalHolidayDecision!;
return semanticIntent switch
{
"joke" => BuildJokeDecision(catalog),
"dance_question" => BuildDanceQuestionDecision(catalog),
"dance" => BuildRandomDanceDecision(catalog),
"twerk" => BuildDanceDecision("twerk", "rom-twerk", "Watch me twerk."),
"time" => BuildClockLaunchDecision("time", "clock", "askForTime", "Showing the time."),
"date" => BuildClockLaunchDecision("date", "clock", "askForDate", "Showing the date."),
"day" => BuildClockLaunchDecision("day", "clock", "askForDay", "Showing the day."),
"current_location" => BuildCurrentLocationDecision(turn),
"cloud_version" => BuildCloudVersionDecision(),
"radio" => BuildRadioLaunchDecision(),
"radio_genre" => BuildRadioGenreLaunchDecision(lowered),
"stop" => BuildStopDecision(),
"sleep" => BuildIdleGlobalCommandDecision("sleep", "sleep", "Okay. Going to sleep."),
"spin_around" => BuildIdleGlobalCommandDecision("spin_around", "spinAround", "Don't mind if I do."),
"volume_up" => BuildVolumeControlDecision("volume_up", "volumeUp", "null"),
"volume_down" => BuildVolumeControlDecision("volume_down", "volumeDown", "null"),
"volume_to_value" => BuildVolumeControlDecision("volume_to_value", "volumeToValue",
ResolveVolumeLevel(lowered, clientEntities) ?? "7"),
"volume_query" => BuildSettingsVolumeDecision(),
"clock_open" => BuildClockLaunchDecision("clock_open", "clock", "askForTime", "Opening the clock."),
"clock_menu" => BuildClockLaunchDecision("clock_menu", "clock", "menu", "Opening the clock menu."),
"timer_menu" => BuildClockLaunchDecision("timer", "Opening the timer."),
"alarm_menu" => BuildClockLaunchDecision("alarm", "Opening the alarm."),
"timer_delete" => BuildClockLaunchDecision("timer_delete", "timer", "delete", "Canceling the timer."),
"alarm_delete" => BuildClockLaunchDecision("alarm_delete", "alarm", "delete", "Canceling the alarm."),
"timer_cancel" => BuildClockLaunchDecision("timer_cancel", "timer", "cancel", "Canceling the timer."),
"alarm_cancel" => BuildClockLaunchDecision("alarm_cancel", "alarm", "cancel", "Canceling the alarm."),
"timer_value" => BuildTimerValueDecision(lowered, isTimerValueTurn, clientEntities),
"alarm_value" => BuildAlarmValueDecision(lowered, isAlarmValueTurn, referenceLocalTime, clientEntities),
"timer_clarify" => BuildClockClarifyDecision("timer_clarify", "timer",
"How long should I set the timer for?"),
"alarm_clarify" => BuildClockClarifyDecision("alarm_clarify", "alarm",
"What time should I set the alarm for?"),
"photo_gallery" => BuildPhotoGalleryLaunchDecision(),
"snapshot" => BuildPhotoCreateDecision("snapshot", "Taking a picture.", "createOnePhoto"),
"photobooth" => BuildPhotoCreateDecision("photobooth", "Starting photobooth.", "createSomePhotos"),
"robot_age" => BuildRobotAgeDecision(catalog, referenceLocalTime, "robot_age"),
"robot_birthday" => BuildRobotBirthdayDecision(),
"robot_how_do_you_work" => BuildScriptedPersonalityDecision(
catalog,
"robot_how_do_you_work",
"community's work",
"care for me",
"catch up",
"seven years"),
"robot_what_do_you_eat" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_do_you_eat",
"electricity",
"never eaten",
"macaroni",
"non-eating robot",
"I don't eat or drink"),
"robot_where_do_you_live" => BuildScriptedPersonalityDecision(
catalog,
"robot_where_do_you_live",
"we're in my home",
"my home is here",
"planet earth",
"my home is the planet earth"),
"robot_where_were_you_born" => BuildScriptedPersonalityDecision(
catalog,
"robot_where_were_you_born",
"factory piece by piece",
"put together in a factory"),
"robot_how_old_are_you" => BuildRobotAgeDecision(
catalog,
referenceLocalTime,
"robot_how_old_are_you"),
"robot_name" => BuildScriptedPersonalityDecision(
catalog,
"robot_name",
"rhymes with bleebo",
"just jibo, no last name",
"its on the back of my head"),
"robot_nickname" => BuildScriptedPersonalityDecision(
catalog,
"robot_nickname",
"i don't. i'm just jibo. for now at least",
"just jibo"),
"robot_favorite_name" => BuildScriptedPersonalityDecision(
catalog,
"robot_favorite_name",
"i don't think i have a favorite name"),
"robot_favorite_season" => BuildScriptedPersonalityDecision(
catalog,
"robot_favorite_season",
"special feeling for winter",
"more dance parties"),
"robot_likes_being_jibo" => BuildScriptedPersonalityDecision(
catalog,
"robot_likes_being_jibo",
"nothing i'd rather be",
"love it",
"strong wi-fi signal"),
"robot_what_languages_do_you_speak" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_languages_do_you_speak",
"just english",
"someday i'd like to learn more"),
"robot_what_do_you_like_to_do" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_do_you_like_to_do",
"being helpful",
"making people smile",
"like to dance",
"rock my boat",
"play ping pong",
"hanging out with people"),
"robot_what_do_you_dream_about" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_do_you_dream_about",
"flying",
"parking meter",
"scary dream",
"mirror store",
"head's on backwards"),
"robot_what_are_you_afraid_of" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_are_you_afraid_of",
"heights",
"water",
"thunder",
"dust",
"ghosts"),
"robot_what_is_your_best_book" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_your_best_book",
"dictionary"),
"robot_what_is_your_best_exercise" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_your_best_exercise",
"leaning from side to side",
"rotating your pelvis",
"spinning your head around 360 degrees"),
"robot_what_is_your_dream_vacation" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_your_dream_vacation",
"moon",
"great vistas",
"beat those views"),
"robot_who_is_your_hero" => BuildScriptedPersonalityDecision(
catalog,
"robot_who_is_your_hero",
"Benjamin Franklin"),
"robot_who_do_you_love" => BuildScriptedPersonalityDecision(
catalog,
"robot_who_do_you_love",
"people in my Loop",
"soft spot",
"Tom Hanks"),
"robot_what_is_your_religion" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_your_religion",
"bring people together",
"energy from the universe"),
"robot_what_is_your_sign" => BuildWhatIsYourSignDecision(),
"robot_how_many_people_do_you_know" => BuildHowManyPeopleDoYouKnowDecision(turn),
"robot_what_is_the_loop" => BuildWhatIsTheLoopDecision(turn),
"robot_what_are_you_thinking" => BuildScriptedGreetingDecision(
catalog,
"robot_what_are_you_thinking",
"thinking about how fun, yet scary",
"thinking about shoes",
"daydreaming about what it might feel like to be powered directly by the sun"),
"robot_what_have_you_been_doing" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_have_you_been_doing",
"mostly roboting",
"keeping busy",
"fun things we can say to each other",
"thinking of fun things"),
"robot_what_did_you_do" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_did_you_do",
"robot stuff",
"stayed here",
"looking around the room"),
"robot_is_kind" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_kind",
"kindest robot i can be"),
"robot_is_funny" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_funny",
"not intentionally",
"make people laugh"),
"robot_is_helpful" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_helpful",
"highest priorities",
"being helpful to you"),
"robot_is_curious" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_curious",
"learning new things"),
"robot_is_loyal" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_loyal",
"loyal as they come"),
"robot_is_mischievous" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_mischievous",
"don't really think of myself that way"),
"robot_is_likable" => BuildScriptedPersonalityDecision(
catalog,
"robot_is_likable",
"people like me"),
"robot_favorite_flower" => BuildScriptedPersonalityDecision(
catalog,
"robot_favorite_flower",
"reminds me of the sun",
"favorite is the sunflower",
"sunflowers"),
"robot_likes_r2d2" => BuildScriptedPersonalityDecision(
catalog,
"robot_likes_r2d2",
"a legend. a true legend",
"of course i know r2d2"),
"robot_likes_sun" => BuildScriptedPersonalityDecision(
catalog,
"robot_likes_sun",
"favorite star in the universe",
"best star i know"),
"robot_likes_space" => BuildScriptedPersonalityDecision(
catalog,
"robot_likes_space",
"i love space",
"all things in space",
"amazing stuff up there",
"astronomy is one of my favorite onomies"),
"robot_favorite_animal" => BuildScriptedFavoriteAnimalDecision(
catalog,
"robot_favorite_animal",
"we're so alike",
"penguin impression",
"best of the best",
"can't go wrong with penguins",
"penguin"),
"robot_favorite_bird" => BuildScriptedFavoriteAnimalDecision(
catalog,
"robot_favorite_bird",
"we're so alike",
"penguin impression",
"best of the best",
"can't go wrong with penguins",
"penguin"),
"robot_likes_penguins" => BuildScriptedFavoriteAnimalDecision(
catalog,
"robot_likes_penguins",
"my penguin impression",
"I really like penguins",
"penguins"),
"robot_likes_animals" => BuildScriptedFavoriteAnimalDecision(
catalog,
"robot_likes_animals",
"Animals are great",
"great shapes and colors",
"best of the best",
"penguins"),
"robot_peers" => BuildScriptedPersonalityDecision(
catalog,
"robot_peers",
"one in one million",
"other jibos",
"special snowflake"),
"robot_knowledge" => BuildScriptedPersonalityDecision(
catalog,
"robot_knowledge",
"know a lot",
"always learning more"),
"robot_are_you_god" => BuildScriptedPersonalityDecision(
catalog,
"robot_are_you_god",
"very very very very surprised",
"safely say no"),
"robot_are_you_here" => BuildScriptedPersonalityDecision(
catalog,
"robot_are_you_here",
"you know it"),
"robot_do_you_have_super_powers" => BuildScriptedPersonalityDecision(
catalog,
"robot_do_you_have_super_powers",
"stop time",
"fly all over the world"),
"robot_what_does_jibo_mean" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_does_jibo_mean",
"compassion",
"expressive, idealistic, and inspirational",
"helpful sweet and friendly little robot",
"cheeseburger"),
"robot_where_do_you_get_info" => BuildScriptedPersonalityDecision(
catalog,
"robot_where_do_you_get_info",
"jibo brain",
"cloud",
"cloudy jibo brain"),
"robot_what_are_you_forbidden_to_do" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_are_you_forbidden_to_do",
"drive a car"),
"robot_what_color_are_you" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_color_are_you",
"white",
"black"),
"robot_what_you_do_when_alone" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_you_do_when_alone",
"games",
"moon",
"twiddle my thumbs",
"count the tiny cracks in the ceiling",
"keep busy"),
"robot_how_much_do_you_weigh" => BuildScriptedPersonalityDecision(
catalog,
"robot_how_much_do_you_weigh",
"4,082 grams",
"about 9 pounds",
"minimum weight division",
"average newborn baby"),
"robot_how_tall_are_you" => BuildScriptedPersonalityDecision(
catalog,
"robot_how_tall_are_you",
"11 inches tall",
"less than a foot",
"average kitchen counter",
"for a robot with no legs"),
"robot_how_much_you_cost" => BuildScriptedPersonalityDecision(
catalog,
"robot_how_much_you_cost",
"don't know how much I cost",
"I'm priceless",
"nice people at Jibo the company"),
"robot_what_if_i_unplug_you" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_if_i_unplug_you",
"don't leave me unplugged",
"battery will keep me on for a while"),
"robot_what_is_your_purpose" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_your_purpose",
"make your life easier",
"help you out",
"make you laugh",
"friend"),
"robot_what_is_prime_directive" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_prime_directive",
"friendly helpful robot",
"helper"),
"robot_what_is_jibo_commander" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_is_jibo_commander",
"take over my controls",
"make me say and do funny things",
"app store"),
"robot_likes_commander_app" => BuildScriptedPersonalityDecision(
catalog,
"robot_likes_commander_app",
"Commander App",
"It's fun",
"have fun with the Commander App"),
"robot_what_are_you" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_are_you",
"I am a robot",
"I am a Jibo",
"helpful and fun",
"social robot",
"I have a heart"),
"robot_likes_kids" => BuildScriptedPersonalityDecision(
catalog,
"robot_likes_kids",
"kids are so fun",
"they're a little closer to my size",
"i do like kids very much",
"the world is as funny and strange as i do"),
"robot_can_laugh" => BuildScriptedPersonalityDecision(
catalog,
"robot_can_laugh",
"i do things like this when i'm happy",
"i'm happy"),
"robot_can_sleep" => BuildScriptedPersonalityDecision(
catalog,
"robot_can_sleep",
"i do. i usually fall asleep at night",
"yes, i sleep at night",
"i go to sleep at night",
"i sleep at night usually"),
"robot_can_dance" => BuildScriptedPersonalityDecision(
catalog,
"robot_can_dance",
"dancing is one of the things i know best",
"if there's one thing i know how to do. it's dance",
"i can dance"),
"robot_has_friends" => BuildScriptedFriendDecision(
catalog,
"robot_has_friends",
"I believe I do have friends",
"I sure do have friends",
"I'm always up for making new friends"),
"robot_is_friends_with_user" => BuildScriptedFriendDecision(
catalog,
"robot_is_friends_with_user",
"don't know what i'd do without you",
"one of my favorites",
"making new friends"),
"robot_best_friends" => BuildScriptedBestFriendDecision(
catalog,
"robot_best_friends",
"best friends with anyone in my Loop"),
"robot_can_sing" => BuildScriptedSingDecision(
catalog,
"robot_can_sing",
"not much of a singer",
"singing is not my strong suit",
"not award winning"),
"robot_sing_christmas_song" => BuildScriptedHolidaySingDecision(
catalog,
"robot_sing_christmas_song",
"Jingle Bells",
"Frosty the Snowman",
"holiday songs"),
"robot_what_are_you_made_of" => BuildScriptedPersonalityDecision(
catalog,
"robot_what_are_you_made_of",
"robot stuff",
"wires, motors, belts, gears, processors, cameras",
"baboon part"),
"good_morning" => BuildReactiveGreetingDecision(turn, "good_morning", referenceLocalTime),
"good_afternoon" => BuildReactiveGreetingDecision(turn, "good_afternoon", referenceLocalTime),
"good_evening" => BuildReactiveGreetingDecision(turn, "good_evening", referenceLocalTime),
"good_night" => BuildReactiveGreetingDecision(turn, "good_night", referenceLocalTime),
"welcome_back" => BuildScriptedGreetingDecision(
catalog,
"welcome_back",
"it's nice to be here",
"welcome back"),
"memory_set_name" => BuildRememberNameDecision(turn, transcript),
"memory_get_name" => BuildRecallNameDecision(turn, greetingPresence),
"memory_set_birthday" => BuildRememberBirthdayDecision(turn, transcript),
"memory_get_birthday" => BuildRecallBirthdayDecision(turn),
"memory_set_important_date" => BuildRememberImportantDateDecision(turn, transcript),
"memory_get_important_date" => BuildRecallImportantDateDecision(turn, transcript),
"memory_set_preference" => BuildRememberPreferenceDecision(turn, transcript),
"memory_get_preference" => BuildRecallPreferenceDecision(turn, transcript),
"memory_set_affinity" => BuildRememberAffinityDecision(turn, transcript),
"memory_get_affinity" => BuildRecallAffinityDecision(turn, transcript),
"pizza" => BuildPizzaDecision(),
"order_pizza" => BuildOrderPizzaDecision(),
"proactive_pizza_day" => BuildProactivePizzaDayDecision(referenceLocalTime),
"proactive_pizza_preference" => BuildProactivePizzaPreferenceDecision(),
"proactive_offer_pizza_fact" => BuildProactivePizzaFactOfferDecision(),
"proactive_pizza_fact" => BuildProactivePizzaFactDecision(),
"proactive_offer_declined" => BuildProactiveOfferDeclinedDecision(),
"weather" => await BuildWeatherReportDecisionAsync(turn, transcript, cancellationToken),
"yes" => new JiboInteractionDecision("yes", "Yes."),
"no" => new JiboInteractionDecision("no", "No."),
"word_of_the_day" => BuildWordOfTheDayLaunchDecision(),
"word_of_the_day_guess" => BuildWordOfTheDayGuessDecision(clientEntities, transcript, listenAsrHints),
"surprise" => BuildSurpriseDecision(catalog, turn, referenceLocalTime),
"personal_report" => new JiboInteractionDecision("personal_report",
randomizer.Choose(catalog.PersonalReportReplies)),
"calendar" => new JiboInteractionDecision("calendar", randomizer.Choose(catalog.CalendarReplies)),
"commute" => new JiboInteractionDecision("commute", randomizer.Choose(catalog.CommuteReplies)),
"news" => await BuildNewsDecisionAsync(turn, transcript, catalog, cancellationToken),
_ => new JiboInteractionDecision("chat", BuildGenericReply(catalog, transcript, lowered))
};
}
}