Diagnostics: forward upstream events + errors to device as 'debug' envelopes

Coolify container logs aren't accessible from the dev sandbox, so the only
log surface we can read is the Pi journal. The relay now forwards every
upstream event type to the device as {type:'debug', message:'relay evt=<T>'}
and every mid-session upstream error event as {type:'error',code:'upstream_<C>'}.

The client's Session.dispatch handles 'debug' as an INFO log line. Updates
the wake-flow integration test's receive-loop to skip over the new debug
envelopes via a ReceiveUntil helper.
This commit is contained in:
2026-06-12 06:59:14 +00:00
parent 8bb0ce51b1
commit a42038b825
3 changed files with 49 additions and 3 deletions
+33 -1
View File
@@ -120,15 +120,47 @@ public class RealtimeSession
private async Task PumpAsync(CancellationToken ct)
{
int nullPolls = 0;
while (!ct.IsCancellationRequested && !_endRequested)
{
var evt = await ReceiveOrIdleAsync(ct);
if (evt is null && _endRequested) return;
if (evt is null && ct.IsCancellationRequested) return;
if (evt is null) continue;
if (evt is null)
{
// Upstream has gone silent. If null persists for >2s, log so
// we can spot a dead upstream that's not surfacing as a close.
if (++nullPolls % 8 == 0)
_logger.LogDebug("upstream silent ({Polls} x 250ms polls)", nullPolls);
continue;
}
nullPolls = 0;
var type = (string?)evt["type"];
_logger.LogInformation("relay evt={EvtType}", type);
// Forward the event type to the device so it appears in the Pi
// journal — Coolify logs aren't accessible from the dev sandbox.
await _output.WriteEnvelopeAsync(new JsonObject
{
["type"] = "debug",
["message"] = "relay evt=" + (type ?? "<null>"),
}, ct);
switch (type)
{
case "error":
{
var err = evt["error"] as JsonObject;
var code = (string?)err?["code"] ?? "unknown";
var msg = (string?)err?["message"] ?? evt.ToJsonString();
_logger.LogWarning("upstream mid-session error code={Code} message={Message}", code, msg);
await _output.WriteEnvelopeAsync(new JsonObject
{
["type"] = "error",
["code"] = "upstream_" + code,
["message"] = msg,
["fatal"] = false,
}, ct);
break;
}
case "input_audio_buffer.speech_started":
_lastSpeechAt = DateTime.UtcNow;
break;