Add Build B charm descriptors and mood replies

This commit is contained in:
Jacob Dubin
2026-05-16 08:39:45 -05:00
parent c8beb0d1f0
commit 84759f51de
14 changed files with 336 additions and 0 deletions

View File

@@ -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`

View File

@@ -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

View File

@@ -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",

View File

@@ -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`.

View File

@@ -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"
}
]
}

View File

@@ -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. <break size=\"0.3\"/> Even if I don't do it on purpose.",
"media": "TTS",
"prompt_id": "RI_JBO_IsFunny_AN_02"
}
]
}

View File

@@ -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 <pitch mult=\"1.2\">highest</pitch> priorities. <break size=\"0.4\"/>Visiting <pitch mult=\"1.1\">Mars</pitch> someday is also on my list.",
"media": "TTS",
"prompt_id": "RI_JBO_IsHelpful_AN_02"
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -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()
{

View File

@@ -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()
{