Skip to content

pearl th-01c714: bracketed-paste + flatten prompt so multi-line task arrives as one TUI submission - #58

Merged
brentrager merged 1 commit into
mainfrom
th-01c714-paste-fix
May 20, 2026
Merged

pearl th-01c714: bracketed-paste + flatten prompt so multi-line task arrives as one TUI submission#58
brentrager merged 1 commit into
mainfrom
th-01c714-paste-fix

Conversation

@brentrager

Copy link
Copy Markdown
Contributor

Summary

After PR #57 (pearl th-7fdfa9) fixed the literal-`j` newline encoding bug in `tmux_driver::send`, newlines correctly survive into the TUI's input box — but the `smooth-code` TUI submits on every `\n`. A 13-line task prompt was therefore arriving as 13 separate `You:` submissions instead of one cohesive task (evidence: `~/.smooth/bench-runs/80c092b0/python-affine-cipher.pane.log`).

Two-pronged fix:

  • tmux_driver::send — added `-p` to `tmux paste-buffer` for bracketed-paste mode. Bracketed-paste-aware TUIs treat embedded newlines as soft newlines (insert), not Enter (submit). For applications that don't enable bracketed-paste mode, tmux strips the markers — safe upgrade.
  • lib::build_prompt + human_driver::flatten_for_tui — reformatted the bench task prompt to a single line (semicolon-joined), and added `flatten_for_tui` (collapses `\n` to ` | `) applied to the seed prompt and every driver-model follow-up before `driver.send`. Belt-and-suspenders so the harness doesn't depend on the receiver honoring bracketed paste.

Tests added

  • `lib::build_prompt_is_single_line` — asserts no `\n`/`\r` in the bench task prompt.
  • `human_driver::flatten_for_tui_*` (5 cases) — passthrough, trimming, empty input, blank-line dropping, multi-line → pipe-separated.

Verification (single-task smoke)

`cargo run --release -p smooai-smooth-bench -- score-tui --pr --th-binary $(which th) --task-limit 1 --debug --output /tmp/bench/smoke3.json --budget-usd 2`

New pane log (`~/.smooth/bench-runs/83791c18/python-affine-cipher.pane.log`) shows the seeded prompt landing as one `You:` block containing the full prompt:

```
System:
Type a message to get started. /help for commands.

You:
You are solving Aider Polyglot task `affine-cipher` (python). Working directory: the current directory. Files present: INSTRUCTIONS.md, affine_cipher.py, affine_cipher_test.py. Your job: read
INSTRUCTIONS.md and the test file to understand the requirements; edit the source file(s) so `python3 -m pytest -q` passes every test; do not modify test files; stop once the tests pass — do not keep
iterating. Constraints: use only the standard library for the language; keep the implementation idiomatic and concise.
```

