respond(response: unknown, options: StreamRespondOptions<ConfigurableType>): Promise<void>| Name | Type | Description |
|---|---|---|
response* | unknown | Payload sent back to the interrupted namespace. |
options | StreamRespondOptions<ConfigurableType> | Optional target ( |
Respond to a single pending protocol interrupt.
When options.interruptId is omitted, resolution walks
thread.interrupts from newest to
oldest and picks the first entry whose interruptId has not already
been resolved by a prior respond() call. That entry may be at the
root (namespace: []) or inside a subgraph (non-empty namespace).
This is not the same as * rootStore.interrupts[0] / framework stream.interrupt, which only
mirrors root-namespace interrupts for UI convenience.
Omitting interruptId is fine when exactly one interrupt is pending.
When several can be active (parallel subagents, fan-out, nested
graphs), pass an explicit interruptId (and namespace for subgraph
interrupts) so you resume the interrupt the user acted on.
To resume several interrupts pending at the same checkpoint in one
command, use respondAll — sequential single respond() calls
would not work, since the first resume starts a run, leaving the
others with no interrupted run to respond to.
The server validates namespace against the pending interrupt. Root
interrupts use namespace: [] (the default when namespace is
omitted). Subgraph interrupts require the exact tuple from
getThread()?.interrupts — see the example below.
await controller.respond({ approved: true });await controller.respond(
{ approved: true },
{ config: { configurable: { model: "gpt-4o" } }, metadata: { source: "ui" } },
);for (const intr of stream.interrupts) {
await stream.respond(decide(intr.value), { interruptId: intr.id! });
}const thread = stream.getThread();
for (const entry of thread?.interrupts ?? []) {
await stream.respond(buildResponse(entry.payload), {
interruptId: entry.interruptId,
namespace: entry.namespace,
});
}