Back to Copilotkit

useInterrupt

docs/content/docs/reference/v2/hooks/useInterrupt.mdx

1.59.35.0 KB
Original Source

Overview

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.

Signature

tsx
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;

Parameters

<PropertyReference name="config" type="UseInterruptConfig<any, TResult, TRenderInChat>" required> Interrupt configuration. <PropertyReference name="render" type="(props: InterruptRenderProps<any, TResult | null>) => React.ReactElement" required> Render callback for interrupt UI. Called when an interrupt is available. The callback receives: - `event` -- interrupt event (`{ name, value }`). `value` is `any`; type-narrow in your callback as needed. - `result` -- inferred from `handler` return type, or `null` - `resolve(response)` -- resumes the agent with `command.resume = response` </PropertyReference> <PropertyReference name="handler" type="(props: InterruptHandlerProps) => TResult | PromiseLike<TResult>"> Optional preprocessing callback. Runs before rendering and can return sync or async data that is exposed as `result` in `render`. `TResult` is automatically inferred from the handler's return type. If the handler throws/rejects, `result` is `null`. </PropertyReference> <PropertyReference name="enabled" type="(event: InterruptEvent) => boolean"> Optional filter. Return `false` to ignore matching interrupts for this hook instance. </PropertyReference> <PropertyReference name="agentId" type="string"> Optional agent id. Defaults to the currently configured chat agent. </PropertyReference> <PropertyReference name="renderInChat" type="boolean" default="true"> Controls where UI renders: - `true` (default): publishes interrupt UI into `<CopilotChat>` - `false`: returns interrupt element from the hook for manual placement </PropertyReference> </PropertyReference>

Return Value

<PropertyReference name="element" type="Conditional by renderInChat"> Return type is inferred from `renderInChat`: - `renderInChat: false` -> `React.ReactElement | null` - `renderInChat: true` or omitted -> `void` - dynamic boolean -> `React.ReactElement | null | void` </PropertyReference>

Usage

In-chat interrupt UI (default)

tsx
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;
}

Manual placement with async preprocessing

tsx
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}</>;
}

Behavior

  • Interrupts are collected from agent custom events named on_interrupt.
  • Interrupt UI is surfaced when the run finalizes.
  • Starting a new run clears pending interrupt state.
  • event.value is any -- type-narrow in your callbacks as needed.
  • render.result is inferred from handler return type and is always TResult | null.
  • If handler throws or rejects, result is set to null.