From 19093112ce82659e15bd87ad42f2319e06aed24b Mon Sep 17 00:00:00 2001 From: scoootscooob Date: Tue, 24 Mar 2026 10:39:49 -0700 Subject: [PATCH] Chat UI: tighten compact transport handling --- .../Chat/IOSGatewayChatTransport.swift | 7 ++++++ .../OpenClawChatUI/ChatViewModel.swift | 7 ++++-- .../OpenClawKitTests/ChatViewModelTests.swift | 25 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/apps/ios/Sources/Chat/IOSGatewayChatTransport.swift b/apps/ios/Sources/Chat/IOSGatewayChatTransport.swift index 297811d3ee7..264d76dc961 100644 --- a/apps/ios/Sources/Chat/IOSGatewayChatTransport.swift +++ b/apps/ios/Sources/Chat/IOSGatewayChatTransport.swift @@ -46,6 +46,13 @@ struct IOSGatewayChatTransport: OpenClawChatTransport, Sendable { _ = try await self.gateway.request(method: "sessions.reset", paramsJSON: json, timeoutSeconds: 10) } + func compactSession(sessionKey: String) async throws { + struct Params: Codable { var key: String } + let data = try JSONEncoder().encode(Params(key: sessionKey)) + let json = String(data: data, encoding: .utf8) + _ = try await self.gateway.request(method: "sessions.compact", paramsJSON: json, timeoutSeconds: 10) + } + func requestHistory(sessionKey: String) async throws -> OpenClawChatHistoryPayload { struct Params: Codable { var sessionKey: String } let data = try JSONEncoder().encode(Params(sessionKey: sessionKey)) diff --git a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift index ac2592eff6e..858e2fc89ba 100644 --- a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift @@ -637,8 +637,11 @@ public final class OpenClawChatViewModel { do { try await self.transport.compactSession(sessionKey: self.sessionKey) } catch { - self.errorText = error.localizedDescription - chatUILogger.error("session compact failed \(error.localizedDescription, privacy: .public)") + self.errorText = "Unable to compact the session. Please try again." + let nsError = error as NSError + chatUILogger.error( + "session compact failed domain=\(nsError.domain, privacy: .public) code=\(nsError.code, privacy: .public) details=\(String(describing: error), privacy: .private)" + ) return } diff --git a/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift index d29fb8a7320..fd357a2d16a 100644 --- a/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift @@ -84,6 +84,7 @@ private func makeViewModel( sessionsResponses: [OpenClawChatSessionsListResponse] = [], modelResponses: [[OpenClawChatModelChoice]] = [], resetSessionHook: (@Sendable (String) async throws -> Void)? = nil, + compactSessionHook: (@Sendable (String) async throws -> Void)? = nil, setSessionModelHook: (@Sendable (String?) async throws -> Void)? = nil, setSessionThinkingHook: (@Sendable (String) async throws -> Void)? = nil, initialThinkingLevel: String? = nil, @@ -95,6 +96,7 @@ private func makeViewModel( sessionsResponses: sessionsResponses, modelResponses: modelResponses, resetSessionHook: resetSessionHook, + compactSessionHook: compactSessionHook, setSessionModelHook: setSessionModelHook, setSessionThinkingHook: setSessionThinkingHook) let vm = await MainActor.run { @@ -964,6 +966,29 @@ extension TestChatTransportState { #expect(await transport.lastSentRunId() == nil) } + @Test func compactTriggerShowsGenericErrorMessageOnFailure() async throws { + let history = historyPayload() + let (transport, vm) = await makeViewModel( + historyResponses: [history], + compactSessionHook: { _ in + throw NSError( + domain: "TestCompact", + code: 42, + userInfo: [NSLocalizedDescriptionKey: "backend details should not leak"]) + }) + try await loadAndWaitBootstrap(vm: vm) + + await MainActor.run { + vm.input = "/compact" + vm.send() + } + + try await waitUntil("compact attempted") { + await transport.compactSessionKeys() == ["main"] + } + #expect(await MainActor.run { vm.errorText } == "Unable to compact the session. Please try again.") + } + @Test func bootstrapsModelSelectionFromSessionAndDefaults() async throws { let now = Date().timeIntervalSince1970 * 1000 let history = historyPayload()