@langchain/langgraph 0.2.62 → 0.2.63
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 +14 -0
- package/dist/prebuilt/react_agent_executor.cjs +34 -13
- package/dist/prebuilt/react_agent_executor.d.ts +3 -0
- package/dist/prebuilt/react_agent_executor.js +34 -15
- package/dist/prebuilt/react_agent_executor.js.map +1 -1
- package/dist/prebuilt/tool_node.cjs +26 -4
- package/dist/prebuilt/tool_node.js +27 -5
- package/dist/prebuilt/tool_node.js.map +1 -1
- package/dist/pregel/debug.cjs +9 -7
- package/dist/pregel/debug.d.ts +10 -0
- package/dist/pregel/debug.js +2 -2
- package/dist/pregel/debug.js.map +1 -1
- package/dist/pregel/debug.test.cjs +189 -0
- package/dist/pregel/debug.test.d.ts +1 -0
- package/dist/pregel/debug.test.js +187 -0
- package/dist/pregel/debug.test.js.map +1 -0
- package/dist/pregel/io.mapCommand.test.cjs +151 -0
- package/dist/pregel/io.mapCommand.test.d.ts +1 -0
- package/dist/pregel/io.mapCommand.test.js +149 -0
- package/dist/pregel/io.mapCommand.test.js.map +1 -0
- package/dist/pregel/messages.test.cjs +351 -0
- package/dist/pregel/messages.test.d.ts +1 -0
- package/dist/pregel/messages.test.js +349 -0
- package/dist/pregel/messages.test.js.map +1 -0
- package/dist/pregel/read.cjs +1 -1
- package/dist/pregel/read.js +1 -1
- package/dist/pregel/read.js.map +1 -1
- package/dist/pregel/read.test.cjs +194 -0
- package/dist/pregel/read.test.d.ts +1 -0
- package/dist/pregel/read.test.js +192 -0
- package/dist/pregel/read.test.js.map +1 -0
- package/dist/pregel/runner.test.cjs +66 -0
- package/dist/pregel/runner.test.d.ts +1 -0
- package/dist/pregel/runner.test.js +64 -0
- package/dist/pregel/runner.test.js.map +1 -0
- package/dist/pregel/utils/config.test.cjs +214 -0
- package/dist/pregel/utils/config.test.d.ts +1 -0
- package/dist/pregel/utils/config.test.js +212 -0
- package/dist/pregel/utils/config.test.js.map +1 -0
- package/dist/pregel/utils/subgraph.test.cjs +83 -0
- package/dist/pregel/utils/subgraph.test.d.ts +1 -0
- package/dist/pregel/utils/subgraph.test.js +81 -0
- package/dist/pregel/utils/subgraph.test.js.map +1 -0
- package/dist/pregel/validate.test.cjs +220 -0
- package/dist/pregel/validate.test.d.ts +1 -0
- package/dist/pregel/validate.test.js +218 -0
- package/dist/pregel/validate.test.js.map +1 -0
- package/dist/pregel/write.test.cjs +181 -0
- package/dist/pregel/write.test.d.ts +1 -0
- package/dist/pregel/write.test.js +179 -0
- package/dist/pregel/write.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, expect, it } from "@jest/globals";
|
|
2
|
+
import { Command, Send } from "../constants.js";
|
|
3
|
+
import { mapCommand } from "./io.js";
|
|
4
|
+
import { InvalidUpdateError } from "../errors.js";
|
|
5
|
+
describe("mapCommand", () => {
|
|
6
|
+
it("should handle Command with goto (string)", () => {
|
|
7
|
+
const cmd = new Command({
|
|
8
|
+
goto: "nextNode",
|
|
9
|
+
});
|
|
10
|
+
const pendingWrites = [];
|
|
11
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
12
|
+
expect(result).toEqual([
|
|
13
|
+
[
|
|
14
|
+
"00000000-0000-0000-0000-000000000000",
|
|
15
|
+
"branch:__start__:__self__:nextNode",
|
|
16
|
+
"__start__",
|
|
17
|
+
],
|
|
18
|
+
]);
|
|
19
|
+
});
|
|
20
|
+
it("should handle Command with goto (Send object)", () => {
|
|
21
|
+
const send = new Send("targetNode", { arg1: "value1" });
|
|
22
|
+
const cmd = new Command({
|
|
23
|
+
goto: send,
|
|
24
|
+
});
|
|
25
|
+
const pendingWrites = [];
|
|
26
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
27
|
+
expect(result).toEqual([
|
|
28
|
+
["00000000-0000-0000-0000-000000000000", "__pregel_tasks", send],
|
|
29
|
+
]);
|
|
30
|
+
});
|
|
31
|
+
it("should handle Command with goto (array of strings and Send objects)", () => {
|
|
32
|
+
const send = new Send("targetNode", { arg1: "value1" });
|
|
33
|
+
const cmd = new Command({
|
|
34
|
+
goto: ["nextNode1", send, "nextNode2"],
|
|
35
|
+
});
|
|
36
|
+
const pendingWrites = [];
|
|
37
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
38
|
+
expect(result).toEqual([
|
|
39
|
+
[
|
|
40
|
+
"00000000-0000-0000-0000-000000000000",
|
|
41
|
+
"branch:__start__:__self__:nextNode1",
|
|
42
|
+
"__start__",
|
|
43
|
+
],
|
|
44
|
+
["00000000-0000-0000-0000-000000000000", "__pregel_tasks", send],
|
|
45
|
+
[
|
|
46
|
+
"00000000-0000-0000-0000-000000000000",
|
|
47
|
+
"branch:__start__:__self__:nextNode2",
|
|
48
|
+
"__start__",
|
|
49
|
+
],
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
it("should throw error for invalid goto value", () => {
|
|
53
|
+
const cmd = new Command({
|
|
54
|
+
// @ts-expect-error Testing invalid input
|
|
55
|
+
goto: { invalidType: true },
|
|
56
|
+
});
|
|
57
|
+
const pendingWrites = [];
|
|
58
|
+
expect(() => Array.from(mapCommand(cmd, pendingWrites))).toThrow("In Command.send, expected Send or string, got object");
|
|
59
|
+
});
|
|
60
|
+
it("should handle Command with resume (single value)", () => {
|
|
61
|
+
const cmd = new Command({
|
|
62
|
+
resume: "resumeValue",
|
|
63
|
+
});
|
|
64
|
+
const pendingWrites = [];
|
|
65
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
66
|
+
expect(result).toEqual([
|
|
67
|
+
["00000000-0000-0000-0000-000000000000", "__resume__", "resumeValue"],
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
it("should handle Command with resume (object of task IDs)", () => {
|
|
71
|
+
// Using a valid UUID-like structure
|
|
72
|
+
const cmd = new Command({
|
|
73
|
+
resume: {
|
|
74
|
+
"123e4567-e89b-12d3-a456-426614174000": "resumeValue1",
|
|
75
|
+
"123e4567-e89b-12d3-a456-426614174001": "resumeValue2",
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
const pendingWrites = [];
|
|
79
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
80
|
+
expect(result).toEqual([
|
|
81
|
+
["123e4567-e89b-12d3-a456-426614174000", "__resume__", ["resumeValue1"]],
|
|
82
|
+
["123e4567-e89b-12d3-a456-426614174001", "__resume__", ["resumeValue2"]],
|
|
83
|
+
]);
|
|
84
|
+
});
|
|
85
|
+
it("should handle Command with update (object)", () => {
|
|
86
|
+
const cmd = new Command({
|
|
87
|
+
update: {
|
|
88
|
+
channel1: "value1",
|
|
89
|
+
channel2: "value2",
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
const pendingWrites = [];
|
|
93
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
94
|
+
expect(result).toEqual([
|
|
95
|
+
["00000000-0000-0000-0000-000000000000", "channel1", "value1"],
|
|
96
|
+
["00000000-0000-0000-0000-000000000000", "channel2", "value2"],
|
|
97
|
+
]);
|
|
98
|
+
});
|
|
99
|
+
it("should handle Command with update (array of tuples)", () => {
|
|
100
|
+
const cmd = new Command({
|
|
101
|
+
update: [
|
|
102
|
+
["channel1", "value1"],
|
|
103
|
+
["channel2", "value2"],
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
const pendingWrites = [];
|
|
107
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
108
|
+
expect(result).toEqual([
|
|
109
|
+
["00000000-0000-0000-0000-000000000000", "channel1", "value1"],
|
|
110
|
+
["00000000-0000-0000-0000-000000000000", "channel2", "value2"],
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
it("should throw error for invalid update type", () => {
|
|
114
|
+
const cmd = new Command({
|
|
115
|
+
// @ts-expect-error Testing invalid input
|
|
116
|
+
update: "invalidUpdateType",
|
|
117
|
+
});
|
|
118
|
+
const pendingWrites = [];
|
|
119
|
+
expect(() => Array.from(mapCommand(cmd, pendingWrites))).toThrow("Expected cmd.update to be a dict mapping channel names to update values");
|
|
120
|
+
});
|
|
121
|
+
it("should throw error for parent graph reference when none exists", () => {
|
|
122
|
+
const cmd = new Command({
|
|
123
|
+
graph: Command.PARENT,
|
|
124
|
+
goto: "nextNode",
|
|
125
|
+
});
|
|
126
|
+
const pendingWrites = [];
|
|
127
|
+
expect(() => Array.from(mapCommand(cmd, pendingWrites))).toThrow(InvalidUpdateError);
|
|
128
|
+
expect(() => Array.from(mapCommand(cmd, pendingWrites))).toThrow("There is no parent graph.");
|
|
129
|
+
});
|
|
130
|
+
it("should handle multiple command attributes together", () => {
|
|
131
|
+
const cmd = new Command({
|
|
132
|
+
goto: "nextNode",
|
|
133
|
+
resume: "resumeValue",
|
|
134
|
+
update: { channel1: "value1" },
|
|
135
|
+
});
|
|
136
|
+
const pendingWrites = [];
|
|
137
|
+
const result = Array.from(mapCommand(cmd, pendingWrites));
|
|
138
|
+
expect(result).toEqual([
|
|
139
|
+
[
|
|
140
|
+
"00000000-0000-0000-0000-000000000000",
|
|
141
|
+
"branch:__start__:__self__:nextNode",
|
|
142
|
+
"__start__",
|
|
143
|
+
],
|
|
144
|
+
["00000000-0000-0000-0000-000000000000", "__resume__", "resumeValue"],
|
|
145
|
+
["00000000-0000-0000-0000-000000000000", "channel1", "value1"],
|
|
146
|
+
]);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=io.mapCommand.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.mapCommand.test.js","sourceRoot":"","sources":["../../src/pregel/io.mapCommand.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const globals_1 = require("@jest/globals");
|
|
4
|
+
const messages_1 = require("@langchain/core/messages");
|
|
5
|
+
const outputs_1 = require("@langchain/core/outputs");
|
|
6
|
+
const messages_js_1 = require("./messages.cjs");
|
|
7
|
+
const constants_js_1 = require("../constants.cjs");
|
|
8
|
+
(0, globals_1.describe)("StreamMessagesHandler", () => {
|
|
9
|
+
(0, globals_1.describe)("constructor", () => {
|
|
10
|
+
(0, globals_1.it)("should properly initialize the handler", () => {
|
|
11
|
+
const streamFn = globals_1.jest.fn();
|
|
12
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
13
|
+
(0, globals_1.expect)(handler.name).toBe("StreamMessagesHandler");
|
|
14
|
+
(0, globals_1.expect)(handler.streamFn).toBe(streamFn);
|
|
15
|
+
(0, globals_1.expect)(handler.metadatas).toEqual({});
|
|
16
|
+
(0, globals_1.expect)(handler.seen).toEqual({});
|
|
17
|
+
(0, globals_1.expect)(handler.emittedChatModelRunIds).toEqual({});
|
|
18
|
+
(0, globals_1.expect)(handler.stableMessageIdMap).toEqual({});
|
|
19
|
+
(0, globals_1.expect)(handler.lc_prefer_streaming).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
(0, globals_1.describe)("_emit", () => {
|
|
23
|
+
(0, globals_1.it)("should emit a message with metadata", () => {
|
|
24
|
+
const streamFn = globals_1.jest.fn();
|
|
25
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
26
|
+
const meta = [
|
|
27
|
+
["ns1", "ns2"],
|
|
28
|
+
{ name: "test", tags: [] },
|
|
29
|
+
];
|
|
30
|
+
const message = new messages_1.AIMessage({ content: "Hello world" });
|
|
31
|
+
const runId = "run-123";
|
|
32
|
+
handler._emit(meta, message, runId);
|
|
33
|
+
(0, globals_1.expect)(streamFn).toHaveBeenCalledWith([
|
|
34
|
+
["ns1", "ns2"],
|
|
35
|
+
"messages",
|
|
36
|
+
[message, { name: "test", tags: [] }],
|
|
37
|
+
]);
|
|
38
|
+
// Should store the message in seen if it has an ID
|
|
39
|
+
message.id = "msg-123";
|
|
40
|
+
handler._emit(meta, message, runId);
|
|
41
|
+
(0, globals_1.expect)(handler.seen["msg-123"]).toBe(message);
|
|
42
|
+
});
|
|
43
|
+
(0, globals_1.it)("should deduplicate messages when dedupe=true and message has been seen", () => {
|
|
44
|
+
const streamFn = globals_1.jest.fn();
|
|
45
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
46
|
+
const meta = [
|
|
47
|
+
["ns1"],
|
|
48
|
+
{ name: "test" },
|
|
49
|
+
];
|
|
50
|
+
const message = new messages_1.AIMessage({ content: "Hello world", id: "msg-123" });
|
|
51
|
+
const runId = "run-123";
|
|
52
|
+
// First emit should work
|
|
53
|
+
handler._emit(meta, message, runId);
|
|
54
|
+
(0, globals_1.expect)(streamFn).toHaveBeenCalledTimes(1);
|
|
55
|
+
// Second emit with same ID and dedupe=true should be ignored
|
|
56
|
+
streamFn.mockClear();
|
|
57
|
+
handler._emit(meta, message, runId, true);
|
|
58
|
+
(0, globals_1.expect)(streamFn).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
(0, globals_1.it)("should assign proper ID to tool messages", () => {
|
|
61
|
+
const streamFn = globals_1.jest.fn();
|
|
62
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
63
|
+
const meta = [
|
|
64
|
+
["ns1"],
|
|
65
|
+
{ name: "test" },
|
|
66
|
+
];
|
|
67
|
+
const toolMessage = new messages_1.ToolMessage({
|
|
68
|
+
content: "Tool result",
|
|
69
|
+
tool_call_id: "tc-123",
|
|
70
|
+
});
|
|
71
|
+
const runId = "run-456";
|
|
72
|
+
handler._emit(meta, toolMessage, runId);
|
|
73
|
+
// Should assign an ID based on the tool call ID
|
|
74
|
+
(0, globals_1.expect)(toolMessage.id).toBe(`run-${runId}-tool-tc-123`);
|
|
75
|
+
(0, globals_1.expect)(streamFn).toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
(0, globals_1.it)("should maintain stable message IDs for the same run", () => {
|
|
78
|
+
const streamFn = globals_1.jest.fn();
|
|
79
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
80
|
+
const meta = [
|
|
81
|
+
["ns1"],
|
|
82
|
+
{ name: "test" },
|
|
83
|
+
];
|
|
84
|
+
const runId = "run-789";
|
|
85
|
+
// First message with auto-generated ID
|
|
86
|
+
const message1 = new messages_1.AIMessage({ content: "First chunk" });
|
|
87
|
+
handler._emit(meta, message1, runId);
|
|
88
|
+
const stableId = message1.id;
|
|
89
|
+
// Second message with no ID should get the same stable ID
|
|
90
|
+
const message2 = new messages_1.AIMessage({ content: "Second chunk" });
|
|
91
|
+
handler._emit(meta, message2, runId);
|
|
92
|
+
(0, globals_1.expect)(message2.id).toBe(stableId);
|
|
93
|
+
(0, globals_1.expect)(handler.stableMessageIdMap[runId]).toBe(stableId);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
(0, globals_1.describe)("handleChatModelStart", () => {
|
|
97
|
+
(0, globals_1.it)("should store metadata when provided", () => {
|
|
98
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
99
|
+
const runId = "run-123";
|
|
100
|
+
const metadata = {
|
|
101
|
+
langgraph_checkpoint_ns: "ns1|ns2",
|
|
102
|
+
other_meta: "value",
|
|
103
|
+
};
|
|
104
|
+
handler.handleChatModelStart({}, // llm
|
|
105
|
+
[], // messages
|
|
106
|
+
runId, undefined, // parentRunId
|
|
107
|
+
{}, // extraParams
|
|
108
|
+
[], // tags
|
|
109
|
+
metadata, // metadata
|
|
110
|
+
"ModelName" // name
|
|
111
|
+
);
|
|
112
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toEqual([
|
|
113
|
+
["ns1", "ns2"],
|
|
114
|
+
{ tags: [], name: "ModelName", ...metadata },
|
|
115
|
+
]);
|
|
116
|
+
});
|
|
117
|
+
(0, globals_1.it)("should not store metadata when TAG_NOSTREAM is present", () => {
|
|
118
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
119
|
+
const runId = "run-123";
|
|
120
|
+
const metadata = {
|
|
121
|
+
langgraph_checkpoint_ns: "ns1|ns2",
|
|
122
|
+
};
|
|
123
|
+
handler.handleChatModelStart({}, [], runId, undefined, {}, [constants_js_1.TAG_NOSTREAM], // nostream tag
|
|
124
|
+
metadata, "ModelName");
|
|
125
|
+
// Should not store metadata due to TAG_NOSTREAM
|
|
126
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
(0, globals_1.describe)("handleLLMNewToken", () => {
|
|
130
|
+
(0, globals_1.it)("should emit message chunk when metadata exists", () => {
|
|
131
|
+
const streamFn = globals_1.jest.fn();
|
|
132
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
133
|
+
const runId = "run-123";
|
|
134
|
+
handler.metadatas[runId] = [["ns1", "ns2"], { name: "test" }];
|
|
135
|
+
// Spy on _emit
|
|
136
|
+
const emitSpy = globals_1.jest.spyOn(handler, "_emit");
|
|
137
|
+
handler.handleLLMNewToken("token", { prompt: 0, completion: 0 }, // idx
|
|
138
|
+
runId);
|
|
139
|
+
// Should mark run as emitted
|
|
140
|
+
(0, globals_1.expect)(handler.emittedChatModelRunIds[runId]).toBe(true);
|
|
141
|
+
// Should emit AIMessageChunk when no chunk is provided
|
|
142
|
+
(0, globals_1.expect)(emitSpy).toHaveBeenCalledWith(handler.metadatas[runId], globals_1.expect.any(messages_1.AIMessageChunk), runId);
|
|
143
|
+
(0, globals_1.expect)(emitSpy.mock.calls[0][1].content).toBe("token");
|
|
144
|
+
});
|
|
145
|
+
(0, globals_1.it)("should emit provided chunk when available", () => {
|
|
146
|
+
const streamFn = globals_1.jest.fn();
|
|
147
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
148
|
+
const runId = "run-123";
|
|
149
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
150
|
+
// Spy on _emit
|
|
151
|
+
const emitSpy = globals_1.jest.spyOn(handler, "_emit");
|
|
152
|
+
// Create a chunk
|
|
153
|
+
const chunk = new outputs_1.ChatGenerationChunk({
|
|
154
|
+
message: new messages_1.AIMessageChunk({ content: "chunk content" }),
|
|
155
|
+
text: "chunk content", // Add text field to satisfy ChatGenerationChunkFields
|
|
156
|
+
});
|
|
157
|
+
handler.handleLLMNewToken("token", { prompt: 0, completion: 0 }, runId, undefined, undefined, { chunk } // provide the chunk
|
|
158
|
+
);
|
|
159
|
+
// Should emit the chunk's message
|
|
160
|
+
(0, globals_1.expect)(emitSpy).toHaveBeenCalledWith(handler.metadatas[runId], chunk.message, runId);
|
|
161
|
+
});
|
|
162
|
+
(0, globals_1.it)("should not emit when metadata is missing", () => {
|
|
163
|
+
const streamFn = globals_1.jest.fn();
|
|
164
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
165
|
+
const runId = "run-123";
|
|
166
|
+
// No metadata for this runId
|
|
167
|
+
// Spy on _emit
|
|
168
|
+
const emitSpy = globals_1.jest.spyOn(handler, "_emit");
|
|
169
|
+
handler.handleLLMNewToken("token", { prompt: 0, completion: 0 }, runId);
|
|
170
|
+
// Should mark run as emitted
|
|
171
|
+
(0, globals_1.expect)(handler.emittedChatModelRunIds[runId]).toBe(true);
|
|
172
|
+
// But should not call _emit
|
|
173
|
+
(0, globals_1.expect)(emitSpy).not.toHaveBeenCalled();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
(0, globals_1.describe)("handleLLMEnd", () => {
|
|
177
|
+
(0, globals_1.it)("should emit message from non-streaming run", () => {
|
|
178
|
+
const streamFn = globals_1.jest.fn();
|
|
179
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
180
|
+
const runId = "run-123";
|
|
181
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
182
|
+
// Not marked as emitted yet
|
|
183
|
+
// Mock _emit directly instead of spying
|
|
184
|
+
handler._emit = globals_1.jest.fn();
|
|
185
|
+
const message = new messages_1.AIMessage({ content: "final result" });
|
|
186
|
+
handler.handleLLMEnd({
|
|
187
|
+
generations: [[{ text: "test output", message }]],
|
|
188
|
+
}, runId);
|
|
189
|
+
// Should emit the message with dedupe=true
|
|
190
|
+
(0, globals_1.expect)(handler._emit).toHaveBeenCalledWith(globals_1.expect.anything(), globals_1.expect.objectContaining({ content: "final result" }), runId, true);
|
|
191
|
+
// Should clean up
|
|
192
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
193
|
+
});
|
|
194
|
+
(0, globals_1.it)("should not emit for streaming runs that already emitted", () => {
|
|
195
|
+
const streamFn = globals_1.jest.fn();
|
|
196
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
197
|
+
const runId = "run-123";
|
|
198
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
199
|
+
// Mark as already emitted
|
|
200
|
+
handler.emittedChatModelRunIds[runId] = true;
|
|
201
|
+
// Mock _emit directly
|
|
202
|
+
handler._emit = globals_1.jest.fn();
|
|
203
|
+
handler.handleLLMEnd({
|
|
204
|
+
generations: [
|
|
205
|
+
[
|
|
206
|
+
{
|
|
207
|
+
text: "test output",
|
|
208
|
+
message: new messages_1.AIMessage({ content: "result" }),
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
],
|
|
212
|
+
}, runId);
|
|
213
|
+
// Should not emit anything
|
|
214
|
+
(0, globals_1.expect)(handler._emit).not.toHaveBeenCalled();
|
|
215
|
+
// Should clean up metadata
|
|
216
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
(0, globals_1.describe)("handleLLMError", () => {
|
|
220
|
+
(0, globals_1.it)("should clean up metadata on error", () => {
|
|
221
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
222
|
+
const runId = "run-123";
|
|
223
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
224
|
+
handler.handleLLMError(new Error("Test error"), runId);
|
|
225
|
+
// Should clean up metadata
|
|
226
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
(0, globals_1.describe)("handleChainStart", () => {
|
|
230
|
+
(0, globals_1.it)("should store metadata for matching node name", () => {
|
|
231
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
232
|
+
const runId = "chain-123";
|
|
233
|
+
const metadata = {
|
|
234
|
+
langgraph_checkpoint_ns: "ns1|ns2",
|
|
235
|
+
langgraph_node: "NodeName", // Matches name parameter
|
|
236
|
+
};
|
|
237
|
+
handler.handleChainStart({}, {}, runId, undefined, [], metadata, undefined, "NodeName" // Name matches langgraph_node
|
|
238
|
+
);
|
|
239
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toEqual([
|
|
240
|
+
["ns1", "ns2"],
|
|
241
|
+
{ tags: [], name: "NodeName", ...metadata },
|
|
242
|
+
]);
|
|
243
|
+
});
|
|
244
|
+
(0, globals_1.it)("should not store metadata when node name doesn't match", () => {
|
|
245
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
246
|
+
const runId = "chain-123";
|
|
247
|
+
const metadata = {
|
|
248
|
+
langgraph_checkpoint_ns: "ns1|ns2",
|
|
249
|
+
langgraph_node: "NodeName", // Doesn't match name parameter
|
|
250
|
+
};
|
|
251
|
+
handler.handleChainStart({}, {}, runId, undefined, [], metadata, undefined, "DifferentName" // Different from langgraph_node
|
|
252
|
+
);
|
|
253
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
254
|
+
});
|
|
255
|
+
(0, globals_1.it)("should not store metadata when TAG_HIDDEN is present", () => {
|
|
256
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
257
|
+
const runId = "chain-123";
|
|
258
|
+
const metadata = {
|
|
259
|
+
langgraph_checkpoint_ns: "ns1|ns2",
|
|
260
|
+
langgraph_node: "NodeName",
|
|
261
|
+
};
|
|
262
|
+
handler.handleChainStart({}, {}, runId, undefined, [constants_js_1.TAG_HIDDEN], // Hidden tag
|
|
263
|
+
metadata, undefined, "NodeName");
|
|
264
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
(0, globals_1.describe)("handleChainEnd", () => {
|
|
268
|
+
(0, globals_1.it)("should emit a single message output", () => {
|
|
269
|
+
const streamFn = globals_1.jest.fn();
|
|
270
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
271
|
+
const runId = "chain-123";
|
|
272
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
273
|
+
// Mock _emit directly
|
|
274
|
+
handler._emit = globals_1.jest.fn();
|
|
275
|
+
const message = new messages_1.AIMessage({ content: "chain result" });
|
|
276
|
+
handler.handleChainEnd(message, runId);
|
|
277
|
+
// Should emit the message with dedupe=true
|
|
278
|
+
(0, globals_1.expect)(handler._emit).toHaveBeenCalledWith(globals_1.expect.anything(), globals_1.expect.objectContaining({ content: "chain result" }), runId, true);
|
|
279
|
+
// Should clean up
|
|
280
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
281
|
+
});
|
|
282
|
+
(0, globals_1.it)("should emit messages from an array output", () => {
|
|
283
|
+
const streamFn = globals_1.jest.fn();
|
|
284
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
285
|
+
const runId = "chain-123";
|
|
286
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
287
|
+
// Mock _emit directly
|
|
288
|
+
handler._emit = globals_1.jest.fn();
|
|
289
|
+
const message1 = new messages_1.AIMessage({ content: "result 1" });
|
|
290
|
+
const message2 = new messages_1.AIMessage({ content: "result 2" });
|
|
291
|
+
const notAMessage = "not a message";
|
|
292
|
+
handler.handleChainEnd([message1, message2, notAMessage], runId);
|
|
293
|
+
// Should emit both messages
|
|
294
|
+
(0, globals_1.expect)(handler._emit).toHaveBeenCalledTimes(2);
|
|
295
|
+
// Verify calls in a way that's less brittle
|
|
296
|
+
const callArgs = handler._emit.mock.calls;
|
|
297
|
+
const emittedContents = callArgs.map((args) => args[1].content);
|
|
298
|
+
(0, globals_1.expect)(emittedContents).toContain("result 1");
|
|
299
|
+
(0, globals_1.expect)(emittedContents).toContain("result 2");
|
|
300
|
+
// Should clean up
|
|
301
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
302
|
+
});
|
|
303
|
+
(0, globals_1.it)("should emit messages from object output properties", () => {
|
|
304
|
+
const streamFn = globals_1.jest.fn();
|
|
305
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
306
|
+
const runId = "chain-123";
|
|
307
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
308
|
+
// Mock _emit directly
|
|
309
|
+
handler._emit = globals_1.jest.fn();
|
|
310
|
+
const message = new messages_1.AIMessage({ content: "direct result" });
|
|
311
|
+
const arrayMessage = new messages_1.AIMessage({ content: "array result" });
|
|
312
|
+
handler.handleChainEnd({
|
|
313
|
+
directMessage: message,
|
|
314
|
+
arrayMessages: [arrayMessage, "not a message"],
|
|
315
|
+
otherProp: "something else",
|
|
316
|
+
}, runId);
|
|
317
|
+
// Should emit both messages
|
|
318
|
+
(0, globals_1.expect)(handler._emit).toHaveBeenCalledTimes(2);
|
|
319
|
+
// Verify calls in a way that's less brittle
|
|
320
|
+
const callArgs = handler._emit.mock.calls;
|
|
321
|
+
const emittedContents = callArgs.map((args) => args[1].content);
|
|
322
|
+
(0, globals_1.expect)(emittedContents).toContain("direct result");
|
|
323
|
+
(0, globals_1.expect)(emittedContents).toContain("array result");
|
|
324
|
+
// Should clean up
|
|
325
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
326
|
+
});
|
|
327
|
+
(0, globals_1.it)("should do nothing when metadata is missing", () => {
|
|
328
|
+
const streamFn = globals_1.jest.fn();
|
|
329
|
+
const handler = new messages_js_1.StreamMessagesHandler(streamFn);
|
|
330
|
+
const runId = "chain-123";
|
|
331
|
+
// No metadata for this runId
|
|
332
|
+
// Spy on _emit
|
|
333
|
+
const emitSpy = globals_1.jest.spyOn(handler, "_emit");
|
|
334
|
+
const message = new messages_1.AIMessage({ content: "result" });
|
|
335
|
+
handler.handleChainEnd(message, runId);
|
|
336
|
+
// Should not emit anything
|
|
337
|
+
(0, globals_1.expect)(emitSpy).not.toHaveBeenCalled();
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
(0, globals_1.describe)("handleChainError", () => {
|
|
341
|
+
(0, globals_1.it)("should clean up metadata on error", () => {
|
|
342
|
+
const handler = new messages_js_1.StreamMessagesHandler(globals_1.jest.fn());
|
|
343
|
+
const runId = "chain-123";
|
|
344
|
+
handler.metadatas[runId] = [["ns1"], { name: "test" }];
|
|
345
|
+
handler.handleChainError(new Error("Test error"), runId);
|
|
346
|
+
// Should clean up metadata
|
|
347
|
+
(0, globals_1.expect)(handler.metadatas[runId]).toBeUndefined();
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
//# sourceMappingURL=messages.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|