@langchain/langgraph-sdk 0.0.41 → 0.0.43

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.
@@ -0,0 +1,48 @@
1
+ type ResponseCallback = (response?: Response) => Promise<boolean>;
2
+ export interface AsyncCallerParams {
3
+ /**
4
+ * The maximum number of concurrent calls that can be made.
5
+ * Defaults to `Infinity`, which means no limit.
6
+ */
7
+ maxConcurrency?: number;
8
+ /**
9
+ * The maximum number of retries that can be made for a single call,
10
+ * with an exponential backoff between each attempt. Defaults to 6.
11
+ */
12
+ maxRetries?: number;
13
+ onFailedResponseHook?: ResponseCallback;
14
+ /**
15
+ * Specify a custom fetch implementation.
16
+ *
17
+ * By default we expect the `fetch` is available in the global scope.
18
+ */
19
+ fetch?: typeof fetch | ((...args: any[]) => any);
20
+ }
21
+ export interface AsyncCallerCallOptions {
22
+ signal?: AbortSignal;
23
+ }
24
+ /**
25
+ * A class that can be used to make async calls with concurrency and retry logic.
26
+ *
27
+ * This is useful for making calls to any kind of "expensive" external resource,
28
+ * be it because it's rate-limited, subject to network issues, etc.
29
+ *
30
+ * Concurrent calls are limited by the `maxConcurrency` parameter, which defaults
31
+ * to `Infinity`. This means that by default, all calls will be made in parallel.
32
+ *
33
+ * Retries are limited by the `maxRetries` parameter, which defaults to 5. This
34
+ * means that by default, each call will be retried up to 5 times, with an
35
+ * exponential backoff between each attempt.
36
+ */
37
+ export declare class AsyncCaller {
38
+ protected maxConcurrency: AsyncCallerParams["maxConcurrency"];
39
+ protected maxRetries: AsyncCallerParams["maxRetries"];
40
+ private queue;
41
+ private onFailedResponseHook?;
42
+ private customFetch?;
43
+ constructor(params: AsyncCallerParams);
44
+ call<A extends any[], T extends (...args: A) => Promise<any>>(callable: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
45
+ callWithOptions<A extends any[], T extends (...args: A) => Promise<any>>(options: AsyncCallerCallOptions, callable: T, ...args: Parameters<T>): Promise<Awaited<ReturnType<T>>>;
46
+ fetch(...args: Parameters<typeof fetch>): ReturnType<typeof fetch>;
47
+ }
48
+ export {};
@@ -0,0 +1 @@
1
+ export declare function getEnvironmentVariable(name: string): string | undefined;
@@ -0,0 +1,12 @@
1
+ export function getEnvironmentVariable(name) {
2
+ // Certain setups (Deno, frontend) will throw an error if you try to access environment variables
3
+ try {
4
+ return typeof process !== "undefined"
5
+ ? // eslint-disable-next-line no-process-env
6
+ process.env?.[name]
7
+ : undefined;
8
+ }
9
+ catch (e) {
10
+ return undefined;
11
+ }
12
+ }
@@ -0,0 +1,18 @@
1
+ export function mergeSignals(...signals) {
2
+ const nonZeroSignals = signals.filter((signal) => signal != null);
3
+ if (nonZeroSignals.length === 0)
4
+ return undefined;
5
+ if (nonZeroSignals.length === 1)
6
+ return nonZeroSignals[0];
7
+ const controller = new AbortController();
8
+ for (const signal of signals) {
9
+ if (signal?.aborted) {
10
+ controller.abort(signal.reason);
11
+ return controller.signal;
12
+ }
13
+ signal?.addEventListener("abort", () => controller.abort(signal.reason), {
14
+ once: true,
15
+ });
16
+ }
17
+ return controller.signal;
18
+ }
@@ -0,0 +1,11 @@
1
+ export declare class BytesLineDecoder extends TransformStream<Uint8Array, Uint8Array> {
2
+ constructor();
3
+ }
4
+ interface StreamPart {
5
+ event: string;
6
+ data: unknown;
7
+ }
8
+ export declare class SSEDecoder extends TransformStream<Uint8Array, StreamPart> {
9
+ constructor();
10
+ }
11
+ export {};
@@ -0,0 +1,152 @@
1
+ const CR = "\r".charCodeAt(0);
2
+ const LF = "\n".charCodeAt(0);
3
+ const NULL = "\0".charCodeAt(0);
4
+ const COLON = ":".charCodeAt(0);
5
+ const SPACE = " ".charCodeAt(0);
6
+ const TRAILING_NEWLINE = [CR, LF];
7
+ export class BytesLineDecoder extends TransformStream {
8
+ constructor() {
9
+ let buffer = [];
10
+ let trailingCr = false;
11
+ super({
12
+ start() {
13
+ buffer = [];
14
+ trailingCr = false;
15
+ },
16
+ transform(chunk, controller) {
17
+ // See https://docs.python.org/3/glossary.html#term-universal-newlines
18
+ let text = chunk;
19
+ // Handle trailing CR from previous chunk
20
+ if (trailingCr) {
21
+ text = joinArrays([[CR], text]);
22
+ trailingCr = false;
23
+ }
24
+ // Check for trailing CR in current chunk
25
+ if (text.length > 0 && text.at(-1) === CR) {
26
+ trailingCr = true;
27
+ text = text.subarray(0, -1);
28
+ }
29
+ if (!text.length)
30
+ return;
31
+ const trailingNewline = TRAILING_NEWLINE.includes(text.at(-1));
32
+ const lastIdx = text.length - 1;
33
+ const { lines } = text.reduce((acc, cur, idx) => {
34
+ if (acc.from > idx)
35
+ return acc;
36
+ if (cur === CR || cur === LF) {
37
+ acc.lines.push(text.subarray(acc.from, idx));
38
+ if (cur === CR && text[idx + 1] === LF) {
39
+ acc.from = idx + 2;
40
+ }
41
+ else {
42
+ acc.from = idx + 1;
43
+ }
44
+ }
45
+ if (idx === lastIdx && acc.from <= lastIdx) {
46
+ acc.lines.push(text.subarray(acc.from));
47
+ }
48
+ return acc;
49
+ }, { lines: [], from: 0 });
50
+ if (lines.length === 1 && !trailingNewline) {
51
+ buffer.push(lines[0]);
52
+ return;
53
+ }
54
+ if (buffer.length) {
55
+ // Include existing buffer in first line
56
+ buffer.push(lines[0]);
57
+ lines[0] = joinArrays(buffer);
58
+ buffer = [];
59
+ }
60
+ if (!trailingNewline) {
61
+ // If the last segment is not newline terminated,
62
+ // buffer it for the next chunk
63
+ if (lines.length)
64
+ buffer = [lines.pop()];
65
+ }
66
+ // Enqueue complete lines
67
+ for (const line of lines) {
68
+ controller.enqueue(line);
69
+ }
70
+ },
71
+ flush(controller) {
72
+ if (buffer.length) {
73
+ controller.enqueue(joinArrays(buffer));
74
+ }
75
+ },
76
+ });
77
+ }
78
+ }
79
+ export class SSEDecoder extends TransformStream {
80
+ constructor() {
81
+ let event = "";
82
+ let data = [];
83
+ let lastEventId = "";
84
+ let retry = null;
85
+ const decoder = new TextDecoder();
86
+ super({
87
+ transform(chunk, controller) {
88
+ // Handle empty line case
89
+ if (!chunk.length) {
90
+ if (!event && !data.length && !lastEventId && retry == null)
91
+ return;
92
+ const sse = {
93
+ event,
94
+ data: data.length ? decodeArraysToJson(decoder, data) : null,
95
+ };
96
+ // NOTE: as per the SSE spec, do not reset lastEventId
97
+ event = "";
98
+ data = [];
99
+ retry = null;
100
+ controller.enqueue(sse);
101
+ return;
102
+ }
103
+ // Ignore comments
104
+ if (chunk[0] === COLON)
105
+ return;
106
+ const sepIdx = chunk.indexOf(COLON);
107
+ if (sepIdx === -1)
108
+ return;
109
+ const fieldName = decoder.decode(chunk.subarray(0, sepIdx));
110
+ let value = chunk.subarray(sepIdx + 1);
111
+ if (value[0] === SPACE)
112
+ value = value.subarray(1);
113
+ if (fieldName === "event") {
114
+ event = decoder.decode(value);
115
+ }
116
+ else if (fieldName === "data") {
117
+ data.push(value);
118
+ }
119
+ else if (fieldName === "id") {
120
+ if (value.indexOf(NULL) === -1)
121
+ lastEventId = decoder.decode(value);
122
+ }
123
+ else if (fieldName === "retry") {
124
+ const retryNum = Number.parseInt(decoder.decode(value));
125
+ if (!Number.isNaN(retryNum))
126
+ retry = retryNum;
127
+ }
128
+ },
129
+ flush(controller) {
130
+ if (event) {
131
+ controller.enqueue({
132
+ event,
133
+ data: data.length ? decodeArraysToJson(decoder, data) : null,
134
+ });
135
+ }
136
+ },
137
+ });
138
+ }
139
+ }
140
+ function joinArrays(data) {
141
+ const totalLength = data.reduce((acc, curr) => acc + curr.length, 0);
142
+ let merged = new Uint8Array(totalLength);
143
+ let offset = 0;
144
+ for (const c of data) {
145
+ merged.set(c, offset);
146
+ offset += c.length;
147
+ }
148
+ return merged;
149
+ }
150
+ function decodeArraysToJson(decoder, data) {
151
+ return JSON.parse(decoder.decode(joinArrays(data)));
152
+ }
@@ -0,0 +1,13 @@
1
+ type IterableReadableStreamInterface<T> = ReadableStream<T> & AsyncIterable<T>;
2
+ export declare class IterableReadableStream<T> extends ReadableStream<T> implements IterableReadableStreamInterface<T> {
3
+ reader: ReadableStreamDefaultReader<T>;
4
+ ensureReader(): void;
5
+ next(): Promise<IteratorResult<T>>;
6
+ return(): Promise<IteratorResult<T>>;
7
+ throw(e: any): Promise<IteratorResult<T>>;
8
+ [Symbol.asyncDispose](): Promise<void>;
9
+ [Symbol.asyncIterator](): this;
10
+ static fromReadableStream<T>(stream: ReadableStream<T>): IterableReadableStream<T>;
11
+ static fromAsyncGenerator<T>(generator: AsyncGenerator<T>): IterableReadableStream<T>;
12
+ }
13
+ export {};
@@ -0,0 +1,111 @@
1
+ /*
2
+ * Support async iterator syntax for ReadableStreams in all environments.
3
+ * Source: https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
4
+ */
5
+ export class IterableReadableStream extends ReadableStream {
6
+ constructor() {
7
+ super(...arguments);
8
+ Object.defineProperty(this, "reader", {
9
+ enumerable: true,
10
+ configurable: true,
11
+ writable: true,
12
+ value: void 0
13
+ });
14
+ }
15
+ ensureReader() {
16
+ if (!this.reader) {
17
+ this.reader = this.getReader();
18
+ }
19
+ }
20
+ async next() {
21
+ this.ensureReader();
22
+ try {
23
+ const result = await this.reader.read();
24
+ if (result.done) {
25
+ this.reader.releaseLock(); // release lock when stream becomes closed
26
+ return {
27
+ done: true,
28
+ value: undefined,
29
+ };
30
+ }
31
+ else {
32
+ return {
33
+ done: false,
34
+ value: result.value,
35
+ };
36
+ }
37
+ }
38
+ catch (e) {
39
+ this.reader.releaseLock(); // release lock when stream becomes errored
40
+ throw e;
41
+ }
42
+ }
43
+ async return() {
44
+ this.ensureReader();
45
+ // If wrapped in a Node stream, cancel is already called.
46
+ if (this.locked) {
47
+ const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet
48
+ this.reader.releaseLock(); // release lock first
49
+ await cancelPromise; // now await it
50
+ }
51
+ return { done: true, value: undefined };
52
+ }
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ async throw(e) {
55
+ this.ensureReader();
56
+ if (this.locked) {
57
+ const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet
58
+ this.reader.releaseLock(); // release lock first
59
+ await cancelPromise; // now await it
60
+ }
61
+ throw e;
62
+ }
63
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
64
+ // @ts-ignore Not present in Node 18 types, required in latest Node 22
65
+ async [Symbol.asyncDispose]() {
66
+ await this.return();
67
+ }
68
+ [Symbol.asyncIterator]() {
69
+ return this;
70
+ }
71
+ static fromReadableStream(stream) {
72
+ // From https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams#reading_the_stream
73
+ const reader = stream.getReader();
74
+ return new IterableReadableStream({
75
+ start(controller) {
76
+ return pump();
77
+ function pump() {
78
+ return reader.read().then(({ done, value }) => {
79
+ // When no more data needs to be consumed, close the stream
80
+ if (done) {
81
+ controller.close();
82
+ return;
83
+ }
84
+ // Enqueue the next data chunk into our target stream
85
+ controller.enqueue(value);
86
+ return pump();
87
+ });
88
+ }
89
+ },
90
+ cancel() {
91
+ reader.releaseLock();
92
+ },
93
+ });
94
+ }
95
+ static fromAsyncGenerator(generator) {
96
+ return new IterableReadableStream({
97
+ async pull(controller) {
98
+ const { value, done } = await generator.next();
99
+ // When no more data needs to be consumed, close the stream
100
+ if (done) {
101
+ controller.close();
102
+ }
103
+ // Fix: `else if (value)` will hang the streaming when nullish value (e.g. empty string) is pulled
104
+ controller.enqueue(value);
105
+ },
106
+ async cancel(reason) {
107
+ await generator.return(reason);
108
+ },
109
+ });
110
+ }
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph-sdk",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "description": "Client library for interacting with the LangGraph API",
5
5
  "type": "module",
6
6
  "packageManager": "yarn@1.22.19",
@@ -43,6 +43,14 @@
43
43
  "react": "^18 || ^19",
44
44
  "@langchain/core": ">=0.2.31 <0.4.0"
45
45
  },
46
+ "peerDependenciesMeta": {
47
+ "react": {
48
+ "optional": true
49
+ },
50
+ "@langchain/core": {
51
+ "optional": true
52
+ }
53
+ },
46
54
  "exports": {
47
55
  ".": {
48
56
  "types": {