Add pizza yes-no wiring and Pegasus parser guardrails

This commit is contained in:
Jacob Dubin
2026-05-06 16:49:26 -05:00
parent c64f4b91a8
commit a5de0fdbdd
9 changed files with 364 additions and 27 deletions

View File

@@ -2102,18 +2102,7 @@ public sealed class JiboInteractionService(
{
var normalized = NormalizeCommandPhrase(transcript);
var directMappings = new (string Prefix, PersonalAffinity Affinity)[]
{
("i love ", PersonalAffinity.Love),
("i like ", PersonalAffinity.Like),
("i dislike ", PersonalAffinity.Dislike),
("i hate ", PersonalAffinity.Dislike),
("i don t like ", PersonalAffinity.Dislike),
("i dont like ", PersonalAffinity.Dislike),
("i do not like ", PersonalAffinity.Dislike)
};
foreach (var (prefix, affinity) in directMappings)
foreach (var (prefix, affinity) in PegasusUserAffinitySetPrefixes)
{
if (!normalized.StartsWith(prefix, StringComparison.Ordinal))
{
@@ -2133,17 +2122,8 @@ public sealed class JiboInteractionService(
private static (string Item, PersonalAffinity? ExpectedAffinity)? TryExtractAffinityLookup(string transcript)
{
var normalized = NormalizeCommandPhrase(transcript);
var expectationPrefixes = new (string Prefix, PersonalAffinity? ExpectedAffinity)[]
{
("do i love ", PersonalAffinity.Love),
("do i like ", PersonalAffinity.Like),
("do i dislike ", PersonalAffinity.Dislike),
("do i hate ", PersonalAffinity.Dislike),
("how do i feel about ", null),
("what do i think about ", null)
};
foreach (var (prefix, expectedAffinity) in expectationPrefixes)
foreach (var (prefix, expectedAffinity) in PegasusUserAffinityLookupPrefixes)
{
if (!normalized.StartsWith(prefix, StringComparison.Ordinal))
{
@@ -2826,7 +2806,47 @@ public sealed class JiboInteractionService(
private static readonly string[] PreferenceReverseMarkers =
[
" is my favorite ",
" is my favourite "
" is my favourite ",
" are my favorite ",
" are my favourite "
];
// Directly imported from Pegasus parser intent phrase families:
// userLikesThing / userDislikesThing / doesUserLikeThing / doesUserDislikeThing.
private static readonly (string Prefix, PersonalAffinity Affinity)[] PegasusUserAffinitySetPrefixes =
[
("i love ", PersonalAffinity.Love),
("i like ", PersonalAffinity.Like),
("i enjoy ", PersonalAffinity.Like),
("i do like ", PersonalAffinity.Like),
("i dislike ", PersonalAffinity.Dislike),
("i hate ", PersonalAffinity.Dislike),
("i don t like ", PersonalAffinity.Dislike),
("i dont like ", PersonalAffinity.Dislike),
("i do not like ", PersonalAffinity.Dislike),
("i don t enjoy ", PersonalAffinity.Dislike),
("i dont enjoy ", PersonalAffinity.Dislike),
("i do not enjoy ", PersonalAffinity.Dislike),
("i don t love ", PersonalAffinity.Dislike),
("i dont love ", PersonalAffinity.Dislike),
("i do not love ", PersonalAffinity.Dislike),
("i can t stand ", PersonalAffinity.Dislike),
("i cant stand ", PersonalAffinity.Dislike),
("i despise ", PersonalAffinity.Dislike),
("i detest ", PersonalAffinity.Dislike)
];
private static readonly (string Prefix, PersonalAffinity? ExpectedAffinity)[] PegasusUserAffinityLookupPrefixes =
[
("do i love ", PersonalAffinity.Love),
("do i like ", PersonalAffinity.Like),
("do i enjoy ", PersonalAffinity.Like),
("do i dislike ", PersonalAffinity.Dislike),
("do i hate ", PersonalAffinity.Dislike),
("do i despise ", PersonalAffinity.Dislike),
("do i detest ", PersonalAffinity.Dislike),
("how do i feel about ", null),
("what do i think about ", null)
];
private static readonly string[] PizzaPreferenceCategories =

View File

@@ -31,6 +31,7 @@ public sealed class ResponsePlanToSocketMessagesMapper
var isVolumeControl = string.Equals(plan.IntentName, "volume_up", StringComparison.OrdinalIgnoreCase) ||
string.Equals(plan.IntentName, "volume_down", StringComparison.OrdinalIgnoreCase) ||
string.Equals(plan.IntentName, "volume_to_value", StringComparison.OrdinalIgnoreCase);
var isProactivePizzaFactOffer = string.Equals(plan.IntentName, "proactive_offer_pizza_fact", StringComparison.OrdinalIgnoreCase);
var isSettingsLaunch = string.Equals(skill?.SkillName, "@be/settings", StringComparison.OrdinalIgnoreCase);
var isGlobalCommand = isStopCommand || isVolumeControl;
var isPhotoGalleryLaunch = string.Equals(plan.IntentName, "photo_gallery", StringComparison.OrdinalIgnoreCase);
@@ -99,7 +100,9 @@ public sealed class ResponsePlanToSocketMessagesMapper
!string.IsNullOrWhiteSpace(clientIntent)
? clientIntent
: transcript;
var outboundRules = isWordOfDayLaunch
var outboundRules = isProactivePizzaFactOffer
? ["shared/yes_no", "$YESNO"]
: isWordOfDayLaunch
? ["word-of-the-day/menu"]
: isGlobalCommand
? BuildGlobalCommandRules(rules)

View File

@@ -18,6 +18,28 @@ public sealed partial class WebSocketTurnFinalizationService(
private static readonly TimeSpan AutoFinalizeMissingTranscriptFallbackAge = TimeSpan.FromMilliseconds(4200);
private static readonly TimeSpan AutoFinalizeContinuationDeferralMaxAge = TimeSpan.FromMilliseconds(3600);
private const int AutoFinalizeContinuationDeferralMaxAttempts = 2;
private static readonly HashSet<string> PegasusAffinityContinuationStems = new(StringComparer.Ordinal)
{
"i love",
"i like",
"i enjoy",
"i do like",
"i dislike",
"i hate",
"i dont like",
"i don t like",
"i do not like",
"i dont enjoy",
"i don t enjoy",
"i do not enjoy",
"i dont love",
"i don t love",
"i do not love",
"i cant stand",
"i can t stand",
"i despise",
"i detest"
};
public static void ObserveIncomingMessage(CloudSession session, string? text)
{
@@ -1482,9 +1504,20 @@ public sealed partial class WebSocketTurnFinalizationService(
}
}
if (LooksLikeIncompleteAffinitySet(normalized))
{
reason = "affinity_set_incomplete";
return true;
}
return false;
}
private static bool LooksLikeIncompleteAffinitySet(string normalized)
{
return PegasusAffinityContinuationStems.Contains(normalized);
}
private static Dictionary<string, object?> BuildTurnDiagnosticSnapshot(
CloudSession session,
WebSocketMessageEnvelope envelope,