@ai-group/chat-sdk 3.8.0-alpha.1 → 3.8.0-alpha.2
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/cjs/components/XAdkChatbot/index.js +240 -68
- package/dist/cjs/components/XAdkChatbot/index.js.map +3 -3
- package/dist/cjs/components/XAdkChatbot/styles.d.ts +1 -0
- package/dist/cjs/components/XAdkChatbot/styles.js +34 -6
- package/dist/cjs/components/XAdkChatbot/styles.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/Messages.d.ts +7 -1
- package/dist/cjs/components/XAdkProvider/compound/Messages.js +10 -0
- package/dist/cjs/components/XAdkProvider/compound/Messages.js.map +2 -2
- package/dist/cjs/components/XAdkSender/index.js +53 -5
- package/dist/cjs/components/XAdkSender/index.js.map +3 -3
- package/dist/cjs/components/XAdkThoughtChain/index.js +7 -3
- package/dist/cjs/components/XAdkThoughtChain/index.js.map +2 -2
- package/dist/cjs/components/XAdkThoughtChain/styles.d.ts +1 -1
- package/dist/cjs/components/XAdkThoughtChain/styles.js +25 -32
- package/dist/cjs/components/XAdkThoughtChain/styles.js.map +2 -2
- package/dist/cjs/components/XAiChatbot/index.js.map +2 -2
- package/dist/cjs/components/XAiProvider/index.js.map +2 -2
- package/dist/cjs/hooks/useADKMessageQueue.d.ts +4 -2
- package/dist/cjs/hooks/useADKMessageQueue.js +13 -11
- package/dist/cjs/hooks/useADKMessageQueue.js.map +2 -2
- package/dist/cjs/types/XAdkChatbot.d.ts +36 -0
- package/dist/cjs/types/XAdkChatbot.js.map +1 -1
- package/dist/cjs/types/XAdkSender.d.ts +8 -1
- package/dist/cjs/types/XAdkSender.js.map +1 -1
- package/dist/cjs/types/antdx.d.ts +4 -1
- package/dist/cjs/types/antdx.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/index.js +210 -33
- package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/styles.d.ts +1 -0
- package/dist/esm/components/XAdkChatbot/styles.js +30 -29
- package/dist/esm/components/XAdkChatbot/styles.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/Messages.d.ts +7 -1
- package/dist/esm/components/XAdkProvider/compound/Messages.js +11 -1
- package/dist/esm/components/XAdkProvider/compound/Messages.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.js +80 -16
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/esm/components/XAdkThoughtChain/index.js +7 -7
- package/dist/esm/components/XAdkThoughtChain/index.js.map +1 -1
- package/dist/esm/components/XAdkThoughtChain/styles.d.ts +1 -1
- package/dist/esm/components/XAdkThoughtChain/styles.js +14 -14
- package/dist/esm/components/XAdkThoughtChain/styles.js.map +1 -1
- package/dist/esm/components/XAiChatbot/index.js.map +1 -1
- package/dist/esm/components/XAiProvider/index.js.map +1 -1
- package/dist/esm/hooks/useADKMessageQueue.d.ts +4 -2
- package/dist/esm/hooks/useADKMessageQueue.js +12 -10
- package/dist/esm/hooks/useADKMessageQueue.js.map +1 -1
- package/dist/esm/types/XAdkChatbot.d.ts +36 -0
- package/dist/esm/types/XAdkChatbot.js.map +1 -1
- package/dist/esm/types/XAdkSender.d.ts +8 -1
- package/dist/esm/types/XAdkSender.js.map +1 -1
- package/dist/esm/types/antdx.d.ts +4 -1
- package/dist/esm/types/antdx.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -57,7 +57,10 @@ export type BaseNode = React.ReactNode | false;
|
|
|
57
57
|
export type NodeRender = (oriNode: React.ReactNode, info: {
|
|
58
58
|
components: ActionsComponents;
|
|
59
59
|
}) => BaseNode;
|
|
60
|
-
export interface SenderProps extends Partial<Pick<TextareaProps, 'placeholder' | 'onKeyUp' | 'onFocus' | 'onBlur'
|
|
60
|
+
export interface SenderProps extends Omit<Partial<Pick<TextareaProps, 'placeholder' | 'onKeyUp' | 'onFocus' | 'onBlur'>>, 'onKeyUp' | 'onFocus' | 'onBlur'> {
|
|
61
|
+
onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>;
|
|
62
|
+
onFocus?: React.FocusEventHandler<HTMLTextAreaElement>;
|
|
63
|
+
onBlur?: React.FocusEventHandler<HTMLTextAreaElement>;
|
|
61
64
|
prefixCls?: string;
|
|
62
65
|
defaultValue?: string;
|
|
63
66
|
value?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/types/antdx.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @ant-design/x 类型本地声明\n * 从 @ant-design/x 源码提取的公共 API 类型,减少外部依赖\n */\nimport type React from 'react';\nimport type { UploadFile, MenuProps, InputProps } from 'antd';\n\n// ==================== Conversations ====================\n\nexport interface ConversationItemType\n extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick'> {\n key: string;\n label?: React.ReactNode;\n group?: string;\n icon?: React.ReactNode;\n disabled?: boolean;\n [key: string]: any;\n}\n\nexport interface DividerItemType {\n type: 'divider';\n key?: string;\n dashed?: boolean;\n}\n\nexport type ItemType = ConversationItemType | DividerItemType;\n\ntype ConversationsSemanticType = 'root' | 'creation' | 'group' | 'item';\n\nexport interface ConversationsProps extends React.HTMLAttributes<HTMLUListElement> {\n items?: ItemType[];\n activeKey?: ConversationItemType['key'];\n defaultActiveKey?: ConversationItemType['key'];\n onActiveChange?: (value: ConversationItemType['key'], item?: ItemType) => void;\n menu?:\n | (MenuProps & {\n trigger?:\n | React.ReactNode\n | ((\n conversation: ConversationItemType,\n info: { originNode: React.ReactNode },\n ) => React.ReactNode);\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n })\n | ((\n value: ConversationItemType,\n ) => MenuProps & {\n trigger?:\n | React.ReactNode\n | ((\n conversation: ConversationItemType,\n info: { originNode: React.ReactNode },\n ) => React.ReactNode);\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n });\n groupable?: boolean | Record<string, any>;\n styles?: Partial<Record<ConversationsSemanticType, React.CSSProperties>>;\n classNames?: Partial<Record<ConversationsSemanticType, string>>;\n prefixCls?: string;\n rootClassName?: string;\n}\n\n// ==================== Sender ====================\n\ntype TextareaProps = InputProps;\n\ntype SubmitType = 'enter' | 'shiftEnter';\n\ntype SenderSemanticType = 'root' | 'prefix' | 'input' | 'suffix' | 'footer' | 'switch' | 'content';\n\nexport interface SenderComponents {\n input?: React.ComponentType<any>;\n}\n\nexport type ActionsComponents = {\n SendButton: React.ComponentType<any>;\n ClearButton: React.ComponentType<any>;\n LoadingButton: React.ComponentType<any>;\n SpeechButton: React.ComponentType<any>;\n};\n\nexport type BaseNode = React.ReactNode | false;\nexport type NodeRender = (\n oriNode: React.ReactNode,\n info: { components: ActionsComponents },\n) => BaseNode;\n\nexport interface SenderProps\n extends Partial<Pick<TextareaProps, 'placeholder' | 'onKeyUp' | 'onFocus' | 'onBlur'
|
|
4
|
+
"sourcesContent": ["/**\n * @ant-design/x 类型本地声明\n * 从 @ant-design/x 源码提取的公共 API 类型,减少外部依赖\n */\nimport type React from 'react';\nimport type { UploadFile, MenuProps, InputProps } from 'antd';\n\n// ==================== Conversations ====================\n\nexport interface ConversationItemType\n extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick'> {\n key: string;\n label?: React.ReactNode;\n group?: string;\n icon?: React.ReactNode;\n disabled?: boolean;\n [key: string]: any;\n}\n\nexport interface DividerItemType {\n type: 'divider';\n key?: string;\n dashed?: boolean;\n}\n\nexport type ItemType = ConversationItemType | DividerItemType;\n\ntype ConversationsSemanticType = 'root' | 'creation' | 'group' | 'item';\n\nexport interface ConversationsProps extends React.HTMLAttributes<HTMLUListElement> {\n items?: ItemType[];\n activeKey?: ConversationItemType['key'];\n defaultActiveKey?: ConversationItemType['key'];\n onActiveChange?: (value: ConversationItemType['key'], item?: ItemType) => void;\n menu?:\n | (MenuProps & {\n trigger?:\n | React.ReactNode\n | ((\n conversation: ConversationItemType,\n info: { originNode: React.ReactNode },\n ) => React.ReactNode);\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n })\n | ((\n value: ConversationItemType,\n ) => MenuProps & {\n trigger?:\n | React.ReactNode\n | ((\n conversation: ConversationItemType,\n info: { originNode: React.ReactNode },\n ) => React.ReactNode);\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n });\n groupable?: boolean | Record<string, any>;\n styles?: Partial<Record<ConversationsSemanticType, React.CSSProperties>>;\n classNames?: Partial<Record<ConversationsSemanticType, string>>;\n prefixCls?: string;\n rootClassName?: string;\n}\n\n// ==================== Sender ====================\n\ntype TextareaProps = InputProps;\n\ntype SubmitType = 'enter' | 'shiftEnter';\n\ntype SenderSemanticType = 'root' | 'prefix' | 'input' | 'suffix' | 'footer' | 'switch' | 'content';\n\nexport interface SenderComponents {\n input?: React.ComponentType<any>;\n}\n\nexport type ActionsComponents = {\n SendButton: React.ComponentType<any>;\n ClearButton: React.ComponentType<any>;\n LoadingButton: React.ComponentType<any>;\n SpeechButton: React.ComponentType<any>;\n};\n\nexport type BaseNode = React.ReactNode | false;\nexport type NodeRender = (\n oriNode: React.ReactNode,\n info: { components: ActionsComponents },\n) => BaseNode;\n\nexport interface SenderProps\n extends Omit<Partial<Pick<TextareaProps, 'placeholder' | 'onKeyUp' | 'onFocus' | 'onBlur'>>, 'onKeyUp' | 'onFocus' | 'onBlur'> {\n onKeyUp?: React.KeyboardEventHandler<HTMLTextAreaElement>;\n onFocus?: React.FocusEventHandler<HTMLTextAreaElement>;\n onBlur?: React.FocusEventHandler<HTMLTextAreaElement>;\n prefixCls?: string;\n defaultValue?: string;\n value?: string;\n loading?: boolean;\n readOnly?: boolean;\n submitType?: SubmitType;\n disabled?: boolean;\n onSubmit?: (message: string, ...args: any[]) => void;\n onChange?: (value: string, ...args: any[]) => void;\n onCancel?: VoidFunction;\n onKeyDown?: (event: React.KeyboardEvent) => void | false;\n onPaste?: React.ClipboardEventHandler<HTMLElement>;\n onPasteFile?: (files: FileList) => void;\n components?: SenderComponents;\n classNames?: Partial<Record<SenderSemanticType, string>>;\n styles?: Partial<Record<SenderSemanticType, React.CSSProperties>>;\n rootClassName?: string;\n style?: React.CSSProperties;\n className?: string;\n allowSpeech?: any;\n prefix?: BaseNode | NodeRender;\n footer?: BaseNode | NodeRender;\n suffix?: BaseNode | NodeRender;\n header?: BaseNode | NodeRender;\n autoSize?: boolean | { minRows?: number; maxRows?: number };\n slotConfig?: Readonly<any[]>;\n skill?: any;\n}\n\n// ==================== Prompts ====================\n\nexport interface BasePromptsItemType {\n key: string;\n icon?: React.ReactNode;\n label?: React.ReactNode;\n description?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport interface PromptsItemType extends BasePromptsItemType {\n children?: BasePromptsItemType[];\n}\n\ntype PromptsSemanticType =\n | 'root'\n | 'list'\n | 'item'\n | 'itemContent'\n | 'title'\n | 'subList'\n | 'subItem';\n\nexport interface PromptsProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onClick' | 'title'> {\n items?: PromptsItemType[];\n title?: React.ReactNode;\n onClick?: (info: { data: PromptsItemType }) => void;\n styles?: Partial<Record<PromptsSemanticType, React.CSSProperties>>;\n classNames?: Partial<Record<PromptsSemanticType, string>>;\n prefixCls?: string;\n rootClassName?: string;\n vertical?: boolean;\n wrap?: boolean;\n}\n\n// ==================== Attachments ====================\n\nexport interface Attachment<T = any>\n extends UploadFile<T> {\n description?: React.ReactNode;\n cardType?: 'audio' | 'video' | 'image' | 'file';\n}\n\nexport interface AttachmentsRef {\n nativeElement?: HTMLDivElement | null;\n fileNativeElement?: HTMLInputElement | null;\n upload: (file: File) => void;\n select: (options?: { accept?: string; multiple?: boolean }) => void;\n}\n\n// ==================== Think ====================\n\ntype ThinkSemanticType = 'root' | 'header' | 'content' | 'icon';\n\nexport interface ThinkProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n prefixCls?: string;\n style?: React.CSSProperties;\n styles?: Partial<Record<ThinkSemanticType, React.CSSProperties>>;\n className?: string;\n classNames?: Partial<Record<ThinkSemanticType, string>>;\n rootClassName?: string;\n title?: React.ReactNode;\n icon?: React.ReactNode;\n loading?: boolean | React.ReactNode;\n defaultExpanded?: boolean;\n expanded?: boolean;\n onExpand?: (expand: boolean) => void;\n blink?: boolean;\n destroyOnHidden?: boolean;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
2
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
3
|
-
import { useMemo, useCallback, useEffect, useRef, useImperativeHandle, forwardRef } from "react";
|
|
3
|
+
import { useMemo, useCallback, useEffect, useLayoutEffect, useRef, useImperativeHandle, forwardRef, Fragment } from "react";
|
|
4
4
|
import { Button, Flex, Tooltip, message as antdMessage } from "antd";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import { SwapRightOutlined, ReloadOutlined, CopyOutlined, InfoCircleOutlined } from "@ant-design/icons";
|
|
@@ -30,12 +30,16 @@ var scrollThreshold = 10;
|
|
|
30
30
|
* - ✅ 欢迎页面 (agentName/agentIcon/description)
|
|
31
31
|
*/
|
|
32
32
|
var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
33
|
-
var _mergedStrategies$par;
|
|
33
|
+
var _mergedStrategies$par, _history$direction;
|
|
34
34
|
var _ref$loading = _ref.loading,
|
|
35
35
|
loading = _ref$loading === void 0 ? false : _ref$loading,
|
|
36
36
|
prologue = _ref.prologue,
|
|
37
37
|
suggestions = _ref.suggestions,
|
|
38
38
|
messages = _ref.messages,
|
|
39
|
+
renderBeforeGroup = _ref.renderBeforeGroup,
|
|
40
|
+
renderAfterGroup = _ref.renderAfterGroup,
|
|
41
|
+
renderGroup = _ref.renderGroup,
|
|
42
|
+
history = _ref.history,
|
|
39
43
|
showFnCallDetail = _ref.showFnCallDetail,
|
|
40
44
|
onConfirm = _ref.onConfirm,
|
|
41
45
|
onSuggest = _ref.onSuggest,
|
|
@@ -76,6 +80,98 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
76
80
|
var prevInitializedRef = useRef(false);
|
|
77
81
|
var prevSessionIdRef = useRef(sessionId);
|
|
78
82
|
var previousMessageCountRef = useRef(messages.length);
|
|
83
|
+
var historyRef = useRef(history);
|
|
84
|
+
historyRef.current = history;
|
|
85
|
+
var messagesRef = useRef(messages);
|
|
86
|
+
messagesRef.current = messages;
|
|
87
|
+
var historyRequestRef = useRef(false);
|
|
88
|
+
var historyRequestIdRef = useRef(0);
|
|
89
|
+
var historyRequestControllerRef = useRef(null);
|
|
90
|
+
var historyRefreshRef = useRef(false);
|
|
91
|
+
var historyRefreshIdRef = useRef(0);
|
|
92
|
+
var historyRefreshControllerRef = useRef(null);
|
|
93
|
+
var prependAnchorRef = useRef(null);
|
|
94
|
+
var skipNextAutoScrollRef = useRef(false);
|
|
95
|
+
var prependExpiryRef = useRef(null);
|
|
96
|
+
var loadMoreHistory = useCallback(function () {
|
|
97
|
+
var _pagination$direction;
|
|
98
|
+
var pagination = historyRef.current;
|
|
99
|
+
var el = listRef.current;
|
|
100
|
+
if (!(pagination !== null && pagination !== void 0 && pagination.hasMore) || pagination.loading || historyRequestRef.current || !el) return;
|
|
101
|
+
var direction = (_pagination$direction = pagination.direction) !== null && _pagination$direction !== void 0 ? _pagination$direction : "top";
|
|
102
|
+
if (direction === "top") {
|
|
103
|
+
var _currentMessages$;
|
|
104
|
+
if (prependExpiryRef.current) clearTimeout(prependExpiryRef.current);
|
|
105
|
+
var currentMessages = messagesRef.current;
|
|
106
|
+
prependAnchorRef.current = {
|
|
107
|
+
sessionId: prevSessionIdRef.current,
|
|
108
|
+
firstMessageId: (_currentMessages$ = currentMessages[0]) === null || _currentMessages$ === void 0 ? void 0 : _currentMessages$.id,
|
|
109
|
+
messageCount: currentMessages.length,
|
|
110
|
+
scrollTop: el.scrollTop,
|
|
111
|
+
scrollHeight: el.scrollHeight
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
historyRequestRef.current = true;
|
|
115
|
+
var requestId = ++historyRequestIdRef.current;
|
|
116
|
+
var controller = new AbortController();
|
|
117
|
+
historyRequestControllerRef.current = controller;
|
|
118
|
+
void Promise.resolve().then(function () {
|
|
119
|
+
return pagination.onLoadMore({
|
|
120
|
+
signal: controller.signal
|
|
121
|
+
});
|
|
122
|
+
}).catch(function () {
|
|
123
|
+
if (requestId !== historyRequestIdRef.current || controller.signal.aborted) return;
|
|
124
|
+
prependAnchorRef.current = null;
|
|
125
|
+
antdMessage.error("加载历史消息失败,请重试");
|
|
126
|
+
}).finally(function () {
|
|
127
|
+
if (requestId === historyRequestIdRef.current) {
|
|
128
|
+
historyRequestRef.current = false;
|
|
129
|
+
historyRequestControllerRef.current = null;
|
|
130
|
+
// 没有新页时解除滚动锚点,避免后续正常消息被误认为 prepend。
|
|
131
|
+
prependExpiryRef.current = setTimeout(function () {
|
|
132
|
+
prependAnchorRef.current = null;
|
|
133
|
+
prependExpiryRef.current = null;
|
|
134
|
+
}, 500);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}, []);
|
|
138
|
+
var refreshHistory = useCallback(function () {
|
|
139
|
+
var pagination = historyRef.current;
|
|
140
|
+
if (!(pagination !== null && pagination !== void 0 && pagination.onRefresh) || pagination.refreshing || historyRefreshRef.current) return;
|
|
141
|
+
historyRefreshRef.current = true;
|
|
142
|
+
var requestId = ++historyRefreshIdRef.current;
|
|
143
|
+
var controller = new AbortController();
|
|
144
|
+
historyRefreshControllerRef.current = controller;
|
|
145
|
+
void Promise.resolve().then(function () {
|
|
146
|
+
var _pagination$onRefresh;
|
|
147
|
+
return (_pagination$onRefresh = pagination.onRefresh) === null || _pagination$onRefresh === void 0 ? void 0 : _pagination$onRefresh.call(pagination, {
|
|
148
|
+
signal: controller.signal
|
|
149
|
+
});
|
|
150
|
+
}).catch(function () {
|
|
151
|
+
if (!controller.signal.aborted) antdMessage.error("刷新历史消息失败,请重试");
|
|
152
|
+
}).finally(function () {
|
|
153
|
+
if (requestId === historyRefreshIdRef.current) {
|
|
154
|
+
historyRefreshRef.current = false;
|
|
155
|
+
historyRefreshControllerRef.current = null;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}, []);
|
|
159
|
+
useLayoutEffect(function () {
|
|
160
|
+
var _messages$;
|
|
161
|
+
var anchor = prependAnchorRef.current;
|
|
162
|
+
var el = listRef.current;
|
|
163
|
+
if (!anchor || !el) return;
|
|
164
|
+
if (anchor.sessionId !== sessionId) {
|
|
165
|
+
prependAnchorRef.current = null;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (messages.length <= anchor.messageCount || ((_messages$ = messages[0]) === null || _messages$ === void 0 ? void 0 : _messages$.id) === anchor.firstMessageId) return;
|
|
169
|
+
el.scrollTop = anchor.scrollTop + el.scrollHeight - anchor.scrollHeight;
|
|
170
|
+
skipNextAutoScrollRef.current = true;
|
|
171
|
+
prependAnchorRef.current = null;
|
|
172
|
+
if (prependExpiryRef.current) clearTimeout(prependExpiryRef.current);
|
|
173
|
+
prependExpiryRef.current = null;
|
|
174
|
+
}, [messages, sessionId]);
|
|
79
175
|
|
|
80
176
|
// 暴露命令式 API
|
|
81
177
|
var scrollToBottom = useCallback(function () {
|
|
@@ -174,18 +270,40 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
174
270
|
|
|
175
271
|
// 会话切换时重置滚动状态,允许重新触发初始化置底
|
|
176
272
|
useEffect(function () {
|
|
273
|
+
var _historyRequestContro, _historyRefreshContro;
|
|
177
274
|
if (sessionId === undefined) return; // 未传 sessionId 不处理
|
|
178
275
|
if (prevSessionIdRef.current === sessionId) return; // 同一会话不处理
|
|
179
276
|
prevSessionIdRef.current = sessionId;
|
|
180
277
|
prevInitializedRef.current = false;
|
|
181
278
|
userHasScrolledRef.current = false;
|
|
279
|
+
(_historyRequestContro = historyRequestControllerRef.current) === null || _historyRequestContro === void 0 || _historyRequestContro.abort();
|
|
280
|
+
(_historyRefreshContro = historyRefreshControllerRef.current) === null || _historyRefreshContro === void 0 || _historyRefreshContro.abort();
|
|
281
|
+
prependAnchorRef.current = null;
|
|
282
|
+
historyRequestRef.current = false;
|
|
283
|
+
historyRequestIdRef.current += 1;
|
|
284
|
+
historyRefreshRef.current = false;
|
|
285
|
+
historyRefreshIdRef.current += 1;
|
|
286
|
+
if (prependExpiryRef.current) clearTimeout(prependExpiryRef.current);
|
|
287
|
+
prependExpiryRef.current = null;
|
|
182
288
|
}, [sessionId]);
|
|
289
|
+
useEffect(function () {
|
|
290
|
+
return function () {
|
|
291
|
+
var _historyRequestContro2, _historyRefreshContro2;
|
|
292
|
+
(_historyRequestContro2 = historyRequestControllerRef.current) === null || _historyRequestContro2 === void 0 || _historyRequestContro2.abort();
|
|
293
|
+
(_historyRefreshContro2 = historyRefreshControllerRef.current) === null || _historyRefreshContro2 === void 0 || _historyRefreshContro2.abort();
|
|
294
|
+
if (prependExpiryRef.current) clearTimeout(prependExpiryRef.current);
|
|
295
|
+
};
|
|
296
|
+
}, []);
|
|
183
297
|
|
|
184
298
|
// 新增用户消息代表一次主动发送,应无条件恢复跟随并置底。
|
|
185
299
|
// 之后的流式回复继续沿用“用户未主动上滚时跟随”的规则。
|
|
186
300
|
useEffect(function () {
|
|
187
301
|
var previousCount = previousMessageCountRef.current;
|
|
188
302
|
previousMessageCountRef.current = messages.length;
|
|
303
|
+
if (skipNextAutoScrollRef.current || prependAnchorRef.current) {
|
|
304
|
+
skipNextAutoScrollRef.current = false;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
189
307
|
var hasNewUserMessage = messages.slice(previousCount).some(function (message) {
|
|
190
308
|
return message.role === "user";
|
|
191
309
|
});
|
|
@@ -234,8 +352,15 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
234
352
|
if (isAtBottom) {
|
|
235
353
|
userHasScrolledRef.current = false;
|
|
236
354
|
}
|
|
355
|
+
var pagination = historyRef.current;
|
|
356
|
+
if (pagination !== null && pagination !== void 0 && pagination.hasMore) {
|
|
357
|
+
var _pagination$threshold, _pagination$direction2;
|
|
358
|
+
var threshold = (_pagination$threshold = pagination.threshold) !== null && _pagination$threshold !== void 0 ? _pagination$threshold : 80;
|
|
359
|
+
var atLoadEdge = ((_pagination$direction2 = pagination.direction) !== null && _pagination$direction2 !== void 0 ? _pagination$direction2 : "top") === "top" ? currentTop <= threshold : el.scrollHeight - currentTop - el.clientHeight <= threshold;
|
|
360
|
+
if (atLoadEdge) loadMoreHistory();
|
|
361
|
+
}
|
|
237
362
|
lastScrollTopRef.current = currentTop;
|
|
238
|
-
}, []);
|
|
363
|
+
}, [loadMoreHistory]);
|
|
239
364
|
useEffect(function () {
|
|
240
365
|
var listElement = listRef.current;
|
|
241
366
|
if (!listElement) return;
|
|
@@ -245,6 +370,13 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
245
370
|
};
|
|
246
371
|
}, [handleScroll]);
|
|
247
372
|
|
|
373
|
+
// 首屏内容不足一屏时没有滚动事件,继续按需加载直到内容可滚动或数据耗尽。
|
|
374
|
+
useEffect(function () {
|
|
375
|
+
if (!initialized || !(history !== null && history !== void 0 && history.hasMore) || history.loading) return;
|
|
376
|
+
var el = listRef.current;
|
|
377
|
+
if (el && el.scrollHeight <= el.clientHeight + 1) loadMoreHistory();
|
|
378
|
+
}, [history === null || history === void 0 ? void 0 : history.hasMore, history === null || history === void 0 ? void 0 : history.loading, initialized, loadMoreHistory, messages]);
|
|
379
|
+
|
|
248
380
|
// ========== 消息分组逻辑 ==========
|
|
249
381
|
var chatGroups = useMemo(function () {
|
|
250
382
|
if (!enableGrouping) {
|
|
@@ -570,12 +702,25 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
570
702
|
}, [enableProcessParsing, parseOptions, parseProcessMessage, showFnCallDetail, onConfirm, loading, showRetry, showCopy, showLog, onRetry, onCopy, onShowLog, actions, actionsExtra, onFileClick, onResourceLinkClick, renderResourceLink, mergedMarkdownExtensions, resourceLinkSchemes, styles, resolveToolKind, mergedStrategies]);
|
|
571
703
|
|
|
572
704
|
// ========== 渲染用户消息组 ==========
|
|
573
|
-
var renderUserGroup = useCallback(function (group) {
|
|
574
|
-
|
|
705
|
+
var renderUserGroup = useCallback(function (group, nextGroup) {
|
|
706
|
+
var _userActions, _group$msgs;
|
|
707
|
+
var compactWithNextText = group.msgs.some(function (message) {
|
|
708
|
+
var _message$fileData;
|
|
709
|
+
return Boolean((_message$fileData = message.fileData) === null || _message$fileData === void 0 ? void 0 : _message$fileData.length);
|
|
710
|
+
}) && group.msgs.every(function (message) {
|
|
711
|
+
var _message$text;
|
|
712
|
+
return !((_message$text = message.text) !== null && _message$text !== void 0 && _message$text.trim());
|
|
713
|
+
}) && (nextGroup === null || nextGroup === void 0 ? void 0 : nextGroup.role) === "user" && nextGroup.msgs.some(function (message) {
|
|
714
|
+
var _message$text2;
|
|
715
|
+
return Boolean((_message$text2 = message.text) === null || _message$text2 === void 0 ? void 0 : _message$text2.trim());
|
|
716
|
+
});
|
|
717
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
575
718
|
className: styles.userMsg,
|
|
576
719
|
"data-message-id": group.id,
|
|
577
|
-
|
|
578
|
-
|
|
720
|
+
style: compactWithNextText ? {
|
|
721
|
+
marginBottom: 8
|
|
722
|
+
} : undefined,
|
|
723
|
+
children: [group.msgs.map(function (m, i) {
|
|
579
724
|
return /*#__PURE__*/_jsxs("div", {
|
|
580
725
|
className: styles.userContainer,
|
|
581
726
|
children: [m.fileData && m.fileData.length > 0 && /*#__PURE__*/_jsx(_Fragment, {
|
|
@@ -584,7 +729,7 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
584
729
|
file: file,
|
|
585
730
|
align: "left",
|
|
586
731
|
style: {
|
|
587
|
-
marginBottom:
|
|
732
|
+
marginBottom: compactWithNextText && i === group.msgs.length - 1 && index === m.fileData.length - 1 ? 0 : 16
|
|
588
733
|
},
|
|
589
734
|
onClick: onFileClick
|
|
590
735
|
}, index);
|
|
@@ -611,30 +756,36 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
611
756
|
renderResourceLink: renderResourceLink,
|
|
612
757
|
markdownExtensions: mergedMarkdownExtensions
|
|
613
758
|
})
|
|
614
|
-
}), showUserActions && /*#__PURE__*/_jsx("div", {
|
|
615
|
-
className: "x-user-actions ".concat(styles.userActions),
|
|
616
|
-
children: (_userActions = userActions === null || userActions === void 0 ? void 0 : userActions({
|
|
617
|
-
message: group
|
|
618
|
-
})) !== null && _userActions !== void 0 ? _userActions : /*#__PURE__*/_jsxs(_Fragment, {
|
|
619
|
-
children: [/*#__PURE__*/_jsx("span", {
|
|
620
|
-
className: styles.userTime,
|
|
621
|
-
children: formatTimestamp(m.timestamp)
|
|
622
|
-
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
623
|
-
title: "\u590D\u5236\u5185\u5BB9",
|
|
624
|
-
children: /*#__PURE__*/_jsx(CopyOutlined, {
|
|
625
|
-
className: styles.userActionIcon,
|
|
626
|
-
onClick: function onClick() {
|
|
627
|
-
var card = document.querySelector("[data-message-id=\"".concat(group.id, "\"] [data-xadk-user-card]"));
|
|
628
|
-
var selected = getSelectionText(card);
|
|
629
|
-
copy(selected || m.text || "");
|
|
630
|
-
antdMessage.success("复制成功");
|
|
631
|
-
}
|
|
632
|
-
})
|
|
633
|
-
})]
|
|
634
|
-
})
|
|
635
759
|
})]
|
|
636
760
|
}, m.id || i);
|
|
637
|
-
})
|
|
761
|
+
}), showUserActions && group.msgs.some(function (message) {
|
|
762
|
+
var _message$text3;
|
|
763
|
+
return Boolean((_message$text3 = message.text) === null || _message$text3 === void 0 ? void 0 : _message$text3.trim());
|
|
764
|
+
}) && /*#__PURE__*/_jsx("div", {
|
|
765
|
+
className: "x-user-actions ".concat(styles.userActions),
|
|
766
|
+
children: (_userActions = userActions === null || userActions === void 0 ? void 0 : userActions({
|
|
767
|
+
message: group
|
|
768
|
+
})) !== null && _userActions !== void 0 ? _userActions : /*#__PURE__*/_jsxs(_Fragment, {
|
|
769
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
770
|
+
className: styles.userTime,
|
|
771
|
+
children: formatTimestamp((_group$msgs = group.msgs[group.msgs.length - 1]) === null || _group$msgs === void 0 ? void 0 : _group$msgs.timestamp)
|
|
772
|
+
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
773
|
+
title: "\u590D\u5236\u5185\u5BB9",
|
|
774
|
+
children: /*#__PURE__*/_jsx(CopyOutlined, {
|
|
775
|
+
className: styles.userActionIcon,
|
|
776
|
+
onClick: function onClick() {
|
|
777
|
+
var container = document.querySelector("[data-message-id=\"".concat(group.id, "\"]"));
|
|
778
|
+
var selected = getSelectionText(container);
|
|
779
|
+
var fullText = group.msgs.map(function (message) {
|
|
780
|
+
return message.text || "";
|
|
781
|
+
}).join("");
|
|
782
|
+
copy(selected || fullText);
|
|
783
|
+
antdMessage.success("复制成功");
|
|
784
|
+
}
|
|
785
|
+
})
|
|
786
|
+
})]
|
|
787
|
+
})
|
|
788
|
+
})]
|
|
638
789
|
}, group.id);
|
|
639
790
|
}, [styles, onFileClick, onResourceLinkClick, renderResourceLink, mergedMarkdownExtensions, resourceLinkSchemes, showUserActions, userActions]);
|
|
640
791
|
|
|
@@ -676,6 +827,20 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
676
827
|
|
|
677
828
|
// 空状态判断
|
|
678
829
|
var isEmpty = messages.length === 0 && !prologue && (!suggestions || suggestions.length === 0);
|
|
830
|
+
var historyControls = history && (history.hasMore || history.loading || history.onRefresh) && /*#__PURE__*/_jsxs("div", {
|
|
831
|
+
className: styles.historyControls,
|
|
832
|
+
children: [history.onRefresh && /*#__PURE__*/_jsx("button", {
|
|
833
|
+
type: "button",
|
|
834
|
+
onClick: refreshHistory,
|
|
835
|
+
disabled: history.refreshing,
|
|
836
|
+
children: history.refreshing ? "正在刷新..." : "刷新"
|
|
837
|
+
}), (history.hasMore || history.loading) && /*#__PURE__*/_jsx("button", {
|
|
838
|
+
type: "button",
|
|
839
|
+
onClick: loadMoreHistory,
|
|
840
|
+
disabled: history.loading,
|
|
841
|
+
children: history.loading ? "正在加载..." : "加载更多"
|
|
842
|
+
})]
|
|
843
|
+
});
|
|
679
844
|
return /*#__PURE__*/_jsxs("div", {
|
|
680
845
|
className: clsx(styles.wrapper, className),
|
|
681
846
|
style: style,
|
|
@@ -688,7 +853,7 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
688
853
|
style: isEmpty ? {
|
|
689
854
|
flex: 0
|
|
690
855
|
} : undefined,
|
|
691
|
-
children: [prologue && /*#__PURE__*/_jsx("div", {
|
|
856
|
+
children: [((_history$direction = history === null || history === void 0 ? void 0 : history.direction) !== null && _history$direction !== void 0 ? _history$direction : "top") === "top" && historyControls, prologue && /*#__PURE__*/_jsx("div", {
|
|
692
857
|
className: styles.prologue,
|
|
693
858
|
children: /*#__PURE__*/_jsx(MarkdownRender, {
|
|
694
859
|
text: prologue,
|
|
@@ -699,8 +864,20 @@ var XAdkChatbot = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
699
864
|
markdownExtensions: mergedMarkdownExtensions
|
|
700
865
|
})
|
|
701
866
|
}), chatGroups.map(function (group, idx) {
|
|
702
|
-
|
|
703
|
-
|
|
867
|
+
var context = {
|
|
868
|
+
group: group,
|
|
869
|
+
index: idx,
|
|
870
|
+
previousGroup: chatGroups[idx - 1],
|
|
871
|
+
nextGroup: chatGroups[idx + 1]
|
|
872
|
+
};
|
|
873
|
+
var defaultNode = group.role === "user" ? renderUserGroup(group, chatGroups[idx + 1]) : renderBotGroup(group, idx === chatGroups.length - 1, renderFunctionCall);
|
|
874
|
+
var customNode = renderGroup === null || renderGroup === void 0 ? void 0 : renderGroup(_objectSpread(_objectSpread({}, context), {}, {
|
|
875
|
+
defaultNode: defaultNode
|
|
876
|
+
}));
|
|
877
|
+
return /*#__PURE__*/_jsxs(Fragment, {
|
|
878
|
+
children: [renderBeforeGroup === null || renderBeforeGroup === void 0 ? void 0 : renderBeforeGroup(context), customNode === undefined ? defaultNode : customNode, renderAfterGroup === null || renderAfterGroup === void 0 ? void 0 : renderAfterGroup(context)]
|
|
879
|
+
}, group.id);
|
|
880
|
+
}), (history === null || history === void 0 ? void 0 : history.direction) === "bottom" && historyControls, renderSuggestions(), /*#__PURE__*/_jsx("div", {
|
|
704
881
|
ref: messagesEndRef
|
|
705
882
|
})]
|
|
706
883
|
})]
|