mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 13:44:11 +00:00
fix: handle iOS global agent transcripts
This commit is contained in:
@@ -95,6 +95,7 @@ import Testing
|
||||
@Test func mapsSessionMessageEventToSessionMessage() {
|
||||
let payload = AnyCodable([
|
||||
"sessionKey": AnyCodable("agent:main:main"),
|
||||
"agentId": AnyCodable("main"),
|
||||
"messageId": AnyCodable("msg-1"),
|
||||
"messageSeq": AnyCodable(7),
|
||||
"message": AnyCodable([
|
||||
@@ -119,6 +120,7 @@ import Testing
|
||||
switch mapped {
|
||||
case let .sessionMessage(message):
|
||||
#expect(message.sessionKey == "agent:main:main")
|
||||
#expect(message.agentId == "main")
|
||||
#expect(message.messageId == "msg-1")
|
||||
#expect(message.messageSeq == 7)
|
||||
#expect(message.message?.role == "assistant")
|
||||
|
||||
@@ -326,17 +326,20 @@ public struct OpenClawChatEventPayload: Codable, Sendable {
|
||||
|
||||
public struct OpenClawSessionMessageEventPayload: Codable, Sendable {
|
||||
public let sessionKey: String?
|
||||
public let agentId: String?
|
||||
public let message: OpenClawChatMessage?
|
||||
public let messageId: String?
|
||||
public let messageSeq: Int?
|
||||
|
||||
public init(
|
||||
sessionKey: String?,
|
||||
agentId: String? = nil,
|
||||
message: OpenClawChatMessage?,
|
||||
messageId: String?,
|
||||
messageSeq: Int?)
|
||||
{
|
||||
self.sessionKey = sessionKey
|
||||
self.agentId = agentId
|
||||
self.message = message
|
||||
self.messageId = messageId
|
||||
self.messageSeq = messageSeq
|
||||
|
||||
@@ -8,7 +8,21 @@ extension OpenClawChatViewModel {
|
||||
mainSessionKey: self.resolvedMainSessionKey)
|
||||
}
|
||||
|
||||
static func matchesCurrentSessionKey(incoming: String, current: String, mainSessionKey: String) -> Bool {
|
||||
func matchesCurrentSessionKey(incoming: String, agentId: String?, current: String) -> Bool {
|
||||
Self.matchesCurrentSessionKey(
|
||||
incoming: incoming,
|
||||
agentId: agentId,
|
||||
current: current,
|
||||
mainSessionKey: self.resolvedMainSessionKey)
|
||||
}
|
||||
|
||||
static func matchesCurrentSessionKey(
|
||||
incoming: String,
|
||||
agentId: String? = nil,
|
||||
current: String,
|
||||
mainSessionKey: String)
|
||||
-> Bool
|
||||
{
|
||||
let incomingNormalized = incoming.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
||||
let currentNormalized = current.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
||||
if incomingNormalized == currentNormalized {
|
||||
@@ -23,6 +37,13 @@ extension OpenClawChatViewModel {
|
||||
{
|
||||
return true
|
||||
}
|
||||
if Self.matchesSelectedAgentGlobal(
|
||||
incoming: incomingNormalized,
|
||||
agentId: agentId,
|
||||
current: currentNormalized)
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -36,4 +57,14 @@ extension OpenClawChatViewModel {
|
||||
return (current == "main" && incoming == "agent:main:main") ||
|
||||
(incoming == "main" && current == "agent:main:main")
|
||||
}
|
||||
|
||||
private static func matchesSelectedAgentGlobal(incoming: String, agentId: String?, current: String) -> Bool {
|
||||
guard incoming == "global",
|
||||
let selectedAgentId = agentId?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased(),
|
||||
!selectedAgentId.isEmpty
|
||||
else {
|
||||
return false
|
||||
}
|
||||
return current == "agent:\(selectedAgentId):global"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1302,7 +1302,7 @@ public final class OpenClawChatViewModel {
|
||||
|
||||
private func handleSessionMessageEvent(_ payload: OpenClawSessionMessageEventPayload) {
|
||||
if let sessionKey = payload.sessionKey,
|
||||
!self.matchesCurrentSessionKey(incoming: sessionKey, current: self.sessionKey)
|
||||
!self.matchesCurrentSessionKey(incoming: sessionKey, agentId: payload.agentId, current: self.sessionKey)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1092,6 +1092,75 @@ extension TestChatTransportState {
|
||||
}
|
||||
}
|
||||
|
||||
@Test func appendsGlobalSessionUserMessageForSelectedAgent() async throws {
|
||||
let now = Date().timeIntervalSince1970 * 1000
|
||||
let (transport, vm) = await makeViewModel(
|
||||
sessionKey: "agent:work:global",
|
||||
historyResponses: [historyPayload(sessionKey: "agent:work:global")])
|
||||
|
||||
await MainActor.run { vm.load() }
|
||||
try await waitUntil("bootstrap history loaded") { await MainActor.run { vm.messages.isEmpty } }
|
||||
|
||||
transport.emit(
|
||||
.sessionMessage(
|
||||
OpenClawSessionMessageEventPayload(
|
||||
sessionKey: "global",
|
||||
agentId: "work",
|
||||
message: OpenClawChatMessage(
|
||||
role: "user",
|
||||
content: [
|
||||
OpenClawChatMessageContent(
|
||||
type: "text",
|
||||
text: "global transcript",
|
||||
mimeType: nil,
|
||||
fileName: nil,
|
||||
content: nil),
|
||||
],
|
||||
timestamp: now),
|
||||
messageId: "msg-global-work",
|
||||
messageSeq: 1)))
|
||||
|
||||
try await waitUntil("selected agent global transcript visible") {
|
||||
await MainActor.run {
|
||||
vm.messages.count == 1 &&
|
||||
vm.messages.first?.role == "user" &&
|
||||
vm.messages.first?.content.first?.text == "global transcript"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test func ignoresGlobalSessionUserMessageForDifferentAgent() async throws {
|
||||
let now = Date().timeIntervalSince1970 * 1000
|
||||
let (transport, vm) = await makeViewModel(
|
||||
sessionKey: "agent:work:global",
|
||||
historyResponses: [historyPayload(sessionKey: "agent:work:global")])
|
||||
|
||||
await MainActor.run { vm.load() }
|
||||
try await waitUntil("bootstrap history loaded") { await MainActor.run { vm.messages.isEmpty } }
|
||||
|
||||
transport.emit(
|
||||
.sessionMessage(
|
||||
OpenClawSessionMessageEventPayload(
|
||||
sessionKey: "global",
|
||||
agentId: "main",
|
||||
message: OpenClawChatMessage(
|
||||
role: "user",
|
||||
content: [
|
||||
OpenClawChatMessageContent(
|
||||
type: "text",
|
||||
text: "wrong global transcript",
|
||||
mimeType: nil,
|
||||
fileName: nil,
|
||||
content: nil),
|
||||
],
|
||||
timestamp: now),
|
||||
messageId: "msg-global-main",
|
||||
messageSeq: 1)))
|
||||
|
||||
try await Task.sleep(nanoseconds: 100_000_000)
|
||||
#expect(await MainActor.run { vm.messages.isEmpty })
|
||||
}
|
||||
|
||||
@Test func ignoresAgentMainSessionMessageForDifferentCurrentMainAlias() async throws {
|
||||
let now = Date().timeIntervalSince1970 * 1000
|
||||
let (transport, vm) = await makeViewModel(historyResponses: [historyPayload()])
|
||||
|
||||
Reference in New Issue
Block a user