docs/content/docs/reference/v2/hooks/useInterrupt.mdx
useInterrupt listens for agent custom events named on_interrupt, captures the latest interrupt payload for a run, and renders interrupt UI once the run finalizes. Your UI can call resolve(response) to resume the agent with a resume payload.
By default, interrupt UI is rendered inside <CopilotChat> automatically. If you set renderInChat: false, the hook returns the element so you can place it manually.
event.value is typed as any since the interrupt payload shape depends on your agent. Type-narrow it in your callbacks (e.g. handler, enabled, render) as needed.
import { useInterrupt } from "@copilotkit/react-core/v2";
function useInterrupt<
TResult = never,
TRenderInChat extends boolean | undefined = undefined,
>(
config: UseInterruptConfig<any, TResult, TRenderInChat>,
): TRenderInChat extends false
? React.ReactElement | null
: TRenderInChat extends true | undefined
? void
: React.ReactElement | null | void;
import { useInterrupt } from "@copilotkit/react-core/v2";
function ApprovalInterrupt() {
useInterrupt({
render: ({ event, resolve }) => (
<div className="p-3 border rounded">
<p>{event.value.question}</p>
<div className="mt-2 flex gap-2">
<button onClick={() => resolve({ approved: true })}>Approve</button>
<button onClick={() => resolve({ approved: false })}>Reject</button>
</div>
</div>
),
});
return null;
}
import { useInterrupt } from "@copilotkit/react-core/v2";
function SidePanelInterrupt() {
const element = useInterrupt({
renderInChat: false,
enabled: (event) => event.value.startsWith("approval:"),
handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
render: ({ event, result, resolve }) => (
<aside className="rounded border p-3">
<div className="font-medium">{result?.label ?? ""}</div>
<div className="mt-2">{event.value}</div>
<button className="mt-2" onClick={() => resolve({ accepted: true })}>
Continue
</button>
</aside>
),
});
return <>{element}</>;
}
on_interrupt.event.value is any -- type-narrow in your callbacks as needed.render.result is inferred from handler return type and is always TResult | null.handler throws or rejects, result is set to null.useHumanInTheLoop -- structured interactive tool workflowsuseFrontendTool -- client-side tool registrationuseAgent -- access and subscribe to agent events