handlePayload method

Future<void> handlePayload(
  1. Uint8List bytes
)

Feed bytes from the LiveKit data-channel onData callback here.

Implementation

Future<void> handlePayload(Uint8List bytes) async {
  Map<String, dynamic>? json;
  try {
    json = jsonDecode(utf8.decode(bytes)) as Map<String, dynamic>;
  } catch (_) {
    return;
  }
  final type = json['type'] as String?;
  if (type == null) return;
  if (WireLog.enabled) {
    WireLog.emit(
      '${WireLog.prefix} ◀ RECV] type=$type bytes=${bytes.length}',
      body: jsonEncode(redactForLog(json)),
    );
  }

  const gatedTypes = {
    MissionMessage.kType,
    'highlight',
  };
  if (gatedTypes.contains(type) &&
      !ActionGates.instance.actionIntelligenceEnabled) {
    if (WireLog.enabled) {
      debugPrint('${WireLog.prefix} ◀ DROP] type=$type '
          '(actionIntelligence disabled by action_config)');
    }
    return;
  }

  switch (type) {
    case MissionMessage.kType:
      // Defensive parse: a malformed step still dispatches — the runner
      // answers `failed failure_reason=invalid_mission` instead of the
      // frame vanishing while the backend waits out its timeout. Only a
      // frame with no usable mission_id (nothing to answer) is dropped.
      final MissionMessage? mission;
      try {
        mission = MissionMessage.tryParse(json);
      } catch (e, st) {
        debugPrint('[VoiceLoop] mission parse failed: $e\n$st');
        break;
      }
      if (mission == null) {
        debugPrint('[VoiceLoop] mission frame without a mission_id — dropped');
        break;
      }
      try {
        await _startMission(mission);
      } catch (e, st) {
        debugPrint('[VoiceLoop] mission dispatch failed: $e\n$st');
      }
      break;

    case CancelMessage.kType:
      try {
        _cancelMission(CancelMessage.fromJson(json));
      } catch (e, st) {
        debugPrint('[VoiceLoop] cancel parse failed: $e\n$st');
      }
      break;

    case SpeakMessage.kType:
      break;

    case HighlightMessage.kType:
      final HighlightMessage msg;
      try {
        msg = HighlightMessage.fromJson(json);
      } catch (e, st) {
        debugPrint('[VoiceLoop] highlight parse failed: $e\n$st');
        break;
      }
      await _handleHighlight(msg);
      break;

    case 'request_ui_tree':
      onRequestSnapshot?.call();
      break;

    default:
      break;
  }
}