The pieces of an assistant interface come from the chat of the AMSET assistant, which uses them every day: the input box, the messages, the reasoning, the tool calls, the log of what an agent does, the files it generates and the model picker. There are 12, with no dependencies, one CSS file per component, and everything conveyed with text as well as colour.
PromptInput grows with the text up to a limit, sends with Enter and adds a new line with Shift+Enter (without sending while composing with an IME), recalls the last message with the up arrow and accepts files that are pasted, dragged or picked. With busyModes you can keep typing while it answers: add to the turn, stop and correct, or queue.
ChatMessage includes copy, regenerate and edit in the same bubble, plus custom actions.
ActivityLog follows the end only if you were already at the bottom and groups repeated events; with group, a history of several tasks.
FindBar searches within a long conversation, where the browser's find cannot see what has not been loaded.
ArtifactFrame isolates the HTML an assistant generates with sandbox="allow-scripts", never with allow-same-origin.
Rich text editor
@amset/ui does not include a text editor and does not depend on one. It includes what has to look and behave like the rest of the library (the toolbar, its link and image panels and the styles of the writing area) and leaves the engine to your application. There are two complete recipes, one for Tiptap and one for Lexical, compiled and checked in the library's repository.
Direction
Prop
What it carries
editor → toolbar
state
What is applied where the cursor is (active), what cannot be used right now (unavailable) and the link at the cursor (link).
toolbar → editor
onCommand
The command: 'bold', 'heading2', 'bulletList', 'undo', 'clearFormatting'...
toolbar → editor
onLinkChange
{ href, newTab } already checked, or null to remove it.
toolbar → editor
onImageInsert
{ src, alt } already checked; alt is only empty if the image is marked as decorative.
application → toolbar
shortcuts
The editor's shortcuts (Mod+B), which the toolbar announces and shows in its help. The editor listens for them, not the toolbar.
A single tab stop for the whole toolbar, arrow keys between buttons and focus memory when you come back.
Each format is a ToggleButton with aria-pressed; clicking it with the mouse does not take focus away from the editor, so the selection stays where it was.
The link and image panels are only mounted when opened and are not a <form>: the toolbar works inside your application's form.
Addresses are checked with normalizeLinkHref and normalizeImageSrc (an allowlist of schemes: a javascript: or a data: does not get through). The toolbar does not clean what the editor stores: that HTML is sanitised on the server before storing or rendering it.
The Tiptap and Lexical recipes
You install the editor of your choice in your application; the library needs nothing new. The recipes are built on each editor's core, without @tiptap/react or @lexical/react: those packages pull in floating menu code that this toolbar does not need.
Code from the library's guide (docs/rich-text-editor.md, revision 3bb3996d), checked there by the compiler.
Each recipe is a React hook that mounts the editor in a <div>, keeps state up to date on every change and translates each command into the editor's API. That is all the glue there is. With another editor it is enough to answer the same questions: what is active at the cursor, what cannot be used right now, and how each command is executed.