@langgraph-js/pure-graph 3.2.0 → 3.2.3
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/adapter/fetch/index.js +124 -30
- package/dist/adapter/fetch/index.js.map +1 -1
- package/dist/adapter/fetch/utils.d.ts +13 -3
- package/dist/adapter/nextjs/index.js +1 -1
- package/dist/{checkpoint-C5AFBYE-.js → checkpoint-Due32543.js} +71 -41
- package/dist/checkpoint-Due32543.js.map +1 -0
- package/dist/{createEndpoint-C2KsYHDx.js → createEndpoint-CTPbz_D8.js} +20 -5
- package/dist/createEndpoint-CTPbz_D8.js.map +1 -0
- package/dist/createEndpoint.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/queue/stream_queue.d.ts +3 -1
- package/dist/{queue-DySatFkr.js → queue-DPHwOl26.js} +120 -16
- package/dist/queue-DPHwOl26.js.map +1 -0
- package/dist/remote/index.js +1 -1
- package/dist/{shallow-checkpoint-BEhTdp7z.js → shallow-checkpoint-CHYRdSct.js} +79 -49
- package/dist/shallow-checkpoint-CHYRdSct.js.map +1 -0
- package/dist/{sqlite-adapter-oBA95xba.js → sqlite-adapter-CJXgit1j.js} +7 -12
- package/dist/sqlite-adapter-CJXgit1j.js.map +1 -0
- package/dist/storage/memory/queue.d.ts +6 -0
- package/dist/storage/redis/queue.d.ts +14 -1
- package/dist/{stream-pZfO6Y-p.js → stream-Zt8tbgEj.js} +188 -63
- package/dist/stream-Zt8tbgEj.js.map +1 -0
- package/package.json +2 -1
- package/dist/checkpoint-C5AFBYE-.js.map +0 -1
- package/dist/createEndpoint-C2KsYHDx.js.map +0 -1
- package/dist/queue-DySatFkr.js.map +0 -1
- package/dist/shallow-checkpoint-BEhTdp7z.js.map +0 -1
- package/dist/sqlite-adapter-oBA95xba.js.map +0 -1
- package/dist/stream-pZfO6Y-p.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { s as serialiseAsDict, a as streamState, g as getGraph, L as LangGraphGlobal } from '../../stream-
|
|
2
|
-
import { c as createEndpoint } from '../../createEndpoint-
|
|
1
|
+
import { s as serialiseAsDict, a as streamState, g as getGraph, L as LangGraphGlobal } from '../../stream-Zt8tbgEj.js';
|
|
2
|
+
import { c as createEndpoint } from '../../createEndpoint-CTPbz_D8.js';
|
|
3
3
|
import z from 'zod';
|
|
4
4
|
import camelcaseKeys from 'camelcase-keys';
|
|
5
5
|
|
|
@@ -284,13 +284,15 @@ function errorResponse(error, status = 500) {
|
|
|
284
284
|
function createSSEStream(streamFn) {
|
|
285
285
|
let controller;
|
|
286
286
|
let isClosed = false;
|
|
287
|
+
const abortController = new AbortController();
|
|
287
288
|
const stream = new ReadableStream({
|
|
288
289
|
async start(ctrl) {
|
|
289
290
|
controller = ctrl;
|
|
290
291
|
const encoder = new TextEncoder();
|
|
291
292
|
const writer = {
|
|
293
|
+
signal: abortController.signal,
|
|
292
294
|
writeSSE: async ({ data, event, id }) => {
|
|
293
|
-
if (isClosed) {
|
|
295
|
+
if (isClosed || abortController.signal.aborted) {
|
|
294
296
|
return;
|
|
295
297
|
}
|
|
296
298
|
try {
|
|
@@ -308,7 +310,7 @@ function createSSEStream(streamFn) {
|
|
|
308
310
|
`;
|
|
309
311
|
controller.enqueue(encoder.encode(message));
|
|
310
312
|
} catch (error) {
|
|
311
|
-
if (!isClosed) {
|
|
313
|
+
if (!isClosed && !abortController.signal.aborted) {
|
|
312
314
|
throw error;
|
|
313
315
|
}
|
|
314
316
|
}
|
|
@@ -326,7 +328,9 @@ function createSSEStream(streamFn) {
|
|
|
326
328
|
try {
|
|
327
329
|
await streamFn(writer);
|
|
328
330
|
} catch (error) {
|
|
329
|
-
|
|
331
|
+
if (!abortController.signal.aborted) {
|
|
332
|
+
console.error("SSE stream error:", error);
|
|
333
|
+
}
|
|
330
334
|
} finally {
|
|
331
335
|
if (!isClosed) {
|
|
332
336
|
isClosed = true;
|
|
@@ -339,6 +343,9 @@ function createSSEStream(streamFn) {
|
|
|
339
343
|
},
|
|
340
344
|
cancel() {
|
|
341
345
|
isClosed = true;
|
|
346
|
+
if (!abortController.signal.aborted) {
|
|
347
|
+
abortController.abort("Client disconnected");
|
|
348
|
+
}
|
|
342
349
|
}
|
|
343
350
|
});
|
|
344
351
|
return new Response(stream, {
|
|
@@ -352,32 +359,42 @@ function createSSEStream(streamFn) {
|
|
|
352
359
|
function withHeartbeat(streamFn, heartbeatInterval = process.env.HEARTBEAT_INTERVAL ? parseInt(process.env.HEARTBEAT_INTERVAL) : 1500) {
|
|
353
360
|
return async (writer) => {
|
|
354
361
|
let heartbeatTimer = null;
|
|
355
|
-
|
|
362
|
+
let isCleaningUp = false;
|
|
363
|
+
const stopHeartbeat = () => {
|
|
356
364
|
if (heartbeatTimer) {
|
|
357
365
|
clearInterval(heartbeatTimer);
|
|
366
|
+
heartbeatTimer = null;
|
|
358
367
|
}
|
|
368
|
+
};
|
|
369
|
+
const startHeartbeat = () => {
|
|
370
|
+
stopHeartbeat();
|
|
359
371
|
heartbeatTimer = setInterval(async () => {
|
|
372
|
+
if (writer.signal.aborted || isCleaningUp) {
|
|
373
|
+
stopHeartbeat();
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
360
376
|
try {
|
|
361
377
|
await writer.writeSSE({ event: "ping", data: "{}" });
|
|
362
378
|
} catch (error) {
|
|
363
|
-
|
|
364
|
-
clearInterval(heartbeatTimer);
|
|
365
|
-
heartbeatTimer = null;
|
|
366
|
-
}
|
|
379
|
+
stopHeartbeat();
|
|
367
380
|
}
|
|
368
381
|
}, heartbeatInterval);
|
|
369
382
|
};
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
clearInterval(heartbeatTimer);
|
|
373
|
-
heartbeatTimer = null;
|
|
374
|
-
}
|
|
383
|
+
const abortHandler = () => {
|
|
384
|
+
stopHeartbeat();
|
|
375
385
|
};
|
|
386
|
+
writer.signal.addEventListener("abort", abortHandler);
|
|
376
387
|
const proxiedWriter = {
|
|
388
|
+
signal: writer.signal,
|
|
377
389
|
writeSSE: async (data) => {
|
|
390
|
+
if (writer.signal.aborted) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
378
393
|
stopHeartbeat();
|
|
379
394
|
await writer.writeSSE(data);
|
|
380
|
-
|
|
395
|
+
if (!writer.signal.aborted) {
|
|
396
|
+
startHeartbeat();
|
|
397
|
+
}
|
|
381
398
|
},
|
|
382
399
|
close: () => {
|
|
383
400
|
stopHeartbeat();
|
|
@@ -388,7 +405,9 @@ function withHeartbeat(streamFn, heartbeatInterval = process.env.HEARTBEAT_INTER
|
|
|
388
405
|
try {
|
|
389
406
|
await streamFn(proxiedWriter);
|
|
390
407
|
} finally {
|
|
408
|
+
isCleaningUp = true;
|
|
391
409
|
stopHeartbeat();
|
|
410
|
+
writer.signal.removeEventListener("abort", abortHandler);
|
|
392
411
|
}
|
|
393
412
|
};
|
|
394
413
|
}
|
|
@@ -715,12 +734,33 @@ async function streamRun(req, context) {
|
|
|
715
734
|
if (langgraphContext) {
|
|
716
735
|
Object.assign(payload.config.configurable, langgraphContext);
|
|
717
736
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
737
|
+
let generator = null;
|
|
738
|
+
let isCleaningUp = false;
|
|
739
|
+
const abortHandler = () => {
|
|
740
|
+
isCleaningUp = true;
|
|
741
|
+
};
|
|
742
|
+
writer.signal.addEventListener("abort", abortHandler);
|
|
743
|
+
try {
|
|
744
|
+
generator = client.runs.stream(thread_id, payload.assistant_id, camelcaseKeys(payload));
|
|
745
|
+
for await (const { event, data } of generator) {
|
|
746
|
+
if (isCleaningUp || writer.signal.aborted) {
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
await writer.writeSSE({ data: serialiseAsDict(data) ?? "", event });
|
|
750
|
+
}
|
|
751
|
+
} catch (error) {
|
|
752
|
+
if (!writer.signal.aborted && !isCleaningUp) {
|
|
753
|
+
throw error;
|
|
754
|
+
}
|
|
755
|
+
} finally {
|
|
756
|
+
writer.signal.removeEventListener("abort", abortHandler);
|
|
757
|
+
if (generator) {
|
|
758
|
+
try {
|
|
759
|
+
await generator.return(void 0);
|
|
760
|
+
} catch (e) {
|
|
761
|
+
}
|
|
762
|
+
generator = null;
|
|
763
|
+
}
|
|
724
764
|
}
|
|
725
765
|
})
|
|
726
766
|
);
|
|
@@ -737,19 +777,33 @@ async function joinRunStream(req, context) {
|
|
|
737
777
|
return createSSEStream(
|
|
738
778
|
withHeartbeat(async (writer) => {
|
|
739
779
|
const controller = new AbortController();
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
780
|
+
let generator = null;
|
|
781
|
+
let isCleaningUp = false;
|
|
782
|
+
const abortHandlers = [];
|
|
783
|
+
const cleanup = () => {
|
|
784
|
+
controller.abort("Client disconnected");
|
|
785
|
+
};
|
|
786
|
+
if (req.signal) {
|
|
787
|
+
req.signal.addEventListener("abort", cleanup);
|
|
788
|
+
abortHandlers.push({ signal: req.signal, handler: cleanup });
|
|
745
789
|
}
|
|
790
|
+
const writerAbortHandler = () => {
|
|
791
|
+
isCleaningUp = true;
|
|
792
|
+
controller.abort("SSE stream closed");
|
|
793
|
+
};
|
|
794
|
+
writer.signal.addEventListener("abort", writerAbortHandler);
|
|
795
|
+
abortHandlers.push({ signal: writer.signal, handler: writerAbortHandler });
|
|
746
796
|
try {
|
|
747
|
-
|
|
797
|
+
generator = client.runs.joinStream(thread_id, run_id, {
|
|
748
798
|
signal: controller.signal,
|
|
749
799
|
cancelOnDisconnect: cancel_on_disconnect,
|
|
750
800
|
lastEventId: last_event_id,
|
|
751
801
|
streamMode: stream_mode ? [stream_mode] : void 0
|
|
752
|
-
})
|
|
802
|
+
});
|
|
803
|
+
for await (const { event, data, id } of generator) {
|
|
804
|
+
if (isCleaningUp || writer.signal.aborted || controller.signal.aborted) {
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
753
807
|
await writer.writeSSE({
|
|
754
808
|
data: serialiseAsDict(data) ?? "",
|
|
755
809
|
event,
|
|
@@ -757,7 +811,8 @@ async function joinRunStream(req, context) {
|
|
|
757
811
|
});
|
|
758
812
|
}
|
|
759
813
|
} catch (error) {
|
|
760
|
-
|
|
814
|
+
const isAbortError = controller.signal.aborted || writer.signal.aborted;
|
|
815
|
+
if (!isAbortError && !(error instanceof Error && error.message.includes("user cancel"))) {
|
|
761
816
|
console.error("Join stream error:", error);
|
|
762
817
|
await writer.writeSSE({
|
|
763
818
|
event: "error",
|
|
@@ -766,6 +821,20 @@ async function joinRunStream(req, context) {
|
|
|
766
821
|
})
|
|
767
822
|
});
|
|
768
823
|
}
|
|
824
|
+
} finally {
|
|
825
|
+
for (const { signal, handler } of abortHandlers) {
|
|
826
|
+
try {
|
|
827
|
+
signal.removeEventListener("abort", handler);
|
|
828
|
+
} catch (e) {
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (generator) {
|
|
832
|
+
try {
|
|
833
|
+
await generator.return(void 0);
|
|
834
|
+
} catch (e) {
|
|
835
|
+
}
|
|
836
|
+
generator = null;
|
|
837
|
+
}
|
|
769
838
|
}
|
|
770
839
|
})
|
|
771
840
|
);
|
|
@@ -819,6 +888,7 @@ async function createRun(req, context) {
|
|
|
819
888
|
const threads = client.threads;
|
|
820
889
|
const run = await threads.createRun(thread_id, payload.assistant_id, camelPayload);
|
|
821
890
|
(async () => {
|
|
891
|
+
let queueCleared = false;
|
|
822
892
|
try {
|
|
823
893
|
for await (const _ of streamState(threads, run, camelPayload, {
|
|
824
894
|
attempt: 0,
|
|
@@ -827,6 +897,14 @@ async function createRun(req, context) {
|
|
|
827
897
|
}
|
|
828
898
|
} catch (error) {
|
|
829
899
|
console.error("Background run error:", error);
|
|
900
|
+
} finally {
|
|
901
|
+
if (!queueCleared) {
|
|
902
|
+
queueCleared = true;
|
|
903
|
+
try {
|
|
904
|
+
await LangGraphGlobal.globalMessageQueue.removeQueue(run.run_id);
|
|
905
|
+
} catch (e) {
|
|
906
|
+
}
|
|
907
|
+
}
|
|
830
908
|
}
|
|
831
909
|
})();
|
|
832
910
|
return jsonResponse(run, 200, {
|
|
@@ -955,6 +1033,7 @@ async function createStatelessRun(req, context) {
|
|
|
955
1033
|
camelPayload.temporary = true;
|
|
956
1034
|
const run = await threads.createRun(thread.thread_id, payload.assistant_id, camelPayload);
|
|
957
1035
|
(async () => {
|
|
1036
|
+
let queueCleared = false;
|
|
958
1037
|
try {
|
|
959
1038
|
for await (const _ of streamState(threads, run, camelPayload, {
|
|
960
1039
|
attempt: 0,
|
|
@@ -969,6 +1048,13 @@ async function createStatelessRun(req, context) {
|
|
|
969
1048
|
} catch (e) {
|
|
970
1049
|
console.error("Error cleaning up temporary thread:", e);
|
|
971
1050
|
}
|
|
1051
|
+
if (!queueCleared) {
|
|
1052
|
+
queueCleared = true;
|
|
1053
|
+
try {
|
|
1054
|
+
await LangGraphGlobal.globalMessageQueue.removeQueue(run.run_id);
|
|
1055
|
+
} catch (e) {
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
972
1058
|
}
|
|
973
1059
|
})();
|
|
974
1060
|
return jsonResponse(run, 200, {
|
|
@@ -1092,6 +1178,7 @@ async function createBatchRuns(req, context) {
|
|
|
1092
1178
|
camelPayload.temporary = true;
|
|
1093
1179
|
const run = await threads.createRun(thread.thread_id, payload.assistant_id, camelPayload);
|
|
1094
1180
|
(async () => {
|
|
1181
|
+
let queueCleared = false;
|
|
1095
1182
|
try {
|
|
1096
1183
|
for await (const _ of streamState(threads, run, camelPayload, {
|
|
1097
1184
|
attempt: 0,
|
|
@@ -1106,6 +1193,13 @@ async function createBatchRuns(req, context) {
|
|
|
1106
1193
|
} catch (e) {
|
|
1107
1194
|
console.error("Error cleaning up temporary thread:", e);
|
|
1108
1195
|
}
|
|
1196
|
+
if (!queueCleared) {
|
|
1197
|
+
queueCleared = true;
|
|
1198
|
+
try {
|
|
1199
|
+
await LangGraphGlobal.globalMessageQueue.removeQueue(run.run_id);
|
|
1200
|
+
} catch (e) {
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1109
1203
|
}
|
|
1110
1204
|
})();
|
|
1111
1205
|
return { thread_id: thread.thread_id, run_id: run.run_id };
|