@langchain/langgraph 0.1.1 → 0.1.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.
Files changed (46) hide show
  1. package/README.md +2 -2
  2. package/dist/constants.cjs +1 -0
  3. package/dist/constants.d.ts +1 -0
  4. package/dist/constants.js +1 -0
  5. package/dist/graph/annotation.cjs +78 -4
  6. package/dist/graph/annotation.d.ts +82 -5
  7. package/dist/graph/annotation.js +77 -2
  8. package/dist/graph/graph.cjs +14 -8
  9. package/dist/graph/graph.d.ts +14 -5
  10. package/dist/graph/graph.js +14 -8
  11. package/dist/graph/message.cjs +6 -0
  12. package/dist/graph/message.d.ts +6 -0
  13. package/dist/graph/message.js +6 -0
  14. package/dist/graph/messages_annotation.cjs +5 -0
  15. package/dist/graph/messages_annotation.d.ts +5 -0
  16. package/dist/graph/messages_annotation.js +5 -0
  17. package/dist/graph/state.cjs +84 -3
  18. package/dist/graph/state.d.ts +75 -5
  19. package/dist/graph/state.js +86 -5
  20. package/dist/prebuilt/agent_executor.cjs +1 -0
  21. package/dist/prebuilt/agent_executor.d.ts +2 -0
  22. package/dist/prebuilt/agent_executor.js +1 -0
  23. package/dist/prebuilt/chat_agent_executor.cjs +1 -0
  24. package/dist/prebuilt/chat_agent_executor.d.ts +2 -0
  25. package/dist/prebuilt/chat_agent_executor.js +1 -0
  26. package/dist/prebuilt/react_agent_executor.cjs +1 -1
  27. package/dist/prebuilt/react_agent_executor.js +2 -2
  28. package/dist/pregel/algo.cjs +3 -41
  29. package/dist/pregel/algo.d.ts +0 -5
  30. package/dist/pregel/algo.js +2 -39
  31. package/dist/pregel/debug.d.ts +1 -1
  32. package/dist/pregel/index.cjs +17 -30
  33. package/dist/pregel/index.d.ts +2 -0
  34. package/dist/pregel/index.js +18 -31
  35. package/dist/pregel/loop.cjs +5 -2
  36. package/dist/pregel/loop.js +5 -2
  37. package/dist/pregel/read.cjs +19 -1
  38. package/dist/pregel/read.d.ts +5 -0
  39. package/dist/pregel/read.js +19 -1
  40. package/dist/pregel/retry.cjs +147 -0
  41. package/dist/pregel/retry.d.ts +11 -0
  42. package/dist/pregel/retry.js +143 -0
  43. package/dist/pregel/types.d.ts +4 -2
  44. package/dist/pregel/utils.d.ts +26 -0
  45. package/dist/web.d.ts +1 -0
  46. package/package.json +6 -4
