The gateway replays the full transcript over a new socket on session.resume unless omit_messages is set; mobile hydrates history via REST in parallel, so the replay is redundant. When a reconnect lands mid-stream, the replayed message gets a fresh UUID and dedup can't collapse the 90% orphan with the 100% replay (different ids + content), leaving a duplicate bubble. Desktop already sends omit_messages: true; mirror that in both resume paths (ChatViewModel + NotificationReplyReceiver) and pin it in the exact-map test verifies. Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
@@ -128,7 +128,7 @@ open class NotificationReplyReceiver : BroadcastReceiver() {
|
|||||||
HermesWsClient
|
HermesWsClient
|
||||||
.request(
|
.request(
|
||||||
WsMethods.SESSION_RESUME,
|
WsMethods.SESSION_RESUME,
|
||||||
mapOf("session_id" to storedSessionId),
|
mapOf("session_id" to storedSessionId, "omit_messages" to true),
|
||||||
timeoutMs = REPLY_TIMEOUT_MS,
|
timeoutMs = REPLY_TIMEOUT_MS,
|
||||||
).await() as? Map<*, *>
|
).await() as? Map<*, *>
|
||||||
val runtimeSessionId =
|
val runtimeSessionId =
|
||||||
|
|||||||
@@ -1952,7 +1952,7 @@ class ChatViewModel(
|
|||||||
viewModelScope.launch(ioDispatcher) {
|
viewModelScope.launch(ioDispatcher) {
|
||||||
wsClient.send(
|
wsClient.send(
|
||||||
WsMethods.SESSION_RESUME,
|
WsMethods.SESSION_RESUME,
|
||||||
mapOf("session_id" to sessionId),
|
mapOf("session_id" to sessionId, "omit_messages" to true),
|
||||||
onSent = { id ->
|
onSent = { id ->
|
||||||
trackSessionRequest(
|
trackSessionRequest(
|
||||||
id = id,
|
id = id,
|
||||||
|
|||||||
+5
-1
@@ -306,7 +306,11 @@ class NotificationReplyReceiverTest {
|
|||||||
Thread.sleep(500)
|
Thread.sleep(500)
|
||||||
|
|
||||||
verify {
|
verify {
|
||||||
HermesWsClient.request(WsMethods.SESSION_RESUME, match { it["session_id"] == "session-abc" }, any())
|
HermesWsClient.request(
|
||||||
|
WsMethods.SESSION_RESUME,
|
||||||
|
match { it["session_id"] == "session-abc" && it["omit_messages"] == true },
|
||||||
|
any(),
|
||||||
|
)
|
||||||
HermesWsClient.request(
|
HermesWsClient.request(
|
||||||
WsMethods.PROMPT_SUBMIT,
|
WsMethods.PROMPT_SUBMIT,
|
||||||
match { it["session_id"] == "runtime-session-abc" },
|
match { it["session_id"] == "runtime-session-abc" },
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ class ChatViewModelTest {
|
|||||||
verify {
|
verify {
|
||||||
HermesWsClient.send(
|
HermesWsClient.send(
|
||||||
WsMethods.SESSION_RESUME,
|
WsMethods.SESSION_RESUME,
|
||||||
mapOf("session_id" to "session-from-notification"),
|
mapOf("session_id" to "session-from-notification", "omit_messages" to true),
|
||||||
any(),
|
any(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1271,7 +1271,13 @@ class ChatViewModelTest {
|
|||||||
.isEmpty(),
|
.isEmpty(),
|
||||||
)
|
)
|
||||||
|
|
||||||
verify { HermesWsClient.send(WsMethods.SESSION_RESUME, mapOf("session_id" to "session-456"), any()) }
|
verify {
|
||||||
|
HermesWsClient.send(
|
||||||
|
WsMethods.SESSION_RESUME,
|
||||||
|
mapOf("session_id" to "session-456", "omit_messages" to true),
|
||||||
|
any(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1894,7 +1900,7 @@ class ChatViewModelTest {
|
|||||||
verify {
|
verify {
|
||||||
HermesWsClient.send(
|
HermesWsClient.send(
|
||||||
WsMethods.SESSION_RESUME,
|
WsMethods.SESSION_RESUME,
|
||||||
mapOf("session_id" to "session-456"),
|
mapOf("session_id" to "session-456", "omit_messages" to true),
|
||||||
any(),
|
any(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user