diff --git a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift index 5d5b63c3bd7..762fda73f68 100644 --- a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift +++ b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatViewModel.swift @@ -646,7 +646,6 @@ public final class OpenClawChatViewModel { } self.isCompacting = true - self.lastCompactAt = Date() self.isLoading = true self.errorText = nil defer { @@ -665,6 +664,7 @@ public final class OpenClawChatViewModel { return } + self.lastCompactAt = Date() await self.bootstrap() } diff --git a/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift index 903dd6607ee..0f579c5d94b 100644 --- a/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift +++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatViewModelTests.swift @@ -221,6 +221,19 @@ private actor AsyncGate { } } +private actor AsyncCounter { + private var value: Int + + init(_ initialValue: Int = 0) { + self.value = initialValue + } + + func increment() -> Int { + self.value += 1 + return self.value + } +} + private actor TestChatTransportState { var historyCallCount: Int = 0 var sessionsCallCount: Int = 0 @@ -1033,6 +1046,43 @@ extension TestChatTransportState { #expect(await MainActor.run { vm.errorText } == "Please wait before compacting this session again.") } + @Test func compactTriggerAllowsImmediateRetryAfterFailure() async throws { + let history = historyPayload() + let attemptCount = AsyncCounter() + let (transport, vm) = await makeViewModel( + historyResponses: [history], + compactSessionHook: { _ in + let next = await attemptCount.increment() + if next == 1 { + throw NSError( + domain: "TestCompact", + code: 42, + userInfo: [NSLocalizedDescriptionKey: "temporary failure"]) + } + }) + try await loadAndWaitBootstrap(vm: vm) + + await MainActor.run { + vm.input = "/compact" + vm.send() + } + + try await waitUntil("first compact attempted") { + await transport.compactSessionKeys() == ["main"] + } + #expect(await MainActor.run { vm.errorText } == "Unable to compact the session. Please try again.") + + await MainActor.run { + vm.input = "/compact" + vm.send() + } + + try await waitUntil("second compact attempted") { + await transport.compactSessionKeys() == ["main", "main"] + } + #expect(await MainActor.run { vm.errorText } == nil) + } + @Test func bootstrapsModelSelectionFromSessionAndDefaults() async throws { let now = Date().timeIntervalSince1970 * 1000 let history = historyPayload()