UNPKG

@langchain/langgraph

Version:

LangGraph

196 lines 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vitest_1 = require("vitest"); const messages_1 = require("@langchain/core/messages"); const message_js_1 = require("./message.cjs"); const constants_js_1 = require("../constants.cjs"); const state_js_1 = require("../graph/state.cjs"); const messages_annotation_js_1 = require("../graph/messages_annotation.cjs"); (0, vitest_1.describe)("messagesStateReducer", () => { (0, vitest_1.it)("should add a single message", () => { const left = [new messages_1.HumanMessage({ id: "1", content: "Hello" })]; const right = new messages_1.AIMessage({ id: "2", content: "Hi there!" }); const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [ new messages_1.HumanMessage({ id: "1", content: "Hello" }), new messages_1.AIMessage({ id: "2", content: "Hi there!" }), ]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should add multiple messages", () => { const left = [new messages_1.HumanMessage({ id: "1", content: "Hello" })]; const right = [ new messages_1.AIMessage({ id: "2", content: "Hi there!" }), new messages_1.SystemMessage({ id: "3", content: "System message" }), ]; const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [ new messages_1.HumanMessage({ id: "1", content: "Hello" }), new messages_1.AIMessage({ id: "2", content: "Hi there!" }), new messages_1.SystemMessage({ id: "3", content: "System message" }), ]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should update existing message", () => { const left = [new messages_1.HumanMessage({ id: "1", content: "Hello" })]; const right = new messages_1.HumanMessage({ id: "1", content: "Hello again" }); const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [new messages_1.HumanMessage({ id: "1", content: "Hello again" })]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should assign missing IDs", () => { const left = [new messages_1.HumanMessage({ content: "Hello" })]; const right = [new messages_1.AIMessage({ content: "Hi there!" })]; const result = (0, message_js_1.messagesStateReducer)(left, right); (0, vitest_1.expect)(result).toHaveLength(2); (0, vitest_1.expect)(result.every((m) => typeof m.id === "string" && m.id.length > 0)).toBe(true); }); (0, vitest_1.it)("should handle duplicates in input", () => { const left = []; const right = [ new messages_1.AIMessage({ id: "1", content: "Hi there!" }), new messages_1.AIMessage({ id: "1", content: "Hi there again!" }), ]; const result = (0, message_js_1.messagesStateReducer)(left, right); (0, vitest_1.expect)(result).toHaveLength(1); (0, vitest_1.expect)(result[0].id).toBe("1"); (0, vitest_1.expect)(result[0].content).toBe("Hi there again!"); }); (0, vitest_1.it)("should handle duplicates with remove", () => { const left = [new messages_1.AIMessage({ id: "1", content: "Hello!" })]; const right = [ new messages_1.RemoveMessage({ id: "1" }), new messages_1.AIMessage({ id: "1", content: "Hi there!" }), new messages_1.AIMessage({ id: "1", content: "Hi there again!" }), ]; const result = (0, message_js_1.messagesStateReducer)(left, right); (0, vitest_1.expect)(result).toHaveLength(1); (0, vitest_1.expect)(result[0].id).toBe("1"); (0, vitest_1.expect)(result[0].content).toBe("Hi there again!"); }); (0, vitest_1.it)("should remove message", () => { const left = [ new messages_1.HumanMessage({ id: "1", content: "Hello" }), new messages_1.AIMessage({ id: "2", content: "Hi there!" }), ]; const right = new messages_1.RemoveMessage({ id: "2" }); const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [new messages_1.HumanMessage({ id: "1", content: "Hello" })]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should handle duplicate remove messages", () => { const left = [ new messages_1.HumanMessage({ id: "1", content: "Hello" }), new messages_1.AIMessage({ id: "2", content: "Hi there!" }), ]; const right = [ new messages_1.RemoveMessage({ id: "2" }), new messages_1.RemoveMessage({ id: "2" }), ]; const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [new messages_1.HumanMessage({ id: "1", content: "Hello" })]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should throw on removing nonexistent message", () => { const left = [new messages_1.HumanMessage({ id: "1", content: "Hello" })]; const right = new messages_1.RemoveMessage({ id: "2" }); (0, vitest_1.expect)(() => (0, message_js_1.messagesStateReducer)(left, right)).toThrow("Attempting to delete a message with an ID that doesn't exist"); }); (0, vitest_1.it)("should handle mixed operations", () => { const left = [ new messages_1.HumanMessage({ id: "1", content: "Hello" }), new messages_1.AIMessage({ id: "2", content: "Hi there!" }), ]; const right = [ new messages_1.HumanMessage({ id: "1", content: "Updated hello" }), new messages_1.RemoveMessage({ id: "2" }), new messages_1.SystemMessage({ id: "3", content: "New message" }), ]; const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [ new messages_1.HumanMessage({ id: "1", content: "Updated hello" }), new messages_1.SystemMessage({ id: "3", content: "New message" }), ]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should handle empty inputs", () => { (0, vitest_1.expect)((0, message_js_1.messagesStateReducer)([], [])).toEqual([]); (0, vitest_1.expect)((0, message_js_1.messagesStateReducer)([], [new messages_1.HumanMessage({ id: "1", content: "Hello" })])).toEqual([new messages_1.HumanMessage({ id: "1", content: "Hello" })]); (0, vitest_1.expect)((0, message_js_1.messagesStateReducer)([new messages_1.HumanMessage({ id: "1", content: "Hello" })], [])).toEqual([new messages_1.HumanMessage({ id: "1", content: "Hello" })]); }); (0, vitest_1.it)("should handle non-array inputs", () => { const left = new messages_1.HumanMessage({ id: "1", content: "Hello" }); const right = new messages_1.AIMessage({ id: "2", content: "Hi there!" }); const result = (0, message_js_1.messagesStateReducer)(left, right); const expected = [ new messages_1.HumanMessage({ id: "1", content: "Hello" }), new messages_1.AIMessage({ id: "2", content: "Hi there!" }), ]; (0, vitest_1.expect)(result).toEqual(expected); }); (0, vitest_1.it)("should remove all messages", () => { // simple removal (0, vitest_1.expect)((0, message_js_1.messagesStateReducer)([new messages_1.HumanMessage("Hello"), new messages_1.AIMessage("Hi there!")], [new messages_1.RemoveMessage({ id: message_js_1.REMOVE_ALL_MESSAGES })])).toEqual([]); // removal and update (i.e. overwriting) (0, vitest_1.expect)((0, message_js_1.messagesStateReducer)([new messages_1.HumanMessage("Hello"), new messages_1.AIMessage("Hi there!")], [ new messages_1.RemoveMessage({ id: message_js_1.REMOVE_ALL_MESSAGES }), new messages_1.HumanMessage({ id: "1", content: "Updated hello" }), ])).toEqual([new messages_1.HumanMessage({ id: "1", content: "Updated hello" })]); // test removing preceding messages in the right list (0, vitest_1.expect)((0, message_js_1.messagesStateReducer)([new messages_1.HumanMessage("Hello"), new messages_1.AIMessage("Hi there!")], [ new messages_1.HumanMessage("Updated hello"), new messages_1.RemoveMessage({ id: message_js_1.REMOVE_ALL_MESSAGES }), new messages_1.HumanMessage({ id: "1", content: "Updated hi there" }), ])).toEqual([new messages_1.HumanMessage({ id: "1", content: "Updated hi there" })]); }); }); (0, vitest_1.describe)("pushMessage", () => { (0, vitest_1.it)("should throw on message without ID", () => { const message = new messages_1.AIMessage("No ID"); const config = { callbacks: [] }; (0, vitest_1.expect)(() => (0, message_js_1.pushMessage)(message, config)).toThrow("Message ID is required"); }); (0, vitest_1.it)("should handle message with ID", () => { const message = new messages_1.AIMessage({ id: "1", content: "With ID" }); const config = { callbacks: [] }; const result = (0, message_js_1.pushMessage)(message, config); (0, vitest_1.expect)(result).toEqual(message); }); (0, vitest_1.it)("should handle message with custom state key", () => { const message = new messages_1.AIMessage({ id: "1", content: "With ID" }); const config = { callbacks: [], configurable: { __pregel_send: (messages) => { (0, vitest_1.expect)(messages).toEqual([["custom", message]]); }, }, }; (0, message_js_1.pushMessage)(message, config, { stateKey: "custom" }); }); (0, vitest_1.it)("should push messages in graph", async () => { const graph = new state_js_1.StateGraph(messages_annotation_js_1.MessagesAnnotation) .addNode("chat", (state, config) => { (0, vitest_1.expect)(() => (0, message_js_1.pushMessage)(new messages_1.AIMessage("No ID"), config)).toThrow(); (0, message_js_1.pushMessage)(new messages_1.AIMessage({ id: "1", content: "First" }), config); (0, message_js_1.pushMessage)(new messages_1.HumanMessage({ id: "2", content: "Second" }), config); (0, message_js_1.pushMessage)(new messages_1.AIMessage({ id: "3", content: "Third" }), config); return state; }) .addEdge(constants_js_1.START, "chat") .compile(); const messages = []; let values; for await (const [event, chunk] of await graph.stream({ messages: [] }, { streamMode: ["messages", "values"] })) { if (event === "values") { values = chunk.messages; } else if (event === "messages") { const [message] = chunk; messages.push(message); } } (0, vitest_1.expect)(values).toEqual(messages); }); }); //# sourceMappingURL=message.test.js.map