Skip to content

Keep picked skills and pending uploads when native chat composers close - #26538

Merged
brennanb2025 merged 8 commits into
mainfrom
brennanb2025/nc-split-draft-fixes
Oct 8, 2026
Merged

brennanb2025 merged 8 commits into
mainfrom
brennanb2025/nc-split-draft-fixes

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

A picked skill could turn into ordinary text when a file finished uploading after the chat box closed. Local and SSH image pastes could also disappear when the composer closed before saving finished. Text appends discarded the saved editor document, and the composer still controlled some pending uploads even though the draft outlived it.

Reopening the chat now preserves picked skill chips and completed attachments. Every pending paste appears in the existing attachment row, including pastes that will become file references. Its remove button releases Send if saving stalls; removing an attachment or its workspace prevents a late result from adding it back.

What Changed

The existing draft-addition function appends text while preserving selected nodes. Normal store updates, delayed loading, and crash-journal replay all use that function. Pending file results keep their operation IDs until the attachment cache settles them into their owning draft, including its workspace owner. Pending local, SSH, and paired uploads survive composer teardown. Menu paste first checks for a supported clipboard image source; plain text registers no image operation or Send hold. Confirmed-image ownership starts before saving, independently of a thumbnail or image-input support; agents that use file references keep that presentation. The hidden pending state is removed: pending operations always use the existing chip and remove control, while file-reference agents still receive a path when saving succeeds. Desktop presence checks and saving share one source selector, including Windows single-file PNG/JPEG copies; file reads, decoding and existing limits remain in the save. Deferred paired previews recheck operation ownership before creating an object URL, so removal cannot leave a late thumbnail without an owner. Preview URLs remain owned by the composer. Unique operation IDs and per-scope composer lifetime prevent results from another composer being mistaken for current input.

These are the two independent fixes split out of #26054. Its draft-move behavior is excluded because the planned /clear redesign keeps one conversation; that follow-up is coming separately. This PR does not change /clear behavior.

Why

The draft store and pending-attachment cache already own unsent input. Fixing their append and completion paths preserves input even without a mounted editor, rather than adding protections to individual upload callers. There is no draft-move registry, new persisted field, or wire-format change.

Differences from the common pattern:

  • Intended: uploads can finish into an unmounted draft, because switching between chat and terminal views and answering prompt cards can close Orca's composer while keeping the draft.
  • Intended: pending operations stay in the existing renderer cache. Completion, failure, explicit removal, draft or workspace deletion, and renderer exit end ownership; they are not restored as unfinished uploads after restart. Direct filesystem saves do not universally have a deadline. Visible removal explicitly abandons the pending draft operation; it does not cancel a host filesystem promise. Host-side deadlines are deferred to a separate follow-up.

Linked Issue

N/A — maintainer follow-up from a native chat audit.

Visual Proof

A genuine native clipboard save completed while a permission card had replaced the composer. Answering the card restored the same conversation with its picked Review pill, suffix and image. Hidden macOS Electron QA used a hooks-off isolated profile and a stand-in provider; the held request forwarded the original host handler and returned its actual file. Protected-file hashes matched all three checkpoints; recorded processes and rig were cleaned up. Workspace switching also preserved the draft, but retained the composer and is separate evidence.

Before: the image is still saving beside the picked skill and suffix.

Pending save beside picked skill

The permission card replaces the composer while the save finishes.

Permission card replaces composer

After: the same conversation restores the skill pill, suffix and image.

Restored draft

A file-reference paste also shows the existing pending chip and remove control. In isolated OMP QA, removing it re-enabled Send; releasing the original native save afterward left the original question unchanged. Workspace switching preserved the same chat but does not establish a component unmount.

Removable pending reference paste

A plain-text app-menu paste preserved the question and kept Send enabled without registering an image. Hidden Electron QA used the production renderer menu event route and a genuine native text clipboard: the original presence handler returned false once and the save handler was never called. Physical menu interaction was not exercised.

Plain-text menu paste keeps Send enabled

