From ec14e61a8184205d24db70b1ede7e62559c03cb7 Mon Sep 17 00:00:00 2001 From: Jacob Dubin Date: Wed, 6 May 2026 20:10:31 -0500 Subject: [PATCH] Update implementation details --- .../Services/JiboWebSocketService.cs | 65 ++++++++++++++++++- .../WebSockets/JiboWebSocketServiceTests.cs | 12 +++- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboWebSocketService.cs b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboWebSocketService.cs index fa85e61..9c71791 100644 --- a/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboWebSocketService.cs +++ b/OpenJibo/src/Jibo.Cloud/dotnet/src/Jibo.Cloud.Application/Services/JiboWebSocketService.cs @@ -37,12 +37,24 @@ public sealed class JiboWebSocketService( !containsInlineTurnPayload && WebSocketTurnFinalizationService.ShouldIgnoreLateListenSetup(session, envelope.Text)) { + var (lateTransId, lateRules) = ResolveLateListenNoInputPayload(session, envelope.Text); + var replies = ResponsePlanToSocketMessagesMapper + .MapNoInputAndRedirectToSkill(lateTransId, lateRules, "@be/idle") + .Select(map => new WebSocketReply + { + Text = map.Text, + DelayMs = map.DelayMs + }) + .ToArray(); + await telemetrySink.RecordTurnEventAsync(envelope, session, "late_listen_ignored", new Dictionary { ["messageType"] = parsedType, - ["activeTransID"] = session.TurnState.TransId + ["activeTransID"] = session.TurnState.TransId, + ["ignoredTransID"] = lateTransId, + ["replyCount"] = replies.Length }, cancellationToken); - return []; + return replies; } WebSocketTurnFinalizationService.ObserveIncomingMessage(session, envelope.Text); @@ -145,4 +157,53 @@ public sealed class JiboWebSocketService( return false; } } + + private static (string TransId, IReadOnlyList Rules) ResolveLateListenNoInputPayload( + CloudSession session, + string? text) + { + var transId = session.TurnState.TransId ?? session.LastTransId ?? string.Empty; + var rules = session.TurnState.ListenRules; + + if (string.IsNullOrWhiteSpace(text)) + { + return (transId, rules); + } + + try + { + using var document = JsonDocument.Parse(text); + var root = document.RootElement; + + if (root.TryGetProperty("transID", out var transIdValue) && + transIdValue.ValueKind == JsonValueKind.String && + !string.IsNullOrWhiteSpace(transIdValue.GetString())) + { + transId = transIdValue.GetString()!; + } + + if (root.TryGetProperty("data", out var data) && + data.ValueKind == JsonValueKind.Object && + data.TryGetProperty("rules", out var ruleValues) && + ruleValues.ValueKind == JsonValueKind.Array) + { + var parsedRules = ruleValues.EnumerateArray() + .Where(static item => item.ValueKind == JsonValueKind.String) + .Select(static item => item.GetString() ?? string.Empty) + .Where(static rule => !string.IsNullOrWhiteSpace(rule)) + .ToArray(); + + if (parsedRules.Length > 0) + { + rules = parsedRules; + } + } + } + catch + { + // Best effort parsing for late-listen cleanup. + } + + return (transId, rules); + } } diff --git a/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboWebSocketServiceTests.cs b/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboWebSocketServiceTests.cs index 66d7f6d..7ab7779 100644 --- a/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboWebSocketServiceTests.cs +++ b/OpenJibo/tests/Jibo.Cloud.Tests/WebSockets/JiboWebSocketServiceTests.cs @@ -77,7 +77,7 @@ public sealed class JiboWebSocketServiceTests } [Fact] - public async Task Listen_CloudVersion_DoesNotOpenFollowUpAndIgnoresSpeechTailListen() + public async Task Listen_CloudVersion_DoesNotOpenFollowUpAndClosesLateTailListen() { var replies = await _service.HandleMessageAsync(new WebSocketMessageEnvelope { @@ -127,7 +127,15 @@ public sealed class JiboWebSocketServiceTests Text = """{"type":"LISTEN","transID":"trans-cloud-version-tail","data":{"hotphrase":true,"rules":["launch","globals/global_commands_launch"]}}""" }); - Assert.Empty(tailListenReplies); + Assert.Equal(3, tailListenReplies.Count); + Assert.Equal("LISTEN", ReadReplyType(tailListenReplies[0])); + Assert.Equal("EOS", ReadReplyType(tailListenReplies[1])); + Assert.Equal("SKILL_REDIRECT", ReadReplyType(tailListenReplies[2])); + using (var lateListenPayload = JsonDocument.Parse(tailListenReplies[0].Text!)) + { + Assert.Equal("trans-cloud-version-tail", lateListenPayload.RootElement.GetProperty("transID").GetString()); + Assert.Equal("launch", lateListenPayload.RootElement.GetProperty("data").GetProperty("nlu").GetProperty("rules")[0].GetString()); + } Assert.Equal("trans-cloud-version", session.TurnState.TransId); Assert.False(session.TurnState.AwaitingTurnCompletion); Assert.False(session.TurnState.SawListen);