(The visual line-wrapping above is just the pane width — it's a single TUI submission. The previous buggy run had 13 separate `You:` blocks for the same prompt.)

The task itself still failed (affine-cipher under single-shot constraints is hard), but the harness is now sending what we intend.

Which strategy did the heavy lifting?

Hard to say in isolation — both shipped together. The flattened prompt is the load-bearing fix because it makes the question moot regardless of whether the TUI honors bracketed paste. The `-p` flag is the cleaner long-term fix if/when smooth-code adds bracketed-paste handling; for now it's a free safety belt.

Test plan

  • `cargo fmt -- --check`
  • `cargo clippy -p smooai-smooth-bench --all-targets` (0 errors)
  • `cargo build` (clean)
  • `cargo test -p smooai-smooth-bench --lib` (130 passed)
  • Single-task `score-tui --pr --task-limit 1 --debug` smoke — pane log shows one `You:` block per submission

🤖 Generated with Claude Code

…description arrives as one TUI submission

After th-7fdfa9 fixed the literal-`j` newline encoding bug in
`tmux_driver::send`, newlines correctly survive into the TUI's
input box — but the TUI submits on every `\n`, so a 13-line task
prompt arrived as 13 separate `You:` submissions instead of one
(evidence: ~/.smooth/bench-runs/80c092b0/python-affine-cipher.pane.log).

Two-pronged fix:

1. tmux_driver::send: add `-p` to `paste-buffer` for bracketed
   paste. Bracketed-paste-aware TUIs distinguish pasted content
   from typed input and keep embedded newlines as soft newlines.
   For applications that never enable bracketed-paste mode, tmux
   strips the markers — safe upgrade.

2. lib::build_prompt: flatten to a single line (semicolon-joined
   clauses). Add human_driver::flatten_for_tui which collapses
   `\n` to ` | `; apply it to the initial seed prompt and every
   driver-model follow-up before driver.send. Belt-and-suspenders
   so the harness doesn't depend on the receiver honoring
   bracketed paste.

Tests added: build_prompt_is_single_line, flatten_for_tui_*
(5 cases).

Smoke-verified with `score-tui --pr --task-limit 1 --debug`:
new pane log shows the seeded prompt as one `You:` block
containing the full prompt text, not 13 separate blocks.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented May 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d045c8a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@smooai/smooth Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@brentrager
brentrager merged commit d937223 into main May 20, 2026
1 of 2 checks passed
brentrager added a commit that referenced this pull request May 21, 2026
… false-pass guard + investigate disk-edit gap (#59)

Fix five score-tui harness bugs uncovered in PR #58's failed sweep
(2/18 pass, $0.00 cost across the board, tasks 15-18 errored with
"no server running on /private/tmp/tmux-501/default"):

Bug 1 — tmux server dies mid-sweep: per-task socket isolation via
`tmux -L <socket>`. Each driver gets a private server-of-one so
sibling Drops can't kill us. New `per_socket_isolation_survives_
sibling_drop` test pins the behaviour.

Bug 2 — cost $0.00: scrape the TUI's `spend: $X.XXX` from a
visible-only final pane capture and thread it into TuiTaskOutcome.
Hand-rolled scanner (no new regex dep). Smoke run produces
$0.0190 instead of $0.0000.

Bug 3 — Rust false-positive passes: hash every editable file
before+after the agent runs; refuse to mark solved=true on a
no-edit workspace. Belt-and-suspenders: `score_work_dir` sets
`CARGO_TARGET_DIR` per task so the user-config'd shared cargo
target dir can no longer leak a previously-compiled test binary
across runs. `--allow-no-edit-passes` opts out for debugging.

Bug 4 — agents do work but tasks fail: tied to Bug 5. With
full-scrollback capture wired, the LLM-as-human driver now sees
the agent's tool calls and edits instead of asking the same
question 10 times. Root cause for the affine-cipher smoke
specifically appears to be smooth-code's `list_files` tool hanging
mid-run + the forgiving XML parser emitting "malformed tool-call"
notes — both outside this bench's scope, but the bench now reports
the failure honestly (FAIL with $0.019 of real spend) instead of
silently mis-attributing it.

Bug 5 — capture-pane blind to scrollback: `capture()` now passes
`-S -` + `-J` so the full pane history is returned. A 64KiB
budget front-truncates the oldest content with a marker prepended.
A new `capture_visible()` keeps the cheap visible-only path for
the cost-scraping case.

151 lib tests pass (10 new: per-socket isolation, full-scrollback
vs visible-only capture, truncation budget+newline-snap, cost
extraction across 7 status-line shapes, hash-based editable-file
detection across the 5 langs that need it).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
brentrager added a commit that referenced this pull request Jul 4, 2026
* th-3be564: multimodal Big Smooth chat — attach + see images (Phases 1-3)

Web: paperclip/paste/drag-drop image+PDF attachments, composer thumbnails,
inline <img> render in the user bubble. Sends {content, attachments:[{name,
mime,data(base64)}]} — optional field, text-only sends unchanged.

Daemon: chat routes accept attachments, content-address bytes under
~/.smooth/attachments/, build a multimodal turn via Message::user_with_images.
Image turns auto-route to gemini-2.5-flash-lite (cheap vision, native PDF);
text-only keeps the default model; explicit body.model still wins. Documents
are marker-only (Phase 4 does real ingest).

Engine: pins smooth-operator-core rev b43c04fe (multimodal Message content +
image_url wire + AgentConfig::with_user_images; PRs #58/#62). Decoupled from
core main's post_call change (th-10eb50) — see Cargo.toml comment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* th-1b14d6: PDFs read natively — route as data: media to gemini-flash

Verified live against llm.smoo.ai: a PDF sent as a data:application/pdf
image_url part to gemini-2.5-flash-lite is read natively (answered a
question about the file). So PDF 'documents' need no separate ingest —
add an AttachmentKind::Pdf that rides the same multimodal/vision path as
images (is_model_media). docx/xlsx stay marker-only (docling microVM is
the future upgrade).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant