mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-14 11:26:13 +00:00
fix(watch): preserve snapshot compatibility
This commit is contained in:
@@ -436,6 +436,42 @@ struct WatchAppSnapshotMessage: Codable, Equatable {
|
||||
var sentAtMs: Int64?
|
||||
var snapshotId: String?
|
||||
|
||||
private init(
|
||||
gatewayStatus: OpenClawWatchAppStatus,
|
||||
gatewayConnected: Bool,
|
||||
agentName: String,
|
||||
agentAvatarURL: String?,
|
||||
agentAvatarText: String?,
|
||||
sessionKey: String,
|
||||
gatewayStableID: String?,
|
||||
talkStatus: OpenClawWatchAppStatus,
|
||||
talkEnabled: Bool,
|
||||
talkListening: Bool,
|
||||
talkSpeaking: Bool,
|
||||
pendingApprovalCount: Int,
|
||||
chatItems: [WatchChatItem]?,
|
||||
chatStatus: OpenClawWatchAppStatus?,
|
||||
sentAtMs: Int64?,
|
||||
snapshotId: String?)
|
||||
{
|
||||
self.gatewayStatus = gatewayStatus
|
||||
self.gatewayConnected = gatewayConnected
|
||||
self.agentName = agentName
|
||||
self.agentAvatarURL = agentAvatarURL
|
||||
self.agentAvatarText = agentAvatarText
|
||||
self.sessionKey = sessionKey
|
||||
self.gatewayStableID = gatewayStableID
|
||||
self.talkStatus = talkStatus
|
||||
self.talkEnabled = talkEnabled
|
||||
self.talkListening = talkListening
|
||||
self.talkSpeaking = talkSpeaking
|
||||
self.pendingApprovalCount = pendingApprovalCount
|
||||
self.chatItems = chatItems
|
||||
self.chatStatus = chatStatus
|
||||
self.sentAtMs = sentAtMs
|
||||
self.snapshotId = snapshotId
|
||||
}
|
||||
|
||||
static func parsePayload(_ payload: [String: Any]) -> Self? {
|
||||
guard let type = payload["type"] as? String,
|
||||
type == WatchPayloadType.appSnapshot.rawValue
|
||||
@@ -548,21 +584,21 @@ struct WatchAppSnapshotMessage: Codable, Equatable {
|
||||
self.chatItems = try container.decodeIfPresent([WatchChatItem].self, forKey: .chatItems)
|
||||
self.sentAtMs = try container.decodeIfPresent(Int64.self, forKey: .sentAtMs)
|
||||
self.snapshotId = try container.decodeIfPresent(String.self, forKey: .snapshotId)
|
||||
self.gatewayStatus = try container.decodeIfPresent(
|
||||
self.gatewayStatus = (try? container.decode(
|
||||
OpenClawWatchAppStatus.self,
|
||||
forKey: .gatewayStatus) ?? Self.decodeLegacyGatewayStatus(
|
||||
forKey: .gatewayStatus)) ?? Self.decodeLegacyGatewayStatus(
|
||||
text: container.decodeIfPresent(String.self, forKey: .gatewayStatusText),
|
||||
connected: self.gatewayConnected)
|
||||
self.talkStatus = try container.decodeIfPresent(
|
||||
self.talkStatus = (try? container.decode(
|
||||
OpenClawWatchAppStatus.self,
|
||||
forKey: .talkStatus) ?? Self.decodeLegacyTalkStatus(
|
||||
forKey: .talkStatus)) ?? Self.decodeLegacyTalkStatus(
|
||||
text: container.decodeIfPresent(String.self, forKey: .talkStatusText),
|
||||
enabled: self.talkEnabled,
|
||||
listening: self.talkListening,
|
||||
speaking: self.talkSpeaking)
|
||||
self.chatStatus = try container.decodeIfPresent(
|
||||
self.chatStatus = (try? container.decode(
|
||||
OpenClawWatchAppStatus.self,
|
||||
forKey: .chatStatus) ?? Self.decodeLegacyChatStatus(
|
||||
forKey: .chatStatus)) ?? Self.decodeLegacyChatStatus(
|
||||
code: container.decodeIfPresent(String.self, forKey: .chatStatusCode),
|
||||
text: container.decodeIfPresent(String.self, forKey: .chatStatusText))
|
||||
}
|
||||
|
||||
@@ -384,6 +384,53 @@ public struct OpenClawWatchAppSnapshotMessage: Codable, Sendable, Equatable {
|
||||
self.snapshotId = snapshotId
|
||||
}
|
||||
|
||||
public init(
|
||||
gatewayStatusText: String,
|
||||
gatewayConnected: Bool,
|
||||
agentName: String,
|
||||
agentAvatarURL: String? = nil,
|
||||
agentAvatarText: String? = nil,
|
||||
sessionKey: String,
|
||||
gatewayStableID: String? = nil,
|
||||
talkStatusText: String,
|
||||
talkEnabled: Bool,
|
||||
talkListening: Bool,
|
||||
talkSpeaking: Bool,
|
||||
pendingApprovalCount: Int,
|
||||
chatItems: [OpenClawWatchChatItem]? = nil,
|
||||
chatStatusText: String? = nil,
|
||||
sentAtMs: Int64? = nil,
|
||||
snapshotId: String? = nil)
|
||||
{
|
||||
// Preserve the shipped source API while producers migrate to semantic statuses.
|
||||
self.init(
|
||||
gatewayStatus: Self.decodeLegacyGatewayStatus(
|
||||
text: gatewayStatusText,
|
||||
connected: gatewayConnected),
|
||||
gatewayStatusText: gatewayStatusText,
|
||||
gatewayConnected: gatewayConnected,
|
||||
agentName: agentName,
|
||||
agentAvatarURL: agentAvatarURL,
|
||||
agentAvatarText: agentAvatarText,
|
||||
sessionKey: sessionKey,
|
||||
gatewayStableID: gatewayStableID,
|
||||
talkStatus: Self.decodeLegacyTalkStatus(
|
||||
text: talkStatusText,
|
||||
enabled: talkEnabled,
|
||||
listening: talkListening,
|
||||
speaking: talkSpeaking),
|
||||
talkStatusText: talkStatusText,
|
||||
talkEnabled: talkEnabled,
|
||||
talkListening: talkListening,
|
||||
talkSpeaking: talkSpeaking,
|
||||
pendingApprovalCount: pendingApprovalCount,
|
||||
chatItems: chatItems,
|
||||
chatStatus: Self.decodeLegacyChatStatus(code: nil, text: chatStatusText),
|
||||
chatStatusText: chatStatusText,
|
||||
sentAtMs: sentAtMs,
|
||||
snapshotId: snapshotId)
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
case gatewayStatus
|
||||
@@ -426,25 +473,25 @@ public struct OpenClawWatchAppSnapshotMessage: Codable, Sendable, Equatable {
|
||||
self.snapshotId = try container.decodeIfPresent(String.self, forKey: .snapshotId)
|
||||
|
||||
let gatewayStatusText = try container.decodeIfPresent(String.self, forKey: .gatewayStatusText)
|
||||
self.gatewayStatus = try container.decodeIfPresent(
|
||||
self.gatewayStatus = (try? container.decode(
|
||||
OpenClawWatchAppStatus.self,
|
||||
forKey: .gatewayStatus) ?? Self.decodeLegacyGatewayStatus(
|
||||
forKey: .gatewayStatus)) ?? Self.decodeLegacyGatewayStatus(
|
||||
text: gatewayStatusText,
|
||||
connected: self.gatewayConnected)
|
||||
self.gatewayStatusText = gatewayStatusText ?? Self.legacyText(for: self.gatewayStatus)
|
||||
let talkStatusText = try container.decodeIfPresent(String.self, forKey: .talkStatusText)
|
||||
self.talkStatus = try container.decodeIfPresent(
|
||||
self.talkStatus = (try? container.decode(
|
||||
OpenClawWatchAppStatus.self,
|
||||
forKey: .talkStatus) ?? Self.decodeLegacyTalkStatus(
|
||||
forKey: .talkStatus)) ?? Self.decodeLegacyTalkStatus(
|
||||
text: talkStatusText,
|
||||
enabled: self.talkEnabled,
|
||||
listening: self.talkListening,
|
||||
speaking: self.talkSpeaking)
|
||||
self.talkStatusText = talkStatusText ?? Self.legacyText(for: self.talkStatus)
|
||||
let chatStatusText = try container.decodeIfPresent(String.self, forKey: .chatStatusText)
|
||||
self.chatStatus = try container.decodeIfPresent(
|
||||
self.chatStatus = (try? container.decode(
|
||||
OpenClawWatchAppStatus.self,
|
||||
forKey: .chatStatus) ?? Self.decodeLegacyChatStatus(
|
||||
forKey: .chatStatus)) ?? Self.decodeLegacyChatStatus(
|
||||
code: container.decodeIfPresent(String.self, forKey: .chatStatusCode),
|
||||
text: chatStatusText)
|
||||
self.chatStatusText = chatStatusText ?? self.chatStatus.map(Self.legacyText)
|
||||
|
||||
@@ -29,4 +29,55 @@ struct WatchCommandsTests {
|
||||
#expect(object["chatStatus"] != nil)
|
||||
#expect(object["chatStatusText"] as? String == "No chat messages yet")
|
||||
}
|
||||
|
||||
@Test func `shipped snapshot initializer remains available`() {
|
||||
let message = OpenClawWatchAppSnapshotMessage(
|
||||
gatewayStatusText: "Connected",
|
||||
gatewayConnected: true,
|
||||
agentName: "Main",
|
||||
sessionKey: "main",
|
||||
talkStatusText: "Off",
|
||||
talkEnabled: false,
|
||||
talkListening: false,
|
||||
talkSpeaking: false,
|
||||
pendingApprovalCount: 0)
|
||||
|
||||
#expect(message.gatewayStatus.code == .gatewayConnected)
|
||||
#expect(message.talkStatus.code == .talkOff)
|
||||
}
|
||||
|
||||
@Test func `unknown semantic statuses fall back to legacy text`() throws {
|
||||
let json = """
|
||||
{
|
||||
"type": "watch.appSnapshot",
|
||||
"gatewayStatus": {"code": "futureGateway", "arguments": []},
|
||||
"gatewayStatusText": "Future gateway state",
|
||||
"gatewayConnected": false,
|
||||
"agentName": "Main",
|
||||
"sessionKey": "main",
|
||||
"talkStatus": {"code": "futureTalk", "arguments": []},
|
||||
"talkStatusText": "Future Talk state",
|
||||
"talkEnabled": true,
|
||||
"talkListening": false,
|
||||
"talkSpeaking": false,
|
||||
"pendingApprovalCount": 0,
|
||||
"chatStatus": {"code": "futureChat", "arguments": []},
|
||||
"chatStatusText": "Future chat state"
|
||||
}
|
||||
"""
|
||||
|
||||
let message = try JSONDecoder().decode(
|
||||
OpenClawWatchAppSnapshotMessage.self,
|
||||
from: Data(json.utf8))
|
||||
|
||||
#expect(message.gatewayStatus == OpenClawWatchAppStatus(
|
||||
code: .legacy,
|
||||
verbatim: "Future gateway state"))
|
||||
#expect(message.talkStatus == OpenClawWatchAppStatus(
|
||||
code: .legacy,
|
||||
verbatim: "Future Talk state"))
|
||||
#expect(message.chatStatus == OpenClawWatchAppStatus(
|
||||
code: .legacy,
|
||||
verbatim: "Future chat state"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user