fix(web): switch to plainText mode for composer due to glitching skill invocation in question tool - #7818
Conversation
Summary: - Add a plainText mode to ComposerPromptEditor: the value renders as raw text with no mention/skill/terminal-context chips and none of the inline-token plugins mounted. With no token nodes, collapsed and expanded cursor offsets coincide, so cursor mapping reduces to a raw clamp. The Lexical editor remounts when the mode flips, which also keeps undo history from leaking between an answer and the main draft. - Enable plainText in ChatComposer while a pending question is active: trigger menus (skills, slash commands, file paths) stay closed over answers, cursor state uses raw offsets, and composer state is re-derived from the regular draft when the question ends. Rationale: - Pending question responses only send plain answer strings; nothing is invoked. Rendering `$skill` syntax as tokens desynced Lexical cursor state (recursive update crashes), left the picker open after submit, and leaked answers into the next question. Treating the whole answer as plain text, as mobile already does, removes the bug class instead of special-casing skill tokens, and leaves the shared tokenizer and cursor logic untouched. - Alternative to the includeSkillTokens flag threading in PR pingdotgg#7812. Tests: - vp test run on composer-logic, composer-editor-mentions, ComposerPromptEditor, composerSubmission, and ComposerPendingUserInputPanel suites (77 passed) - web typecheck (tsgo) and vp lint on both changed files Closes pingdotgg#7805 AI-Assisted-By: Codex AI-Assisted: true AI-Agent: claude-code AI-Model: anthropic/claude-fable-5
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR introduces significant runtime behavior changes including editor remounting, focus management, and conditional plugin rendering for question-answer mode. The changes affect complex cursor and state management logic in core composer components and warrant human review. You can add or adjust custom eligibility rules. Learn more. |
There was a problem hiding this comment.
UI consistency review: one interaction regression found in apps/web/src/components/ComposerPromptEditor.tsx (editor remount on mode flip drops composer focus). Details inline.
Posted via Macroscope — UI Consistency
Summary: - Add a draftPromptRef in ChatComposer that always tracks the draft prompt; promptRef keeps meaning "what the editor shows" (the answer text while a question is open). - Ref-sync and pending-sync effects no longer clamp or reset the answer caret when the draft changes underneath an open question; the question-ended handoff reads the draft from the ref instead of a `prompt` effect dep. - Trait toggles and stash restore now write the parked draft without moving the answer caret or stealing focus; stash restore also appends to the actual draft instead of the visible answer text. - ComposerPromptEditor records focus ownership when the plainText flip unmounts the editor and refocuses the remounted instance, so a question opening or resolving mid-typing no longer drops focus. Rationale: - PR pingdotgg#7818 review bots (Cursor Bugbot, Macroscope) flagged two real regressions: draft writes yanked the caret to the end of the answer, and the keyed LexicalComposer remount silently dropped focus (closing the keyboard on mobile). - Kept the deliberate remount and restored focus across it instead of rewriting editor state in place; smaller change, same behavior. Tests: - vp test run src/components/ComposerPromptEditor.test.ts (5 passed) - tsc --noEmit on apps/web clean; oxlint on both files clean - Focus behavior not covered by jsdom tests (needs real browser focus semantics); not verified in a browser AI-Assisted-By: Codex AI-Assisted: true AI-Agent: claude-code AI-Model: anthropic/claude-fable-5
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fdea833. Configure here.
There was a problem hiding this comment.
One finding: the new plainText plugin gate also disables the non-token surround-selection typing behavior for question answers. Details inline.
Posted via Macroscope — UI Consistency
…wers Summary: - The focus restore after a plainText remount now places the caret at the end of the current value instead of the snapshot cursor, which was seeded from the previous mode's stale cursor prop. Both mode transitions settle the caret at the end anyway, so this removes the brief window where a keystroke could land at a stale offset. - ComposerSurroundSelectionPlugin is mounted in both modes: wrapping a selection by typing brackets/quotes is plain typing behavior, not token behavior. The plugin takes a plainText prop and uses raw cursor clamps in plain mode; the mention-boundary guard is skipped there so answer text that merely looks like a mention still wraps. Rationale: - Follow-up to PR pingdotgg#7818 bot re-review: Cursor Bugbot flagged the stale caret on mode remount, Macroscope flagged the surround-typing regression for question answers introduced by the plugin gate. Tests: - vp test run src/components/ComposerPromptEditor.test.ts (5 passed) - tsc --noEmit on apps/web clean; oxlint on both touched files clean AI-Assisted-By: Codex AI-Assisted: true AI-Agent: claude-code AI-Model: anthropic/claude-fable-5

Closes #7805
When a provider asks a question, the custom-answer composer reused the full prompt editor, so
$skillsyntax turned into skill tokens and opened the picker, even though question responses only ever send plain answer strings. That desynced Lexical cursor state (recursive update crashes), left the picker open after submit, and leaked the previous answer into the next question.This makes question answers plain text end to end, the way mobile already handles them. The prompt editor gets a
plainTextmode that renders the value as raw text with no inline-token plugins mounted; with no token nodes, collapsed and expanded cursor offsets coincide, so all cursor mapping reduces to a raw clamp. While a question is active, the chat composer enables that mode and keeps every trigger menu (skills, slash commands, file paths) closed over answers, then re-derives normal composer state from the regular draft when the question ends. The editor remounts when the mode flips, which also stops undo history from leaking between an answer and the main draft.Compared to #7812 (which this replaces), the shared tokenizer and cursor logic stay untouched, and the fix removes the bug class structurally instead of special-casing skill tokens. The trade-off is intentional: no mention/slash pickers inside question answers, matching mobile.
Tests:
Evidence:
Implemented with Anthropic Claude Fable 5 using Claude Code in T3 Code.
🤖 Generated with Claude Code
Note
Medium Risk
Touches composer cursor mapping, remount/focus, and draft vs answer state during pending questions—easy to regress caret, menus, or draft clobbering, but not auth or data-plane.
Overview
Stops pending-question answers from being tokenized as skills/mentions, which previously desynced Lexical cursor state, left pickers open, and leaked answers between questions.
ComposerPromptEditorgains aplainTextmode that inserts raw text, skips token plugins, and treats collapsed/expanded cursors as the same offset. The Lexical tree remounts when the mode flips (clearing undo history) and restores focus so a question opening mid-type does not drop keystrokes.While a question is active,
ChatComposerenables that mode, keeps trigger menus closed, and parks the real draft indraftPromptRefso trait/stash writes do not move the answer caret. When the question ends, it restores the draft with token-aware cursor/trigger state.Reviewed by Cursor Bugbot for commit 9674662. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix glitching skill invocation in question tool by adding
plainTextmode toComposerPromptEditorplainTextprop toComposerPromptEditorin ComposerPromptEditor.tsx. When true, the editor remounts (via a-plain/-richkey suffix), renders prompts as raw text without mention/skill/terminal-context token nodes, and disables token-aware cursor mapping and token-related plugins (arrow, backspace, paste, chip selection).ChatComposerin ChatComposer.tsx setsplainAnswerModewhen a pending question is active, passingplainText={true}andskills={[]}to the editor. Trigger menus are suppressed and cursor offsets are raw during this mode.draftPromptRefso they do not disturb the answer caret. When the question resolves, the draft is restored intopromptRefand token-aware behavior resumes.$setComposerEditorPromptnow requires aplainTextboolean parameter; all internal callers were updated. Editor remounts on mode toggle, with a layout effect restoring focus to end-of-text.Macroscope summarized 9674662.