fix(ios): preserve realtime relay issue codes

Map known relay issue codes into the iOS Talk runtime taxonomy while retaining the generic fallback for forward-compatible unknown codes.

Co-authored-by: Zhilong Zheng <zhengzhilong1115@gmail.com>
Punchcard-Session: golden-meadow-cedar-dv
This commit is contained in:
Vincent Koc
2026-08-11 18:03:00 +08:00
parent 39597be775
commit 4145df6fca
3 changed files with 56 additions and 42 deletions
+35 -35
View File
@@ -28099,7 +28099,7 @@
},
{
"kind": "ui-localized-call",
"line": 2921,
"line": 2915,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Generating voice…",
"surface": "apple",
@@ -28107,7 +28107,7 @@
},
{
"kind": "ui-localized-call",
"line": 3059,
"line": 3053,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speak failed: %@",
"surface": "apple",
@@ -28115,7 +28115,7 @@
},
{
"kind": "ui-localized-call",
"line": 3158,
"line": 3152,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speaking (System)…",
"surface": "apple",
@@ -28123,7 +28123,7 @@
},
{
"kind": "ui-localized-call",
"line": 4054,
"line": 4048,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "iOS System Voice",
"surface": "apple",
@@ -28131,7 +28131,7 @@
},
{
"kind": "ui-localized-call",
"line": 4056,
"line": 4050,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime Voice",
"surface": "apple",
@@ -28139,7 +28139,7 @@
},
{
"kind": "ui-localized-call",
"line": 4060,
"line": 4054,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway Default",
"surface": "apple",
@@ -28147,7 +28147,7 @@
},
{
"kind": "ui-localized-call",
"line": 4121,
"line": 4115,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening (Realtime)",
"surface": "apple",
@@ -28155,7 +28155,7 @@
},
{
"kind": "ui-localized-call",
"line": 4123,
"line": 4117,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Thinking",
"surface": "apple",
@@ -28163,7 +28163,7 @@
},
{
"kind": "ui-localized-call",
"line": 4125,
"line": 4119,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Thinking…",
"surface": "apple",
@@ -28171,7 +28171,7 @@
},
{
"kind": "ui-localized-call",
"line": 4127,
"line": 4121,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Asking OpenClaw",
"surface": "apple",
@@ -28179,7 +28179,7 @@
},
{
"kind": "ui-localized-call",
"line": 4129,
"line": 4123,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Still asking OpenClaw",
"surface": "apple",
@@ -28187,7 +28187,7 @@
},
{
"kind": "ui-localized-call",
"line": 4131,
"line": 4125,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Updating OpenClaw",
"surface": "apple",
@@ -28195,7 +28195,7 @@
},
{
"kind": "ui-localized-call",
"line": 4133,
"line": 4127,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speaking",
"surface": "apple",
@@ -28203,7 +28203,7 @@
},
{
"kind": "ui-localized-call",
"line": 4135,
"line": 4129,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speaking…",
"surface": "apple",
@@ -28211,7 +28211,7 @@
},
{
"kind": "ui-localized-call",
"line": 4137,
"line": 4131,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Connecting",
"surface": "apple",
@@ -28219,7 +28219,7 @@
},
{
"kind": "ui-localized-call",
"line": 4139,
"line": 4133,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Connecting realtime…",
"surface": "apple",
@@ -28227,7 +28227,7 @@
},
{
"kind": "ui-localized-call",
"line": 4141,
"line": 4135,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Waiting for realtime…",
"surface": "apple",
@@ -28235,7 +28235,7 @@
},
{
"kind": "ui-localized-call",
"line": 4143,
"line": 4137,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Ready",
"surface": "apple",
@@ -28243,7 +28243,7 @@
},
{
"kind": "ui-localized-call",
"line": 4145,
"line": 4139,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Reconnecting",
"surface": "apple",
@@ -28251,7 +28251,7 @@
},
{
"kind": "ui-localized-call",
"line": 4147,
"line": 4141,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Reconnecting…",
"surface": "apple",
@@ -28259,7 +28259,7 @@
},
{
"kind": "ui-localized-call",
"line": 4149,
"line": 4143,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime failed before connecting",
"surface": "apple",
@@ -28267,7 +28267,7 @@
},
{
"kind": "ui-localized-call",
"line": 4151,
"line": 4145,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime disconnected",
"surface": "apple",
@@ -28275,7 +28275,7 @@
},
{
"kind": "ui-localized-call",
"line": 4153,
"line": 4147,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "OpenClaw unavailable",
"surface": "apple",
@@ -28283,7 +28283,7 @@
},
{
"kind": "ui-localized-call",
"line": 4155,
"line": 4149,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Confirmation needed",
"surface": "apple",
@@ -28291,7 +28291,7 @@
},
{
"kind": "ui-localized-call",
"line": 4198,
"line": 4192,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "iOS Speech + TTS",
"surface": "apple",
@@ -28299,7 +28299,7 @@
},
{
"kind": "ui-localized-call",
"line": 4200,
"line": 4194,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening",
"surface": "apple",
@@ -28307,7 +28307,7 @@
},
{
"kind": "ui-localized-call",
"line": 4204,
"line": 4198,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "iOS Speech fallback",
"surface": "apple",
@@ -28315,7 +28315,7 @@
},
{
"kind": "ui-localized-call",
"line": 4465,
"line": 4469,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway Relay",
"surface": "apple",
@@ -28323,7 +28323,7 @@
},
{
"kind": "ui-localized-call",
"line": 4467,
"line": 4471,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Native WebRTC",
"surface": "apple",
@@ -28331,7 +28331,7 @@
},
{
"kind": "ui-localized-call",
"line": 4468,
"line": 4472,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Native",
"surface": "apple",
@@ -28339,7 +28339,7 @@
},
{
"kind": "ui-localized-call",
"line": 4529,
"line": 4533,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway permission required",
"surface": "apple",
@@ -28347,7 +28347,7 @@
},
{
"kind": "ui-localized-call",
"line": 4551,
"line": 4555,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Not loaded",
"surface": "apple",
@@ -28355,7 +28355,7 @@
},
{
"kind": "ui-localized-call",
"line": 4569,
"line": 4573,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Approval requested",
"surface": "apple",
@@ -28363,7 +28363,7 @@
},
{
"kind": "ui-localized-call",
"line": 5099,
"line": 5103,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime unavailable",
"surface": "apple",
@@ -28371,7 +28371,7 @@
},
{
"kind": "ui-localized-call",
"line": 5127,
"line": 5131,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening (PTT)",
"surface": "apple",
+11 -7
View File
@@ -2360,13 +2360,7 @@ final class TalkModeManager: NSObject {
},
onIssue: { [weak self] relayIssue in
guard let self, self.realtimeRelayGeneration == relayGeneration else { return }
let issue = TalkRuntimeIssue(
code: .realtimeUnavailable,
message: relayIssue.message,
provider: relayIssue.provider,
model: relayIssue.model,
transport: relayIssue.transport,
phase: relayIssue.phase)
let issue = Self.runtimeIssue(from: relayIssue)
self.realtimeRelayStartIssue = issue
self.pendingRealtimeIssue = issue
self.gatewayTalkLastIssueText = issue.diagnosticSummary
@@ -4217,6 +4211,16 @@ extension TalkModeManager {
phase: phase)
}
static func runtimeIssue(from issue: RealtimeTalkRelayIssue) -> TalkRuntimeIssue {
TalkRuntimeIssue(
code: TalkRuntimeIssue.Code(rawValue: issue.code) ?? .realtimeUnavailable,
message: issue.message,
provider: issue.provider,
model: issue.model,
transport: issue.transport,
phase: issue.phase)
}
private func realtimeIssue(from error: Error, phase: String) -> TalkRuntimeIssue {
if let gatewayError = error as? GatewayResponseError,
let issue = Self.talkRuntimeIssue(
@@ -403,6 +403,16 @@ struct TalkModeManagerTests {
#expect(issue.technicalDetails.contains("code: realtime_unavailable"))
}
@Test func `relay issue preserves known code and falls back for unknown code`() {
let codes = ["realtime_output_cancel_failed", "future_code"].map { rawCode in
TalkModeManager.runtimeIssue(from: RealtimeTalkRelayIssue(
code: rawCode,
message: "failed")).code
}
#expect(codes == [.realtimeOutputCancelFailed, .realtimeUnavailable])
}
@Test func `native fallback keeps realtime issue visible`() {
let manager = TalkModeManager(allowSimulatorCapture: true)
let issue = TalkRuntimeIssue(