@ai-group/chat-sdk 3.8.0-alpha.1 → 3.8.0-alpha.3

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.
Files changed (55) hide show
  1. package/README.md +42 -2
  2. package/dist/cjs/components/XAdkChatbot/index.js +240 -68
  3. package/dist/cjs/components/XAdkChatbot/index.js.map +3 -3
  4. package/dist/cjs/components/XAdkChatbot/styles.d.ts +1 -0
  5. package/dist/cjs/components/XAdkChatbot/styles.js +34 -6
  6. package/dist/cjs/components/XAdkChatbot/styles.js.map +2 -2
  7. package/dist/cjs/components/XAdkProvider/compound/Messages.d.ts +7 -1
  8. package/dist/cjs/components/XAdkProvider/compound/Messages.js +10 -0
  9. package/dist/cjs/components/XAdkProvider/compound/Messages.js.map +2 -2
  10. package/dist/cjs/components/XAdkSender/index.js +69 -5
  11. package/dist/cjs/components/XAdkSender/index.js.map +3 -3
  12. package/dist/cjs/components/XAdkThoughtChain/index.js +7 -3
  13. package/dist/cjs/components/XAdkThoughtChain/index.js.map +2 -2
  14. package/dist/cjs/components/XAdkThoughtChain/styles.d.ts +1 -1
  15. package/dist/cjs/components/XAdkThoughtChain/styles.js +25 -32
  16. package/dist/cjs/components/XAdkThoughtChain/styles.js.map +2 -2
  17. package/dist/cjs/components/XAiChatbot/index.js.map +2 -2
  18. package/dist/cjs/components/XAiProvider/index.js.map +2 -2
  19. package/dist/cjs/hooks/useADKMessageQueue.d.ts +4 -2
  20. package/dist/cjs/hooks/useADKMessageQueue.js +13 -11
  21. package/dist/cjs/hooks/useADKMessageQueue.js.map +2 -2
  22. package/dist/cjs/types/XAdkChatbot.d.ts +36 -0
  23. package/dist/cjs/types/XAdkChatbot.js.map +1 -1
  24. package/dist/cjs/types/XAdkSender.d.ts +20 -1
  25. package/dist/cjs/types/XAdkSender.js.map +1 -1
  26. package/dist/cjs/types/antdx.d.ts +4 -1
  27. package/dist/cjs/types/antdx.js.map +1 -1
  28. package/dist/esm/components/XAdkChatbot/index.js +210 -33
  29. package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
  30. package/dist/esm/components/XAdkChatbot/styles.d.ts +1 -0
  31. package/dist/esm/components/XAdkChatbot/styles.js +30 -29
  32. package/dist/esm/components/XAdkChatbot/styles.js.map +1 -1
  33. package/dist/esm/components/XAdkProvider/compound/Messages.d.ts +7 -1
  34. package/dist/esm/components/XAdkProvider/compound/Messages.js +11 -1
  35. package/dist/esm/components/XAdkProvider/compound/Messages.js.map +1 -1
  36. package/dist/esm/components/XAdkSender/index.js +94 -16
  37. package/dist/esm/components/XAdkSender/index.js.map +1 -1
  38. package/dist/esm/components/XAdkThoughtChain/index.js +7 -7
  39. package/dist/esm/components/XAdkThoughtChain/index.js.map +1 -1
  40. package/dist/esm/components/XAdkThoughtChain/styles.d.ts +1 -1
  41. package/dist/esm/components/XAdkThoughtChain/styles.js +14 -14
  42. package/dist/esm/components/XAdkThoughtChain/styles.js.map +1 -1
  43. package/dist/esm/components/XAiChatbot/index.js.map +1 -1
  44. package/dist/esm/components/XAiProvider/index.js.map +1 -1
  45. package/dist/esm/hooks/useADKMessageQueue.d.ts +4 -2
  46. package/dist/esm/hooks/useADKMessageQueue.js +12 -10
  47. package/dist/esm/hooks/useADKMessageQueue.js.map +1 -1
  48. package/dist/esm/types/XAdkChatbot.d.ts +36 -0
  49. package/dist/esm/types/XAdkChatbot.js.map +1 -1
  50. package/dist/esm/types/XAdkSender.d.ts +20 -1
  51. package/dist/esm/types/XAdkSender.js.map +1 -1
  52. package/dist/esm/types/antdx.d.ts +4 -1
  53. package/dist/esm/types/antdx.js.map +1 -1
  54. package/dist/umd/chat-sdk.min.js +1 -1
  55. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/XAiChatbot/index.tsx"],