@@ -0,0 +1,143 @@
1
+ import { GraphInterrupt } from "../errors.js";
2
+ export const DEFAULT_INITIAL_INTERVAL = 500;
3
+ export const DEFAULT_BACKOFF_FACTOR = 2;
4
+ export const DEFAULT_MAX_INTERVAL = 128000;
5
+ export const DEFAULT_MAX_RETRIES = 3;
6
+ const DEFAULT_STATUS_NO_RETRY = [
7
+ 400,
8
+ 401,
9
+ 402,
10
+ 403,
11
+ 404,
12
+ 405,
13
+ 406,
14
+ 407,
15
+ 409, // Conflict
16
+ ];
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ const DEFAULT_RETRY_ON_HANDLER = (error) => {
19
+ if (error.message.startsWith("Cancel") ||
20
+ error.message.startsWith("AbortError") ||
21
+ error.name === "AbortError") {
22
+ return false;
23
+ }
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ if (error?.code === "ECONNABORTED") {
26
+ return false;
27
+ }
28
+ const status =
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ error?.response?.status ?? error?.status;
31
+ if (status && DEFAULT_STATUS_NO_RETRY.includes(+status)) {
32
+ return false;
33
+ }
34
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ if (error?.error?.code === "insufficient_quota") {
36
+ return false;
37
+ }
38
+ return true;
39
+ };
40
+ export async function* executeTasksWithRetry(
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ tasks, options
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ ) {
45
+ const { stepTimeout, retryPolicy } = options ?? {};
46
+ let signal = options?.signal;
47
+ // Start tasks
48
+ const executingTasksMap = Object.fromEntries(tasks.map((pregelTask) => {
49
+ return [pregelTask.id, _runWithRetry(pregelTask, retryPolicy)];
50
+ }));
51
+ if (stepTimeout && signal) {
52
+ if ("any" in AbortSignal) {
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ signal = AbortSignal.any([
55
+ signal,
56
+ AbortSignal.timeout(stepTimeout),
57
+ ]);
58
+ }
59
+ }
60
+ else if (stepTimeout) {
61
+ signal = AbortSignal.timeout(stepTimeout);
62
+ }
63
+ // Abort if signal is aborted
64
+ signal?.throwIfAborted();
65
+ let listener;
66
+ const signalPromise = new Promise((_resolve, reject) => {
67
+ listener = () => reject(new Error("Abort"));
68
+ signal?.addEventListener("abort", listener);
69
+ }).finally(() => signal?.removeEventListener("abort", listener));
70
+ while (Object.keys(executingTasksMap).length > 0) {
71
+ const { task, error } = await Promise.race([
72
+ ...Object.values(executingTasksMap),
73
+ signalPromise,
74
+ ]);
75
+ if (error !== undefined) {
76
+ // TODO: don't stop others if exception is interrupt
77
+ throw error;
78
+ }
79
+ yield task;
80
+ delete executingTasksMap[task.id];
81
+ }
82
+ }
83
+ async function _runWithRetry(
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ pregelTask, retryPolicy) {
86
+ const resolvedRetryPolicy = pregelTask.retry_policy ?? retryPolicy;
87
+ let interval = resolvedRetryPolicy !== undefined
88
+ ? resolvedRetryPolicy.initialInterval ?? DEFAULT_INITIAL_INTERVAL
89
+ : 0;
90
+ let attempts = 0;
91
+ let error;
92
+ let result;
93
+ // eslint-disable-next-line no-constant-condition
94
+ while (true) {
95
+ // Modify writes in place to clear any previous retries
96
+ while (pregelTask.writes.length > 0) {
97
+ pregelTask.writes.pop();
98
+ }
99
+ error = undefined;
100
+ try {
101
+ result = await pregelTask.proc.invoke(pregelTask.input, pregelTask.config);
102
+ break;
103
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
+ }
105
+ catch (e) {
106
+ error = e;
107
+ error.pregelTaskId = pregelTask.id;
108
+ if (error.name === GraphInterrupt.unminifiable_name) {
109
+ break;
110
+ }
111
+ if (resolvedRetryPolicy === undefined) {
112
+ break;
113
+ }
114
+ attempts += 1;
115
+ // check if we should give up
116
+ if (attempts >= (resolvedRetryPolicy.maxAttempts ?? DEFAULT_MAX_RETRIES)) {
117
+ break;
118
+ }
119
+ const retryOn = resolvedRetryPolicy.retryOn ?? DEFAULT_RETRY_ON_HANDLER;
120
+ if (!retryOn(error)) {
121
+ break;
122
+ }
123
+ interval = Math.min(resolvedRetryPolicy.maxInterval ?? DEFAULT_MAX_INTERVAL, interval * (resolvedRetryPolicy.backoffFactor ?? DEFAULT_BACKOFF_FACTOR));
124
+ const intervalWithJitter = resolvedRetryPolicy.jitter
125
+ ? Math.floor(interval + Math.random() * 1000)
126
+ : interval;
127
+ // sleep before retrying
128
+ // eslint-disable-next-line no-promise-executor-return
129
+ await new Promise((resolve) => setTimeout(resolve, intervalWithJitter));
130
+ // log the retry
131
+ const errorName = error.name ??
132
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
133
+ error.constructor.unminifiable_name ??
134
+ error.constructor.name;
135
+ console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)} seconds (attempt ${attempts}) after ${errorName}: ${error}`);
136
+ }
137
+ }
138
+ return {
139
+ task: pregelTask,
140
+ result,
141
+ error,
142
+ };
143
+ }
@@ -2,6 +2,7 @@ import type { Runnable, RunnableConfig } from "@langchain/core/runnables";
2
2
  import type { PendingWrite, CheckpointMetadata, BaseCheckpointSaver } from "@langchain/langgraph-checkpoint";
3
3
  import type { BaseChannel } from "../channels/base.js";
4
4
  import type { PregelNode } from "./read.js";
5
+ import { RetryPolicy } from "./utils.js";
5
6
  export type StreamMode = "values" | "updates" | "debug";
6
7
  /**
7
8
  * Construct a type with a set of properties K of type T
@@ -41,6 +42,7 @@ export interface PregelInterface<Nn extends StrRecord<string, PregelNode>, Cc ex
41
42
  */
42
43
  debug?: boolean;
43
44
  checkpointer?: BaseCheckpointSaver;
45
+ retryPolicy?: RetryPolicy;
44
46
  }
45
47
  export type PregelParams<Nn extends StrRecord<string, PregelNode>, Cc extends StrRecord<string, BaseChannel>> = Omit<PregelInterface<Nn, Cc>, "streamChannelsAsIs">;
46
48
  export interface PregelTaskDescription {
@@ -53,9 +55,9 @@ export interface PregelExecutableTask<N extends PropertyKey, C extends PropertyK
53
55
  readonly input: unknown;
54
56
  readonly proc: Runnable;
55
57
  readonly writes: PendingWrite<C>[];
56
- readonly config: RunnableConfig | undefined;
58
+ readonly config?: RunnableConfig;
57
59
  readonly triggers: Array<string>;
58
- readonly retry_policy?: string;
60
+ readonly retry_policy?: RetryPolicy;
59
61
  readonly id: string;
60
62
  }
61
63
  export interface StateSnapshot {
@@ -8,3 +8,29 @@ export declare function _getIdMetadata(metadata: Record<string, unknown>): {
8
8
  langgraph_triggers: unknown;
9
9
  langgraph_task_idx: unknown;
10
10
  };
11
+ export type RetryPolicy = {
12
+ /**
13
+ * Amount of time that must elapse before the first retry occurs in milliseconds.
14
+ * @default 500
15
+ */
16
+ initialInterval?: number;
17
+ /**
18
+ * Multiplier by which the interval increases after each retry.
19
+ * @default 2
20
+ */
21
+ backoffFactor?: number;
22
+ /**
23
+ * Maximum amount of time that may elapse between retries in milliseconds.
24
+ * @default 128000
25
+ */
26
+ maxInterval?: number;
27
+ /**
28
+ * Maximum amount of time that may elapse between retries.
29
+ * @default 3
30
+ */
31
+ maxAttempts?: number;
32
+ /** Whether to add random jitter to the interval between retries. */
33
+ jitter?: boolean;
34
+ /** A function that returns True for exceptions that should trigger a retry. */
35
+ retryOn?: (e: any) => boolean;
36
+ };
package/dist/web.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { END, Graph, type StateGraphArgs, START, StateGraph, type CompiledStateGraph, MessageGraph, messagesStateReducer, Annotation, type StateType, type UpdateType, type CompiledGraph, } from "./graph/index.js";
2
2
  export { GraphRecursionError, GraphValueError, InvalidUpdateError, EmptyChannelError, } from "./errors.js";
3
+ export { type RetryPolicy } from "./pregel/utils.js";
3
4
  export { Send } from "./constants.js";
4
5
  export { MemorySaver, type Checkpoint, type CheckpointMetadata, type CheckpointTuple, copyCheckpoint, emptyCheckpoint, BaseCheckpointSaver, } from "@langchain/langgraph-checkpoint";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langchain/langgraph",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "LangGraph",
5
5
  "type": "module",
6
6
  "engines": {
@@ -14,7 +14,8 @@
14
14
  },
15
15
  "scripts": {
16
16
  "build": "yarn turbo:command build:internal --filter=@langchain/langgraph",
17
- "build:internal": "yarn lc_build --create-entrypoints --pre --tree-shaking",
17
+ "build:internal": "yarn clean && yarn lc_build --create-entrypoints --pre --tree-shaking",
18
+ "clean": "rm -rf dist/ dist-cjs/ .turbo/",
18
19
  "lint:eslint": "NODE_OPTIONS=--max-old-space-size=4096 eslint --cache --ext .ts,.js src/",
19
20
  "lint:dpdm": "dpdm --exit-code circular:1 --no-warning --no-tree src/*.ts src/**/*.ts",
20
21
  "lint": "yarn lint:eslint && yarn lint:dpdm",
@@ -31,7 +32,7 @@
31
32
  "license": "MIT",
32
33
  "dependencies": {
33
34
  "@langchain/core": ">=0.2.20 <0.3.0",
34
- "@langchain/langgraph-checkpoint": "~0.0.1",
35
+ "@langchain/langgraph-checkpoint": "~0.0.3",
35
36
  "@langchain/langgraph-checkpoint-sqlite": "~0.0.1",
36
37
  "double-ended-queue": "^2.1.0-0",
37
38
  "uuid": "^10.0.0",
@@ -49,8 +50,9 @@
49
50
  "@jest/globals": "^29.5.0",
50
51
  "@langchain/anthropic": "^0.2.12",
51
52
  "@langchain/community": "^0.2.25",
53
+ "@langchain/core": "^0.2.29",
52
54
  "@langchain/openai": "^0.2.4",
53
- "@langchain/scripts": ">=0.1.0 <0.2.0",
55
+ "@langchain/scripts": ">=0.1.2 <0.2.0",
54
56
  "@swc/core": "^1.3.90",
55
57
  "@swc/jest": "^0.2.29",
56
58
  "@tsconfig/recommended": "^1.0.3",