fix(chat): preserve attachment references from JSON RPC results (#1210)

Co-authored-by: M57 <41645758+Hy4ri@users.noreply.github.com>
This commit is contained in:
AlexDev_andM57 authored and GitHub committed 2026-09-22 14:26:06 +03:00
1 parent 799bb2959e
commit 83b2a8fa9b
4 files changed
+168 -4

No files matched your search

@@ -120,6 +120,100 @@ class ChatViewModelTest {
assertEquals("ws-local-1", merged.single().id)
}
@Test
fun mergeTranscriptWithLive_collapsesGatewayAttachmentContextCopy() {
val local =
ChatMessage(
id = "ws-local-attachment",
role = MessageRole.USER,
content = "What is the secret word in the attached file?",
timestamp = 100L,
)
val rest =
ChatMessage(
id = "rest-sess-attachment",
role = MessageRole.USER,
content =
"""
@file:files/agent-vault/hermes/attachments/note.txt
What is the secret word in the attached file?
--- Attached Context ---
📄 @file:files/agent-vault/hermes/attachments/note.txt (8 tokens)
```
THE_SECRET_WORD_IS_MANGO_8421
```
""".trimIndent(),
timestamp = 100L,
)
val merged = mergeTranscriptWithLive(listOf(rest), listOf(local))
assertEquals(1, merged.size)
assertEquals("ws-local-attachment", merged.single().id)
}
@Test
fun mapServerMessages_restOnlyAttachmentHidesGatewayContext() {
val ref = "@file:files/agent-vault/hermes/attachments/note.txt"
val persisted =
"""
$ref
What is the secret word in the attached file?
--- Attached Context ---
📄 $ref (8 tokens)
```
THE_SECRET_WORD_IS_MANGO_8421
```
""".trimIndent()
val mapped =
mapServerMessages(
sessionId = "session-1",
messages =
listOf(
SessionMessage(
id = 42,
role = "user",
content = JsonPrimitive(persisted),
timestamp = JsonPrimitive("100"),
),
),
offset = 0,
latestPaging = true,
liveMessages = emptyList(),
)
assertEquals(1, mapped.size)
assertEquals(
"""
$ref
What is the secret word in the attached file?
""".trimIndent(),
mapped.single().content,
)
assertFalse(mapped.single().content.contains("--- Attached Context ---"))
assertFalse(mapped.single().content.contains("THE_SECRET_WORD_IS_MANGO_8421"))
}
@Test
fun stripAttachmentRefLines_preservesUserAuthoredAttachedContextHeading() {
val authored =
"""
Explain this heading:
--- Attached Context ---
this is ordinary user-authored text
""".trimIndent()
assertEquals(authored, stripAttachmentRefLines(authored))
}
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
@@ -1981,6 +2075,34 @@ class ChatViewModelTest {
verify(exactly = 0) { HermesWsClient.sendMessage(any(), any(), any(), any()) }
}
@Test
fun sendMessage_rawJsonFileAttachmentRetainsReference() =
runTest {
val (viewModel, _) = createViewModelWithSession()
val uriString = "content://test/note"
val uri = mockk<Uri>()
val resolver = mockk<ContentResolver>()
mockkStatic(Uri::class)
every { Uri.parse(uriString) } returns uri
every { app.contentResolver } returns resolver
every { resolver.openInputStream(uri) } answers { "hello".byteInputStream() }
every { HermesWsClient.request(WsMethods.FILE_ATTACH, any(), any()) } returns
CompletableDeferred<Any?>(
buildJsonObject {
put("attached", true)
put("ref_text", "@file:attachments/note.txt")
},
)
viewModel.addAttachment(uriString, "note.txt", "text/plain", 5)
viewModel.sendMessage("Inspect file")
advanceUntilIdle()
verify {
HermesWsClient.sendMessage(any(), "@file:attachments/note.txt\n\nInspect file", any(), any())
}
}
@Test
fun sendMessage_laterGrowingAttachmentDoesNotPartiallyUploadEarlierAttachments() =
runTest {