fix: preserve image attachments in live and restored conversations

This commit is contained in:
2026-09-12 23:51:57 +08:00
parent 1d661f7a56
commit 03fc50f7a9
9 changed files with 347 additions and 10 deletions

View File

@@ -0,0 +1,56 @@
# Task: Fix model image delivery and sent attachment visibility
## Identity
- Task ID: 20260912-fix-image-delivery-d74b1f08
- Mode: Feature
- Branch: codex/20260912-fix-image-delivery-d74b1f08-fix-image-delivery
- Worktree: D:\Datas\OthersProjects\.codex-worktrees\makelore\20260912-fix-image-delivery-d74b1f08
- Base commit: 1d661f7a5695f0ef1364e1fae5874d106f855bd9
- Owner: codex
- Status: Ready for Integration
## Scope
- Diagnose the reported deepseek-flash image refusal and disappearance of sent image attachments.
- Fix Makelore's optimistic user messages and production Pi live/session image projection. Cover binary attachment reuse and renderer reload.
- one-api and Works Square remain read-only in this follow-up; no model-capability catalog or provider control changes were justified by the observations.
## Intent And Constraints
- Concurrent Task Gate and Planning Gate passed in this exclusively owned isolated worktree before edits. Read peer task scopes; no conflicting ownership was found.
- No subagents. No external inference, publishing, installation, main-branch changes or live-session mutation.
- The installed app is 1.4.7 with Pi 0.84.2. Preserve runtime version, Host API boundaries, original user history and pending unrelated work.
- Only task-owned project memory is updated. README describes the implemented behavior.
## Outcome
- Confirmed the affected persisted user message contains text and a PNG image (base64 length 7,616,308); the configured deepseek-flash model contains text/image. Both global and project image-block settings are absent.
- Used the installed runtime to restore a temporary local copy of the affected session and send to a loopback fixture. Its selected model retained text/image and the affected user message reached the fixture as text plus a complete image_url. Original history stayed untouched, and the temporary copy was removed. Only message types, sizes and model capability fields were reported; no secrets or private message bodies were captured in task artifacts.
- User confirmed that a new empty deepseek-flash conversation can recognize the same image. Old history includes prior omitted-image wording. Historical context influencing the model's denial is a supported inference; the original production HTTP exchange was not captured, so its exact earlier failure is not asserted. Current multimodal support and fresh-session operation are confirmed.
- Fixed the reproducible UI defect: PiConversationRuntime now includes uploaded image references in the optimistic user message, including image-only prompts. Production coding composition now wires projectImage to attachment storage for both live events and persisted sessions.
- Attachment storage uses a content address over MIME and bytes to reuse the original newly uploaded file across repeated Pi projections and application restarts. This digest replaces repeated large-file writes and determines whether writing is skipped; it introduces no separate integrity catalog. Existing randomly identified attachments remain readable.
- No model-name special case, forced vision flag, history deletion or prompt override was added.
## Verification
- Initial regression: `pnpm exec vitest run tests/unit/pi-conversation-runtime.test.ts -t 'keeps submitted image references' --maxWorkers=1` failed because the optimistic node contained text only, while the outgoing Pi RPC already contained the image.
- After fixing: composition image storage/projection wiring, event projector, session projector, conversation runtime and attachment routes: 35 tests passed.
- Final focused run: composition images, conversation runtime (text+image and image-only), real Agent Server process, managed capabilities and attachment facade: 17 tests passed. This includes the DeepSeek-compatible real HTTP image assertions for fresh and restored sessions.
- Updated Electron first-chat E2E passed against the final build. It covers binary upload, optimistic preview, replacement with a persisted message, and image display after a complete renderer reload.
- `pnpm run typecheck`, targeted ESLint, `pnpm run build:vite` and `git diff --check` passed. Build retains existing chunk-size, mixed-import and outdated Browserslist notices.
- Additional Main TypeScript check does not pass on this repository baseline. Compiler comparison using the recorded base versions of all three changed production files: 61 diagnostics before, 61 after, zero new diagnostics. These existing errors are outside the image fix.
- Final self-review inspected the source/test/README diff against the recorded base; no temporary diagnostic code, private session copy, dependencies or build artifacts are included.
## Follow-ups
- Merge and package this fix before expecting it in the installed 1.4.7 client; this feature task does not install or release a client build.
- For the affected old conversation, a new conversation is the user-confirmed working route. No original messages were removed or rewritten.
## Promotion Candidates
- Target: `20-architecture/data-flow.md`. Record the now-connected Pi live/session image projection into Main-owned attachment storage and the reuse of stored bytes during hydration.
- Evidence: production composition regression, projector tests and Electron reload E2E.
- Future impact: prevents future refactors from testing only injected projection callbacks while omitting production composition wiring.
- Semantic conflicts: none identified; follows the accepted Main-owned binary attachment contract.
- Human confirmation required: no product-direction decision; promote through the normal Integration Gate when this fix is merged.