@langchain/langgraph-sdk 1.10.3-rc.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/client/stream/index.cjs +23 -1
  2. package/dist/client/stream/index.cjs.map +1 -1
  3. package/dist/client/stream/index.d.cts +6 -0
  4. package/dist/client/stream/index.d.cts.map +1 -1
  5. package/dist/client/stream/index.d.ts +6 -0
  6. package/dist/client/stream/index.d.ts.map +1 -1
  7. package/dist/client/stream/index.js +23 -1
  8. package/dist/client/stream/index.js.map +1 -1
  9. package/dist/client/stream/transport/http.cjs +23 -5
  10. package/dist/client/stream/transport/http.cjs.map +1 -1
  11. package/dist/client/stream/transport/http.d.cts +1 -0
  12. package/dist/client/stream/transport/http.d.cts.map +1 -1
  13. package/dist/client/stream/transport/http.d.ts +1 -0
  14. package/dist/client/stream/transport/http.d.ts.map +1 -1
  15. package/dist/client/stream/transport/http.js +23 -5
  16. package/dist/client/stream/transport/http.js.map +1 -1
  17. package/dist/client/stream/transport/types.d.cts +9 -12
  18. package/dist/client/stream/transport/types.d.cts.map +1 -1
  19. package/dist/client/stream/transport/types.d.ts +9 -12
  20. package/dist/client/stream/transport/types.d.ts.map +1 -1
  21. package/dist/client/stream/transport/websocket.cjs +15 -3
  22. package/dist/client/stream/transport/websocket.cjs.map +1 -1
  23. package/dist/client/stream/transport/websocket.d.cts +1 -0
  24. package/dist/client/stream/transport/websocket.d.cts.map +1 -1
  25. package/dist/client/stream/transport/websocket.d.ts +1 -0
  26. package/dist/client/stream/transport/websocket.d.ts.map +1 -1
  27. package/dist/client/stream/transport/websocket.js +15 -3
  28. package/dist/client/stream/transport/websocket.js.map +1 -1
  29. package/dist/client/stream/types.d.cts +5 -7
  30. package/dist/client/stream/types.d.cts.map +1 -1
  31. package/dist/client/stream/types.d.ts +5 -7
  32. package/dist/client/stream/types.d.ts.map +1 -1
  33. package/dist/client/threads/index.cjs +2 -1
  34. package/dist/client/threads/index.cjs.map +1 -1
  35. package/dist/client/threads/index.js +2 -1
  36. package/dist/client/threads/index.js.map +1 -1
  37. package/dist/stream/controller.cjs +111 -31
  38. package/dist/stream/controller.cjs.map +1 -1
  39. package/dist/stream/controller.d.cts.map +1 -1
  40. package/dist/stream/controller.d.ts.map +1 -1
  41. package/dist/stream/controller.js +111 -31
  42. package/dist/stream/controller.js.map +1 -1
  43. package/dist/stream/types.d.cts +5 -0
  44. package/dist/stream/types.d.cts.map +1 -1
  45. package/dist/stream/types.d.ts +5 -0
  46. package/dist/stream/types.d.ts.map +1 -1
  47. package/dist/utils/reconnect.cjs.map +1 -1
  48. package/dist/utils/reconnect.d.cts +18 -0
  49. package/dist/utils/reconnect.d.cts.map +1 -0
  50. package/dist/utils/reconnect.d.ts +18 -0
  51. package/dist/utils/reconnect.d.ts.map +1 -0
  52. package/dist/utils/reconnect.js.map +1 -1
  53. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.cts","names":[],"sources":["../../src/stream/controller.ts"],"mappings":";;;;;;;;;;;;;;AA6KA;;cAAa,kBAAA,WAA6B,OAAA;;AAkC1C;;;;;;;;;;;;cAAa,gBAAA,4BACgB,MAAA,8EAEO,MAAA;EAAA;WAEzB,SAAA,EAAW,WAAA,CAAY,YAAA,CAAa,SAAA,EAAW,aAAA;EAAA,SAC/C,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,mBAAA,EAAqB,WAAA,CAAY,iBAAA;EAAA,SACjC,oBAAA,EAAsB,WAAA,CAAY,kBAAA;EAAA,SAClC,UAAA,EAAY,WAAA,CAAY,uBAAA,CAAwB,SAAA;EAAA,SAChD,QAAA,EAAU,eAAA;EAiK0B;;;;;EAA7C,WAAA,CAAY,OAAA,EAAS,uBAAA,CAAwB,SAAA;EAoyBF;;;;;;;EAAA,IAxqBvC,gBAAA,CAAA,GAAoB,OAAA;EA60BS;;;;;;;;EApxB3B,OAAA,CAAQ,QAAA,mBAA2B,OAAA;EAsgCpB;;;;;;;;;;;;;;EA7pBf,wBAAA,CAAyB,UAAA,WAAqB,OAAA;EApsB5B;;;;;;;;EAw8BlB,MAAA,CACJ,KAAA,WACA,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EAx8B4B;;;;;;EAk9BzB,IAAA,CAAK,OAAA,GAAU,iBAAA,GAAoB,OAAA;EAh9BtB;;;;EAo+Bb,UAAA,CAAA,GAAc,OAAA;EAvsBhB;;;;;;;;;;;EAuwBE,YAAA,CAAa,EAAA,WAAa,OAAA;EA/FW;;;EAsGrC,UAAA,CAAA,GAAc,OAAA;EA3FC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwJf,OAAA,CACJ,QAAA,WACA,OAAA,GAAU,oBAAA,CAAqB,gBAAA,IAC9B,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiHG,UAAA,CACJ,aAAA,EAAe,MAAA,mBACf,OAAA,GAAU,uBAAA,CAAwB,gBAAA,IACjC,OAAA;;;;EA4DG,OAAA,CAAA,GAAW,OAAA;;;;;;;;;;;;;;;;EAyBjB,QAAA,CAAA;;;;;;EA4BA,SAAA,CAAA,GAAa,YAAA;;;;;;;;EAWb,eAAA,CACE,QAAA,GAAW,MAAA,EAAQ,YAAA;AAAA"}
