fix: include selected text in follow-up context - #830
Conversation
PR Reviewer Guide 🔍(Review updated until commit dd8d7ee)Here are some key observations to aid the review process:
|
appergb
left a comment
There was a problem hiding this comment.
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:
-
[P1] Typed follow-ups reuse the previous turn's selection.
submit_qa_text_questiononly callscapture_selection_with_status()whenstate.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 onlystate.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_sessioncorrectly 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 seesSomeand reuses it.open_qa_panelclearing selection once (qa.rs:82-90) and the empty/cancel cleanup atqa_session.rs:1290-1306do not cover the normal successful multi-turn path. The newqa_followup_includes_new_selection_in_model_contexttest only callscompose_qa_user_contentdirectly 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. -
[P2] The Linux install warning survives desktop close/reopen and is not announced accessibly.
QaPanelonly updatesselectionWarningfor anidleevent when the field is present (QaPanel.tsx:159-166). Opening the panel emits anidlepayload withoutselection_warning(qa.rs:105-114). On desktop, closing emitschat-panel:closingand 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: triggerlinux_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 explicitselection_warning: nullin reset events, and add a lifecycle/component regression test. The dynamically inserted warning is also a plaindiv(QaPanel.tsx:397-400) with norole="status"/aria-live, so screen-reader users are not notified; please give the non-blocking update appropriate live-region semantics. -
[P2] Sanitized envelope text is double-escaped in the selection quote. The backend deliberately rewrites an injected boundary such as
</selected_text>to</selected_text>before storing the user message (qa_session.rs:11-20;polish.rs:1683-1709).splitSelectionUserreturns that encoded capture verbatim (QaPanel.tsx:567-573), and React then escapes its ampersand. ForA </selected_text> B & C < D, the rendered HTML isA &lt;/selected_text> B & C < D, so the user sees literal</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<replacement would corrupt an originally literal<) and add those tests.
Validation evidence on the current-beta synthetic merge:
- Conflict-free
git merge-tree --write-tree;git diff --checkpassed. - Full Rust library suite: 707 passed, 0 failed; focused
qa_: 21 passed; Linux reader tests: 2 passed. npm run buildpassed (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 beforebetaadvanced, 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.
|
收到,新改进将在不久推出 |
|
Persistent review updated to latest commit f718515 |
|
Persistent review updated to latest commit 07d10a2 |
|
Persistent review updated to latest commit 9e13f79 |
|
Persistent review updated to latest commit 3c9af35 |
|
Persistent review updated to latest commit a121919 |
…-ask-context # Conflicts: # openless-all/app/src-tauri/src/coordinator/qa_session.rs
|
Persistent review updated to latest commit 3b4da1b |
|
Persistent review updated to latest commit 3e02a6f |
|
Persistent review updated to latest commit dd8d7ee |
|
Persistent review updated to latest commit dd8d7ee |
User description
Summary
<selected_text>untrusted-content envelopewl-paste,xclip, orxselwhen none is installedRoot 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
Noneresult, so the UI could not tell users that a selection reader needed to be installed.Validation
cargo test --lib qa_ -- --nocapture— 22 passedcargo test --lib selection::linux_selection::tests -- --nocapture— 2 passednpm.cmd run build— passedgit diff --check— passedPR 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?"]File Walkthrough
9 files
Update imports and error monitorRewrite turn logic with session guardingAdd session-scoped resource managementAdd SelectionCaptureOutcome mockAdd capture_with_status and Linux tool detectionAdd selection_text field to QaChatMessageImplement message parsing and session event filteringAdd session_id and selection_warning to typesIntegrate session guarding and selection warning UI1 files
Refresh session id on open/close3 files
Update tests with selection_textUpdate test with selection_textTest helper functions for selection warnings5 files
Add linuxSelectionToolsMissing translationAdd linuxSelectionToolsMissing translationAdd linuxSelectionToolsMissing translationAdd linuxSelectionToolsMissing translationAdd linuxSelectionToolsMissing translation