Beamline

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 Beamline agent workspace: threads, a conversation with reasoning and a plan, and an artifacts panel
The agent workspace block, on demo data

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.