feat(chat): lead the composer bottom row with the attach buttons#180
Conversation
The paperclip (and folder) buttons sat after the flex-1 control strip, so they landed in the middle of the row — between the profile/harness/model pickers and the send button. Attachment is the composer's primary left-side affordance, so the row now runs attach · folder · controls · trailing · send: the attach buttons come first and the control strip keeps its flex-1 growth, pushing trailing + send to the far right exactly as before. Pure reorder — no change to the attach handlers, drag-and-drop, or paste ingress.
tangletools
left a comment
There was a problem hiding this comment.
🟢 Value Audit — sound
| Verdict | sound |
| Concerns | 0 (none) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 44.7s (2 bridge agents) |
| Total | 44.7s |
💰 Value — sound
Pure JSX reorder that moves the AgentComposer attach/folder buttons to lead the bottom row (far left), ahead of the flex-1 control strip — correct, minimal, and in the grain of the component; ship.
- What it does: Reorders children of the composer's bottom flex row in src/chat/agent-composer.tsx:465-559 so the attach (paperclip) and folder buttons render before the
flex min-w-0 flex-1control strip instead of after it. Net layout: attach · folder · controls (profile/harness/model/effort) · trailing · send, with trailing+send still pinned right by the strip's flex-1 growth. Doc comment updated; no handler, - Goals it achieves: Conventional chat-composer layout: attachment is the primary left-side affordance (Claude/ChatGPT pattern), so the paperclip belongs at the far left rather than stranded mid-row between the model picker and send. Previously the attach buttons rendered after the flex-1 strip, landing awkwardly in the middle of the row.
- Assessment: Good on its merits. Verified against the real file: the row container keeps
items-end gap-2(src/chat/agent-composer.tsx:465), the control strip keepsflex-1(:521) so right-side pinning is preserved, and the moved blocks are byte-identical aside from position. AgentComposer is authored in this repo (exported from ./agent-composer at src/chat/index.ts:44-47; no AgentComposer exists in @tangle- - Better / existing approach: None — this is the right approach. Checked for an existing
leadingslot or layout primitive: the component exposes onlycontrolsandtrailingslots (agent-composer.tsx:521-535), so a JSX reorder is the minimal correct change; adding aleadingslot would be disproportionate machinery for a built-in button pair. No equivalent composer exists in @tangle-network/ui to extend (grep of node_modu - Model: opencode/kimi-for-coding/k2p7
- Bridge attempts: 1
🎯 Usefulness — sound
A clean JSX reorder that moves the attach/folder buttons ahead of the growing control strip so the paperclip leads the bottom row; no logic, handler, or contract changes, and the flex layout still pins send to the far right.
- Integration: AgentComposer is the canonical composer exported from src/chat/index.ts:44 and is exercised by agent-composer.test.tsx, AgentComposer.stories.tsx, and downstream apps (gtm-agent). The reorder touches only the render order inside the existing bottom-row flex container (src/chat/agent-composer.tsx:465-568); every caller sees the new layout with zero prop/API changes, so reachability is unchanged and
- Fit with existing patterns: Fits the codebase grain precisely. The bottom row was already a single
flex items-end gap-2with oneflex-1growth element; this change only reorders children within that established pattern. Leading with the primary attach affordance on the left matches the convention used by ChatGPT/Claude/most agent composers and aligns with the doc comment's stated intent. No competing layout pattern exist - Real-world viability: Holds across all prop combinations: with/without
onAttach(buttons conditionally render), with/withoutonAttachFolder, with thecontrolsoverride slot (still rendered inside the sameflex-1wrapper), with/withouttrailing, and in the busy/Stop-button state. Because the attach buttons areshrink-0and only the control strip hasflex-1, the right-edge pinning of trailing+send is preser - Model: opencode/zai-coding-plan/glm-5.2
- Bridge attempts: 1
No concerns — sound change, no better or existing approach found. ✅
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
✅ No Blockers —
|
| glm | kimi-code | aggregate | |
|---|---|---|---|
| Readiness | 92 | 95 | 92 |
| Confidence | 65 | 65 | 65 |
| Correctness | 92 | 95 | 92 |
| Security | 92 | 95 | 92 |
| Testing | 92 | 95 | 92 |
| Architecture | 92 | 95 | 92 |
Reviewer score is advisory once the run is complete and the verdict has no blockers.
Full multi-shot audit completed 1/1 planned shots over 1 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 1 changed files. Global verifier still owns final merge decision.
🟡 LOW No visual/DOM-order regression test for the composer bottom row — src/chat/agent-composer.tsx
This PR's entire payload is a child-order change inside
<div className="flex items-end gap-2">. The existing suite (agent-composer.test.tsx) asserts only behavior (paste/drop/submit/retry) via role queries — nothing pins the left→right sequence attach·folder·controls·trailing·send, so a future regression that re-splits the row would pass silently. Not introduced by this PR (gap is pre-existing), but it is the class of change most in need of a layout assertion. Cheap fix: add a test that renders with onAttach + controls and asserts the paperclip button's previousElementSibling is null (i.e., it is the first focusable in the row), or a Playwright snapshot.
tangletools · 2026-07-16T06:49:12Z · trace
tangletools
left a comment
There was a problem hiding this comment.
✅ Approved — 1 non-blocking finding — 2d7e639b
Full multi-shot audit completed 1/1 planned shots over 1 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 1 changed files. Global verifier still owns final merge decision.
Full immutable report for this review: trace
Summary comment for this run: full summary
tangletools · 2026-07-16T06:49:12Z · immutable trace
What
Move the
AgentComposerattach (paperclip) and folder buttons to the left of the bottom control row, ahead of the control strip.The bottom row now runs, left → right:
Previously the attach buttons rendered after the
flex-1control strip, so the paperclip ended up mid-row between the model picker and the send button. Attachment is the composer's primary left-side affordance, so it now leads.Details
flex-1growth, sotrailing+ the send button stay pinned to the far right exactly as before.controls/trailingslots.Before / after
Before:
[ controls … ] 📎 📁 [model] ⬆After:
📎 📁 [ controls … ] [model] ⬆Verified rendering in a downstream app (gtm-agent) build.