1
+ {"version":3,"file":"controller.d.cts","names":[],"sources":["../../src/stream/controller.ts"],"mappings":";;;;;;;;;;;;;;AA6KA;;cAAa,kBAAA,WAA6B,OAAA;;AAwC1C;;;;;;;;;;;;cAAa,gBAAA,4BACgB,MAAA,8EAEO,MAAA;EAAA;WAEzB,SAAA,EAAW,WAAA,CAAY,YAAA,CAAa,SAAA,EAAW,aAAA;EAAA,SAC/C,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,mBAAA,EAAqB,WAAA,CAAY,iBAAA;EAAA,SACjC,oBAAA,EAAsB,WAAA,CAAY,kBAAA;EAAA,SAClC,UAAA,EAAY,WAAA,CAAY,uBAAA,CAAwB,SAAA;EAAA,SAChD,QAAA,EAAU,eAAA;EAiK0B;;;;;EAA7C,WAAA,CAAY,OAAA,EAAS,uBAAA,CAAwB,SAAA;EAiyBF;;;;;;;EAAA,IAtqBvC,gBAAA,CAAA,GAAoB,OAAA;EA20BS;;;;;;;;EAlxB3B,OAAA,CAAQ,QAAA,mBAA2B,OAAA;EAogCpB;;;;;;;;;;;;;;EA7pBf,wBAAA,CAAyB,UAAA,WAAqB,OAAA;EAjsB5B;;;;;;;;EAq8BlB,MAAA,CACJ,KAAA,WACA,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EAr8B4B;;;;;;EA+8BzB,IAAA,CAAK,OAAA,GAAU,iBAAA,GAAoB,OAAA;EA78BtB;;;;EAi+Bb,UAAA,CAAA,GAAc,OAAA;EArsBhB;;;;;;;;;;;EAqwBE,YAAA,CAAa,EAAA,WAAa,OAAA;EA/FW;;;EAsGrC,UAAA,CAAA,GAAc,OAAA;EA3FC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwJf,OAAA,CACJ,QAAA,WACA,OAAA,GAAU,oBAAA,CAAqB,gBAAA,IAC9B,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiHG,UAAA,CACJ,aAAA,EAAe,MAAA,mBACf,OAAA,GAAU,uBAAA,CAAwB,gBAAA,IACjC,OAAA;;;;EA4DG,OAAA,CAAA,GAAW,OAAA;;;;;;;;;;;;;;;;EAyBjB,QAAA,CAAA;;;;;;EA4BA,SAAA,CAAA,GAAa,YAAA;;;;;;;;EAWb,eAAA,CACE,QAAA,GAAW,MAAA,EAAQ,YAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","names":[],"sources":["../../src/stream/controller.ts"],"mappings":";;;;;;;;;;;;;;;AA6KA;cAAa,kBAAA,WAA6B,OAAA;;;AAkC1C;;;;;;;;;;;cAAa,gBAAA,4BACgB,MAAA,8EAEO,MAAA;EAAA;WAEzB,SAAA,EAAW,WAAA,CAAY,YAAA,CAAa,SAAA,EAAW,aAAA;EAAA,SAC/C,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,mBAAA,EAAqB,WAAA,CAAY,iBAAA;EAAA,SACjC,oBAAA,EAAsB,WAAA,CAAY,kBAAA;EAAA,SAClC,UAAA,EAAY,WAAA,CAAY,uBAAA,CAAwB,SAAA;EAAA,SAChD,QAAA,EAAU,eAAA;EAAA;;;;;EAiKnB,WAAA,CAAY,OAAA,EAAS,uBAAA,CAAwB,SAAA;EAoyBb;;;;;;;EAAA,IAxqB5B,gBAAA,CAAA,GAAoB,OAAA;EA8wBJ;;;;;;;;EArtBd,OAAA,CAAQ,QAAA,mBAA2B,OAAA;EA0/B5B;;;;;;;;;;;;;;EAjpBP,wBAAA,CAAyB,UAAA,WAAqB,OAAA;EApsB3C;;;;;;;;EAw8BH,MAAA,CACJ,KAAA,WACA,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EAx8BM;;;;;;EAk9BH,IAAA,CAAK,OAAA,GAAU,iBAAA,GAAoB,OAAA;EAh9BhC;;;;EAo+BH,UAAA,CAAA,GAAc,OAAA;EAn0BR;;;;;;;;;;;EAm4BN,YAAA,CAAa,EAAA,WAAa,OAAA;EA/FA;;;EAsG1B,UAAA,CAAA,GAAc,OAAA;EA3Fd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwJA,OAAA,CACJ,QAAA,WACA,OAAA,GAAU,oBAAA,CAAqB,gBAAA,IAC9B,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiHG,UAAA,CACJ,aAAA,EAAe,MAAA,mBACf,OAAA,GAAU,uBAAA,CAAwB,gBAAA,IACjC,OAAA;;;;EA4DG,OAAA,CAAA,GAAW,OAAA;;;;;;;;;;;;;;;;EAyBjB,QAAA,CAAA;;;;;;EA4BA,SAAA,CAAA,GAAa,YAAA;;;;;;;;EAWb,eAAA,CACE,QAAA,GAAW,MAAA,EAAQ,YAAA;AAAA"}
1
+ {"version":3,"file":"controller.d.ts","names":[],"sources":["../../src/stream/controller.ts"],"mappings":";;;;;;;;;;;;;;;AA6KA;cAAa,kBAAA,WAA6B,OAAA;;;AAwC1C;;;;;;;;;;;cAAa,gBAAA,4BACgB,MAAA,8EAEO,MAAA;EAAA;WAEzB,SAAA,EAAW,WAAA,CAAY,YAAA,CAAa,SAAA,EAAW,aAAA;EAAA,SAC/C,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,aAAA,EAAe,WAAA,CAAY,WAAA;EAAA,SAC3B,mBAAA,EAAqB,WAAA,CAAY,iBAAA;EAAA,SACjC,oBAAA,EAAsB,WAAA,CAAY,kBAAA;EAAA,SAClC,UAAA,EAAY,WAAA,CAAY,uBAAA,CAAwB,SAAA;EAAA,SAChD,QAAA,EAAU,eAAA;EAAA;;;;;EAiKnB,WAAA,CAAY,OAAA,EAAS,uBAAA,CAAwB,SAAA;EAiyBb;;;;;;;EAAA,IAtqB5B,gBAAA,CAAA,GAAoB,OAAA;EA4wBJ;;;;;;;;EAntBd,OAAA,CAAQ,QAAA,mBAA2B,OAAA;EAw/B5B;;;;;;;;;;;;;;EAjpBP,wBAAA,CAAyB,UAAA,WAAqB,OAAA;EAjsB3C;;;;;;;;EAq8BH,MAAA,CACJ,KAAA,WACA,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,gBAAA,IACxC,OAAA;EAr8BM;;;;;;EA+8BH,IAAA,CAAK,OAAA,GAAU,iBAAA,GAAoB,OAAA;EA78BhC;;;;EAi+BH,UAAA,CAAA,GAAc,OAAA;EAh0BR;;;;;;;;;;;EAg4BN,YAAA,CAAa,EAAA,WAAa,OAAA;EA/FA;;;EAsG1B,UAAA,CAAA,GAAc,OAAA;EA3Fd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwJA,OAAA,CACJ,QAAA,WACA,OAAA,GAAU,oBAAA,CAAqB,gBAAA,IAC9B,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiHG,UAAA,CACJ,aAAA,EAAe,MAAA,mBACf,OAAA,GAAU,uBAAA,CAAwB,gBAAA,IACjC,OAAA;;;;EA4DG,OAAA,CAAA,GAAW,OAAA;;;;;;;;;;;;;;;;EAyBjB,QAAA,CAAA;;;;;;EA4BA,SAAA,CAAA,GAAa,YAAA;;;;;;;;EAWb,eAAA,CACE,QAAA,GAAW,MAAA,EAAQ,YAAA;AAAA"}
@@ -104,6 +104,8 @@ const ROOT_PUMP_CHANNELS = [
104
104
  "messages",
105
105
  "tools"
106
106
  ];
107
+ const PARKED_INTERRUPT_SETTLE_MS = 5e3;
108
+ const PARKED_INTERRUPT_SETTLE_POLL_MS = 500;
107
109
  /**
108
110
  * Coordinates one thread's protocol-v2 stream and exposes stable
109
111
  * observable projections for framework bindings.
@@ -142,6 +144,7 @@ var StreamController = class {
142
144
  */
143
145
  #rootPumpDeferred = false;
144
146
  #threadEventUnsubscribe;
147
+ #threadErrorUnsubscribe;
145
148
  #disposed = false;
146
149
  #pendingDisposeTimer = null;
147
150
  /**
@@ -166,17 +169,16 @@ var StreamController = class {
166
169
  * than {@link #interruptReplayThroughSeq} bypass the allowlist.
167
170
  */
168
171
  #hydratedActiveInterruptIds = null;
169
- /** Checkpoint whose replay establishes the hydrate-time interrupt cutoff. */
170
- #hydratedInterruptCheckpointId;
171
172
  /**
172
- * Highest event sequence represented by hydration or already applied when
173
- * the latest run command was accepted. Interrupts outside the hydrate-time
174
- * allowlist remain filtered through this sequence, while newer events are
175
- * live output and must be accepted.
173
+ * Highest event sequence already applied when the latest run command
174
+ * was accepted. Interrupts outside the hydrate-time allowlist remain
175
+ * filtered through this sequence, while newer events are live output
176
+ * from the newly-started run and must be accepted.
176
177
  */
177
178
  #interruptReplayThroughSeq;
178
- /** Unknown inputs waiting for replay to reach the hydrated checkpoint. */
179
+ /** Unknown inputs waiting to be classified as live or replayed history. */
179
180
  #pendingHydrationInterruptEvents = [];
181
+ #settleParkedInterruptsPromise;
180
182
  /**
181
183
  * Unknown interrupt events received between local command dispatch and its
182
184
  * response. The response supplies the sequence barrier needed to classify
@@ -330,7 +332,6 @@ var StreamController = class {
330
332
  this.#interruptCommandPending = this.#hydratedActiveInterruptIds != null;
331
333
  this.#pendingInterruptEvents = this.#pendingHydrationInterruptEvents;
332
334
  this.#pendingHydrationInterruptEvents = [];
333
- this.#hydratedInterruptCheckpointId = void 0;
334
335
  },
335
336
  onRunStart: () => this.#markLocalRunStart(),
336
337
  onRunCreated: (runId) => {
@@ -581,7 +582,6 @@ var StreamController = class {
581
582
  }));
582
583
  if (this.#submitGeneration === generationAtFetch) {
583
584
  this.#hydratedActiveInterruptIds = activeIds;
584
- this.#hydratedInterruptCheckpointId = state.checkpoint?.checkpoint_id ?? void 0;
585
585
  this.#interruptReplayThroughSeq = void 0;
586
586
  }
587
587
  }
@@ -1217,7 +1217,10 @@ var StreamController = class {
1217
1217
  * still required.
1218
1218
  */
1219
1219
  #ensureThread(threadId, deferRootPump = false) {
1220
- if (this.#thread != null) return this.#thread;
1220
+ if (this.#thread != null) {
1221
+ if (!deferRootPump && !this.#rootPumpDeferred && this.#rootPump == null) this.#startRootPump(this.#thread);
1222
+ return this.#thread;
1223
+ }
1221
1224
  this.#thread = this.#options.client.threads.stream(threadId, {
1222
1225
  assistantId: this.#options.assistantId,
1223
1226
  transport: this.#options.transport,
@@ -1226,7 +1229,8 @@ var StreamController = class {
1226
1229
  maxReconnectAttempts: this.#options.maxReconnectAttempts,
1227
1230
  streamIdleReconnect: this.#options.streamIdleReconnect,
1228
1231
  reconnectDelayMs: this.#options.reconnectDelayMs,
1229
- onReconnect: this.#options.onReconnect
1232
+ onReconnect: this.#options.onReconnect,
1233
+ onConnected: this.#options.onConnected
1230
1234
  });
1231
1235
  this.registry.bind(this.#thread);
1232
1236
  if (deferRootPump) {
@@ -1286,6 +1290,8 @@ var StreamController = class {
1286
1290
  this.registry.bind(void 0);
1287
1291
  this.#threadEventUnsubscribe?.();
1288
1292
  this.#threadEventUnsubscribe = void 0;
1293
+ this.#threadErrorUnsubscribe?.();
1294
+ this.#threadErrorUnsubscribe = void 0;
1289
1295
  /**
1290
1296
  * Persistent lifecycle driver is scoped to the current thread
1291
1297
  * stream. Remove it so a swap to a new thread starts with a clean
@@ -1313,7 +1319,6 @@ var StreamController = class {
1313
1319
  this.#localRunDepth = 0;
1314
1320
  this.#messageMetadata.reset();
1315
1321
  this.#hydratedActiveInterruptIds = null;
1316
- this.#hydratedInterruptCheckpointId = void 0;
1317
1322
  this.#interruptReplayThroughSeq = void 0;
1318
1323
  this.#pendingHydrationInterruptEvents = [];
1319
1324
  this.#discardPendingInterruptEvents();
@@ -1362,6 +1367,14 @@ var StreamController = class {
1362
1367
  * pump's narrow filter.
1363
1368
  */
1364
1369
  this.#threadEventUnsubscribe = thread.onEvent((event) => this.#onWildcardEvent(event));
1370
+ this.#threadErrorUnsubscribe = thread.onError((error) => {
1371
+ this.rootStore.setState((s) => ({
1372
+ ...s,
1373
+ error,
1374
+ isLoading: false
1375
+ }));
1376
+ this.#rootSubscription?.close();
1377
+ });
1365
1378
  /**
1366
1379
  * Persistent isLoading driver. Drives `isLoading` from
1367
1380
  * root-namespace lifecycle events so that in-flight runs observed
@@ -1372,7 +1385,7 @@ var StreamController = class {
1372
1385
  */
1373
1386
  this.#rootEventListeners.add(this.#lifecycleLoading.listener);
1374
1387
  this.#rootEventListeners.add(this.#runLifecycleListener);
1375
- this.#rootPump = (async () => {
1388
+ const pump = (async () => {
1376
1389
  try {
1377
1390
  /**
1378
1391
  * Root content pump: depth 1 is required because the controller
@@ -1463,7 +1476,15 @@ var StreamController = class {
1463
1476
  } catch {}
1464
1477
  }
1465
1478
  if (this.#disposed || pumpGeneration !== this.#rootPumpGeneration) break;
1466
- if (!subscription.isPaused) break;
1479
+ if (!subscription.isPaused) {
1480
+ const snapshot = this.rootStore.getSnapshot();
1481
+ if (snapshot.isLoading && snapshot.error == null) this.rootStore.setState((s) => ({
1482
+ ...s,
1483
+ error: /* @__PURE__ */ new Error("Thread event stream closed before the active run completed."),
1484
+ isLoading: false
1485
+ }));
1486
+ break;
1487
+ }
1467
1488
  await subscription.waitForResume();
1468
1489
  }
