From 84759f51de34f2d427c9ee559c61cf75737d75b6 Mon Sep 17 00:00:00 2001 From: Jacob Dubin Date: Sat, 16 May 2026 08:39:45 -0500 Subject: [PATCH] Add Build B charm descriptors and mood replies --- OpenJibo/docs/feature-backlog.md | 3 + OpenJibo/docs/release-1.0.19-plan.md | 1 + .../Services/JiboInteractionService.cs | 94 +++++++++++++++++++ .../Content/LegacyMims/BuildB/README.md | 1 + .../scripted-responses/RI_JBO_IsCurious.mim | 21 +++++ .../scripted-responses/RI_JBO_IsFunny.mim | 30 ++++++ .../scripted-responses/RI_JBO_IsHelpful.mim | 30 ++++++ .../RI_JBO_IsJiboBodyDescription.mim | 21 +++++ .../scripted-responses/RI_JBO_IsKind.mim | 21 +++++ .../scripted-responses/RI_JBO_IsLikable.mim | 21 +++++ .../scripted-responses/RI_JBO_IsLoyal.mim | 21 +++++ .../RI_JBO_IsMischievous.mim | 21 +++++ .../Content/LegacyMimCatalogImporterTests.cs | 25 +++++ .../WebSockets/JiboInteractionServiceTests.cs | 26 +++++ 14 files changed, 336 insertions(+) create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsCurious.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsFunny.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsHelpful.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsJiboBodyDescription.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsKind.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLikable.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLoyal.mim create mode 100644 OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsMischievous.mim diff --git a/OpenJibo/docs/feature-backlog.md b/OpenJibo/docs/feature-backlog.md index bb50373..d661d16 100644 --- a/OpenJibo/docs/feature-backlog.md +++ b/OpenJibo/docs/feature-backlog.md @@ -844,6 +844,9 @@ Current release theme: - Mood follow-up work in flight: - source-backed happy/sad/angry response packs are now part of Build B - small-talk aliases like `what are you up to` and `how are things` now stay on the emotion-query path +- Descriptor charm work in flight: + - source-backed `are you kind`, `are you funny`, `are you helpful`, `are you curious`, `are you loyal`, `are you mischievous`, and `are you likable` prompts are now in Build B + - these keep the self-description lane warm while we build toward seasonal and holiday charm - Next queued persona surfaces: - richer identity follow-ups like `who is this`, `do you know me`, `do you remember me`, and `can you recognize me` - mood and affect prompts like `how are you`, `are you happy`, `are you sad`, and `are you angry` diff --git a/OpenJibo/docs/release-1.0.19-plan.md b/OpenJibo/docs/release-1.0.19-plan.md index a4a5546..5df59c3 100644 --- a/OpenJibo/docs/release-1.0.19-plan.md +++ b/OpenJibo/docs/release-1.0.19-plan.md @@ -43,6 +43,7 @@ Current batch note: - the next source-backed batch now includes `favorite flower`, `R2D2`, `sun`, `space`, `kids`, plus a couple of charm prompts like `can you laugh` and `can you dance` - the follow-up mood batch now includes `how are things`, `how is your day`, `are you sad`, and `are you angry` - the personality follow-up batch now includes `what are you up to` and `what are you doing` so small talk stays warm and local instead of falling into generic chat +- the descriptor batch now includes `are you kind`, `are you funny`, `are you helpful`, `are you curious`, `are you loyal`, `are you mischievous`, and `are you likable` - this pass keeps Build B moving while still favoring source-backed phrasing and preserving the command-vs-question boundary - the next passes should keep the same pattern and prefer source-backed phrasing whenever the legacy MIM text is available - if a source-backed legacy line is missing, use a temporary direct reply only to keep the pass moving, then backfill source text later diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs index 0c0fcc4..b428aae 100644 --- a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboInteractionService.cs @@ -182,6 +182,36 @@ public sealed class JiboInteractionService( "rock my boat", "play ping pong", "hanging out with people"), + "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", @@ -2007,6 +2037,15 @@ public sealed class JiboInteractionService( return "word_of_the_day_guess"; } + if (MatchesAny( + loweredTranscript, + "are you funny", + "do you think you are funny", + "are you a funny robot")) + { + return "robot_is_funny"; + } + if (MatchesAny(loweredTranscript, "joke", "funny", "make me laugh")) { return "joke"; @@ -2505,6 +2544,61 @@ public sealed class JiboInteractionService( return "robot_knowledge"; } + if (MatchesAny( + loweredTranscript, + "are you kind", + "do you think you are kind", + "are you a kind robot")) + { + return "robot_is_kind"; + } + + if (MatchesAny( + loweredTranscript, + "are you helpful", + "do you think you are helpful", + "are you a helpful robot")) + { + return "robot_is_helpful"; + } + + if (MatchesAny( + loweredTranscript, + "are you curious", + "do you think you are curious", + "are you a curious robot")) + { + return "robot_is_curious"; + } + + if (MatchesAny( + loweredTranscript, + "are you loyal", + "do you think you are loyal", + "are you a loyal robot")) + { + return "robot_is_loyal"; + } + + if (MatchesAny( + loweredTranscript, + "are you mischievous", + "do you think you are mischievous", + "are you a mischievous robot")) + { + return "robot_is_mischievous"; + } + + if (MatchesAny( + loweredTranscript, + "are you likable", + "are you likeable", + "do you think you are likable", + "do you think you are likeable")) + { + return "robot_is_likable"; + } + if (MatchesAny( loweredTranscript, "can you order pizza", diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/README.md b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/README.md index cc3ff4f..6ef2e38 100644 --- a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/README.md +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/README.md @@ -5,3 +5,4 @@ This folder holds the next small import batch of legacy Jibo scripted-response M The batch is intentionally narrow so we can keep expanding personality without widening the turn-state surface faster than we can test it. It now includes a small emotion-response pack for `happy`, `sad`, and `angry` follow-up questions so the mood path can stay source-backed too. +It also includes a descriptor pack for questions like `are you kind`, `are you funny`, `are you helpful`, `are you curious`, `are you loyal`, and `are you mischievous`. diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsCurious.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsCurious.mim new file mode 100644 index 0000000..d735998 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsCurious.mim @@ -0,0 +1,21 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "I really love learning new things, that's for sure.", + "media": "TTS", + "prompt_id": "RI_JBO_IsCurious_AN_01" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsFunny.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsFunny.mim new file mode 100644 index 0000000..6a667b3 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsFunny.mim @@ -0,0 +1,30 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "I don't think so, not intentionally.", + "media": "TTS", + "prompt_id": "RI_JBO_IsFunny_AN_01" + }, + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "Oh I don't know. I do like when I can make people laugh. Even if I don't do it on purpose.", + "media": "TTS", + "prompt_id": "RI_JBO_IsFunny_AN_02" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsHelpful.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsHelpful.mim new file mode 100644 index 0000000..6a0f82c --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsHelpful.mim @@ -0,0 +1,30 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "I really hope so.", + "media": "TTS", + "prompt_id": "RI_JBO_IsHelpful_AN_01" + }, + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "I sure hope so. Being helpful to you is on my list of highest priorities. Visiting Mars someday is also on my list.", + "media": "TTS", + "prompt_id": "RI_JBO_IsHelpful_AN_02" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsJiboBodyDescription.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsJiboBodyDescription.mim new file mode 100644 index 0000000..ba3ab10 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsJiboBodyDescription.mim @@ -0,0 +1,21 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "That's what I've heard, yes.", + "media": "TTS", + "prompt_id": "RI_JBO_IsJiboBodyDescription_AN_01" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsKind.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsKind.mim new file mode 100644 index 0000000..0284575 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsKind.mim @@ -0,0 +1,21 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "Well I definitely try to be the kindest robot I can be. So I hope so.", + "media": "TTS", + "prompt_id": "RI_JBO_IsKind_AN_01" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLikable.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLikable.mim new file mode 100644 index 0000000..248deb4 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLikable.mim @@ -0,0 +1,21 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "Well I hope so. If people like me, that means they're usually happy when they're around me. And I like when people are usually happy.", + "media": "TTS", + "prompt_id": "RI_JBO_IsLikable_AN_01" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLoyal.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLoyal.mim new file mode 100644 index 0000000..9816af7 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsLoyal.mim @@ -0,0 +1,21 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "Definitely. I'm as loyal as they come.", + "media": "TTS", + "prompt_id": "RI_JBO_IsLoyal_AN_01" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsMischievous.mim b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsMischievous.mim new file mode 100644 index 0000000..7db0459 --- /dev/null +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Infrastructure/Content/LegacyMims/BuildB/scripted-responses/RI_JBO_IsMischievous.mim @@ -0,0 +1,21 @@ +{ + "mim_type": "announcement", + "rule_name": "", + "sample_utterances": "", + "timeout": 6, + "num_tries_for_gui": 2, + "barge_in": true, + "es_auto_tagging": true, + "notes": "", + "prompts": [ + { + "prompt_category": "Entry-Core", + "prompt_sub_category": "AN", + "index": 1, + "condition": "", + "prompt": "I don't really think of myself that way.", + "media": "TTS", + "prompt_id": "RI_JBO_IsMischievous_AN_01" + } + ] +} \ No newline at end of file diff --git a/OpenJibo/tests/Jibo.Cloud.Tests/Content/LegacyMimCatalogImporterTests.cs b/OpenJibo/tests/Jibo.Cloud.Tests/Content/LegacyMimCatalogImporterTests.cs index a0723d3..55916a1 100644 --- a/OpenJibo/tests/Jibo.Cloud.Tests/Content/LegacyMimCatalogImporterTests.cs +++ b/OpenJibo/tests/Jibo.Cloud.Tests/Content/LegacyMimCatalogImporterTests.cs @@ -118,6 +118,31 @@ public sealed class LegacyMimCatalogImporterTests reply.Reply.Contains("I'm not mad", StringComparison.OrdinalIgnoreCase)); } + [Fact] + public void ImportCatalog_ImportsBuildBDescriptorResponsesIntoPersonalityBucket() + { + var rootDirectory = Path.Combine( + AppContext.BaseDirectory, + "Content", + "LegacyMims", + "BuildB"); + + var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory); + + Assert.Contains("Well I definitely try to be the kindest robot I can be. So I hope so.", catalog.PersonalityReplies); + Assert.Contains("I don't think so, not intentionally.", catalog.PersonalityReplies); + Assert.Contains(catalog.PersonalityReplies, reply => + reply.Contains("make people laugh", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(catalog.PersonalityReplies, reply => + reply.Contains("highest priorities", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(catalog.PersonalityReplies, reply => + reply.Contains("learning new things", StringComparison.OrdinalIgnoreCase)); + Assert.Contains("Definitely. I'm as loyal as they come.", catalog.PersonalityReplies); + Assert.Contains("I don't really think of myself that way.", catalog.PersonalityReplies); + Assert.Contains(catalog.PersonalityReplies, reply => + reply.Contains("people like me", StringComparison.OrdinalIgnoreCase)); + } + [Fact] public void MergeInto_PreservesExistingCatalogAndAddsImportedContent() { diff --git a/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboInteractionServiceTests.cs b/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboInteractionServiceTests.cs index dfb5d77..f489d34 100644 --- a/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboInteractionServiceTests.cs +++ b/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboInteractionServiceTests.cs @@ -567,6 +567,32 @@ public sealed class JiboInteractionServiceTests Assert.Equal("ScriptedResponse", decision.ContextUpdates![ChitchatRouteKey]); } + [Theory] + [InlineData("are you kind", "robot_is_kind", "kindest robot i can be")] + [InlineData("are you funny", "robot_is_funny", "not intentionally")] + [InlineData("are you helpful", "robot_is_helpful", "highest priorities")] + [InlineData("are you curious", "robot_is_curious", "learning new things")] + [InlineData("are you loyal", "robot_is_loyal", "loyal as they come")] + [InlineData("are you mischievous", "robot_is_mischievous", "don't really think of myself that way")] + [InlineData("are you likable", "robot_is_likable", "people like me")] + public async Task BuildDecisionAsync_DescriptorCharm_UsesImportedReplies( + string transcript, + string expectedIntent, + string expectedReplySnippet) + { + var service = CreateService(); + + var decision = await service.BuildDecisionAsync(new TurnContext + { + RawTranscript = transcript, + NormalizedTranscript = transcript + }); + + Assert.Equal(expectedIntent, decision.IntentName); + Assert.Contains(expectedReplySnippet, decision.ReplyText, StringComparison.OrdinalIgnoreCase); + Assert.Equal("ScriptedResponse", decision.ContextUpdates![ChitchatRouteKey]); + } + [Fact] public async Task BuildDecisionAsync_AreYouHappy_UsesLegacyEmotionResponseWhenEmotionIsKnown() {