@langchain/langgraph 0.0.11 → 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.
- package/dist/channels/any_value.cjs +57 -0
- package/dist/channels/any_value.d.ts +16 -0
- package/dist/channels/any_value.js +53 -0
- package/dist/channels/base.cjs +19 -28
- package/dist/channels/base.d.ts +13 -19
- package/dist/channels/base.js +17 -24
- package/dist/channels/binop.cjs +4 -3
- package/dist/channels/binop.d.ts +1 -1
- package/dist/channels/binop.js +3 -2
- package/dist/channels/dynamic_barrier_value.cjs +88 -0
- package/dist/channels/dynamic_barrier_value.d.ts +26 -0
- package/dist/channels/dynamic_barrier_value.js +84 -0
- package/dist/channels/ephemeral_value.cjs +64 -0
- package/dist/channels/ephemeral_value.d.ts +14 -0
- package/dist/channels/ephemeral_value.js +60 -0
- package/dist/channels/index.cjs +1 -3
- package/dist/channels/index.d.ts +1 -1
- package/dist/channels/index.js +1 -1
- package/dist/channels/last_value.cjs +11 -5
- package/dist/channels/last_value.d.ts +5 -1
- package/dist/channels/last_value.js +9 -3
- package/dist/channels/named_barrier_value.cjs +71 -0
- package/dist/channels/named_barrier_value.d.ts +18 -0
- package/dist/channels/named_barrier_value.js +66 -0
- package/dist/channels/topic.cjs +5 -3
- package/dist/channels/topic.d.ts +3 -3
- package/dist/channels/topic.js +5 -3
- package/dist/checkpoint/base.cjs +30 -12
- package/dist/checkpoint/base.d.ts +39 -22
- package/dist/checkpoint/base.js +28 -11
- package/dist/checkpoint/id.cjs +40 -0
- package/dist/checkpoint/id.d.ts +2 -0
- package/dist/checkpoint/id.js +35 -0
- package/dist/checkpoint/index.cjs +2 -2
- package/dist/checkpoint/index.d.ts +2 -2
- package/dist/checkpoint/index.js +2 -2
- package/dist/checkpoint/memory.cjs +63 -49
- package/dist/checkpoint/memory.d.ts +7 -10
- package/dist/checkpoint/memory.js +62 -47
- package/dist/checkpoint/sqlite.cjs +170 -0
- package/dist/checkpoint/sqlite.d.ts +14 -0
- package/dist/checkpoint/sqlite.js +163 -0
- package/dist/constants.cjs +3 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +2 -0
- package/dist/errors.cjs +31 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +24 -0
- package/dist/graph/graph.cjs +234 -96
- package/dist/graph/graph.d.ts +52 -23
- package/dist/graph/graph.js +233 -97
- package/dist/graph/index.cjs +2 -2
- package/dist/graph/index.d.ts +2 -2
- package/dist/graph/index.js +2 -2
- package/dist/graph/message.cjs +4 -3
- package/dist/graph/message.d.ts +4 -1
- package/dist/graph/message.js +4 -3
- package/dist/graph/state.cjs +237 -102
- package/dist/graph/state.d.ts +41 -18
- package/dist/graph/state.js +238 -104
- package/dist/index.cjs +6 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/prebuilt/agent_executor.cjs +22 -36
- package/dist/prebuilt/agent_executor.d.ts +7 -10
- package/dist/prebuilt/agent_executor.js +23 -37
- package/dist/prebuilt/chat_agent_executor.cjs +13 -13
- package/dist/prebuilt/chat_agent_executor.d.ts +3 -1
- package/dist/prebuilt/chat_agent_executor.js +15 -15
- package/dist/prebuilt/index.cjs +4 -1
- package/dist/prebuilt/index.d.ts +1 -0
- package/dist/prebuilt/index.js +1 -0
- package/dist/prebuilt/tool_node.cjs +59 -0
- package/dist/prebuilt/tool_node.d.ts +17 -0
- package/dist/prebuilt/tool_node.js +54 -0
- package/dist/pregel/debug.cjs +6 -8
- package/dist/pregel/debug.d.ts +2 -2
- package/dist/pregel/debug.js +5 -7
- package/dist/pregel/index.cjs +406 -236
- package/dist/pregel/index.d.ts +77 -41
- package/dist/pregel/index.js +408 -241
- package/dist/pregel/io.cjs +117 -30
- package/dist/pregel/io.d.ts +11 -3
- package/dist/pregel/io.js +111 -28
- package/dist/pregel/read.cjs +126 -46
- package/dist/pregel/read.d.ts +27 -18
- package/dist/pregel/read.js +125 -45
- package/dist/pregel/types.cjs +2 -0
- package/dist/pregel/types.d.ts +32 -0
- package/dist/pregel/types.js +1 -0
- package/dist/pregel/validate.cjs +58 -51
- package/dist/pregel/validate.d.ts +14 -13
- package/dist/pregel/validate.js +56 -50
- package/dist/pregel/write.cjs +46 -30
- package/dist/pregel/write.d.ts +18 -8
- package/dist/pregel/write.js +45 -29
- package/dist/serde/base.cjs +2 -0
- package/dist/serde/base.d.ts +4 -0
- package/dist/serde/base.js +1 -0
- package/dist/setup/async_local_storage.cjs +2 -2
- package/dist/setup/async_local_storage.js +1 -1
- package/dist/tests/channels.test.d.ts +1 -0
- package/dist/tests/channels.test.js +151 -0
- package/dist/tests/chatbot.int.test.d.ts +1 -0
- package/dist/tests/chatbot.int.test.js +61 -0
- package/dist/tests/checkpoints.test.d.ts +1 -0
- package/dist/tests/checkpoints.test.js +190 -0
- package/dist/tests/graph.test.d.ts +1 -0
- package/dist/tests/graph.test.js +15 -0
- package/dist/tests/prebuilt.int.test.d.ts +1 -0
- package/dist/tests/prebuilt.int.test.js +101 -0
- package/dist/tests/prebuilt.test.d.ts +1 -0
- package/dist/tests/prebuilt.test.js +195 -0
- package/dist/tests/pregel.io.test.d.ts +1 -0
- package/dist/tests/pregel.io.test.js +332 -0
- package/dist/tests/pregel.read.test.d.ts +1 -0
- package/dist/tests/pregel.read.test.js +109 -0
- package/dist/tests/pregel.test.d.ts +1 -0
- package/dist/tests/pregel.test.js +1879 -0
- package/dist/tests/pregel.validate.test.d.ts +1 -0
- package/dist/tests/pregel.validate.test.js +198 -0
- package/dist/tests/pregel.write.test.d.ts +1 -0
- package/dist/tests/pregel.write.test.js +44 -0
- package/dist/tests/tracing.int.test.d.ts +1 -0
- package/dist/tests/tracing.int.test.js +449 -0
- package/dist/tests/utils.d.ts +22 -0
- package/dist/tests/utils.js +76 -0
- package/dist/utils.cjs +74 -0
- package/dist/utils.d.ts +18 -0
- package/dist/utils.js +70 -0
- package/package.json +12 -8
- package/dist/pregel/reserved.cjs +0 -6
- package/dist/pregel/reserved.d.ts +0 -3
- package/dist/pregel/reserved.js +0 -3
package/dist/pregel/write.cjs
CHANGED
|
@@ -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
|
|
11
|
-
constructor(
|
|
12
|
-
const name = `ChannelWrite<${
|
|
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
|
-
...{
|
|
19
|
+
...{ writes, name, tags },
|
|
15
20
|
func: async (input, config) => this._write(input, config ?? {}),
|
|
16
21
|
});
|
|
17
|
-
Object.defineProperty(this, "
|
|
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.
|
|
28
|
+
this.writes = writes;
|
|
24
29
|
}
|
|
25
|
-
|
|
26
|
-
return
|
|
27
|
-
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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.
|
|
41
|
-
|
|
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;
|
package/dist/pregel/write.d.ts
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
import { Runnable, RunnableConfig,
|
|
2
|
-
import {
|
|
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
|
|
8
|
-
|
|
9
|
-
constructor(
|
|
10
|
-
|
|
11
|
-
_write(input:
|
|
12
|
-
static doWrite(config: RunnableConfig, values: Record<string,
|
|
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
|
}
|
package/dist/pregel/write.js
CHANGED
|
@@ -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
|
|
8
|
-
constructor(
|
|
9
|
-
const name = `ChannelWrite<${
|
|
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
|
-
...{
|
|
16
|
+
...{ writes, name, tags },
|
|
12
17
|
func: async (input, config) => this._write(input, config ?? {}),
|
|
13
18
|
});
|
|
14
|
-
Object.defineProperty(this, "
|
|
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.
|
|
25
|
+
this.writes = writes;
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
return
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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.
|
|
38
|
-
|
|
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 @@
|
|
|
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
|
|
5
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
6
6
|
function initializeAsyncLocalStorageSingleton() {
|
|
7
|
-
singletons_1.AsyncLocalStorageProviderSingleton.initializeGlobalInstance(new
|
|
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 {};
|