@langchain/langgraph 0.0.31 → 0.0.32
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/README.md +75 -28
- package/dist/channels/base.cjs +14 -0
- package/dist/channels/base.d.ts +2 -0
- package/dist/channels/base.js +14 -0
- package/dist/graph/message.d.ts +1 -1
- package/dist/graph/state.cjs +36 -2
- package/dist/graph/state.d.ts +23 -9
- package/dist/graph/state.js +34 -1
- package/dist/prebuilt/agent_executor.d.ts +1 -1
- package/dist/pregel/index.cjs +26 -21
- package/dist/pregel/index.js +26 -21
- package/package.json +9 -16
- package/dist/tests/channels.test.d.ts +0 -1
- package/dist/tests/channels.test.js +0 -151
- package/dist/tests/chatbot.int.test.d.ts +0 -1
- package/dist/tests/chatbot.int.test.js +0 -66
- package/dist/tests/checkpoints.test.d.ts +0 -1
- package/dist/tests/checkpoints.test.js +0 -178
- package/dist/tests/diagrams.test.d.ts +0 -1
- package/dist/tests/diagrams.test.js +0 -25
- package/dist/tests/graph.test.d.ts +0 -1
- package/dist/tests/graph.test.js +0 -33
- package/dist/tests/prebuilt.int.test.d.ts +0 -1
- package/dist/tests/prebuilt.int.test.js +0 -207
- package/dist/tests/prebuilt.test.d.ts +0 -1
- package/dist/tests/prebuilt.test.js +0 -427
- package/dist/tests/pregel.io.test.d.ts +0 -1
- package/dist/tests/pregel.io.test.js +0 -332
- package/dist/tests/pregel.read.test.d.ts +0 -1
- package/dist/tests/pregel.read.test.js +0 -109
- package/dist/tests/pregel.test.d.ts +0 -1
- package/dist/tests/pregel.test.js +0 -1882
- package/dist/tests/pregel.validate.test.d.ts +0 -1
- package/dist/tests/pregel.validate.test.js +0 -198
- package/dist/tests/pregel.write.test.d.ts +0 -1
- package/dist/tests/pregel.write.test.js +0 -44
- package/dist/tests/tracing.int.test.d.ts +0 -1
- package/dist/tests/tracing.int.test.js +0 -450
- package/dist/tests/tracing.test.d.ts +0 -1
- package/dist/tests/tracing.test.js +0 -332
- package/dist/tests/utils.d.ts +0 -53
- package/dist/tests/utils.js +0 -167
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langchain/langgraph",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "LangGraph",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -13,40 +13,33 @@
|
|
|
13
13
|
"url": "git@github.com:langchain-ai/langgraphjs.git"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"build": "yarn
|
|
17
|
-
"build:
|
|
18
|
-
"build:cjs": "NODE_OPTIONS=--max-old-space-size=4096 echo '{}' > src/package.json && tsc --outDir dist-cjs/ -p tsconfig.cjs.json && yarn move-cjs-to-dist && rm -rf dist-cjs/ src/package.json",
|
|
19
|
-
"build:watch": "yarn create-entrypoints && tsc --outDir dist/ --watch",
|
|
20
|
-
"build:scripts": "yarn create-entrypoints && yarn check-tree-shaking",
|
|
16
|
+
"build": "yarn turbo:command build:internal --filter=@langchain/langgraph",
|
|
17
|
+
"build:internal": "yarn lc_build_v2 --create-entrypoints --pre --tree-shaking",
|
|
21
18
|
"lint:eslint": "NODE_OPTIONS=--max-old-space-size=4096 eslint --cache --ext .ts,.js src/",
|
|
22
19
|
"lint:dpdm": "dpdm --exit-code circular:1 --no-warning --no-tree src/*.ts src/**/*.ts",
|
|
23
20
|
"lint": "yarn lint:eslint && yarn lint:dpdm",
|
|
24
21
|
"lint:fix": "yarn lint:eslint --fix && yarn lint:dpdm",
|
|
25
|
-
"clean": "rm -rf dist/ dist-cjs/ src/package.json && NODE_OPTIONS=--max-old-space-size=4096 yarn create-entrypoints -- --pre",
|
|
26
22
|
"prepack": "yarn build",
|
|
27
23
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000 --maxWorkers=50%",
|
|
28
24
|
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch --testPathIgnorePatterns=\\.int\\.test.ts",
|
|
29
25
|
"test:single": "NODE_OPTIONS=--experimental-vm-modules yarn run jest --config jest.config.cjs --testTimeout 100000",
|
|
30
26
|
"test:int": "NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=\\.int\\.test.ts --testTimeout 100000 --maxWorkers=50%",
|
|
31
27
|
"format": "prettier --config .prettierrc --write \"src\"",
|
|
32
|
-
"format:check": "prettier --config .prettierrc --check \"src\""
|
|
33
|
-
"move-cjs-to-dist": "yarn lc-build --config ./langchain.config.js --move-cjs-dist",
|
|
34
|
-
"create-entrypoints": "yarn lc-build --config ./langchain.config.js --create-entrypoints",
|
|
35
|
-
"check-tree-shaking": "yarn lc-build --config ./langchain.config.js --tree-shaking"
|
|
28
|
+
"format:check": "prettier --config .prettierrc --check \"src\""
|
|
36
29
|
},
|
|
37
30
|
"author": "LangChain",
|
|
38
31
|
"license": "MIT",
|
|
39
32
|
"dependencies": {
|
|
40
|
-
"@langchain/core": ">=0.2.
|
|
33
|
+
"@langchain/core": ">=0.2.20 <0.3.0",
|
|
41
34
|
"uuid": "^10.0.0",
|
|
42
35
|
"zod": "^3.23.8"
|
|
43
36
|
},
|
|
44
37
|
"devDependencies": {
|
|
45
38
|
"@jest/globals": "^29.5.0",
|
|
46
|
-
"@langchain/anthropic": "^0.2.
|
|
39
|
+
"@langchain/anthropic": "^0.2.12",
|
|
47
40
|
"@langchain/community": "^0.2.19",
|
|
48
41
|
"@langchain/openai": "^0.2.4",
|
|
49
|
-
"@langchain/scripts": "^0.0.
|
|
42
|
+
"@langchain/scripts": "^0.0.19",
|
|
50
43
|
"@swc/core": "^1.3.90",
|
|
51
44
|
"@swc/jest": "^0.2.29",
|
|
52
45
|
"@tsconfig/recommended": "^1.0.3",
|
|
@@ -62,14 +55,14 @@
|
|
|
62
55
|
"eslint": "^8.33.0",
|
|
63
56
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
64
57
|
"eslint-config-prettier": "^8.6.0",
|
|
65
|
-
"eslint-plugin-import": "^2.
|
|
58
|
+
"eslint-plugin-import": "^2.29.1",
|
|
66
59
|
"eslint-plugin-no-instanceof": "^1.0.1",
|
|
67
60
|
"eslint-plugin-prettier": "^4.2.1",
|
|
68
61
|
"jest": "^29.5.0",
|
|
69
62
|
"jest-environment-node": "^29.6.4",
|
|
70
63
|
"langchain": "^0.2.10",
|
|
71
64
|
"prettier": "^2.8.3",
|
|
72
|
-
"release-it": "^
|
|
65
|
+
"release-it": "^17.6.0",
|
|
73
66
|
"rollup": "^4.5.2",
|
|
74
67
|
"ts-jest": "^29.1.0",
|
|
75
68
|
"tsx": "^4.7.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { AnyValue } from "../channels/any_value.js";
|
|
3
|
-
import { EphemeralValue } from "../channels/ephemeral_value.js";
|
|
4
|
-
import { LastValue } from "../channels/last_value.js";
|
|
5
|
-
import { EmptyChannelError, InvalidUpdateError } from "../errors.js";
|
|
6
|
-
import { Topic } from "../channels/topic.js";
|
|
7
|
-
import { BinaryOperatorAggregate } from "../channels/binop.js";
|
|
8
|
-
describe("LastValue", () => {
|
|
9
|
-
it("should handle last value correctly", () => {
|
|
10
|
-
const channel = new LastValue();
|
|
11
|
-
expect(() => {
|
|
12
|
-
channel.get();
|
|
13
|
-
}).toThrow(EmptyChannelError);
|
|
14
|
-
expect(() => {
|
|
15
|
-
channel.update([5, 6]);
|
|
16
|
-
}).toThrow(InvalidUpdateError);
|
|
17
|
-
channel.update([3]);
|
|
18
|
-
expect(channel.get()).toBe(3);
|
|
19
|
-
channel.update([4]);
|
|
20
|
-
expect(channel.get()).toBe(4);
|
|
21
|
-
});
|
|
22
|
-
it("should handle restoring from checkpoint correctly", () => {
|
|
23
|
-
// call `.update()` to add a value to the channel
|
|
24
|
-
const channel = new LastValue();
|
|
25
|
-
channel.update([100]);
|
|
26
|
-
const checkpoint = channel.checkpoint();
|
|
27
|
-
const restoredChannel = new LastValue();
|
|
28
|
-
const channel2 = restoredChannel.fromCheckpoint(checkpoint);
|
|
29
|
-
expect(channel2.get()).toBe(100);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe("Topic", () => {
|
|
33
|
-
const channel = new Topic();
|
|
34
|
-
it("should handle updates and get operations", () => {
|
|
35
|
-
channel.update(["a", "b"]);
|
|
36
|
-
expect(channel.get()).toEqual(["a", "b"]);
|
|
37
|
-
channel.update([["c", "d"], "d"]);
|
|
38
|
-
expect(channel.get()).toEqual(["c", "d", "d"]);
|
|
39
|
-
channel.update([]);
|
|
40
|
-
expect(channel.get()).toEqual([]);
|
|
41
|
-
channel.update(["e"]);
|
|
42
|
-
expect(channel.get()).toEqual(["e"]);
|
|
43
|
-
});
|
|
44
|
-
it("should create and use a checkpoint", () => {
|
|
45
|
-
const checkpoint = channel.checkpoint();
|
|
46
|
-
const newChannel = new Topic().fromCheckpoint(checkpoint);
|
|
47
|
-
expect(newChannel.get()).toEqual(["e"]);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
describe("Topic with unique: true", () => {
|
|
51
|
-
const channel = new Topic({ unique: true });
|
|
52
|
-
it("should de-dupe updates and get the last unique value", () => {
|
|
53
|
-
channel.update(["a", "b"]);
|
|
54
|
-
expect(channel.get()).toEqual(["a", "b"]);
|
|
55
|
-
channel.update(["b", ["c", "d"], "d"]);
|
|
56
|
-
expect(channel.get()).toEqual(["c", "d"]);
|
|
57
|
-
channel.update([]);
|
|
58
|
-
expect(channel.get()).toEqual([]);
|
|
59
|
-
channel.update(["e"]);
|
|
60
|
-
expect(channel.get()).toEqual(["e"]);
|
|
61
|
-
});
|
|
62
|
-
it("should de-dupe from checkpoint", () => {
|
|
63
|
-
const checkpoint = channel.checkpoint();
|
|
64
|
-
const newChannel = new Topic({ unique: true }).fromCheckpoint(checkpoint);
|
|
65
|
-
expect(newChannel.get()).toEqual(["e"]);
|
|
66
|
-
newChannel.update(["d", "f"]);
|
|
67
|
-
expect(newChannel.get()).toEqual(["f"]);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
describe("Topic with accumulate: true", () => {
|
|
71
|
-
const channel = new Topic({ accumulate: true });
|
|
72
|
-
it("should accumulate updates and get operations", () => {
|
|
73
|
-
channel.update(["a", "b"]);
|
|
74
|
-
expect(channel.get()).toEqual(["a", "b"]);
|
|
75
|
-
channel.update(["b", ["c", "d"], "d"]);
|
|
76
|
-
expect(channel.get()).toEqual(["a", "b", "b", "c", "d", "d"]);
|
|
77
|
-
channel.update([]);
|
|
78
|
-
expect(channel.get()).toEqual(["a", "b", "b", "c", "d", "d"]);
|
|
79
|
-
});
|
|
80
|
-
it("should create and use a checkpoint", () => {
|
|
81
|
-
const checkpoint = channel.checkpoint();
|
|
82
|
-
const newChannel = new Topic({ accumulate: true }).fromCheckpoint(checkpoint);
|
|
83
|
-
expect(newChannel.get()).toEqual(["a", "b", "b", "c", "d", "d"]);
|
|
84
|
-
newChannel.update(["e"]);
|
|
85
|
-
expect(newChannel.get()).toEqual(["a", "b", "b", "c", "d", "d", "e"]);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
describe("Topic with accumulate and unique: true", () => {
|
|
89
|
-
const channel = new Topic({ unique: true, accumulate: true });
|
|
90
|
-
it("should handle unique and accumulate updates and get operations", () => {
|
|
91
|
-
channel.update(["a", "b"]);
|
|
92
|
-
expect(channel.get()).toEqual(["a", "b"]);
|
|
93
|
-
channel.update(["b", ["c", "d"], "d"]);
|
|
94
|
-
expect(channel.get()).toEqual(["a", "b", "c", "d"]);
|
|
95
|
-
channel.update([]);
|
|
96
|
-
expect(channel.get()).toEqual(["a", "b", "c", "d"]);
|
|
97
|
-
});
|
|
98
|
-
it("should create and use a checkpoint", () => {
|
|
99
|
-
const checkpoint = channel.checkpoint();
|
|
100
|
-
const newChannel = new Topic({
|
|
101
|
-
unique: true,
|
|
102
|
-
accumulate: true,
|
|
103
|
-
}).fromCheckpoint(checkpoint);
|
|
104
|
-
expect(newChannel.get()).toEqual(["a", "b", "c", "d"]);
|
|
105
|
-
newChannel.update(["d", "e"]);
|
|
106
|
-
expect(newChannel.get()).toEqual(["a", "b", "c", "d", "e"]);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
describe("BinaryOperatorAggregate", () => {
|
|
110
|
-
it("should handle binary operator aggregation correctly", () => {
|
|
111
|
-
const channel = new BinaryOperatorAggregate((a, b) => a + b, () => 0);
|
|
112
|
-
expect(channel.get()).toBe(0);
|
|
113
|
-
channel.update([1, 2, 3]);
|
|
114
|
-
expect(channel.get()).toBe(6);
|
|
115
|
-
channel.update([4]);
|
|
116
|
-
expect(channel.get()).toBe(10);
|
|
117
|
-
});
|
|
118
|
-
it("should handle checkpointing correctly", () => {
|
|
119
|
-
const channel = new BinaryOperatorAggregate((a, b) => a + b, () => 0);
|
|
120
|
-
channel.update([1, 2, 3]);
|
|
121
|
-
channel.update([4]);
|
|
122
|
-
const checkpoint = channel.checkpoint();
|
|
123
|
-
const restoredChannel = new BinaryOperatorAggregate((a, b) => a + b, () => 10);
|
|
124
|
-
const channel2 = restoredChannel.fromCheckpoint(checkpoint);
|
|
125
|
-
expect(channel2.get()).toBe(10);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
describe("AnyValue", () => {
|
|
129
|
-
it("should handle any value correctly", () => {
|
|
130
|
-
const channel = new AnyValue();
|
|
131
|
-
expect(() => {
|
|
132
|
-
channel.get();
|
|
133
|
-
}).toThrow(EmptyChannelError);
|
|
134
|
-
channel.update([3]);
|
|
135
|
-
expect(channel.get()).toBe(3);
|
|
136
|
-
channel.update([4, 5]);
|
|
137
|
-
expect(channel.get()).toBe(5);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
describe("EphemeralValue with gaurd: false", () => {
|
|
141
|
-
it("should handle ephemeral value correctly", () => {
|
|
142
|
-
const channel = new EphemeralValue(false);
|
|
143
|
-
expect(() => {
|
|
144
|
-
channel.get();
|
|
145
|
-
}).toThrow(EmptyChannelError);
|
|
146
|
-
channel.update([3]);
|
|
147
|
-
expect(channel.get()).toBe(3);
|
|
148
|
-
channel.update([4, 5]);
|
|
149
|
-
expect(channel.get()).toBe(5);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { beforeAll, describe, it } from "@jest/globals";
|
|
2
|
-
import { ChatOpenAI } from "@langchain/openai";
|
|
3
|
-
import { HumanMessage, ToolMessage, } from "@langchain/core/messages";
|
|
4
|
-
import { Calculator } from "@langchain/community/tools/calculator";
|
|
5
|
-
import { convertToOpenAITool } from "@langchain/core/utils/function_calling";
|
|
6
|
-
import { END, MessageGraph, START } from "../index.js";
|
|
7
|
-
import { initializeAsyncLocalStorageSingleton } from "../setup/async_local_storage.js";
|
|
8
|
-
describe("Chatbot", () => {
|
|
9
|
-
beforeAll(() => {
|
|
10
|
-
// Will occur naturally if user imports from main `@langchain/langgraph` endpoint.
|
|
11
|
-
initializeAsyncLocalStorageSingleton();
|
|
12
|
-
});
|
|
13
|
-
it("Simple chat use-case", async () => {
|
|
14
|
-
const model = new ChatOpenAI({ temperature: 0 });
|
|
15
|
-
const graph = new MessageGraph()
|
|
16
|
-
.addNode("oracle", async (state) => model.invoke(state))
|
|
17
|
-
.addEdge("oracle", END)
|
|
18
|
-
.addEdge(START, "oracle")
|
|
19
|
-
.compile();
|
|
20
|
-
const res = await graph.invoke(new HumanMessage("What is 1 + 1?"));
|
|
21
|
-
console.log(res);
|
|
22
|
-
});
|
|
23
|
-
it("Chat use-case with tool calling", async () => {
|
|
24
|
-
const model = new ChatOpenAI({
|
|
25
|
-
temperature: 0,
|
|
26
|
-
}).bind({
|
|
27
|
-
tools: [convertToOpenAITool(new Calculator())],
|
|
28
|
-
tool_choice: "auto",
|
|
29
|
-
});
|
|
30
|
-
const router = (state) => {
|
|
31
|
-
const toolCalls = state[state.length - 1].additional_kwargs.tool_calls ?? [];
|
|
32
|
-
if (toolCalls.length) {
|
|
33
|
-
return "calculator";
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return "end";
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const graph = new MessageGraph()
|
|
40
|
-
.addNode("oracle", async (state) => model.invoke(state))
|
|
41
|
-
.addNode("calculator", async (state) => {
|
|
42
|
-
const tool = new Calculator();
|
|
43
|
-
const toolCalls = state[state.length - 1].additional_kwargs.tool_calls ?? [];
|
|
44
|
-
const calculatorCall = toolCalls.find((toolCall) => toolCall.function.name === "calculator");
|
|
45
|
-
if (calculatorCall === undefined) {
|
|
46
|
-
throw new Error("No calculator input found.");
|
|
47
|
-
}
|
|
48
|
-
const result = await tool.invoke(JSON.parse(calculatorCall.function.arguments));
|
|
49
|
-
return new ToolMessage({
|
|
50
|
-
tool_call_id: calculatorCall.id,
|
|
51
|
-
content: result,
|
|
52
|
-
});
|
|
53
|
-
})
|
|
54
|
-
.addEdge("calculator", END)
|
|
55
|
-
.addEdge(START, "oracle")
|
|
56
|
-
.addConditionalEdges("oracle", router, {
|
|
57
|
-
calculator: "calculator",
|
|
58
|
-
end: END,
|
|
59
|
-
})
|
|
60
|
-
.compile();
|
|
61
|
-
const res = await graph.invoke(new HumanMessage("What is 1 + 1?"));
|
|
62
|
-
console.log(res);
|
|
63
|
-
const res2 = await graph.invoke(new HumanMessage("What is your name?"));
|
|
64
|
-
console.log(res2);
|
|
65
|
-
});
|
|
66
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { deepCopy } from "../checkpoint/base.js";
|
|
3
|
-
import { MemorySaver } from "../checkpoint/memory.js";
|
|
4
|
-
import { SqliteSaver } from "../checkpoint/sqlite.js";
|
|
5
|
-
import { uuid6 } from "../checkpoint/id.js";
|
|
6
|
-
const checkpoint1 = {
|
|
7
|
-
v: 1,
|
|
8
|
-
id: uuid6(-1),
|
|
9
|
-
ts: "2024-04-19T17:19:07.952Z",
|
|
10
|
-
channel_values: {
|
|
11
|
-
someKey1: "someValue1",
|
|
12
|
-
},
|
|
13
|
-
channel_versions: {
|
|
14
|
-
someKey2: 1,
|
|
15
|
-
},
|
|
16
|
-
versions_seen: {
|
|
17
|
-
someKey3: {
|
|
18
|
-
someKey4: 1,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
const checkpoint2 = {
|
|
23
|
-
v: 1,
|
|
24
|
-
id: uuid6(1),
|
|
25
|
-
ts: "2024-04-20T17:19:07.952Z",
|
|
26
|
-
channel_values: {
|
|
27
|
-
someKey1: "someValue2",
|
|
28
|
-
},
|
|
29
|
-
channel_versions: {
|
|
30
|
-
someKey2: 2,
|
|
31
|
-
},
|
|
32
|
-
versions_seen: {
|
|
33
|
-
someKey3: {
|
|
34
|
-
someKey4: 2,
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
describe("Base", () => {
|
|
39
|
-
it("should deep copy a simple object", () => {
|
|
40
|
-
const obj = { a: 1, b: { c: 2 } };
|
|
41
|
-
const copiedObj = deepCopy(obj);
|
|
42
|
-
// Check if the copied object is equal to the original object
|
|
43
|
-
expect(copiedObj).toEqual(obj);
|
|
44
|
-
// Check if the copied object is not the same object reference as the original object
|
|
45
|
-
expect(copiedObj).not.toBe(obj);
|
|
46
|
-
// Check if the nested object is also deep copied
|
|
47
|
-
expect(copiedObj.b).toEqual(obj.b);
|
|
48
|
-
expect(copiedObj.b).not.toBe(obj.b);
|
|
49
|
-
});
|
|
50
|
-
it("should deep copy an array", () => {
|
|
51
|
-
const arr = [1, 2, 3];
|
|
52
|
-
const copiedArr = deepCopy(arr);
|
|
53
|
-
// Check if the copied array is equal to the original array
|
|
54
|
-
expect(copiedArr).toEqual(arr);
|
|
55
|
-
});
|
|
56
|
-
it("should deep copy an array of objects", () => {
|
|
57
|
-
const arr = [{ a: 1 }, { b: 2 }];
|
|
58
|
-
const copiedArr = deepCopy(arr);
|
|
59
|
-
// Check if the copied array is equal to the original array
|
|
60
|
-
expect(copiedArr).toEqual(arr);
|
|
61
|
-
// Check if the copied array is not the same array reference as the original array
|
|
62
|
-
expect(copiedArr).not.toBe(arr);
|
|
63
|
-
// Check if the nested objects in the array are also deep copied
|
|
64
|
-
expect(copiedArr[0]).toEqual(arr[0]);
|
|
65
|
-
expect(copiedArr[0]).not.toBe(arr[0]);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
describe("MemorySaver", () => {
|
|
69
|
-
it("should save and retrieve checkpoints correctly", async () => {
|
|
70
|
-
const memorySaver = new MemorySaver();
|
|
71
|
-
// save checkpoint
|
|
72
|
-
const runnableConfig = await memorySaver.put({ configurable: { thread_id: "1" } }, checkpoint1, { source: "update", step: -1, writes: null });
|
|
73
|
-
expect(runnableConfig).toEqual({
|
|
74
|
-
configurable: {
|
|
75
|
-
thread_id: "1",
|
|
76
|
-
checkpoint_id: checkpoint1.id,
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
// get checkpoint tuple
|
|
80
|
-
const checkpointTuple = await memorySaver.getTuple({
|
|
81
|
-
configurable: { thread_id: "1" },
|
|
82
|
-
});
|
|
83
|
-
expect(checkpointTuple?.config).toEqual({
|
|
84
|
-
configurable: {
|
|
85
|
-
thread_id: "1",
|
|
86
|
-
checkpoint_id: checkpoint1.id,
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
expect(checkpointTuple?.checkpoint).toEqual(checkpoint1);
|
|
90
|
-
// save another checkpoint
|
|
91
|
-
await memorySaver.put({ configurable: { thread_id: "1" } }, checkpoint2, {
|
|
92
|
-
source: "update",
|
|
93
|
-
step: -1,
|
|
94
|
-
writes: null,
|
|
95
|
-
});
|
|
96
|
-
// list checkpoints
|
|
97
|
-
const checkpointTupleGenerator = await memorySaver.list({
|
|
98
|
-
configurable: { thread_id: "1" },
|
|
99
|
-
});
|
|
100
|
-
const checkpointTuples = [];
|
|
101
|
-
for await (const checkpoint of checkpointTupleGenerator) {
|
|
102
|
-
checkpointTuples.push(checkpoint);
|
|
103
|
-
}
|
|
104
|
-
expect(checkpointTuples.length).toBe(2);
|
|
105
|
-
const checkpointTuple1 = checkpointTuples[0];
|
|
106
|
-
const checkpointTuple2 = checkpointTuples[1];
|
|
107
|
-
expect(checkpointTuple1.checkpoint.ts).toBe("2024-04-20T17:19:07.952Z");
|
|
108
|
-
expect(checkpointTuple2.checkpoint.ts).toBe("2024-04-19T17:19:07.952Z");
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
describe("SqliteSaver", () => {
|
|
112
|
-
it("should save and retrieve checkpoints correctly", async () => {
|
|
113
|
-
const sqliteSaver = SqliteSaver.fromConnString(":memory:");
|
|
114
|
-
// get undefined checkpoint
|
|
115
|
-
const undefinedCheckpoint = await sqliteSaver.getTuple({
|
|
116
|
-
configurable: { thread_id: "1" },
|
|
117
|
-
});
|
|
118
|
-
expect(undefinedCheckpoint).toBeUndefined();
|
|
119
|
-
// save first checkpoint
|
|
120
|
-
const runnableConfig = await sqliteSaver.put({ configurable: { thread_id: "1" } }, checkpoint1, { source: "update", step: -1, writes: null });
|
|
121
|
-
expect(runnableConfig).toEqual({
|
|
122
|
-
configurable: {
|
|
123
|
-
thread_id: "1",
|
|
124
|
-
checkpoint_id: checkpoint1.id,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
// get first checkpoint tuple
|
|
128
|
-
const firstCheckpointTuple = await sqliteSaver.getTuple({
|
|
129
|
-
configurable: { thread_id: "1" },
|
|
130
|
-
});
|
|
131
|
-
expect(firstCheckpointTuple?.config).toEqual({
|
|
132
|
-
configurable: {
|
|
133
|
-
thread_id: "1",
|
|
134
|
-
checkpoint_id: checkpoint1.id,
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
expect(firstCheckpointTuple?.checkpoint).toEqual(checkpoint1);
|
|
138
|
-
expect(firstCheckpointTuple?.parentConfig).toBeUndefined();
|
|
139
|
-
// save second checkpoint
|
|
140
|
-
await sqliteSaver.put({
|
|
141
|
-
configurable: {
|
|
142
|
-
thread_id: "1",
|
|
143
|
-
checkpoint_id: "2024-04-18T17:19:07.952Z",
|
|
144
|
-
},
|
|
145
|
-
}, checkpoint2, { source: "update", step: -1, writes: null });
|
|
146
|
-
// verify that parentTs is set and retrieved correctly for second checkpoint
|
|
147
|
-
const secondCheckpointTuple = await sqliteSaver.getTuple({
|
|
148
|
-
configurable: { thread_id: "1" },
|
|
149
|
-
});
|
|
150
|
-
expect(secondCheckpointTuple?.parentConfig).toEqual({
|
|
151
|
-
configurable: {
|
|
152
|
-
thread_id: "1",
|
|
153
|
-
checkpoint_id: "2024-04-18T17:19:07.952Z",
|
|
154
|
-
},
|
|
155
|
-
});
|
|
156
|
-
// list checkpoints
|
|
157
|
-
const checkpointTupleGenerator = await sqliteSaver.list({
|
|
158
|
-
configurable: { thread_id: "1" },
|
|
159
|
-
});
|
|
160
|
-
const checkpointTuples = [];
|
|
161
|
-
for await (const checkpoint of checkpointTupleGenerator) {
|
|
162
|
-
checkpointTuples.push(checkpoint);
|
|
163
|
-
}
|
|
164
|
-
expect(checkpointTuples.length).toBe(2);
|
|
165
|
-
const checkpointTuple1 = checkpointTuples[0];
|
|
166
|
-
const checkpointTuple2 = checkpointTuples[1];
|
|
167
|
-
expect(checkpointTuple1.checkpoint.ts).toBe("2024-04-20T17:19:07.952Z");
|
|
168
|
-
expect(checkpointTuple2.checkpoint.ts).toBe("2024-04-19T17:19:07.952Z");
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
describe("id", () => {
|
|
172
|
-
it("should accept clockseq -1", () => {
|
|
173
|
-
const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-6[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
174
|
-
const uuid = uuid6(-1);
|
|
175
|
-
expect(uuid).toMatch(regex);
|
|
176
|
-
expect(uuid.includes("u")).toBe(false);
|
|
177
|
-
});
|
|
178
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { test, expect } from "@jest/globals";
|
|
2
|
-
import { createReactAgent } from "../prebuilt/index.js";
|
|
3
|
-
import { FakeSearchTool, FakeToolCallingChatModel } from "./utils.js";
|
|
4
|
-
test("prebuilt agent", async () => {
|
|
5
|
-
// Define the tools for the agent to use
|
|
6
|
-
const tools = [new FakeSearchTool()];
|
|
7
|
-
const model = new FakeToolCallingChatModel({});
|
|
8
|
-
const app = createReactAgent({ llm: model, tools });
|
|
9
|
-
const graph = app.getGraph();
|
|
10
|
-
const mermaid = graph.drawMermaid();
|
|
11
|
-
expect(mermaid).toEqual(`%%{init: {'flowchart': {'curve': 'linear'}}}%%
|
|
12
|
-
graph TD;
|
|
13
|
-
\t__start__[__start__]:::startclass;
|
|
14
|
-
\t__end__[__end__]:::endclass;
|
|
15
|
-
\tagent([agent]):::otherclass;
|
|
16
|
-
\ttools([tools]):::otherclass;
|
|
17
|
-
\t__start__ --> agent;
|
|
18
|
-
\ttools --> agent;
|
|
19
|
-
\tagent -. continue .-> tools;
|
|
20
|
-
\tagent -.-> __end__;
|
|
21
|
-
\tclassDef startclass fill:#ffdfba;
|
|
22
|
-
\tclassDef endclass fill:#baffc9;
|
|
23
|
-
\tclassDef otherclass fill:#fad7de;
|
|
24
|
-
`);
|
|
25
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/tests/graph.test.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import { StateGraph } from "../graph/state.js";
|
|
3
|
-
import { END, START } from "../web.js";
|
|
4
|
-
describe("State", () => {
|
|
5
|
-
it("should validate a new node key correctly ", () => {
|
|
6
|
-
const stateGraph = new StateGraph({
|
|
7
|
-
channels: { existingStateAttributeKey: null },
|
|
8
|
-
});
|
|
9
|
-
expect(() => {
|
|
10
|
-
stateGraph.addNode("existingStateAttributeKey", (_) => ({}));
|
|
11
|
-
}).toThrow("existingStateAttributeKey");
|
|
12
|
-
expect(() => {
|
|
13
|
-
stateGraph.addNode("newNodeKey", (_) => ({}));
|
|
14
|
-
}).not.toThrow();
|
|
15
|
-
});
|
|
16
|
-
it("should allow reducers with different argument types", async () => {
|
|
17
|
-
const stateGraph = new StateGraph({
|
|
18
|
-
channels: {
|
|
19
|
-
testval: {
|
|
20
|
-
reducer: (left, right) => right ? left.concat([right.toString()]) : left,
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
const graph = stateGraph
|
|
25
|
-
.addNode("testnode", (_) => ({ testval: "hi!" }))
|
|
26
|
-
.addEdge(START, "testnode")
|
|
27
|
-
.addEdge("testnode", END)
|
|
28
|
-
.compile();
|
|
29
|
-
expect(await graph.invoke({ testval: ["hello"] })).toEqual({
|
|
30
|
-
testval: ["hello", "hi!"],
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|