@vegintech/langchain-react-agent 0.0.4 → 0.0.6
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 +70 -21
- package/dist/index.mjs +369 -311
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,58 @@
|
|
|
1
1
|
import * as react from "react";
|
|
2
|
-
import
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
3
|
import { Components } from "streamdown";
|
|
4
4
|
import { BaseNode, InsertPosition, NodeRender, SenderProps, SkillType, SlotConfigType } from "@ant-design/x/es/sender/interface.ts";
|
|
5
5
|
|
|
6
6
|
//#region src/types.d.ts
|
|
7
|
+
/** ToolCard 组件 Props */
|
|
8
|
+
interface ToolCardProps {
|
|
9
|
+
/**
|
|
10
|
+
* 前缀文本(中文,使用小字体)
|
|
11
|
+
*/
|
|
12
|
+
prefix: string;
|
|
13
|
+
/**
|
|
14
|
+
* 正文内容(英文/文件名,保持默认大小)
|
|
15
|
+
*/
|
|
16
|
+
content?: string;
|
|
17
|
+
/**
|
|
18
|
+
* 左侧图标
|
|
19
|
+
*/
|
|
20
|
+
icon: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/** Interrupt 事件数据结构 */
|
|
23
|
+
interface InterruptEvent {
|
|
24
|
+
/** Interrupt 的值,可以是任意类型(由 LangChain 后端决定) */
|
|
25
|
+
value: unknown;
|
|
26
|
+
/** Interrupt 的唯一标识 */
|
|
27
|
+
id: string;
|
|
28
|
+
}
|
|
29
|
+
/** Interrupt 渲染函数的参数 */
|
|
30
|
+
interface InterruptRenderProps {
|
|
31
|
+
/** Interrupt 事件数据 */
|
|
32
|
+
event: InterruptEvent;
|
|
33
|
+
/** 解决 Interrupt 的回调函数,传入响应值 */
|
|
34
|
+
resolve: (response: unknown) => void;
|
|
35
|
+
}
|
|
36
|
+
/** Interrupt 处理配置 */
|
|
37
|
+
interface InterruptConfig {
|
|
38
|
+
/** 自定义 Interrupt 渲染函数 */
|
|
39
|
+
render: (props: InterruptRenderProps) => ReactNode;
|
|
40
|
+
}
|
|
41
|
+
/** InterruptManager Hook 的 Props */
|
|
42
|
+
interface InterruptManagerProps {
|
|
43
|
+
/** 当前 interrupt 事件 */
|
|
44
|
+
interrupt: InterruptEvent | null;
|
|
45
|
+
/** Interrupt 处理配置 */
|
|
46
|
+
config?: InterruptConfig;
|
|
47
|
+
/** 提交回调 */
|
|
48
|
+
onSubmit: (values: {
|
|
49
|
+
[x: string]: unknown;
|
|
50
|
+
} | null | undefined, options?: {
|
|
51
|
+
command?: {
|
|
52
|
+
resume: unknown;
|
|
53
|
+
};
|
|
54
|
+
}) => Promise<void> | void;
|
|
55
|
+
}
|
|
7
56
|
/** Context Item,用于传递上下文信息 */
|
|
8
57
|
interface ContextItem {
|
|
9
58
|
/** 描述信息 */
|
|
@@ -19,15 +68,13 @@ interface SenderSubmitParams {
|
|
|
19
68
|
slotConfig?: SenderSlotConfig;
|
|
20
69
|
skillData?: SkillType;
|
|
21
70
|
}
|
|
22
|
-
/** onPreSend
|
|
71
|
+
/** onPreSend 钩子返回值:只返回消息数组 */
|
|
23
72
|
interface PreSendResult {
|
|
24
73
|
/** 要发送的消息数组 */
|
|
25
74
|
messages: Array<{
|
|
26
75
|
type: string;
|
|
27
76
|
content: string;
|
|
28
77
|
}>;
|
|
29
|
-
/** 其他任意字段会作为额外参数一起 submit */
|
|
30
|
-
[x: string]: unknown;
|
|
31
78
|
}
|
|
32
79
|
/** Sender 组件的可定制参数 */
|
|
33
80
|
interface SenderCustomizationProps {
|
|
@@ -131,6 +178,15 @@ interface BackendTool<TArgs = Record<string, unknown>> extends ToolBase<TArgs> {
|
|
|
131
178
|
}
|
|
132
179
|
/** 工具定义联合类型 */
|
|
133
180
|
type ToolDefinition<TArgs = Record<string, unknown>> = FrontendTool<TArgs> | BackendTool<TArgs>;
|
|
181
|
+
/** 空状态配置 */
|
|
182
|
+
interface EmptyStateConfig {
|
|
183
|
+
/** 空状态标题 */
|
|
184
|
+
title?: string;
|
|
185
|
+
/** 空状态描述 */
|
|
186
|
+
description?: string;
|
|
187
|
+
/** 自定义渲染 */
|
|
188
|
+
render?: () => ReactNode;
|
|
189
|
+
}
|
|
134
190
|
/** 消息渲染配置 */
|
|
135
191
|
interface MessageConfig {
|
|
136
192
|
/** Markdown 自定义组件 */
|
|
@@ -141,6 +197,8 @@ interface MessageConfig {
|
|
|
141
197
|
literalTagContent?: string[];
|
|
142
198
|
/** Loading 动画颜色,支持 CSS 颜色值 */
|
|
143
199
|
loadingColor?: string;
|
|
200
|
+
/** 空状态配置 */
|
|
201
|
+
emptyState?: EmptyStateConfig;
|
|
144
202
|
}
|
|
145
203
|
/** 输入框配置 */
|
|
146
204
|
interface InputConfig extends SenderCustomizationProps {
|
|
@@ -161,6 +219,11 @@ interface AgentChatProps {
|
|
|
161
219
|
messageConfig?: MessageConfig;
|
|
162
220
|
inputConfig?: InputConfig;
|
|
163
221
|
onError?: (error: Error) => void;
|
|
222
|
+
interruptConfig?: InterruptConfig;
|
|
223
|
+
/** Agent 状态值 */
|
|
224
|
+
agentState?: Record<string, unknown>;
|
|
225
|
+
/** Agent 状态变化回调 */
|
|
226
|
+
onAgentStateChange?: (state: Record<string, unknown>) => void;
|
|
164
227
|
}
|
|
165
228
|
/** AgentChat 组件对外暴露的方法 */
|
|
166
229
|
interface AgentChatRef {
|
|
@@ -174,28 +237,14 @@ interface AgentChatRef {
|
|
|
174
237
|
focusInput: () => void;
|
|
175
238
|
}
|
|
176
239
|
//#endregion
|
|
177
|
-
//#region src/AgentChat.d.ts
|
|
240
|
+
//#region src/components/AgentChat.d.ts
|
|
178
241
|
declare const AgentChat: react.ForwardRefExoticComponent<AgentChatProps & react.RefAttributes<AgentChatRef>>;
|
|
179
242
|
//#endregion
|
|
180
|
-
//#region src/ToolCard.d.ts
|
|
181
|
-
interface ToolCardProps {
|
|
182
|
-
/**
|
|
183
|
-
* 前缀文本(中文,使用小字体)
|
|
184
|
-
*/
|
|
185
|
-
prefix: string;
|
|
186
|
-
/**
|
|
187
|
-
* 正文内容(英文/文件名,保持默认大小)
|
|
188
|
-
*/
|
|
189
|
-
content?: string;
|
|
190
|
-
/**
|
|
191
|
-
* 左侧图标
|
|
192
|
-
*/
|
|
193
|
-
icon: React.ReactNode;
|
|
194
|
-
}
|
|
243
|
+
//#region src/components/ToolCard.d.ts
|
|
195
244
|
/**
|
|
196
245
|
* ToolCard 组件 - 用于展示工具调用结果
|
|
197
246
|
* 样式:圆角矩形框,左侧 icon,label 分两行显示(prefix 小字体,content 默认字体)
|
|
198
247
|
*/
|
|
199
248
|
declare const ToolCard: React.FC<ToolCardProps>;
|
|
200
249
|
//#endregion
|
|
201
|
-
export { AgentChat, type AgentChatInputRef, type AgentChatProps, type AgentChatRef, type BackendTool, type ChatMessage, type ContextItem, type FrontendTool, type InputConfig, type MessageConfig, type MessageType, type SenderCustomizationProps, type SenderSlotConfig, type SenderSubmitParams, type ToolCallInput, ToolCard, type ToolCardProps, type ToolDefinition, type ToolExecutionRecord, type ToolExecutionStatus, type ToolParameterSchema, type ToolRenderProps };
|
|
250
|
+
export { AgentChat, type AgentChatInputRef, type AgentChatProps, type AgentChatRef, type BackendTool, type ChatMessage, type ContextItem, type EmptyStateConfig, type FrontendTool, type InputConfig, type InterruptConfig, type InterruptEvent, type InterruptManagerProps, type InterruptRenderProps, type MessageConfig, type MessageType, type SenderCustomizationProps, type SenderSlotConfig, type SenderSubmitParams, type ToolCallInput, ToolCard, type ToolCardProps, type ToolDefinition, type ToolExecutionRecord, type ToolExecutionStatus, type ToolParameterSchema, type ToolRenderProps };
|
package/dist/index.mjs
CHANGED
|
@@ -1,117 +1,9 @@
|
|
|
1
1
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { useStream } from "@langchain/react";
|
|
3
|
-
import { Bubble, Sender, Think } from "@ant-design/x";
|
|
3
|
+
import { Actions, Bubble, Sender, Think } from "@ant-design/x";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Streamdown } from "streamdown";
|
|
6
|
-
//#region src/
|
|
7
|
-
const styles = `
|
|
8
|
-
/* Agent Chat Container */
|
|
9
|
-
.agent-chat-container {
|
|
10
|
-
display: flex;
|
|
11
|
-
flex-direction: column;
|
|
12
|
-
height: 100%;
|
|
13
|
-
background-color: transparent;
|
|
14
|
-
overflow: hidden;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/* Message List */
|
|
18
|
-
.agent-message-list {
|
|
19
|
-
flex: 1;
|
|
20
|
-
overflow-y: auto;
|
|
21
|
-
display: flex;
|
|
22
|
-
flex-direction: column;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.agent-message-list .empty {
|
|
26
|
-
display: flex;
|
|
27
|
-
align-items: center;
|
|
28
|
-
justify-content: center;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.agent-message-list .ant-think-status-text {
|
|
32
|
-
font-size: 13px;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.agent-message-empty {
|
|
36
|
-
color: #8b8d91;
|
|
37
|
-
font-size: 14px;
|
|
38
|
-
text-align: center;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@keyframes agent-loading-bounce {
|
|
42
|
-
0%,
|
|
43
|
-
80%,
|
|
44
|
-
100% {
|
|
45
|
-
transform: scale(0);
|
|
46
|
-
}
|
|
47
|
-
40% {
|
|
48
|
-
transform: scale(1);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/* Chat Input */
|
|
53
|
-
.agent-chat-input-container {
|
|
54
|
-
padding: 12px 4px;
|
|
55
|
-
background-color: transparent;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* Tool Calls Container */
|
|
59
|
-
.tool-calls-container {
|
|
60
|
-
display: flex;
|
|
61
|
-
flex-direction: column;
|
|
62
|
-
gap: 8px;
|
|
63
|
-
margin-top: 8px;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* Tool Call Default Style */
|
|
67
|
-
.tool-call-default {
|
|
68
|
-
display: flex;
|
|
69
|
-
flex-direction: column;
|
|
70
|
-
gap: 4px;
|
|
71
|
-
padding: 6px 0;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.tool-call-header {
|
|
75
|
-
display: flex;
|
|
76
|
-
align-items: center;
|
|
77
|
-
gap: 8px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.tool-call-name {
|
|
81
|
-
font-weight: 500;
|
|
82
|
-
font-size: 13px;
|
|
83
|
-
color: #fff;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.tool-call-status {
|
|
87
|
-
font-size: 12px;
|
|
88
|
-
color: #8b8d91;
|
|
89
|
-
margin-left: auto;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.tool-call-error {
|
|
93
|
-
display: flex;
|
|
94
|
-
align-items: center;
|
|
95
|
-
gap: 4px;
|
|
96
|
-
font-size: 12px;
|
|
97
|
-
color: #ff4d4f;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.tool-call-wrapper {
|
|
101
|
-
width: 100%;
|
|
102
|
-
}
|
|
103
|
-
`;
|
|
104
|
-
let injected = false;
|
|
105
|
-
function injectStyles() {
|
|
106
|
-
if (injected || typeof document === "undefined") return;
|
|
107
|
-
const styleElement = document.createElement("style");
|
|
108
|
-
styleElement.textContent = styles;
|
|
109
|
-
document.head.appendChild(styleElement);
|
|
110
|
-
injected = true;
|
|
111
|
-
}
|
|
112
|
-
//#endregion
|
|
113
|
-
//#region src/ChatInput.tsx
|
|
114
|
-
injectStyles();
|
|
6
|
+
//#region src/components/ChatInput.tsx
|
|
115
7
|
const slotConfig = [];
|
|
116
8
|
const ChatInput = forwardRef(({ onSend, onStop, isLoading = false, disabled = false, placeholder = "输入消息...", className = "", footer, skill: externalSkill, header, prefix }, ref) => {
|
|
117
9
|
const senderRef = useRef(null);
|
|
@@ -159,7 +51,7 @@ const ChatInput = forwardRef(({ onSend, onStop, isLoading = false, disabled = fa
|
|
|
159
51
|
});
|
|
160
52
|
ChatInput.displayName = "ChatInput";
|
|
161
53
|
//#endregion
|
|
162
|
-
//#region src/ToolCallRenderer.tsx
|
|
54
|
+
//#region src/components/ToolCallRenderer.tsx
|
|
163
55
|
/**
|
|
164
56
|
* 工具调用渲染组件
|
|
165
57
|
*
|
|
@@ -209,125 +101,7 @@ const DefaultToolCallRenderer = ({ record }) => {
|
|
|
209
101
|
});
|
|
210
102
|
};
|
|
211
103
|
//#endregion
|
|
212
|
-
//#region src/
|
|
213
|
-
/**
|
|
214
|
-
* 工具管理器组件
|
|
215
|
-
*
|
|
216
|
-
* 职责:
|
|
217
|
-
* 1. 管理工具执行状态
|
|
218
|
-
* 2. 自动执行前端工具(避免重复执行)
|
|
219
|
-
* 3. 通知外部执行状态变化
|
|
220
|
-
*
|
|
221
|
-
* 这是一个无 UI 组件,只负责逻辑处理
|
|
222
|
-
*/
|
|
223
|
-
const ToolManager = ({ tools, toolCalls, isLoading = false, onExecutionChange, onToolResult, completedToolResults }) => {
|
|
224
|
-
const executedCallsRef = useRef(/* @__PURE__ */ new Set());
|
|
225
|
-
const executingCallsRef = useRef(/* @__PURE__ */ new Set());
|
|
226
|
-
const pendingNotifiedRef = useRef(/* @__PURE__ */ new Set());
|
|
227
|
-
const initializedRef = useRef(false);
|
|
228
|
-
useEffect(() => {
|
|
229
|
-
if (initializedRef.current || !completedToolResults || completedToolResults.size === 0) return;
|
|
230
|
-
initializedRef.current = true;
|
|
231
|
-
completedToolResults.forEach((result, callId) => {
|
|
232
|
-
executedCallsRef.current.add(callId);
|
|
233
|
-
const call = toolCalls.find((c) => c.id === callId);
|
|
234
|
-
if (call) onExecutionChange?.({
|
|
235
|
-
callId,
|
|
236
|
-
name: call.name,
|
|
237
|
-
arguments: call.arguments,
|
|
238
|
-
status: "success",
|
|
239
|
-
result
|
|
240
|
-
});
|
|
241
|
-
});
|
|
242
|
-
}, [completedToolResults]);
|
|
243
|
-
/**
|
|
244
|
-
* 执行单个前端工具
|
|
245
|
-
*/
|
|
246
|
-
const executeFrontendTool = useCallback(async (tool, call) => {
|
|
247
|
-
const callId = call.id;
|
|
248
|
-
executingCallsRef.current.add(callId);
|
|
249
|
-
onExecutionChange?.({
|
|
250
|
-
callId,
|
|
251
|
-
name: call.name,
|
|
252
|
-
arguments: call.arguments,
|
|
253
|
-
status: "running"
|
|
254
|
-
});
|
|
255
|
-
try {
|
|
256
|
-
const result = await tool.execute(call.arguments);
|
|
257
|
-
onExecutionChange?.({
|
|
258
|
-
callId,
|
|
259
|
-
name: call.name,
|
|
260
|
-
arguments: call.arguments,
|
|
261
|
-
status: "success",
|
|
262
|
-
result
|
|
263
|
-
});
|
|
264
|
-
onToolResult?.(callId, call.name, result);
|
|
265
|
-
} catch (error) {
|
|
266
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
267
|
-
onExecutionChange?.({
|
|
268
|
-
callId,
|
|
269
|
-
name: call.name,
|
|
270
|
-
arguments: call.arguments,
|
|
271
|
-
status: "error",
|
|
272
|
-
error: errorMessage
|
|
273
|
-
});
|
|
274
|
-
} finally {
|
|
275
|
-
executingCallsRef.current.delete(callId);
|
|
276
|
-
executedCallsRef.current.add(callId);
|
|
277
|
-
}
|
|
278
|
-
}, [onExecutionChange, onToolResult]);
|
|
279
|
-
/**
|
|
280
|
-
* 处理工具调用
|
|
281
|
-
*/
|
|
282
|
-
const processToolCalls = useCallback(async () => {
|
|
283
|
-
if (!tools) return;
|
|
284
|
-
for (const call of toolCalls) {
|
|
285
|
-
const callId = call.id;
|
|
286
|
-
if (executedCallsRef.current.has(callId) || executingCallsRef.current.has(callId)) continue;
|
|
287
|
-
const tool = tools.find((t) => t.name === call.name);
|
|
288
|
-
if (isLoading) {
|
|
289
|
-
if (!pendingNotifiedRef.current.has(callId)) {
|
|
290
|
-
pendingNotifiedRef.current.add(callId);
|
|
291
|
-
onExecutionChange?.({
|
|
292
|
-
callId,
|
|
293
|
-
name: call.name,
|
|
294
|
-
arguments: call.arguments,
|
|
295
|
-
status: "pending"
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
if (!tool) {
|
|
301
|
-
onExecutionChange?.({
|
|
302
|
-
callId,
|
|
303
|
-
name: call.name,
|
|
304
|
-
arguments: call.arguments,
|
|
305
|
-
status: "pending"
|
|
306
|
-
});
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
if (tool.type === "frontend") await executeFrontendTool(tool, call);
|
|
310
|
-
else onExecutionChange?.({
|
|
311
|
-
callId,
|
|
312
|
-
name: call.name,
|
|
313
|
-
arguments: call.arguments,
|
|
314
|
-
status: "pending"
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
}, [
|
|
318
|
-
tools,
|
|
319
|
-
toolCalls,
|
|
320
|
-
isLoading,
|
|
321
|
-
executeFrontendTool,
|
|
322
|
-
onExecutionChange
|
|
323
|
-
]);
|
|
324
|
-
useEffect(() => {
|
|
325
|
-
processToolCalls();
|
|
326
|
-
}, [useMemo(() => {
|
|
327
|
-
return toolCalls.filter((call) => !executedCallsRef.current.has(call.id) && !executingCallsRef.current.has(call.id)).map((call) => call.id).sort().join(",");
|
|
328
|
-
}, [toolCalls]), isLoading]);
|
|
329
|
-
return null;
|
|
330
|
-
};
|
|
104
|
+
//#region src/utils/toolUtils.ts
|
|
331
105
|
/**
|
|
332
106
|
* 辅助函数:根据工具名查找工具定义
|
|
333
107
|
*/
|
|
@@ -341,7 +115,7 @@ function isFrontendTool(tool) {
|
|
|
341
115
|
return tool.type === "frontend";
|
|
342
116
|
}
|
|
343
117
|
//#endregion
|
|
344
|
-
//#region src/ReasoningContent.tsx
|
|
118
|
+
//#region src/components/ReasoningContent.tsx
|
|
345
119
|
const REASONING_CONTENT_MAX_HEIGHT = 58;
|
|
346
120
|
const ReasoningContent = ({ content }) => {
|
|
347
121
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
@@ -374,22 +148,23 @@ const ReasoningContent = ({ content }) => {
|
|
|
374
148
|
justifyContent: "flex-end"
|
|
375
149
|
},
|
|
376
150
|
children: content.trim()
|
|
377
|
-
}), isOverflowing && !isExpanded && /* @__PURE__ */ jsx(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
151
|
+
}), isOverflowing && !isExpanded && /* @__PURE__ */ jsx(Actions, {
|
|
152
|
+
items: [{
|
|
153
|
+
key: "expand",
|
|
154
|
+
icon: /* @__PURE__ */ jsx("span", {
|
|
155
|
+
style: {
|
|
156
|
+
fontSize: "12px",
|
|
157
|
+
marginLeft: "-4px",
|
|
158
|
+
opacity: .8
|
|
159
|
+
},
|
|
160
|
+
children: "查看全部"
|
|
161
|
+
})
|
|
162
|
+
}],
|
|
163
|
+
onClick: () => setIsExpanded(true)
|
|
389
164
|
})] });
|
|
390
165
|
};
|
|
391
166
|
//#endregion
|
|
392
|
-
//#region src/WaveLoading.tsx
|
|
167
|
+
//#region src/components/WaveLoading.tsx
|
|
393
168
|
/**
|
|
394
169
|
* 波浪动画 Loading 组件
|
|
395
170
|
* 三个小圆点波浪状动画效果
|
|
@@ -428,8 +203,7 @@ const WaveLoading = ({ color = "#1890ff" }) => {
|
|
|
428
203
|
});
|
|
429
204
|
};
|
|
430
205
|
//#endregion
|
|
431
|
-
//#region src/MessageList.tsx
|
|
432
|
-
injectStyles();
|
|
206
|
+
//#region src/components/MessageList.tsx
|
|
433
207
|
const CustomParagraph = (props) => {
|
|
434
208
|
const { node, ...rest } = props;
|
|
435
209
|
return /* @__PURE__ */ jsx("span", { ...rest });
|
|
@@ -530,7 +304,7 @@ const renderToolCalls = (toolCalls, tools, toolExecutions) => {
|
|
|
530
304
|
tool,
|
|
531
305
|
record
|
|
532
306
|
}, call.id);
|
|
533
|
-
});
|
|
307
|
+
}).filter(Boolean);
|
|
534
308
|
};
|
|
535
309
|
const roleConfig = {
|
|
536
310
|
user: {
|
|
@@ -546,7 +320,7 @@ const roleConfig = {
|
|
|
546
320
|
}
|
|
547
321
|
}
|
|
548
322
|
};
|
|
549
|
-
const MessageList = ({ messages, isLoading = false, className = "", tools, toolExecutions, components, securityConfig, loadingColor }) => {
|
|
323
|
+
const MessageList = ({ messages, isLoading = false, className = "", tools, toolExecutions, components, securityConfig, loadingColor, interruptRender, emptyState }) => {
|
|
550
324
|
const reasoningCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
551
325
|
const processedMessages = useMemo(() => {
|
|
552
326
|
const cache = reasoningCacheRef.current;
|
|
@@ -576,13 +350,19 @@ const MessageList = ({ messages, isLoading = false, className = "", tools, toolE
|
|
|
576
350
|
}, [processedMessages]);
|
|
577
351
|
const items = groupedItems.map((group, groupIndex) => {
|
|
578
352
|
const isLastGroup = groupIndex === groupedItems.length - 1;
|
|
353
|
+
const isLastAiGroup = isLastGroup && group.type === "ai";
|
|
579
354
|
if (group.type === "user" || group.messages.length === 1) {
|
|
580
355
|
const message = group.messages[0];
|
|
581
|
-
|
|
356
|
+
const bubbleItem = toBubbleItem(message, isLastGroup && group.messages.length === 1, isLoading, tools, toolExecutions, components, securityConfig);
|
|
357
|
+
if (isLastAiGroup && interruptRender) return {
|
|
358
|
+
...bubbleItem,
|
|
359
|
+
content: /* @__PURE__ */ jsxs(Fragment, { children: [bubbleItem.content, interruptRender()] })
|
|
360
|
+
};
|
|
361
|
+
return bubbleItem;
|
|
582
362
|
}
|
|
583
|
-
const mergedContent = /* @__PURE__ */
|
|
363
|
+
const mergedContent = /* @__PURE__ */ jsxs(Fragment, { children: [group.messages.map((message, msgIndex) => {
|
|
584
364
|
return renderMessageContent(message, isLastGroup && msgIndex === group.messages.length - 1, isLoading, tools, toolExecutions, components, securityConfig);
|
|
585
|
-
}) });
|
|
365
|
+
}), isLastAiGroup && interruptRender?.()] });
|
|
586
366
|
return {
|
|
587
367
|
key: group.messages.map((m) => m.id).join("-"),
|
|
588
368
|
role: "ai",
|
|
@@ -597,13 +377,19 @@ const MessageList = ({ messages, isLoading = false, className = "", tools, toolE
|
|
|
597
377
|
placement: "start",
|
|
598
378
|
style: { paddingBlock: 0 }
|
|
599
379
|
}] : items;
|
|
600
|
-
if (allItems.length === 0)
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
380
|
+
if (allItems.length === 0) {
|
|
381
|
+
if (emptyState?.render) return /* @__PURE__ */ jsx("div", {
|
|
382
|
+
className: `agent-message-list empty ${className}`,
|
|
383
|
+
children: emptyState.render()
|
|
384
|
+
});
|
|
385
|
+
return /* @__PURE__ */ jsx("div", {
|
|
386
|
+
className: `agent-message-list empty ${className}`,
|
|
387
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
388
|
+
className: "agent-message-empty",
|
|
389
|
+
children: [emptyState?.title && /* @__PURE__ */ jsx("h4", { children: emptyState.title }), emptyState?.description ? /* @__PURE__ */ jsx("p", { children: emptyState.description }) : /* @__PURE__ */ jsx("p", { children: "开始对话吧" })]
|
|
390
|
+
})
|
|
391
|
+
});
|
|
392
|
+
}
|
|
607
393
|
return /* @__PURE__ */ jsx(Bubble.List, {
|
|
608
394
|
className: `agent-message-list ${className}`,
|
|
609
395
|
items: allItems,
|
|
@@ -612,7 +398,169 @@ const MessageList = ({ messages, isLoading = false, className = "", tools, toolE
|
|
|
612
398
|
});
|
|
613
399
|
};
|
|
614
400
|
//#endregion
|
|
615
|
-
//#region src/
|
|
401
|
+
//#region src/hooks/useInterrupt.tsx
|
|
402
|
+
/**
|
|
403
|
+
* InterruptManager - 管理 Interrupt 状态的 Hook
|
|
404
|
+
*
|
|
405
|
+
* 封装 Interrupt 状态管理和处理逻辑,避免在 AgentChat 组件中臃肿
|
|
406
|
+
*/
|
|
407
|
+
function useInterrupt({ interrupt, config, onSubmit }) {
|
|
408
|
+
const [activeInterrupt, setActiveInterrupt] = useState(null);
|
|
409
|
+
const processedInterruptIdRef = useRef(null);
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
if (interrupt) {
|
|
412
|
+
const interruptEvent = interrupt;
|
|
413
|
+
if (interruptEvent.id !== processedInterruptIdRef.current) {
|
|
414
|
+
processedInterruptIdRef.current = interruptEvent.id;
|
|
415
|
+
setActiveInterrupt(interruptEvent);
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
processedInterruptIdRef.current = null;
|
|
419
|
+
setActiveInterrupt(null);
|
|
420
|
+
}
|
|
421
|
+
}, [interrupt?.id]);
|
|
422
|
+
const handleResolveInterrupt = useCallback((response) => {
|
|
423
|
+
onSubmit(null, { command: { resume: response } });
|
|
424
|
+
setActiveInterrupt(null);
|
|
425
|
+
}, [onSubmit]);
|
|
426
|
+
return {
|
|
427
|
+
activeInterrupt,
|
|
428
|
+
handleResolveInterrupt,
|
|
429
|
+
renderInterrupt: useCallback(() => {
|
|
430
|
+
if (!activeInterrupt || !config?.render) return null;
|
|
431
|
+
return /* @__PURE__ */ jsx("div", {
|
|
432
|
+
className: "agent-chat-interrupt",
|
|
433
|
+
children: config.render({
|
|
434
|
+
event: activeInterrupt,
|
|
435
|
+
resolve: handleResolveInterrupt
|
|
436
|
+
})
|
|
437
|
+
});
|
|
438
|
+
}, [
|
|
439
|
+
activeInterrupt,
|
|
440
|
+
config,
|
|
441
|
+
handleResolveInterrupt
|
|
442
|
+
])
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region src/hooks/useToolExecution.ts
|
|
447
|
+
/**
|
|
448
|
+
* useToolExecution - 管理前端工具执行的 Hook
|
|
449
|
+
*
|
|
450
|
+
* 职责:
|
|
451
|
+
* 1. 管理工具执行状态
|
|
452
|
+
* 2. 自动执行前端工具(避免重复执行)
|
|
453
|
+
* 3. 通知外部执行状态变化
|
|
454
|
+
*/
|
|
455
|
+
function useToolExecution({ tools, toolCalls, isLoading = false, onExecutionChange, onToolResult, completedToolResults }) {
|
|
456
|
+
const executedCallsRef = useRef(/* @__PURE__ */ new Set());
|
|
457
|
+
const executingCallsRef = useRef(/* @__PURE__ */ new Set());
|
|
458
|
+
const pendingNotifiedRef = useRef(/* @__PURE__ */ new Set());
|
|
459
|
+
const initializedRef = useRef(false);
|
|
460
|
+
useEffect(() => {
|
|
461
|
+
if (initializedRef.current || !completedToolResults || completedToolResults.size === 0) return;
|
|
462
|
+
initializedRef.current = true;
|
|
463
|
+
completedToolResults.forEach((result, callId) => {
|
|
464
|
+
executedCallsRef.current.add(callId);
|
|
465
|
+
const call = toolCalls.find((c) => c.id === callId);
|
|
466
|
+
if (call) onExecutionChange?.({
|
|
467
|
+
callId,
|
|
468
|
+
name: call.name,
|
|
469
|
+
arguments: call.arguments,
|
|
470
|
+
status: "success",
|
|
471
|
+
result
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
}, [completedToolResults]);
|
|
475
|
+
/**
|
|
476
|
+
* 执行单个前端工具
|
|
477
|
+
*/
|
|
478
|
+
const executeFrontendTool = useCallback(async (tool, call) => {
|
|
479
|
+
const callId = call.id;
|
|
480
|
+
executingCallsRef.current.add(callId);
|
|
481
|
+
onExecutionChange?.({
|
|
482
|
+
callId,
|
|
483
|
+
name: call.name,
|
|
484
|
+
arguments: call.arguments,
|
|
485
|
+
status: "running"
|
|
486
|
+
});
|
|
487
|
+
try {
|
|
488
|
+
const result = await tool.execute(call.arguments);
|
|
489
|
+
onExecutionChange?.({
|
|
490
|
+
callId,
|
|
491
|
+
name: call.name,
|
|
492
|
+
arguments: call.arguments,
|
|
493
|
+
status: "success",
|
|
494
|
+
result
|
|
495
|
+
});
|
|
496
|
+
onToolResult?.(callId, call.name, result);
|
|
497
|
+
} catch (error) {
|
|
498
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
499
|
+
onExecutionChange?.({
|
|
500
|
+
callId,
|
|
501
|
+
name: call.name,
|
|
502
|
+
arguments: call.arguments,
|
|
503
|
+
status: "error",
|
|
504
|
+
error: errorMessage
|
|
505
|
+
});
|
|
506
|
+
} finally {
|
|
507
|
+
executingCallsRef.current.delete(callId);
|
|
508
|
+
executedCallsRef.current.add(callId);
|
|
509
|
+
}
|
|
510
|
+
}, [onExecutionChange, onToolResult]);
|
|
511
|
+
/**
|
|
512
|
+
* 处理工具调用
|
|
513
|
+
*/
|
|
514
|
+
const processToolCalls = useCallback(async () => {
|
|
515
|
+
if (!tools) return;
|
|
516
|
+
for (const call of toolCalls) {
|
|
517
|
+
const callId = call.id;
|
|
518
|
+
if (executedCallsRef.current.has(callId) || executingCallsRef.current.has(callId)) continue;
|
|
519
|
+
const tool = findTool(tools, call.name);
|
|
520
|
+
if (isLoading) {
|
|
521
|
+
if (!pendingNotifiedRef.current.has(callId)) {
|
|
522
|
+
pendingNotifiedRef.current.add(callId);
|
|
523
|
+
onExecutionChange?.({
|
|
524
|
+
callId,
|
|
525
|
+
name: call.name,
|
|
526
|
+
arguments: call.arguments,
|
|
527
|
+
status: "pending"
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
if (!tool) {
|
|
533
|
+
onExecutionChange?.({
|
|
534
|
+
callId,
|
|
535
|
+
name: call.name,
|
|
536
|
+
arguments: call.arguments,
|
|
537
|
+
status: "pending"
|
|
538
|
+
});
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (isFrontendTool(tool)) await executeFrontendTool(tool, call);
|
|
542
|
+
else onExecutionChange?.({
|
|
543
|
+
callId,
|
|
544
|
+
name: call.name,
|
|
545
|
+
arguments: call.arguments,
|
|
546
|
+
status: "pending"
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
}, [
|
|
550
|
+
tools,
|
|
551
|
+
toolCalls,
|
|
552
|
+
isLoading,
|
|
553
|
+
executeFrontendTool,
|
|
554
|
+
onExecutionChange
|
|
555
|
+
]);
|
|
556
|
+
useEffect(() => {
|
|
557
|
+
processToolCalls();
|
|
558
|
+
}, [useMemo(() => {
|
|
559
|
+
return toolCalls.filter((call) => !executedCallsRef.current.has(call.id) && !executingCallsRef.current.has(call.id)).map((call) => call.id).sort().join(",");
|
|
560
|
+
}, [toolCalls]), isLoading]);
|
|
561
|
+
}
|
|
562
|
+
//#endregion
|
|
563
|
+
//#region src/utils/messageUtils.ts
|
|
616
564
|
/**
|
|
617
565
|
* 从 BaseMessage 中提取 tool_calls
|
|
618
566
|
*/
|
|
@@ -684,9 +632,115 @@ function processMessages(rawMessages) {
|
|
|
684
632
|
};
|
|
685
633
|
}
|
|
686
634
|
//#endregion
|
|
687
|
-
//#region src/
|
|
635
|
+
//#region src/utils/injectStyles.ts
|
|
636
|
+
const styles = `
|
|
637
|
+
/* Agent Chat Container */
|
|
638
|
+
.agent-chat-container {
|
|
639
|
+
display: flex;
|
|
640
|
+
flex-direction: column;
|
|
641
|
+
height: 100%;
|
|
642
|
+
background-color: transparent;
|
|
643
|
+
overflow: hidden;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/* Message List */
|
|
647
|
+
.agent-message-list {
|
|
648
|
+
flex: 1;
|
|
649
|
+
overflow-y: auto;
|
|
650
|
+
display: flex;
|
|
651
|
+
flex-direction: column;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.agent-message-list .empty {
|
|
655
|
+
display: flex;
|
|
656
|
+
align-items: center;
|
|
657
|
+
justify-content: center;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.agent-message-list .ant-think-status-text {
|
|
661
|
+
font-size: 13px;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.agent-message-empty {
|
|
665
|
+
color: #8b8d91;
|
|
666
|
+
font-size: 14px;
|
|
667
|
+
text-align: center;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
@keyframes agent-loading-bounce {
|
|
671
|
+
0%,
|
|
672
|
+
80%,
|
|
673
|
+
100% {
|
|
674
|
+
transform: scale(0);
|
|
675
|
+
}
|
|
676
|
+
40% {
|
|
677
|
+
transform: scale(1);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/* Chat Input */
|
|
682
|
+
.agent-chat-input-container {
|
|
683
|
+
padding: 12px 4px;
|
|
684
|
+
background-color: transparent;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/* Tool Calls Container */
|
|
688
|
+
.tool-calls-container {
|
|
689
|
+
display: flex;
|
|
690
|
+
flex-direction: column;
|
|
691
|
+
gap: 8px;
|
|
692
|
+
margin-top: 8px;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/* Tool Call Default Style */
|
|
696
|
+
.tool-call-default {
|
|
697
|
+
display: flex;
|
|
698
|
+
flex-direction: column;
|
|
699
|
+
gap: 4px;
|
|
700
|
+
padding: 6px 0;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.tool-call-header {
|
|
704
|
+
display: flex;
|
|
705
|
+
align-items: center;
|
|
706
|
+
gap: 8px;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
.tool-call-name {
|
|
710
|
+
font-weight: 500;
|
|
711
|
+
font-size: 13px;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.tool-call-status {
|
|
715
|
+
font-size: 12px;
|
|
716
|
+
color: #8b8d91;
|
|
717
|
+
margin-left: auto;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.tool-call-error {
|
|
721
|
+
display: flex;
|
|
722
|
+
align-items: center;
|
|
723
|
+
gap: 4px;
|
|
724
|
+
font-size: 12px;
|
|
725
|
+
color: #ff4d4f;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.tool-call-wrapper {
|
|
729
|
+
width: 100%;
|
|
730
|
+
}
|
|
731
|
+
`;
|
|
732
|
+
let injected = false;
|
|
733
|
+
function injectStyles() {
|
|
734
|
+
if (injected || typeof document === "undefined") return;
|
|
735
|
+
const styleElement = document.createElement("style");
|
|
736
|
+
styleElement.textContent = styles;
|
|
737
|
+
document.head.appendChild(styleElement);
|
|
738
|
+
injected = true;
|
|
739
|
+
}
|
|
740
|
+
//#endregion
|
|
741
|
+
//#region src/components/AgentChat.tsx
|
|
688
742
|
injectStyles();
|
|
689
|
-
const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: externalThreadId, onThreadIdChange, className = "", tools, contexts, messageConfig, inputConfig, onError }, ref) => {
|
|
743
|
+
const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: externalThreadId, onThreadIdChange, className = "", tools, contexts, messageConfig, inputConfig, onError, interruptConfig, agentState, onAgentStateChange }, ref) => {
|
|
690
744
|
const [internalThreadId, setInternalThreadId] = useState(externalThreadId);
|
|
691
745
|
useEffect(() => {
|
|
692
746
|
setInternalThreadId(externalThreadId);
|
|
@@ -714,6 +768,14 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
714
768
|
onError?.(err);
|
|
715
769
|
}
|
|
716
770
|
});
|
|
771
|
+
useEffect(() => {
|
|
772
|
+
if (stream.values && onAgentStateChange) onAgentStateChange(stream.values);
|
|
773
|
+
}, [stream.values, onAgentStateChange]);
|
|
774
|
+
const { renderInterrupt: interruptRender } = useInterrupt({
|
|
775
|
+
interrupt: stream.interrupt,
|
|
776
|
+
config: interruptConfig,
|
|
777
|
+
onSubmit: stream.submit
|
|
778
|
+
});
|
|
717
779
|
const [toolExecutions, setToolExecutions] = useState(/* @__PURE__ */ new Map());
|
|
718
780
|
const { messages, toolResults } = useMemo(() => {
|
|
719
781
|
return processMessages(stream.messages);
|
|
@@ -728,10 +790,10 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
728
790
|
return next;
|
|
729
791
|
});
|
|
730
792
|
}, []);
|
|
731
|
-
const submitToStream = useCallback((submitMessages
|
|
732
|
-
stream.submit({
|
|
793
|
+
const submitToStream = useCallback(async (submitMessages) => {
|
|
794
|
+
await stream.submit({
|
|
795
|
+
...agentState,
|
|
733
796
|
messages: submitMessages,
|
|
734
|
-
...extraState,
|
|
735
797
|
agentkit: {
|
|
736
798
|
actions: tools,
|
|
737
799
|
context: contexts
|
|
@@ -749,7 +811,8 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
749
811
|
}, [
|
|
750
812
|
stream,
|
|
751
813
|
tools,
|
|
752
|
-
contexts
|
|
814
|
+
contexts,
|
|
815
|
+
agentState
|
|
753
816
|
]);
|
|
754
817
|
const handleToolResult = useCallback((callId, name, result) => {
|
|
755
818
|
submitToStream([{
|
|
@@ -761,12 +824,8 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
761
824
|
}, [submitToStream]);
|
|
762
825
|
const handleSend = useCallback(async (params) => {
|
|
763
826
|
let messages = [];
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
const { messages: resultMessages, ...rest } = await onPreSend(params);
|
|
767
|
-
messages = resultMessages.filter((m) => m != null);
|
|
768
|
-
extraState = rest;
|
|
769
|
-
} else {
|
|
827
|
+
if (onPreSend && params.message.trim()) messages = (await onPreSend(params)).messages.filter((m) => m != null);
|
|
828
|
+
else {
|
|
770
829
|
if (!params.message.trim()) return;
|
|
771
830
|
messages = [{
|
|
772
831
|
type: "human",
|
|
@@ -774,54 +833,53 @@ const AgentChat = forwardRef(({ apiUrl, assistantId, headers, threadId: external
|
|
|
774
833
|
}];
|
|
775
834
|
}
|
|
776
835
|
if (messages.length === 0) return;
|
|
777
|
-
submitToStream(messages
|
|
836
|
+
await submitToStream(messages);
|
|
778
837
|
}, [onPreSend, submitToStream]);
|
|
779
|
-
const handleStop = useCallback(() => {
|
|
780
|
-
stream.stop();
|
|
838
|
+
const handleStop = useCallback(async () => {
|
|
839
|
+
await stream.stop();
|
|
781
840
|
}, [stream]);
|
|
841
|
+
useToolExecution({
|
|
842
|
+
tools,
|
|
843
|
+
toolCalls: allToolCalls,
|
|
844
|
+
isLoading: stream.isLoading,
|
|
845
|
+
onExecutionChange: handleExecutionChange,
|
|
846
|
+
onToolResult: handleToolResult,
|
|
847
|
+
completedToolResults: toolResults
|
|
848
|
+
});
|
|
782
849
|
return /* @__PURE__ */ jsxs("div", {
|
|
783
850
|
className: `agent-chat-container ${className}`,
|
|
784
|
-
children: [
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
className: "agent-chat-input",
|
|
812
|
-
footer,
|
|
813
|
-
skill,
|
|
814
|
-
slotConfig,
|
|
815
|
-
header,
|
|
816
|
-
prefix,
|
|
817
|
-
placeholder
|
|
818
|
-
})
|
|
819
|
-
]
|
|
851
|
+
children: [/* @__PURE__ */ jsx(MessageList, {
|
|
852
|
+
messages,
|
|
853
|
+
isLoading: stream.isLoading,
|
|
854
|
+
className: "agent-chat-messages",
|
|
855
|
+
tools,
|
|
856
|
+
toolExecutions,
|
|
857
|
+
components: messageConfig?.components,
|
|
858
|
+
securityConfig: {
|
|
859
|
+
allowedTags: messageConfig?.allowedTags,
|
|
860
|
+
literalTagContent: messageConfig?.literalTagContent
|
|
861
|
+
},
|
|
862
|
+
loadingColor: messageConfig?.loadingColor,
|
|
863
|
+
interruptRender,
|
|
864
|
+
emptyState: messageConfig?.emptyState
|
|
865
|
+
}), /* @__PURE__ */ jsx(ChatInput, {
|
|
866
|
+
ref: chatInputRef,
|
|
867
|
+
onSend: handleSend,
|
|
868
|
+
onStop: handleStop,
|
|
869
|
+
isLoading: stream.isLoading,
|
|
870
|
+
className: "agent-chat-input",
|
|
871
|
+
footer,
|
|
872
|
+
skill,
|
|
873
|
+
slotConfig,
|
|
874
|
+
header,
|
|
875
|
+
prefix,
|
|
876
|
+
placeholder
|
|
877
|
+
})]
|
|
820
878
|
});
|
|
821
879
|
});
|
|
822
880
|
AgentChat.displayName = "AgentChat";
|
|
823
881
|
//#endregion
|
|
824
|
-
//#region src/ToolCard.tsx
|
|
882
|
+
//#region src/components/ToolCard.tsx
|
|
825
883
|
/**
|
|
826
884
|
* ToolCard 组件 - 用于展示工具调用结果
|
|
827
885
|
* 样式:圆角矩形框,左侧 icon,label 分两行显示(prefix 小字体,content 默认字体)
|