mirror of
https://kevinblog.sytes.net/Code/Jibo-Revival-Group/JiboExperiments.git
synced 2026-06-16 13:16:37 +00:00
version 16 with bug fixes
This commit is contained in:
@@ -228,6 +228,12 @@ Useful external references:
|
||||
- more capable skill/runtime integration
|
||||
- possible LLM or tool-use patterns inspired by workshop-era experimentation
|
||||
|
||||
## Latest Notes
|
||||
|
||||
- The `jibo test 19` bundle confirmed that gallery follow-up confirmation uses the stock local `shared/yes_no` rule family, not just the create/settings/surprise yes-no families. Spoken `yes` was being heard correctly, but leaking the global rules back into Nimbus instead of staying local.
|
||||
- The same bundle also confirmed some `OPENJIBO_AUDIO_RECEIVED` noise was still coming from an older running build, because the current `.NET` source no longer emits that synthetic websocket event. When a live session still shows it, operator workflow should treat that as a rebuild/restart sanity-check clue before assuming a new regression.
|
||||
- Spoken `cancel alarm` should map into stock `@be/clock` `delete` semantics, not generic chat. The current cloud path now mirrors that local intent so voice cancel can follow the same lane as the robot's clock skill.
|
||||
|
||||
## MCP-Like Ideas
|
||||
|
||||
Recent MIT workshop materials suggest experimentation around modern AI tooling for Jibo, including an MCP-oriented idea. We should treat that as inspiration for future OpenJibo directions, not as a present dependency or supported integration.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
This is the production-oriented path for restoring device connectivity and creating a foundation for future runtime, AI, and OTA work.
|
||||
|
||||
Current spoken cloud version: `Open Jibo Cloud version 1.0.15.`
|
||||
Current spoken cloud version: `Open Jibo Cloud version 1.0.16.`
|
||||
|
||||
Release hygiene reminder:
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ public sealed class JiboInteractionService(
|
||||
"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_value" => BuildTimerValueDecision(lowered, isTimerValueTurn),
|
||||
"alarm_value" => BuildAlarmValueDecision(lowered, isAlarmValueTurn, referenceLocalTime),
|
||||
"timer_clarify" => new JiboInteractionDecision("timer_clarify", "How long should I set the timer for?"),
|
||||
@@ -288,6 +290,28 @@ public sealed class JiboInteractionService(
|
||||
return "alarm_menu";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"cancel alarm",
|
||||
"delete alarm",
|
||||
"remove alarm",
|
||||
"stop alarm",
|
||||
"turn off alarm"))
|
||||
{
|
||||
return "alarm_delete";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"cancel timer",
|
||||
"delete timer",
|
||||
"remove timer",
|
||||
"stop timer",
|
||||
"turn off timer"))
|
||||
{
|
||||
return "timer_delete";
|
||||
}
|
||||
|
||||
if (TryParseAlarmValue(loweredTranscript, isAlarmValueTurn, referenceLocalTime) is not null)
|
||||
{
|
||||
return "alarm_value";
|
||||
@@ -616,6 +640,7 @@ public sealed class JiboInteractionService(
|
||||
.Any(static rule =>
|
||||
string.Equals(rule, "$YESNO", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "create/is_it_a_keeper", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "shared/yes_no", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "settings/download_now_later", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-date/offer_date_fact", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-ota/want_to_download_now", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace Jibo.Cloud.Application.Services;
|
||||
|
||||
public static class OpenJiboCloudBuildInfo
|
||||
{
|
||||
public const string Version = "1.0.15";
|
||||
public const string Version = "1.0.16";
|
||||
|
||||
public static string VersionWords => Version.Replace(".", " dot ");
|
||||
|
||||
|
||||
@@ -457,6 +457,7 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
return ReadRuleValues(turn)
|
||||
.FirstOrDefault(static rule =>
|
||||
string.Equals(rule, "create/is_it_a_keeper", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "shared/yes_no", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "settings/download_now_later", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-date/offer_date_fact", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-ota/want_to_download_now", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@@ -836,6 +836,7 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
.Concat(ReadRules(turn, "clientRules"))
|
||||
.FirstOrDefault(static rule =>
|
||||
string.Equals(rule, "create/is_it_a_keeper", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "shared/yes_no", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "settings/download_now_later", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-date/offer_date_fact", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(rule, "surprises-ota/want_to_download_now", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@@ -113,6 +113,26 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("No.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_SharedYesNoPrompt_MapsShortAffirmationToYesIntent()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "yes",
|
||||
NormalizedTranscript = "yes",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
["listenRules"] = new[] { "shared/yes_no", "globals/gui_nav" },
|
||||
["listenAsrHints"] = new[] { "$YESNO" }
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Equal("yes", decision.IntentName);
|
||||
Assert.Equal("Yes.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_SettingsDownloadPrompt_MapsShortDenialToNoIntent()
|
||||
{
|
||||
@@ -482,6 +502,23 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("What time should I set the alarm for?", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_CancelAlarm_MapsToClockDeleteIntent()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "cancel alarm",
|
||||
NormalizedTranscript = "cancel alarm"
|
||||
});
|
||||
|
||||
Assert.Equal("alarm_delete", decision.IntentName);
|
||||
Assert.Equal("@be/clock", decision.SkillName);
|
||||
Assert.Equal("alarm", decision.SkillPayload!["domain"]);
|
||||
Assert.Equal("delete", decision.SkillPayload["clockIntent"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_SetTimerWithoutDuration_AsksForClarification()
|
||||
{
|
||||
|
||||
@@ -687,6 +687,38 @@ public sealed class JiboWebSocketServiceTests
|
||||
Assert.Contains("What time should I set the alarm for?", esml, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_CancelAlarm_RedirectsIntoClockSkillWithDeleteIntent()
|
||||
{
|
||||
await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-cancel-alarm-token",
|
||||
Text = """{"type":"LISTEN","transID":"trans-clock-cancel-alarm","data":{"rules":["globals/global_commands_launch"]}}"""
|
||||
});
|
||||
|
||||
var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-clock-cancel-alarm-token",
|
||||
Text = """{"type":"CLIENT_ASR","transID":"trans-clock-cancel-alarm","data":{"text":"cancel alarm"}}"""
|
||||
});
|
||||
|
||||
Assert.Equal(5, replies.Count);
|
||||
|
||||
using var listenPayload = JsonDocument.Parse(replies[0].Text!);
|
||||
Assert.Equal("delete", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("intent").GetString());
|
||||
Assert.Equal("alarm", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("entities").GetProperty("domain").GetString());
|
||||
|
||||
using var redirectPayload = JsonDocument.Parse(replies[2].Text!);
|
||||
Assert.Equal("@be/clock", redirectPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("skillID").GetString());
|
||||
Assert.Equal("delete", redirectPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("intent").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_OpenPhotoGallery_RedirectsIntoGallerySkill()
|
||||
{
|
||||
@@ -924,6 +956,37 @@ public sealed class JiboWebSocketServiceTests
|
||||
Assert.Equal("surprises-ota/want_to_download_now", listenPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("rule").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientAsr_SharedYesNoPrompt_StripsGlobalRulesAndStaysLocal()
|
||||
{
|
||||
await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-shared-yesno-token",
|
||||
Text = """{"type":"LISTEN","transID":"trans-shared-yesno","data":{"rules":["shared/yes_no","globals/gui_nav","globals/mim_repeat","globals/global_commands_launch"],"asr":{"hints":["$YESNO"]}}}"""
|
||||
});
|
||||
|
||||
var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
HostName = "neo-hub.jibo.com",
|
||||
Path = "/listen",
|
||||
Kind = "neo-hub-listen",
|
||||
Token = "hub-shared-yesno-token",
|
||||
Text = """{"type":"CLIENT_ASR","transID":"trans-shared-yesno","data":{"text":"yes"}}"""
|
||||
});
|
||||
|
||||
Assert.Equal(3, replies.Count);
|
||||
|
||||
using var listenPayload = JsonDocument.Parse(replies[0].Text!);
|
||||
Assert.Equal("yes", listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("intent").GetString());
|
||||
var rules = listenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("rules");
|
||||
Assert.Single(rules.EnumerateArray());
|
||||
Assert.Equal("shared/yes_no", rules[0].GetString());
|
||||
Assert.Equal("shared/yes_no", listenPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("rule").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BufferedAudio_YesNoPromptWithSttFailure_AutoFinalizesAsLocalNoInput()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user