Skip to content

Agent (full example)

A miniature coding agent: a Conversation transcript with a plan tree, reasoning, a Bash tool call, a file chip, a usage meter, a composer, and a model badge

This is the Agent Kit working end to end: the whole screen is one Conversation. Nothing here is bespoke — every piece is a kit component, wired together with a few handlers.

  • Transcript — the turns are ChatBubbles whose bodies mix a TaskTree plan, a collapsible Reasoning block, a ToolRender Bash call (highlighted command + streaming output), a FileChip citation, and a StreamingText tail.
  • ComposerConversation’s composer carries an @ file-mention trigger and a /model command.
  • Model picker/model (or clicking the model badge) opens a ModelPicker in a Popover, anchored to the badge. The badge lives in the conversation’s hintTrailing slot, on the same row as the contextual hints.
  • Usage — a compact UsageMeter sits in the footer, between the transcript and the composer.
<Conversation
busy={busy}
placeholder="Message the agent… (/model to switch · @ to mention a file)"
composer={{
triggers: [fileMention],
commands: [{ name: "model", run: () => setPicker(true) }],
onCommand: (name) => name === "model" && setPicker(true),
}}
footer={<UsageMeter variant="compact" turn={turn} contextSize={200_000} contextUsed={used} cost={cost} />}
hintTrailing={
<HBox ref={badgeRef} onClick={() => setPicker(true)}>
<Pill color="$accent">{model.name}</Pill>
</HBox>
}
onSubmit={send}
onInterrupt={stop}
>
{turns /* ChatBubble · Reasoning · TaskTree · ToolRender · StreamingText */}
</Conversation>
<Popover open={picker} anchorRef={badgeRef} onClose={() => setPicker(false)}>
<ModelPicker models={MODELS} value={model.id} onSelect={pick} />
</Popover>

The app owns only the turn list, the busy flag, and the selected model — the kit does the layout, tailing, hint line, and event wiring. See the Conversation page for the full slot map.

Full demo →