@vegintech/langchain-react-agent 0.0.8 → 0.0.9
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 +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +108 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ const searchTool: BackendTool = {
|
|
|
137
137
|
render: (props) => (
|
|
138
138
|
<div className="tool-search">
|
|
139
139
|
{props.status === "pending" && "等待执行..."}
|
|
140
|
-
{props.status === "running" && `搜索: ${props.
|
|
140
|
+
{props.status === "running" && `搜索: ${props.args.query}`}
|
|
141
141
|
{props.status === "success" && `找到 ${props.result?.count || 0} 条结果`}
|
|
142
142
|
</div>
|
|
143
143
|
),
|
package/dist/index.d.mts
CHANGED
|
@@ -150,7 +150,7 @@ interface ChatMessage {
|
|
|
150
150
|
interface ToolCallInput {
|
|
151
151
|
id: string;
|
|
152
152
|
name: string;
|
|
153
|
-
|
|
153
|
+
args: Record<string, unknown>;
|
|
154
154
|
/** 后端工具执行结果(来自 ToolMessage) */
|
|
155
155
|
result?: unknown;
|
|
156
156
|
}
|
|
@@ -160,7 +160,7 @@ type ToolExecutionStatus = "pending" | "running" | "success" | "error";
|
|
|
160
160
|
interface ToolExecutionRecord {
|
|
161
161
|
callId: string;
|
|
162
162
|
name: string;
|
|
163
|
-
|
|
163
|
+
args: Record<string, unknown>;
|
|
164
164
|
status: ToolExecutionStatus;
|
|
165
165
|
result?: unknown;
|
|
166
166
|
error?: string;
|
|
@@ -168,7 +168,7 @@ interface ToolExecutionRecord {
|
|
|
168
168
|
/** 渲染函数的 props */
|
|
169
169
|
interface ToolRenderProps<TArgs = Record<string, unknown>> {
|
|
170
170
|
name: string;
|
|
171
|
-
|
|
171
|
+
args: TArgs;
|
|
172
172
|
result?: unknown;
|
|
173
173
|
status: ToolExecutionStatus;
|
|
174
174
|
error?: string;
|
package/dist/index.mjs
CHANGED
|
@@ -65,7 +65,7 @@ const ToolCallRenderer = ({ tool, record }) => {
|
|
|
65
65
|
className: "tool-call-wrapper",
|
|
66
66
|
children: tool.render({
|
|
67
67
|
name: record.name,
|
|
68
|
-
|
|
68
|
+
args: record.args,
|
|
69
69
|
result: record.result,
|
|
70
70
|
status: record.status,
|
|
71
71
|
error: record.error
|
|
@@ -262,16 +262,20 @@ const renderToolCalls = (toolCalls, tools, toolExecutions) => {
|
|
|
262
262
|
return toolCalls.map((call) => {
|
|
263
263
|
const tool = findTool(tools, call.name);
|
|
264
264
|
let record;
|
|
265
|
-
if (tool && isFrontendTool(tool))
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
265
|
+
if (tool && isFrontendTool(tool)) {
|
|
266
|
+
const execution = toolExecutions.get(call.id);
|
|
267
|
+
record = {
|
|
268
|
+
callId: call.id,
|
|
269
|
+
name: call.name,
|
|
270
|
+
args: call.args,
|
|
271
|
+
status: execution?.status || "pending",
|
|
272
|
+
result: execution?.result,
|
|
273
|
+
error: execution?.error
|
|
274
|
+
};
|
|
275
|
+
} else record = {
|
|
272
276
|
callId: call.id,
|
|
273
277
|
name: call.name,
|
|
274
|
-
|
|
278
|
+
args: call.args,
|
|
275
279
|
status: call.result !== void 0 ? "success" : "pending",
|
|
276
280
|
result: call.result
|
|
277
281
|
};
|
|
@@ -426,12 +430,17 @@ function useInterrupt({ interrupt, config, onSubmit }) {
|
|
|
426
430
|
* 1. 管理工具执行状态
|
|
427
431
|
* 2. 自动执行前端工具(避免重复执行)
|
|
428
432
|
* 3. 通知外部执行状态变化
|
|
433
|
+
* 4. 支持批量提交工具结果
|
|
429
434
|
*/
|
|
430
|
-
function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChange,
|
|
435
|
+
function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChange, onToolResultsBatch, completedToolResults }) {
|
|
431
436
|
const executedCallsRef = useRef(/* @__PURE__ */ new Set());
|
|
432
437
|
const executingCallsRef = useRef(/* @__PURE__ */ new Set());
|
|
433
438
|
const pendingNotifiedRef = useRef(/* @__PURE__ */ new Set());
|
|
434
439
|
const initializedRef = useRef(false);
|
|
440
|
+
const batchCallIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
441
|
+
const batchResultsRef = useRef(/* @__PURE__ */ new Map());
|
|
442
|
+
const isProcessingRef = useRef(false);
|
|
443
|
+
const batchSubmittedRef = useRef(false);
|
|
435
444
|
useEffect(() => {
|
|
436
445
|
if (initializedRef.current || !completedToolResults || completedToolResults.size === 0) return;
|
|
437
446
|
initializedRef.current = true;
|
|
@@ -441,13 +450,26 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
441
450
|
if (call) onExecutionChange?.({
|
|
442
451
|
callId,
|
|
443
452
|
name: call.name,
|
|
444
|
-
|
|
453
|
+
args: call.args,
|
|
445
454
|
status: "success",
|
|
446
455
|
result
|
|
447
456
|
});
|
|
448
457
|
});
|
|
449
458
|
}, [completedToolResults]);
|
|
450
459
|
/**
|
|
460
|
+
* 检查批次是否完成并提交结果
|
|
461
|
+
*/
|
|
462
|
+
const checkAndSubmitBatch = useCallback(() => {
|
|
463
|
+
if (batchSubmittedRef.current) return;
|
|
464
|
+
if (Array.from(batchCallIdsRef.current).every((callId) => executedCallsRef.current.has(callId)) && batchCallIdsRef.current.size > 0) {
|
|
465
|
+
batchSubmittedRef.current = true;
|
|
466
|
+
const results = Array.from(batchResultsRef.current.values());
|
|
467
|
+
if (results.length > 0) onToolResultsBatch?.(results);
|
|
468
|
+
batchCallIdsRef.current.clear();
|
|
469
|
+
batchResultsRef.current.clear();
|
|
470
|
+
}
|
|
471
|
+
}, [onToolResultsBatch]);
|
|
472
|
+
/**
|
|
451
473
|
* 执行单个前端工具
|
|
452
474
|
*/
|
|
453
475
|
const executeFrontendTool = useCallback(async (tool, call) => {
|
|
@@ -456,38 +478,50 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
456
478
|
onExecutionChange?.({
|
|
457
479
|
callId,
|
|
458
480
|
name: call.name,
|
|
459
|
-
|
|
481
|
+
args: call.args,
|
|
460
482
|
status: "running"
|
|
461
483
|
});
|
|
462
484
|
try {
|
|
463
|
-
const result = await tool.execute(call.
|
|
485
|
+
const result = await tool.execute(call.args);
|
|
464
486
|
onExecutionChange?.({
|
|
465
487
|
callId,
|
|
466
488
|
name: call.name,
|
|
467
|
-
|
|
489
|
+
args: call.args,
|
|
468
490
|
status: "success",
|
|
469
491
|
result
|
|
470
492
|
});
|
|
471
|
-
|
|
493
|
+
batchResultsRef.current.set(callId, {
|
|
494
|
+
callId,
|
|
495
|
+
name: call.name,
|
|
496
|
+
result
|
|
497
|
+
});
|
|
472
498
|
} catch (error) {
|
|
473
499
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
474
500
|
onExecutionChange?.({
|
|
475
501
|
callId,
|
|
476
502
|
name: call.name,
|
|
477
|
-
|
|
503
|
+
args: call.args,
|
|
478
504
|
status: "error",
|
|
479
505
|
error: errorMessage
|
|
480
506
|
});
|
|
507
|
+
batchResultsRef.current.set(callId, {
|
|
508
|
+
callId,
|
|
509
|
+
name: call.name,
|
|
510
|
+
result: { error: errorMessage }
|
|
511
|
+
});
|
|
481
512
|
} finally {
|
|
482
513
|
executingCallsRef.current.delete(callId);
|
|
483
514
|
executedCallsRef.current.add(callId);
|
|
515
|
+
checkAndSubmitBatch();
|
|
484
516
|
}
|
|
485
|
-
}, [onExecutionChange,
|
|
517
|
+
}, [onExecutionChange, checkAndSubmitBatch]);
|
|
486
518
|
/**
|
|
487
519
|
* 处理工具调用
|
|
488
520
|
*/
|
|
489
521
|
const processToolCalls = useCallback(async () => {
|
|
490
522
|
if (!tools) return;
|
|
523
|
+
if (isProcessingRef.current) return;
|
|
524
|
+
const frontendCalls = [];
|
|
491
525
|
for (const call of toolCalls) {
|
|
492
526
|
const callId = call.id;
|
|
493
527
|
if (executedCallsRef.current.has(callId) || executingCallsRef.current.has(callId)) continue;
|
|
@@ -498,7 +532,7 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
498
532
|
onExecutionChange?.({
|
|
499
533
|
callId,
|
|
500
534
|
name: call.name,
|
|
501
|
-
|
|
535
|
+
args: call.args,
|
|
502
536
|
status: "pending"
|
|
503
537
|
});
|
|
504
538
|
}
|
|
@@ -508,19 +542,33 @@ function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChan
|
|
|
508
542
|
onExecutionChange?.({
|
|
509
543
|
callId,
|
|
510
544
|
name: call.name,
|
|
511
|
-
|
|
545
|
+
args: call.args,
|
|
512
546
|
status: "pending"
|
|
513
547
|
});
|
|
514
548
|
continue;
|
|
515
549
|
}
|
|
516
|
-
if (isFrontendTool(tool))
|
|
550
|
+
if (isFrontendTool(tool)) frontendCalls.push({
|
|
551
|
+
tool,
|
|
552
|
+
call
|
|
553
|
+
});
|
|
517
554
|
else onExecutionChange?.({
|
|
518
555
|
callId,
|
|
519
556
|
name: call.name,
|
|
520
|
-
|
|
557
|
+
args: call.args,
|
|
521
558
|
status: "pending"
|
|
522
559
|
});
|
|
523
560
|
}
|
|
561
|
+
if (frontendCalls.length > 0) {
|
|
562
|
+
batchSubmittedRef.current = false;
|
|
563
|
+
isProcessingRef.current = true;
|
|
564
|
+
batchCallIdsRef.current = new Set(frontendCalls.map(({ call }) => call.id));
|
|
565
|
+
batchResultsRef.current = /* @__PURE__ */ new Map();
|
|
566
|
+
try {
|
|
567
|
+
await Promise.all(frontendCalls.map(({ tool, call }) => executeFrontendTool(tool, call)));
|
|
568
|
+
} finally {
|
|
569
|
+
isProcessingRef.current = false;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
524
572
|
}, [
|
|
525
573
|
tools,
|
|
526
574
|
toolCalls,
|
|
@@ -543,7 +591,7 @@ function extractToolCalls(message) {
|
|
|
543
591
|
if ("tool_calls" in message && Array.isArray(message.tool_calls)) return message.tool_calls.map((tc) => ({
|
|
544
592
|
id: tc.id || crypto.randomUUID(),
|
|
545
593
|
name: tc.name || tc.function?.name || "",
|
|
546
|
-
|
|
594
|
+
args: typeof tc.function?.args === "string" ? JSON.parse(tc.function.args) : tc.args || {}
|
|
547
595
|
}));
|
|
548
596
|
}
|
|
549
597
|
/**
|
|
@@ -632,10 +680,33 @@ const styles = `
|
|
|
632
680
|
justify-content: center;
|
|
633
681
|
}
|
|
634
682
|
|
|
683
|
+
|
|
684
|
+
|
|
635
685
|
.agent-message-list .ant-think-status-text {
|
|
636
686
|
font-size: 13px;
|
|
637
687
|
}
|
|
638
688
|
|
|
689
|
+
.agent-message-list table {
|
|
690
|
+
border-collapse: collapse;
|
|
691
|
+
width: 100%;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.agent-message-list th,
|
|
695
|
+
.agent-message-list td {
|
|
696
|
+
border: 1px solid rgba(128, 128, 128, 0.3);
|
|
697
|
+
padding: 8px 12px;
|
|
698
|
+
text-align: left;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.agent-message-list th {
|
|
702
|
+
background-color: rgba(128, 128, 128, 0.12);
|
|
703
|
+
font-weight: 500;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.agent-message-list tr:nth-child(even) {
|
|
707
|
+
background-color: rgba(128, 128, 128, 0.06);
|
|
708
|
+
}
|
|
709
|
+
|
|
639
710
|
.agent-message-empty {
|
|
640
711
|
color: #8b8d91;
|
|
641
712
|
font-size: 14px;
|
|
@@ -774,7 +845,9 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
774
845
|
context: contexts
|
|
775
846
|
}
|
|
776
847
|
}, {
|
|
848
|
+
streamSubgraphs: true,
|
|
777
849
|
streamResumable: true,
|
|
850
|
+
config: { recursion_limit: 1e3 },
|
|
778
851
|
optimisticValues(prev) {
|
|
779
852
|
const newMessages = [...prev.messages ?? [], ...submitMessages];
|
|
780
853
|
return {
|
|
@@ -789,13 +862,18 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
789
862
|
contexts,
|
|
790
863
|
agentState
|
|
791
864
|
]);
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
865
|
+
const handleToolResultsBatch = useCallback((results) => {
|
|
866
|
+
const toolMessages = results.map(({ callId, name, result }) => {
|
|
867
|
+
return {
|
|
868
|
+
type: "tool",
|
|
869
|
+
content: typeof result === "string" ? result : JSON.stringify(result),
|
|
870
|
+
tool_call_id: callId,
|
|
871
|
+
name
|
|
872
|
+
};
|
|
873
|
+
});
|
|
874
|
+
setTimeout(() => {
|
|
875
|
+
submitToStream(toolMessages);
|
|
876
|
+
}, 100);
|
|
799
877
|
}, [submitToStream]);
|
|
800
878
|
const handleSend = useCallback(async (params) => {
|
|
801
879
|
let messages = [];
|
|
@@ -818,7 +896,7 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
818
896
|
toolCalls: allToolCalls,
|
|
819
897
|
isLoading: stream.isLoading,
|
|
820
898
|
onExecutionChange: handleExecutionChange,
|
|
821
|
-
|
|
899
|
+
onToolResultsBatch: handleToolResultsBatch,
|
|
822
900
|
completedToolResults: toolResults
|
|
823
901
|
});
|
|
824
902
|
return /* @__PURE__ */ jsxs("div", {
|