Skip to content

Add selected local Review diff text to the chat draft with patch provenance #455

Closed

Description

@wheregmis

User problem and benefit

While reviewing an agent's changes, asking “why was this removed?” or “keep this part” requires copying patch text, switching to Chat, and reconstructing its filename and diff provenance. Opening the saved file loses deleted lines; editor excerpts cannot describe both sides of a change.

Add Add selection to chat to a loaded single-file local Review diff. Append an editable, safely fenced patch excerpt to the current draft, then focus Chat. This spends no model tokens until the user sends and performs no Git operation.

Source inspiration — code evidence, not app screenshots

Reviewed both repositories at pinned commits; neither source application was launched or visually inspected.

  • Synara: DiffPanel.tsx:1120–1157 accepts a selection only when both ends belong to the same file container, captures its path and text, and appends a reference to the active thread's composer. Borrow the direct selection-to-draft workflow, not its floating web toolbar.
  • T3 Code: AnnotatableCodeView.tsx:194–215 builds a diff comment and adds it to an explicit composerDraftTarget. buildDiffReviewComment:402–448 resolves selected diff lines, distinguishes old/new coordinates, and preserves change markers in a fenced diff. Borrow explicit destination and patch provenance; do not import its persistent annotation store or line-comment UI.

This is a smaller, feasible improvement than a new review-comment system: Threadlane already has selectable patches and guarded, undoable draft insertion.

Current Threadlane implementation

Inspected upstream main at c3a6f09107e742df36c55d97795ff95e903b3bb0, rather than assuming the automation worktree was current.

Proposed UX and states

  1. Entry point: reuse the familiar label Add selection to chat as a quiet labeled kit Button in the Review document toolbar and a Review-scoped Action reachable by keyboard. No hover-only control, new global shortcut, or automatic sending. Keep Find, Previous/Next file, whitespace toggle and Back available. At narrow widths, wrap or use a standard keyboard-operable overflow menu.
  2. Result: append Review diff excerpt: src/config.rs, a Displayed patch snapshot label, and the exact selected display text inside a safe diff fence. Preserve selected +/- markers, indentation, Unicode and partial lines. If Ignore whitespace is enabled, explicitly label the excerpt Whitespace-filtered patch snapshot. Do not invent old/new line numbers, infer omitted markers, claim it is an applicable patch, or reread disk to replace what the user selected. Existing draft text/images and clipboard remain untouched; one Undo removes the insertion.
  3. Availability: v1 supports a ready, nonempty single-file local Review patch only. Disable with an accessible textual reason for empty/whitespace-only selection, loading/error/parse-pending state, missing chat target, checkout mismatch, or more than 32 KiB of selected UTF-8 text (matching existing editor/terminal excerpt policy). Reject oversized selections without truncation. All changes says “Open a single-file diff to add an excerpt.” Binary/metadata-only output without textual hunks is not eligible. No implicit whole-file fallback.
  4. Identity and staleness: capture the source document, loaded request revision, file target, whitespace mode, checkout, selection and destination (work_dir, session_id) before toolbar/menu focus transfer. Revalidate on activation. File navigation, reload, whitespace change, checkout/session switch, closing Review or a replacement text document invalidates the capture. A changed target must never receive the excerpt; explain “The diff or chat changed. Select the text again.” If only focus moves to the command, retain the selection. A patch can age on disk after loading: snapshot labeling is deliberate, not a promise of live Git freshness.
  5. Accessibility: keyboard users must be able to select text in the diff and invoke the same command; verify the pinned TextView selection/focus APIs rather than assuming mouse selection suffices. Provide visible focus, accessible names and disabled reasons, with no color-only states. Escape closes the topmost menu/find layer and restores focus without insertion. On success focus the composer; on rejection keep the draft and source intact. Use semantic theme tokens and standard compact controls per the project Design Guides.

Out of scope: All changes/cross-file selections, GitHub PR review comments, commit/stash diff previews, editor-tab diff exports, persistent annotations, line remapping, extra Git reads, staging/discarding, sending/queueing/steering, and model permission changes.

Scoped implementation plan

  1. Shared document and formatting: extend crates/threadlane-ui-kit/src/review_find.rs / review.rs with selection capture, availability and a host-facing action for the existing ReviewDiffDocument; keep Git/session services outside the kit. Add bounded pure excerpt formatting, reusing safe_fence from editor.rs. Reuse the TextView ownership/focus-capture lessons in threadlane-ui-chat/src/quote_selection.rs, but do not reuse assistant-quote trimming for literal patch text. Use a patch-content identity distinct from the find-search generation (typing a search query alone must not pretend the patch changed).
  2. Guarded host request: in threadlane-ui-right-panel/src/view.rs and types.rs, derive eligibility from ReviewDiffRequest, ReviewDiffState, target and active checkout. Capture a narrowly scoped excerpt request and recheck the live document/request at consumption, including selections extending outside the diff. Clear captures through existing load/reset/navigation paths; do not materialize the whole patch on every render or selection notification.
  3. Draft handoff: subscribe in threadlane-ui-workspace/src/view.rs, following the Files-selection route, and call the existing append_draft_text_for. Keep source and destination validation at both boundaries. Leave chat draft storage, daemon/protocol, Git and the application binary shell unchanged.
  4. Shared preview and regression fixtures: update threadlane-ui-kit/examples/preview/review.rs for the controlled component contract. Add ready, filtered, empty, loading, stale and disabled fixtures; a preview without an explicit draft destination stays disabled and must not probe the filesystem. Add tests alongside the shared document, right-panel request guards and workspace/chat handoff tests.

Acceptance criteria and validation

  • Selected added, deleted and context text reaches the correct draft with path and snapshot/whitespace provenance, safe fences and exact content; no fabricated line numbers or silent truncation.
  • Existing draft/images/clipboard survive; Undo restores the previous draft. No send, queue, steer, Git mutation, filesystem write or new network request occurs.
  • Tests cover Unicode/CRLF/backticks, partial lines, 32 KiB boundaries, empty/oversized/binary selections, parse readiness and selections crossing outside the document.
  • Deterministic tests reject races across file/revision/whitespace/checkout/session changes, including identical session IDs in different projects. Focus-only transfer succeeds; find highlights/navigation never masquerade as user selection.
  • Mount GPUI tests under the initialized kit Root, use AppState::for_tests(), and verify mouse plus keyboard-only selection → command → composer → Undo, menu Escape, and disabled/error behavior. Test same-project different-worktree routing and active agent turns without sending.
  • During implementation run focused cargo nextest run for affected kit/right-panel/workspace/chat tests, cargo check -p threadlane-gpui, and git diff --check. Exercise the real window at minimum width, larger text and light/dark themes; check preview build/fixtures. These are proposed validations, not tests performed by this research run.

Duplicate screening

Reviewed all 106 existing issues, open and closed, searched titles/bodies/comments by diff, patch, excerpt, annotation, selected text, add-to-chat and review-comment concepts, and read nearby discussion. Rechecked before filing.

  • #416 covers editable file buffers and explicitly excludes Review/diff-side selection. This proposal supplies that missing source, not another editor excerpt implementation.
  • #405 and #320 cover assistant text and terminal output; their draft handoff behavior should be reused.
  • #434, #402 and #333 cover local diff find, adjacent-file navigation and whitespace filtering—not excerpts.
  • #156 concerns GitHub/PR integration. #271's two inspiration images were inspected: the visible Add to chat command is in a PR object menu, not a selected local-patch workflow. #160 concerns browser DOM annotations. No source-app visual inspection is implied.
  • #350 covers insertion identity hardening; reuse the project/session guard rather than reopen that issue.

Risks and tradeoffs

The main risk is selection loss or stale ownership during focus transfer, not Git plumbing; prove that behavior in real GPUI before expanding scope. Snapshot excerpts can omit surrounding context or include secrets, so require explicit insertion and a separate send, with no new telemetry/persistence channel. Restricting v1 to one file and omitting inferred line coordinates loses T3 Code's richer annotation precision, but avoids introducing a diff parser, annotation database and remapping machinery for a simple draft handoff.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions