@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.
- package/dist/client/stream/index.cjs +23 -1
- package/dist/client/stream/index.cjs.map +1 -1
- package/dist/client/stream/index.d.cts +6 -0
- package/dist/client/stream/index.d.cts.map +1 -1
- package/dist/client/stream/index.d.ts +6 -0
- package/dist/client/stream/index.d.ts.map +1 -1
- package/dist/client/stream/index.js +23 -1
- package/dist/client/stream/index.js.map +1 -1
- package/dist/client/stream/transport/http.cjs +23 -5
- package/dist/client/stream/transport/http.cjs.map +1 -1
- package/dist/client/stream/transport/http.d.cts +1 -0
- package/dist/client/stream/transport/http.d.cts.map +1 -1
- package/dist/client/stream/transport/http.d.ts +1 -0
- package/dist/client/stream/transport/http.d.ts.map +1 -1
- package/dist/client/stream/transport/http.js +23 -5
- package/dist/client/stream/transport/http.js.map +1 -1
- package/dist/client/stream/transport/types.d.cts +9 -12
- package/dist/client/stream/transport/types.d.cts.map +1 -1
- package/dist/client/stream/transport/types.d.ts +9 -12
- package/dist/client/stream/transport/types.d.ts.map +1 -1
- package/dist/client/stream/transport/websocket.cjs +15 -3
- package/dist/client/stream/transport/websocket.cjs.map +1 -1
- package/dist/client/stream/transport/websocket.d.cts +1 -0
- package/dist/client/stream/transport/websocket.d.cts.map +1 -1
- package/dist/client/stream/transport/websocket.d.ts +1 -0
- package/dist/client/stream/transport/websocket.d.ts.map +1 -1
- package/dist/client/stream/transport/websocket.js +15 -3
- package/dist/client/stream/transport/websocket.js.map +1 -1
- package/dist/client/stream/types.d.cts +5 -7
- package/dist/client/stream/types.d.cts.map +1 -1
- package/dist/client/stream/types.d.ts +5 -7
- package/dist/client/stream/types.d.ts.map +1 -1
- package/dist/client/threads/index.cjs +2 -1
- package/dist/client/threads/index.cjs.map +1 -1
- package/dist/client/threads/index.js +2 -1
- package/dist/client/threads/index.js.map +1 -1
- package/dist/stream/controller.cjs +111 -31
- package/dist/stream/controller.cjs.map +1 -1
- package/dist/stream/controller.d.cts.map +1 -1
- package/dist/stream/controller.d.ts.map +1 -1
- package/dist/stream/controller.js +111 -31
- package/dist/stream/controller.js.map +1 -1
- package/dist/stream/types.d.cts +5 -0
- package/dist/stream/types.d.cts.map +1 -1
- package/dist/stream/types.d.ts +5 -0
- package/dist/stream/types.d.ts.map +1 -1
- package/dist/utils/reconnect.cjs.map +1 -1
- package/dist/utils/reconnect.d.cts +18 -0
- package/dist/utils/reconnect.d.cts.map +1 -0
- package/dist/utils/reconnect.d.ts +18 -0
- package/dist/utils/reconnect.d.ts.map +1 -0
- package/dist/utils/reconnect.js.map +1 -1
- 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;;
|
|
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;;;
|
|
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
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
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
|
|
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)
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
1780
|
+
const barrier = this.#interruptReplayThroughSeq;
|
|
1781
|
+
if (isUnknownInterrupt && barrier == null) {
|
|
1745
1782
|
this.#pendingHydrationInterruptEvents.push(event);
|
|
1746
1783
|
return;
|
|
1747
1784
|
}
|
|
1748
|
-
if (isUnknownInterrupt &&
|
|
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
|
-
|
|
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
|
});
|