Fix birthday, memory, pizza, and weather intent handling
This commit is contained in:
@@ -385,8 +385,7 @@ public sealed class JiboInteractionService(
|
||||
var payload = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["skillId"] = "report-skill",
|
||||
["localIntent"] = "requestWeatherPR",
|
||||
["cloudSkill"] = "weather"
|
||||
["localIntent"] = "requestWeatherPR"
|
||||
};
|
||||
var dateEntity = TryResolveWeatherDateEntity(transcript);
|
||||
if (dateEntity is not null)
|
||||
@@ -747,12 +746,12 @@ public sealed class JiboInteractionService(
|
||||
return "memory_get_name";
|
||||
}
|
||||
|
||||
if (IsUserBirthdaySetStatement(loweredTranscript))
|
||||
if (IsUserBirthdaySetStatement(loweredTranscript) || IsUserBirthdaySetAttempt(loweredTranscript))
|
||||
{
|
||||
return "memory_set_birthday";
|
||||
}
|
||||
|
||||
if (IsUserBirthdayRecallQuestion(loweredTranscript))
|
||||
if (IsUserBirthdayRecallQuestion(loweredTranscript) || IsUserBirthdayRecallAttempt(loweredTranscript))
|
||||
{
|
||||
return "memory_get_birthday";
|
||||
}
|
||||
@@ -887,12 +886,12 @@ public sealed class JiboInteractionService(
|
||||
return "cloud_version";
|
||||
}
|
||||
|
||||
if (IsPreferenceSetStatement(loweredTranscript))
|
||||
if (IsPreferenceSetStatement(loweredTranscript) || IsPreferenceSetAttempt(loweredTranscript))
|
||||
{
|
||||
return "memory_set_preference";
|
||||
}
|
||||
|
||||
if (IsPreferenceRecallQuestion(loweredTranscript))
|
||||
if (IsPreferenceRecallQuestion(loweredTranscript) || IsPreferenceRecallAttempt(loweredTranscript))
|
||||
{
|
||||
return "memory_get_preference";
|
||||
}
|
||||
@@ -1079,20 +1078,6 @@ public sealed class JiboInteractionService(
|
||||
return "robot_personality";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"can you cook us a pizza",
|
||||
"flip a pizza",
|
||||
"make a pizza",
|
||||
"make pizza",
|
||||
"show pizza",
|
||||
"can you make pizza",
|
||||
"let's make pizza",
|
||||
"lets make pizza"))
|
||||
{
|
||||
return "pizza";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"can you order pizza",
|
||||
@@ -1102,11 +1087,31 @@ public sealed class JiboInteractionService(
|
||||
"order a pizza",
|
||||
"order us a pizza",
|
||||
"order me a pizza",
|
||||
"please order pizza"))
|
||||
"please order pizza") ||
|
||||
(loweredTranscript.Contains("order", StringComparison.Ordinal) &&
|
||||
loweredTranscript.Contains("pizza", StringComparison.Ordinal)))
|
||||
{
|
||||
return "order_pizza";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"can you cook us a pizza",
|
||||
"flip a pizza",
|
||||
"make a pizza",
|
||||
"make pizza",
|
||||
"show pizza",
|
||||
"can you make pizza",
|
||||
"let's make pizza",
|
||||
"lets make pizza") ||
|
||||
(loweredTranscript.Contains("pizza", StringComparison.Ordinal) &&
|
||||
(loweredTranscript.Contains("make", StringComparison.Ordinal) ||
|
||||
loweredTranscript.Contains("cook", StringComparison.Ordinal) ||
|
||||
loweredTranscript.Contains("flip", StringComparison.Ordinal))))
|
||||
{
|
||||
return "pizza";
|
||||
}
|
||||
|
||||
if (MatchesAny(loweredTranscript, "personal report", "my report", "daily report", "my update"))
|
||||
{
|
||||
return "personal_report";
|
||||
@@ -1822,15 +1827,22 @@ public sealed class JiboInteractionService(
|
||||
|
||||
private static bool IsRobotBirthdayQuestion(string loweredTranscript)
|
||||
{
|
||||
return MatchesAny(
|
||||
loweredTranscript,
|
||||
var normalized = NormalizeCommandPhrase(loweredTranscript);
|
||||
if (MatchesAny(
|
||||
normalized,
|
||||
"when is your birthday",
|
||||
"when's your birthday",
|
||||
"what's your birthday",
|
||||
"when s your birthday",
|
||||
"what s your birthday",
|
||||
"what is your birthday",
|
||||
"when were you born",
|
||||
"what day is your birthday");
|
||||
"what day is your birthday"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return (normalized.Contains("your birthday", StringComparison.Ordinal) ||
|
||||
normalized.Contains("your birth date", StringComparison.Ordinal))
|
||||
&& !normalized.Contains("my birthday", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static bool IsNameSetStatement(string loweredTranscript)
|
||||
@@ -1889,6 +1901,22 @@ public sealed class JiboInteractionService(
|
||||
return TryExtractBirthdayFact(loweredTranscript) is not null;
|
||||
}
|
||||
|
||||
private static bool IsUserBirthdaySetAttempt(string loweredTranscript)
|
||||
{
|
||||
var normalized = NormalizeCommandPhrase(loweredTranscript);
|
||||
return normalized.Contains("my birthday is", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static bool IsUserBirthdayRecallAttempt(string loweredTranscript)
|
||||
{
|
||||
var normalized = NormalizeCommandPhrase(loweredTranscript);
|
||||
return normalized.Contains("my birthday", StringComparison.Ordinal) &&
|
||||
(normalized.StartsWith("when", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("what", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("tell me", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("do you remember", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static string? TryExtractBirthdayFact(string transcript)
|
||||
{
|
||||
var normalized = NormalizeCommandPhrase(transcript);
|
||||
@@ -1913,6 +1941,30 @@ public sealed class JiboInteractionService(
|
||||
return TryExtractPreferenceSet(loweredTranscript) is not null;
|
||||
}
|
||||
|
||||
private static bool IsPreferenceSetAttempt(string loweredTranscript)
|
||||
{
|
||||
var normalized = NormalizeCommandPhrase(loweredTranscript);
|
||||
if (IsPreferenceRecallAttempt(normalized))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return normalized.Contains("my favorite", StringComparison.Ordinal) ||
|
||||
normalized.Contains("my favourite", StringComparison.Ordinal) ||
|
||||
PreferenceReverseMarkers.Any(marker => normalized.Contains(marker, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static bool IsPreferenceRecallAttempt(string loweredTranscript)
|
||||
{
|
||||
var normalized = NormalizeCommandPhrase(loweredTranscript);
|
||||
return normalized.StartsWith("what is my favorite", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("what s my favorite", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("what is my favourite", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("what s my favourite", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("do you remember my favorite", StringComparison.Ordinal) ||
|
||||
normalized.StartsWith("do you remember my favourite", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static string? TryExtractPreferenceLookupCategory(string transcript)
|
||||
{
|
||||
var normalized = NormalizeCommandPhrase(transcript);
|
||||
@@ -2830,6 +2882,8 @@ public sealed class JiboInteractionService(
|
||||
("country music", "Country"),
|
||||
("country radio", "Country"),
|
||||
("country", "Country"),
|
||||
("football", "Sports"),
|
||||
("sports", "Sports"),
|
||||
("classic rock", "ClassicRock"),
|
||||
("soft rock", "SoftRock"),
|
||||
("hip hop", "HipHop"),
|
||||
|
||||
@@ -175,6 +175,21 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("You told me your birthday is april 12.", recallDecision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_BirthdaySetAttemptWithoutValue_RoutesToBirthdayPrompt()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "my birthday is",
|
||||
NormalizedTranscript = "my birthday is"
|
||||
});
|
||||
|
||||
Assert.Equal("memory_set_birthday", decision.IntentName);
|
||||
Assert.Equal("I can remember it if you say, my birthday is March 14.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_PreferenceMemory_SetThenRecallWithinTenant()
|
||||
{
|
||||
@@ -212,6 +227,51 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("You told me your favorite music is jazz.", recallDecision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_PreferenceSetAttemptWithoutValue_RoutesToPreferencePrompt()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "my favorite music is",
|
||||
NormalizedTranscript = "my favorite music is"
|
||||
});
|
||||
|
||||
Assert.Equal("memory_set_preference", decision.IntentName);
|
||||
Assert.Equal("I can remember it if you say, my favorite music is jazz.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_PreferenceSetAttemptSportWithoutValue_RoutesToPreferencePrompt()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "my favorite sport.",
|
||||
NormalizedTranscript = "my favorite sport."
|
||||
});
|
||||
|
||||
Assert.Equal("memory_set_preference", decision.IntentName);
|
||||
Assert.Equal("I can remember it if you say, my favorite music is jazz.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_PreferenceRecallAttemptWithoutCategory_RoutesToRecallPrompt()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "what's my favorite",
|
||||
NormalizedTranscript = "what's my favorite"
|
||||
});
|
||||
|
||||
Assert.Equal("memory_get_preference", decision.IntentName);
|
||||
Assert.Equal("Ask me like this: what is my favorite music?", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_PersonalMemory_IsTenantScoped()
|
||||
{
|
||||
@@ -545,6 +605,22 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("RA_JBO_OrderPizza", decision.SkillPayload!["mim_id"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_CanYouOrderAPizzaWithPunctuation_UsesLegacyOrderPizzaMimPayload()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "Can you order a pizza?",
|
||||
NormalizedTranscript = "Can you order a pizza?"
|
||||
});
|
||||
|
||||
Assert.Equal("order_pizza", decision.IntentName);
|
||||
Assert.Equal("chitchat-skill", decision.SkillName);
|
||||
Assert.Equal("RA_JBO_OrderPizza", decision.SkillPayload!["mim_id"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_ClientNluRequestOrderPizza_UsesLegacyOrderPizzaMimPayload()
|
||||
{
|
||||
@@ -579,7 +655,7 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("weather", decision.IntentName);
|
||||
Assert.Equal("report-skill", decision.SkillName);
|
||||
Assert.Equal("requestWeatherPR", decision.SkillPayload!["localIntent"]);
|
||||
Assert.Equal("weather", decision.SkillPayload["cloudSkill"]);
|
||||
Assert.False(decision.SkillPayload!.ContainsKey("cloudSkill"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -713,6 +789,25 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("My birthday is March 22, 2026.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_ClientNluAskForDate_WithPrefixBirthdayTranscript_PrefersRobotBirthdayIntent()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "so what's your birthday",
|
||||
NormalizedTranscript = "so what's your birthday",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["clientIntent"] = "askForDate"
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Equal("robot_birthday", decision.IntentName);
|
||||
Assert.Equal("My birthday is March 22, 2026.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_YesNoFollowUp_MapsShortAffirmationToYesIntent()
|
||||
{
|
||||
|
||||
@@ -1727,7 +1727,7 @@ public sealed class JiboWebSocketServiceTests
|
||||
using var listenPayload = JsonDocument.Parse(replies[0].Text!);
|
||||
Assert.Equal("requestWeatherPR", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("intent").GetString());
|
||||
Assert.Equal("report-skill", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("skill").GetString());
|
||||
Assert.Equal("weather", listenPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("cloudSkill").GetString());
|
||||
Assert.Equal(JsonValueKind.Null, listenPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("cloudSkill").ValueKind);
|
||||
|
||||
using var redirectPayload = JsonDocument.Parse(replies[2].Text!);
|
||||
Assert.Equal("report-skill", redirectPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("skillID").GetString());
|
||||
|
||||
File diff suppressed because one or more lines are too long
12298
artifact-output/jibo-test-33/captures/turn/20260506.events.ndjson
Normal file
12298
artifact-output/jibo-test-33/captures/turn/20260506.events.ndjson
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
{
|
||||
"name": "neohubjibocom-neohubproactive-tidd36da4d442a611f1aba45cf821ea55ae",
|
||||
"session": {
|
||||
"hostName": "neo-hub.jibo.com",
|
||||
"path": "/v1/proactive",
|
||||
"kind": "neo-hub-proactive",
|
||||
"token": "hub-usr_openjibo_owner-1777340189867"
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"text": {
|
||||
"type": "TRIGGER",
|
||||
"ts": 1777341970615,
|
||||
"msgID": "mid-d388c070-42a6-11f1-a414-5cf821ea55ae",
|
||||
"transID": "tid-d36da4d4-42a6-11f1-aba4-5cf821ea55ae",
|
||||
"data": {
|
||||
"triggerSource": "SURPRISE",
|
||||
"triggerData": {
|
||||
"looperID": "5c0b221fdf9d450019c5e255"
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": []
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"type": "CONTEXT",
|
||||
"ts": 1777341970702,
|
||||
"msgID": "mid-d395f790-42a6-11f1-95f4-5cf821ea55ae",
|
||||
"transID": "tid-d36da4d4-42a6-11f1-aba4-5cf821ea55ae",
|
||||
"data": {
|
||||
"runtime": {
|
||||
"character": {
|
||||
"emotion": {
|
||||
"name": "NEUTRAL",
|
||||
"valence": 0.45,
|
||||
"confidence": 0.2
|
||||
},
|
||||
"motivation": {
|
||||
"social": 1,
|
||||
"playful": 0.5152989351851469
|
||||
}
|
||||
},
|
||||
"perception": {
|
||||
"speaker": "5c0b221fdf9d450019c5e255",
|
||||
"peoplePresent": [
|
||||
{
|
||||
"id": "NOT_TRAINED",
|
||||
"entityId": 16085,
|
||||
"type": "fused",
|
||||
"confidence": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"city": "Pleasant Hill",
|
||||
"state": "Missouri",
|
||||
"stateAbbr": "MO",
|
||||
"country": "United States",
|
||||
"countryCode": "US",
|
||||
"lat": 38.8358494,
|
||||
"lng": -94.1427229,
|
||||
"iso": "2026-04-27T21:06:10.626-05:00"
|
||||
},
|
||||
"loop": {
|
||||
"loopId": "5c0b221fdf9d450019c5e253",
|
||||
"users": [
|
||||
{
|
||||
"firstName": "Erin",
|
||||
"lastName": "Picone",
|
||||
"phoneticName": "Erin",
|
||||
"gender": "female",
|
||||
"birthdate": 649209600000,
|
||||
"id": "5c0b221fdf9d450019c5e255",
|
||||
"accountId": "5c0b20547c46170019235759"
|
||||
}
|
||||
],
|
||||
"jibo": {
|
||||
"color": "WHITE",
|
||||
"birthdate": 1544234645598,
|
||||
"id": "5c0b221fdf9d450019c5e254"
|
||||
},
|
||||
"owner": "5c0b221fdf9d450019c5e255"
|
||||
},
|
||||
"dialog": {
|
||||
"referent": null
|
||||
}
|
||||
},
|
||||
"skill": {
|
||||
"id": null
|
||||
},
|
||||
"general": {
|
||||
"release": "1.9.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"binary": null,
|
||||
"expectedReplyTypes": []
|
||||
}
|
||||
]
|
||||
}
|
||||
4691
artifact-output/jibo-test-33/jibo test 33.txt
Normal file
4691
artifact-output/jibo-test-33/jibo test 33.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user