mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
cb51cf7d3e
* feat(apps): adopt the system-notice family in Apple chat (OpenClawChatUI) Decode internal_system provenance and __openclaw history markers, classify once into message/notice/divider rows (web-parity kinds), render minimal hairline notice/divider SwiftUI rows, preserve metadata through history reconciliation, live transport, and the transcript cache, and align the transcript exporter with visible classification instead of leaking raw [System] prompts. * fix(apps): satisfy OpenClawKit periphery gate Remove the dead visibleMessages projection (rows path replaced its consumers) and annotate the provenance test-fixture initializer with the repo-standard periphery:ignore rationale. * fix(apps): refresh native i18n inventory after periphery cleanup
72 lines
2.6 KiB
Swift
72 lines
2.6 KiB
Swift
import Foundation
|
|
import OpenClawKit
|
|
import Testing
|
|
@testable import OpenClawChatUI
|
|
|
|
/// Tool-result diff metadata rides on `OpenClawChatMessage.details`; every
|
|
/// field-enumerating message rebuild must carry it or inline diffs silently
|
|
/// disappear after cache-warm reconciliation.
|
|
@Suite("ChatMessageDetailsPreservation")
|
|
struct ChatMessageDetailsPreservationTests {
|
|
private func toolResultMessage(id: UUID = UUID()) -> OpenClawChatMessage {
|
|
OpenClawChatMessage(
|
|
id: id,
|
|
role: "toolResult",
|
|
content: [
|
|
OpenClawChatMessageContent(
|
|
type: "text",
|
|
text: "Successfully replaced 1 block(s).",
|
|
mimeType: nil,
|
|
fileName: nil,
|
|
content: nil),
|
|
],
|
|
timestamp: 1,
|
|
toolCallId: "call-1",
|
|
toolName: "edit",
|
|
details: AnyCodable(["diff": AnyCodable("+1 added\n-1 removed")]))
|
|
}
|
|
|
|
private func systemNoticeMessage(id: UUID = UUID()) -> OpenClawChatMessage {
|
|
OpenClawChatMessage(
|
|
id: id,
|
|
role: "user",
|
|
content: [
|
|
OpenClawChatMessageContent(
|
|
type: "text",
|
|
text: "[System] gateway restarted",
|
|
mimeType: nil,
|
|
fileName: nil,
|
|
content: nil),
|
|
],
|
|
timestamp: 2,
|
|
provenance: OpenClawChatInputProvenance(
|
|
kind: "internal_system",
|
|
sourceTool: "restart-sentinel"))
|
|
}
|
|
|
|
@MainActor @Test func `decode pipeline keeps message details`() throws {
|
|
let payloadData = try JSONEncoder().encode([self.toolResultMessage(), self.systemNoticeMessage()])
|
|
let anyMessages = try JSONDecoder().decode([AnyCodable].self, from: payloadData)
|
|
let decoded = OpenClawChatViewModel.decodeMessages(anyMessages)
|
|
|
|
#expect(decoded.first?.details != nil)
|
|
#expect(decoded.last?.provenance?.sourceTool == "restart-sentinel")
|
|
}
|
|
|
|
@MainActor @Test func `canonical adoption keeps incoming details`() {
|
|
let incoming = self.toolResultMessage()
|
|
let existing = self.toolResultMessage()
|
|
|
|
let adopted = OpenClawChatViewModel.adoptingCanonicalMessage(incoming, over: existing)
|
|
|
|
#expect(adopted.id == existing.id)
|
|
#expect(adopted.details != nil)
|
|
|
|
let incomingNotice = self.systemNoticeMessage()
|
|
let adoptedNotice = OpenClawChatViewModel.adoptingCanonicalMessage(
|
|
incomingNotice,
|
|
over: self.systemNoticeMessage())
|
|
#expect(adoptedNotice.provenance == incomingNotice.provenance)
|
|
}
|
|
}
|