feat: materialize pasted/dropped chat images to server temp file paths (#635) - #754
Open
Shadowzzh wants to merge 1 commit into
Open
feat: materialize pasted/dropped chat images to server temp file paths (#635)#754Shadowzzh wants to merge 1 commit into
Shadowzzh wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #635
Summary
When a user pastes, drops, or picks an image in pi-web, the server now writes the received bytes to private temporary files and appends their absolute paths (numbered in attachment order) to the agent's message, matching the TUI's clipboard semantics. Inline image inputs are preserved unchanged for vision models, so each path is an additional, addressable, re-attachable artifact for local file/image tools.
Implementation
lib/image-materialization.ts(new):ImageAttachmentStorewrites each batch atomically under$TMPDIR/pi-web-clipboard-v1-<pid>-<rand>/batch-<rand>/, with per-image UUID filenames and extensions derived from the declared MIME type (client-supplied names/paths are never used). Directories use0700and files0600on POSIX. Cleanup is layered: an hourly GC expires the process's files after 24 h of inactivity (refreshed by new submissions, deferred while any session is busy or has queued messages), orphan directories older than 24 h whose owning PID no longer exists are collected on later uploads (skipping live owners, other users' directories and symlinks), and normal process exit removes everything.lib/rpc-manager.ts:prompt/steer/follow_upcommands materialize their images before dispatch and append the path annotation to the message. A batch is rolled back only when the submission is rejected before preflight acceptance; files survive provider failures after acceptance so follow-up work can reuse the referenced paths. Text-only messages allocate nothing.read-tool access), a browser E2E exercising picker/paste/drop on desktop and mobile widths, and a design doc (docs/image-attachments.md).Acceptance criteria
$TMPDIR), not just inline base64.read/file tools) for the attached image.0600perms, extension derived frommimeType, and a GC/cleanup mechanism prevents orphan accumulation.Design notes
pi-web-clipboard-*, deliberately distinct from the TUI'spi-clipboard-*, to avoid collisions when both run on the same host.Verification
ce18006(post-v0.9.0, pi-coding-agent 0.85.1) with no drift frommain.npx tsc --noEmitclean;npm run lintclean;npm test969/969 pass (16 new tests covering byte preservation, private permissions, batch isolation/rollback, GC & orphan collection, and the RPC preflight accept/reject lifecycle).e2e/image-attachments.mjs) runs in the CI e2e job and verifies readable server files at the SDK extension boundary without contacting a model provider.