Skip to content

fix: include selected text in follow-up context - #830

Merged
H-Chris233 merged 9 commits into
Open-Less:betafrom
H-Chris233:codex/fix-selection-ask-context
Jul 16, 2026
Merged

fix: include selected text in follow-up context#830
H-Chris233 merged 9 commits into
Open-Less:betafrom
H-Chris233:codex/fix-selection-ask-context

Conversation

@H-Chris233

@H-Chris233 H-Chris233 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

User description

Summary

  • include the freshly captured selection in every Selection Ask turn instead of only the first turn
  • wrap selected text in the existing <selected_text> untrusted-content envelope
  • distinguish an empty Linux selection from all supported selection readers being unavailable
  • show a localized, non-blocking prompt to install wl-paste, xclip, or xsel when none is installed
  • keep QA message rendering compatible with both the new envelope and the legacy message format

Root cause

The QA coordinator captured a new selection for every recording, but message assembly injected it only when the conversation history was empty. Follow-up selections were therefore discarded before the provider request was built on both Windows and Linux.

The Linux reader also collapsed command-not-found, reader failure, and an empty selection into the same None result, so the UI could not tell users that a selection reader needed to be installed.

Validation

  • cargo test --lib qa_ -- --nocapture — 22 passed
  • cargo test --lib selection::linux_selection::tests -- --nocapture — 2 passed
  • npm.cmd run build — passed
  • git diff --check — passed

PR Type

Bug fix, Enhancement


Description

  • Include selected text in every QA turn, not just first

  • Wrap selected text in XML envelope for security

  • Distinguish empty Linux selection from missing tools

  • Show localized warning when no Linux selection tool installed

  • Guard stale sessions with session_id to prevent race conditions


Diagram Walkthrough

flowchart LR
  User["User action"] --> Capture["capture_qa_turn_selection"]
  Capture --> Check{"session_id valid?"}
  Check -->|Yes| Compose["compose_qa_user_content"]
  Compose --> Answer["answer_qa_question_text"]
  Check -->|No| Discard["discard turn"]
  Check -->|No| Warning["show linux_selection_warning?"]
Loading

File Walkthrough

Relevant files
Enhancement
9 files
coordinator.rs
Update imports and error monitor                                                 
+19/-11 
qa_session.rs
Rewrite turn logic with session guarding                                 
+596/-444
resources.rs
Add session-scoped resource management                                     
+28/-2   
selection.rs
Add SelectionCaptureOutcome mock                                                 
+12/-0   
selection.rs
Add capture_with_status and Linux tool detection                 
+132/-35
types.rs
Add selection_text field to QaChatMessage                               
+3/-0     
qaMessage.ts
Implement message parsing and session event filtering       
+60/-0   
types.ts
Add session_id and selection_warning to types                       
+6/-0     
QaPanel.tsx
Integrate session guarding and selection warning UI           
+36/-10 
Bug fix
1 files
qa.rs
Refresh session id on open/close                                                 
+25/-13 
Tests
3 files
llm_gemini.rs
Update tests with selection_text                                                 
+3/-0     
polish.rs
Update test with selection_text                                                   
+1/-0     
qaMessage.test.ts
Test helper functions for selection warnings                         
+83/-0   
I18n
5 files
en.ts
Add linuxSelectionToolsMissing translation                             
+1/-0     
ja.ts
Add linuxSelectionToolsMissing translation                             
+1/-0     
ko.ts
Add linuxSelectionToolsMissing translation                             
+1/-0     
zh-CN.ts
Add linuxSelectionToolsMissing translation                             
+1/-0     
zh-TW.ts
Add linuxSelectionToolsMissing translation                             
+1/-0     

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd8d7ee)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected

@appergb appergb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logical verdict: REQUEST_CHANGES (submitted as a COMMENTED review).