1469
1490
  } catch {
@@ -1471,6 +1492,21 @@ var StreamController = class {
1471
1492
  resolveReady = void 0;
1472
1493
  }
1473
1494
  })();
1495
+ this.#rootPump = pump;
1496
+ pump.finally(() => {
1497
+ if (pumpGeneration !== this.#rootPumpGeneration) return;
1498
+ if (this.#rootPump !== pump) return;
1499
+ this.#rootPumpGeneration += 1;
1500
+ this.#rootSubscription = void 0;
1501
+ this.#rootPump = void 0;
1502
+ this.#rootPumpReady = void 0;
1503
+ this.#threadEventUnsubscribe?.();
1504
+ this.#threadEventUnsubscribe = void 0;
1505
+ this.#threadErrorUnsubscribe?.();
1506
+ this.#threadErrorUnsubscribe = void 0;
1507
+ this.#rootEventListeners.delete(this.#lifecycleLoading.listener);
1508
+ this.#rootEventListeners.delete(this.#runLifecycleListener);
1509
+ });
1474
1510
  }
1475
1511
  /**
1476
1512
  * Handle an event delivered via {@link ThreadStream.onEvent}.
@@ -1491,7 +1527,6 @@ var StreamController = class {
1491
1527
  } catch {}
1492
1528
  this.#subgraphs.push(event);
1493
1529
  this.#lifecycleLoading.handle(event);
1494
- this.#advanceInterruptReplayBarrierFromCheckpoint(event);
1495
1530
  /**
1496
1531
  * `input.requested` events (including HITL inside a subagent /
1497
1532
  * subgraph) are not always observable via the narrow content pump.
@@ -1501,6 +1536,7 @@ var StreamController = class {
1501
1536
  * resume targeting.
1502
1537
  */
1503
1538
  this.#recordInterrupt(event);
1539
+ this.#settleParkedInterruptsOnTerminal(event);
1504
1540
  }
1505
1541
  /**
1506
1542
  * Process one root-pump event and update all root projections.
@@ -1741,11 +1777,12 @@ var StreamController = class {
1741
1777
  this.#pendingInterruptEvents.push(event);
1742
1778
  return;
1743
1779
  }
1744
- if (isUnknownInterrupt && this.#interruptReplayThroughSeq == null && this.#hydratedInterruptCheckpointId != null) {
1780
+ const barrier = this.#interruptReplayThroughSeq;
1781
+ if (isUnknownInterrupt && barrier == null) {
1745
1782
  this.#pendingHydrationInterruptEvents.push(event);
1746
1783
  return;
1747
1784
  }
1748
- if (isUnknownInterrupt && (this.#interruptReplayThroughSeq == null || eventSeq != null && eventSeq <= this.#interruptReplayThroughSeq)) return;
1785
+ if (isUnknownInterrupt && barrier != null && eventSeq != null && eventSeq <= barrier) return;
1749
1786
  const namespace = Array.isArray(event.params.namespace) ? [...event.params.namespace] : [...ROOT_NAMESPACE];
1750
1787
  const interrupt = normalizeInterruptForClient({
1751
1788
  id: interruptId,
@@ -1762,16 +1799,6 @@ var StreamController = class {
1762
1799
  };
1763
1800
  });
1764
1801
  }
1765
- /** Establish the hydration cutoff when ordered replay reaches its checkpoint. */
1766
- #advanceInterruptReplayBarrierFromCheckpoint(event) {
1767
- if (event.method !== "checkpoints" || this.#hydratedInterruptCheckpointId == null || !isRootNamespace(event.params.namespace)) return;
1768
- if (event.params.data?.id !== this.#hydratedInterruptCheckpointId || typeof event.seq !== "number") return;
1769
- this.#interruptReplayThroughSeq = event.seq;
1770
- this.#hydratedInterruptCheckpointId = void 0;
1771
- const pendingEvents = this.#pendingHydrationInterruptEvents.sort((a, b) => (a.seq ?? 0) - (b.seq ?? 0));
1772
- this.#pendingHydrationInterruptEvents = [];
1773
- for (const pendingEvent of pendingEvents) this.#recordInterrupt(pendingEvent);
1774
- }
1775
1802
  /**
1776
1803
  * Convert the hydrate-time allowlist into a replay barrier after a command
1777
1804
  * is accepted. Built-in transports update `lastAppliedThroughSeq` from the
@@ -1848,12 +1875,12 @@ var StreamController = class {
1848
1875
  */
1849
1876
  async #reconcilePendingInterruptsFromServer() {
1850
1877
  const threadId = this.#currentThreadId;
1851
- if (threadId == null || this.#disposed) return;
1878
+ if (threadId == null || this.#disposed) return null;
1852
1879
  const generationAtFetch = this.#submitGeneration;
1853
1880
  try {
1854
1881
  const state = await this.#fetchHydrationState();
1855
- if (this.#disposed || this.#currentThreadId !== threadId || this.#submitGeneration !== generationAtFetch) return;
1856
- if (!Array.isArray(state?.tasks)) return;
1882
+ if (this.#disposed || this.#currentThreadId !== threadId || this.#submitGeneration !== generationAtFetch) return null;
1883
+ if (!Array.isArray(state?.tasks)) return null;
1857
1884
  const { activeInterrupts, activeIds } = collectActiveInterruptsFromTasks(state.tasks);
1858
1885
  const pendingInterrupts = activeInterrupts.filter((interrupt) => interrupt.id == null || !this.#resolvedInterrupts.has(interrupt.id));
1859
1886
  this.rootStore.setState((s) => ({
@@ -1862,7 +1889,55 @@ var StreamController = class {
1862
1889
  interrupt: pendingInterrupts[0]
1863
1890
  }));
1864
1891
  this.#hydratedActiveInterruptIds = activeIds;
1865
- } catch {}
1892
+ return state;
1893
+ } catch {
1894
+ return null;
1895
+ }
1896
+ }
1897
+ #settleParkedInterruptsOnTerminal(event) {
1898
+ if (this.#pendingHydrationInterruptEvents.length === 0) return;
1899
+ if (event.method !== "lifecycle") return;
1900
+ if (!isRootNamespace(event.params.namespace)) return;
1901
+ const status = event.params.data?.event;
1902
+ if (status !== "interrupted" && status !== "completed" && status !== "failed") return;
1903
+ this.#settleParkedInterrupts();
1904
+ }
1905
+ /**
1906
+ * Decide parked interrupts with server state instead of a stream marker.
1907
+ *
1908
+ * After a passive rejoin the stream cannot tell a replayed, already
1909
+ * resolved `input.requested` from one the current run just raised: the
1910
+ * SSE replays the thread buffer on connect with no marker for where the
1911
+ * replay ends. `state.tasks[].interrupts` is authoritative: parked ids it
1912
+ * lists are live, the rest are history.
1913
+ */
1914
+ async #settleParkedInterrupts() {
1915
+ const makePromise = async () => {
1916
+ try {
1917
+ const threadId = this.#currentThreadId;
1918
+ const generation = this.#submitGeneration;
1919
+ const deadline = Date.now() + PARKED_INTERRUPT_SETTLE_MS;
1920
+ for (;;) {
1921
+ if (this.#disposed || this.#currentThreadId !== threadId || this.#submitGeneration !== generation || this.#pendingHydrationInterruptEvents.length === 0) return;
1922
+ const parkedIds = new Set(this.#pendingHydrationInterruptEvents.map((event) => event.params.data.interrupt_id));
1923
+ const state = await this.#reconcilePendingInterruptsFromServer();
1924
+ if (state != null) {
1925
+ if ([...this.#hydratedActiveInterruptIds ?? []].some((id) => parkedIds.has(id)) || !isThreadStateActive(state)) {
1926
+ this.#pendingHydrationInterruptEvents = [];
1927
+ return;
1928
+ }
1929
+ }
1930
+ if (Date.now() >= deadline) return;
1931
+ await new Promise((resolve) => {
1932
+ setTimeout(resolve, PARKED_INTERRUPT_SETTLE_POLL_MS);
1933
+ });
1934
+ }
1935
+ } finally {
1936
+ this.#settleParkedInterruptsPromise = void 0;
1937
+ }
1938
+ };
1939
+ this.#settleParkedInterruptsPromise ??= makePromise();
1940
+ return this.#settleParkedInterruptsPromise;
1866
1941
  }
1867
1942
  /**
1868
1943
  * Resolve on the next root-namespace terminal lifecycle event
@@ -1908,6 +1983,7 @@ var StreamController = class {
1908
1983
  settled = true;
1909
1984
  unsubscribeRoot?.();
1910
1985
  unsubscribeThread?.();
1986
+ unsubscribeError?.();
1911
1987
  signal.removeEventListener("abort", finishAborted);
1912
1988
  resolve(result);
1913
1989
  }
@@ -1933,6 +2009,10 @@ var StreamController = class {
1933
2009
  };
1934
2010
  const unsubscribeRoot = this.#rootBus.subscribe(onEvent);
1935
2011
  const unsubscribeThread = this.#thread?.onEvent(onEvent);
2012
+ const unsubscribeError = this.#thread?.onError((error) => finish({
2013
+ event: "failed",
2014
+ error: error.message
2015
+ }));
1936
2016
  if (signal.aborted) finishAborted();
1937
2017
  else signal.addEventListener("abort", finishAborted, { once: true });
1938
2018
  });