Guide · By Danylo Pravda · Updated
Build an AI agent interface in React
An agent's interface is more than a chat box. The agent thinks, calls tools, proposes a plan, stops to ask before it acts, cites what it read and streams an answer that is still arriving. Each of those moments needs its own part, and each one fails in its own way when it is built from a generic message bubble. Beamline has seventeen AI parts and a whole workspace screen. This guide maps the moments to the parts.

The moments, and the part for each
| moment | part | not for |
|---|---|---|
| the answer, streaming or settled | Response | short answers with numbered sources: citations |
| what the agent did while thinking | Reasoning | tool calls with inputs and outputs: tool call |
| one tool call, as it runs | Tool call | a plan approved up front: plan |
| multi-step work before and while it runs | Plan | background jobs: task rows |
| permission before an action with side effects | Approval card | a suggestion to take or leave: recommendation card |
| an answer grounded in documents | Citations | the retrieved chunks in full: context cards |
| the composer | Prompt bar | people chatting with people: chat thread |
| the scrolling column | Conversation with Message | a feed of events: timeline |
The "not for" column is the part that saves the most rework: it is what an agent building your UI reads before it picks.
Streamed answers that do not jump
Tokens arrive in bursts. Rendered as they come, an answer stutters, a word drops to the next line and back as the next
one lands, and a table resizes its columns row by row. Response renders markdown that is still
arriving: bursty tokens flow in at an even pace, each new word fades in, paragraphs that are still streaming wrap
without hopping, and a table lands whole. You pass the text received so far and a streaming flag:
import { Response } from "@beamline/response";
<Response streaming={!done}>{text}</Response>
Showing the work: reasoning and tool calls
Reasoning is the agent's trace, fed by your stream: a working label with the seconds so far while it thinks ("Searching… 3s"), then "Thought for N seconds", with the steps folded away and one press to open them. A closed trace is out of the tab order, so keyboard users are not walked through work they did not ask to see.
Tool call is one call on one quiet row: its status, what it did and a short result, opening to
the exact input and output. When a call needs the person's permission before it runs, the same row waits with Allow
and Deny (onApprove, onDeny).
Asking before acting: plans and approvals
Two parts cover the moment an agent must stop:
- Plan is multi-step work: numbered steps with live status and progress, and Approve, Edit or
Reject while it waits (
awaitingApproval). After approval it shows the steps running. - Approval card is one action with side effects (send, update, delete): what the agent wants to do, exactly what that changes, any questions it needs answered, and Approve or Reject. Number keys pick an answer, and ⌘ or Ctrl+Enter approves once every required question is answered.
Neither one does the action. They call your handlers, and the screen shows what your backend reports.
The composer
Prompt bar is the agent's input: it grows with the text, @ adds a source, / at the start
opens commands, there is a model picker, files and dictation, and one button that sends and then stops a running
answer. Enter sends, Shift+Enter starts a new line, and typing in a language with an input method never sends by
accident. When sending is refused (a quota, a permission), the draft stays.
Or start from the whole workspace
The agent workspace block puts it together for a product where the model plans, asks before acting and produces things people review: threads, a conversation with streamed reasoning, cited answers and a plan that waits for approval and then runs step by step, and an artifacts panel for the changes it made. You pass the run and the handlers:
import { AgentWorkspace } from "@beamline/agent-workspace";
<AgentWorkspace run={run} threads={threads} onSubmit={send} onStop={stop} onApprove={approve} onReject={reject} />
For a small help widget, the workspace is too much: a conversation, messages and a prompt bar are enough. Person-to-person chat has its own part, the chat thread, and a voice agent has the voice agent screen.
Ask your agent for it
With Beamline connected (setup for your agent), describe the product rather than the widgets: "a research copilot that searches our docs, shows what it read, cites its answers and asks before it files a ticket". The agent maps each moment to its part, installs them, and wires them to your model's stream. How streaming text plugs in is in Connect your data.