mirror of
https://kevinblog.sytes.net/Code/Jibo-Revival-Group/JiboExperiments.git
synced 2026-06-18 17:46:00 +00:00
more code matching for skill launch
This commit is contained in:
@@ -110,6 +110,7 @@ Evidence from the smaller `2026-04-18/19` hotphrase and word-of-the-day verifica
|
||||
- the `jibo test 5` bundle suggests the remaining WOD launch and post-win cleanup bugs share the same root cause: we were leaving the robot-side `cloudSkillResponse` promise unresolved on `word_of_the_day`, `word_of_the_day_guess`, and `word-of-the-day/right_word`, so the latest .NET pass now emits a completion-only silent `SKILL_ACTION` for those paths instead of stopping at `LISTEN` + `EOS` or going fully silent
|
||||
- the `jibo test 6` bundle plus the attached `@be` source snapshot refine that diagnosis: Nimbus does accept the silent completion response, but treats it as a normal `SLIM/RUNTIME_PROMPT` instead of a skill redirect, while the successful on-robot path is built around `menu + domain=word-of-the-day` skill switching through `SkillSwitchScheduler`
|
||||
- the attached `be-framework.js` adds one more strong clue: the Be relaunch hook reads `skillData.nlu.skill`, so synthetic cloud launch turns for word-of-the-day should carry the explicit target skill name in the outbound NLU payload instead of expecting the robot to infer it from `intent/domain` alone
|
||||
- the `JiboOs/V3.1` Nimbus source confirms the hotphrase/global launch path still routes through `@be/nimbus` and waits on `listenResult.cloudSkillResponse`, while Nimbus only supports a narrow set of cloud JCP behaviors and does not use cloud `REDIRECT` to jump into local skills; by contrast, the post-win `word-of-the-day/right_word` turn is a local `Optional-Response`, so the cleaner robot-side closeout is to synthesize an immediate empty `LISTEN + EOS` no-response result rather than replying with only `SKILL_ACTION`
|
||||
- the same `jibo test 6` capture also shows the blue-ring cleanup loop was partly self-inflicted in `.NET`: after `word-of-the-day/right_word` we stopped the active turn, but later stray binary audio on the same transID could still re-arm buffering even without a fresh `LISTEN`, so the next pass now requires a real listen phase before post-turn audio can reopen buffered completion
|
||||
- the local buffered-audio seam is still producing repeated `whisper.cpp returned no transcript` and `ffmpeg ... Codec not found` failures, so lightweight waveform or energy screening is worth considering once the core launch flow is stable
|
||||
|
||||
|
||||
@@ -143,6 +143,48 @@ public sealed class ResponsePlanToSocketMessagesMapper
|
||||
];
|
||||
}
|
||||
|
||||
public static IReadOnlyList<SocketReplyPlan> MapNoInput(string transId, IReadOnlyList<string> rules)
|
||||
{
|
||||
return
|
||||
[
|
||||
new SocketReplyPlan(JsonSerializer.Serialize(new
|
||||
{
|
||||
type = "LISTEN",
|
||||
transID = transId,
|
||||
data = new
|
||||
{
|
||||
asr = new
|
||||
{
|
||||
confidence = 0.95,
|
||||
final = true,
|
||||
text = string.Empty
|
||||
},
|
||||
nlu = new
|
||||
{
|
||||
confidence = 0.95,
|
||||
intent = string.Empty,
|
||||
rules,
|
||||
entities = new Dictionary<string, object?>()
|
||||
},
|
||||
match = new
|
||||
{
|
||||
intent = string.Empty,
|
||||
rule = rules.FirstOrDefault() ?? string.Empty,
|
||||
score = 0.95
|
||||
}
|
||||
}
|
||||
})),
|
||||
new SocketReplyPlan(JsonSerializer.Serialize(new
|
||||
{
|
||||
type = "EOS",
|
||||
ts = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
|
||||
msgID = CreateHubMessageId(),
|
||||
transID = transId,
|
||||
data = new { }
|
||||
}))
|
||||
];
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> ReadRules(TurnContext turn, string? messageType)
|
||||
{
|
||||
var attributeName = string.Equals(messageType, "CLIENT_NLU", StringComparison.OrdinalIgnoreCase)
|
||||
|
||||
@@ -150,9 +150,9 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
ResetBufferedAudio(session);
|
||||
session.TurnState.SawListen = false;
|
||||
session.TurnState.SawContext = false;
|
||||
return ResponsePlanToSocketMessagesMapper.MapCompletionOnly(
|
||||
return ResponsePlanToSocketMessagesMapper.MapNoInput(
|
||||
session.TurnState.TransId ?? session.LastTransId ?? string.Empty,
|
||||
"@be/word-of-the-day")
|
||||
session.TurnState.ListenRules)
|
||||
.Select(map => new WebSocketReply
|
||||
{
|
||||
Text = map.Text,
|
||||
@@ -433,7 +433,15 @@ public sealed class WebSocketTurnFinalizationService(
|
||||
ResetBufferedAudio(session);
|
||||
turnState.SawListen = false;
|
||||
turnState.SawContext = false;
|
||||
return [];
|
||||
return ResponsePlanToSocketMessagesMapper.MapNoInput(
|
||||
turnState.TransId ?? session.LastTransId ?? string.Empty,
|
||||
turnState.ListenRules)
|
||||
.Select(map => new WebSocketReply
|
||||
{
|
||||
Text = map.Text,
|
||||
DelayMs = map.DelayMs
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (ShouldIgnoreInitialEmptyHotphraseTurn(finalizedTurn, turnState))
|
||||
|
||||
@@ -629,7 +629,9 @@ public sealed class JiboWebSocketServiceTests
|
||||
Text = """{"type":"CLIENT_ASR","transID":"trans-wod-right-word","data":{}}"""
|
||||
});
|
||||
|
||||
Assert.Empty(replies);
|
||||
Assert.Equal(2, replies.Count);
|
||||
Assert.Equal("LISTEN", ReadReplyType(replies[0]));
|
||||
Assert.Equal("EOS", ReadReplyType(replies[1]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -674,8 +676,13 @@ public sealed class JiboWebSocketServiceTests
|
||||
Text = """{"type":"LISTEN","transID":"trans-wod-right-word-audio","data":{"rules":["word-of-the-day/right_word","globals/gui_nav","globals/mim_repeat","globals/global_commands_launch"]}}"""
|
||||
});
|
||||
|
||||
Assert.Single(replies);
|
||||
Assert.Equal("SKILL_ACTION", ReadReplyType(replies[0]));
|
||||
Assert.Equal(2, replies.Count);
|
||||
Assert.Equal("LISTEN", ReadReplyType(replies[0]));
|
||||
Assert.Equal("EOS", ReadReplyType(replies[1]));
|
||||
|
||||
using var listenPayload = JsonDocument.Parse(replies[0].Text!);
|
||||
Assert.Equal(string.Empty, listenPayload.RootElement.GetProperty("data").GetProperty("asr").GetProperty("text").GetString());
|
||||
Assert.Equal("word-of-the-day/right_word", listenPayload.RootElement.GetProperty("data").GetProperty("match").GetProperty("rule").GetString());
|
||||
|
||||
var binaryReplies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user