Testing

  • I manually tested these changes locally
  • Automated tests added/updated

The final post-sync regression run passes 468 tests across 37 files. The manifest explicitly lists 38 files; one optional cleanup benchmark file/test remains skipped and is not counted as passing. Coverage includes picker-created skills with an unmounted PDF completion, delayed loading, crash replay, local/SSH/paired unmount survival, original draft/workspace ownership, reference-only agents, removal, failures, workspace deletion and remount identity. All clipboard suites are included, covering shared image-source selection, Windows single-file validation, destination routing, older hosts and authorization. Seventeen recorded behavior ablations fail the intended assertions when their fixes are removed.

Fresh web, node and CLI typechecks pass through the machine queue after the single final main sync and frozen install. All 22 final local static checks pass. Final post-sync review passed with zero P0–P2 findings. Final CI completed on the exact head. Full PR run 37776453242 passed all ten unit shards, both packaging jobs, relay integration and the required aggregate. The readiness PR run explicitly reused that identical successful source/workflow; the Headless Node run succeeded and reported no server inputs changed, so its platform lanes were skipped. Final confirmation found 16 passed checks, 21 skipped and no failures or pending checks. Skips are not passes; no end-to-end specs were selected. No lockfile changes are included.

Hidden macOS Electron evidence was captured on the source committed as d49d546 (true composer unmount with picked skill and native image), 4dbd128 (visible reference chip/removal) and 7b93b2d (plain-text menu paste). The final source has automated coverage for the subsequent shared desktop clipboard selector. The rigs used isolated hooks-off profiles and stand-in providers, forwarded original native handlers, and were cleaned up; protected-file hashes matched all three checkpoints. Physical native-menu input was not used.

Live SSH, a live paired server, mobile, Windows and Linux were not exercised manually. SSH/paired ownership and Windows clipboard sources have automated coverage. Existing peer formats and execution-host ownership are preserved.

Review

Round seven reviewed the final post-sync head 44330e9c2660452e349c54e818dd7896544d6761 and found zero P0–P2 findings. It reran 565 repository tests across 45 files and 93 earlier regression controls, verified the merge preserved the fixes, and downloaded/checked all five embedded screenshots. Earlier rounds corrected thumbnail-dependent ownership, reference-only paste ownership, invisible stalled operations, plain-text image feedback, previews created after removal, Windows file-source detection and two stale clipboard test fixtures. Host-side save deadlines remain deferred; no draft movement is included.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • Before/after screenshots or videos attached
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered
  • Required local checks and final CI completed and classified; skipped jobs are not passes

@brennanb2025

brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Native chat could lose a pasted image when its composer closed, and a completed file upload could flatten a picked skill into ordinary text or lose its original draft owner. This split preserves the stored editor document during text append and makes the existing pending cache complete accepted uploads into their owning draft after the composer closes.

Pending pastes now use the existing chip and remove control, including pastes that will become file references. Removing one releases Send and rejects late results. The seven review rounds verified these corrections:

  • R1: pending menu-image ownership starts before saving and survives missing or delayed thumbnails.
  • R2: local and SSH uploads survive composer closure for agents that use file references, retaining their original destination.
  • R3: pending reference pastes are visible and removable, so a stalled save cannot leave Send blocked without a way to abandon it.
  • R4: plain text creates no image-saving chip or Send hold; removed uploads create no late preview.
  • R5: one desktop source selector lets presence checks and saving agree on supported Windows copied-image files.
  • R6: two clipboard test setups now describe their native image formats; existing paired and nested SSH routing assertions are unchanged.
  • R7: fresh review of the final post-main-sync revision found zero P0–P2 issues and verified the merge preserved the fixes.

Draft movement and the planned same-conversation clear redesign are excluded. Host-side save deadlines remain deferred; removing a draft operation does not cancel the host promise.