I reviewed exact head 24ad458ce930d2f51fde3df5d4f1ff4fcc60f76d and also synthesized/tested its conflict-free merge with current beta eb099c4f411af546628408e30482d23b2fcc6bf8 (merge tree 74d7321a9fbb952130ef8506c3aa0899875854c8). The Linux reader status split itself is sound: only three NotFound attempts produce ToolsUnavailable; any installed reader that produces no usable text yields NoSelection, and the first text result wins. Voice-to-voice selection refresh is also correct. The following issues block approval:

  1. [P1] Typed follow-ups reuse the previous turn's selection. submit_qa_text_question only calls capture_selection_with_status() when state.selection.is_none() (qa_session.rs:105-109). A successful answer reads that value to compose the user message (qa_session.rs:432-440) but finishes by changing only state.phase (qa_session.rs:574); it does not consume or clear the selection. Therefore, after the first typed answer, a second typed submission skips capture and wraps the old selection again. The same stale reuse occurs for voice -> typed: begin_qa_session correctly clears and captures every voice turn (qa_session.rs:598,632-640), but its selection remains after a successful answer, so the next typed turn sees Some and reuses it. open_qa_panel clearing selection once (qa.rs:82-90) and the empty/cancel cleanup at qa_session.rs:1290-1306 do not cover the normal successful multi-turn path. The new qa_followup_includes_new_selection_in_model_context test only calls compose_qa_user_content directly and never constructs the two-turn state transition, so it passes while the advertised typed lifecycle remains broken. Please make selection turn-scoped (recapture/replace it for every typed turn, with the platform focus handling needed to capture the external selection, or consume it after composition as appropriate) and add stateful typed -> typed and voice -> typed regression tests that prove selection B, not A, reaches the second provider request.

  2. [P2] The Linux install warning survives desktop close/reopen and is not announced accessibly. QaPanel only updates selectionWarning for an idle event when the field is present (QaPanel.tsx:159-166). Opening the panel emits an idle payload without selection_warning (qa.rs:105-114). On desktop, closing emits chat-panel:closing and hides the persistent webview (lib.rs:2322-2340); qa:dismiss, the only listener that clears this React state (QaPanel.tsx:218-227), is emitted only on Android. Reproduction from this lifecycle: trigger linux_selection_tools_missing, close with X/Esc/hotkey, then reopen; the old warning remains even though the new panel state has not reported missing tools (and can remain after tools are installed). Please clear the warning deterministically on every reset/open/desktop close, or include an explicit selection_warning: null in reset events, and add a lifecycle/component regression test. The dynamically inserted warning is also a plain div (QaPanel.tsx:397-400) with no role="status"/aria-live, so screen-reader users are not notified; please give the non-blocking update appropriate live-region semantics.

  3. [P2] Sanitized envelope text is double-escaped in the selection quote. The backend deliberately rewrites an injected boundary such as </selected_text> to &lt;/selected_text> before storing the user message (qa_session.rs:11-20; polish.rs:1683-1709). splitSelectionUser returns that encoded capture verbatim (QaPanel.tsx:567-573), and React then escapes its ampersand. For A &lt;/selected_text> B & C < D, the rendered HTML is A &amp;lt;/selected_text&gt; B &amp; C &lt; D, so the user sees literal &lt;/selected_text> instead of the selected </selected_text>. Raw < and & remain safely text-escaped by React, and the legacy # 选区原文 form parses safely, but the new canonical format loses display fidelity for exactly the boundary-like content the sanitizer changes. There is no frontend parser/rendering test for canonical, escaped, or legacy input. Please preserve a display-safe copy or use an unambiguous reversible encoding/decoding contract (a naive global &lt; replacement would corrupt an originally literal &lt;) and add those tests.

Validation evidence on the current-beta synthetic merge:

  • Conflict-free git merge-tree --write-tree; git diff --check passed.
  • Full Rust library suite: 707 passed, 0 failed; focused qa_: 21 passed; Linux reader tests: 2 passed.
  • npm run build passed (Android IPC boundary, TypeScript, Vite); QA markdown test and all eight package contract scripts passed, including current beta's macOS speech-usage-description contract.
  • npm audit: 0 vulnerabilities. cargo audit: exit 0 with 18 allowed warnings. Gitleaks on the exact PR commit: no leaks.
  • GitNexus compare reports 11 files / 45 changed symbols, 9 affected execution flows, high risk, which matches the lifecycle-sensitive scope above.
  • All five remote checks on exact head are green: Android cargo check, Linux checks, macOS checks, Windows checks, and pr_agent_job. Those jobs ran before beta advanced, so the local current-beta merge-tree run above supplies the updated regression evidence.

Please keep the PR at exact head or call out a new head for re-review after addressing the three lifecycle/display gaps.

@H-Chris233

Copy link
Copy Markdown
Collaborator Author

收到,新改进将在不久推出

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit f718515

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 07d10a2

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 9e13f79

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 3c9af35

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit a121919

…-ask-context

# Conflicts:
#	openless-all/app/src-tauri/src/coordinator/qa_session.rs
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 3b4da1b

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 3e02a6f

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd8d7ee

@H-Chris233
H-Chris233 marked this pull request as ready for review July 16, 2026 05:25
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd8d7ee

@H-Chris233
H-Chris233 merged commit 07f394f into Open-Less:beta Jul 16, 2026
6 checks passed
@H-Chris233
H-Chris233 deleted the codex/fix-selection-ask-context branch August 3, 2026 08:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants