In AI chat, users interact with both the assistant and any tool UIs it renders. Most tool UIs treat this relationship as incidental: a tool UI appears, the user clicks something, done. We treat it as foundational. The assistant, the tool UI, and the user form a collaborative triad.
The assistant contextualizes, interprets, and narrates. The tool UI provides structure that prose cannot: sortable tables, precise controls, rich media. Neither replaces the other.
Found 8 React auth libraries on GitHub. Here are the top results by recent activity:
| next-auth↗ | 19,420 | +342↑ | 86 | MIT |
| passport↗ | 847 | -12↓ | 124 | MIT |
| auth0-react↗ | 3,210 | +89↑ | 23 | MIT |
| firebase-auth↗ | 562 | +8↑ | 45 | Apache-2.0 |
| clerk-sdk↗ | 1,580 | +156↑ | 31 | MIT |
Which one would you recommend for a Next.js app?
I recommend next-auth. It's purpose-built for Next.js, has by far the most stars, and was updated most recently. Want me to show you setup instructions?
The assistant introduces the tool UI, the user scans it and asks a follow-up, the assistant answers by referencing specific rows. This is the triadic loop.
Every Tool UI has a primary role:
Information: Display data (tables, cards, charts). The focus is on comprehension rather than interaction.
Decision: Capture consequential choices (approve/reject, send/cancel). These require clear options and receipts that prove what happened.
Control: Adjust parameters without commitment (filters, sort orders, date ranges). Changes are reversible.
State: Expose internal activity (progress indicators, status logs, loading states).
Some tool UIs combine roles. A data table with row actions is "information with control." When combining, the primary role should dominate.
Tool UIs live in chat: narrow widths, variable heights, mixed with prose.
If the assistant can't point at something later, you lose half the value of rendering it.
id: Identifies this specific tool UI in the conversation ("the preview above", "that table").assetId / row IDs / option IDs: Identify real objects ("that link", "row 4", "the merge option").Prefer stable IDs derived from your backend (database IDs, canonical URLs) over array indexes or UUIDs generated at render time. When something can be acted on, it should have an ID the assistant can cite.
When a user takes an action with consequences, the tool UI should transition to a receipt state that confirms what happened. This gives the user proof and gives the assistant something to reference later.
How would you like to handle the duplicate contacts?
Done. I merged 12 duplicate contacts. You can undo this from Settings → Contact History if needed.
The receipt shows what the user chose. The assistant's follow-up confirms the outcome and offers a way to reverse it.