Fresh final-head review at 44330e9 found zero P0–P2 issues and reran 565 repository tests plus 93 prior controls. Final local validation passed 468 tests, all 3 queued typechecks and 22 static checks; one optional benchmark stayed skipped and is not a pass. Seventeen behavior ablations recorded intended failures. Final CI completed on the exact head. Full PR run 37776453242 passed all ten unit shards, both packaging jobs, relay integration and the required aggregate. The readiness PR run explicitly reused that identical successful source/workflow; the Headless Node run succeeded and reported no server inputs changed, so its platform lanes were skipped. Final confirmation found 16 passed checks, 21 skipped and no failures or pending checks. Skips are not passes; no end-to-end specs were selected.

The five embedded captures show hidden macOS Electron with isolated profiles and stand-in providers: a native image finishes through a genuine composer unmount and returns with the picked skill; removing a reference paste releases Send and rejects its late result; plain-text menu-event paste keeps Send enabled. Captures are from the disclosed earlier heads. Live final-head/Windows/Linux/SSH/paired/mobile/real-provider/native-menu and concurrent-window behavior are unverified; final source and routing have automated coverage.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 8, 2026 12:41
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4cb83e0d-5580-457f-9669-c5290db326bc
📥 Commits

Reviewing files that changed from the base of the PR and between 7c50009 and 44330e9.

📒 Files selected for processing (33)
  • src/main/window/clipboard-agent-session-attachment-paste.test.ts
  • src/main/window/clipboard-image-source.test.ts
  • src/main/window/clipboard-image-source.ts
  • src/main/window/clipboard-ipc-handlers.test.ts
  • src/main/window/clipboard-ipc-handlers.ts
  • src/main/window/clipboard-runtime-owned-ssh-paste.test.ts
  • src/main/window/clipboard-windows-image-file.ts
  • src/renderer/src/components/native-chat/NativeChatComposer.paste-remount.test.tsx
  • src/renderer/src/components/native-chat/NativeChatComposer.tsx
  • src/renderer/src/components/native-chat/NativeChatComposerField.tsx
  • src/renderer/src/components/native-chat/native-chat-composer-draft-addition.test.ts
  • src/renderer/src/components/native-chat/native-chat-composer-draft-addition.ts
  • src/renderer/src/components/native-chat/native-chat-composer-draft-journal.ts
  • src/renderer/src/components/native-chat/native-chat-composer-draft-store.ts
  • src/renderer/src/components/native-chat/native-chat-composer-paste-options.ts
  • src/renderer/src/components/native-chat/native-chat-composer-upload-completion.test.tsx
  • src/renderer/src/components/native-chat/native-chat-draft-cache.ts
  • src/renderer/src/components/native-chat/native-chat-pending-attachment-cache.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending-attachment-cache.ts
  • src/renderer/src/components/native-chat/native-chat-prompt-document-text.test.ts
  • src/renderer/src/components/native-chat/native-chat-prompt-document-text.ts
  • src/renderer/src/components/native-chat/native-chat-prompt-document.ts
  • src/renderer/src/components/native-chat/native-chat-session-attachment-drop.ts
  • src/renderer/src/components/native-chat/use-native-chat-composer-attachments.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-composer-attachments.ts
  • src/renderer/src/components/native-chat/use-native-chat-composer-image-input.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-composer-paste-session-attachments.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-composer-paste.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-composer-paste.ts
  • src/renderer/src/components/native-chat/use-native-chat-external-attachments.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-menu-paste-lifetime.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-paste-lifetime.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-paste-lifetime.ts
💤 Files with no reviewable changes (1)
  • src/renderer/src/components/native-chat/native-chat-composer-draft-journal.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Clipboard image checks now use detected image sources, including validated Windows copied-image paths. Native chat paste operations create and track pending attachments across composer lifetimes, and reference settlement retains operation IDs. Draft additions update prompt-document content alongside text.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 44330

No actionable merge-blocking issue is established; the change is mergeable after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 32 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary change: preserving picked skills and pending uploads when the native chat composer closes.
Description check ✅ Passed The description covers the required sections, user impact, implementation, rationale, testing, visual proof, scope, and compatibility considerations. The Linked Issue section says N/A, but the descrip…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant