@langchain/langgraph-sdk 1.9.20 → 1.9.22

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 (132) hide show
  1. package/dist/client/base.cjs +4 -1
  2. package/dist/client/base.cjs.map +1 -1
  3. package/dist/client/base.d.cts +2 -0
  4. package/dist/client/base.d.cts.map +1 -1
  5. package/dist/client/base.d.ts +2 -0
  6. package/dist/client/base.d.ts.map +1 -1
  7. package/dist/client/base.js +5 -2
  8. package/dist/client/base.js.map +1 -1
  9. package/dist/client/index.cjs +1 -1
  10. package/dist/client/index.js +1 -1
  11. package/dist/client/runs/index.cjs +2 -0
  12. package/dist/client/runs/index.cjs.map +1 -1
  13. package/dist/client/runs/index.d.cts +15 -0
  14. package/dist/client/runs/index.d.cts.map +1 -1
  15. package/dist/client/runs/index.d.ts +15 -0
  16. package/dist/client/runs/index.d.ts.map +1 -1
  17. package/dist/client/runs/index.js +2 -0
  18. package/dist/client/runs/index.js.map +1 -1
  19. package/dist/client/stream/error.cjs +21 -0
  20. package/dist/client/stream/error.cjs.map +1 -1
  21. package/dist/client/stream/error.js +21 -1
  22. package/dist/client/stream/error.js.map +1 -1
  23. package/dist/client/stream/index.cjs +24 -1
  24. package/dist/client/stream/index.cjs.map +1 -1
  25. package/dist/client/stream/index.d.cts.map +1 -1
  26. package/dist/client/stream/index.d.ts.map +1 -1
  27. package/dist/client/stream/index.js +24 -1
  28. package/dist/client/stream/index.js.map +1 -1
  29. package/dist/client/stream/transport/agent-server.cjs +8 -2
  30. package/dist/client/stream/transport/agent-server.cjs.map +1 -1
  31. package/dist/client/stream/transport/agent-server.d.cts +17 -2
  32. package/dist/client/stream/transport/agent-server.d.cts.map +1 -1
  33. package/dist/client/stream/transport/agent-server.d.ts +17 -2
  34. package/dist/client/stream/transport/agent-server.d.ts.map +1 -1
  35. package/dist/client/stream/transport/agent-server.js +8 -2
  36. package/dist/client/stream/transport/agent-server.js.map +1 -1
  37. package/dist/client/stream/transport/http.cjs +81 -21
  38. package/dist/client/stream/transport/http.cjs.map +1 -1
  39. package/dist/client/stream/transport/http.d.cts +22 -7
  40. package/dist/client/stream/transport/http.d.cts.map +1 -1
  41. package/dist/client/stream/transport/http.d.ts +22 -7
  42. package/dist/client/stream/transport/http.d.ts.map +1 -1
  43. package/dist/client/stream/transport/http.js +83 -23
  44. package/dist/client/stream/transport/http.js.map +1 -1
  45. package/dist/client/stream/transport/index.cjs +2 -1
  46. package/dist/client/stream/transport/index.js +2 -1
  47. package/dist/client/stream/transport/types.d.cts +85 -5
  48. package/dist/client/stream/transport/types.d.cts.map +1 -1
  49. package/dist/client/stream/transport/types.d.ts +85 -5
  50. package/dist/client/stream/transport/types.d.ts.map +1 -1
  51. package/dist/client/stream/transport/utils.cjs +19 -0
  52. package/dist/client/stream/transport/utils.cjs.map +1 -1
  53. package/dist/client/stream/transport/utils.js +19 -1
  54. package/dist/client/stream/transport/utils.js.map +1 -1
  55. package/dist/client/stream/transport/websocket.cjs +125 -21
  56. package/dist/client/stream/transport/websocket.cjs.map +1 -1
  57. package/dist/client/stream/transport/websocket.d.cts +32 -4
  58. package/dist/client/stream/transport/websocket.d.cts.map +1 -1
  59. package/dist/client/stream/transport/websocket.d.ts +32 -4
  60. package/dist/client/stream/transport/websocket.d.ts.map +1 -1
  61. package/dist/client/stream/transport/websocket.js +126 -23
  62. package/dist/client/stream/transport/websocket.js.map +1 -1
  63. package/dist/client/stream/transport.d.cts +20 -3
  64. package/dist/client/stream/transport.d.cts.map +1 -1
  65. package/dist/client/stream/transport.d.ts +20 -3
  66. package/dist/client/stream/transport.d.ts.map +1 -1
  67. package/dist/client/stream/types.d.cts +31 -0
  68. package/dist/client/stream/types.d.cts.map +1 -1
  69. package/dist/client/stream/types.d.ts +31 -0
  70. package/dist/client/stream/types.d.ts.map +1 -1
  71. package/dist/client/threads/index.cjs +36 -17
  72. package/dist/client/threads/index.cjs.map +1 -1
  73. package/dist/client/threads/index.js +35 -16
  74. package/dist/client/threads/index.js.map +1 -1
  75. package/dist/client.cjs +1 -1
  76. package/dist/client.js +1 -1
  77. package/dist/index.cjs +1 -1
  78. package/dist/index.js +1 -1
  79. package/dist/react-ui/server/server.cjs +2 -2
  80. package/dist/react-ui/server/server.cjs.map +1 -1
  81. package/dist/react-ui/server/server.js +1 -1
  82. package/dist/react-ui/server/server.js.map +1 -1
  83. package/dist/stream/controller.cjs +21 -3
  84. package/dist/stream/controller.cjs.map +1 -1
  85. package/dist/stream/controller.d.cts.map +1 -1
  86. package/dist/stream/controller.d.ts.map +1 -1
  87. package/dist/stream/controller.js +20 -2
  88. package/dist/stream/controller.js.map +1 -1
  89. package/dist/stream/index.cjs +2 -0
  90. package/dist/stream/index.d.cts +2 -1
  91. package/dist/stream/index.d.ts +2 -1
  92. package/dist/stream/index.js +2 -1
  93. package/dist/stream/projections/channel-effect.cjs +52 -0
  94. package/dist/stream/projections/channel-effect.cjs.map +1 -0
  95. package/dist/stream/projections/channel-effect.d.cts +35 -0
  96. package/dist/stream/projections/channel-effect.d.cts.map +1 -0
  97. package/dist/stream/projections/channel-effect.d.ts +35 -0
  98. package/dist/stream/projections/channel-effect.d.ts.map +1 -0
  99. package/dist/stream/projections/channel-effect.js +52 -0
  100. package/dist/stream/projections/channel-effect.js.map +1 -0
  101. package/dist/stream/projections/index.cjs +1 -0
  102. package/dist/stream/projections/index.d.ts +1 -0
  103. package/dist/stream/projections/index.js +1 -0
  104. package/dist/stream/root-message-projection.cjs +55 -0
  105. package/dist/stream/root-message-projection.cjs.map +1 -1
  106. package/dist/stream/root-message-projection.js +55 -0
  107. package/dist/stream/root-message-projection.js.map +1 -1
  108. package/dist/stream/submit-coordinator.cjs +3 -3
  109. package/dist/stream/submit-coordinator.cjs.map +1 -1
  110. package/dist/stream/submit-coordinator.js +1 -1
  111. package/dist/stream/submit-coordinator.js.map +1 -1
  112. package/dist/types.d.cts +20 -0
  113. package/dist/types.d.cts.map +1 -1
  114. package/dist/types.d.ts +20 -0
  115. package/dist/types.d.ts.map +1 -1
  116. package/dist/ui/branching.d.cts +1 -1
  117. package/dist/ui/branching.d.ts +1 -1
  118. package/dist/ui/orchestrator.d.cts +1 -1
  119. package/dist/ui/orchestrator.d.cts.map +1 -1
  120. package/dist/ui/orchestrator.d.ts +1 -1
  121. package/dist/ui/orchestrator.d.ts.map +1 -1
  122. package/dist/utils/index.d.cts +1 -1
  123. package/dist/utils/index.d.ts +1 -1
  124. package/dist/utils/stream.cjs +94 -0
  125. package/dist/utils/stream.cjs.map +1 -1
  126. package/dist/utils/stream.d.cts +16 -2
  127. package/dist/utils/stream.d.cts.map +1 -1
  128. package/dist/utils/stream.d.ts +16 -2
  129. package/dist/utils/stream.d.ts.map +1 -1
  130. package/dist/utils/stream.js +94 -1
  131. package/dist/utils/stream.js.map +1 -1
  132. package/package.json +6 -5
@@ -3,17 +3,31 @@ type IterableReadableStreamInterface<T> = ReadableStream<T> & AsyncIterable<T>;
3
3
  /**
4
4
  * Options for streaming with automatic retry logic.
5
5
  */
6
+ /**
7
+ * How {@link idleReconnectStream} decides when the connection is idle.
8
+ *
9
+ * - A `number` is a fixed idle window in milliseconds: the watchdog arms
10
+ * immediately (even before the first byte) and trips after that long with no
11
+ * activity. Use when you know your server's behaviour and want guaranteed
12
+ * coverage from t=0; it does not depend on heartbeats.
13
+ * - `"auto"` is heartbeat-adaptive: the watchdog stays dormant until it has
14
+ * observed the server's SSE keep-alive comments (e.g. LangGraph Platform's
15
+ * `: heartbeat` every ~5s), then arms with a window derived from the
16
+ * observed cadence. On a server that never sends heartbeats it never arms,
17
+ * so it can't false-fire during a legitimately quiet period.
18
+ */
19
+ type IdleReconnectMode = number | "auto";
6
20
  declare class IterableReadableStream<T> extends ReadableStream<T> implements IterableReadableStreamInterface<T> {
7
- [Symbol.asyncDispose]: () => Promise<void>;
8
21
  reader: ReadableStreamDefaultReader<T>;
9
22
  ensureReader(): void;
10
23
  next(): Promise<IteratorResult<T>>;
11
24
  return(): Promise<IteratorResult<T>>;
12
25
  throw(e: any): Promise<IteratorResult<T>>;
26
+ [Symbol.asyncDispose](): Promise<void>;
13
27
  [Symbol.asyncIterator](): this;
14
28
  static fromReadableStream<T>(stream: ReadableStream<T>): IterableReadableStream<T>;
15
29
  static fromAsyncGenerator<T>(generator: AsyncGenerator<T>): IterableReadableStream<T>;
16
30
  }
