Components
useAgUiAgent
An AG-UI agent’s run as AI SDK messages, status, usage and approvals, for the same components.
Example
Interactive, and the same on the components page. Try the keyboard below on it.
Installation
npm i signoff-ui ai @ag-ui/clientimport { useAgUiAgent } from 'signoff-ui/ag-ui';
// Once per app (with Tailwind v4: @import 'signoff-ui/tailwind.css'; in your CSS)
import 'signoff-ui/styles.css';npx shadcn@latest add https://signoff-ui.vercel.app/r/ag-ui.json
npm i @ag-ui/clientimport { useAgUiAgent } from '@/components/signoff-ui/use-ag-ui-agent';The styles are once per app; Getting started has the Tailwind v4 and plain CSS options.
Usage
const agent = new HttpAgent({ url: '/api/agent' }); // once, outside the component
function AgentRun() {
const { messages, status, usage, step, respond } = useAgUiAgent(agent);
const last = messages.findLast((m) => m.role === 'assistant');
const { state, detail } = deriveAgentState({ status, message: last });
return (
<>
<AgentStatus state={state} detail={step ?? detail} />
{last && <AgentMessage message={last} onToolApproval={respond} />}
<RunMeter usage={usage} />
</>
);
}How it works
Takes any @ag-ui/ agent (HttpAgent, or a framework integration's own AbstractAgent) and turns its messages and events into AI SDK message parts, so every component works with it unchanged, approvals included. Interrupts bound to a tool call become approval cards, and respond resumes the run. AG-UI agents has the event mapping, LangGraph and the pure functions behind the hook.
API reference
Generated from the types the package ships, so it matches the version you install.
useAgUiAgent
Render an AG-UI agent with these components: its messages as AI SDK parts, run status, usage, and tool-call interrupts as approvals.
const agent = useMemo(() => new HttpAgent({ url: '/api/agent' }), []);
const { messages, status, respond } = useAgUiAgent(agent);useAgUiAgent(agent: AgUiAgentLike): UseAgUiAgentResultParameter: AgUiAgentLike
messagesrequiredreadonly AgUiMessage[]subscriberequired(subscriber: AgUiSubscriber) => { unsubscribe(): void; }runAgentrequired(parameters?: { resume?: AgUiResumeEntry[]; }) => Promise<unknown>pendingInterruptsreadonly AgUiInterrupt[]abortRun() => void
Returns: UseAgUiAgentResult
messagesrequiredUIMessage[]The conversation as AI SDK messages: pass each to
AgentMessage.statusrequiredChatStatus'error' | 'submitted' | 'streaming' | 'ready'useChat-style status, forderiveAgentStateandAgentStatus.errorrequiredAgUiRunState['error']usagerequiredRunUsageToken usage summed over the runs seen, for
RunMeter.steprequiredstringThe step in progress, e.g. a LangGraph node.
interruptsrequiredAgUiInterrupt[]Open interrupts. Those bound to a tool call show as approval cards; answer the rest with
resolve.respondrequired(response: AgUiApprovalResponse) => Promise<void>Answer a tool-call interrupt. Pass it as
AgentMessage'sonToolApproval. The agent resumes once every open interrupt has an answer, since AG-UI resumes them all in one run.resolverequired(entry: AgUiResumeEntry) => Promise<void>Answer any interrupt with your own payload (match its
responseSchema).editInputrequired(toolCallId: string, input: unknown) => voidArguments a person edited for a tool call, sent as the approval's
inputwhen it is approved. Pass it asAgentMessage'sonToolInputEdit, so approval cards offer editing.stoprequired() => voidAbort the run in progress. It ends like a cancelled run: what was streaming stays cut off, which
deriveAgentStatereads asstopped.
AgUiInterrupt
A pause for human input (AG-UI Interrupt). toolCallId binds it to a tool call to approve.
idrequiredstringreasonrequiredstringmessagestringtoolCallIdstringresponseSchemaRecord<string, unknown>
AgUiApprovalResponse
A tool approval, as ToolApprovalCard and AgentMessage's onToolApproval give it.
idrequiredstringapprovedrequiredbooleanreasonstringinputunknownArguments the person edited, sent with an approval as the payload's
input.
AgUiResumeEntry
An answer to an interrupt, sent in RunAgentInput.resume (AG-UI ResumeEntry).
interruptIdrequiredstringstatusrequired'resolved' | 'cancelled'payloadunknown
Accessibility
- A hook with no markup of its own: the components it feeds carry the behavior on their pages.
- A tool-call interrupt becomes an approval card with the same keyboard and announcements as an AI SDK approval.