@assistant-ui/react-langgraph 0.0.10 → 0.0.11
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/index.js +20 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +15 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,8 +27,8 @@ __export(src_exports, {
|
|
|
27
27
|
module.exports = __toCommonJS(src_exports);
|
|
28
28
|
|
|
29
29
|
// src/useLangGraphRuntime.ts
|
|
30
|
-
var
|
|
31
|
-
var
|
|
30
|
+
var import_react3 = require("react");
|
|
31
|
+
var import_react4 = require("@assistant-ui/react");
|
|
32
32
|
|
|
33
33
|
// src/convertLangchainMessages.ts
|
|
34
34
|
var convertLangchainMessages = (message) => {
|
|
@@ -77,6 +77,8 @@ var convertLangchainMessages = (message) => {
|
|
|
77
77
|
|
|
78
78
|
// src/useLangGraphMessages.ts
|
|
79
79
|
var import_react = require("react");
|
|
80
|
+
var import_react2 = require("@assistant-ui/react");
|
|
81
|
+
var { generateId } = import_react2.INTERNAL;
|
|
80
82
|
var useLangGraphMessages = ({
|
|
81
83
|
stream
|
|
82
84
|
}) => {
|
|
@@ -92,28 +94,33 @@ var useLangGraphMessages = ({
|
|
|
92
94
|
let partialMessages = /* @__PURE__ */ new Map();
|
|
93
95
|
for await (const chunk of response) {
|
|
94
96
|
if (chunk.event === "messages/partial") {
|
|
97
|
+
if (completeMessages.length === 0) {
|
|
98
|
+
completeMessages.push(...optimisticMessages);
|
|
99
|
+
}
|
|
95
100
|
for (const message of chunk.data) {
|
|
96
101
|
if (!message.id) throw new Error("Partial message missing id");
|
|
97
102
|
partialMessages.set(message.id, message);
|
|
98
103
|
}
|
|
99
104
|
} else if (chunk.event === "messages/complete") {
|
|
100
105
|
for (const message of chunk.data) {
|
|
101
|
-
if (
|
|
102
|
-
|
|
106
|
+
if (message.id) {
|
|
107
|
+
partialMessages.delete(message.id);
|
|
108
|
+
}
|
|
109
|
+
if (partialMessages.size > 0) {
|
|
110
|
+
partialMessages.set(message.id ?? generateId(), message);
|
|
111
|
+
} else {
|
|
112
|
+
completeMessages.push(message);
|
|
113
|
+
}
|
|
103
114
|
}
|
|
104
|
-
completeMessages.push(...chunk.data);
|
|
105
115
|
} else {
|
|
106
116
|
continue;
|
|
107
117
|
}
|
|
108
|
-
|
|
109
|
-
setMessages([...prevMessages, ...partialMessages.values()]);
|
|
110
|
-
}
|
|
111
|
-
if (partialMessages.size > 0) {
|
|
112
|
-
throw new Error("A partial message was not marked as complete");
|
|
118
|
+
setMessages([...completeMessages, ...partialMessages.values()]);
|
|
113
119
|
}
|
|
114
120
|
},
|
|
115
121
|
[stream]
|
|
116
122
|
);
|
|
123
|
+
console.log("messages", messages);
|
|
117
124
|
return { messages, sendMessage, setMessages };
|
|
118
125
|
};
|
|
119
126
|
|
|
@@ -141,7 +148,7 @@ var useLangGraphRuntime = ({
|
|
|
141
148
|
const { messages, sendMessage, setMessages } = useLangGraphMessages({
|
|
142
149
|
stream
|
|
143
150
|
});
|
|
144
|
-
const [isRunning, setIsRunning] = (0,
|
|
151
|
+
const [isRunning, setIsRunning] = (0, import_react3.useState)(false);
|
|
145
152
|
const handleSendMessage = async (messages2) => {
|
|
146
153
|
try {
|
|
147
154
|
setIsRunning(true);
|
|
@@ -152,12 +159,12 @@ var useLangGraphRuntime = ({
|
|
|
152
159
|
setIsRunning(false);
|
|
153
160
|
}
|
|
154
161
|
};
|
|
155
|
-
const threadMessages = (0,
|
|
162
|
+
const threadMessages = (0, import_react4.useExternalMessageConverter)({
|
|
156
163
|
callback: convertLangchainMessages,
|
|
157
164
|
messages,
|
|
158
165
|
isRunning
|
|
159
166
|
});
|
|
160
|
-
return (0,
|
|
167
|
+
return (0, import_react4.useExternalStoreRuntime)({
|
|
161
168
|
threadId,
|
|
162
169
|
isRunning,
|
|
163
170
|
messages: threadMessages,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/useLangGraphRuntime.ts","../src/convertLangchainMessages.ts","../src/useLangGraphMessages.ts"],"sourcesContent":["export { useLangGraphRuntime } from \"./useLangGraphRuntime\";\n\nexport { useLangGraphMessages } from \"./useLangGraphMessages\";\nexport { convertLangchainMessages } from \"./convertLangchainMessages\";\nexport type {\n LangChainMessage,\n LangChainEvent,\n LangChainToolCall,\n LangChainToolCallChunk,\n} from \"./types\";\n","import { useState } from \"react\";\nimport { LangChainMessage, LangChainToolCall } from \"./types\";\nimport {\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangchainMessages } from \"./convertLangchainMessages\";\nimport { useLangGraphMessages } from \"./useLangGraphMessages\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nexport const useLangGraphRuntime = ({\n threadId,\n stream,\n onSwitchToNewThread,\n onSwitchToThread,\n}: {\n threadId?: string | undefined;\n stream: (messages: LangChainMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (\n threadId: string,\n ) => Promise<{ messages: LangChainMessage[] }>;\n}) => {\n const { messages, sendMessage, setMessages } = useLangGraphMessages({\n stream,\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (messages: LangChainMessage[]) => {\n try {\n setIsRunning(true);\n await sendMessage(messages);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangchainMessages,\n messages,\n isRunning,\n });\n\n return useExternalStoreRuntime({\n threadId,\n isRunning,\n messages: threadMessages,\n onNew: (msg) => {\n if (msg.content.length !== 1 || msg.content[0]?.type !== \"text\")\n throw new Error(\"Only text messages are supported\");\n\n const cancellations = getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n }) satisfies LangChainMessage & { type: \"tool\" },\n );\n return handleSendMessage([\n ...cancellations,\n {\n type: \"human\",\n content: msg.content[0].text,\n },\n ]);\n },\n onAddToolResult: async ({ toolCallId, toolName, result }) => {\n await handleSendMessage([\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n },\n ]);\n },\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n },\n onSwitchToThread: !onSwitchToThread\n ? undefined\n : async (threadId) => {\n const { messages } = await onSwitchToThread(threadId);\n setMessages(messages);\n },\n });\n};\n","\"use client\";\n\nimport { useExternalMessageConverter } from \"@assistant-ui/react\";\nimport { LangChainMessage } from \"./types\";\nimport { ToolCallContentPart } from \"@assistant-ui/react\";\n\nexport const convertLangchainMessages: useExternalMessageConverter.Callback<\n LangChainMessage\n> = (message) => {\n switch (message.type) {\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"human\":\n return {\n role: \"user\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"ai\":\n return {\n role: \"assistant\",\n id: message.id,\n content: [\n {\n type: \"text\",\n text: message.content,\n },\n ...(message.tool_calls?.map(\n (chunk): ToolCallContentPart => ({\n type: \"tool-call\",\n toolCallId: chunk.id,\n toolName: chunk.name,\n args: chunk.args,\n argsText:\n message.tool_call_chunks?.find((c) => c.id === chunk.id)\n ?.args ?? JSON.stringify(chunk.args),\n }),\n ) ?? []),\n ],\n };\n case \"tool\":\n return {\n role: \"tool\",\n toolName: message.name,\n toolCallId: message.tool_call_id,\n result: message.content,\n };\n }\n};\n","import { useState, useCallback } from \"react\";\n\nexport const useLangGraphMessages = <TMessage>({\n stream,\n}: {\n stream: (messages: TMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n}) => {\n const [messages, setMessages] = useState<TMessage[]>([]);\n\n const sendMessage = useCallback(\n async (newMessages: TMessage[]) => {\n const optimisticMessages = [...messages, ...newMessages];\n if (newMessages.length > 0) {\n setMessages(optimisticMessages);\n }\n\n const response = await stream(newMessages);\n\n const completeMessages: TMessage[] = [];\n let partialMessages: Map<string, TMessage> = new Map();\n for await (const chunk of response) {\n if (chunk.event === \"messages/partial\") {\n for (const message of chunk.data) {\n if (!message.id) throw new Error(\"Partial message missing id\");\n\n partialMessages.set(message.id, message);\n }\n } else if (chunk.event === \"messages/complete\") {\n for (const message of chunk.data) {\n if (!message.id) continue;\n partialMessages.delete(message.id);\n }\n\n completeMessages.push(...chunk.data);\n } else {\n continue;\n }\n\n const prevMessages = completeMessages.length\n ? completeMessages\n : optimisticMessages;\n\n setMessages([...prevMessages, ...partialMessages.values()]);\n }\n if (partialMessages.size > 0) {\n throw new Error(\"A partial message was not marked as complete\");\n }\n },\n [stream],\n );\n\n return { messages, sendMessage, setMessages };\n};\n"],"mappings":"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","names":["import_react","messages","threadId"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/useLangGraphRuntime.ts","../src/convertLangchainMessages.ts","../src/useLangGraphMessages.ts"],"sourcesContent":["export { useLangGraphRuntime } from \"./useLangGraphRuntime\";\n\nexport { useLangGraphMessages } from \"./useLangGraphMessages\";\nexport { convertLangchainMessages } from \"./convertLangchainMessages\";\nexport type {\n LangChainMessage,\n LangChainEvent,\n LangChainToolCall,\n LangChainToolCallChunk,\n} from \"./types\";\n","import { useState } from \"react\";\nimport { LangChainMessage, LangChainToolCall } from \"./types\";\nimport {\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangchainMessages } from \"./convertLangchainMessages\";\nimport { useLangGraphMessages } from \"./useLangGraphMessages\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nexport const useLangGraphRuntime = ({\n threadId,\n stream,\n onSwitchToNewThread,\n onSwitchToThread,\n}: {\n threadId?: string | undefined;\n stream: (messages: LangChainMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (\n threadId: string,\n ) => Promise<{ messages: LangChainMessage[] }>;\n}) => {\n const { messages, sendMessage, setMessages } = useLangGraphMessages({\n stream,\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (messages: LangChainMessage[]) => {\n try {\n setIsRunning(true);\n await sendMessage(messages);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangchainMessages,\n messages,\n isRunning,\n });\n\n return useExternalStoreRuntime({\n threadId,\n isRunning,\n messages: threadMessages,\n onNew: (msg) => {\n if (msg.content.length !== 1 || msg.content[0]?.type !== \"text\")\n throw new Error(\"Only text messages are supported\");\n\n const cancellations = getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n }) satisfies LangChainMessage & { type: \"tool\" },\n );\n return handleSendMessage([\n ...cancellations,\n {\n type: \"human\",\n content: msg.content[0].text,\n },\n ]);\n },\n onAddToolResult: async ({ toolCallId, toolName, result }) => {\n await handleSendMessage([\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n },\n ]);\n },\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n },\n onSwitchToThread: !onSwitchToThread\n ? undefined\n : async (threadId) => {\n const { messages } = await onSwitchToThread(threadId);\n setMessages(messages);\n },\n });\n};\n","\"use client\";\n\nimport { useExternalMessageConverter } from \"@assistant-ui/react\";\nimport { LangChainMessage } from \"./types\";\nimport { ToolCallContentPart } from \"@assistant-ui/react\";\n\nexport const convertLangchainMessages: useExternalMessageConverter.Callback<\n LangChainMessage\n> = (message) => {\n switch (message.type) {\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"human\":\n return {\n role: \"user\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"ai\":\n return {\n role: \"assistant\",\n id: message.id,\n content: [\n {\n type: \"text\",\n text: message.content,\n },\n ...(message.tool_calls?.map(\n (chunk): ToolCallContentPart => ({\n type: \"tool-call\",\n toolCallId: chunk.id,\n toolName: chunk.name,\n args: chunk.args,\n argsText:\n message.tool_call_chunks?.find((c) => c.id === chunk.id)\n ?.args ?? JSON.stringify(chunk.args),\n }),\n ) ?? []),\n ],\n };\n case \"tool\":\n return {\n role: \"tool\",\n toolName: message.name,\n toolCallId: message.tool_call_id,\n result: message.content,\n };\n }\n};\n","import { useState, useCallback } from \"react\";\nimport { INTERNAL } from \"@assistant-ui/react\";\n\nconst { generateId } = INTERNAL;\n\nexport const useLangGraphMessages = <TMessage>({\n stream,\n}: {\n stream: (messages: TMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n}) => {\n const [messages, setMessages] = useState<TMessage[]>([]);\n\n const sendMessage = useCallback(\n async (newMessages: TMessage[]) => {\n const optimisticMessages = [...messages, ...newMessages];\n if (newMessages.length > 0) {\n setMessages(optimisticMessages);\n }\n\n const response = await stream(newMessages);\n\n const completeMessages: TMessage[] = [];\n let partialMessages: Map<string, TMessage> = new Map();\n for await (const chunk of response) {\n if (chunk.event === \"messages/partial\") {\n // bug fix: messages/complete is not sent for some python langchain backends\n if (completeMessages.length === 0) {\n completeMessages.push(...optimisticMessages);\n }\n\n for (const message of chunk.data) {\n if (!message.id) throw new Error(\"Partial message missing id\");\n\n partialMessages.set(message.id, message);\n }\n } else if (chunk.event === \"messages/complete\") {\n for (const message of chunk.data) {\n if (message.id) {\n partialMessages.delete(message.id);\n }\n\n // bug fix: tool results can arrive before the message is complete ?\n // if we have partial messages left, we add complete message to partial messages\n if (partialMessages.size > 0) {\n partialMessages.set(message.id ?? generateId(), message);\n } else {\n completeMessages.push(message);\n }\n }\n } else {\n continue;\n }\n\n setMessages([...completeMessages, ...partialMessages.values()]);\n }\n // if (partialMessages.size > 0) {\n // throw new Error(\"A partial message was not marked as complete\");\n // }\n },\n [stream],\n );\n console.log(\"messages\", messages);\n return { messages, sendMessage, setMessages };\n};\n"],"mappings":"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","names":["import_react","import_react","messages","threadId"]}
|
package/dist/index.mjs
CHANGED
|
@@ -52,6 +52,8 @@ var convertLangchainMessages = (message) => {
|
|
|
52
52
|
|
|
53
53
|
// src/useLangGraphMessages.ts
|
|
54
54
|
import { useState, useCallback } from "react";
|
|
55
|
+
import { INTERNAL } from "@assistant-ui/react";
|
|
56
|
+
var { generateId } = INTERNAL;
|
|
55
57
|
var useLangGraphMessages = ({
|
|
56
58
|
stream
|
|
57
59
|
}) => {
|
|
@@ -67,28 +69,33 @@ var useLangGraphMessages = ({
|
|
|
67
69
|
let partialMessages = /* @__PURE__ */ new Map();
|
|
68
70
|
for await (const chunk of response) {
|
|
69
71
|
if (chunk.event === "messages/partial") {
|
|
72
|
+
if (completeMessages.length === 0) {
|
|
73
|
+
completeMessages.push(...optimisticMessages);
|
|
74
|
+
}
|
|
70
75
|
for (const message of chunk.data) {
|
|
71
76
|
if (!message.id) throw new Error("Partial message missing id");
|
|
72
77
|
partialMessages.set(message.id, message);
|
|
73
78
|
}
|
|
74
79
|
} else if (chunk.event === "messages/complete") {
|
|
75
80
|
for (const message of chunk.data) {
|
|
76
|
-
if (
|
|
77
|
-
|
|
81
|
+
if (message.id) {
|
|
82
|
+
partialMessages.delete(message.id);
|
|
83
|
+
}
|
|
84
|
+
if (partialMessages.size > 0) {
|
|
85
|
+
partialMessages.set(message.id ?? generateId(), message);
|
|
86
|
+
} else {
|
|
87
|
+
completeMessages.push(message);
|
|
88
|
+
}
|
|
78
89
|
}
|
|
79
|
-
completeMessages.push(...chunk.data);
|
|
80
90
|
} else {
|
|
81
91
|
continue;
|
|
82
92
|
}
|
|
83
|
-
|
|
84
|
-
setMessages([...prevMessages, ...partialMessages.values()]);
|
|
85
|
-
}
|
|
86
|
-
if (partialMessages.size > 0) {
|
|
87
|
-
throw new Error("A partial message was not marked as complete");
|
|
93
|
+
setMessages([...completeMessages, ...partialMessages.values()]);
|
|
88
94
|
}
|
|
89
95
|
},
|
|
90
96
|
[stream]
|
|
91
97
|
);
|
|
98
|
+
console.log("messages", messages);
|
|
92
99
|
return { messages, sendMessage, setMessages };
|
|
93
100
|
};
|
|
94
101
|
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useLangGraphRuntime.ts","../src/convertLangchainMessages.ts","../src/useLangGraphMessages.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { LangChainMessage, LangChainToolCall } from \"./types\";\nimport {\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangchainMessages } from \"./convertLangchainMessages\";\nimport { useLangGraphMessages } from \"./useLangGraphMessages\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nexport const useLangGraphRuntime = ({\n threadId,\n stream,\n onSwitchToNewThread,\n onSwitchToThread,\n}: {\n threadId?: string | undefined;\n stream: (messages: LangChainMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (\n threadId: string,\n ) => Promise<{ messages: LangChainMessage[] }>;\n}) => {\n const { messages, sendMessage, setMessages } = useLangGraphMessages({\n stream,\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (messages: LangChainMessage[]) => {\n try {\n setIsRunning(true);\n await sendMessage(messages);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangchainMessages,\n messages,\n isRunning,\n });\n\n return useExternalStoreRuntime({\n threadId,\n isRunning,\n messages: threadMessages,\n onNew: (msg) => {\n if (msg.content.length !== 1 || msg.content[0]?.type !== \"text\")\n throw new Error(\"Only text messages are supported\");\n\n const cancellations = getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n }) satisfies LangChainMessage & { type: \"tool\" },\n );\n return handleSendMessage([\n ...cancellations,\n {\n type: \"human\",\n content: msg.content[0].text,\n },\n ]);\n },\n onAddToolResult: async ({ toolCallId, toolName, result }) => {\n await handleSendMessage([\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n },\n ]);\n },\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n },\n onSwitchToThread: !onSwitchToThread\n ? undefined\n : async (threadId) => {\n const { messages } = await onSwitchToThread(threadId);\n setMessages(messages);\n },\n });\n};\n","\"use client\";\n\nimport { useExternalMessageConverter } from \"@assistant-ui/react\";\nimport { LangChainMessage } from \"./types\";\nimport { ToolCallContentPart } from \"@assistant-ui/react\";\n\nexport const convertLangchainMessages: useExternalMessageConverter.Callback<\n LangChainMessage\n> = (message) => {\n switch (message.type) {\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"human\":\n return {\n role: \"user\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"ai\":\n return {\n role: \"assistant\",\n id: message.id,\n content: [\n {\n type: \"text\",\n text: message.content,\n },\n ...(message.tool_calls?.map(\n (chunk): ToolCallContentPart => ({\n type: \"tool-call\",\n toolCallId: chunk.id,\n toolName: chunk.name,\n args: chunk.args,\n argsText:\n message.tool_call_chunks?.find((c) => c.id === chunk.id)\n ?.args ?? JSON.stringify(chunk.args),\n }),\n ) ?? []),\n ],\n };\n case \"tool\":\n return {\n role: \"tool\",\n toolName: message.name,\n toolCallId: message.tool_call_id,\n result: message.content,\n };\n }\n};\n","import { useState, useCallback } from \"react\";\n\nexport const useLangGraphMessages = <TMessage>({\n stream,\n}: {\n stream: (messages: TMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n}) => {\n const [messages, setMessages] = useState<TMessage[]>([]);\n\n const sendMessage = useCallback(\n async (newMessages: TMessage[]) => {\n const optimisticMessages = [...messages, ...newMessages];\n if (newMessages.length > 0) {\n setMessages(optimisticMessages);\n }\n\n const response = await stream(newMessages);\n\n const completeMessages: TMessage[] = [];\n let partialMessages: Map<string, TMessage> = new Map();\n for await (const chunk of response) {\n if (chunk.event === \"messages/partial\") {\n for (const message of chunk.data) {\n if (!message.id) throw new Error(\"Partial message missing id\");\n\n partialMessages.set(message.id, message);\n }\n } else if (chunk.event === \"messages/complete\") {\n for (const message of chunk.data) {\n if (!message.id) continue;\n partialMessages.delete(message.id);\n }\n\n completeMessages.push(...chunk.data);\n } else {\n continue;\n }\n\n const prevMessages = completeMessages.length\n ? completeMessages\n : optimisticMessages;\n\n setMessages([...prevMessages, ...partialMessages.values()]);\n }\n if (partialMessages.size > 0) {\n throw new Error(\"A partial message was not marked as complete\");\n }\n },\n [stream],\n );\n\n return { messages, sendMessage, setMessages };\n};\n"],"mappings":"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","names":["useState","useState","messages","threadId"]}
|
|
1
|
+
{"version":3,"sources":["../src/useLangGraphRuntime.ts","../src/convertLangchainMessages.ts","../src/useLangGraphMessages.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { LangChainMessage, LangChainToolCall } from \"./types\";\nimport {\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangchainMessages } from \"./convertLangchainMessages\";\nimport { useLangGraphMessages } from \"./useLangGraphMessages\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nexport const useLangGraphRuntime = ({\n threadId,\n stream,\n onSwitchToNewThread,\n onSwitchToThread,\n}: {\n threadId?: string | undefined;\n stream: (messages: LangChainMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (\n threadId: string,\n ) => Promise<{ messages: LangChainMessage[] }>;\n}) => {\n const { messages, sendMessage, setMessages } = useLangGraphMessages({\n stream,\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (messages: LangChainMessage[]) => {\n try {\n setIsRunning(true);\n await sendMessage(messages);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangchainMessages,\n messages,\n isRunning,\n });\n\n return useExternalStoreRuntime({\n threadId,\n isRunning,\n messages: threadMessages,\n onNew: (msg) => {\n if (msg.content.length !== 1 || msg.content[0]?.type !== \"text\")\n throw new Error(\"Only text messages are supported\");\n\n const cancellations = getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n }) satisfies LangChainMessage & { type: \"tool\" },\n );\n return handleSendMessage([\n ...cancellations,\n {\n type: \"human\",\n content: msg.content[0].text,\n },\n ]);\n },\n onAddToolResult: async ({ toolCallId, toolName, result }) => {\n await handleSendMessage([\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n },\n ]);\n },\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n },\n onSwitchToThread: !onSwitchToThread\n ? undefined\n : async (threadId) => {\n const { messages } = await onSwitchToThread(threadId);\n setMessages(messages);\n },\n });\n};\n","\"use client\";\n\nimport { useExternalMessageConverter } from \"@assistant-ui/react\";\nimport { LangChainMessage } from \"./types\";\nimport { ToolCallContentPart } from \"@assistant-ui/react\";\n\nexport const convertLangchainMessages: useExternalMessageConverter.Callback<\n LangChainMessage\n> = (message) => {\n switch (message.type) {\n case \"system\":\n return {\n role: \"system\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"human\":\n return {\n role: \"user\",\n id: message.id,\n content: [{ type: \"text\", text: message.content }],\n };\n case \"ai\":\n return {\n role: \"assistant\",\n id: message.id,\n content: [\n {\n type: \"text\",\n text: message.content,\n },\n ...(message.tool_calls?.map(\n (chunk): ToolCallContentPart => ({\n type: \"tool-call\",\n toolCallId: chunk.id,\n toolName: chunk.name,\n args: chunk.args,\n argsText:\n message.tool_call_chunks?.find((c) => c.id === chunk.id)\n ?.args ?? JSON.stringify(chunk.args),\n }),\n ) ?? []),\n ],\n };\n case \"tool\":\n return {\n role: \"tool\",\n toolName: message.name,\n toolCallId: message.tool_call_id,\n result: message.content,\n };\n }\n};\n","import { useState, useCallback } from \"react\";\nimport { INTERNAL } from \"@assistant-ui/react\";\n\nconst { generateId } = INTERNAL;\n\nexport const useLangGraphMessages = <TMessage>({\n stream,\n}: {\n stream: (messages: TMessage[]) => Promise<\n AsyncGenerator<{\n event: string;\n data: any;\n }>\n >;\n}) => {\n const [messages, setMessages] = useState<TMessage[]>([]);\n\n const sendMessage = useCallback(\n async (newMessages: TMessage[]) => {\n const optimisticMessages = [...messages, ...newMessages];\n if (newMessages.length > 0) {\n setMessages(optimisticMessages);\n }\n\n const response = await stream(newMessages);\n\n const completeMessages: TMessage[] = [];\n let partialMessages: Map<string, TMessage> = new Map();\n for await (const chunk of response) {\n if (chunk.event === \"messages/partial\") {\n // bug fix: messages/complete is not sent for some python langchain backends\n if (completeMessages.length === 0) {\n completeMessages.push(...optimisticMessages);\n }\n\n for (const message of chunk.data) {\n if (!message.id) throw new Error(\"Partial message missing id\");\n\n partialMessages.set(message.id, message);\n }\n } else if (chunk.event === \"messages/complete\") {\n for (const message of chunk.data) {\n if (message.id) {\n partialMessages.delete(message.id);\n }\n\n // bug fix: tool results can arrive before the message is complete ?\n // if we have partial messages left, we add complete message to partial messages\n if (partialMessages.size > 0) {\n partialMessages.set(message.id ?? generateId(), message);\n } else {\n completeMessages.push(message);\n }\n }\n } else {\n continue;\n }\n\n setMessages([...completeMessages, ...partialMessages.values()]);\n }\n // if (partialMessages.size > 0) {\n // throw new Error(\"A partial message was not marked as complete\");\n // }\n },\n [stream],\n );\n console.log(\"messages\", messages);\n return { messages, sendMessage, setMessages };\n};\n"],"mappings":";AAAA,SAAS,YAAAA,iBAAgB;AAEzB;AAAA,EACE;AAAA,EACA;AAAA,OACK;;;ACCA,IAAM,2BAET,CAAC,YAAY;AACf,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,QAAQ;AAAA,QACZ,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,QAAQ,CAAC;AAAA,MACnD;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,QAAQ;AAAA,QACZ,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,QAAQ,CAAC;AAAA,MACnD;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,QAAQ;AAAA,QACZ,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,QAAQ;AAAA,UAChB;AAAA,UACA,GAAI,QAAQ,YAAY;AAAA,YACtB,CAAC,WAAgC;AAAA,cAC/B,MAAM;AAAA,cACN,YAAY,MAAM;AAAA,cAClB,UAAU,MAAM;AAAA,cAChB,MAAM,MAAM;AAAA,cACZ,UACE,QAAQ,kBAAkB,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,GACnD,QAAQ,KAAK,UAAU,MAAM,IAAI;AAAA,YACzC;AAAA,UACF,KAAK,CAAC;AAAA,QACR;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU,QAAQ;AAAA,QAClB,YAAY,QAAQ;AAAA,QACpB,QAAQ,QAAQ;AAAA,MAClB;AAAA,EACJ;AACF;;;ACpDA,SAAS,UAAU,mBAAmB;AACtC,SAAS,gBAAgB;AAEzB,IAAM,EAAE,WAAW,IAAI;AAEhB,IAAM,uBAAuB,CAAW;AAAA,EAC7C;AACF,MAOM;AACJ,QAAM,CAAC,UAAU,WAAW,IAAI,SAAqB,CAAC,CAAC;AAEvD,QAAM,cAAc;AAAA,IAClB,OAAO,gBAA4B;AACjC,YAAM,qBAAqB,CAAC,GAAG,UAAU,GAAG,WAAW;AACvD,UAAI,YAAY,SAAS,GAAG;AAC1B,oBAAY,kBAAkB;AAAA,MAChC;AAEA,YAAM,WAAW,MAAM,OAAO,WAAW;AAEzC,YAAM,mBAA+B,CAAC;AACtC,UAAI,kBAAyC,oBAAI,IAAI;AACrD,uBAAiB,SAAS,UAAU;AAClC,YAAI,MAAM,UAAU,oBAAoB;AAEtC,cAAI,iBAAiB,WAAW,GAAG;AACjC,6BAAiB,KAAK,GAAG,kBAAkB;AAAA,UAC7C;AAEA,qBAAW,WAAW,MAAM,MAAM;AAChC,gBAAI,CAAC,QAAQ,GAAI,OAAM,IAAI,MAAM,4BAA4B;AAE7D,4BAAgB,IAAI,QAAQ,IAAI,OAAO;AAAA,UACzC;AAAA,QACF,WAAW,MAAM,UAAU,qBAAqB;AAC9C,qBAAW,WAAW,MAAM,MAAM;AAChC,gBAAI,QAAQ,IAAI;AACd,8BAAgB,OAAO,QAAQ,EAAE;AAAA,YACnC;AAIA,gBAAI,gBAAgB,OAAO,GAAG;AAC5B,8BAAgB,IAAI,QAAQ,MAAM,WAAW,GAAG,OAAO;AAAA,YACzD,OAAO;AACL,+BAAiB,KAAK,OAAO;AAAA,YAC/B;AAAA,UACF;AAAA,QACF,OAAO;AACL;AAAA,QACF;AAEA,oBAAY,CAAC,GAAG,kBAAkB,GAAG,gBAAgB,OAAO,CAAC,CAAC;AAAA,MAChE;AAAA,IAIF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AACA,UAAQ,IAAI,YAAY,QAAQ;AAChC,SAAO,EAAE,UAAU,aAAa,YAAY;AAC9C;;;AF3DA,IAAM,sBAAsB,CAAC,aAAiC;AAC5D,QAAM,mBAAmB,oBAAI,IAA+B;AAC5D,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,SAAS,MAAM;AACzB,iBAAW,YAAY,QAAQ,cAAc,CAAC,GAAG;AAC/C,yBAAiB,IAAI,SAAS,IAAI,QAAQ;AAAA,MAC5C;AAAA,IACF;AACA,QAAI,QAAQ,SAAS,QAAQ;AAC3B,uBAAiB,OAAO,QAAQ,YAAY;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,iBAAiB,OAAO,CAAC;AACtC;AAEO,IAAM,sBAAsB,CAAC;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAYM;AACJ,QAAM,EAAE,UAAU,aAAa,YAAY,IAAI,qBAAqB;AAAA,IAClE;AAAA,EACF,CAAC;AAED,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,oBAAoB,OAAOC,cAAiC;AAChE,QAAI;AACF,mBAAa,IAAI;AACjB,YAAM,YAAYA,SAAQ;AAAA,IAC5B,SAAS,OAAO;AACd,cAAQ,MAAM,6BAA6B,KAAK;AAAA,IAClD,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,iBAAiB,4BAA4B;AAAA,IACjD,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,wBAAwB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,CAAC,QAAQ;AACd,UAAI,IAAI,QAAQ,WAAW,KAAK,IAAI,QAAQ,CAAC,GAAG,SAAS;AACvD,cAAM,IAAI,MAAM,kCAAkC;AAEpD,YAAM,gBAAgB,oBAAoB,QAAQ,EAAE;AAAA,QAClD,CAAC,OACE;AAAA,UACC,MAAM;AAAA,UACN,MAAM,EAAE;AAAA,UACR,cAAc,EAAE;AAAA,UAChB,SAAS,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,QAC7C;AAAA,MACJ;AACA,aAAO,kBAAkB;AAAA,QACvB,GAAG;AAAA,QACH;AAAA,UACE,MAAM;AAAA,UACN,SAAS,IAAI,QAAQ,CAAC,EAAE;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,iBAAiB,OAAO,EAAE,YAAY,UAAU,OAAO,MAAM;AAC3D,YAAM,kBAAkB;AAAA,QACtB;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,cAAc;AAAA,UACd,SAAS,KAAK,UAAU,MAAM;AAAA,QAChC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,qBAAqB,CAAC,sBAClB,SACA,YAAY;AACV,YAAM,oBAAoB;AAC1B,kBAAY,CAAC,CAAC;AAAA,IAChB;AAAA,IACJ,kBAAkB,CAAC,mBACf,SACA,OAAOC,cAAa;AAClB,YAAM,EAAE,UAAAD,UAAS,IAAI,MAAM,iBAAiBC,SAAQ;AACpD,kBAAYD,SAAQ;AAAA,IACtB;AAAA,EACN,CAAC;AACH;","names":["useState","useState","messages","threadId"]}
|