Skip to content

Collapse large pastes; remove stale queued-message notice - #7

Merged
MathiTz merged 7 commits into
mainfrom
fix/tool-loop-tag-leaks-and-message-queue
Sep 20, 2026
Merged

MathiTz merged 7 commits into
mainfrom
fix/tool-loop-tag-leaks-and-message-queue

Conversation

@MathiTz

@MathiTz MathiTz commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #6 (already merged): two small composer/queueing UX fixes that landed on the same branch after that PR was merged, so they need their own PR.

Changes

  • Paste collapse (ui/tui.py): pasting more than 100 characters into the chat composer now collapses to a [LINES N] placeholder instead of dumping the raw text inline. The real content is tracked internally and substituted back in on submit, so the model still receives the full text. Duplicate same-line-count pastes in one draft get distinct placeholders ([LINES N], [LINES N#2], ...).
  • Queued-notice cleanup (ui/tui.py): the "📥 Queued (#N) — will run once the current task finishes" notice now gets removed from the chat log once that queued message is dequeued and starts running (or discarded, with its notice removed, if the run is cancelled). Previously it stayed in the log indefinitely even after being consumed.

Testing

Full test suite passes locally: PYTHONPATH=. .venv/bin/pytest tests/ -q → 70 passed.

Co-Authored-By: Warp agent@warp.dev

MathiTz and others added 7 commits August 23, 2026 01:45
Pasting something long (e.g. a stack trace, file content, or diff) used to
dump the entire text inline into the composer, making it unreadable and
pushing the actual prompt out of view.

- ChatComposer.on_paste: pastes over PASTE_COLLAPSE_THRESHOLD (100 chars)
  are collapsed to a "[LINES N]" placeholder instead of being inserted
  verbatim; shorter pastes are inserted as before.
- The real pasted text is tracked internally and substituted back in when
  the message is submitted (Enter/Ctrl+S), so the model still receives the
  full original content - only the on-screen composer is compressed.
- Same-line-count pastes within one draft get distinct placeholders
  (`[LINES N]`, `[LINES N#2]`, ...) so each expands back to its own text.
- Added tests in tests/test_composer.py covering collapse, the threshold
  boundary, expansion on submit, and disambiguation of duplicate placeholders.

Co-Authored-By: Warp <agent@warp.dev>
ChatPane now tracks each "📥 Queued (#N)" SystemMessage widget in
self._queued_notices, parallel to self.state.message_queue. When a queued
prompt is dequeued and starts its turn, the matching notice is removed from
the chat log instead of staying there indefinitely. Notices for prompts
discarded on cancellation are removed the same way.

Co-Authored-By: Warp <agent@warp.dev>
- ui/tui.py: add Escape keybinding to request_cancel and map
  tool_start/tool_done/tool_error/tool_progress to readable trace labels.
- main.py: break the agent tool loop on any tool execution error instead of
  letting the model retry blindly; keep plan-mode write rejection as a soft
  policy nudge so the model can recover with a real plan.
- core/workspace_tools.py: tighten the generic tool-leak guard so natural
  language mentioning "arguments"/"path"/"content" near HTML-like "<" is
  not treated as a malformed tool call.
- tests/test_workspace_tools.py: add regression test for the false-positive
  prose case.

Co-Authored-By: Warp <agent@warp.dev>
Revert the break-on-tool_error behavior in main.py. Malformed tool calls
and tool execution failures are now appended to the conversation history
as context so the model can self-correct on the next turn. The user
interrupts via Esc (and ctrl+c) only.

Add regression tests verifying the loop continues after a malformed tool
call and after a tool execution failure.

Co-Authored-By: Warp <agent@warp.dev>
ui/tui.py: on_trace_event now builds short, human-readable sentences for
tool_start/tool_done/tool_error instead of empty or key=value details. For
example:
  - tool.start → "about to run read_file on `scraper/base.py`"
  - tool.done → "read_file finished on `scraper/base.py`"
  - tool.error → "read_file failed on `scraper/base.py`: file does not exist"

main.py: include `path` in tool_done and tool_error trace payloads so the
UI can show the affected file/path.

tests/test_workspace_tools.py: regression tests already cover the
continue-after-error behavior.

Co-Authored-By: Warp <agent@warp.dev>
- ui/tui.py: cap conversation history passed to the model at the most recent
  8 turns so long sessions cannot drown out the latest user message.
- core/workspace_tools.py: add a system reminder to always answer the most
  recent user message, not earlier conversation turns.
- core/providers.py: reduce httpx default timeout from 120s to 30s so a stuck
  provider call returns faster and Esc/cancel feels responsive.

Co-Authored-By: Warp <agent@warp.dev>
@MathiTz
MathiTz merged commit a9fde0c into main Sep 20, 2026
1 check passed
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