[Repo Assist] fix(chat): persist attachment metadata in sidecar for history reload#615
Conversation
Closes #453 Root cause: when SendMessageAsync sends a message with attachments, the display text is built locally with zero-width-space chip markers but only the trimmed text (without markers) is sent to the gateway. On history reload or app restart, the gateway returns only the trimmed text; the chip markers are gone and attachment chips disappear. Fix: - Add attachment-sidecar.json (alongside tool-metadata.json) that persists per-thread attachment display metadata (filename + isImage) keyed by trimmed text and send timestamp. - On SendMessageAsync, when attachments are present, record a sidecar entry before sending. - On LoadHistoryAsync, for each user message, match against the sidecar by text + 24-hour timestamp window and re-inject chip markers. - Pasted/spoofed markers without a sidecar entry are not affected. Tests added: - SendMessageAsync_WithAttachment_RecordedInSidecar - SendMessageAsync_WithImageAttachment_RecordedAsImageInSidecar - LoadHistoryAsync_WithMatchingSidecarEntry_InjectsAttachmentChips - LoadHistoryAsync_WithNoSidecarEntry_DoesNotModifyText - HydrateAttachmentsFromSidecarLocked_PastedMarkerText_NotHydrated Also isolate CreateProvider to per-test temp directory to prevent cache cross-contamination between tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Codex review: needs changes before merge. Reviewed May 31, 2026, 9:55 PM ET / 01:55 UTC. Summary Reproducibility: yes. Source inspection shows the underlying bug path: attachments render from local chip text while history reloads rebuild from trimmed gateway text, and the patch findings are directly source-reproducible from the added sidecar write and hydrate paths. Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Keep the sidecar concept, but store only minimized attachment metadata plus a non-reversible match key or stable message id, and commit sidecar entries only for sends accepted by the gateway. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows the underlying bug path: attachments render from local chip text while history reloads rebuild from trimmed gateway text, and the patch findings are directly source-reproducible from the added sidecar write and hydrate paths. Is this the best way to solve the issue? No. A local sidecar is a reasonable narrow direction, but this implementation should not persist plaintext message content or save metadata before the gateway accepts the send. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 6d14b00f6cfc. Label changesLabel changes:
Label justifications:
Evidence reviewedSecurity concerns:
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
🤖 This is an automated pull request from Repo Assist.
Closes #453
Summary
Attachment chips (file/image indicators) in the chat timeline disappear after a history reload, session switch, or app restart. This PR fixes the root cause and adds 5 new tests covering the persistence and rehydration path.
Root Cause
SendMessageAsyncappends zero-width-space chip markers (\u200B📎 filename) to the local display text, but only the trimmed text (without markers) is sent to the gateway. On history reload, the gateway returns the trimmed text only — attachment chips are lost.Fix
OpenClawChatDataProvider.csattachment-sidecar.json(written alongsidetool-metadata.json) storing per-thread attachment display metadata: filename,IsImageflag, trimmed text, and send timestamp.SendMessageAsync: when attachments are present, record a sidecar entry before dispatching to the gateway.LoadHistoryAsync: for eachrole=usermessage, callHydrateAttachmentsFromSidecarLocked— matches by text equality + 24-hour timestamp window, then re-injects\u200B📎/\u200B🖼️chip markers.DisposeAsync: flush sidecar to disk.Spoof protection: A message that looks like chip marker text but has no matching sidecar entry gets no additional chips injected.
Trade-offs
Test Status
OpenClaw.Tray.Tests —
GITHUB_ENVenv-file infrastructure failure is pre-existing; tests still run and pass.New tests all pass:
SendMessageAsync_WithAttachment_RecordedInSidecarSendMessageAsync_WithImageAttachment_RecordedAsImageInSidecarLoadHistoryAsync_WithMatchingSidecarEntry_InjectsAttachmentChipsLoadHistoryAsync_WithNoSidecarEntry_DoesNotModifyTextHydrateAttachmentsFromSidecarLocked_PastedMarkerText_NotHydratedAlso isolated
CreateProviderto a per-test temp directory, preventing sidecar/cache cross-contamination between tests.OpenClaw.Shared.Tests: 8 pre-existing failures unrelated to this change (path resolution, MCP host tests).