fix(tui): expand paste placeholders at submit time#149
Merged
Conversation
handle_paste stores large pastes in paste_contents and inserts a [Pasted ~N lines #K] placeholder, but nothing ever read the store back: PromptInputState::take() returned the composer text verbatim, so the model received the literal placeholder instead of the pasted content. take() now rebuilds each placeholder from its stored content and expands it before returning; the placeholder format lives in one helper shared with handle_paste so the two cannot drift. clear() drops stored contents (placeholders live in text, so once text is cleared they are unreachable) while paste_counter stays monotonic to keep stale placeholder ids from colliding after undo. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Fixes a TUI prompt-composer correctness issue where large clipboard pastes were replaced by [Pasted ~N lines #K] markers and the real content was stored, but submission (PromptInputState::take()) returned the marker text verbatim—silently dropping the pasted content.
Changes:
- Extracts placeholder formatting into
paste_placeholder()so insertion and later expansion share the exact same format. - Updates
PromptInputState::take()to expand placeholders back to their stored paste content before clearing input state. - Adds tests for placeholder expansion (single/multiple), deletion behavior, and clearing paste storage.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+3161
to
3166
| // Placeholders live in `text`, so once that is gone the stored paste | ||
| // contents are unreachable. `paste_counter` stays monotonic so a | ||
| // stale placeholder (e.g. restored via undo) can never collide with | ||
| // a later paste's id. | ||
| self.paste_contents.clear(); | ||
| } |
Comment on lines
+3174
to
3183
| let mut text = std::mem::take(&mut self.text); | ||
| for (id, content) in &self.paste_contents { | ||
| let placeholder = paste_placeholder(content.lines().count(), *id); | ||
| if text.contains(&placeholder) { | ||
| text = text.replace(&placeholder, content); | ||
| } | ||
| } | ||
| self.clear(); | ||
| text | ||
| } |
This was referenced Jul 15, 2026
BunsDev
added a commit
that referenced
this pull request
Jul 15, 2026
…urn (#166) * fix(query): recover announce-then-stop stalls instead of ending the turn The model sometimes announces work and then ends the turn with stop_reason end_turn and zero tool calls ("Writing the CLI uninstall module now." — then nothing). Both provider paths treated end_turn as authoritative, so the loop fired Stop hooks and returned EndTurn; the issue #149 placeholder made the empty variant visible but nothing made either variant recoverable. Users had to keep typing "continue". Mirror the max_tokens recovery pattern: when a round ends end_turn with no tool calls and its text is empty or closes on an imminent-action announcement, inject a continuation nudge as a user message and keep looping. Bounded at STALL_RECOVERY_LIMIT (2) per user turn; the counter resets whenever a tool round actually executes. The intermediate TurnComplete is suppressed while a nudge is pending, exactly like an in-budget max_tokens recovery. Deliberate handoffs (questions, "let me know…", "I'll wait for your review.") never trigger recovery, and COVEN_CODE_DISABLE_STALL_RECOVERY=1 turns the whole mechanism off. The announcement heuristic works on the final sentence-like chunk, skipping punctuation debris from dotted identifiers (`main.rs`.), and is deliberately cheap to false-positive: the nudge tells the model to state the final outcome if the work is already done, so a wrong guess costs one bounded round-trip. Observed transcripts from the stalled session are pinned as unit tests for both the stall and non-stall (completion/handoff) shapes. fixes #165 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(query): honor documented =1 contract for the stall-recovery kill switch Review follow-up: stall_recovery_enabled() checked env presence, so COVEN_CODE_DISABLE_STALL_RECOVERY=0 also disabled recovery. Parse the value with feature_gates::is_env_truthy so only 1/true/yes/on disable, matching the documented contract and the repo's gate convention. Refs #165 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Uberration
pushed a commit
to Uberration/meatycoven-code
that referenced
this pull request
Jul 18, 2026
…en#125) Adds a discoverable `/steer <message>` command, gated behind a new off-by- default `steer` Cargo feature (build with `--features steer`). Behavior: - While a turn is in flight: queue the message; it auto-runs after the current turn, mirroring the existing Enter-while-busy queueing (issue OpenCoven#149). - When idle: submit the message immediately via the auto-submit path. Implementation reuses the proven queued_messages + pending_auto_submit mechanisms, so no new turn-dispatch logic is introduced. The command is registered in PROMPT_SLASH_COMMANDS (feature-gated) for palette/help discoverability, handled in the CLI main loop, and added to the prompt_slash_commands_covers_registry allow-list (like /handoff, /stats). Verified: builds with and without the feature; the coverage test passes in both configurations; /steer appears in the command palette when enabled. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Large pastes into the TUI composer (>=3 lines or >150 chars) are replaced with a
[Pasted ~N lines #K]placeholder and the real content is stored inpaste_contents"for retrieval at submit time" — but no retrieval existed.PromptInputState::take()returned the composer text verbatim, so submitted messages carried the literal placeholder and the pasted content was silently dropped. Observed in practice: multiple user pastes arriving at the model as[Pasted ~1 lines #N].Changes
PromptInputState::take()expands every placeholder back to its stored content before returning; the submitted text and prompt history now carry the real paste.paste_placeholder(), shared byhandle_pasteandtake(), so the insert and expand sides cannot drift.clear()dropspaste_contents(oncetextis cleared the placeholders are unreachable);paste_counterstays monotonic so a stale placeholder restored via undo can never collide with a later paste's id.clear()drops the store.Verification
From
src-rust/:cargo check --workspace— cleancargo clippy --workspace --all-targets -- -D warnings— cleancargo test --package claurst-tui prompt_input— 5 new tests pass alongside existing paste testscargo fmt --all— applied (unrelated drift inclaude_cli.rsexcluded from this branch)🤖 Generated with Claude Code