4
- "sourcesContent": ["// 文件: components/XAiChatbot/index.tsx\n\nimport React, { useRef, useState, useMemo } from \"react\";\nimport { Tooltip, GetProp, Flex } from \"antd\";\nimport { Bubble, Prompts, FileCard } from \"@ant-design/x\";\nimport type { BubbleListProps } from \"@ant-design/x/es/bubble/interface\";\nimport {\n UserOutlined,\n RedoOutlined,\n CopyOutlined,\n DeleteOutlined,\n} from \"@ant-design/icons\";\nimport clsx from \"clsx\";\nimport MarkdownIt from \"markdown-it\";\nimport reactHtmlParser from \"react-html-parser\";\nimport type { Attachment } from \"@/types/antdx\";\nimport MarkdownGlobalStyle from \"@/styles/markdown\";\nimport { MessageStatus, MessageRole, Messages } from \"@/types/XAiMessage\";\nimport { XAiChatbotProps, ActionItem } from \"@/types/XAiChatbot\";\nimport emptyIcon from \"@/assets/empty.png\";\nimport arrowUp from \"@/assets/arrow-up.png\";\nimport arrowDown from \"@/assets/arrow-down.png\";\nimport thinkIcon from \"@/assets/think.png\";\nimport groupIcon from \"@/assets/group.png\";\nimport arrowDownBlue from \"@/assets/arrow-down-blue.png\";\nimport { useChatbotContext } from \"@/hooks/useProviderContext\";\nimport { useStyles, GlobalStyle } from \"./styles\";\nimport XAiSender from \"../XAiSender\";\nimport type { SendContent } from \"@/types\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n typographer: true,\n});\n\n// 自定义 link_open 渲染规则\nconst defaultRender =\n md.renderer.rules.link_open ||\n ((tokens, idx, options, env, self) => {\n return self.renderToken(tokens, idx, options);\n });\n\n// a 标签打开规则\nmd.renderer.rules.link_open = (tokens, idx, options, env, self) => {\n // 添加 target=\"_blank\"\n const aIndex = tokens[idx].attrIndex(\"target\");\n if (aIndex < 0) {\n tokens[idx].attrPush([\"target\", \"_blank\"]);\n } else {\n tokens[idx].attrs![aIndex][1] = \"_blank\";\n }\n // 添加 rel=\"noopener noreferrer\"\n const relIndex = tokens[idx].attrIndex(\"rel\");\n if (relIndex < 0) {\n tokens[idx].attrPush([\"rel\", \"noopener noreferrer\"]);\n } else {\n tokens[idx].attrs![relIndex][1] = \"noopener noreferrer\";\n }\n return defaultRender(tokens, idx, options, env, self);\n};\n\nexport interface ActionHeaderProps {\n execute: any[];\n thinks: string;\n}\n\n// ActionHeader 组件\nexport const ActionHeader: React.FC<ActionHeaderProps> = ({\n execute = [],\n thinks = \"\",\n}) => {\n const styles = useStyles();\n const [expanded, setExpanded] = useState(true);\n const [executeExpanded, setExecuteExpanded] = useState(false);\n\n // 关键修复:只要有思考内容或执行过程就显示,不要同时要求两者都有\n if (!thinks && (!execute || execute.length === 0)) return null;\n\n const last = execute[execute.length - 1] || {};\n const { name } = last;\n const icon = last?.icon || last?.extra?.icon;\n\n return (\n <div className={styles.actionHeaderWrapper}>\n {!expanded && (\n <div\n className={styles.actionTitle}\n onClick={() => setExpanded((v) => !v)}\n >\n <img src={thinkIcon} alt=\"icon\" className={styles.actionHeaderIcon} />\n <span className={styles.flex1}>运行过程</span>\n <img alt=\"展开icon\" src={arrowDown} className={styles.w(\"16px\")} />\n </div>\n )}\n {expanded && (\n <div className={styles.actionHeaderDetail}>\n <div\n className={styles.actionDetailTitle}\n onClick={() => setExpanded((v) => !v)}\n >\n <img src={thinkIcon} alt=\"\" className={clsx(styles.w(14))} />\n <div className={clsx(styles.flex1, styles.pl(10))}>\n 隐藏运行过程\n </div>\n <img alt=\"收起icon\" src={arrowUp} className={styles.w(\"16px\")} />\n </div>\n\n {thinks && (\n <div\n className={styles.actionDetailContent}\n style={{ whiteSpace: \"pre-line\" }}\n >\n {thinks}\n </div>\n )}\n\n {execute && execute.length > 0 && (\n <>\n {!executeExpanded && (\n <div\n className={styles.executeHiddenWrapper}\n onClick={() => setExecuteExpanded((v) => !v)}\n >\n {icon && (\n <img src={icon} alt=\"icon\" className={styles.h(15)} />\n )}\n <span className={styles.flex1}>{name}</span>\n <img\n alt=\"工具icon\"\n src={arrowDownBlue}\n className={styles.w(\"16px\")}\n />\n </div>\n )}\n {executeExpanded && (\n <div className={styles.executeWrapper}>\n <div\n className={styles.executeTitle}\n onClick={() => setExecuteExpanded((v) => !v)}\n >\n <img\n src={groupIcon}\n alt=\"icon\"\n className={styles.executeHeaderIcon}\n />\n <span className={styles.flex1}>隐藏运行详情</span>\n <img\n alt=\"展开详情icon\"\n src={arrowUp}\n className={styles.w(\"16px\")}\n />\n </div>\n <div className={styles.executeContent}>\n {execute.map((action: any, idx: number) => {\n const thinkIcon2 =\n action?.expandIcon ||\n action?.extra?.expandIcon ||\n action?.extra?.icon ||\n action?.icon;\n const thinkCost = action?.cost || action?.extra?.cost;\n return (\n <div\n key={action.uniqueId || idx}\n className={styles.actionHeaderDetailItem}\n >\n {thinkIcon2 && (\n <img\n src={thinkIcon2}\n alt=\"icon\"\n className={styles.actionHeaderIcon}\n />\n )}\n <span>{action?.name}</span>\n <span className={styles.actionHeaderCost}>\n {thinkCost ? `${thinkCost}s` : \"\"}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n};\n\n// 默认消息功能区\nexport const defaultActions: ActionItem[] = [\n {\n key: \"redo\",\n icon: <RedoOutlined />,\n tooltip: \"重新生成\",\n },\n {\n key: \"copy\",\n icon: <CopyOutlined />,\n tooltip: \"复制\",\n },\n {\n key: \"delete\",\n icon: <DeleteOutlined />,\n tooltip: \"删除\",\n },\n];\n\nconst XAiChatbot: React.FC<XAiChatbotProps> = (props) => {\n const styles = useStyles();\n // 使用新的 Hook 来处理 Provider 上下文\n const { mergedProps } = useChatbotContext(props);\n\n const {\n navbarShow = false,\n navbar,\n renderNavbar = null,\n clearBtnShow = true,\n inputShow = true,\n // renderMessageContent,\n // quickReplies = [],\n // quickRepliesVisible = true,\n // onQuickReplyClick,\n loading: propLoading = false,\n messageTooltip,\n avatar,\n userAvatar,\n messages: propMessages,\n text = \"\",\n footerTips = \"\",\n empty = null,\n emptyStateImage = emptyIcon,\n emptyStateText = \"我的智能体\",\n messageActions = defaultActions,\n onMessagesActionsCallback,\n // 点击帮助消息\n onSuggestMessageClick,\n onSend,\n onClear,\n onStop,\n providerId,\n // 消息顶部\n messageTop,\n enableUpload,\n uploadRequest,\n } = mergedProps as XAiChatbotProps;\n\n // 如果在 Provider 中,使用 Provider 的状态\n const messages = mergedProps.messages || propMessages || [];\n const loading = mergedProps.loading || propLoading;\n\n const [content, setContent] = useState<string>(text); // 输入框文本\n const [files, setFiles] = useState<Attachment[]>([]);\n const lastMessageId = useRef<string>(\"\");\n const isScriptScrolling = useRef<boolean>(false);\n const chatId = providerId\n ? `za-chatbot-container-${providerId}`\n : \"za-chatbot-container\";\n\n // 滚动到最底部\n const scrollToBottom = () => {\n isScriptScrolling.current = true;\n setTimeout(() => {\n const mainChatWrapper = document.getElementById(chatId);\n if (mainChatWrapper) {\n mainChatWrapper.scrollTop = mainChatWrapper?.scrollHeight;\n }\n isScriptScrolling.current = false;\n }, 0);\n };\n\n // 消息功能区组件\n const FooterActions: React.FC<{ data: Messages; lastMessage: boolean }> = ({\n data,\n lastMessage = false,\n }) => (\n <div className={clsx(styles.flex, styles.gap(13))}>\n {messageActions.map((action: ActionItem, index: number) => {\n if (!lastMessage && action.key === \"redo\") return null;\n return (\n <Tooltip key={action.key} title={action.tooltip}>\n <span\n className={styles.cursor(\"pointer\")}\n onClick={() => onMessagesActionsCallback?.(index, data)}\n >\n {action.icon}\n {action.render?.(index, data)}\n </span>\n </Tooltip>\n );\n })}\n </div>\n );\n\n // 消息底部区域\n const MessageFooter: React.FC<{ data: Messages; lastMessage: boolean }> = ({\n data,\n lastMessage = false,\n }) => (\n <>\n {messageTooltip?.(data)}\n <FooterActions data={data} lastMessage={lastMessage} />\n </>\n );\n\n // 聊天角色\n const rolesObject: NonNullable<BubbleListProps[\"role\"]> = {\n assistant: {\n placement: \"start\",\n avatar: () => {\n return (\n avatar || (\n <UserOutlined\n className={clsx(styles.bg(\"#fde3cf\"), styles.userAvatar)}\n />\n )\n );\n },\n typing: { step: 5, interval: 20, effect: \"typing\" },\n style: {\n maxWidth: 600,\n },\n classNames: {\n content: \"assistant-content\",\n },\n },\n user: {\n placement: \"end\",\n avatar: () => {\n return (\n userAvatar || (\n <UserOutlined\n className={clsx(styles.bg(\"#87d068\"), styles.userAvatar)}\n />\n )\n );\n },\n classNames: {\n content: \"user-content\",\n },\n },\n suggestion: {\n placement: \"start\",\n avatar: () => {\n return (\n avatar || (\n <UserOutlined\n className={clsx(styles.bg(\"#fde3cf\"), styles.userAvatar)}\n />\n )\n );\n },\n variant: \"borderless\",\n },\n };\n\n // 触发发送\n const handleSend = (obj: SendContent) => {\n // 直接使用合并后的 onSend,自动处理 Provider 和独立模式\n onSend?.(obj);\n setContent(\"\"); // 发送后清空输入框内容\n setFiles([]); // 发送后清空文件\n scrollToBottom();\n };\n\n // 输出内容\n const handleChange = (str: string) => {\n setContent(str);\n };\n\n // 停止生成\n const handleStop = () => {\n onStop?.();\n };\n\n // 导航栏\n const NavBar: React.FC = () => {\n if (renderNavbar) {\n return renderNavbar();\n }\n if (navbar?.title) {\n return (\n <header className={styles.navbar}>\n {navbar.avatar && (\n <img src={navbar.avatar} className={styles.avatar} alt=\"\" />\n )}\n <div>\n <div className={styles.title}>{navbar.title}</div>\n <div className={styles.subtitle}>{navbar.subtitle}</div>\n </div>\n </header>\n );\n }\n return <></>;\n };\n\n // 确认清除\n const confirmClear = () => {\n onClear?.();\n };\n\n // 空状态\n const EmptyState = useMemo(\n () => () =>\n empty || (\n <div className={styles.emptyWrapper}>\n <img\n src={emptyStateImage}\n alt=\"空状态图标\"\n className={styles.emptyImg}\n />\n <div\n className={clsx(\n styles.text(16),\n styles.weight(600),\n styles.textColor(\"#343434\"),\n )}\n >\n {emptyStateText}\n </div>\n </div>\n ),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [emptyStateImage, emptyStateText],\n );\n\n return (\n <>\n <GlobalStyle />\n <MarkdownGlobalStyle />\n <div id=\"x-ai-chatbot\" className={styles.wrapper}>\n {navbarShow && <NavBar />}\n {/** 消息容器 */}\n <div className={styles.messageContainer}>\n {/* 消息列表主体 */}\n {messages?.length ? (\n <Bubble.List\n id={chatId}\n role={rolesObject}\n className={styles.messageList}\n items={messages.map((msg: any) => {\n const {\n id,\n role,\n status,\n type,\n execute = [],\n thinks = \"\",\n extra = { noFooter: false },\n stepContent,\n } = msg as Messages;\n // 最后一条 AI消息标识\n if (role === MessageRole.assistant) {\n lastMessageId.current = id;\n }\n // 会话内容\n const bubbleContent: any = {\n key: id,\n role,\n loading: status === MessageStatus.init,\n header: () =>\n messageTop || (\n <ActionHeader execute={execute} thinks={thinks} />\n ),\n content: (() => {\n // 文本消息\n if (type === \"TextMessage\") {\n // 用户消息\n if (role === \"user\") {\n return (\n <div\n className=\"ai-markdown-body\"\n style={{\n minWidth: 0,\n maxWidth: 600,\n }}\n >\n {msg.content?.text}\n </div>\n );\n }\n\n // 输出html字符串\n const html = md.render(msg.content?.text || \"\");\n // 生成React节点\n const htmlString = reactHtmlParser(html);\n return (\n <>\n {/* 输出阶段性回答内容 */}\n {stepContent?.length &&\n stepContent.map((item) => {\n // 输出html字符串\n const html2 = md.render(item.content || \"\");\n // 生成React节点\n const stepHtmlString = reactHtmlParser(html2);\n return (\n <div\n key={item.id}\n className=\"ai-markdown-body step-content\"\n style={{\n minWidth: 0,\n maxWidth: 600,\n }}\n >\n <div>{stepHtmlString}</div>\n <div className={styles.stepLine} />\n </div>\n );\n })}\n {/** 输出最终回答内容 */}\n <div\n className=\"ai-markdown-body\"\n style={{\n minWidth: 0,\n maxWidth: 600,\n }}\n >\n {htmlString}\n </div>\n </>\n );\n }\n // 提示类型\n if (type === \"SuggestionMessage\") {\n return (\n <Prompts\n vertical\n items={msg.content as any}\n onItemClick={(info: { data: { description?: string; key: string; [key: string]: any } }) => {\n onSuggestMessageClick?.(info?.data, id);\n if (info.data.description) {\n onSend?.({\n text: info.data.description as string,\n });\n }\n }}\n />\n );\n }\n // 其他类型...\n return null;\n })(),\n };\n\n if (!extra.noFooter) {\n bubbleContent.footer = () => {\n const msgFiles = msg.content?.files || [];\n if (role === MessageRole.user && msgFiles.length) {\n return (\n <Flex gap={8} wrap justify=\"flex-end\">\n {msgFiles.map((f: any) => (\n <FileCard\n styles={{\n file:\n f?.fileType === \"image\"\n ? {\n width: 100,\n height: 100,\n }\n : {},\n }}\n key={f.fileId}\n {...f}\n name={f.fileName}\n size={f.fileSize}\n type={f.fileType}\n src={f.fileUrl}\n />\n ))}\n </Flex>\n );\n }\n if (\n role === MessageRole.assistant &&\n status !== MessageStatus.failed\n ) {\n return (\n <MessageFooter\n data={msg as Messages}\n lastMessage={lastMessageId.current === id}\n />\n );\n }\n };\n }\n\n return bubbleContent;\n })}\n />\n ) : (\n <EmptyState />\n )}\n </div>\n {/* 输入框 */}\n {inputShow && (\n <XAiSender\n value={content}\n loading={loading}\n footerTips={footerTips}\n clearBtnShow={clearBtnShow}\n enableUpload={enableUpload}\n files={files}\n onChangeFiles={setFiles}\n uploadRequest={uploadRequest}\n onChange={handleChange}\n onSubmit={handleSend}\n onStop={handleStop}\n onClear={confirmClear}\n />\n )}\n </div>\n </>\n );\n};\n\nexport default XAiChatbot;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// 文件: components/XAiChatbot/index.tsx\n\nimport React, { useRef, useState, useMemo } from \"react\";\nimport { Tooltip, GetProp, Flex } from \"antd\";\nimport { Bubble, Prompts, FileCard } from \"@ant-design/x\";\nimport type { BubbleListProps } from \"@ant-design/x/es/bubble/interface\";\nimport {\n UserOutlined,\n RedoOutlined,\n CopyOutlined,\n DeleteOutlined,\n} from \"@ant-design/icons\";\nimport clsx from \"clsx\";\nimport MarkdownIt from \"markdown-it\";\nimport reactHtmlParser from \"react-html-parser\";\nimport type { Attachment, PromptsItemType } from \"@/types/antdx\";\nimport MarkdownGlobalStyle from \"@/styles/markdown\";\nimport { MessageStatus, MessageRole, Messages } from \"@/types/XAiMessage\";\nimport { XAiChatbotProps, ActionItem } from \"@/types/XAiChatbot\";\nimport emptyIcon from \"@/assets/empty.png\";\nimport arrowUp from \"@/assets/arrow-up.png\";\nimport arrowDown from \"@/assets/arrow-down.png\";\nimport thinkIcon from \"@/assets/think.png\";\nimport groupIcon from \"@/assets/group.png\";\nimport arrowDownBlue from \"@/assets/arrow-down-blue.png\";\nimport { useChatbotContext } from \"@/hooks/useProviderContext\";\nimport { useStyles, GlobalStyle } from \"./styles\";\nimport XAiSender from \"../XAiSender\";\nimport type { SendContent } from \"@/types\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n typographer: true,\n});\n\n// 自定义 link_open 渲染规则\nconst defaultRender =\n md.renderer.rules.link_open ||\n ((tokens, idx, options, env, self) => {\n return self.renderToken(tokens, idx, options);\n });\n\n// a 标签打开规则\nmd.renderer.rules.link_open = (tokens, idx, options, env, self) => {\n // 添加 target=\"_blank\"\n const aIndex = tokens[idx].attrIndex(\"target\");\n if (aIndex < 0) {\n tokens[idx].attrPush([\"target\", \"_blank\"]);\n } else {\n tokens[idx].attrs![aIndex][1] = \"_blank\";\n }\n // 添加 rel=\"noopener noreferrer\"\n const relIndex = tokens[idx].attrIndex(\"rel\");\n if (relIndex < 0) {\n tokens[idx].attrPush([\"rel\", \"noopener noreferrer\"]);\n } else {\n tokens[idx].attrs![relIndex][1] = \"noopener noreferrer\";\n }\n return defaultRender(tokens, idx, options, env, self);\n};\n\nexport interface ActionHeaderProps {\n execute: any[];\n thinks: string;\n}\n\n// ActionHeader 组件\nexport const ActionHeader: React.FC<ActionHeaderProps> = ({\n execute = [],\n thinks = \"\",\n}) => {\n const styles = useStyles();\n const [expanded, setExpanded] = useState(true);\n const [executeExpanded, setExecuteExpanded] = useState(false);\n\n // 关键修复:只要有思考内容或执行过程就显示,不要同时要求两者都有\n if (!thinks && (!execute || execute.length === 0)) return null;\n\n const last = execute[execute.length - 1] || {};\n const { name } = last;\n const icon = last?.icon || last?.extra?.icon;\n\n return (\n <div className={styles.actionHeaderWrapper}>\n {!expanded && (\n <div\n className={styles.actionTitle}\n onClick={() => setExpanded((v) => !v)}\n >\n <img src={thinkIcon} alt=\"icon\" className={styles.actionHeaderIcon} />\n <span className={styles.flex1}>运行过程</span>\n <img alt=\"展开icon\" src={arrowDown} className={styles.w(\"16px\")} />\n </div>\n )}\n {expanded && (\n <div className={styles.actionHeaderDetail}>\n <div\n className={styles.actionDetailTitle}\n onClick={() => setExpanded((v) => !v)}\n >\n <img src={thinkIcon} alt=\"\" className={clsx(styles.w(14))} />\n <div className={clsx(styles.flex1, styles.pl(10))}>\n 隐藏运行过程\n </div>\n <img alt=\"收起icon\" src={arrowUp} className={styles.w(\"16px\")} />\n </div>\n\n {thinks && (\n <div\n className={styles.actionDetailContent}\n style={{ whiteSpace: \"pre-line\" }}\n >\n {thinks}\n </div>\n )}\n\n {execute && execute.length > 0 && (\n <>\n {!executeExpanded && (\n <div\n className={styles.executeHiddenWrapper}\n onClick={() => setExecuteExpanded((v) => !v)}\n >\n {icon && (\n <img src={icon} alt=\"icon\" className={styles.h(15)} />\n )}\n <span className={styles.flex1}>{name}</span>\n <img\n alt=\"工具icon\"\n src={arrowDownBlue}\n className={styles.w(\"16px\")}\n />\n </div>\n )}\n {executeExpanded && (\n <div className={styles.executeWrapper}>\n <div\n className={styles.executeTitle}\n onClick={() => setExecuteExpanded((v) => !v)}\n >\n <img\n src={groupIcon}\n alt=\"icon\"\n className={styles.executeHeaderIcon}\n />\n <span className={styles.flex1}>隐藏运行详情</span>\n <img\n alt=\"展开详情icon\"\n src={arrowUp}\n className={styles.w(\"16px\")}\n />\n </div>\n <div className={styles.executeContent}>\n {execute.map((action: any, idx: number) => {\n const thinkIcon2 =\n action?.expandIcon ||\n action?.extra?.expandIcon ||\n action?.extra?.icon ||\n action?.icon;\n const thinkCost = action?.cost || action?.extra?.cost;\n return (\n <div\n key={action.uniqueId || idx}\n className={styles.actionHeaderDetailItem}\n >\n {thinkIcon2 && (\n <img\n src={thinkIcon2}\n alt=\"icon\"\n className={styles.actionHeaderIcon}\n />\n )}\n <span>{action?.name}</span>\n <span className={styles.actionHeaderCost}>\n {thinkCost ? `${thinkCost}s` : \"\"}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n};\n\n// 默认消息功能区\nexport const defaultActions: ActionItem[] = [\n {\n key: \"redo\",\n icon: <RedoOutlined />,\n tooltip: \"重新生成\",\n },\n {\n key: \"copy\",\n icon: <CopyOutlined />,\n tooltip: \"复制\",\n },\n {\n key: \"delete\",\n icon: <DeleteOutlined />,\n tooltip: \"删除\",\n },\n];\n\nconst XAiChatbot: React.FC<XAiChatbotProps> = (props) => {\n const styles = useStyles();\n // 使用新的 Hook 来处理 Provider 上下文\n const { mergedProps } = useChatbotContext(props);\n\n const {\n navbarShow = false,\n navbar,\n renderNavbar = null,\n clearBtnShow = true,\n inputShow = true,\n // renderMessageContent,\n // quickReplies = [],\n // quickRepliesVisible = true,\n // onQuickReplyClick,\n loading: propLoading = false,\n messageTooltip,\n avatar,\n userAvatar,\n messages: propMessages,\n text = \"\",\n footerTips = \"\",\n empty = null,\n emptyStateImage = emptyIcon,\n emptyStateText = \"我的智能体\",\n messageActions = defaultActions,\n onMessagesActionsCallback,\n // 点击帮助消息\n onSuggestMessageClick,\n onSend,\n onClear,\n onStop,\n providerId,\n // 消息顶部\n messageTop,\n enableUpload,\n uploadRequest,\n } = mergedProps as XAiChatbotProps;\n\n // 如果在 Provider 中,使用 Provider 的状态\n const messages = mergedProps.messages || propMessages || [];\n const loading = mergedProps.loading || propLoading;\n\n const [content, setContent] = useState<string>(text); // 输入框文本\n const [files, setFiles] = useState<Attachment[]>([]);\n const lastMessageId = useRef<string>(\"\");\n const isScriptScrolling = useRef<boolean>(false);\n const chatId = providerId\n ? `za-chatbot-container-${providerId}`\n : \"za-chatbot-container\";\n\n // 滚动到最底部\n const scrollToBottom = () => {\n isScriptScrolling.current = true;\n setTimeout(() => {\n const mainChatWrapper = document.getElementById(chatId);\n if (mainChatWrapper) {\n mainChatWrapper.scrollTop = mainChatWrapper?.scrollHeight;\n }\n isScriptScrolling.current = false;\n }, 0);\n };\n\n // 消息功能区组件\n const FooterActions: React.FC<{ data: Messages; lastMessage: boolean }> = ({\n data,\n lastMessage = false,\n }) => (\n <div className={clsx(styles.flex, styles.gap(13))}>\n {messageActions.map((action: ActionItem, index: number) => {\n if (!lastMessage && action.key === \"redo\") return null;\n return (\n <Tooltip key={action.key} title={action.tooltip}>\n <span\n className={styles.cursor(\"pointer\")}\n onClick={() => onMessagesActionsCallback?.(index, data)}\n >\n {action.icon}\n {action.render?.(index, data)}\n </span>\n </Tooltip>\n );\n })}\n </div>\n );\n\n // 消息底部区域\n const MessageFooter: React.FC<{ data: Messages; lastMessage: boolean }> = ({\n data,\n lastMessage = false,\n }) => (\n <>\n {messageTooltip?.(data)}\n <FooterActions data={data} lastMessage={lastMessage} />\n </>\n );\n\n // 聊天角色\n const rolesObject: NonNullable<BubbleListProps[\"role\"]> = {\n assistant: {\n placement: \"start\",\n avatar: () => {\n return (\n avatar || (\n <UserOutlined\n className={clsx(styles.bg(\"#fde3cf\"), styles.userAvatar)}\n />\n )\n );\n },\n typing: { step: 5, interval: 20, effect: \"typing\" },\n style: {\n maxWidth: 600,\n },\n classNames: {\n content: \"assistant-content\",\n },\n },\n user: {\n placement: \"end\",\n avatar: () => {\n return (\n userAvatar || (\n <UserOutlined\n className={clsx(styles.bg(\"#87d068\"), styles.userAvatar)}\n />\n )\n );\n },\n classNames: {\n content: \"user-content\",\n },\n },\n suggestion: {\n placement: \"start\",\n avatar: () => {\n return (\n avatar || (\n <UserOutlined\n className={clsx(styles.bg(\"#fde3cf\"), styles.userAvatar)}\n />\n )\n );\n },\n variant: \"borderless\",\n },\n };\n\n // 触发发送\n const handleSend = (obj: SendContent) => {\n // 直接使用合并后的 onSend,自动处理 Provider 和独立模式\n onSend?.(obj);\n setContent(\"\"); // 发送后清空输入框内容\n setFiles([]); // 发送后清空文件\n scrollToBottom();\n };\n\n // 输出内容\n const handleChange = (str: string) => {\n setContent(str);\n };\n\n // 停止生成\n const handleStop = () => {\n onStop?.();\n };\n\n // 导航栏\n const NavBar: React.FC = () => {\n if (renderNavbar) {\n return renderNavbar();\n }\n if (navbar?.title) {\n return (\n <header className={styles.navbar}>\n {navbar.avatar && (\n <img src={navbar.avatar} className={styles.avatar} alt=\"\" />\n )}\n <div>\n <div className={styles.title}>{navbar.title}</div>\n <div className={styles.subtitle}>{navbar.subtitle}</div>\n </div>\n </header>\n );\n }\n return <></>;\n };\n\n // 确认清除\n const confirmClear = () => {\n onClear?.();\n };\n\n // 空状态\n const EmptyState = useMemo(\n () => () =>\n empty || (\n <div className={styles.emptyWrapper}>\n <img\n src={emptyStateImage}\n alt=\"空状态图标\"\n className={styles.emptyImg}\n />\n <div\n className={clsx(\n styles.text(16),\n styles.weight(600),\n styles.textColor(\"#343434\"),\n )}\n >\n {emptyStateText}\n </div>\n </div>\n ),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [emptyStateImage, emptyStateText],\n );\n\n return (\n <>\n <GlobalStyle />\n <MarkdownGlobalStyle />\n <div id=\"x-ai-chatbot\" className={styles.wrapper}>\n {navbarShow && <NavBar />}\n {/** 消息容器 */}\n <div className={styles.messageContainer}>\n {/* 消息列表主体 */}\n {messages?.length ? (\n <Bubble.List\n id={chatId}\n role={rolesObject}\n className={styles.messageList}\n items={messages.map((msg: any) => {\n const {\n id,\n role,\n status,\n type,\n execute = [],\n thinks = \"\",\n extra = { noFooter: false },\n stepContent,\n } = msg as Messages;\n // 最后一条 AI消息标识\n if (role === MessageRole.assistant) {\n lastMessageId.current = id;\n }\n // 会话内容\n const bubbleContent: any = {\n key: id,\n role,\n loading: status === MessageStatus.init,\n header: () =>\n messageTop || (\n <ActionHeader execute={execute} thinks={thinks} />\n ),\n content: (() => {\n // 文本消息\n if (type === \"TextMessage\") {\n // 用户消息\n if (role === \"user\") {\n return (\n <div\n className=\"ai-markdown-body\"\n style={{\n minWidth: 0,\n maxWidth: 600,\n }}\n >\n {msg.content?.text}\n </div>\n );\n }\n\n // 输出html字符串\n const html = md.render(msg.content?.text || \"\");\n // 生成React节点\n const htmlString = reactHtmlParser(html);\n return (\n <>\n {/* 输出阶段性回答内容 */}\n {stepContent?.length &&\n stepContent.map((item) => {\n // 输出html字符串\n const html2 = md.render(item.content || \"\");\n // 生成React节点\n const stepHtmlString = reactHtmlParser(html2);\n return (\n <div\n key={item.id}\n className=\"ai-markdown-body step-content\"\n style={{\n minWidth: 0,\n maxWidth: 600,\n }}\n >\n <div>{stepHtmlString}</div>\n <div className={styles.stepLine} />\n </div>\n );\n })}\n {/** 输出最终回答内容 */}\n <div\n className=\"ai-markdown-body\"\n style={{\n minWidth: 0,\n maxWidth: 600,\n }}\n >\n {htmlString}\n </div>\n </>\n );\n }\n // 提示类型\n if (type === \"SuggestionMessage\") {\n return (\n <Prompts\n vertical\n items={msg.content as any}\n onItemClick={(info: { data: PromptsItemType }) => {\n onSuggestMessageClick?.(info?.data, id);\n if (info.data.description) {\n onSend?.({\n text: info.data.description as string,\n });\n }\n }}\n />\n );\n }\n // 其他类型...\n return null;\n })(),\n };\n\n if (!extra.noFooter) {\n bubbleContent.footer = () => {\n const msgFiles = msg.content?.files || [];\n if (role === MessageRole.user && msgFiles.length) {\n return (\n <Flex gap={8} wrap justify=\"flex-end\">\n {msgFiles.map((f: any) => (\n <FileCard\n styles={{\n file:\n f?.fileType === \"image\"\n ? {\n width: 100,\n height: 100,\n }\n : {},\n }}\n key={f.fileId}\n {...f}\n name={f.fileName}\n size={f.fileSize}\n type={f.fileType}\n src={f.fileUrl}\n />\n ))}\n </Flex>\n );\n }\n if (\n role === MessageRole.assistant &&\n status !== MessageStatus.failed\n ) {\n return (\n <MessageFooter\n data={msg as Messages}\n lastMessage={lastMessageId.current === id}\n />\n );\n }\n };\n }\n\n return bubbleContent;\n })}\n />\n ) : (\n <EmptyState />\n )}\n </div>\n {/* 输入框 */}\n {inputShow && (\n <XAiSender\n value={content}\n loading={loading}\n footerTips={footerTips}\n clearBtnShow={clearBtnShow}\n enableUpload={enableUpload}\n files={files}\n onChangeFiles={setFiles}\n uploadRequest={uploadRequest}\n onChange={handleChange}\n onSubmit={handleSend}\n onStop={handleStop}\n onClear={confirmClear}\n />\n )}\n </div>\n </>\n );\n};\n\nexport default XAiChatbot;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAAiD;AACjD,kBAAuC;AACvC,eAA0C;AAE1C,mBAKO;AACP,kBAAiB;AACjB,yBAAuB;AACvB,+BAA4B;AAE5B,sBAAgC;AAChC,wBAAqD;AAErD,mBAAsB;AACtB,sBAAoB;AACpB,wBAAsB;AACtB,mBAAsB;AACtB,mBAAsB;AACtB,6BAA0B;AAC1B,gCAAkC;AAClC,oBAAuC;AACvC,uBAAsB;AA2Dd;AAxDR,IAAM,KAAK,IAAI,mBAAAA,QAAW;AAAA,EACxB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AACf,CAAC;AAGD,IAAM,gBACJ,GAAG,SAAS,MAAM,cACjB,CAAC,QAAQ,KAAK,SAAS,KAAK,SAAS;AACpC,SAAO,KAAK,YAAY,QAAQ,KAAK,OAAO;AAC9C;AAGF,GAAG,SAAS,MAAM,YAAY,CAAC,QAAQ,KAAK,SAAS,KAAK,SAAS;AAEjE,QAAM,SAAS,OAAO,GAAG,EAAE,UAAU,QAAQ;AAC7C,MAAI,SAAS,GAAG;AACd,WAAO,GAAG,EAAE,SAAS,CAAC,UAAU,QAAQ,CAAC;AAAA,EAC3C,OAAO;AACL,WAAO,GAAG,EAAE,MAAO,MAAM,EAAE,CAAC,IAAI;AAAA,EAClC;AAEA,QAAM,WAAW,OAAO,GAAG,EAAE,UAAU,KAAK;AAC5C,MAAI,WAAW,GAAG;AAChB,WAAO,GAAG,EAAE,SAAS,CAAC,OAAO,qBAAqB,CAAC;AAAA,EACrD,OAAO;AACL,WAAO,GAAG,EAAE,MAAO,QAAQ,EAAE,CAAC,IAAI;AAAA,EACpC;AACA,SAAO,cAAc,QAAQ,KAAK,SAAS,KAAK,IAAI;AACtD;AAQO,IAAM,eAA4C,CAAC;AAAA,EACxD,UAAU,CAAC;AAAA,EACX,SAAS;AACX,MAAM;AAvEN;AAwEE,QAAM,aAAS,yBAAU;AACzB,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,IAAI;AAC7C,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAS,KAAK;AAG5D,MAAI,CAAC,WAAW,CAAC,WAAW,QAAQ,WAAW;AAAI,WAAO;AAE1D,QAAM,OAAO,QAAQ,QAAQ,SAAS,CAAC,KAAK,CAAC;AAC7C,QAAM,EAAE,KAAK,IAAI;AACjB,QAAM,QAAO,6BAAM,WAAQ,kCAAM,UAAN,mBAAa;AAExC,SACE,6CAAC,SAAI,WAAW,OAAO,qBACpB;AAAA,KAAC,YACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,OAAO;AAAA,QAClB,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,QAEpC;AAAA,sDAAC,SAAI,KAAK,aAAAC,SAAW,KAAI,QAAO,WAAW,OAAO,kBAAkB;AAAA,UACpE,4CAAC,UAAK,WAAW,OAAO,OAAO,kBAAI;AAAA,UACnC,4CAAC,SAAI,KAAI,UAAS,KAAK,kBAAAC,SAAW,WAAW,OAAO,EAAE,MAAM,GAAG;AAAA;AAAA;AAAA,IACjE;AAAA,IAED,YACC,6CAAC,SAAI,WAAW,OAAO,oBACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,UAEpC;AAAA,wDAAC,SAAI,KAAK,aAAAD,SAAW,KAAI,IAAG,eAAW,YAAAE,SAAK,OAAO,EAAE,EAAE,CAAC,GAAG;AAAA,YAC3D,4CAAC,SAAI,eAAW,YAAAA,SAAK,OAAO,OAAO,OAAO,GAAG,EAAE,CAAC,GAAG,oBAEnD;AAAA,YACA,4CAAC,SAAI,KAAI,UAAS,KAAK,gBAAAC,SAAS,WAAW,OAAO,EAAE,MAAM,GAAG;AAAA;AAAA;AAAA,MAC/D;AAAA,MAEC,UACC;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,OAAO;AAAA,UAClB,OAAO,EAAE,YAAY,WAAW;AAAA,UAE/B;AAAA;AAAA,MACH;AAAA,MAGD,WAAW,QAAQ,SAAS,KAC3B,4EACG;AAAA,SAAC,mBACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,OAAO;AAAA,YAClB,SAAS,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAAA,YAE1C;AAAA,sBACC,4CAAC,SAAI,KAAK,MAAM,KAAI,QAAO,WAAW,OAAO,EAAE,EAAE,GAAG;AAAA,cAEtD,4CAAC,UAAK,WAAW,OAAO,OAAQ,gBAAK;AAAA,cACrC;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAI;AAAA,kBACJ,KAAK,uBAAAC;AAAA,kBACL,WAAW,OAAO,EAAE,MAAM;AAAA;AAAA,cAC5B;AAAA;AAAA;AAAA,QACF;AAAA,QAED,mBACC,6CAAC,SAAI,WAAW,OAAO,gBACrB;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,OAAO;AAAA,cAClB,SAAS,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAAA,cAE3C;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,KAAK,aAAAC;AAAA,oBACL,KAAI;AAAA,oBACJ,WAAW,OAAO;AAAA;AAAA,gBACpB;AAAA,gBACA,4CAAC,UAAK,WAAW,OAAO,OAAO,oBAAM;AAAA,gBACrC;AAAA,kBAAC;AAAA;AAAA,oBACC,KAAI;AAAA,oBACJ,KAAK,gBAAAF;AAAA,oBACL,WAAW,OAAO,EAAE,MAAM;AAAA;AAAA,gBAC5B;AAAA;AAAA;AAAA,UACF;AAAA,UACA,4CAAC,SAAI,WAAW,OAAO,gBACpB,kBAAQ,IAAI,CAAC,QAAa,QAAgB;AA1J/D,gBAAAG,KAAA;AA2JsB,kBAAM,cACJ,iCAAQ,iBACRA,MAAA,iCAAQ,UAAR,gBAAAA,IAAe,iBACf,sCAAQ,UAAR,mBAAe,UACf,iCAAQ;AACV,kBAAM,aAAY,iCAAQ,WAAQ,sCAAQ,UAAR,mBAAe;AACjD,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAW,OAAO;AAAA,gBAEjB;AAAA,gCACC;AAAA,oBAAC;AAAA;AAAA,sBACC,KAAK;AAAA,sBACL,KAAI;AAAA,sBACJ,WAAW,OAAO;AAAA;AAAA,kBACpB;AAAA,kBAEF,4CAAC,UAAM,2CAAQ,MAAK;AAAA,kBACpB,4CAAC,UAAK,WAAW,OAAO,kBACrB,sBAAY,GAAG,eAAe,IACjC;AAAA;AAAA;AAAA,cAbK,OAAO,YAAY;AAAA,YAc1B;AAAA,UAEJ,CAAC,GACH;AAAA,WACF;AAAA,SAEJ;AAAA,OAEJ;AAAA,KAEJ;AAEJ;AAGO,IAAM,iBAA+B;AAAA,EAC1C;AAAA,IACE,KAAK;AAAA,IACL,MAAM,4CAAC,6BAAa;AAAA,IACpB,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,MAAM,4CAAC,6BAAa;AAAA,IACpB,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,MAAM,4CAAC,+BAAe;AAAA,IACtB,SAAS;AAAA,EACX;AACF;AAEA,IAAM,aAAwC,CAAC,UAAU;AACvD,QAAM,aAAS,yBAAU;AAEzB,QAAM,EAAE,YAAY,QAAI,6CAAkB,KAAK;AAE/C,QAAM;AAAA,IACJ,aAAa;AAAA,IACb;AAAA,IACA,eAAe;AAAA,IACf,eAAe;AAAA,IACf,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,IAKZ,SAAS,cAAc;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB,aAAAC;AAAA,IAClB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAGJ,QAAM,WAAW,YAAY,YAAY,gBAAgB,CAAC;AAC1D,QAAM,UAAU,YAAY,WAAW;AAEvC,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAiB,IAAI;AACnD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAuB,CAAC,CAAC;AACnD,QAAM,oBAAgB,qBAAe,EAAE;AACvC,QAAM,wBAAoB,qBAAgB,KAAK;AAC/C,QAAM,SAAS,aACX,wBAAwB,eACxB;AAGJ,QAAM,iBAAiB,MAAM;AAC3B,sBAAkB,UAAU;AAC5B,eAAW,MAAM;AACf,YAAM,kBAAkB,SAAS,eAAe,MAAM;AACtD,UAAI,iBAAiB;AACnB,wBAAgB,YAAY,mDAAiB;AAAA,MAC/C;AACA,wBAAkB,UAAU;AAAA,IAC9B,GAAG,CAAC;AAAA,EACN;AAGA,QAAM,gBAAoE,CAAC;AAAA,IACzE;AAAA,IACA,cAAc;AAAA,EAChB,MACE,4CAAC,SAAI,eAAW,YAAAL,SAAK,OAAO,MAAM,OAAO,IAAI,EAAE,CAAC,GAC7C,yBAAe,IAAI,CAAC,QAAoB,UAAkB;AAvRjE;AAwRQ,QAAI,CAAC,eAAe,OAAO,QAAQ;AAAQ,aAAO;AAClD,WACE,4CAAC,uBAAyB,OAAO,OAAO,SACtC;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,OAAO,OAAO,SAAS;AAAA,QAClC,SAAS,MAAM,uEAA4B,OAAO;AAAA,QAEjD;AAAA,iBAAO;AAAA,WACP,YAAO,WAAP,gCAAgB,OAAO;AAAA;AAAA;AAAA,IAC1B,KAPY,OAAO,GAQrB;AAAA,EAEJ,CAAC,GACH;AAIF,QAAM,gBAAoE,CAAC;AAAA,IACzE;AAAA,IACA,cAAc;AAAA,EAChB,MACE,4EACG;AAAA,qDAAiB;AAAA,IAClB,4CAAC,iBAAc,MAAY,aAA0B;AAAA,KACvD;AAIF,QAAM,cAAoD;AAAA,IACxD,WAAW;AAAA,MACT,WAAW;AAAA,MACX,QAAQ,MAAM;AACZ,eACE,UACE;AAAA,UAAC;AAAA;AAAA,YACC,eAAW,YAAAA,SAAK,OAAO,GAAG,SAAS,GAAG,OAAO,UAAU;AAAA;AAAA,QACzD;AAAA,MAGN;AAAA,MACA,QAAQ,EAAE,MAAM,GAAG,UAAU,IAAI,QAAQ,SAAS;AAAA,MAClD,OAAO;AAAA,QACL,UAAU;AAAA,MACZ;AAAA,MACA,YAAY;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,MAAM;AAAA,MACJ,WAAW;AAAA,MACX,QAAQ,MAAM;AACZ,eACE,cACE;AAAA,UAAC;AAAA;AAAA,YACC,eAAW,YAAAA,SAAK,OAAO,GAAG,SAAS,GAAG,OAAO,UAAU;AAAA;AAAA,QACzD;AAAA,MAGN;AAAA,MACA,YAAY;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,WAAW;AAAA,MACX,QAAQ,MAAM;AACZ,eACE,UACE;AAAA,UAAC;AAAA;AAAA,YACC,eAAW,YAAAA,SAAK,OAAO,GAAG,SAAS,GAAG,OAAO,UAAU;AAAA;AAAA,QACzD;AAAA,MAGN;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAGA,QAAM,aAAa,CAAC,QAAqB;AAEvC,qCAAS;AACT,eAAW,EAAE;AACb,aAAS,CAAC,CAAC;AACX,mBAAe;AAAA,EACjB;AAGA,QAAM,eAAe,CAAC,QAAgB;AACpC,eAAW,GAAG;AAAA,EAChB;AAGA,QAAM,aAAa,MAAM;AACvB;AAAA,EACF;AAGA,QAAM,SAAmB,MAAM;AAC7B,QAAI,cAAc;AAChB,aAAO,aAAa;AAAA,IACtB;AACA,QAAI,iCAAQ,OAAO;AACjB,aACE,6CAAC,YAAO,WAAW,OAAO,QACvB;AAAA,eAAO,UACN,4CAAC,SAAI,KAAK,OAAO,QAAQ,WAAW,OAAO,QAAQ,KAAI,IAAG;AAAA,QAE5D,6CAAC,SACC;AAAA,sDAAC,SAAI,WAAW,OAAO,OAAQ,iBAAO,OAAM;AAAA,UAC5C,4CAAC,SAAI,WAAW,OAAO,UAAW,iBAAO,UAAS;AAAA,WACpD;AAAA,SACF;AAAA,IAEJ;AACA,WAAO,2EAAE;AAAA,EACX;AAGA,QAAM,eAAe,MAAM;AACzB;AAAA,EACF;AAGA,QAAM,iBAAa;AAAA,IACjB,MAAM,MACJ,SACE,6CAAC,SAAI,WAAW,OAAO,cACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,KAAI;AAAA,UACJ,WAAW,OAAO;AAAA;AAAA,MACpB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,eAAW,YAAAA;AAAA,YACT,OAAO,KAAK,EAAE;AAAA,YACd,OAAO,OAAO,GAAG;AAAA,YACjB,OAAO,UAAU,SAAS;AAAA,UAC5B;AAAA,UAEC;AAAA;AAAA,MACH;AAAA,OACF;AAAA;AAAA,IAGJ,CAAC,iBAAiB,cAAc;AAAA,EAClC;AAEA,SACE,4EACE;AAAA,gDAAC,6BAAY;AAAA,IACb,4CAAC,gBAAAM,SAAA,EAAoB;AAAA,IACrB,6CAAC,SAAI,IAAG,gBAAe,WAAW,OAAO,SACtC;AAAA,oBAAc,4CAAC,UAAO;AAAA,MAEvB,4CAAC,SAAI,WAAW,OAAO,kBAEpB,gDAAU,UACT;AAAA,QAAC,gBAAO;AAAA,QAAP;AAAA,UACC,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,WAAW,OAAO;AAAA,UAClB,OAAO,SAAS,IAAI,CAAC,QAAa;AAChC,kBAAM;AAAA,cACJ;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,UAAU,CAAC;AAAA,cACX,SAAS;AAAA,cACT,QAAQ,EAAE,UAAU,MAAM;AAAA,cAC1B;AAAA,YACF,IAAI;AAEJ,gBAAI,SAAS,8BAAY,WAAW;AAClC,4BAAc,UAAU;AAAA,YAC1B;AAEA,kBAAM,gBAAqB;AAAA,cACzB,KAAK;AAAA,cACL;AAAA,cACA,SAAS,WAAW,gCAAc;AAAA,cAClC,QAAQ,MACN,cACE,4CAAC,gBAAa,SAAkB,QAAgB;AAAA,cAEpD,UAAU,MAAM;AAldlC;AAodoB,oBAAI,SAAS,eAAe;AAE1B,sBAAI,SAAS,QAAQ;AACnB,2BACE;AAAA,sBAAC;AAAA;AAAA,wBACC,WAAU;AAAA,wBACV,OAAO;AAAA,0BACL,UAAU;AAAA,0BACV,UAAU;AAAA,wBACZ;AAAA,wBAEC,oBAAI,YAAJ,mBAAa;AAAA;AAAA,oBAChB;AAAA,kBAEJ;AAGA,wBAAM,OAAO,GAAG,SAAO,SAAI,YAAJ,mBAAa,SAAQ,EAAE;AAE9C,wBAAM,iBAAa,yBAAAC,SAAgB,IAAI;AACvC,yBACE,4EAEG;AAAA,gEAAa,WACZ,YAAY,IAAI,CAAC,SAAS;AAExB,4BAAM,QAAQ,GAAG,OAAO,KAAK,WAAW,EAAE;AAE1C,4BAAM,qBAAiB,yBAAAA,SAAgB,KAAK;AAC5C,6BACE;AAAA,wBAAC;AAAA;AAAA,0BAEC,WAAU;AAAA,0BACV,OAAO;AAAA,4BACL,UAAU;AAAA,4BACV,UAAU;AAAA,0BACZ;AAAA,0BAEA;AAAA,wEAAC,SAAK,0BAAe;AAAA,4BACrB,4CAAC,SAAI,WAAW,OAAO,UAAU;AAAA;AAAA;AAAA,wBAR5B,KAAK;AAAA,sBASZ;AAAA,oBAEJ,CAAC;AAAA,oBAEH;AAAA,sBAAC;AAAA;AAAA,wBACC,WAAU;AAAA,wBACV,OAAO;AAAA,0BACL,UAAU;AAAA,0BACV,UAAU;AAAA,wBACZ;AAAA,wBAEC;AAAA;AAAA,oBACH;AAAA,qBACF;AAAA,gBAEJ;AAEA,oBAAI,SAAS,qBAAqB;AAChC,yBACE;AAAA,oBAAC;AAAA;AAAA,sBACC,UAAQ;AAAA,sBACR,OAAO,IAAI;AAAA,sBACX,aAAa,CAAC,SAAoC;AAChD,uFAAwB,6BAAM,MAAM;AACpC,4BAAI,KAAK,KAAK,aAAa;AACzB,2DAAS;AAAA,4BACP,MAAM,KAAK,KAAK;AAAA,0BAClB;AAAA,wBACF;AAAA,sBACF;AAAA;AAAA,kBACF;AAAA,gBAEJ;AAEA,uBAAO;AAAA,cACT,GAAG;AAAA,YACL;AAEA,gBAAI,CAAC,MAAM,UAAU;AACnB,4BAAc,SAAS,MAAM;AAniB/C;AAoiBoB,sBAAM,aAAW,SAAI,YAAJ,mBAAa,UAAS,CAAC;AACxC,oBAAI,SAAS,8BAAY,QAAQ,SAAS,QAAQ;AAChD,yBACE,4CAAC,oBAAK,KAAK,GAAG,MAAI,MAAC,SAAQ,YACxB,mBAAS,IAAI,CAAC,MACb;AAAA,oBAAC;AAAA;AAAA,sBACC,QAAQ;AAAA,wBACN,OACE,uBAAG,cAAa,UACZ;AAAA,0BACE,OAAO;AAAA,0BACP,QAAQ;AAAA,wBACV,IACA,CAAC;AAAA,sBACT;AAAA,sBAEC,GAAG;AAAA,sBACJ,MAAM,EAAE;AAAA,sBACR,MAAM,EAAE;AAAA,sBACR,MAAM,EAAE;AAAA,sBACR,KAAK,EAAE;AAAA;AAAA,oBALF,EAAE;AAAA,kBAMT,CACD,GACH;AAAA,gBAEJ;AACA,oBACE,SAAS,8BAAY,aACrB,WAAW,gCAAc,QACzB;AACA,yBACE;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAM;AAAA,sBACN,aAAa,cAAc,YAAY;AAAA;AAAA,kBACzC;AAAA,gBAEJ;AAAA,cACF;AAAA,YACF;AAEA,mBAAO;AAAA,UACT,CAAC;AAAA;AAAA,MACH,IAEA,4CAAC,cAAW,GAEhB;AAAA,MAEC,aACC;AAAA,QAAC,iBAAAC;AAAA,QAAA;AAAA,UACC,OAAO;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,eAAe;AAAA,UACf;AAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,SAAS;AAAA;AAAA,MACX;AAAA,OAEJ;AAAA,KACF;AAEJ;AAEA,IAAO,qBAAQ;",
6
6
  "names": ["MarkdownIt", "thinkIcon", "arrowDown", "clsx", "arrowUp", "arrowDownBlue", "groupIcon", "_a", "emptyIcon", "MarkdownGlobalStyle", "reactHtmlParser", "XAiSender"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/XAiProvider/index.tsx"],
4
- "sourcesContent": ["import React, { forwardRef, useImperativeHandle, useState, useRef, useEffect } from 'react';\nimport { message, Divider, Modal, Input, ConfigProvider } from 'antd';\nimport copy from 'copy-to-clipboard';\nimport { XProvider } from '@ant-design/x';\nimport type { ConversationsProps } from '@/types/antdx';\nimport { ExclamationCircleFilled, LikeFilled, LikeOutlined } from '@ant-design/icons';\nimport { XAiContext } from '@/context/AiProviderContext';\nimport { XAiProviderProps, XAiProviderHandle } from '@/types/XAiProvider';\nimport useAgentGenerator from '@/hooks/useAgentGenerator';\nimport { MOBILE_MAX_WIDTH, API_SUCCESS_CODE } from '@/constants';\nimport userIcon from '@/assets/user.png';\nimport { primaryBlue } from '@/styles/common';\nimport DislikeFeedback from '../DislikeFeedback';\nimport { addFeedback } from '@/services/api';\nimport { defaultActions } from '../XAiChatbot';\nimport type { SendContent } from '@/types';\n\nconst { confirm } = Modal;\n\nconst XAiProvider = forwardRef<XAiProviderHandle, XAiProviderProps>(({\n url = window.location.origin,\n token,\n config,\n providerId = 'defaultId',\n onSuccess,\n onError,\n onMessage,\n children,\n}, ref) => {\n // 使用 useAgentGenerator Hook 管理消息状态\n\n const { textSpeed = 55 } = config?.chatProps || {};\n\n const {\n appInfo,\n chat,\n stopChat,\n reChat,\n createNewChat,\n deleteSession,\n updateSession,\n currentSessionId,\n sessionPagination,\n sessionList,\n messages,\n loading,\n setCurrentSession,\n setMessages,\n } = useAgentGenerator({ url, token, config, onError, onSuccess, onMessage, textSpeed });\n\n const { appName, icon } = appInfo || {};\n\n useImperativeHandle(ref, () => ({\n chat,\n stopChat,\n reChat,\n getAppInfo: () => appInfo,\n getMessages: () => messages,\n getSessions: () => sessionList,\n setMessages,\n setCurrentSession,\n }), [appInfo, messages, chat, stopChat, reChat, setMessages, setCurrentSession]);\n\n const [isNarrow, setIsNarrow] = useState<boolean>(false);\n const divRef = useRef<HTMLDivElement>(null);\n\n // 监听容器宽度变化\n useEffect(() => {\n const div = divRef.current;\n if (!div) return;\n\n // 创建监听器\n const resizeObserver = new ResizeObserver((entries) => {\n // eslint-disable-next-line no-restricted-syntax\n for (const entry of entries) {\n const { width } = entry.contentRect;\n setIsNarrow(width <= MOBILE_MAX_WIDTH);\n }\n });\n\n // 开始监听\n resizeObserver.observe(div);\n\n // 初始化检查\n const initialWidth = div.offsetWidth;\n setIsNarrow(initialWidth <= MOBILE_MAX_WIDTH);\n\n // 清理函数\n return () => {\n resizeObserver.disconnect();\n };\n }, []);\n\n // 发送消息\n const handleSendMessage = (content: SendContent) => {\n chat(content);\n };\n\n // 清空消息\n const handleCreateNewMessage = () => {\n createNewChat();\n };\n\n // 工具栏按钮点击\n const handleActions = async (index: number, actionData: any) => {\n const { content, id } = actionData || {};\n const { text = '' } = content;\n switch (index) {\n case 0:\n reChat();\n break;\n case 1:\n copy(text);\n message.success('复制成功');\n break;\n case 2: {\n const idx = messages.findIndex((item) => item.id === id);\n if (idx >= 0) {\n // 删除该条消息及建议类消息\n if (messages.length - idx <= 2) {\n setMessages((prev) => prev.filter((item) => item.id !== id && item.type !== 'SuggestionMessage'));\n } else {\n // 非最新消息 只删除该条消息\n setMessages((prev) => prev.filter((item) => item.id !== id));\n }\n message.success('删除成功');\n }\n break;\n }\n case 3: {\n const { appNo } = config || {};\n const isLike = actionData.isLike ?? 0;\n if (isLike !== 0) {\n message.warning('已收到您的反馈,无需重复提交');\n return;\n }\n if (appNo) {\n const { result } = await addFeedback({\n url,\n token,\n appNo,\n requestId: actionData.raw?.requestId,\n isLike: 1,\n });\n if (result?.code === API_SUCCESS_CODE) {\n message.success('感谢您的反馈');\n setMessages((prev) => {\n return prev.map((item) => {\n if (item.id === id) {\n return {\n ...item,\n isLike: 1,\n };\n }\n return item;\n });\n });\n } else {\n message.error('反馈失败,请稍后再试');\n }\n }\n break;\n }\n }\n };\n\n // 建议消息点击\n const handleSuggestMessageClick = (_item: any, id: string) => {\n setMessages((prev: any[]) => prev.filter((m: any) => m.id !== id));\n };\n\n // 切换会话\n const handleActiveChange = (key: string) => {\n setCurrentSession(key);\n };\n\n // 删除会话\n const handleDeleteSession = (sessionId: string) => {\n deleteSession(sessionId);\n };\n\n // 修改会话内容\n const handleUpdateSession = (sessionId: string, title: string) => {\n updateSession(sessionId, title);\n };\n\n // 会话操作菜单\n const menuConfig: ConversationsProps['menu'] = (conversation) => ({\n items: [\n {\n label: '重命名',\n key: 'edit',\n },\n {\n label: '删除',\n key: 'delete',\n danger: true,\n },\n ],\n onClick: (menuInfo: { key: string; domEvent: React.MouseEvent<HTMLElement> }) => {\n menuInfo.domEvent.stopPropagation();\n const { key } = menuInfo;\n switch (key) {\n case 'edit': {\n let inputValue = conversation.label as string || '';\n confirm({\n title: '编辑对话名称',\n icon: null,\n content: (\n <Input\n defaultValue={inputValue}\n autoFocus\n style={{ width: '100%' }}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n inputValue = e.target.value;\n }}\n />\n ),\n okText: '确认',\n cancelText: '取消',\n okButtonProps: {\n style: { background: '#000', borderColor: '#000', color: '#fff' },\n },\n onOk: () => {\n if (!inputValue.trim()) {\n message.error('对话名称不能为空');\n return Promise.reject();\n }\n handleUpdateSession(conversation.key, inputValue);\n },\n onCancel: () => {\n // 静默处理\n },\n });\n break;\n }\n case 'delete':\n confirm({\n title: '确认删除?',\n icon: <ExclamationCircleFilled />,\n content: '该对话内容将被删除无法恢复。',\n okText: '确认删除',\n okType: 'danger',\n cancelText: '取消',\n okButtonProps: {\n style: { background: '#ff4d4f', borderColor: '#ff4d4f', color: '#fff' },\n },\n onOk() {\n handleDeleteSession(conversation.key);\n },\n onCancel() {\n //\n },\n });\n break;\n }\n },\n });\n\n const ToolTip = (messageData: any) => {\n const finalResult = (messageData?.think || []).find((item: any) => item.actionName === 'FINISHED');\n if (!finalResult) return null;\n const { cost, token: tokenCount } = finalResult.extra || {};\n if (!cost && !token) return null;\n return (\n <div style={{ display: 'flex', alignItems: 'center', fontSize: '12px', color: '#949494', flex: 1, paddingRight: '40px' }}>\n { (cost !== undefined && cost !== null) && <div>{cost}s</div> }\n { tokenCount && <Divider type=\"vertical\" /> }\n { tokenCount && <div>{ tokenCount } tokens</div> }\n </div>\n );\n };\n // 是否展示清空按钮\n const clearBtnShow = typeof config?.chatProps?.clearBtnShow !== 'undefined'\n ? config.chatProps.clearBtnShow\n : !config?.session?.showSessionList;\n\n return (\n <ConfigProvider theme={{\n token: {\n colorPrimary: appInfo?.appTheme || primaryBlue,\n },\n }}\n >\n <XProvider>\n <XAiContext.Provider value={{\n avatar: <img src={icon} alt=\"智能体头像\" />,\n userAvatar: <img src={userIcon} alt=\"用户头像\" />,\n emptyStateImage: icon,\n emptyStateText: appName,\n footerTips: '内容由AI生成,无法确保真实准确,仅供参考',\n providerId,\n sessionList,\n sessionTotal: sessionPagination.total,\n token,\n messages,\n loading,\n error: null,\n activeKey: currentSessionId,\n clearBtnShow,\n inputShow: config?.chatProps?.inputShow || true,\n isNarrow,\n messageTooltip: ToolTip,\n messageActions: [...defaultActions, {\n key: 'like',\n tooltip: '赞',\n render: (i, msg) => {\n const isLike = msg.isLike === 1;\n if (isLike) {\n return (\n <LikeFilled style={{ color: appInfo?.appTheme || primaryBlue }} />\n );\n }\n return <LikeOutlined />;\n },\n }, {\n key: 'dislike',\n tooltip: '踩',\n render: (_i, msg) => {\n const requestId = msg.raw?.requestId;\n return (\n <DislikeFeedback\n msg={msg}\n activeColor={appInfo?.appTheme || primaryBlue}\n onSubmit={async (formData) => {\n const { result } = await addFeedback({\n ...formData,\n requestId,\n isLike: -1,\n url,\n appNo: config?.appNo,\n token,\n });\n if (result?.code === API_SUCCESS_CODE) {\n message.success('已收到您的反馈,我们会努力做的更好');\n setMessages((prev) => {\n return prev.map((item) => {\n if (item.id === msg.id) {\n return {\n ...item,\n isLike: -1,\n };\n }\n return item;\n });\n });\n return true;\n }\n message.error('反馈失败,请稍后再试');\n return false;\n }}\n />\n );\n },\n }],\n onSend: handleSendMessage,\n onClear: handleCreateNewMessage,\n onNewChat: handleCreateNewMessage,\n onStop: stopChat,\n menu: menuConfig,\n onActiveChange: handleActiveChange,\n onSuggestMessageClick: handleSuggestMessageClick,\n onMessagesActionsCallback: handleActions,\n isInProvider: true,\n }}\n >\n <div\n ref={divRef}\n style={{\n display: 'flex',\n height: '100%',\n position: 'relative',\n }}\n >\n {children}\n </div>\n </XAiContext.Provider>\n </XProvider>\n </ConfigProvider>\n );\n});\n\nexport default XAiProvider;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAoF;AACpF,kBAA+D;AAC/D,+BAAiB;AACjB,eAA0B;AAE1B,mBAAkE;AAClE,+BAA2B;AAE3B,+BAA8B;AAC9B,uBAAmD;AACnD,kBAAqB;AACrB,oBAA4B;AAC5B,6BAA4B;AAC5B,iBAA4B;AAC5B,wBAA+B;AAmMjB;AAhMd,IAAM,EAAE,QAAQ,IAAI;AAEpB,IAAM,kBAAc,yBAAgD,CAAC;AAAA,EACnE,MAAM,OAAO,SAAS;AAAA,EACtB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAG,QAAQ;AA5BX;AA+BE,QAAM,EAAE,YAAY,GAAG,KAAI,iCAAQ,cAAa,CAAC;AAEjD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,yBAAAA,SAAkB,EAAE,KAAK,OAAO,QAAQ,SAAS,WAAW,WAAW,UAAU,CAAC;AAEtF,QAAM,EAAE,SAAS,KAAK,IAAI,WAAW,CAAC;AAEtC,wCAAoB,KAAK,OAAO;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,aAAa,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,EACF,IAAI,CAAC,SAAS,UAAU,MAAM,UAAU,QAAQ,aAAa,iBAAiB,CAAC;AAE/E,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAkB,KAAK;AACvD,QAAM,aAAS,qBAAuB,IAAI;AAG1C,8BAAU,MAAM;AACd,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC;AAAK;AAGV,UAAM,iBAAiB,IAAI,eAAe,CAAC,YAAY;AAErD,iBAAW,SAAS,SAAS;AAC3B,cAAM,EAAE,MAAM,IAAI,MAAM;AACxB,oBAAY,SAAS,iCAAgB;AAAA,MACvC;AAAA,IACF,CAAC;AAGD,mBAAe,QAAQ,GAAG;AAG1B,UAAM,eAAe,IAAI;AACzB,gBAAY,gBAAgB,iCAAgB;AAG5C,WAAO,MAAM;AACX,qBAAe,WAAW;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,oBAAoB,CAAC,YAAyB;AAClD,SAAK,OAAO;AAAA,EACd;AAGA,QAAM,yBAAyB,MAAM;AACnC,kBAAc;AAAA,EAChB;AAGA,QAAM,gBAAgB,OAAO,OAAe,eAAoB;AAxGlE,QAAAC;AAyGI,UAAM,EAAE,SAAS,GAAG,IAAI,cAAc,CAAC;AACvC,UAAM,EAAE,OAAO,GAAG,IAAI;AACtB,YAAQ,OAAO;AAAA,MACb,KAAK;AACH,eAAO;AACP;AAAA,MACF,KAAK;AACH,qCAAAC,SAAK,IAAI;AACT,4BAAQ,QAAQ,MAAM;AACtB;AAAA,MACF,KAAK,GAAG;AACN,cAAM,MAAM,SAAS,UAAU,CAAC,SAAS,KAAK,OAAO,EAAE;AACvD,YAAI,OAAO,GAAG;AAEZ,cAAI,SAAS,SAAS,OAAO,GAAG;AAC9B,wBAAY,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,KAAK,OAAO,MAAM,KAAK,SAAS,mBAAmB,CAAC;AAAA,UAClG,OAAO;AAEL,wBAAY,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;AAAA,UAC7D;AACA,8BAAQ,QAAQ,MAAM;AAAA,QACxB;AACA;AAAA,MACF;AAAA,MACA,KAAK,GAAG;AACN,cAAM,EAAE,MAAM,IAAI,UAAU,CAAC;AAC7B,cAAM,SAAS,WAAW,UAAU;AACpC,YAAI,WAAW,GAAG;AAChB,8BAAQ,QAAQ,gBAAgB;AAChC;AAAA,QACF;AACA,YAAI,OAAO;AACT,gBAAM,EAAE,OAAO,IAAI,UAAM,wBAAY;AAAA,YACnC;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAWD,MAAA,WAAW,QAAX,gBAAAA,IAAgB;AAAA,YAC3B,QAAQ;AAAA,UACV,CAAC;AACD,eAAI,iCAAQ,UAAS,mCAAkB;AACrC,gCAAQ,QAAQ,QAAQ;AACxB,wBAAY,CAAC,SAAS;AACpB,qBAAO,KAAK,IAAI,CAAC,SAAS;AACxB,oBAAI,KAAK,OAAO,IAAI;AAClB,yBAAO;AAAA,oBACL,GAAG;AAAA,oBACH,QAAQ;AAAA,kBACV;AAAA,gBACF;AACA,uBAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AAAA,UACH,OAAO;AACL,gCAAQ,MAAM,YAAY;AAAA,UAC5B;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,4BAA4B,CAAC,OAAY,OAAe;AAC5D,gBAAY,CAAC,SAAgB,KAAK,OAAO,CAAC,MAAW,EAAE,OAAO,EAAE,CAAC;AAAA,EACnE;AAGA,QAAM,qBAAqB,CAAC,QAAgB;AAC1C,sBAAkB,GAAG;AAAA,EACvB;AAGA,QAAM,sBAAsB,CAAC,cAAsB;AACjD,kBAAc,SAAS;AAAA,EACzB;AAGA,QAAM,sBAAsB,CAAC,WAAmB,UAAkB;AAChE,kBAAc,WAAW,KAAK;AAAA,EAChC;AAGA,QAAM,aAAyC,CAAC,kBAAkB;AAAA,IAChE,OAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,KAAK;AAAA,MACP;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,KAAK;AAAA,QACL,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,SAAS,CAAC,aAAuE;AAC/E,eAAS,SAAS,gBAAgB;AAClC,YAAM,EAAE,IAAI,IAAI;AAChB,cAAQ,KAAK;AAAA,QACX,KAAK,QAAQ;AACX,cAAI,aAAa,aAAa,SAAmB;AACjD,kBAAQ;AAAA,YACN,OAAO;AAAA,YACP,MAAM;AAAA,YACN,SACE;AAAA,cAAC;AAAA;AAAA,gBACC,cAAc;AAAA,gBACd,WAAS;AAAA,gBACT,OAAO,EAAE,OAAO,OAAO;AAAA,gBACvB,UAAU,CAAC,MAA2C;AACpD,+BAAa,EAAE,OAAO;AAAA,gBACxB;AAAA;AAAA,YACF;AAAA,YAEF,QAAQ;AAAA,YACR,YAAY;AAAA,YACZ,eAAe;AAAA,cACb,OAAO,EAAE,YAAY,QAAQ,aAAa,QAAQ,OAAO,OAAO;AAAA,YAClE;AAAA,YACA,MAAM,MAAM;AACV,kBAAI,CAAC,WAAW,KAAK,GAAG;AACtB,oCAAQ,MAAM,UAAU;AACxB,uBAAO,QAAQ,OAAO;AAAA,cACxB;AACA,kCAAoB,aAAa,KAAK,UAAU;AAAA,YAClD;AAAA,YACA,UAAU,MAAM;AAAA,YAEhB;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAAA,QACA,KAAK;AACH,kBAAQ;AAAA,YACN,OAAO;AAAA,YACP,MAAM,4CAAC,wCAAwB;AAAA,YAC/B,SAAS;AAAA,YACT,QAAQ;AAAA,YACR,QAAQ;AAAA,YACR,YAAY;AAAA,YACZ,eAAe;AAAA,cACb,OAAO,EAAE,YAAY,WAAW,aAAa,WAAW,OAAO,OAAO;AAAA,YACxE;AAAA,YACA,OAAO;AACL,kCAAoB,aAAa,GAAG;AAAA,YACtC;AAAA,YACA,WAAW;AAAA,YAEX;AAAA,UACF,CAAC;AACD;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,gBAAqB;AACpC,UAAM,gBAAe,2CAAa,UAAS,CAAC,GAAG,KAAK,CAAC,SAAc,KAAK,eAAe,UAAU;AACjG,QAAI,CAAC;AAAa,aAAO;AACzB,UAAM,EAAE,MAAM,OAAO,WAAW,IAAI,YAAY,SAAS,CAAC;AAC1D,QAAI,CAAC,QAAQ,CAAC;AAAO,aAAO;AAC5B,WACE,6CAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,UAAU,QAAQ,OAAO,WAAW,MAAM,GAAG,cAAc,OAAO,GAClH;AAAA,eAAS,UAAa,SAAS,QAAS,6CAAC,SAAK;AAAA;AAAA,QAAK;AAAA,SAAC;AAAA,MACrD,cAAc,4CAAC,uBAAQ,MAAK,YAAW;AAAA,MACvC,cAAc,6CAAC,SAAM;AAAA;AAAA,QAAY;AAAA,SAAO;AAAA,OAC5C;AAAA,EAEJ;AAEA,QAAM,eAAe,SAAO,sCAAQ,cAAR,mBAAmB,kBAAiB,cAC5D,OAAO,UAAU,eACjB,GAAC,sCAAQ,YAAR,mBAAiB;AAEtB,SACE;AAAA,IAAC;AAAA;AAAA,MAAe,OAAO;AAAA,QACrB,OAAO;AAAA,UACL,eAAc,mCAAS,aAAY;AAAA,QACrC;AAAA,MACF;AAAA,MAEE,sDAAC,sBACC;AAAA,QAAC,oCAAW;AAAA,QAAX;AAAA,UAAoB,OAAO;AAAA,YAC1B,QAAQ,4CAAC,SAAI,KAAK,MAAM,KAAI,SAAQ;AAAA,YACpC,YAAY,4CAAC,SAAI,KAAK,YAAAE,SAAU,KAAI,QAAO;AAAA,YAC3C,iBAAiB;AAAA,YACjB,gBAAgB;AAAA,YAChB,YAAY;AAAA,YACZ;AAAA,YACA;AAAA,YACA,cAAc,kBAAkB;AAAA,YAChC;AAAA,YACA;AAAA,YACA;AAAA,YACA,OAAO;AAAA,YACP,WAAW;AAAA,YACX;AAAA,YACA,aAAW,sCAAQ,cAAR,mBAAmB,cAAa;AAAA,YAC3C;AAAA,YACA,gBAAgB;AAAA,YAChB,gBAAgB,CAAC,GAAG,kCAAgB;AAAA,cAClC,KAAK;AAAA,cACL,SAAS;AAAA,cACT,QAAQ,CAAC,GAAG,QAAQ;AAClB,sBAAM,SAAS,IAAI,WAAW;AAC9B,oBAAI,QAAQ;AACV,yBACE,4CAAC,2BAAW,OAAO,EAAE,QAAO,mCAAS,aAAY,0BAAY,GAAG;AAAA,gBAEpE;AACA,uBAAO,4CAAC,6BAAa;AAAA,cACvB;AAAA,YACF,GAAG;AAAA,cACD,KAAK;AAAA,cACL,SAAS;AAAA,cACT,QAAQ,CAAC,IAAI,QAAQ;AA9TjC,oBAAAF;AA+Tc,sBAAM,aAAYA,MAAA,IAAI,QAAJ,gBAAAA,IAAS;AAC3B,uBACE;AAAA,kBAAC,uBAAAG;AAAA,kBAAA;AAAA,oBACC;AAAA,oBACA,cAAa,mCAAS,aAAY;AAAA,oBAClC,UAAU,OAAO,aAAa;AAC5B,4BAAM,EAAE,OAAO,IAAI,UAAM,wBAAY;AAAA,wBACnC,GAAG;AAAA,wBACH;AAAA,wBACA,QAAQ;AAAA,wBACR;AAAA,wBACA,OAAO,iCAAQ;AAAA,wBACf;AAAA,sBACF,CAAC;AACD,2BAAI,iCAAQ,UAAS,mCAAkB;AACrC,4CAAQ,QAAQ,mBAAmB;AACnC,oCAAY,CAAC,SAAS;AACpB,iCAAO,KAAK,IAAI,CAAC,SAAS;AACxB,gCAAI,KAAK,OAAO,IAAI,IAAI;AACtB,qCAAO;AAAA,gCACL,GAAG;AAAA,gCACH,QAAQ;AAAA,8BACV;AAAA,4BACF;AACA,mCAAO;AAAA,0BACT,CAAC;AAAA,wBACH,CAAC;AACD,+BAAO;AAAA,sBACT;AACA,0CAAQ,MAAM,YAAY;AAC1B,6BAAO;AAAA,oBACT;AAAA;AAAA,gBACF;AAAA,cAEJ;AAAA,YACF,CAAC;AAAA,YACD,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,gBAAgB;AAAA,YAChB,uBAAuB;AAAA,YACvB,2BAA2B;AAAA,YAC3B,cAAc;AAAA,UAChB;AAAA,UAEE;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,QAAQ;AAAA,gBACR,UAAU;AAAA,cACZ;AAAA,cAEC;AAAA;AAAA,UACH;AAAA;AAAA,MACF,GACF;AAAA;AAAA,EACF;AAEJ,CAAC;AAED,IAAO,sBAAQ;",
4
+ "sourcesContent": ["import React, { forwardRef, useImperativeHandle, useState, useRef, useEffect } from 'react';\nimport { message, Divider, Modal, Input, ConfigProvider } from 'antd';\nimport copy from 'copy-to-clipboard';\nimport { XProvider } from '@ant-design/x';\nimport type { ConversationsProps } from '@/types/antdx';\nimport { ExclamationCircleFilled, LikeFilled, LikeOutlined } from '@ant-design/icons';\nimport { XAiContext } from '@/context/AiProviderContext';\nimport { XAiProviderProps, XAiProviderHandle } from '@/types/XAiProvider';\nimport useAgentGenerator from '@/hooks/useAgentGenerator';\nimport { MOBILE_MAX_WIDTH, API_SUCCESS_CODE } from '@/constants';\nimport userIcon from '@/assets/user.png';\nimport { primaryBlue } from '@/styles/common';\nimport DislikeFeedback from '../DislikeFeedback';\nimport { addFeedback } from '@/services/api';\nimport { defaultActions } from '../XAiChatbot';\nimport type { SendContent } from '@/types';\n\nconst { confirm } = Modal;\n\nconst XAiProvider = forwardRef<XAiProviderHandle, XAiProviderProps>(({\n url = window.location.origin,\n token,\n config,\n providerId = 'defaultId',\n onSuccess,\n onError,\n onMessage,\n children,\n}, ref) => {\n // 使用 useAgentGenerator Hook 管理消息状态\n\n const { textSpeed = 55 } = config?.chatProps || {};\n\n const {\n appInfo,\n chat,\n stopChat,\n reChat,\n createNewChat,\n deleteSession,\n updateSession,\n currentSessionId,\n sessionPagination,\n sessionList,\n messages,\n loading,\n setCurrentSession,\n setMessages,\n } = useAgentGenerator({ url, token, config, onError, onSuccess, onMessage, textSpeed });\n\n const { appName, icon } = appInfo || {};\n\n useImperativeHandle(ref, () => ({\n chat,\n stopChat,\n reChat,\n getAppInfo: () => appInfo,\n getMessages: () => messages,\n getSessions: () => sessionList,\n setMessages,\n setCurrentSession,\n }), [appInfo, messages, chat, stopChat, reChat, setMessages, setCurrentSession]);\n\n const [isNarrow, setIsNarrow] = useState<boolean>(false);\n const divRef = useRef<HTMLDivElement>(null);\n\n // 监听容器宽度变化\n useEffect(() => {\n const div = divRef.current;\n if (!div) return;\n\n // 创建监听器\n const resizeObserver = new ResizeObserver((entries) => {\n // eslint-disable-next-line no-restricted-syntax\n for (const entry of entries) {\n const { width } = entry.contentRect;\n setIsNarrow(width <= MOBILE_MAX_WIDTH);\n }\n });\n\n // 开始监听\n resizeObserver.observe(div);\n\n // 初始化检查\n const initialWidth = div.offsetWidth;\n setIsNarrow(initialWidth <= MOBILE_MAX_WIDTH);\n\n // 清理函数\n return () => {\n resizeObserver.disconnect();\n };\n }, []);\n\n // 发送消息\n const handleSendMessage = (content: SendContent) => {\n chat(content);\n };\n\n // 清空消息\n const handleCreateNewMessage = () => {\n createNewChat();\n };\n\n // 工具栏按钮点击\n const handleActions = async (index: number, actionData: any) => {\n const { content, id } = actionData || {};\n const { text = '' } = content;\n switch (index) {\n case 0:\n reChat();\n break;\n case 1:\n copy(text);\n message.success('复制成功');\n break;\n case 2: {\n const idx = messages.findIndex((item) => item.id === id);\n if (idx >= 0) {\n // 删除该条消息及建议类消息\n if (messages.length - idx <= 2) {\n setMessages((prev) => prev.filter((item) => item.id !== id && item.type !== 'SuggestionMessage'));\n } else {\n // 非最新消息 只删除该条消息\n setMessages((prev) => prev.filter((item) => item.id !== id));\n }\n message.success('删除成功');\n }\n break;\n }\n case 3: {\n const { appNo } = config || {};\n const isLike = actionData.isLike ?? 0;\n if (isLike !== 0) {\n message.warning('已收到您的反馈,无需重复提交');\n return;\n }\n if (appNo) {\n const { result } = await addFeedback({\n url,\n token,\n appNo,\n requestId: actionData.raw?.requestId,\n isLike: 1,\n });\n if (result?.code === API_SUCCESS_CODE) {\n message.success('感谢您的反馈');\n setMessages((prev) => {\n return prev.map((item) => {\n if (item.id === id) {\n return {\n ...item,\n isLike: 1,\n };\n }\n return item;\n });\n });\n } else {\n message.error('反馈失败,请稍后再试');\n }\n }\n break;\n }\n }\n };\n\n // 建议消息点击\n const handleSuggestMessageClick = (_item: any, id: string) => {\n setMessages((prev: any[]) => prev.filter((m: any) => m.id !== id));\n };\n\n // 切换会话\n const handleActiveChange = (key: string) => {\n setCurrentSession(key);\n };\n\n // 删除会话\n const handleDeleteSession = (sessionId: string) => {\n deleteSession(sessionId);\n };\n\n // 修改会话内容\n const handleUpdateSession = (sessionId: string, title: string) => {\n updateSession(sessionId, title);\n };\n\n // 会话操作菜单\n const menuConfig: ConversationsProps['menu'] = (conversation) => ({\n items: [\n {\n label: '重命名',\n key: 'edit',\n },\n {\n label: '删除',\n key: 'delete',\n danger: true,\n },\n ],\n onClick: (menuInfo: { key: string; domEvent: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement> }) => {\n menuInfo.domEvent.stopPropagation();\n const { key } = menuInfo;\n switch (key) {\n case 'edit': {\n let inputValue = conversation.label as string || '';\n confirm({\n title: '编辑对话名称',\n icon: null,\n content: (\n <Input\n defaultValue={inputValue}\n autoFocus\n style={{ width: '100%' }}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n inputValue = e.target.value;\n }}\n />\n ),\n okText: '确认',\n cancelText: '取消',\n okButtonProps: {\n style: { background: '#000', borderColor: '#000', color: '#fff' },\n },\n onOk: () => {\n if (!inputValue.trim()) {\n message.error('对话名称不能为空');\n return Promise.reject();\n }\n handleUpdateSession(conversation.key, inputValue);\n },\n onCancel: () => {\n // 静默处理\n },\n });\n break;\n }\n case 'delete':\n confirm({\n title: '确认删除?',\n icon: <ExclamationCircleFilled />,\n content: '该对话内容将被删除无法恢复。',\n okText: '确认删除',\n okType: 'danger',\n cancelText: '取消',\n okButtonProps: {\n style: { background: '#ff4d4f', borderColor: '#ff4d4f', color: '#fff' },\n },\n onOk() {\n handleDeleteSession(conversation.key);\n },\n onCancel() {\n //\n },\n });\n break;\n }\n },\n });\n\n const ToolTip = (messageData: any) => {\n const finalResult = (messageData?.think || []).find((item: any) => item.actionName === 'FINISHED');\n if (!finalResult) return null;\n const { cost, token: tokenCount } = finalResult.extra || {};\n if (!cost && !token) return null;\n return (\n <div style={{ display: 'flex', alignItems: 'center', fontSize: '12px', color: '#949494', flex: 1, paddingRight: '40px' }}>\n { (cost !== undefined && cost !== null) && <div>{cost}s</div> }\n { tokenCount && <Divider type=\"vertical\" /> }\n { tokenCount && <div>{ tokenCount } tokens</div> }\n </div>\n );\n };\n // 是否展示清空按钮\n const clearBtnShow = typeof config?.chatProps?.clearBtnShow !== 'undefined'\n ? config.chatProps.clearBtnShow\n : !config?.session?.showSessionList;\n\n return (\n <ConfigProvider theme={{\n token: {\n colorPrimary: appInfo?.appTheme || primaryBlue,\n },\n }}\n >\n <XProvider>\n <XAiContext.Provider value={{\n avatar: <img src={icon} alt=\"智能体头像\" />,\n userAvatar: <img src={userIcon} alt=\"用户头像\" />,\n emptyStateImage: icon,\n emptyStateText: appName,\n footerTips: '内容由AI生成,无法确保真实准确,仅供参考',\n providerId,\n sessionList,\n sessionTotal: sessionPagination.total,\n token,\n messages,\n loading,\n error: null,\n activeKey: currentSessionId,\n clearBtnShow,\n inputShow: config?.chatProps?.inputShow || true,\n isNarrow,\n messageTooltip: ToolTip,\n messageActions: [...defaultActions, {\n key: 'like',\n tooltip: '赞',\n render: (i, msg) => {\n const isLike = msg.isLike === 1;\n if (isLike) {\n return (\n <LikeFilled style={{ color: appInfo?.appTheme || primaryBlue }} />\n );\n }\n return <LikeOutlined />;\n },\n }, {\n key: 'dislike',\n tooltip: '踩',\n render: (_i, msg) => {\n const requestId = msg.raw?.requestId;\n return (\n <DislikeFeedback\n msg={msg}\n activeColor={appInfo?.appTheme || primaryBlue}\n onSubmit={async (formData) => {\n const { result } = await addFeedback({\n ...formData,\n requestId,\n isLike: -1,\n url,\n appNo: config?.appNo,\n token,\n });\n if (result?.code === API_SUCCESS_CODE) {\n message.success('已收到您的反馈,我们会努力做的更好');\n setMessages((prev) => {\n return prev.map((item) => {\n if (item.id === msg.id) {\n return {\n ...item,\n isLike: -1,\n };\n }\n return item;\n });\n });\n return true;\n }\n message.error('反馈失败,请稍后再试');\n return false;\n }}\n />\n );\n },\n }],\n onSend: handleSendMessage,\n onClear: handleCreateNewMessage,\n onNewChat: handleCreateNewMessage,\n onStop: stopChat,\n menu: menuConfig,\n onActiveChange: handleActiveChange,\n onSuggestMessageClick: handleSuggestMessageClick,\n onMessagesActionsCallback: handleActions,\n isInProvider: true,\n }}\n >\n <div\n ref={divRef}\n style={{\n display: 'flex',\n height: '100%',\n position: 'relative',\n }}\n >\n {children}\n </div>\n </XAiContext.Provider>\n </XProvider>\n </ConfigProvider>\n );\n});\n\nexport default XAiProvider;\n"],
5
+ "mappings": "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",
6
6
  "names": ["useAgentGenerator", "_a", "copy", "userIcon", "DislikeFeedback"]
7
7
  }
@@ -7,13 +7,15 @@ export interface ADKQueuedMessage<T> {
7
7
  export interface ADKMessageQueueOptions<T> {
8
8
  sessionId: string;
9
9
  loading: boolean;
10
- send: (payload: T) => Promise<unknown> | void;
10
+ send: (payload: T, sessionId: string) => Promise<unknown> | void;
11
11
  stop: () => void;
12
12
  interrupt?: (sessionId: string) => Promise<unknown> | void;
13
13
  enabled?: boolean;
14
+ /** 允许离开会话后继续发送该会话的待发送消息。 */
15
+ drainInactiveSessions?: boolean;
14
16
  }
15
17
  /** 会话级发送队列;只缓存请求,不负责业务 UI 或打断接口的具体实现。 */
16
- export declare function useADKMessageQueue<T>({ sessionId, loading, send, stop, interrupt, enabled, }: ADKMessageQueueOptions<T>): {
18
+ export declare function useADKMessageQueue<T>({ sessionId, loading, send, stop, interrupt, enabled, drainInactiveSessions, }: ADKMessageQueueOptions<T>): {
17
19
  queuedMessages: ADKQueuedMessage<T>[];
18
20
  interrupting: boolean;
19
21
  sendOrQueue: (payload: T, preview?: string) => void;
@@ -30,13 +30,14 @@ function useADKMessageQueue({
30
30
  send,
31
31
  stop,
32
32
  interrupt,
33
- enabled = true
33
+ enabled = true,
34
+ drainInactiveSessions = false
34
35
  }) {
35
36
  const [queuedMessages, setQueuedMessages] = (0, import_react.useState)([]);
36
37
  const [interrupting, setInterrupting] = (0, import_react.useState)(false);
37
38
  const [drainTick, setDrainTick] = (0, import_react.useState)(0);
38
39
  const queueRef = (0, import_react.useRef)(queuedMessages);
39
- const busySessionRef = (0, import_react.useRef)(null);
40
+ const busySessionsRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
40
41
  const loadingRef = (0, import_react.useRef)(loading);
41
42
  const interruptingRef = (0, import_react.useRef)(false);
42
43
  const callbacksRef = (0, import_react.useRef)({ send, stop, interrupt });
@@ -48,12 +49,11 @@ function useADKMessageQueue({
48
49
  setQueuedMessages(next);
49
50
  }, []);
50
51
  const sendNext = (0, import_react.useCallback)((item) => {
51
- busySessionRef.current = item.sessionId;
52
+ busySessionsRef.current.add(item.sessionId);
52
53
  updateQueue((current) => current.filter((queued) => queued.id !== item.id));
53
- void Promise.resolve().then(() => callbacksRef.current.send(item.payload)).catch(() => {
54
+ void Promise.resolve().then(() => callbacksRef.current.send(item.payload, item.sessionId)).catch(() => {
54
55
  }).finally(() => {
55
- if (busySessionRef.current === item.sessionId)
56
- busySessionRef.current = null;
56
+ busySessionsRef.current.delete(item.sessionId);
57
57
  setDrainTick((tick) => tick + 1);
58
58
  });
59
59
  }, [updateQueue]);
@@ -61,7 +61,7 @@ function useADKMessageQueue({
61
61
  if (!sessionId || !enabled)
62
62
  return;
63
63
  const item = { id: (0, import_uuid.v4)(), sessionId, preview, payload };
64
- if (loadingRef.current || busySessionRef.current === sessionId || interruptingRef.current || queueRef.current.some((queued) => queued.sessionId === sessionId)) {
64
+ if (loadingRef.current || busySessionsRef.current.has(sessionId) || interruptingRef.current || queueRef.current.some((queued) => queued.sessionId === sessionId)) {
65
65
  updateQueue((current) => [...current, item]);
66
66
  } else {
67
67
  sendNext(item);
@@ -80,7 +80,7 @@ function useADKMessageQueue({
80
80
  updateQueue((current) => [selected, ...current.filter((item) => item.id !== id)]);
81
81
  try {
82
82
  await ((_b = (_a = callbacksRef.current).interrupt) == null ? void 0 : _b.call(_a, sessionId));
83
- if (loadingRef.current || busySessionRef.current === sessionId)
83
+ if (loadingRef.current || busySessionsRef.current.has(sessionId))
84
84
  callbacksRef.current.stop();
85
85
  } catch {
86
86
  } finally {
@@ -90,12 +90,14 @@ function useADKMessageQueue({
90
90
  }
91
91
  }, [sessionId, updateQueue]);
92
92
  (0, import_react.useEffect)(() => {
93
- if (!enabled || loading || busySessionRef.current === sessionId || interruptingRef.current)
93
+ if (!enabled || interruptingRef.current)
94
94
  return;
95
- const next = queueRef.current.find((item) => item.sessionId === sessionId);
95
+ const next = queueRef.current.find(
96
+ (item) => (drainInactiveSessions || item.sessionId === sessionId) && !busySessionsRef.current.has(item.sessionId) && !(item.sessionId === sessionId && loading)
97
+ );
96
98
  if (next)
97
99
  sendNext(next);
98
- }, [drainTick, enabled, loading, queuedMessages, sendNext, sessionId]);
100
+ }, [drainInactiveSessions, drainTick, enabled, loading, queuedMessages, sendNext, sessionId]);
99
101
  return { queuedMessages, interrupting, sendOrQueue, removeQueuedMessage, sendQueuedMessageNow };
100
102
  }
101
103
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/hooks/useADKMessageQueue.ts"],
4
- "sourcesContent": ["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { v4 } from \"uuid\";\n\nexport interface ADKQueuedMessage<T> {\n id: string;\n sessionId: string;\n preview: string;\n payload: T;\n}\n\nexport interface ADKMessageQueueOptions<T> {\n sessionId: string;\n loading: boolean;\n send: (payload: T) => Promise<unknown> | void;\n stop: () => void;\n interrupt?: (sessionId: string) => Promise<unknown> | void;\n enabled?: boolean;\n}\n\n/** 会话级发送队列;只缓存请求,不负责业务 UI 或打断接口的具体实现。 */\nexport function useADKMessageQueue<T>({\n sessionId,\n loading,\n send,\n stop,\n interrupt,\n enabled = true,\n}: ADKMessageQueueOptions<T>) {\n const [queuedMessages, setQueuedMessages] = useState<ADKQueuedMessage<T>[]>([]);\n const [interrupting, setInterrupting] = useState(false);\n const [drainTick, setDrainTick] = useState(0);\n const queueRef = useRef(queuedMessages);\n const busySessionRef = useRef<string | null>(null);\n const loadingRef = useRef(loading);\n const interruptingRef = useRef(false);\n const callbacksRef = useRef({ send, stop, interrupt });\n callbacksRef.current = { send, stop, interrupt };\n loadingRef.current = loading;\n\n const updateQueue = useCallback((update: (current: ADKQueuedMessage<T>[]) => ADKQueuedMessage<T>[]) => {\n const next = update(queueRef.current);\n queueRef.current = next;\n setQueuedMessages(next);\n }, []);\n\n const sendNext = useCallback((item: ADKQueuedMessage<T>) => {\n busySessionRef.current = item.sessionId;\n updateQueue((current) => current.filter((queued) => queued.id !== item.id));\n void Promise.resolve()\n .then(() => callbacksRef.current.send(item.payload))\n .catch(() => {\n // 发送错误由 transport 处理;队列仍需继续释放当前项。\n })\n .finally(() => {\n if (busySessionRef.current === item.sessionId) busySessionRef.current = null;\n setDrainTick((tick) => tick + 1);\n });\n }, [updateQueue]);\n\n const sendOrQueue = useCallback((payload: T, preview = \"\") => {\n if (!sessionId || !enabled) return;\n const item = { id: v4(), sessionId, preview, payload };\n if (loadingRef.current || busySessionRef.current === sessionId || interruptingRef.current || queueRef.current.some((queued) => queued.sessionId === sessionId)) {\n updateQueue((current) => [...current, item]);\n } else {\n sendNext(item);\n }\n }, [enabled, sessionId, sendNext, updateQueue]);\n\n const removeQueuedMessage = useCallback((id: string) => {\n updateQueue((current) => current.filter((item) => item.id !== id));\n }, [updateQueue]);\n\n const sendQueuedMessageNow = useCallback(async (id: string) => {\n const selected = queueRef.current.find((item) => item.id === id && item.sessionId === sessionId);\n if (!selected || interruptingRef.current) return;\n interruptingRef.current = true;\n setInterrupting(true);\n updateQueue((current) => [selected, ...current.filter((item) => item.id !== id)]);\n try {\n await callbacksRef.current.interrupt?.(sessionId);\n if (loadingRef.current || busySessionRef.current === sessionId) callbacksRef.current.stop();\n } catch {\n // 中断失败时维持当前回复;选中的消息仍留在队首等待正常完成。\n } finally {\n interruptingRef.current = false;\n setInterrupting(false);\n setDrainTick((tick) => tick + 1);\n }\n }, [sessionId, updateQueue]);\n\n useEffect(() => {\n if (!enabled || loading || busySessionRef.current === sessionId || interruptingRef.current) return;\n const next = queueRef.current.find((item) => item.sessionId === sessionId);\n if (next) sendNext(next);\n }, [drainTick, enabled, loading, queuedMessages, sendNext, sessionId]);\n\n return { queuedMessages, interrupting, sendOrQueue, removeQueuedMessage, sendQueuedMessageNow };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { v4 } from \"uuid\";\n\nexport interface ADKQueuedMessage<T> {\n id: string;\n sessionId: string;\n preview: string;\n payload: T;\n}\n\nexport interface ADKMessageQueueOptions<T> {\n sessionId: string;\n loading: boolean;\n send: (payload: T, sessionId: string) => Promise<unknown> | void;\n stop: () => void;\n interrupt?: (sessionId: string) => Promise<unknown> | void;\n enabled?: boolean;\n /** 允许离开会话后继续发送该会话的待发送消息。 */\n drainInactiveSessions?: boolean;\n}\n\n/** 会话级发送队列;只缓存请求,不负责业务 UI 或打断接口的具体实现。 */\nexport function useADKMessageQueue<T>({\n sessionId,\n loading,\n send,\n stop,\n interrupt,\n enabled = true,\n drainInactiveSessions = false,\n}: ADKMessageQueueOptions<T>) {\n const [queuedMessages, setQueuedMessages] = useState<ADKQueuedMessage<T>[]>([]);\n const [interrupting, setInterrupting] = useState(false);\n const [drainTick, setDrainTick] = useState(0);\n const queueRef = useRef(queuedMessages);\n const busySessionsRef = useRef(new Set<string>());\n const loadingRef = useRef(loading);\n const interruptingRef = useRef(false);\n const callbacksRef = useRef({ send, stop, interrupt });\n callbacksRef.current = { send, stop, interrupt };\n loadingRef.current = loading;\n\n const updateQueue = useCallback((update: (current: ADKQueuedMessage<T>[]) => ADKQueuedMessage<T>[]) => {\n const next = update(queueRef.current);\n queueRef.current = next;\n setQueuedMessages(next);\n }, []);\n\n const sendNext = useCallback((item: ADKQueuedMessage<T>) => {\n busySessionsRef.current.add(item.sessionId);\n updateQueue((current) => current.filter((queued) => queued.id !== item.id));\n void Promise.resolve()\n .then(() => callbacksRef.current.send(item.payload, item.sessionId))\n .catch(() => {\n // 发送错误由 transport 处理;队列仍需继续释放当前项。\n })\n .finally(() => {\n busySessionsRef.current.delete(item.sessionId);\n setDrainTick((tick) => tick + 1);\n });\n }, [updateQueue]);\n\n const sendOrQueue = useCallback((payload: T, preview = \"\") => {\n if (!sessionId || !enabled) return;\n const item = { id: v4(), sessionId, preview, payload };\n if (loadingRef.current || busySessionsRef.current.has(sessionId) || interruptingRef.current || queueRef.current.some((queued) => queued.sessionId === sessionId)) {\n updateQueue((current) => [...current, item]);\n } else {\n sendNext(item);\n }\n }, [enabled, sessionId, sendNext, updateQueue]);\n\n const removeQueuedMessage = useCallback((id: string) => {\n updateQueue((current) => current.filter((item) => item.id !== id));\n }, [updateQueue]);\n\n const sendQueuedMessageNow = useCallback(async (id: string) => {\n const selected = queueRef.current.find((item) => item.id === id && item.sessionId === sessionId);\n if (!selected || interruptingRef.current) return;\n interruptingRef.current = true;\n setInterrupting(true);\n updateQueue((current) => [selected, ...current.filter((item) => item.id !== id)]);\n try {\n await callbacksRef.current.interrupt?.(sessionId);\n if (loadingRef.current || busySessionsRef.current.has(sessionId)) callbacksRef.current.stop();\n } catch {\n // 中断失败时维持当前回复;选中的消息仍留在队首等待正常完成。\n } finally {\n interruptingRef.current = false;\n setInterrupting(false);\n setDrainTick((tick) => tick + 1);\n }\n }, [sessionId, updateQueue]);\n\n useEffect(() => {\n if (!enabled || interruptingRef.current) return;\n const next = queueRef.current.find(\n (item) =>\n (drainInactiveSessions || item.sessionId === sessionId) &&\n !busySessionsRef.current.has(item.sessionId) &&\n !(item.sessionId === sessionId && loading)\n );\n if (next) sendNext(next);\n }, [drainInactiveSessions, drainTick, enabled, loading, queuedMessages, sendNext, sessionId]);\n\n return { queuedMessages, interrupting, sendOrQueue, removeQueuedMessage, sendQueuedMessageNow };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -29,6 +29,32 @@ export interface ChatGroup {
29
29
  /** 点赞状态: 1=赞, -1=踩, 0=未反馈 */
30
30
  isLike?: number;
31
31
  }
32
+ /** 自定义消息流内容的定位上下文。按分组而非数组下标锚定,分页 prepend 后仍可稳定定位。 */
33
+ export interface ChatGroupRenderContext {
34
+ group: ChatGroup;
35
+ index: number;
36
+ previousGroup?: ChatGroup;
37
+ nextGroup?: ChatGroup;
38
+ }
39
+ /** 受控历史消息分页。不传时一次性展示 messages,保持原有行为。 */
40
+ export interface ChatHistoryPagination {
41
+ /** 是否仍有下一页;历史消息通常从顶部加载更早内容。 */
42
+ hasMore: boolean;
43
+ loading?: boolean;
44
+ /** top 加载更早消息,bottom 可用于正序列表加载后续内容。默认 top。 */
45
+ direction?: "top" | "bottom";
46
+ /** 距离指定边缘多少像素时触发加载,默认 80。 */
47
+ threshold?: number;
48
+ /** 使用方负责请求并合并 messages;建议以稳定消息 id 去重。 */
49
+ onLoadMore: (context: {
50
+ signal: AbortSignal;
51
+ }) => Promise<void>;
52
+ /** 可选的显式刷新操作;SDK 只触发回调,不规定请求方式。 */
53
+ onRefresh?: (context: {
54
+ signal: AbortSignal;
55
+ }) => Promise<void>;
56
+ refreshing?: boolean;
57
+ }
32
58
  export interface IInvocation {
33
59
  id: string;
34
60
  name: string;
@@ -301,6 +327,16 @@ export interface XAdkChatbotProps extends Partial<XAdkSenderProps> {
301
327
  loading?: boolean;
302
328
  /** 消息列表 */
303
329
  messages: IMessage[];
330
+ /** 在消息组前插入自定义模块,适合系统提示、日期或分支分界线。 */
331
+ renderBeforeGroup?: (context: ChatGroupRenderContext) => ReactNode;
332
+ /** 在消息组后插入自定义模块,适合与某轮回复关联的业务内容。 */
333
+ renderAfterGroup?: (context: ChatGroupRenderContext) => ReactNode;
334
+ /** 基于组内数据替换默认消息展示;返回 undefined 时沿用默认展示,null 表示隐藏。 */
335
+ renderGroup?: (context: ChatGroupRenderContext & {
336
+ defaultNode: ReactNode;
337
+ }) => ReactNode | undefined;
338
+ /** 按需加载消息。不传时仍一次性展示传入的全部 messages。 */
339
+ history?: ChatHistoryPagination;
304
340
  /** 开场白 */
305
341
  prologue?: string;
306
342
  /** 建议回复 */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/types/XAdkChatbot.ts"],
4
- "sourcesContent": ["import type { CSSProperties, JSX, ReactNode } from \"react\";\nimport { type XAdkSenderProps } from \"./XAdkSender\";\nimport { type SendContent } from \"./XAiSender\";\nimport { type FileItem } from \"./FileGallery\";\nimport { type ToolRenderKind } from \"./FunctionCallRender\";\nimport { type ChatPresetInput, type ChatStrategies } from \"./ChatStrategies\";\n\n/**\n * XAdkChatbot 命令式 API\n */\nexport interface XAdkChatbotHandle {\n /** 手动滚动到底部 */\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n /** 当前消息列表的滚动容器 */\n getScrollContainer: () => HTMLDivElement | null;\n /** 消息组相对滚动容器顶部的位置 */\n getMessagePosition: (messageId: string) => number | null;\n /** 滚动到指定消息组 */\n scrollToMessage: (messageId: string, behavior?: ScrollBehavior) => void;\n}\n\n/**\n * 消息分组接口\n */\nexport interface ChatGroup {\n id: string;\n role: \"user\" | \"bot\";\n msgs: IMessage[];\n invocationId?: string;\n allFiles: any[];\n /** 点赞状态: 1=赞, -1=踩, 0=未反馈 */\n isLike?: number;\n}\n\nexport interface IInvocation {\n id: string;\n name: string;\n spanId: string;\n traceId: string;\n parentSpanId: string;\n startTime: number;\n endTime: number;\n sessionId: string;\n invocationId: string;\n duration: number;\n attributes: Record<string, string>;\n botName: string;\n workspaceNo: string;\n status: number;\n agentName: string;\n agentNo: string;\n agentVersionNo: string;\n userId: string;\n}\n\nexport interface AgentRunRequest {\n stream?: boolean;\n sessionId: string | undefined;\n content: {\n parts: Array<{\n text?: string;\n functionResponse?: {\n id?: string;\n name?: string;\n response?: any;\n };\n }>;\n role: string;\n };\n files?: Array<{\n fileName: string;\n fileId?: string;\n tempUrl: string;\n type?: string;\n mimeType: string;\n }>;\n stateDelta?: any;\n}\nexport interface Blob {\n displayName?: string;\n mimeType?: string;\n data: string;\n}\n\nexport interface FunctionCall {\n id?: string;\n name: string;\n args: { [key: string]: any };\n}\n\nexport interface FunctionResponse {\n id?: string;\n name: string;\n response: { [key: string]: any };\n}\n\nexport interface FileData {\n displayName: string;\n mimeType: string;\n fileUri: string;\n}\n\nexport interface ExecutableCode {\n language: \"UNKNOWN\" | \"PYTHON\";\n code: string;\n}\n\nexport interface CodeExecutionResult {\n outcome: \"UNKNOWN\" | \"OK\" | \"FAILED\" | \"DEADLINE_EXCEEDED\";\n output: string;\n}\n\nexport interface Part {\n text?: string;\n inlineData?: Blob;\n functionCall?: FunctionCall;\n functionResponse?: FunctionResponse;\n thought?: boolean;\n fileData?: FileData;\n executableCode?: ExecutableCode;\n codeExecutionResult?: CodeExecutionResult;\n errorMessage?: string;\n}\n\nexport interface GenAiContent {\n role: string;\n parts: Part[];\n}\n\nexport interface LlmRequest {\n contents: GenAiContent[];\n}\n\nexport interface LlmResponse {\n partial?: boolean;\n content: GenAiContent;\n error?: string;\n errorMessage?: string;\n errorCode?: string;\n longRunningToolIds?: string[];\n}\n\nexport interface UsageMetadata {\n candidatesTokenCount?: number;\n promptTokenCount?: number;\n totalTokenCount?: number;\n [key: string]: any;\n}\n\nexport interface EventActions {\n message?: string;\n artifactDelta?: any;\n functionCall?: FunctionCall;\n functionResponse?: FunctionResponse;\n finishReason?: string;\n}\n\nexport interface Event extends LlmResponse {\n id?: string;\n author?: string;\n modelCode?: string;\n invocationId?: string;\n actions?: EventActions;\n longRunningToolIds?: string[];\n branch?: string;\n timestamp?: number;\n finishReason?: string;\n usageMetadata?: UsageMetadata;\n evalStatus?: any;\n failedMetric?: any;\n evalScore?: any;\n evalThreshold?: any;\n groundingMetadata?: {\n searchEntryPoint?: {\n renderedContent?: any;\n };\n };\n isLike?: number;\n sessionId?: string;\n}\n\nexport interface SessionState {\n [key: string]: unknown;\n}\n\nexport interface Session {\n id?: string;\n appName?: string;\n userId?: string;\n state?: SessionState;\n events?: Event[];\n lastUpdateTime?: number;\n}\n\nexport interface TimeTick {\n position: number;\n label: string;\n}\n\nexport interface IMessage {\n /** 前端生成的唯一标识 */\n id: string;\n /** 单次请求的唯一标识 */\n invocationId?: string;\n /** 单个Event的唯一标识,一个event里有可能有多个parts的消息 */\n eventId?: string;\n /** 消息发起人:智能体名称、user */\n author?: string;\n role: \"bot\" | \"user\";\n /** 时间戳 */\n timestamp?: number;\n isLoading?: boolean;\n /** 函数调用 */\n functionCall?: FunctionCall;\n /** 函数调用结果 */\n functionResponse?: FunctionResponse;\n /** 文件上传 */\n inlineData?: Blob;\n /** 文本消息 */\n text?: string;\n /** 文件信息 */\n fileData?: FileData[];\n /** 思考 */\n thought?: boolean;\n executableCode?: ExecutableCode;\n codeExecutionResult?: CodeExecutionResult;\n renderedContent?: any;\n /** 原始数据 */\n raw?: any;\n /** 模型编码,通常来自 stream 事件或历史消息 */\n modelCode?: string;\n /** 事件级 token 使用量等模型调用元数据 */\n usageMetadata?: UsageMetadata;\n /** 结束原因,通常来自最后一条 stream 事件 */\n finishReason?: string;\n // 下面暂时没有用到\n evalStatus?: any;\n failedMetric?: any;\n evalScore?: any;\n evalThreshold?: any;\n invocationIndex?: any;\n finalResponsePartIndex?: any;\n toolUseIndex?: any;\n /** 是否赞/踩 */\n isLike?: number;\n}\n\nexport type ActionProps = (data: {\n message: ChatGroup;\n isLastBotMsg: boolean;\n}) => JSX.Element | null;\n\nexport type ActionExtraProps = (data: {\n message: ChatGroup;\n isLastBotMsg: boolean;\n}) => ReactNode;\n\nexport type UserActionProps = (data: { message: ChatGroup }) => ReactNode | null;\n\nexport interface MarkdownResourceLink {\n /** 完整链接,如 skill://InnerSkill01 */\n href: string;\n /** Markdown 链接文字,如 @skill-creator */\n label: string;\n /** 协议类型,如 skill/plugin/knowledge */\n type: string;\n /** 协议值,如 InnerSkill01 */\n value: string;\n}\n\nexport type RenderMarkdownResourceLink = (\n link: MarkdownResourceLink,\n) => ReactNode | null;\n\n/**\n * 自定义工具调用渲染函数\n * - 返回 ReactNode:使用自定义渲染\n * - 返回 null:降级使用默认渲染\n *\n * @example\n * renderFunctionCall={(msg) => {\n * if (msg.functionCall?.name === 'my_tool') return <MyToolRender msg={msg} />;\n * return null; // 其他工具使用默认渲染\n * }}\n */\nexport type RenderFunctionCall = (msg: IMessage) => ReactNode | null;\n\n/** Markdown 自定义标签经过安全过滤后的结构化节点。 */\nexport interface MarkdownExtensionNode {\n tagName: string;\n attributes: Readonly<Record<string, string>>;\n text: string;\n children: ReactNode;\n}\n\n/**\n * Markdown 自定义标签扩展。\n * 标签及属性只有显式注册后才会交给渲染函数,业务协议无需进入 SDK 核心。\n */\nexport interface MarkdownExtension {\n tagName: string;\n allowedAttributes?: readonly string[];\n render: (node: MarkdownExtensionNode) => ReactNode | null;\n}\n\nexport interface XAdkChatbotProps extends Partial<XAdkSenderProps> {\n /**\n * 自定义工具调用渲染函数\n * 返回 null 则降级使用默认渲染\n */\n renderFunctionCall?: RenderFunctionCall;\n /**\n * 工具名 → 渲染类型的解析策略,默认使用 defaultToolKindResolver\n */\n toolKindResolver?: (name: string | undefined) => ToolRenderKind;\n /**\n * 聊天策略,可由 Provider preset 自动下发,也可在组件局部覆盖。\n */\n strategies?: ChatStrategies;\n /**\n * 组件直用时的协议预设。默认沿用 xgroup-adk 以兼容既有业务接入;\n * 需要中立行为时可传入 base。\n */\n preset?: ChatPresetInput;\n className?: string;\n style?: CSSProperties;\n // 加载状态\n loading?: boolean;\n /** 消息列表 */\n messages: IMessage[];\n /** 开场白 */\n prologue?: string;\n /** 建议回复 */\n suggestions?: string[];\n /** 欢迎页面 */\n welcome?: ReactNode;\n /** 显示函数调用详情 */\n showFnCallDetail?: boolean;\n /**\n * 数据是否就绪,就绪后触发首次自动滚底。默认 true。\n * 仅在需要等待异步加载历史消息的场景(如 XAdkProvider 内)才需设为 false,\n * 待数据加载完成后再切换为 true;独立使用时无需关心此属性。\n */\n initialized?: boolean;\n /**\n * 当前会话 ID,切换时自动重置滚动状态并置底。\n * 不传则退化为仅依赖 initialized 的单次置底行为。\n */\n sessionId?: string;\n /** 提交回调 */\n onSubmit?: ({ text, files }: SendContent) => void;\n /** 函数调用确认回调 */\n onConfirm?: (fnCall: FunctionCall, confirmed: boolean) => void;\n /** 停止回调 */\n onStop?: () => void;\n /** 清除回调 */\n onClear?: () => void;\n /** 建议回复回调 */\n onSuggest?: (text: string) => void;\n\n // ========== 新增功能 ==========\n\n /** Agent 名称 (欢迎页面) */\n agentName?: string;\n /** Agent 图标 (欢迎页面) */\n agentIcon?: string;\n /** Agent 描述 (欢迎页面) */\n description?: string;\n\n /** 是否显示重试按钮 */\n showRetry?: boolean;\n /** 是否显示复制按钮 */\n showCopy?: boolean;\n /** 是否显示日志按钮 */\n showLog?: boolean;\n\n /** 重试回调 */\n onRetry?: () => void;\n /** 复制回调 */\n onCopy?: (text: string) => void;\n /** 查看日志回调 */\n onShowLog?: (invocationId: string, timestamp?: number) => void;\n\n /** 是否启用消息分组 (默认 true) */\n enableGrouping?: boolean;\n\n /** 是否自动解析 process 内容并展示思维链 (默认 true) */\n enableProcessParsing?: boolean;\n\n /** 消息功能区 */\n actions?: ActionProps;\n /** 追加在消息功能区之后的内容,适合展示 token 消耗等业务扩展信息 */\n actionsExtra?: ActionExtraProps;\n\n /**\n * Process 解析选项\n * @example\n * // 业务项目格式 (注释模式)\n * parseOptions={{ mode: 'comment' }}\n *\n * @example\n * // 自定义格式\n * parseOptions={{\n * mode: 'custom',\n * customPatterns: [\n * { regex: /\\[REASONING\\]([\\s\\S]*?)\\[\\/REASONING\\]/g, type: 'reasoning' }\n * ]\n * }}\n */\n parseOptions?: {\n mode?: \"xml\" | \"comment\" | \"custom\";\n customPatterns?: Array<{ regex: RegExp; type: string }>;\n finalMarker?: string;\n };\n\n /** 是否禁用输入 */\n disabled?: boolean;\n\n /** 是否流式响应 */\n stream?: boolean;\n\n /** 点击对话中附件卡片的回调(非图片、非音视频文件) */\n onFileClick?: (file: FileItem) => void;\n\n /** 点击 Markdown 资源链接标签的回调,如 [@skill](skill://xxx) */\n onResourceLinkClick?: (link: MarkdownResourceLink) => void;\n\n /** 自定义 Markdown 资源链接渲染,返回 null 则降级使用默认标签样式 */\n renderResourceLink?: RenderMarkdownResourceLink;\n\n /** Markdown/XML 自定义标签扩展 */\n markdownExtensions?: readonly MarkdownExtension[];\n\n /** 消息列表为空时展示的自定义空状态组件 */\n empty?: ReactNode | (() => ReactNode);\n\n /** 是否启用用户消息 hover 操作栏(时间 + 复制),默认 false */\n showUserActions?: boolean;\n /** 用户消息自定义操作栏渲染,返回 null 则降级使用默认渲染 */\n userActions?: UserActionProps;\n}\n"],
4
+ "sourcesContent": ["import type { CSSProperties, JSX, ReactNode } from \"react\";\nimport { type XAdkSenderProps } from \"./XAdkSender\";\nimport { type SendContent } from \"./XAiSender\";\nimport { type FileItem } from \"./FileGallery\";\nimport { type ToolRenderKind } from \"./FunctionCallRender\";\nimport { type ChatPresetInput, type ChatStrategies } from \"./ChatStrategies\";\n\n/**\n * XAdkChatbot 命令式 API\n */\nexport interface XAdkChatbotHandle {\n /** 手动滚动到底部 */\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n /** 当前消息列表的滚动容器 */\n getScrollContainer: () => HTMLDivElement | null;\n /** 消息组相对滚动容器顶部的位置 */\n getMessagePosition: (messageId: string) => number | null;\n /** 滚动到指定消息组 */\n scrollToMessage: (messageId: string, behavior?: ScrollBehavior) => void;\n}\n\n/**\n * 消息分组接口\n */\nexport interface ChatGroup {\n id: string;\n role: \"user\" | \"bot\";\n msgs: IMessage[];\n invocationId?: string;\n allFiles: any[];\n /** 点赞状态: 1=赞, -1=踩, 0=未反馈 */\n isLike?: number;\n}\n\n/** 自定义消息流内容的定位上下文。按分组而非数组下标锚定,分页 prepend 后仍可稳定定位。 */\nexport interface ChatGroupRenderContext {\n group: ChatGroup;\n index: number;\n previousGroup?: ChatGroup;\n nextGroup?: ChatGroup;\n}\n\n/** 受控历史消息分页。不传时一次性展示 messages,保持原有行为。 */\nexport interface ChatHistoryPagination {\n /** 是否仍有下一页;历史消息通常从顶部加载更早内容。 */\n hasMore: boolean;\n loading?: boolean;\n /** top 加载更早消息,bottom 可用于正序列表加载后续内容。默认 top。 */\n direction?: \"top\" | \"bottom\";\n /** 距离指定边缘多少像素时触发加载,默认 80。 */\n threshold?: number;\n /** 使用方负责请求并合并 messages;建议以稳定消息 id 去重。 */\n onLoadMore: (context: { signal: AbortSignal }) => Promise<void>;\n /** 可选的显式刷新操作;SDK 只触发回调,不规定请求方式。 */\n onRefresh?: (context: { signal: AbortSignal }) => Promise<void>;\n refreshing?: boolean;\n}\n\nexport interface IInvocation {\n id: string;\n name: string;\n spanId: string;\n traceId: string;\n parentSpanId: string;\n startTime: number;\n endTime: number;\n sessionId: string;\n invocationId: string;\n duration: number;\n attributes: Record<string, string>;\n botName: string;\n workspaceNo: string;\n status: number;\n agentName: string;\n agentNo: string;\n agentVersionNo: string;\n userId: string;\n}\n\nexport interface AgentRunRequest {\n stream?: boolean;\n sessionId: string | undefined;\n content: {\n parts: Array<{\n text?: string;\n functionResponse?: {\n id?: string;\n name?: string;\n response?: any;\n };\n }>;\n role: string;\n };\n files?: Array<{\n fileName: string;\n fileId?: string;\n tempUrl: string;\n type?: string;\n mimeType: string;\n }>;\n stateDelta?: any;\n}\nexport interface Blob {\n displayName?: string;\n mimeType?: string;\n data: string;\n}\n\nexport interface FunctionCall {\n id?: string;\n name: string;\n args: { [key: string]: any };\n}\n\nexport interface FunctionResponse {\n id?: string;\n name: string;\n response: { [key: string]: any };\n}\n\nexport interface FileData {\n displayName: string;\n mimeType: string;\n fileUri: string;\n}\n\nexport interface ExecutableCode {\n language: \"UNKNOWN\" | \"PYTHON\";\n code: string;\n}\n\nexport interface CodeExecutionResult {\n outcome: \"UNKNOWN\" | \"OK\" | \"FAILED\" | \"DEADLINE_EXCEEDED\";\n output: string;\n}\n\nexport interface Part {\n text?: string;\n inlineData?: Blob;\n functionCall?: FunctionCall;\n functionResponse?: FunctionResponse;\n thought?: boolean;\n fileData?: FileData;\n executableCode?: ExecutableCode;\n codeExecutionResult?: CodeExecutionResult;\n errorMessage?: string;\n}\n\nexport interface GenAiContent {\n role: string;\n parts: Part[];\n}\n\nexport interface LlmRequest {\n contents: GenAiContent[];\n}\n\nexport interface LlmResponse {\n partial?: boolean;\n content: GenAiContent;\n error?: string;\n errorMessage?: string;\n errorCode?: string;\n longRunningToolIds?: string[];\n}\n\nexport interface UsageMetadata {\n candidatesTokenCount?: number;\n promptTokenCount?: number;\n totalTokenCount?: number;\n [key: string]: any;\n}\n\nexport interface EventActions {\n message?: string;\n artifactDelta?: any;\n functionCall?: FunctionCall;\n functionResponse?: FunctionResponse;\n finishReason?: string;\n}\n\nexport interface Event extends LlmResponse {\n id?: string;\n author?: string;\n modelCode?: string;\n invocationId?: string;\n actions?: EventActions;\n longRunningToolIds?: string[];\n branch?: string;\n timestamp?: number;\n finishReason?: string;\n usageMetadata?: UsageMetadata;\n evalStatus?: any;\n failedMetric?: any;\n evalScore?: any;\n evalThreshold?: any;\n groundingMetadata?: {\n searchEntryPoint?: {\n renderedContent?: any;\n };\n };\n isLike?: number;\n sessionId?: string;\n}\n\nexport interface SessionState {\n [key: string]: unknown;\n}\n\nexport interface Session {\n id?: string;\n appName?: string;\n userId?: string;\n state?: SessionState;\n events?: Event[];\n lastUpdateTime?: number;\n}\n\nexport interface TimeTick {\n position: number;\n label: string;\n}\n\nexport interface IMessage {\n /** 前端生成的唯一标识 */\n id: string;\n /** 单次请求的唯一标识 */\n invocationId?: string;\n /** 单个Event的唯一标识,一个event里有可能有多个parts的消息 */\n eventId?: string;\n /** 消息发起人:智能体名称、user */\n author?: string;\n role: \"bot\" | \"user\";\n /** 时间戳 */\n timestamp?: number;\n isLoading?: boolean;\n /** 函数调用 */\n functionCall?: FunctionCall;\n /** 函数调用结果 */\n functionResponse?: FunctionResponse;\n /** 文件上传 */\n inlineData?: Blob;\n /** 文本消息 */\n text?: string;\n /** 文件信息 */\n fileData?: FileData[];\n /** 思考 */\n thought?: boolean;\n executableCode?: ExecutableCode;\n codeExecutionResult?: CodeExecutionResult;\n renderedContent?: any;\n /** 原始数据 */\n raw?: any;\n /** 模型编码,通常来自 stream 事件或历史消息 */\n modelCode?: string;\n /** 事件级 token 使用量等模型调用元数据 */\n usageMetadata?: UsageMetadata;\n /** 结束原因,通常来自最后一条 stream 事件 */\n finishReason?: string;\n // 下面暂时没有用到\n evalStatus?: any;\n failedMetric?: any;\n evalScore?: any;\n evalThreshold?: any;\n invocationIndex?: any;\n finalResponsePartIndex?: any;\n toolUseIndex?: any;\n /** 是否赞/踩 */\n isLike?: number;\n}\n\nexport type ActionProps = (data: {\n message: ChatGroup;\n isLastBotMsg: boolean;\n}) => JSX.Element | null;\n\nexport type ActionExtraProps = (data: {\n message: ChatGroup;\n isLastBotMsg: boolean;\n}) => ReactNode;\n\nexport type UserActionProps = (data: { message: ChatGroup }) => ReactNode | null;\n\nexport interface MarkdownResourceLink {\n /** 完整链接,如 skill://InnerSkill01 */\n href: string;\n /** Markdown 链接文字,如 @skill-creator */\n label: string;\n /** 协议类型,如 skill/plugin/knowledge */\n type: string;\n /** 协议值,如 InnerSkill01 */\n value: string;\n}\n\nexport type RenderMarkdownResourceLink = (\n link: MarkdownResourceLink,\n) => ReactNode | null;\n\n/**\n * 自定义工具调用渲染函数\n * - 返回 ReactNode:使用自定义渲染\n * - 返回 null:降级使用默认渲染\n *\n * @example\n * renderFunctionCall={(msg) => {\n * if (msg.functionCall?.name === 'my_tool') return <MyToolRender msg={msg} />;\n * return null; // 其他工具使用默认渲染\n * }}\n */\nexport type RenderFunctionCall = (msg: IMessage) => ReactNode | null;\n\n/** Markdown 自定义标签经过安全过滤后的结构化节点。 */\nexport interface MarkdownExtensionNode {\n tagName: string;\n attributes: Readonly<Record<string, string>>;\n text: string;\n children: ReactNode;\n}\n\n/**\n * Markdown 自定义标签扩展。\n * 标签及属性只有显式注册后才会交给渲染函数,业务协议无需进入 SDK 核心。\n */\nexport interface MarkdownExtension {\n tagName: string;\n allowedAttributes?: readonly string[];\n render: (node: MarkdownExtensionNode) => ReactNode | null;\n}\n\nexport interface XAdkChatbotProps extends Partial<XAdkSenderProps> {\n /**\n * 自定义工具调用渲染函数\n * 返回 null 则降级使用默认渲染\n */\n renderFunctionCall?: RenderFunctionCall;\n /**\n * 工具名 → 渲染类型的解析策略,默认使用 defaultToolKindResolver\n */\n toolKindResolver?: (name: string | undefined) => ToolRenderKind;\n /**\n * 聊天策略,可由 Provider preset 自动下发,也可在组件局部覆盖。\n */\n strategies?: ChatStrategies;\n /**\n * 组件直用时的协议预设。默认沿用 xgroup-adk 以兼容既有业务接入;\n * 需要中立行为时可传入 base。\n */\n preset?: ChatPresetInput;\n className?: string;\n style?: CSSProperties;\n // 加载状态\n loading?: boolean;\n /** 消息列表 */\n messages: IMessage[];\n /** 在消息组前插入自定义模块,适合系统提示、日期或分支分界线。 */\n renderBeforeGroup?: (context: ChatGroupRenderContext) => ReactNode;\n /** 在消息组后插入自定义模块,适合与某轮回复关联的业务内容。 */\n renderAfterGroup?: (context: ChatGroupRenderContext) => ReactNode;\n /** 基于组内数据替换默认消息展示;返回 undefined 时沿用默认展示,null 表示隐藏。 */\n renderGroup?: (context: ChatGroupRenderContext & { defaultNode: ReactNode }) => ReactNode | undefined;\n /** 按需加载消息。不传时仍一次性展示传入的全部 messages。 */\n history?: ChatHistoryPagination;\n /** 开场白 */\n prologue?: string;\n /** 建议回复 */\n suggestions?: string[];\n /** 欢迎页面 */\n welcome?: ReactNode;\n /** 显示函数调用详情 */\n showFnCallDetail?: boolean;\n /**\n * 数据是否就绪,就绪后触发首次自动滚底。默认 true。\n * 仅在需要等待异步加载历史消息的场景(如 XAdkProvider 内)才需设为 false,\n * 待数据加载完成后再切换为 true;独立使用时无需关心此属性。\n */\n initialized?: boolean;\n /**\n * 当前会话 ID,切换时自动重置滚动状态并置底。\n * 不传则退化为仅依赖 initialized 的单次置底行为。\n */\n sessionId?: string;\n /** 提交回调 */\n onSubmit?: ({ text, files }: SendContent) => void;\n /** 函数调用确认回调 */\n onConfirm?: (fnCall: FunctionCall, confirmed: boolean) => void;\n /** 停止回调 */\n onStop?: () => void;\n /** 清除回调 */\n onClear?: () => void;\n /** 建议回复回调 */\n onSuggest?: (text: string) => void;\n\n // ========== 新增功能 ==========\n\n /** Agent 名称 (欢迎页面) */\n agentName?: string;\n /** Agent 图标 (欢迎页面) */\n agentIcon?: string;\n /** Agent 描述 (欢迎页面) */\n description?: string;\n\n /** 是否显示重试按钮 */\n showRetry?: boolean;\n /** 是否显示复制按钮 */\n showCopy?: boolean;\n /** 是否显示日志按钮 */\n showLog?: boolean;\n\n /** 重试回调 */\n onRetry?: () => void;\n /** 复制回调 */\n onCopy?: (text: string) => void;\n /** 查看日志回调 */\n onShowLog?: (invocationId: string, timestamp?: number) => void;\n\n /** 是否启用消息分组 (默认 true) */\n enableGrouping?: boolean;\n\n /** 是否自动解析 process 内容并展示思维链 (默认 true) */\n enableProcessParsing?: boolean;\n\n /** 消息功能区 */\n actions?: ActionProps;\n /** 追加在消息功能区之后的内容,适合展示 token 消耗等业务扩展信息 */\n actionsExtra?: ActionExtraProps;\n\n /**\n * Process 解析选项\n * @example\n * // 业务项目格式 (注释模式)\n * parseOptions={{ mode: 'comment' }}\n *\n * @example\n * // 自定义格式\n * parseOptions={{\n * mode: 'custom',\n * customPatterns: [\n * { regex: /\\[REASONING\\]([\\s\\S]*?)\\[\\/REASONING\\]/g, type: 'reasoning' }\n * ]\n * }}\n */\n parseOptions?: {\n mode?: \"xml\" | \"comment\" | \"custom\";\n customPatterns?: Array<{ regex: RegExp; type: string }>;\n finalMarker?: string;\n };\n\n /** 是否禁用输入 */\n disabled?: boolean;\n\n /** 是否流式响应 */\n stream?: boolean;\n\n /** 点击对话中附件卡片的回调(非图片、非音视频文件) */\n onFileClick?: (file: FileItem) => void;\n\n /** 点击 Markdown 资源链接标签的回调,如 [@skill](skill://xxx) */\n onResourceLinkClick?: (link: MarkdownResourceLink) => void;\n\n /** 自定义 Markdown 资源链接渲染,返回 null 则降级使用默认标签样式 */\n renderResourceLink?: RenderMarkdownResourceLink;\n\n /** Markdown/XML 自定义标签扩展 */\n markdownExtensions?: readonly MarkdownExtension[];\n\n /** 消息列表为空时展示的自定义空状态组件 */\n empty?: ReactNode | (() => ReactNode);\n\n /** 是否启用用户消息 hover 操作栏(时间 + 复制),默认 false */\n showUserActions?: boolean;\n /** 用户消息自定义操作栏渲染,返回 null 则降级使用默认渲染 */\n userActions?: UserActionProps;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -178,6 +178,18 @@ export interface SenderUIProps {
178
178
  * 业务/外层在此回调中决定如何处理文件(通常调用 senderRef.addFiles 注入)。
179
179
  */
180
180
  onFileSelect?: (files: File[]) => void;
181
+ /**
182
+ * 是否启用 Sender 自身的粘贴上传。
183
+ * 粘贴产生的文件通过 onFilePaste 回调交给业务/外层处理;
184
+ * 默认 true,粘贴是常用能力,开箱即用。设为 false 可完全关闭。
185
+ */
186
+ pasteable?: boolean;
187
+ /**
188
+ * 粘贴文件回调:当 pasteable 为 true 且用户向输入区粘贴文件(含截图)时触发。
189
+ * 业务/外层在此回调中决定如何处理文件(通常调用 senderRef.addFiles 注入)。
190
+ * 注意:纯文本粘贴不会触发本回调,输入框照常接收文本。
191
+ */
192
+ onFilePaste?: (files: File[]) => void;
181
193
  loading?: boolean;
182
194
  disabled?: boolean;
183
195
  placeholder?: string;
@@ -186,6 +198,12 @@ export interface SenderUIProps {
186
198
  /** 非受控:输入框默认值 */
187
199
  defaultValue?: string;
188
200
  onClear?: () => void;
201
+ /** 清除按钮的二次确认文案;未传时沿用 SDK 默认文案。 */
202
+ clearConfirm?: {
203
+ title?: React.ReactNode;
204
+ okText?: React.ReactNode;
205
+ cancelText?: React.ReactNode;
206
+ };
189
207
  onChange?: (value: string) => void;
190
208
  onSubmit?: (data: XAdkSenderSubmitData) => void;
191
209
  onStop?: () => void;
@@ -251,7 +269,8 @@ export interface SenderUIProps {
251
269
  }
252
270
  export type XAdkSenderProps = SenderUIProps & UploaderCoreProps;
253
271
  export interface XAdkSenderHandle {
254
- addFiles: (files: File[]) => void;
272
+ /** 添加本地文件或已上传文件;后者直接进入附件列表,不重复上传。 */
273
+ addFiles: (files: Array<File | ServerFile>) => void;
255
274
  /** 向当前光标位置插入一个内联 Mention;未启用 inlineTags 时会退化为追加 Mention。 */
256
275
  insertMention: (mention: MentionTag) => void;
257
276
  /** @deprecated 请使用 insertMention。 */