diff --git a/libs/langgraph/src/lib/internals/stream-manager.bridge.ts b/libs/langgraph/src/lib/internals/stream-manager.bridge.ts index 7ff6558cb..99b66c712 100644 --- a/libs/langgraph/src/lib/internals/stream-manager.bridge.ts +++ b/libs/langgraph/src/lib/internals/stream-manager.bridge.ts @@ -420,6 +420,7 @@ export function createStreamManagerBridge( + payload: unknown, + subjects: StreamSubjects, +): void { + if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return; + const raw = (payload as Record)['__interrupt__']; + // Cast through unknown — Interrupt$ is parameterized over Bag's InterruptType, + // and the SDK delivers raw Interrupt payloads here. + if (Array.isArray(raw) && raw.length > 0) { + const list = raw as Interrupt[]; + subjects.interrupts$.next(list as unknown as Parameters[0]); + subjects.interrupt$.next(list[list.length - 1] as unknown as Parameters[0]); + return; + } + // Payload has no `__interrupt__` key. Clear any stale interrupt so the UI + // dismisses the panel after a resume completes (LangGraph does not emit a + // separate "cleared" event — the absence of `__interrupt__` in subsequent + // values/updates is the signal). No-op if interrupt$ was already empty. + if (subjects.interrupt$.value !== undefined) { + subjects.interrupt$.next(undefined); + subjects.interrupts$.next([]); + } +} + function extractEventData(event: StreamEvent): unknown { // Try event['data'] first (SDK format from normalizeSdkEvent) const d = event['data'];