@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.
Files changed (52) hide show
  1. package/README.md +14 -0
  2. package/dist/prebuilt/react_agent_executor.cjs +34 -13
  3. package/dist/prebuilt/react_agent_executor.d.ts +3 -0
  4. package/dist/prebuilt/react_agent_executor.js +34 -15
  5. package/dist/prebuilt/react_agent_executor.js.map +1 -1
  6. package/dist/prebuilt/tool_node.cjs +26 -4
  7. package/dist/prebuilt/tool_node.js +27 -5
  8. package/dist/prebuilt/tool_node.js.map +1 -1
  9. package/dist/pregel/debug.cjs +9 -7
  10. package/dist/pregel/debug.d.ts +10 -0
  11. package/dist/pregel/debug.js +2 -2
  12. package/dist/pregel/debug.js.map +1 -1
  13. package/dist/pregel/debug.test.cjs +189 -0
  14. package/dist/pregel/debug.test.d.ts +1 -0
  15. package/dist/pregel/debug.test.js +187 -0
  16. package/dist/pregel/debug.test.js.map +1 -0
  17. package/dist/pregel/io.mapCommand.test.cjs +151 -0
  18. package/dist/pregel/io.mapCommand.test.d.ts +1 -0
  19. package/dist/pregel/io.mapCommand.test.js +149 -0
  20. package/dist/pregel/io.mapCommand.test.js.map +1 -0
  21. package/dist/pregel/messages.test.cjs +351 -0
  22. package/dist/pregel/messages.test.d.ts +1 -0
  23. package/dist/pregel/messages.test.js +349 -0
  24. package/dist/pregel/messages.test.js.map +1 -0
  25. package/dist/pregel/read.cjs +1 -1
  26. package/dist/pregel/read.js +1 -1
  27. package/dist/pregel/read.js.map +1 -1
  28. package/dist/pregel/read.test.cjs +194 -0
  29. package/dist/pregel/read.test.d.ts +1 -0
  30. package/dist/pregel/read.test.js +192 -0
  31. package/dist/pregel/read.test.js.map +1 -0
  32. package/dist/pregel/runner.test.cjs +66 -0
  33. package/dist/pregel/runner.test.d.ts +1 -0
  34. package/dist/pregel/runner.test.js +64 -0
  35. package/dist/pregel/runner.test.js.map +1 -0
  36. package/dist/pregel/utils/config.test.cjs +214 -0
  37. package/dist/pregel/utils/config.test.d.ts +1 -0
  38. package/dist/pregel/utils/config.test.js +212 -0
  39. package/dist/pregel/utils/config.test.js.map +1 -0
  40. package/dist/pregel/utils/subgraph.test.cjs +83 -0
  41. package/dist/pregel/utils/subgraph.test.d.ts +1 -0
  42. package/dist/pregel/utils/subgraph.test.js +81 -0
  43. package/dist/pregel/utils/subgraph.test.js.map +1 -0
  44. package/dist/pregel/validate.test.cjs +220 -0
  45. package/dist/pregel/validate.test.d.ts +1 -0
  46. package/dist/pregel/validate.test.js +218 -0
  47. package/dist/pregel/validate.test.js.map +1 -0
  48. package/dist/pregel/write.test.cjs +181 -0
  49. package/dist/pregel/write.test.d.ts +1 -0
  50. package/dist/pregel/write.test.js +179 -0
  51. package/dist/pregel/write.test.js.map +1 -0
  52. 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 {};