17
31
  //#endregion
18
- export { IterableReadableStream };
32
+ export { IdleReconnectMode, IterableReadableStream };
19
33
  //# sourceMappingURL=stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","names":[],"sources":["../../src/utils/stream.ts"],"mappings":";KAGK,+BAAA,MAAqC,cAAA,CAAe,CAAA,IAAK,aAAA,CAAc,CAAA;;;;cAyL/D,sBAAA,YACH,cAAA,CAAe,CAAA,aACZ,+BAAA,CAAgC,CAAA;EAAA,CAwDpC,MAAA,CAAO,YAAA,SAAa,OAAA;EAtDpB,MAAA,EAAQ,2BAAA,CAA4B,CAAA;EAE3C,YAAA,CAAA;EAMM,IAAA,CAAA,GAAQ,OAAA,CAAQ,cAAA,CAAe,CAAA;EAsB/B,MAAA,CAAA,GAAU,OAAA,CAAQ,cAAA,CAAe,CAAA;EAYjC,KAAA,CAAM,CAAA,QAAS,OAAA,CAAQ,cAAA,CAAe,CAAA;EAAA,CAgB3C,MAAA,CAAO,aAAA;EAAA,OAID,kBAAA,GAAA,CAAsB,MAAA,EAAQ,cAAA,CAAe,CAAA,IAAE,sBAAA,CAAA,CAAA;EAAA,OAyB/C,kBAAA,GAAA,CAAsB,SAAA,EAAW,cAAA,CAAe,CAAA,IAAE,sBAAA,CAAA,CAAA;AAAA"}
1
+ {"version":3,"file":"stream.d.ts","names":[],"sources":["../../src/utils/stream.ts"],"mappings":";KAGK,+BAAA,MAAqC,cAAA,CAAe,CAAA,IAAK,aAAA,CAAc,CAAA;;;;;;;;;;;;;;;;;KAwFhE,iBAAA;AAAA,cA2PC,sBAAA,YACH,cAAA,CAAe,CAAA,aACZ,+BAAA,CAAgC,CAAA;EAEpC,MAAA,EAAQ,2BAAA,CAA4B,CAAA;EAE3C,YAAA,CAAA;EAMM,IAAA,CAAA,GAAQ,OAAA,CAAQ,cAAA,CAAe,CAAA;EAsB/B,MAAA,CAAA,GAAU,OAAA,CAAQ,cAAA,CAAe,CAAA;EAYjC,KAAA,CAAM,CAAA,QAAS,OAAA,CAAQ,cAAA,CAAe,CAAA;EAAA,CAYrC,MAAA,CAAO,YAAA,KAAa,OAAA;EAAA,CAI1B,MAAA,CAAO,aAAA;EAAA,OAID,kBAAA,GAAA,CAAsB,MAAA,EAAQ,cAAA,CAAe,CAAA,IAAE,sBAAA,CAAA,CAAA;EAAA,OAyB/C,kBAAA,GAAA,CAAsB,SAAA,EAAW,cAAA,CAAe,CAAA,IAAE,sBAAA,CAAA,CAAA;AAAA"}
@@ -11,6 +11,99 @@ var MaxReconnectAttemptsError = class extends Error {
11
11
  }
12
12
  };
13
13
  /**
14
+ * Error injected into the stream by {@link idleReconnectStream} when no lines
15
+ * arrive within the active idle window. Surfacing this during the read is what
16
+ * lets the reconnect loops in `streamWithRetry` and the protocol SSE transport
17
+ * recover from a half-open socket — one that was silently dropped (e.g. a hard
18
+ * pod kill on a platform revision rollover) without a TCP FIN/RST, so neither
19
+ * a `done` nor a thrown network error ever arrives.
20
+ */
21
+ var StreamIdleTimeoutError = class extends Error {
22
+ idleTimeoutMs;
23
+ constructor(idleTimeoutMs) {
24
+ super(`No SSE bytes received for ${idleTimeoutMs}ms; assuming the connection is half-open and reconnecting.`);
25
+ this.name = "StreamIdleTimeoutError";
26
+ this.idleTimeoutMs = idleTimeoutMs;
27
+ }
28
+ };
29
+ /** `":"` — first byte of an SSE comment / keep-alive line. */
30
+ const SSE_COMMENT_BYTE = 58;
31
+ /**
32
+ * A pass-through {@link TransformStream} that errors the stream when it goes
33
+ * idle, so the surrounding reconnect logic can recover a half-open socket.
34
+ *
35
+ * MUST sit on the *line* stream — i.e. after
36
+ * {@link import("./sse.js").BytesLineDecoder} but before
37
+ * {@link import("./sse.js").SSEDecoder} (which discards `:` comment lines).
38
+ * Operating at the line level lets the watchdog both (a) reset on any line
39
+ * (data *or* heartbeat = liveness) and (b) recognise heartbeat comment lines
40
+ * to drive `"auto"` mode.
41
+ *
42
+ * In `"auto"` mode the watchdog is intentionally dormant until it has seen at
43
+ * least two heartbeats (so it can measure the cadence). This means a socket
44
+ * that dies inside the first heartbeat interval won't be caught until a
45
+ * heartbeat would have been due — an acceptable trade for never false-firing
46
+ * on heartbeat-less servers. Pass a fixed `number` if you need coverage from
47
+ * the very first byte.
48
+ */
49
+ function idleReconnectStream(options) {
50
+ const factor = options.timeoutFactor ?? 3;
51
+ const minTimeoutMs = options.minTimeoutMs ?? 6e3;
52
+ const maxTimeoutMs = options.maxTimeoutMs ?? 3e4;
53
+ const fixedTimeoutMs = typeof options.mode === "number" ? options.mode : null;
54
+ let timer;
55
+ let controllerRef;
56
+ let lastHeartbeatAt;
57
+ let derivedTimeoutMs = fixedTimeoutMs;
58
+ const clear = () => {
59
+ if (timer != null) {
60
+ clearTimeout(timer);
61
+ timer = void 0;
62
+ }
63
+ };
64
+ const arm = () => {
65
+ clear();
66
+ const timeoutMs = derivedTimeoutMs;
67
+ if (timeoutMs == null || timeoutMs <= 0) return;
68
+ timer = setTimeout(() => {
69
+ options.onIdle?.({
70
+ timeoutMs,
71
+ source: fixedTimeoutMs != null ? "fixed" : "heartbeat"
72
+ });
73
+ try {
74
+ controllerRef?.error(new StreamIdleTimeoutError(timeoutMs));
75
+ } catch {}
76
+ }, timeoutMs);
77
+ timer.unref?.();
78
+ };
79
+ const noteHeartbeat = () => {
80
+ if (fixedTimeoutMs != null) return;
81
+ const now = Date.now();
82
+ if (lastHeartbeatAt != null) {
83
+ const interval = now - lastHeartbeatAt;
84
+ if (interval > 0) {
85
+ const candidate = Math.min(Math.max(interval * factor, minTimeoutMs), maxTimeoutMs);
86
+ derivedTimeoutMs = derivedTimeoutMs == null ? candidate : Math.max(derivedTimeoutMs, candidate);
87
+ }
88
+ }
89
+ lastHeartbeatAt = now;
90
+ };
91
+ return new TransformStream({
92
+ start(controller) {
93
+ controllerRef = controller;
94
+ arm();
95
+ },
96
+ transform(line, controller) {
97
+ if (line.length > 0 && line[0] === SSE_COMMENT_BYTE) noteHeartbeat();
98
+ arm();
99
+ controller.enqueue(line);
100
+ },
101
+ flush() {
102
+ clear();
103
+ }
104
+ });
105
+ }
106
+ /**
14
107
  * Stream with automatic retry logic for SSE connections.
15
108
  * Implements reconnection behavior similar to the Python SDK.
16
109
  *
@@ -167,6 +260,6 @@ var IterableReadableStream = class IterableReadableStream extends ReadableStream
167
260
  }
168
261
  };
169
262
  //#endregion
170
- export { IterableReadableStream, streamWithRetry };
263
+ export { IterableReadableStream, idleReconnectStream, streamWithRetry };
171
264
 
172
265
  //# sourceMappingURL=stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","names":[],"sources":["../../src/utils/stream.ts"],"sourcesContent":["import { isNetworkError } from \"./error.js\";\n\n// in this case don't quite match.\ntype IterableReadableStreamInterface<T> = ReadableStream<T> & AsyncIterable<T>;\n\n/**\n * Options for streaming with automatic retry logic.\n */\nexport interface StreamWithRetryOptions {\n /**\n * Maximum number of reconnection attempts. Default is 5.\n */\n maxRetries?: number;\n\n /**\n * AbortSignal to cancel the stream.\n */\n signal?: AbortSignal;\n\n /**\n * Callback invoked when a reconnection attempt is made.\n */\n onReconnect?: (options: {\n attempt: number;\n lastEventId?: string;\n cause: unknown;\n }) => void;\n}\n\n/**\n * Parameters for making a stream request\n */\nexport interface StreamRequestParams {\n /**\n * Last event ID to resume from, if available\n */\n lastEventId?: string;\n\n /**\n * Optional reconnection path from the Location header\n */\n reconnectPath?: string;\n}\n\n/**\n * Error thrown when maximum reconnection attempts are exceeded.\n */\nexport class MaxReconnectAttemptsError extends Error {\n constructor(maxAttempts: number, cause: unknown) {\n super(`Exceeded maximum SSE reconnection attempts (${maxAttempts})`);\n this.name = \"MaxReconnectAttemptsError\";\n this.cause = cause;\n }\n}\n\n/**\n * Stream with automatic retry logic for SSE connections.\n * Implements reconnection behavior similar to the Python SDK.\n *\n * @param makeRequest Function to make requests. When `params` is undefined/empty, it's the initial request.\n * When `params.reconnectPath` is provided, it's a reconnection request.\n * @param options Configuration options\n * @returns AsyncGenerator yielding stream events\n */\nexport async function* streamWithRetry<T extends { id?: string }>(\n makeRequest: (params?: StreamRequestParams) => Promise<{\n response: Response;\n stream: ReadableStream<T>;\n }>,\n options: StreamWithRetryOptions = {}\n): AsyncGenerator<T> {\n const maxRetries = options.maxRetries ?? 5;\n let attempt = 0;\n let lastEventId: string | undefined;\n let reconnectPath: string | undefined;\n\n while (true) {\n let shouldRetry = false;\n let lastError: unknown;\n let reader: ReadableStreamDefaultReader<T> | undefined;\n\n try {\n // Check if aborted before making request\n if (options.signal?.aborted) return;\n\n // Make request - initial if no reconnect path, reconnect otherwise\n const { response, stream } = await makeRequest(\n reconnectPath ? { lastEventId, reconnectPath } : undefined\n );\n\n // Check for Location header (server-provided reconnection path)\n const locationHeader = response.headers.get(\"location\");\n if (locationHeader) {\n reconnectPath = locationHeader;\n }\n\n // Verify content type\n const contentType = response.headers.get(\"content-type\")?.split(\";\")[0];\n if (contentType && !contentType.includes(\"text/event-stream\")) {\n throw new Error(\n `Expected response header Content-Type to contain 'text/event-stream', got '${contentType}'`\n );\n }\n\n reader = stream.getReader();\n\n try {\n while (true) {\n // Check abort signal before each read\n if (options.signal?.aborted) {\n await reader.cancel();\n return;\n }\n\n const { done, value } = await reader.read();\n\n if (done) {\n // Stream completed successfully\n break;\n }\n\n // Track last event ID for reconnection\n if (value.id) {\n lastEventId = value.id;\n }\n\n yield value;\n }\n\n // Stream completed successfully, exit retry loop\n break;\n } catch (error) {\n // Error during streaming - attempt reconnect if we have a location header\n if (reconnectPath && !options.signal?.aborted) {\n shouldRetry = true;\n } else {\n throw error;\n }\n } finally {\n if (reader) {\n try {\n reader.releaseLock();\n } catch {\n // Ignore errors when releasing lock\n }\n }\n }\n } catch (error) {\n lastError = error;\n\n // Only retry if we have reconnection capability and it's a network error\n if (isNetworkError(error) && reconnectPath && !options.signal?.aborted) {\n shouldRetry = true;\n } else {\n throw error;\n }\n }\n\n if (shouldRetry) {\n attempt += 1;\n if (attempt > maxRetries) {\n throw new MaxReconnectAttemptsError(maxRetries, lastError);\n }\n\n // Notify about reconnection attempt\n options.onReconnect?.({ attempt, lastEventId, cause: lastError });\n\n // Exponential backoff with jitter: min(1000 * 2^attempt, 5000) + random jitter\n const baseDelay = Math.min(1000 * 2 ** (attempt - 1), 5000);\n const jitter = Math.random() * 1000;\n const delay = baseDelay + jitter;\n\n await new Promise((resolve) => {\n setTimeout(resolve, delay);\n });\n\n continue;\n }\n\n // Successfully completed\n break;\n }\n}\n\n/*\n * Support async iterator syntax for ReadableStreams in all environments.\n * Source: https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490\n */\nexport class IterableReadableStream<T>\n extends ReadableStream<T>\n implements IterableReadableStreamInterface<T>\n{\n public reader: ReadableStreamDefaultReader<T>;\n\n ensureReader() {\n if (!this.reader) {\n this.reader = this.getReader();\n }\n }\n\n async next(): Promise<IteratorResult<T>> {\n this.ensureReader();\n try {\n const result = await this.reader.read();\n if (result.done) {\n this.reader.releaseLock(); // release lock when stream becomes closed\n return {\n done: true,\n value: undefined,\n };\n } else {\n return {\n done: false,\n value: result.value,\n };\n }\n } catch (e) {\n this.reader.releaseLock(); // release lock when stream becomes errored\n throw e;\n }\n }\n\n async return(): Promise<IteratorResult<T>> {\n this.ensureReader();\n // If wrapped in a Node stream, cancel is already called.\n if (this.locked) {\n const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet\n this.reader.releaseLock(); // release lock first\n await cancelPromise; // now await it\n }\n return { done: true, value: undefined };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async throw(e: any): Promise<IteratorResult<T>> {\n this.ensureReader();\n if (this.locked) {\n const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet\n this.reader.releaseLock(); // release lock first\n await cancelPromise; // now await it\n }\n throw e;\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore Not present in Node 18 types, required in latest Node 22\n async [Symbol.asyncDispose]() {\n await this.return();\n }\n\n [Symbol.asyncIterator]() {\n return this;\n }\n\n static fromReadableStream<T>(stream: ReadableStream<T>) {\n // From https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams#reading_the_stream\n const reader = stream.getReader();\n return new IterableReadableStream<T>({\n start(controller) {\n return pump();\n function pump(): Promise<T | undefined> {\n return reader.read().then(({ done, value }) => {\n // When no more data needs to be consumed, close the stream\n if (done) {\n controller.close();\n return;\n }\n // Enqueue the next data chunk into our target stream\n controller.enqueue(value);\n return pump();\n });\n }\n },\n cancel() {\n reader.releaseLock();\n },\n });\n }\n\n static fromAsyncGenerator<T>(generator: AsyncGenerator<T>) {\n return new IterableReadableStream<T>({\n async pull(controller) {\n const { value, done } = await generator.next();\n // When no more data needs to be consumed, close the stream\n if (done) {\n controller.close();\n }\n // Fix: `else if (value)` will hang the streaming when nullish value (e.g. empty string) is pulled\n controller.enqueue(value);\n },\n async cancel(reason) {\n await generator.return(reason);\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stream.js","names":[],"sources":["../../src/utils/stream.ts"],"sourcesContent":["import { isNetworkError } from \"./error.js\";\n\n// in this case don't quite match.\ntype IterableReadableStreamInterface<T> = ReadableStream<T> & AsyncIterable<T>;\n\n/**\n * Options for streaming with automatic retry logic.\n */\nexport interface StreamWithRetryOptions {\n /**\n * Maximum number of reconnection attempts. Default is 5.\n */\n maxRetries?: number;\n\n /**\n * AbortSignal to cancel the stream.\n */\n signal?: AbortSignal;\n\n /**\n * Callback invoked when a reconnection attempt is made.\n */\n onReconnect?: (options: {\n attempt: number;\n lastEventId?: string;\n cause: unknown;\n }) => void;\n}\n\n/**\n * Parameters for making a stream request\n */\nexport interface StreamRequestParams {\n /**\n * Last event ID to resume from, if available\n */\n lastEventId?: string;\n\n /**\n * Optional reconnection path from the Location header\n */\n reconnectPath?: string;\n}\n\n/**\n * Error thrown when maximum reconnection attempts are exceeded.\n */\nexport class MaxReconnectAttemptsError extends Error {\n constructor(maxAttempts: number, cause: unknown) {\n super(`Exceeded maximum SSE reconnection attempts (${maxAttempts})`);\n this.name = \"MaxReconnectAttemptsError\";\n this.cause = cause;\n }\n}\n\n/**\n * Error injected into the stream by {@link idleReconnectStream} when no lines\n * arrive within the active idle window. Surfacing this during the read is what\n * lets the reconnect loops in `streamWithRetry` and the protocol SSE transport\n * recover from a half-open socket — one that was silently dropped (e.g. a hard\n * pod kill on a platform revision rollover) without a TCP FIN/RST, so neither\n * a `done` nor a thrown network error ever arrives.\n */\nexport class StreamIdleTimeoutError extends Error {\n readonly idleTimeoutMs: number;\n\n constructor(idleTimeoutMs: number) {\n super(\n `No SSE bytes received for ${idleTimeoutMs}ms; assuming the connection is half-open and reconnecting.`\n );\n this.name = \"StreamIdleTimeoutError\";\n this.idleTimeoutMs = idleTimeoutMs;\n }\n}\n\n/** `\":\"` — first byte of an SSE comment / keep-alive line. */\nconst SSE_COMMENT_BYTE = 0x3a;\n\n/**\n * How {@link idleReconnectStream} decides when the connection is idle.\n *\n * - A `number` is a fixed idle window in milliseconds: the watchdog arms\n * immediately (even before the first byte) and trips after that long with no\n * activity. Use when you know your server's behaviour and want guaranteed\n * coverage from t=0; it does not depend on heartbeats.\n * - `\"auto\"` is heartbeat-adaptive: the watchdog stays dormant until it has\n * observed the server's SSE keep-alive comments (e.g. LangGraph Platform's\n * `: heartbeat` every ~5s), then arms with a window derived from the\n * observed cadence. On a server that never sends heartbeats it never arms,\n * so it can't false-fire during a legitimately quiet period.\n */\nexport type IdleReconnectMode = number | \"auto\";\n\nexport interface IdleReconnectStreamOptions {\n /** Fixed timeout (ms) or `\"auto\"` heartbeat-adaptive. */\n mode: IdleReconnectMode;\n /** `\"auto\"`: multiplier applied to the observed heartbeat interval. Default 3. */\n timeoutFactor?: number;\n /** `\"auto\"`: lower clamp for the derived timeout (ms). Default 6000. */\n minTimeoutMs?: number;\n /** `\"auto\"`: upper clamp for the derived timeout (ms). Default 30000. */\n maxTimeoutMs?: number;\n /** Fired immediately before the stream is errored, for logging/metrics. */\n onIdle?: (info: { timeoutMs: number; source: \"fixed\" | \"heartbeat\" }) => void;\n}\n\n/**\n * A pass-through {@link TransformStream} that errors the stream when it goes\n * idle, so the surrounding reconnect logic can recover a half-open socket.\n *\n * MUST sit on the *line* stream — i.e. after\n * {@link import(\"./sse.js\").BytesLineDecoder} but before\n * {@link import(\"./sse.js\").SSEDecoder} (which discards `:` comment lines).\n * Operating at the line level lets the watchdog both (a) reset on any line\n * (data *or* heartbeat = liveness) and (b) recognise heartbeat comment lines\n * to drive `\"auto\"` mode.\n *\n * In `\"auto\"` mode the watchdog is intentionally dormant until it has seen at\n * least two heartbeats (so it can measure the cadence). This means a socket\n * that dies inside the first heartbeat interval won't be caught until a\n * heartbeat would have been due — an acceptable trade for never false-firing\n * on heartbeat-less servers. Pass a fixed `number` if you need coverage from\n * the very first byte.\n */\nexport function idleReconnectStream(\n options: IdleReconnectStreamOptions\n): TransformStream<Uint8Array, Uint8Array> {\n const factor = options.timeoutFactor ?? 3;\n const minTimeoutMs = options.minTimeoutMs ?? 6_000;\n const maxTimeoutMs = options.maxTimeoutMs ?? 30_000;\n const fixedTimeoutMs = typeof options.mode === \"number\" ? options.mode : null;\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n let controllerRef: TransformStreamDefaultController<Uint8Array> | undefined;\n\n // `\"auto\"` cadence inference.\n let lastHeartbeatAt: number | undefined;\n // The active idle window: the fixed value, or (auto) the heartbeat-derived\n // value once known. `null` means \"not armed yet\".\n let derivedTimeoutMs: number | null = fixedTimeoutMs;\n\n const clear = () => {\n if (timer != null) {\n clearTimeout(timer);\n timer = undefined;\n }\n };\n\n const arm = () => {\n clear();\n const timeoutMs = derivedTimeoutMs;\n if (timeoutMs == null || timeoutMs <= 0) return;\n timer = setTimeout(() => {\n options.onIdle?.({\n timeoutMs,\n source: fixedTimeoutMs != null ? \"fixed\" : \"heartbeat\",\n });\n try {\n controllerRef?.error(new StreamIdleTimeoutError(timeoutMs));\n } catch {\n // Stream already closed/errored/cancelled — nothing to abort.\n }\n }, timeoutMs);\n // Don't let the watchdog by itself keep a Node process alive.\n (timer as unknown as { unref?: () => void }).unref?.();\n };\n\n const noteHeartbeat = () => {\n if (fixedTimeoutMs != null) return; // cadence irrelevant in fixed mode\n const now = Date.now();\n if (lastHeartbeatAt != null) {\n const interval = now - lastHeartbeatAt;\n if (interval > 0) {\n const candidate = Math.min(\n Math.max(interval * factor, minTimeoutMs),\n maxTimeoutMs\n );\n // Keep the most conservative (largest) window observed so far.\n derivedTimeoutMs =\n derivedTimeoutMs == null\n ? candidate\n : Math.max(derivedTimeoutMs, candidate);\n }\n }\n lastHeartbeatAt = now;\n };\n\n return new TransformStream<Uint8Array, Uint8Array>({\n start(controller) {\n controllerRef = controller;\n // Fixed mode arms eagerly (also catches pre-first-byte silence). Auto\n // mode waits until a cadence is established in `transform`.\n arm();\n },\n transform(line, controller) {\n // A line beginning with \":\" is an SSE comment / keep-alive heartbeat.\n if (line.length > 0 && line[0] === SSE_COMMENT_BYTE) {\n noteHeartbeat();\n }\n // Any line is liveness — (re)arm the idle timer.\n arm();\n controller.enqueue(line);\n },\n flush() {\n clear();\n },\n });\n}\n\n/**\n * Stream with automatic retry logic for SSE connections.\n * Implements reconnection behavior similar to the Python SDK.\n *\n * @param makeRequest Function to make requests. When `params` is undefined/empty, it's the initial request.\n * When `params.reconnectPath` is provided, it's a reconnection request.\n * @param options Configuration options\n * @returns AsyncGenerator yielding stream events\n */\nexport async function* streamWithRetry<T extends { id?: string }>(\n makeRequest: (params?: StreamRequestParams) => Promise<{\n response: Response;\n stream: ReadableStream<T>;\n }>,\n options: StreamWithRetryOptions = {}\n): AsyncGenerator<T> {\n const maxRetries = options.maxRetries ?? 5;\n let attempt = 0;\n let lastEventId: string | undefined;\n let reconnectPath: string | undefined;\n\n while (true) {\n let shouldRetry = false;\n let lastError: unknown;\n let reader: ReadableStreamDefaultReader<T> | undefined;\n\n try {\n // Check if aborted before making request\n if (options.signal?.aborted) return;\n\n // Make request - initial if no reconnect path, reconnect otherwise\n const { response, stream } = await makeRequest(\n reconnectPath ? { lastEventId, reconnectPath } : undefined\n );\n\n // Check for Location header (server-provided reconnection path)\n const locationHeader = response.headers.get(\"location\");\n if (locationHeader) {\n reconnectPath = locationHeader;\n }\n\n // Verify content type\n const contentType = response.headers.get(\"content-type\")?.split(\";\")[0];\n if (contentType && !contentType.includes(\"text/event-stream\")) {\n throw new Error(\n `Expected response header Content-Type to contain 'text/event-stream', got '${contentType}'`\n );\n }\n\n reader = stream.getReader();\n\n try {\n while (true) {\n // Check abort signal before each read\n if (options.signal?.aborted) {\n await reader.cancel();\n return;\n }\n\n const { done, value } = await reader.read();\n\n if (done) {\n // Stream completed successfully\n break;\n }\n\n // Track last event ID for reconnection\n if (value.id) {\n lastEventId = value.id;\n }\n\n yield value;\n }\n\n // Stream completed successfully, exit retry loop\n break;\n } catch (error) {\n // Error during streaming - attempt reconnect if we have a location header\n if (reconnectPath && !options.signal?.aborted) {\n shouldRetry = true;\n } else {\n throw error;\n }\n } finally {\n if (reader) {\n try {\n reader.releaseLock();\n } catch {\n // Ignore errors when releasing lock\n }\n }\n }\n } catch (error) {\n lastError = error;\n\n // Only retry if we have reconnection capability and it's a network error\n if (isNetworkError(error) && reconnectPath && !options.signal?.aborted) {\n shouldRetry = true;\n } else {\n throw error;\n }\n }\n\n if (shouldRetry) {\n attempt += 1;\n if (attempt > maxRetries) {\n throw new MaxReconnectAttemptsError(maxRetries, lastError);\n }\n\n // Notify about reconnection attempt\n options.onReconnect?.({ attempt, lastEventId, cause: lastError });\n\n // Exponential backoff with jitter: min(1000 * 2^attempt, 5000) + random jitter\n const baseDelay = Math.min(1000 * 2 ** (attempt - 1), 5000);\n const jitter = Math.random() * 1000;\n const delay = baseDelay + jitter;\n\n await new Promise((resolve) => {\n setTimeout(resolve, delay);\n });\n\n continue;\n }\n\n // Successfully completed\n break;\n }\n}\n\n/*\n * Support async iterator syntax for ReadableStreams in all environments.\n * Source: https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490\n */\nexport class IterableReadableStream<T>\n extends ReadableStream<T>\n implements IterableReadableStreamInterface<T>\n{\n public reader: ReadableStreamDefaultReader<T>;\n\n ensureReader() {\n if (!this.reader) {\n this.reader = this.getReader();\n }\n }\n\n async next(): Promise<IteratorResult<T>> {\n this.ensureReader();\n try {\n const result = await this.reader.read();\n if (result.done) {\n this.reader.releaseLock(); // release lock when stream becomes closed\n return {\n done: true,\n value: undefined,\n };\n } else {\n return {\n done: false,\n value: result.value,\n };\n }\n } catch (e) {\n this.reader.releaseLock(); // release lock when stream becomes errored\n throw e;\n }\n }\n\n async return(): Promise<IteratorResult<T>> {\n this.ensureReader();\n // If wrapped in a Node stream, cancel is already called.\n if (this.locked) {\n const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet\n this.reader.releaseLock(); // release lock first\n await cancelPromise; // now await it\n }\n return { done: true, value: undefined };\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async throw(e: any): Promise<IteratorResult<T>> {\n this.ensureReader();\n if (this.locked) {\n const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet\n this.reader.releaseLock(); // release lock first\n await cancelPromise; // now await it\n }\n throw e;\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore Not present in Node 18 types, required in latest Node 22\n async [Symbol.asyncDispose]() {\n await this.return();\n }\n\n [Symbol.asyncIterator]() {\n return this;\n }\n\n static fromReadableStream<T>(stream: ReadableStream<T>) {\n // From https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams#reading_the_stream\n const reader = stream.getReader();\n return new IterableReadableStream<T>({\n start(controller) {\n return pump();\n function pump(): Promise<T | undefined> {\n return reader.read().then(({ done, value }) => {\n // When no more data needs to be consumed, close the stream\n if (done) {\n controller.close();\n return;\n }\n // Enqueue the next data chunk into our target stream\n controller.enqueue(value);\n return pump();\n });\n }\n },\n cancel() {\n reader.releaseLock();\n },\n });\n }\n\n static fromAsyncGenerator<T>(generator: AsyncGenerator<T>) {\n return new IterableReadableStream<T>({\n async pull(controller) {\n const { value, done } = await generator.next();\n // When no more data needs to be consumed, close the stream\n if (done) {\n controller.close();\n }\n // Fix: `else if (value)` will hang the streaming when nullish value (e.g. empty string) is pulled\n controller.enqueue(value);\n },\n async cancel(reason) {\n await generator.return(reason);\n },\n });\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "1.9.20",
3
+ "version": "1.9.22",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "repository": {
@@ -13,8 +13,7 @@
13
13
  "@langchain/protocol": "^0.0.16",
14
14
  "@types/json-schema": "^7.0.15",
15
15
  "p-queue": "^9.0.1",
16
- "p-retry": "^7.1.1",
17
- "uuid": "^14.0.0"
16
+ "p-retry": "^7.1.1"
18
17
  },
19
18
  "devDependencies": {
20
19
  "@langchain/core": "^1.1.48",
@@ -23,7 +22,7 @@
23
22
  "@types/node": "^18.15.11",
24
23
  "@types/react": "^19.2.16",
25
24
  "@types/react-dom": "^19.2.3",
26
- "@types/uuid": "^9.0.1",
25
+ "@types/ws": "^8.18.1",
27
26
  "deepagents": "^1.8.3",
28
27
  "langchain": "^1.4.4",
29
28
  "react": "^19.2.7",
@@ -32,6 +31,7 @@
32
31
  "typescript": "^4.9.5 || ^5.4.5",
33
32
  "vitest": "^4.1.0",
34
33
  "vue": "^3.5.35",
34
+ "ws": "^8.18.3",
35
35
  "zod": "^4.3.5"
36
36
  },
37
37
  "peerDependencies": {
@@ -189,6 +189,7 @@
189
189
  "build:internal": "pnpm --filter @langchain/build compile @langchain/langgraph-sdk",
190
190
  "prepublish": "pnpm build",
191
191
  "lint:eslint": "NODE_OPTIONS=--max-old-space-size=4096 eslint --cache --ext .ts,.js,.jsx,.tsx src/",
192
- "test": "vitest run"
192
+ "test": "vitest run",
193
+ "test:int": "vitest run --mode int"
193
194
  }
194
195
  }