# refactor\(web\): multiple-model sends live in their own hook · PR \#23094 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/23094)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: merged

Source repository: pingdotgg/t3code

Source branch: refactor/split3-send-multimodel

Target branch: refactor/split3-send-plan

Head commit: 70d001c0c38d5e2eaf823da1e55d66b35777684b

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/23094)

[Commits](https://git.cafe/pingdotgg/t3code/pull/23094/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/23094/diffs?format=markdown)

## Description

---

Third layer of splitting `useComposerSend`.

The multiple-model start and its recovery move into `useMultipleModelSend`. Recovery means keeping failed models selected and restoring the prompt, either into this composer or through the "Restore prompt" toast. The hook owns its start command, `navigate`, and the fan-out selection atom, so ChatView no longer passes `setMultipleModelSelections`. Building a turn's attachments (upload records, or inlined data URLs) is now the plain `prepareTurnAttachments` in `chatViewSend.ts`. Both the single-thread and multiple-model paths use it.

| | before | after |
|---|---|---|
| `useComposerSend.ts` lines | 1,553 | 1,377 |
| `useComposerSend` input fields | 77 | 76 |

Render boundaries are unchanged.

Tested in this worktree's dev server (isolated `.t3`, throwaway git repo as the project) with the whole stack applied: plain send from a draft (new thread), send with an image, queued follow-up and Ctrl+Enter steer during a running turn, resume of a stopped run, plan refinement and "Implement in a new thread" (legacy plan mode on), and a two-model start (two threads, two worktrees). All replies arrived and nothing errored. Also ran `apps/web` typecheck, lint on changed files (only the pre-existing `prefer-set-has` warning in `useComposerSend.ts` remains) and the React Compiler coverage test for changed files (0 bailouts).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

