@langchain/langgraph 0.0.12 → 0.0.13

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 (134) hide show
  1. package/dist/channels/any_value.cjs +57 -0
  2. package/dist/channels/any_value.d.ts +16 -0
  3. package/dist/channels/any_value.js +53 -0
  4. package/dist/channels/base.cjs +19 -28
  5. package/dist/channels/base.d.ts +13 -19
  6. package/dist/channels/base.js +17 -24
  7. package/dist/channels/binop.cjs +4 -3
  8. package/dist/channels/binop.d.ts +1 -1
  9. package/dist/channels/binop.js +3 -2
  10. package/dist/channels/dynamic_barrier_value.cjs +88 -0
  11. package/dist/channels/dynamic_barrier_value.d.ts +26 -0
  12. package/dist/channels/dynamic_barrier_value.js +84 -0
  13. package/dist/channels/ephemeral_value.cjs +64 -0
  14. package/dist/channels/ephemeral_value.d.ts +14 -0
  15. package/dist/channels/ephemeral_value.js +60 -0
  16. package/dist/channels/index.cjs +1 -3
  17. package/dist/channels/index.d.ts +1 -1
  18. package/dist/channels/index.js +1 -1
  19. package/dist/channels/last_value.cjs +11 -5
  20. package/dist/channels/last_value.d.ts +5 -1
  21. package/dist/channels/last_value.js +9 -3
  22. package/dist/channels/named_barrier_value.cjs +71 -0
  23. package/dist/channels/named_barrier_value.d.ts +18 -0
  24. package/dist/channels/named_barrier_value.js +66 -0
  25. package/dist/channels/topic.cjs +5 -3
  26. package/dist/channels/topic.d.ts +3 -3
  27. package/dist/channels/topic.js +5 -3
  28. package/dist/checkpoint/base.cjs +30 -12
  29. package/dist/checkpoint/base.d.ts +39 -22
  30. package/dist/checkpoint/base.js +28 -11
  31. package/dist/checkpoint/id.cjs +40 -0
  32. package/dist/checkpoint/id.d.ts +2 -0
  33. package/dist/checkpoint/id.js +35 -0
  34. package/dist/checkpoint/index.cjs +2 -2
  35. package/dist/checkpoint/index.d.ts +2 -2
  36. package/dist/checkpoint/index.js +2 -2
  37. package/dist/checkpoint/memory.cjs +63 -49
  38. package/dist/checkpoint/memory.d.ts +7 -10
  39. package/dist/checkpoint/memory.js +62 -47
  40. package/dist/checkpoint/sqlite.cjs +170 -0
  41. package/dist/checkpoint/sqlite.d.ts +14 -0
  42. package/dist/checkpoint/sqlite.js +163 -0
  43. package/dist/constants.cjs +3 -1
  44. package/dist/constants.d.ts +2 -0
  45. package/dist/constants.js +2 -0
  46. package/dist/errors.cjs +31 -0
  47. package/dist/errors.d.ts +12 -0
  48. package/dist/errors.js +24 -0
  49. package/dist/graph/graph.cjs +235 -95
  50. package/dist/graph/graph.d.ts +52 -23
  51. package/dist/graph/graph.js +234 -96
  52. package/dist/graph/index.cjs +2 -2
  53. package/dist/graph/index.d.ts +2 -2
  54. package/dist/graph/index.js +2 -2
  55. package/dist/graph/message.cjs +4 -3
  56. package/dist/graph/message.d.ts +4 -1
  57. package/dist/graph/message.js +4 -3
  58. package/dist/graph/state.cjs +237 -102
  59. package/dist/graph/state.d.ts +41 -18
  60. package/dist/graph/state.js +238 -104
  61. package/dist/index.cjs +6 -2
  62. package/dist/index.d.ts +3 -2
  63. package/dist/index.js +2 -1
  64. package/dist/prebuilt/agent_executor.cjs +22 -36
  65. package/dist/prebuilt/agent_executor.d.ts +7 -10
  66. package/dist/prebuilt/agent_executor.js +23 -37
  67. package/dist/prebuilt/chat_agent_executor.cjs +13 -13
  68. package/dist/prebuilt/chat_agent_executor.d.ts +3 -1
  69. package/dist/prebuilt/chat_agent_executor.js +15 -15
  70. package/dist/prebuilt/index.cjs +4 -1
  71. package/dist/prebuilt/index.d.ts +1 -0
  72. package/dist/prebuilt/index.js +1 -0
  73. package/dist/prebuilt/tool_node.cjs +59 -0
  74. package/dist/prebuilt/tool_node.d.ts +17 -0
  75. package/dist/prebuilt/tool_node.js +54 -0
  76. package/dist/pregel/debug.cjs +6 -8
  77. package/dist/pregel/debug.d.ts +2 -2
  78. package/dist/pregel/debug.js +5 -7
  79. package/dist/pregel/index.cjs +406 -236
  80. package/dist/pregel/index.d.ts +77 -41
  81. package/dist/pregel/index.js +408 -241
  82. package/dist/pregel/io.cjs +117 -30
  83. package/dist/pregel/io.d.ts +11 -3
  84. package/dist/pregel/io.js +111 -28
  85. package/dist/pregel/read.cjs +126 -46
  86. package/dist/pregel/read.d.ts +27 -18
  87. package/dist/pregel/read.js +125 -45
  88. package/dist/pregel/types.cjs +2 -0
  89. package/dist/pregel/types.d.ts +32 -0
  90. package/dist/pregel/types.js +1 -0
  91. package/dist/pregel/validate.cjs +58 -51
  92. package/dist/pregel/validate.d.ts +14 -13
  93. package/dist/pregel/validate.js +56 -50
  94. package/dist/pregel/write.cjs +46 -30
  95. package/dist/pregel/write.d.ts +18 -8
  96. package/dist/pregel/write.js +45 -29
  97. package/dist/serde/base.cjs +2 -0
  98. package/dist/serde/base.d.ts +4 -0
  99. package/dist/serde/base.js +1 -0
  100. package/dist/setup/async_local_storage.cjs +2 -2
  101. package/dist/setup/async_local_storage.js +1 -1
  102. package/dist/tests/channels.test.d.ts +1 -0
  103. package/dist/tests/channels.test.js +151 -0
  104. package/dist/tests/chatbot.int.test.d.ts +1 -0
  105. package/dist/tests/chatbot.int.test.js +61 -0
  106. package/dist/tests/checkpoints.test.d.ts +1 -0
  107. package/dist/tests/checkpoints.test.js +190 -0
  108. package/dist/tests/graph.test.d.ts +1 -0
  109. package/dist/tests/graph.test.js +15 -0
  110. package/dist/tests/prebuilt.int.test.d.ts +1 -0
  111. package/dist/tests/prebuilt.int.test.js +101 -0
  112. package/dist/tests/prebuilt.test.d.ts +1 -0
  113. package/dist/tests/prebuilt.test.js +195 -0
  114. package/dist/tests/pregel.io.test.d.ts +1 -0
  115. package/dist/tests/pregel.io.test.js +332 -0
  116. package/dist/tests/pregel.read.test.d.ts +1 -0
  117. package/dist/tests/pregel.read.test.js +109 -0
  118. package/dist/tests/pregel.test.d.ts +1 -0
  119. package/dist/tests/pregel.test.js +1879 -0
  120. package/dist/tests/pregel.validate.test.d.ts +1 -0
  121. package/dist/tests/pregel.validate.test.js +198 -0
  122. package/dist/tests/pregel.write.test.d.ts +1 -0
  123. package/dist/tests/pregel.write.test.js +44 -0
  124. package/dist/tests/tracing.int.test.d.ts +1 -0
  125. package/dist/tests/tracing.int.test.js +449 -0
  126. package/dist/tests/utils.d.ts +22 -0
  127. package/dist/tests/utils.js +76 -0
  128. package/dist/utils.cjs +74 -0
  129. package/dist/utils.d.ts +18 -0
  130. package/dist/utils.js +70 -0
  131. package/package.json +11 -7
  132. package/dist/pregel/reserved.cjs +0 -6
  133. package/dist/pregel/reserved.d.ts +0 -3
  134. package/dist/pregel/reserved.js +0 -3
@@ -1,54 +1,70 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ChannelWrite = void 0;
4
- const runnables_1 = require("@langchain/core/runnables");
3
+ exports.ChannelWrite = exports.PASSTHROUGH = exports.SKIP_WRITE = void 0;
5
4
  const constants_js_1 = require("../constants.cjs");
5
+ const utils_js_1 = require("../utils.cjs");
6
+ exports.SKIP_WRITE = {};
7
+ exports.PASSTHROUGH = {};
8
+ const IS_WRITER = Symbol("IS_WRITER");
6
9
  /**
7
10
  * Mapping of write channels to Runnables that return the value to be written,
8
11
  * or None to skip writing.
9
12
  */
10
- class ChannelWrite extends runnables_1.RunnablePassthrough {
11
- constructor(channels) {
12
- const name = `ChannelWrite<${channels.map(([chan]) => chan).join(",")}>`;
13
+ class ChannelWrite extends utils_js_1.RunnableCallable {
14
+ constructor(writes, tags) {
15
+ const name = `ChannelWrite<${writes
16
+ .map(({ channel }) => channel)
17
+ .join(",")}>`;
13
18
  super({
14
- ...{ channels, name },
19
+ ...{ writes, name, tags },
15
20
  func: async (input, config) => this._write(input, config ?? {}),
16
21
  });
17
- Object.defineProperty(this, "channels", {
22
+ Object.defineProperty(this, "writes", {
18
23
  enumerable: true,
19
24
  configurable: true,
20
25
  writable: true,
21
26
  value: void 0
22
27
  });
23
- this.channels = channels;
28
+ this.writes = writes;
24
29
  }
25
- get configSpecs() {
26
- return [
27
- {
28
- id: constants_js_1.CONFIG_KEY_SEND,
29
- name: constants_js_1.CONFIG_KEY_SEND,
30
- description: null,
31
- default: null,
32
- annotation: "TYPE_SEND",
33
- isShared: true,
34
- dependencies: null,
35
- },
36
- ];
30
+ async _getWriteValues(input, config) {
31
+ return Promise.all(this.writes
32
+ .map((write) => ({
33
+ channel: write.channel,
34
+ value: write.value === exports.PASSTHROUGH ? input : write.value,
35
+ skipNone: write.skipNone,
36
+ mapper: write.mapper,
37
+ }))
38
+ .map(async (write) => ({
39
+ channel: write.channel,
40
+ value: write.mapper
41
+ ? await write.mapper.invoke(write.value, config)
42
+ : write.value,
43
+ skipNone: write.skipNone,
44
+ mapper: write.mapper,
45
+ }))).then((writes) => writes
46
+ .filter((write) => !write.skipNone || write.value !== null)
47
+ .reduce((acc, write) => {
48
+ acc[write.channel] = write.value;
49
+ return acc;
50
+ }, {}));
37
51
  }
38
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
52
  async _write(input, config) {
40
- const values = this.channels.map(async ([chan, r]) => [
41
- chan,
42
- r ? await r.invoke(input, config) : input,
43
- ]);
44
- let valuesAwaited = await Promise.all(values);
45
- valuesAwaited = valuesAwaited.filter((write, index) => this.channels[index][1] === null || write[1] !== null);
46
- ChannelWrite.doWrite(config, Object.fromEntries(valuesAwaited.filter(([_, val], i) => this.channels[i][1] ? Boolean(val) : val)));
53
+ const values = await this._getWriteValues(input, config);
54
+ ChannelWrite.doWrite(config, values);
47
55
  }
48
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
56
  static doWrite(config, values) {
50
57
  const write = config.configurable?.[constants_js_1.CONFIG_KEY_SEND];
51
- write(Object.entries(values));
58
+ write(Object.entries(values).filter(([_channel, value]) => value !== exports.SKIP_WRITE));
59
+ }
60
+ static isWriter(runnable) {
61
+ return (
62
+ // eslint-disable-next-line no-instanceof/no-instanceof
63
+ runnable instanceof ChannelWrite ||
64
+ (IS_WRITER in runnable && !!runnable[IS_WRITER]));
65
+ }
66
+ static registerWriter(runnable) {
67
+ return Object.defineProperty(runnable, IS_WRITER, { value: true });
52
68
  }
53
69
  }
54
70
  exports.ChannelWrite = ChannelWrite;
@@ -1,13 +1,23 @@
1
- import { Runnable, RunnableConfig, RunnablePassthrough } from "@langchain/core/runnables";
2
- import { ConfigurableFieldSpec } from "../checkpoint/index.js";
1
+ import { Runnable, RunnableConfig, RunnableLike } from "@langchain/core/runnables";
2
+ import { RunnableCallable } from "../utils.js";
3
+ export declare const SKIP_WRITE: {};
4
+ export declare const PASSTHROUGH: {};
3
5
  /**
4
6
  * Mapping of write channels to Runnables that return the value to be written,
5
7
  * or None to skip writing.
6
8
  */
7
- export declare class ChannelWrite<RunInput = any, RunOutput = any> extends RunnablePassthrough<RunInput> {
8
- channels: Array<[string, Runnable<RunInput, RunOutput> | undefined]>;
9
- constructor(channels: Array<[string, Runnable<RunInput, RunOutput> | undefined]>);
10
- get configSpecs(): ConfigurableFieldSpec[];
11
- _write(input: any, config: RunnableConfig): Promise<void>;
12
- static doWrite(config: RunnableConfig, values: Record<string, any>): void;
9
+ export declare class ChannelWrite<RunInput = any> extends RunnableCallable {
10
+ writes: Array<ChannelWriteEntry>;
11
+ constructor(writes: Array<ChannelWriteEntry>, tags?: string[]);
12
+ _getWriteValues(input: unknown, config: RunnableConfig): Promise<Record<string, unknown>>;
13
+ _write(input: unknown, config: RunnableConfig): Promise<void>;
14
+ static doWrite(config: RunnableConfig, values: Record<string, unknown>): void;
15
+ static isWriter(runnable: RunnableLike): boolean;
16
+ static registerWriter<T extends Runnable>(runnable: T): T;
17
+ }
18
+ export interface ChannelWriteEntry {
19
+ channel: string;
20
+ value: unknown;
21
+ skipNone?: boolean;
22
+ mapper?: Runnable;
13
23
  }
@@ -1,50 +1,66 @@
1
- import { RunnablePassthrough, } from "@langchain/core/runnables";
2
1
  import { CONFIG_KEY_SEND } from "../constants.js";
2
+ import { RunnableCallable } from "../utils.js";
3
+ export const SKIP_WRITE = {};
4
+ export const PASSTHROUGH = {};
5
+ const IS_WRITER = Symbol("IS_WRITER");
3
6
  /**
4
7
  * Mapping of write channels to Runnables that return the value to be written,
5
8
  * or None to skip writing.
6
9
  */
7
- export class ChannelWrite extends RunnablePassthrough {
8
- constructor(channels) {
9
- const name = `ChannelWrite<${channels.map(([chan]) => chan).join(",")}>`;
10
+ export class ChannelWrite extends RunnableCallable {
11
+ constructor(writes, tags) {
12
+ const name = `ChannelWrite<${writes
13
+ .map(({ channel }) => channel)
14
+ .join(",")}>`;
10
15
  super({
11
- ...{ channels, name },
16
+ ...{ writes, name, tags },
12
17
  func: async (input, config) => this._write(input, config ?? {}),
13
18
  });
14
- Object.defineProperty(this, "channels", {
19
+ Object.defineProperty(this, "writes", {
15
20
  enumerable: true,
16
21
  configurable: true,
17
22
  writable: true,
18
23
  value: void 0
19
24
  });
20
- this.channels = channels;
25
+ this.writes = writes;
21
26
  }
22
- get configSpecs() {
23
- return [
24
- {
25
- id: CONFIG_KEY_SEND,
26
- name: CONFIG_KEY_SEND,
27
- description: null,
28
- default: null,
29
- annotation: "TYPE_SEND",
30
- isShared: true,
31
- dependencies: null,
32
- },
33
- ];
27
+ async _getWriteValues(input, config) {
28
+ return Promise.all(this.writes
29
+ .map((write) => ({
30
+ channel: write.channel,
31
+ value: write.value === PASSTHROUGH ? input : write.value,
32
+ skipNone: write.skipNone,
33
+ mapper: write.mapper,
34
+ }))
35
+ .map(async (write) => ({
36
+ channel: write.channel,
37
+ value: write.mapper
38
+ ? await write.mapper.invoke(write.value, config)
39
+ : write.value,
40
+ skipNone: write.skipNone,
41
+ mapper: write.mapper,
42
+ }))).then((writes) => writes
43
+ .filter((write) => !write.skipNone || write.value !== null)
44
+ .reduce((acc, write) => {
45
+ acc[write.channel] = write.value;
46
+ return acc;
47
+ }, {}));
34
48
  }
35
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
49
  async _write(input, config) {
37
- const values = this.channels.map(async ([chan, r]) => [
38
- chan,
39
- r ? await r.invoke(input, config) : input,
40
- ]);
41
- let valuesAwaited = await Promise.all(values);
42
- valuesAwaited = valuesAwaited.filter((write, index) => this.channels[index][1] === null || write[1] !== null);
43
- ChannelWrite.doWrite(config, Object.fromEntries(valuesAwaited.filter(([_, val], i) => this.channels[i][1] ? Boolean(val) : val)));
50
+ const values = await this._getWriteValues(input, config);
51
+ ChannelWrite.doWrite(config, values);
44
52
  }
45
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
53
  static doWrite(config, values) {
47
54
  const write = config.configurable?.[CONFIG_KEY_SEND];
48
- write(Object.entries(values));
55
+ write(Object.entries(values).filter(([_channel, value]) => value !== SKIP_WRITE));
56
+ }
57
+ static isWriter(runnable) {
58
+ return (
59
+ // eslint-disable-next-line no-instanceof/no-instanceof
60
+ runnable instanceof ChannelWrite ||
61
+ (IS_WRITER in runnable && !!runnable[IS_WRITER]));
62
+ }
63
+ static registerWriter(runnable) {
64
+ return Object.defineProperty(runnable, IS_WRITER, { value: true });
49
65
  }
50
66
  }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ export interface SerializerProtocol<D> {
2
+ stringify(obj: D): string;
3
+ parse(data: string): D;
4
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.initializeAsyncLocalStorageSingleton = void 0;
4
4
  const singletons_1 = require("@langchain/core/singletons");
5
- const async_hooks_1 = require("async_hooks");
5
+ const node_async_hooks_1 = require("node:async_hooks");
6
6
  function initializeAsyncLocalStorageSingleton() {
7
- singletons_1.AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new async_hooks_1.AsyncLocalStorage());
7
+ singletons_1.AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new node_async_hooks_1.AsyncLocalStorage());
8
8
  }
9
9
  exports.initializeAsyncLocalStorageSingleton = initializeAsyncLocalStorageSingleton;
@@ -1,5 +1,5 @@
1
1
  import { AsyncLocalStorageProviderSingleton } from "@langchain/core/singletons";
2
- import { AsyncLocalStorage } from "async_hooks";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
3
  export function initializeAsyncLocalStorageSingleton() {
4
4
  AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new AsyncLocalStorage());
5
5
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,151 @@
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
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { describe, it } from "@jest/globals";
2
+ import { ChatOpenAI } from "@langchain/openai";
3
+ import { HumanMessage, ToolMessage, } from "@langchain/core/messages";
4
+ import { Calculator } from "langchain/tools/calculator";
5
+ import { convertToOpenAITool } from "@langchain/core/utils/function_calling";
6
+ import { END, MessageGraph, START } from "../index.js";
7
+ describe("Chatbot", () => {
8
+ it("Simple chat use-case", async () => {
9
+ const model = new ChatOpenAI({ temperature: 0 });
10
+ const graph = new MessageGraph()
11
+ .addNode("oracle", async (state) => model.invoke(state))
12
+ .addEdge("oracle", END)
13
+ .setEntryPoint("oracle")
14
+ .compile();
15
+ const res = await graph.invoke(new HumanMessage("What is 1 + 1?"));
16
+ console.log(res);
17
+ });
18
+ it("Chat use-case with tool calling", async () => {
19
+ const model = new ChatOpenAI({
20
+ temperature: 0,
21
+ }).bind({
22
+ tools: [convertToOpenAITool(new Calculator())],
23
+ tool_choice: "auto",
24
+ });
25
+ const router = (state) => {
26
+ const toolCalls = state[state.length - 1].additional_kwargs.tool_calls ?? [];
27
+ if (toolCalls.length) {
28
+ return "calculator";
29
+ }
30
+ else {
31
+ return "end";
32
+ }
33
+ };
34
+ const graph = new MessageGraph()
35
+ .addNode("oracle", async (state) => model.invoke(state))
36
+ .addNode("calculator", async (state) => {
37
+ const tool = new Calculator();
38
+ const toolCalls = state[state.length - 1].additional_kwargs.tool_calls ?? [];
39
+ const calculatorCall = toolCalls.find((toolCall) => toolCall.function.name === "calculator");
40
+ if (calculatorCall === undefined) {
41
+ throw new Error("No calculator input found.");
42
+ }
43
+ const result = await tool.invoke(JSON.parse(calculatorCall.function.arguments));
44
+ return new ToolMessage({
45
+ tool_call_id: calculatorCall.id,
46
+ content: result,
47
+ });
48
+ })
49
+ .addEdge("calculator", END)
50
+ .addEdge(START, "oracle")
51
+ .addConditionalEdges("oracle", router, {
52
+ calculator: "calculator",
53
+ end: END,
54
+ })
55
+ .compile();
56
+ const res = await graph.invoke(new HumanMessage("What is 1 + 1?"));
57
+ console.log(res);
58
+ const res2 = await graph.invoke(new HumanMessage("What is your name?"));
59
+ console.log(res2);
60
+ });
61
+ });
@@ -0,0 +1 @@
1
+ export {};