| title | useInterrupt |
|---|---|
| description | React hook for handling agent interrupt events and resuming execution with user input |
useInterrupt handles agent interrupts and resumes execution with user input. It supports the AG-UI standard interrupt flow — RUN_FINISHED with outcome.type === "interrupt" carrying an interrupts array — and the legacy custom-event flow (on_interrupt). For standard interrupts, your render/handler receive interrupt (the primary one) and interrupts (the full open set); call resolve(payload) to resume or cancel() to cancel.
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. The element returned by render is a React Native element.
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-native";
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;<PropertyReference name="handler" type="(props: InterruptHandlerProps) => TResult | PromiseLike"
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.
import { Text, TouchableOpacity, View } from "react-native";
import { useInterrupt } from "@copilotkit/react-native";
function ApprovalInterrupt() {
useInterrupt({
render: ({ event, resolve }) => (
<View style={{ padding: 12, borderWidth: 1, borderRadius: 8 }}>
<Text>{event.value.question}</Text>
<View style={{ marginTop: 8, flexDirection: "row", gap: 8 }}>
<TouchableOpacity onPress={() => resolve({ approved: true })}>
<Text>Approve</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => resolve({ approved: false })}>
<Text>Reject</Text>
</TouchableOpacity>
</View>
</View>
),
});
return null;
}import { Text, TouchableOpacity, View } from "react-native";
import { useInterrupt } from "@copilotkit/react-native";
function ApprovalInterrupt() {
useInterrupt({
render: ({ interrupt, resolve, cancel }) => (
<View style={{ padding: 12, borderWidth: 1, borderRadius: 8 }}>
<Text>{interrupt?.message ?? "Approve this action?"}</Text>
<View style={{ marginTop: 8, flexDirection: "row", gap: 8 }}>
<TouchableOpacity onPress={() => resolve({ approved: true })}>
<Text>Approve</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => cancel()}>
<Text>Cancel</Text>
</TouchableOpacity>
</View>
</View>
),
});
return null;
}import { Text, TouchableOpacity, View } from "react-native";
import { useInterrupt } from "@copilotkit/react-native";
function SidePanelInterrupt() {
const element = useInterrupt({
renderInChat: false,
enabled: (event) => event.value.startsWith("approval:"),
handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
render: ({ event, result, resolve }) => (
<View style={{ borderWidth: 1, borderRadius: 8, padding: 12 }}>
<Text style={{ fontWeight: "500" }}>{result?.label ?? ""}</Text>
<Text style={{ marginTop: 8 }}>{event.value}</Text>
<TouchableOpacity style={{ marginTop: 8 }} onPress={() => resolve({ accepted: true })}>
<Text>Continue</Text>
</TouchableOpacity>
</View>
),
});
return <>{element}</>;
}- Standard interrupts are detected from
RUN_FINISHED(outcome.type === "interrupt"); legacy interrupts fromon_interruptcustom events. resolve/cancelaccumulate one response per open interrupt; the resume run starts once every open interrupt is addressed.- Expired interrupts (past
expiresAt) are not resumed. - Interrupt UI is surfaced when the run finalizes.
- Starting a new run clears pending interrupt state.
event.valueisany; type-narrow in your callbacks as needed. For standard interrupts,event.valueis the primaryInterrupt.render.resultis inferred fromhandlerreturn type and is alwaysTResult | null.- If
handlerthrows or rejects,resultis set tonull.
useHumanInTheLoop: structured interactive tool workflowsuseFrontendTool: client-side tool registrationuseAgent: access and subscribe to agent events- React (V2) reference