@vegintech/langchain-react-agent 0.0.35 → 0.0.37
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.d.mts +1 -1
- package/dist/index.mjs +52 -8
- package/package.json +2 -1
package/dist/index.d.mts
CHANGED
|
@@ -154,7 +154,7 @@ interface ToolCallInput {
|
|
|
154
154
|
status?: "success" | "error";
|
|
155
155
|
}
|
|
156
156
|
/** 工具执行状态 */
|
|
157
|
-
type ToolExecutionStatus = "pending" | "running" | "success" | "error";
|
|
157
|
+
type ToolExecutionStatus = "pending" | "running" | "success" | "error" | "cancelled";
|
|
158
158
|
/** 工具执行结果 */
|
|
159
159
|
interface ToolExecutionRecord {
|
|
160
160
|
callId: string;
|
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo
|
|
|
2
2
|
import { Actions, Bubble, Sender, Think, ThoughtChain } from "@ant-design/x";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { Streamdown } from "streamdown";
|
|
5
|
+
import { code } from "@streamdown/code";
|
|
5
6
|
import { useStream } from "@langchain/langgraph-sdk/react";
|
|
6
7
|
//#region src/components/ChatInput.tsx
|
|
7
8
|
const slotConfig = [];
|
|
@@ -180,6 +181,7 @@ const ContentBlock = ({ block, index, components, securityConfig }) => {
|
|
|
180
181
|
},
|
|
181
182
|
allowedTags: securityConfig?.allowedTags,
|
|
182
183
|
literalTagContent: securityConfig?.literalTagContent,
|
|
184
|
+
plugins: { code },
|
|
183
185
|
controls: { table: {
|
|
184
186
|
copy: false,
|
|
185
187
|
download: false,
|
|
@@ -563,10 +565,16 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
563
565
|
const batchResultsRef = useRef(/* @__PURE__ */ new Map());
|
|
564
566
|
const isProcessingRef = useRef(false);
|
|
565
567
|
const batchSubmittedRef = useRef(false);
|
|
568
|
+
const cancelledCallIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
569
|
+
const cancelledExecutionsRef = useRef(/* @__PURE__ */ new Set());
|
|
566
570
|
useEffect(() => {
|
|
567
571
|
if (!completedToolResults || completedToolResults.size === 0) return;
|
|
568
572
|
completedToolResults.forEach(({ result, status }, callId) => {
|
|
569
573
|
if (notifiedCompletedRef.current.has(callId)) return;
|
|
574
|
+
if (cancelledExecutionsRef.current.has(callId)) {
|
|
575
|
+
notifiedCompletedRef.current.add(callId);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
570
578
|
if (executedCallsRef.current.has(callId)) {
|
|
571
579
|
notifiedCompletedRef.current.add(callId);
|
|
572
580
|
return;
|
|
@@ -630,7 +638,12 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
630
638
|
batchResultsRef.current.set(callId, createToolMessage(callId, call.name, null, "error", errorMessage));
|
|
631
639
|
} finally {
|
|
632
640
|
executingCallsRef.current.delete(callId);
|
|
633
|
-
|
|
641
|
+
if (cancelledCallIdsRef.current.has(callId)) {
|
|
642
|
+
cancelledCallIdsRef.current.delete(callId);
|
|
643
|
+
cancelledExecutionsRef.current.add(callId);
|
|
644
|
+
batchResultsRef.current.delete(callId);
|
|
645
|
+
batchCallIdsRef.current.delete(callId);
|
|
646
|
+
} else executedCallsRef.current.add(callId);
|
|
634
647
|
checkAndSubmitBatch();
|
|
635
648
|
}
|
|
636
649
|
}, [onExecutionChange, checkAndSubmitBatch]);
|
|
@@ -643,7 +656,7 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
643
656
|
const frontendCalls = [];
|
|
644
657
|
for (const call of toolCalls) {
|
|
645
658
|
const callId = call.id;
|
|
646
|
-
if (executedCallsRef.current.has(callId) || executingCallsRef.current.has(callId)) continue;
|
|
659
|
+
if (executedCallsRef.current.has(callId) || executingCallsRef.current.has(callId) || cancelledExecutionsRef.current.has(callId)) continue;
|
|
647
660
|
const tool = findTool(tools, call.name);
|
|
648
661
|
if (isLoading) {
|
|
649
662
|
if (!pendingNotifiedRef.current.has(callId)) {
|
|
@@ -695,11 +708,36 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
695
708
|
executeFrontendTool,
|
|
696
709
|
onExecutionChange
|
|
697
710
|
]);
|
|
711
|
+
/**
|
|
712
|
+
* 取消当前正在执行或待执行的前端工具
|
|
713
|
+
*
|
|
714
|
+
* 由于 JavaScript 无法真正中断异步执行,取消仅做标记:
|
|
715
|
+
* 1. 正在执行的工具完成后会被无视(不提交结果)
|
|
716
|
+
* 2. 尚未执行的工具被直接移除,不再执行
|
|
717
|
+
*/
|
|
718
|
+
const cancel = useCallback(() => {
|
|
719
|
+
const callIdsToCancel = new Set([...executingCallsRef.current, ...batchCallIdsRef.current]);
|
|
720
|
+
for (const callId of callIdsToCancel) {
|
|
721
|
+
cancelledCallIdsRef.current.add(callId);
|
|
722
|
+
if (!executingCallsRef.current.has(callId)) {
|
|
723
|
+
cancelledExecutionsRef.current.add(callId);
|
|
724
|
+
batchCallIdsRef.current.delete(callId);
|
|
725
|
+
}
|
|
726
|
+
const call = toolCalls.find((c) => c.id === callId);
|
|
727
|
+
if (call) onExecutionChange?.({
|
|
728
|
+
callId,
|
|
729
|
+
name: call.name,
|
|
730
|
+
args: call.args,
|
|
731
|
+
status: "cancelled"
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}, [toolCalls, onExecutionChange]);
|
|
698
735
|
useEffect(() => {
|
|
699
736
|
processToolCalls();
|
|
700
737
|
}, [useMemo(() => {
|
|
701
|
-
return toolCalls.filter((call) => !executedCallsRef.current.has(call.id) && !executingCallsRef.current.has(call.id)).map((call) => call.id).sort().join(",");
|
|
738
|
+
return toolCalls.filter((call) => !executedCallsRef.current.has(call.id) && !executingCallsRef.current.has(call.id) && !cancelledExecutionsRef.current.has(call.id)).map((call) => call.id).sort().join(",");
|
|
702
739
|
}, [toolCalls]), isLoading]);
|
|
740
|
+
return { cancel };
|
|
703
741
|
}
|
|
704
742
|
//#endregion
|
|
705
743
|
//#region src/utils/messageUtils.ts
|
|
@@ -951,7 +989,6 @@ const AgentChat = forwardRef(({ stream, className = "", tools, contexts, message
|
|
|
951
989
|
onSubmit: stream.submit
|
|
952
990
|
});
|
|
953
991
|
const [toolExecutions, setToolExecutions] = useState(/* @__PURE__ */ new Map());
|
|
954
|
-
const isLoading = stream.isLoading;
|
|
955
992
|
const { messages, toolResults } = useMemo(() => {
|
|
956
993
|
return processMessages(stream.messages);
|
|
957
994
|
}, [stream.messages]);
|
|
@@ -968,6 +1005,12 @@ const AgentChat = forwardRef(({ stream, className = "", tools, contexts, message
|
|
|
968
1005
|
const frontendTools = useMemo(() => {
|
|
969
1006
|
return tools?.filter(isFrontendTool) || [];
|
|
970
1007
|
}, [tools]);
|
|
1008
|
+
const frontendToolNames = useMemo(() => new Set(frontendTools.map((t) => t.name)), [frontendTools]);
|
|
1009
|
+
const hasToolExecuting = useMemo(() => {
|
|
1010
|
+
for (const record of toolExecutions.values()) if (frontendToolNames.has(record.name) && (record.status === "running" || record.status === "pending")) return true;
|
|
1011
|
+
return false;
|
|
1012
|
+
}, [toolExecutions, frontendToolNames]);
|
|
1013
|
+
const isLoading = stream.isLoading || hasToolExecuting;
|
|
971
1014
|
const submitToStream = useCallback(async (submitMessages) => {
|
|
972
1015
|
await stream.submit({
|
|
973
1016
|
...agentState,
|
|
@@ -1012,10 +1055,7 @@ const AgentChat = forwardRef(({ stream, className = "", tools, contexts, message
|
|
|
1012
1055
|
if (messages.length === 0) return;
|
|
1013
1056
|
await submitToStream(messages);
|
|
1014
1057
|
}, [onPreSend, submitToStream]);
|
|
1015
|
-
const
|
|
1016
|
-
await stream.stop();
|
|
1017
|
-
}, [stream]);
|
|
1018
|
-
useToolExecution({
|
|
1058
|
+
const { cancel: cancelToolExecution } = useToolExecution({
|
|
1019
1059
|
tools,
|
|
1020
1060
|
toolCalls: allToolCalls,
|
|
1021
1061
|
isLoading: stream.isLoading,
|
|
@@ -1023,6 +1063,10 @@ const AgentChat = forwardRef(({ stream, className = "", tools, contexts, message
|
|
|
1023
1063
|
onToolResultsBatch: handleToolResultsBatch,
|
|
1024
1064
|
completedToolResults: toolResults
|
|
1025
1065
|
});
|
|
1066
|
+
const handleStop = useCallback(async () => {
|
|
1067
|
+
cancelToolExecution();
|
|
1068
|
+
await stream.stop();
|
|
1069
|
+
}, [stream, cancelToolExecution]);
|
|
1026
1070
|
const shouldRenderWelcome = messages.length === 0 && !isLoading && welcome;
|
|
1027
1071
|
return /* @__PURE__ */ jsxs("div", {
|
|
1028
1072
|
className: `agent-chat-container ${className}`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vegintech/langchain-react-agent",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"description": "LangChain Agent UI component library for React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@ant-design/x": "^2.4.0",
|
|
27
27
|
"@langchain/langgraph-sdk": "^1.8.7",
|
|
28
|
+
"@streamdown/code": "catalog:",
|
|
28
29
|
"streamdown": "^2.5.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|