@ai-group/chat-sdk 3.7.1-alpha5 → 3.7.1-alpha8

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 (110) hide show
  1. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.d.ts +11 -1
  2. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +144 -14
  3. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js.map +2 -2
  4. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js +44 -0
  5. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
  6. package/dist/cjs/components/XAdkChatbot/index.d.ts +2 -2
  7. package/dist/cjs/components/XAdkChatbot/index.js +43 -13
  8. package/dist/cjs/components/XAdkChatbot/index.js.map +2 -2
  9. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.d.ts +7 -2
  10. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js +68 -17
  11. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js.map +2 -2
  12. package/dist/cjs/components/XAdkProvider/compound/Sender.d.ts +2 -1
  13. package/dist/cjs/components/XAdkProvider/compound/Sender.js.map +2 -2
  14. package/dist/cjs/components/XAdkProvider/compound/styles.d.ts +1 -0
  15. package/dist/cjs/components/XAdkProvider/compound/styles.js +16 -0
  16. package/dist/cjs/components/XAdkProvider/compound/styles.js.map +2 -2
  17. package/dist/cjs/components/XAdkProvider/context/ChatSenderStateContext.d.ts +4 -0
  18. package/dist/cjs/components/XAdkProvider/context/ChatSenderStateContext.js.map +2 -2
  19. package/dist/cjs/components/XAdkProvider/index.js +9 -8
  20. package/dist/cjs/components/XAdkProvider/index.js.map +2 -2
  21. package/dist/cjs/components/XAdkSender/InlineTagInput.js +223 -24
  22. package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
  23. package/dist/cjs/components/XAdkSender/InputTags.js.map +2 -2
  24. package/dist/cjs/components/XAdkSender/index.js +21 -55
  25. package/dist/cjs/components/XAdkSender/index.js.map +2 -2
  26. package/dist/cjs/components/XAdkSender/styles.js +13 -0
  27. package/dist/cjs/components/XAdkSender/styles.js.map +2 -2
  28. package/dist/cjs/hooks/useADKChat.js +5 -1
  29. package/dist/cjs/hooks/useADKChat.js.map +2 -2
  30. package/dist/cjs/index.d.ts +4 -3
  31. package/dist/cjs/index.js +14 -0
  32. package/dist/cjs/index.js.map +2 -2
  33. package/dist/cjs/presets/xgroup/index.d.ts +1 -0
  34. package/dist/cjs/presets/xgroup/index.js +2 -0
  35. package/dist/cjs/presets/xgroup/index.js.map +2 -2
  36. package/dist/cjs/presets/xgroup/knowledgeReference.d.ts +17 -0
  37. package/dist/cjs/presets/xgroup/knowledgeReference.js +160 -0
  38. package/dist/cjs/presets/xgroup/knowledgeReference.js.map +7 -0
  39. package/dist/cjs/presets/xgroup/preset.d.ts +3 -1
  40. package/dist/cjs/presets/xgroup/preset.js +17 -0
  41. package/dist/cjs/presets/xgroup/preset.js.map +2 -2
  42. package/dist/cjs/presets/xgroup/strategies.d.ts +1 -1
  43. package/dist/cjs/presets/xgroup/strategies.js +3 -5
  44. package/dist/cjs/presets/xgroup/strategies.js.map +2 -2
  45. package/dist/cjs/types/ChatStrategies.d.ts +3 -1
  46. package/dist/cjs/types/ChatStrategies.js.map +1 -1
  47. package/dist/cjs/types/XAdkChatbot.d.ts +18 -0
  48. package/dist/cjs/types/XAdkChatbot.js.map +1 -1
  49. package/dist/cjs/types/XAdkSender.d.ts +10 -3
  50. package/dist/cjs/types/XAdkSender.js.map +1 -1
  51. package/dist/cjs/utils/markdownResource.d.ts +5 -2
  52. package/dist/cjs/utils/markdownResource.js +57 -5
  53. package/dist/cjs/utils/markdownResource.js.map +2 -2
  54. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +11 -1
  55. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +147 -25
  56. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js.map +1 -1
  57. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js +2 -2
  58. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js.map +1 -1
  59. package/dist/esm/components/XAdkChatbot/index.d.ts +2 -2
  60. package/dist/esm/components/XAdkChatbot/index.js +36 -10
  61. package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
  62. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.d.ts +7 -2
  63. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js +64 -16
  64. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js.map +1 -1
  65. package/dist/esm/components/XAdkProvider/compound/Sender.d.ts +2 -1
  66. package/dist/esm/components/XAdkProvider/compound/Sender.js +2 -1
  67. package/dist/esm/components/XAdkProvider/compound/Sender.js.map +1 -1
  68. package/dist/esm/components/XAdkProvider/compound/styles.d.ts +1 -0
  69. package/dist/esm/components/XAdkProvider/compound/styles.js +3 -2
  70. package/dist/esm/components/XAdkProvider/compound/styles.js.map +1 -1
  71. package/dist/esm/components/XAdkProvider/context/ChatSenderStateContext.d.ts +4 -0
  72. package/dist/esm/components/XAdkProvider/context/ChatSenderStateContext.js.map +1 -1
  73. package/dist/esm/components/XAdkProvider/index.js +6 -2
  74. package/dist/esm/components/XAdkProvider/index.js.map +1 -1
  75. package/dist/esm/components/XAdkSender/InlineTagInput.js +209 -10
  76. package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
  77. package/dist/esm/components/XAdkSender/InputTags.js +1 -0
  78. package/dist/esm/components/XAdkSender/InputTags.js.map +1 -1
  79. package/dist/esm/components/XAdkSender/index.js +25 -58
  80. package/dist/esm/components/XAdkSender/index.js.map +1 -1
  81. package/dist/esm/components/XAdkSender/styles.js +1 -1
  82. package/dist/esm/components/XAdkSender/styles.js.map +1 -1
  83. package/dist/esm/hooks/useADKChat.js +8 -2
  84. package/dist/esm/hooks/useADKChat.js.map +1 -1
  85. package/dist/esm/index.d.ts +4 -3
  86. package/dist/esm/index.js +3 -4
  87. package/dist/esm/index.js.map +1 -1
  88. package/dist/esm/presets/xgroup/index.d.ts +1 -0
  89. package/dist/esm/presets/xgroup/index.js +1 -0
  90. package/dist/esm/presets/xgroup/index.js.map +1 -1
  91. package/dist/esm/presets/xgroup/knowledgeReference.d.ts +17 -0
  92. package/dist/esm/presets/xgroup/knowledgeReference.js +94 -0
  93. package/dist/esm/presets/xgroup/knowledgeReference.js.map +1 -0
  94. package/dist/esm/presets/xgroup/preset.d.ts +3 -1
  95. package/dist/esm/presets/xgroup/preset.js +15 -0
  96. package/dist/esm/presets/xgroup/preset.js.map +1 -1
  97. package/dist/esm/presets/xgroup/strategies.d.ts +1 -1
  98. package/dist/esm/presets/xgroup/strategies.js +3 -3
  99. package/dist/esm/presets/xgroup/strategies.js.map +1 -1
  100. package/dist/esm/types/ChatStrategies.d.ts +3 -1
  101. package/dist/esm/types/ChatStrategies.js.map +1 -1
  102. package/dist/esm/types/XAdkChatbot.d.ts +18 -0
  103. package/dist/esm/types/XAdkChatbot.js.map +1 -1
  104. package/dist/esm/types/XAdkSender.d.ts +10 -3
  105. package/dist/esm/types/XAdkSender.js.map +1 -1
  106. package/dist/esm/utils/markdownResource.d.ts +5 -2
  107. package/dist/esm/utils/markdownResource.js +66 -1
  108. package/dist/esm/utils/markdownResource.js.map +1 -1
  109. package/dist/umd/chat-sdk.min.js +1 -1
  110. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import "@ant-design/x-markdown/themes/light.css";
3
- import type { FileItem, MarkdownResourceLink, RenderMarkdownResourceLink } from "../../../../types";
3
+ import type { FileItem, MarkdownExtension, MarkdownResourceLink, RenderMarkdownResourceLink } from "../../../../types";
4
4
  export interface MarkdownRenderProps {
5
5
  text: string;
6
6
  /** 紧凑布局,适合用户消息气泡等内联场景 */
@@ -13,6 +13,16 @@ export interface MarkdownRenderProps {
13
13
  onResourceLinkClick?: (link: MarkdownResourceLink) => void;
14
14
  /** 自定义资源链接渲染,返回 null 时使用默认标签样式 */
15
15
  renderResourceLink?: RenderMarkdownResourceLink;
16
+ /** Markdown/XML 自定义标签扩展 */
17
+ markdownExtensions?: readonly MarkdownExtension[];
18
+ /**
19
+ * 将命中文件扩展名的裸 URL 当作纯文本展示,不升级为 FileGallery。
20
+ * 用户消息应如实展示输入文本,除资源链接等业务扩展外不做额外富化。
21
+ * 默认 false,保留 Agent 消息现有行为。
22
+ */
23
+ bareUrlAsText?: boolean;
24
+ /** 将已经丢失资源 URI 的 @name 兼容渲染成只读高亮标签。 */
25
+ highlightPlainMentions?: boolean;
16
26
  }
17
27
  declare const MarkdownRender: React.FC<MarkdownRenderProps>;
18
28
  export default MarkdownRender;
@@ -85,8 +85,12 @@ var extractExt = (str) => {
85
85
  return "";
86
86
  return match[1].toLowerCase();
87
87
  };
88
- var escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
89
- var escapeAttr = (value) => escapeHtml(value).replace(/"/g, "&quot;").replace(/'/g, "&#39;");
88
+ var escapeMarkdownLabel = (value) => value.replace(/\\/g, "\\\\").replace(/\]/g, "\\]");
89
+ var RESOURCE_LINK_SENTINEL = "https://xadk.local/resource";
90
+ var PLAIN_MENTION_SENTINEL = "https://xadk.local/mention";
91
+ var CUSTOM_TAG_NAME_REGEX = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/;
92
+ var CUSTOM_ATTRIBUTE_NAME_REGEX = /^[a-z][a-z0-9-]*$/;
93
+ var EMPTY_MARKDOWN_EXTENSIONS = [];
90
94
  var CodeComponent = (props) => {
91
95
  var _a;
92
96
  const { className, children } = props;
@@ -127,19 +131,59 @@ var extractText = (children) => {
127
131
  return extractText(children.props.children);
128
132
  return "";
129
133
  };
134
+ var getExtensionAttribute = (props, attribute) => {
135
+ const record = props;
136
+ const camelCase = attribute.replace(
137
+ /-([a-z])/g,
138
+ (_, char) => char.toUpperCase()
139
+ );
140
+ const compact = attribute.replaceAll("-", "");
141
+ const value = record[attribute] ?? record[camelCase] ?? record[compact];
142
+ return value === void 0 || value === null ? void 0 : String(value);
143
+ };
144
+ var getAllowedExtensionAttributes = (extension) => (extension.allowedAttributes || []).filter(
145
+ (attribute) => CUSTOM_ATTRIBUTE_NAME_REGEX.test(attribute) && !attribute.startsWith("on") && attribute !== "style" && attribute !== "srcdoc"
146
+ );
147
+ var createMarkdownExtensionComponent = (extension) => {
148
+ const MarkdownExtensionComponent = (props) => {
149
+ const attributes = Object.fromEntries(
150
+ getAllowedExtensionAttributes(extension).flatMap((attribute) => {
151
+ const value = getExtensionAttribute(props, attribute);
152
+ return value === void 0 ? [] : [[attribute, value]];
153
+ })
154
+ );
155
+ const node = {
156
+ tagName: extension.tagName,
157
+ attributes,
158
+ text: extractText(props.children).trim(),
159
+ children: props.children
160
+ };
161
+ const customNode = extension.render(node);
162
+ return customNode === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: props.children }) : customNode;
163
+ };
164
+ MarkdownExtensionComponent.displayName = `MarkdownExtension(${extension.tagName})`;
165
+ return MarkdownExtensionComponent;
166
+ };
130
167
  var MarkdownRender = ({
131
168
  text,
132
169
  compact = false,
133
170
  resourceLinkSchemes,
134
171
  onFileClick,
135
172
  onResourceLinkClick,
136
- renderResourceLink
173
+ renderResourceLink,
174
+ markdownExtensions = EMPTY_MARKDOWN_EXTENSIONS,
175
+ bareUrlAsText = false,
176
+ highlightPlainMentions = false
137
177
  }) => {
138
178
  const styles = (0, import_styles.useStyles)();
179
+ const displayText = highlightPlainMentions ? text.replace(
180
+ /(^|[^\[a-z0-9_])@([a-z0-9][a-z0-9._-]*)/gi,
181
+ (_source, prefix, label) => `${prefix}[${escapeMarkdownLabel(label)}](${PLAIN_MENTION_SENTINEL}?label=${encodeURIComponent(label)})`
182
+ ) : text;
139
183
  const markdown = (0, import_markdownResource.replaceMarkdownResourceLinks)(
140
- text,
184
+ displayText,
141
185
  (link) => {
142
- return `<resource-link href="${escapeAttr(link.href)}" label="${escapeAttr(link.label)}" type="${escapeAttr(link.type)}" value="${escapeAttr(link.value)}">${escapeHtml(link.label)}</resource-link>`;
186
+ return `[${escapeMarkdownLabel(link.label)}](${RESOURCE_LINK_SENTINEL}?href=${encodeURIComponent(link.href)}&label=${encodeURIComponent(link.label)})`;
143
187
  },
144
188
  { schemes: resourceLinkSchemes }
145
189
  ).replaceAll(/\/\*\s*PLANNING\s*\*\//g, '<tag type="planning"></tag>').replaceAll(/\/\*\s*REPLANNING\s*\*\//g, '<tag type="replanning"></tag>').replaceAll(/\/\*\s*REASONING\s*\*\//g, '<tag type="reasoning"></tag>').replaceAll(/\/\*\s*ACTION\s*\*\//g, '<tag type="action"></tag>').replaceAll(
@@ -155,6 +199,7 @@ var MarkdownRender = ({
155
199
  });
156
200
  if (!resourceLink)
157
201
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: props.children });
202
+ const displayLabel = (0, import_markdownResource.getMarkdownResourceDisplayLabel)(resourceLink.label);
158
203
  const customNode = renderResourceLink == null ? void 0 : renderResourceLink(resourceLink);
159
204
  if (customNode)
160
205
  return customNode;
@@ -164,8 +209,10 @@ var MarkdownRender = ({
164
209
  type: "button",
165
210
  className: styles.resourceLink,
166
211
  onClick: () => onResourceLinkClick == null ? void 0 : onResourceLinkClick(resourceLink),
167
- "aria-label": resourceLink.label,
168
- children: resourceLink.label
212
+ "aria-label": displayLabel,
213
+ "data-xadk-resource-link": resourceLink.type,
214
+ "data-resource-markdown": `[${resourceLink.label}](${resourceLink.href})`,
215
+ children: displayLabel
169
216
  }
170
217
  );
171
218
  },
@@ -176,14 +223,58 @@ var MarkdownRender = ({
176
223
  styles.resourceLink
177
224
  ]
178
225
  );
226
+ const PlainMentionComponent = import_react.default.useCallback(
227
+ (props) => {
228
+ const label = String(props.label || "") || extractText(props.children);
229
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
230
+ "span",
231
+ {
232
+ className: styles.resourceLink,
233
+ "aria-label": label,
234
+ "data-xadk-resource-link": "true",
235
+ children: label
236
+ }
237
+ );
238
+ },
239
+ [styles.resourceLink]
240
+ );
179
241
  const LinkComponent = import_react.default.useCallback(
180
242
  (props) => {
181
243
  const href = String(props.href || "");
182
244
  const linkText = extractText(props.children);
183
- const resourceLink = (0, import_markdownResource.parseMarkdownResourceHref)(href, linkText, {
184
- schemes: resourceLinkSchemes
185
- });
245
+ let resolvedHref = href;
246
+ let resolvedLabel = linkText;
247
+ try {
248
+ const internalUrl = new URL(href);
249
+ if (internalUrl.origin + internalUrl.pathname === PLAIN_MENTION_SENTINEL) {
250
+ const label = internalUrl.searchParams.get("label") || linkText;
251
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
252
+ "span",
253
+ {
254
+ className: styles.resourceLink,
255
+ "aria-label": label,
256
+ "data-xadk-resource-link": "true",
257
+ children: label
258
+ }
259
+ );
260
+ }
261
+ if (internalUrl.origin + internalUrl.pathname === RESOURCE_LINK_SENTINEL) {
262
+ resolvedHref = internalUrl.searchParams.get("href") || "";
263
+ resolvedLabel = internalUrl.searchParams.get("label") || linkText;
264
+ }
265
+ } catch {
266
+ }
267
+ const resourceLink = (0, import_markdownResource.parseMarkdownResourceHref)(
268
+ resolvedHref,
269
+ resolvedLabel,
270
+ {
271
+ schemes: resourceLinkSchemes
272
+ }
273
+ );
186
274
  if (resourceLink) {
275
+ const displayLabel = (0, import_markdownResource.getMarkdownResourceDisplayLabel)(
276
+ resourceLink.label
277
+ );
187
278
  const customNode = renderResourceLink == null ? void 0 : renderResourceLink(resourceLink);
188
279
  if (customNode)
189
280
  return customNode;
@@ -193,8 +284,10 @@ var MarkdownRender = ({
193
284
  type: "button",
194
285
  className: styles.resourceLink,
195
286
  onClick: () => onResourceLinkClick == null ? void 0 : onResourceLinkClick(resourceLink),
196
- "aria-label": resourceLink.label,
197
- children: resourceLink.label
287
+ "aria-label": displayLabel,
288
+ "data-xadk-resource-link": resourceLink.type,
289
+ "data-resource-markdown": `[${resourceLink.label}](${resourceLink.href})`,
290
+ children: displayLabel
198
291
  }
199
292
  );
200
293
  }
@@ -202,6 +295,9 @@ var MarkdownRender = ({
202
295
  if (ext) {
203
296
  if (!href)
204
297
  return null;
298
+ if (bareUrlAsText) {
299
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: linkText || href });
300
+ }
205
301
  const mimeType = MIME_MAP[ext] || "";
206
302
  const fileItem = {
207
303
  displayName: linkText || href,
@@ -223,9 +319,40 @@ var MarkdownRender = ({
223
319
  onResourceLinkClick,
224
320
  renderResourceLink,
225
321
  resourceLinkSchemes,
226
- styles.resourceLink
322
+ styles.resourceLink,
323
+ bareUrlAsText
227
324
  ]
228
325
  );
326
+ const enabledMarkdownExtensions = import_react.default.useMemo(() => {
327
+ const registeredTags = /* @__PURE__ */ new Set();
328
+ return markdownExtensions.filter((extension) => {
329
+ const tagName = extension.tagName.toLowerCase();
330
+ if (!CUSTOM_TAG_NAME_REGEX.test(tagName) || registeredTags.has(tagName)) {
331
+ return false;
332
+ }
333
+ registeredTags.add(tagName);
334
+ return true;
335
+ });
336
+ }, [markdownExtensions]);
337
+ const dompurifyConfig = import_react.default.useMemo(() => {
338
+ const allowedAttributes = Array.from(
339
+ new Set(
340
+ enabledMarkdownExtensions.flatMap((extension) => [
341
+ ...getAllowedExtensionAttributes(extension)
342
+ ])
343
+ )
344
+ );
345
+ return allowedAttributes.length ? { ADD_ATTR: allowedAttributes } : void 0;
346
+ }, [enabledMarkdownExtensions]);
347
+ const extensionComponents = import_react.default.useMemo(
348
+ () => Object.fromEntries(
349
+ enabledMarkdownExtensions.map((extension) => [
350
+ extension.tagName.toLowerCase(),
351
+ createMarkdownExtensionComponent(extension)
352
+ ])
353
+ ),
354
+ [enabledMarkdownExtensions]
355
+ );
229
356
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
230
357
  "div",
231
358
  {
@@ -240,14 +367,17 @@ var MarkdownRender = ({
240
367
  content: markdown,
241
368
  className: "x-markdown-light",
242
369
  paragraphTag: "div",
370
+ dompurifyConfig,
243
371
  config: {
244
372
  extensions: (0, import_Latex.default)()
245
373
  },
246
374
  components: {
247
375
  tag: ThinkComponent,
248
376
  "resource-link": ResourceLinkComponent,
377
+ "plain-mention": PlainMentionComponent,
249
378
  code: CodeComponent,
250
- a: LinkComponent
379
+ a: LinkComponent,
380
+ ...extensionComponents
251
381
  },
252
382
  streaming: {
253
383
  enableAnimation: true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/XAdkChatbot/components/MarkdownRender/index.tsx"],
4
- "sourcesContent": ["import React from \"react\";\nimport XMarkdown, { type ComponentProps } from \"@ant-design/x-markdown\";\nimport \"@ant-design/x-markdown/themes/light.css\";\nimport { CodeHighlighter } from \"@ant-design/x\";\nimport { Flex } from \"antd\";\nimport Latex from \"@ant-design/x-markdown/plugins/Latex\";\nimport { useStyles } from \"./styles\";\nimport {\n BarsOutlined,\n BulbOutlined,\n ThunderboltOutlined,\n CheckCircleOutlined,\n} from \"@ant-design/icons\";\nimport FileGallery from \"@/components/FileGallery\";\nimport type {\n FileItem,\n MarkdownResourceLink,\n RenderMarkdownResourceLink,\n} from \"@/types\";\nimport {\n parseMarkdownResourceHref,\n replaceMarkdownResourceLinks,\n} from \"@/utils/markdownResource\";\n\n// 支持识别的文件扩展名\nconst FILE_EXT_REGEX =\n /\\.(pdf|doc|docx|xls|xlsx|csv|ppt|pptx|zip|rar|7z|txt|md|json|xml|mp3|wav|m4a|aac|ogg|flac|mp4|mov|webm|mkv|avi|png|jpg|jpeg|gif|webp|bmp|svg)(\\?.*)?$/i;\n\nconst MIME_MAP: Record<string, string> = {\n pdf: \"application/pdf\",\n doc: \"application/msword\",\n docx: \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n xls: \"application/vnd.ms-excel\",\n xlsx: \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n csv: \"text/csv\",\n ppt: \"application/vnd.ms-powerpoint\",\n pptx: \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n zip: \"application/zip\",\n rar: \"application/x-rar-compressed\",\n \"7z\": \"application/x-7z-compressed\",\n txt: \"text/plain\",\n md: \"text/markdown\",\n json: \"application/json\",\n xml: \"application/xml\",\n mp3: \"audio/mpeg\",\n wav: \"audio/wav\",\n m4a: \"audio/mp4\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n flac: \"audio/flac\",\n mp4: \"video/mp4\",\n mov: \"video/quicktime\",\n webm: \"video/webm\",\n mkv: \"video/x-matroska\",\n avi: \"video/x-msvideo\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n bmp: \"image/bmp\",\n svg: \"image/svg+xml\",\n};\n\n/**\n * 从字符串中提取文件扩展名(小写,不含点和查询参数)\n */\nconst extractExt = (str: string): string => {\n const match = str.match(FILE_EXT_REGEX);\n if (!match) return \"\";\n return match[1].toLowerCase();\n};\n\nconst escapeHtml = (value: string) =>\n value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\nconst escapeAttr = (value: string) =>\n escapeHtml(value).replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\n\nconst CodeComponent: React.FC<ComponentProps> = (props) => {\n const { className, children } = props;\n const lang = className?.match(/language-(\\S+)/)?.[1] || \"\";\n\n if (typeof children !== \"string\") return null;\n return <CodeHighlighter lang={lang}>{children}</CodeHighlighter>;\n};\n\nexport interface MarkdownRenderProps {\n text: string;\n /** 紧凑布局,适合用户消息气泡等内联场景 */\n compact?: boolean;\n /** Markdown 资源链接协议白名单,未命中的协议保持普通 Markdown 行为 */\n resourceLinkSchemes?: readonly string[];\n /** 点击 Markdown 中识别到的文件链接的回调 */\n onFileClick?: (file: FileItem) => void;\n /** 点击 Markdown 中识别到的资源链接标签,如 [@skill](skill://xxx) */\n onResourceLinkClick?: (link: MarkdownResourceLink) => void;\n /** 自定义资源链接渲染,返回 null 时使用默认标签样式 */\n renderResourceLink?: RenderMarkdownResourceLink;\n}\n\nconst ThinkComponent = React.memo((props: ComponentProps) => {\n const type = (props.type || \"\") as string;\n const titleMap: Record<string, string> = {\n planning: \"规划\",\n replanning: \"重新规划\",\n reasoning: \"推理\",\n action: \"行动\",\n final_answer: \"最终答案\",\n };\n const iconMap = {\n planning: <BarsOutlined />,\n replanning: <BarsOutlined />,\n reasoning: <BulbOutlined />,\n action: <ThunderboltOutlined />,\n final_answer: <CheckCircleOutlined />,\n };\n\n return (\n <Flex align=\"center\" gap={8} style={{ color: \"#888\", margin: \"4px 0\" }}>\n {type in titleMap && iconMap[type as keyof typeof iconMap]}\n {titleMap[type] && <span>{titleMap[type]}</span>}\n </Flex>\n );\n});\n\n/**\n * 递归从 React children 中提取纯文本\n */\nconst extractText = (children: React.ReactNode): string => {\n if (typeof children === \"string\") return children;\n if (typeof children === \"number\") return String(children);\n if (Array.isArray(children)) return children.map(extractText).join(\"\");\n if (React.isValidElement(children))\n return extractText((children.props as any).children);\n return \"\";\n};\n\nconst MarkdownRender: React.FC<MarkdownRenderProps> = ({\n text,\n compact = false,\n resourceLinkSchemes,\n onFileClick,\n onResourceLinkClick,\n renderResourceLink,\n}) => {\n const styles = useStyles();\n const markdown = replaceMarkdownResourceLinks(\n text,\n (link) => {\n // 非 http(s) 协议容易被 Markdown 引擎清洗成普通文本,先转为内部自定义标签再交给 XMarkdown。\n return `<resource-link href=\"${escapeAttr(link.href)}\" label=\"${escapeAttr(link.label)}\" type=\"${escapeAttr(link.type)}\" value=\"${escapeAttr(link.value)}\">${escapeHtml(link.label)}</resource-link>`;\n },\n { schemes: resourceLinkSchemes },\n )\n .replaceAll(/\\/\\*\\s*PLANNING\\s*\\*\\//g, '<tag type=\"planning\"></tag>')\n .replaceAll(/\\/\\*\\s*REPLANNING\\s*\\*\\//g, '<tag type=\"replanning\"></tag>')\n .replaceAll(/\\/\\*\\s*REASONING\\s*\\*\\//g, '<tag type=\"reasoning\"></tag>')\n .replaceAll(/\\/\\*\\s*ACTION\\s*\\*\\//g, '<tag type=\"action\"></tag>')\n .replaceAll(\n /\\/\\*\\s*FINAL_ANSWER\\s*\\*\\//g,\n '<tag type=\"final_answer\"></tag>',\n );\n\n const ResourceLinkComponent = React.useCallback(\n (props: ComponentProps) => {\n const href = String((props.href as string) || \"\");\n const linkText =\n String((props.label as string) || \"\") || extractText(props.children);\n const resourceLink = parseMarkdownResourceHref(href, linkText, {\n schemes: resourceLinkSchemes,\n });\n if (!resourceLink) return <>{props.children as React.ReactNode}</>;\n\n const customNode = renderResourceLink?.(resourceLink);\n if (customNode) return customNode;\n\n return (\n <button\n type=\"button\"\n className={styles.resourceLink}\n onClick={() => onResourceLinkClick?.(resourceLink)}\n aria-label={resourceLink.label}\n >\n {resourceLink.label}\n </button>\n );\n },\n [\n onResourceLinkClick,\n renderResourceLink,\n resourceLinkSchemes,\n styles.resourceLink,\n ],\n );\n\n // 自定义 a 标签渲染:资源协议渲染为标签,文件链接渲染为 FileGallery,其余保持普通链接。\n const LinkComponent = React.useCallback(\n (props: ComponentProps) => {\n const href = String((props.href as string) || \"\");\n // 用递归提取纯文本,避免 children 是 React node 时 String() 得到 \"[object Object]\"\n const linkText = extractText(props.children);\n const resourceLink = parseMarkdownResourceHref(href, linkText, {\n schemes: resourceLinkSchemes,\n });\n\n if (resourceLink) {\n const customNode = renderResourceLink?.(resourceLink);\n if (customNode) return customNode;\n\n return (\n <button\n type=\"button\"\n className={styles.resourceLink}\n onClick={() => onResourceLinkClick?.(resourceLink)}\n aria-label={resourceLink.label}\n >\n {resourceLink.label}\n </button>\n );\n }\n\n // 先识别 name(链接文字),再识别 url(href)\n const ext = extractExt(linkText) || extractExt(href);\n\n if (ext) {\n // href 为空说明链接还在流式截断中,不渲染,避免显示出错误文字\n if (!href) return null;\n const mimeType = MIME_MAP[ext] || \"\";\n const fileItem: FileItem = {\n displayName: linkText || href,\n mimeType,\n fileUri: href,\n };\n return (\n <FileGallery\n file={fileItem}\n onClick={onFileClick ? () => onFileClick(fileItem) : undefined}\n />\n );\n }\n\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {props.children as React.ReactNode}\n </a>\n );\n },\n [\n onFileClick,\n onResourceLinkClick,\n renderResourceLink,\n resourceLinkSchemes,\n styles.resourceLink,\n ],\n );\n\n return (\n <div\n className={`${styles.markdownWrapper}${compact ? ` ${styles.markdownWrapperCompact}` : \"\"}`}\n >\n <div\n className={`${styles.markdownHost}${compact ? ` ${styles.markdownHostCompact}` : \"\"}`}\n >\n <XMarkdown\n content={markdown}\n className=\"x-markdown-light\"\n paragraphTag=\"div\"\n config={{\n extensions: Latex(),\n }}\n components={{\n tag: ThinkComponent,\n \"resource-link\": ResourceLinkComponent,\n code: CodeComponent,\n a: LinkComponent,\n }}\n streaming={{\n enableAnimation: true,\n animationConfig: {\n fadeDuration: 400,\n },\n }}\n />\n </div>\n </div>\n );\n};\n\nexport default MarkdownRender;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import React from \"react\";\nimport XMarkdown, { type ComponentProps } from \"@ant-design/x-markdown\";\nimport \"@ant-design/x-markdown/themes/light.css\";\nimport { CodeHighlighter } from \"@ant-design/x\";\nimport { Flex } from \"antd\";\nimport Latex from \"@ant-design/x-markdown/plugins/Latex\";\nimport { useStyles } from \"./styles\";\nimport {\n BarsOutlined,\n BulbOutlined,\n ThunderboltOutlined,\n CheckCircleOutlined,\n} from \"@ant-design/icons\";\nimport FileGallery from \"@/components/FileGallery\";\nimport type {\n FileItem,\n MarkdownExtension,\n MarkdownExtensionNode,\n MarkdownResourceLink,\n RenderMarkdownResourceLink,\n} from \"@/types\";\nimport {\n parseMarkdownResourceHref,\n getMarkdownResourceDisplayLabel,\n replaceMarkdownResourceLinks,\n} from \"@/utils/markdownResource\";\n\n// 支持识别的文件扩展名\nconst FILE_EXT_REGEX =\n /\\.(pdf|doc|docx|xls|xlsx|csv|ppt|pptx|zip|rar|7z|txt|md|json|xml|mp3|wav|m4a|aac|ogg|flac|mp4|mov|webm|mkv|avi|png|jpg|jpeg|gif|webp|bmp|svg)(\\?.*)?$/i;\n\nconst MIME_MAP: Record<string, string> = {\n pdf: \"application/pdf\",\n doc: \"application/msword\",\n docx: \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n xls: \"application/vnd.ms-excel\",\n xlsx: \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n csv: \"text/csv\",\n ppt: \"application/vnd.ms-powerpoint\",\n pptx: \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n zip: \"application/zip\",\n rar: \"application/x-rar-compressed\",\n \"7z\": \"application/x-7z-compressed\",\n txt: \"text/plain\",\n md: \"text/markdown\",\n json: \"application/json\",\n xml: \"application/xml\",\n mp3: \"audio/mpeg\",\n wav: \"audio/wav\",\n m4a: \"audio/mp4\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n flac: \"audio/flac\",\n mp4: \"video/mp4\",\n mov: \"video/quicktime\",\n webm: \"video/webm\",\n mkv: \"video/x-matroska\",\n avi: \"video/x-msvideo\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n webp: \"image/webp\",\n bmp: \"image/bmp\",\n svg: \"image/svg+xml\",\n};\n\n/**\n * 从字符串中提取文件扩展名(小写,不含点和查询参数)\n */\nconst extractExt = (str: string): string => {\n const match = str.match(FILE_EXT_REGEX);\n if (!match) return \"\";\n return match[1].toLowerCase();\n};\n\nconst escapeMarkdownLabel = (value: string) =>\n value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\]/g, \"\\\\]\");\n\n// 使用标准 https 链接作为 Markdown AST 的内部载体,避免自定义 HTML 标签被解析器降级成纯文本。\nconst RESOURCE_LINK_SENTINEL = \"https://xadk.local/resource\";\nconst PLAIN_MENTION_SENTINEL = \"https://xadk.local/mention\";\n// 仅开放符合 Custom Element 命名规则的标签,避免覆盖 a/code 等内置 Markdown 节点。\nconst CUSTOM_TAG_NAME_REGEX = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/;\nconst CUSTOM_ATTRIBUTE_NAME_REGEX = /^[a-z][a-z0-9-]*$/;\nconst EMPTY_MARKDOWN_EXTENSIONS: readonly MarkdownExtension[] = [];\n\nconst CodeComponent: React.FC<ComponentProps> = (props) => {\n const { className, children } = props;\n const lang = className?.match(/language-(\\S+)/)?.[1] || \"\";\n\n if (typeof children !== \"string\") return null;\n return <CodeHighlighter lang={lang}>{children}</CodeHighlighter>;\n};\n\nexport interface MarkdownRenderProps {\n text: string;\n /** 紧凑布局,适合用户消息气泡等内联场景 */\n compact?: boolean;\n /** Markdown 资源链接协议白名单,未命中的协议保持普通 Markdown 行为 */\n resourceLinkSchemes?: readonly string[];\n /** 点击 Markdown 中识别到的文件链接的回调 */\n onFileClick?: (file: FileItem) => void;\n /** 点击 Markdown 中识别到的资源链接标签,如 [@skill](skill://xxx) */\n onResourceLinkClick?: (link: MarkdownResourceLink) => void;\n /** 自定义资源链接渲染,返回 null 时使用默认标签样式 */\n renderResourceLink?: RenderMarkdownResourceLink;\n /** Markdown/XML 自定义标签扩展 */\n markdownExtensions?: readonly MarkdownExtension[];\n /**\n * 将命中文件扩展名的裸 URL 当作纯文本展示,不升级为 FileGallery。\n * 用户消息应如实展示输入文本,除资源链接等业务扩展外不做额外富化。\n * 默认 false,保留 Agent 消息现有行为。\n */\n bareUrlAsText?: boolean;\n /** 将已经丢失资源 URI 的 @name 兼容渲染成只读高亮标签。 */\n highlightPlainMentions?: boolean;\n}\n\nconst ThinkComponent = React.memo((props: ComponentProps) => {\n const type = (props.type || \"\") as string;\n const titleMap: Record<string, string> = {\n planning: \"规划\",\n replanning: \"重新规划\",\n reasoning: \"推理\",\n action: \"行动\",\n final_answer: \"最终答案\",\n };\n const iconMap = {\n planning: <BarsOutlined />,\n replanning: <BarsOutlined />,\n reasoning: <BulbOutlined />,\n action: <ThunderboltOutlined />,\n final_answer: <CheckCircleOutlined />,\n };\n\n return (\n <Flex align=\"center\" gap={8} style={{ color: \"#888\", margin: \"4px 0\" }}>\n {type in titleMap && iconMap[type as keyof typeof iconMap]}\n {titleMap[type] && <span>{titleMap[type]}</span>}\n </Flex>\n );\n});\n\n/**\n * 递归从 React children 中提取纯文本\n */\nconst extractText = (children: React.ReactNode): string => {\n if (typeof children === \"string\") return children;\n if (typeof children === \"number\") return String(children);\n if (Array.isArray(children)) return children.map(extractText).join(\"\");\n if (React.isValidElement(children))\n return extractText((children.props as any).children);\n return \"\";\n};\n\n// 从组件 props 中获取自定义 Markdown 扩展属性值,支持 kebab-case、camelCase 和 compactCase。\nconst getExtensionAttribute = (\n props: ComponentProps,\n attribute: string,\n): string | undefined => {\n const record = props as Record<string, unknown>;\n const camelCase = attribute.replace(/-([a-z])/g, (_, char: string) =>\n char.toUpperCase(),\n );\n const compact = attribute.replaceAll(\"-\", \"\");\n const value = record[attribute] ?? record[camelCase] ?? record[compact];\n return value === undefined || value === null ? undefined : String(value);\n};\n\n// 仅允许自定义 Markdown 扩展的安全属性,避免 XSS 注入。s\nconst getAllowedExtensionAttributes = (extension: MarkdownExtension) =>\n (extension.allowedAttributes || []).filter(\n (attribute) =>\n CUSTOM_ATTRIBUTE_NAME_REGEX.test(attribute) &&\n !attribute.startsWith(\"on\") &&\n attribute !== \"style\" &&\n attribute !== \"srcdoc\",\n );\n\nconst createMarkdownExtensionComponent = (\n extension: MarkdownExtension,\n): React.FC<ComponentProps> => {\n const MarkdownExtensionComponent: React.FC<ComponentProps> = (props) => {\n const attributes = Object.fromEntries(\n getAllowedExtensionAttributes(extension).flatMap((attribute) => {\n const value = getExtensionAttribute(props, attribute);\n return value === undefined ? [] : [[attribute, value]];\n }),\n );\n const node: MarkdownExtensionNode = {\n tagName: extension.tagName,\n attributes,\n text: extractText(props.children).trim(),\n children: props.children as React.ReactNode,\n };\n const customNode = extension.render(node);\n return customNode === null ? (\n <>{props.children as React.ReactNode}</>\n ) : (\n customNode\n );\n };\n MarkdownExtensionComponent.displayName = `MarkdownExtension(${extension.tagName})`;\n return MarkdownExtensionComponent;\n};\n\nconst MarkdownRender: React.FC<MarkdownRenderProps> = ({\n text,\n compact = false,\n resourceLinkSchemes,\n onFileClick,\n onResourceLinkClick,\n renderResourceLink,\n markdownExtensions = EMPTY_MARKDOWN_EXTENSIONS,\n bareUrlAsText = false,\n highlightPlainMentions = false,\n}) => {\n const styles = useStyles();\n const displayText = highlightPlainMentions\n ? text.replace(\n /(^|[^\\[a-z0-9_])@([a-z0-9][a-z0-9._-]*)/gi,\n (_source, prefix: string, label: string) =>\n `${prefix}[${escapeMarkdownLabel(label)}](${PLAIN_MENTION_SENTINEL}?label=${encodeURIComponent(label)})`,\n )\n : text;\n const markdown = replaceMarkdownResourceLinks(\n displayText,\n (link) => {\n // 非 http(s) 协议会被 Markdown 引擎清洗,先编码到内部标准链接中交给 a renderer 恢复。\n return `[${escapeMarkdownLabel(link.label)}](${RESOURCE_LINK_SENTINEL}?href=${encodeURIComponent(link.href)}&label=${encodeURIComponent(link.label)})`;\n },\n { schemes: resourceLinkSchemes },\n )\n .replaceAll(/\\/\\*\\s*PLANNING\\s*\\*\\//g, '<tag type=\"planning\"></tag>')\n .replaceAll(/\\/\\*\\s*REPLANNING\\s*\\*\\//g, '<tag type=\"replanning\"></tag>')\n .replaceAll(/\\/\\*\\s*REASONING\\s*\\*\\//g, '<tag type=\"reasoning\"></tag>')\n .replaceAll(/\\/\\*\\s*ACTION\\s*\\*\\//g, '<tag type=\"action\"></tag>')\n .replaceAll(\n /\\/\\*\\s*FINAL_ANSWER\\s*\\*\\//g,\n '<tag type=\"final_answer\"></tag>',\n );\n\n const ResourceLinkComponent = React.useCallback(\n (props: ComponentProps) => {\n const href = String((props.href as string) || \"\");\n const linkText =\n String((props.label as string) || \"\") || extractText(props.children);\n const resourceLink = parseMarkdownResourceHref(href, linkText, {\n schemes: resourceLinkSchemes,\n });\n if (!resourceLink) return <>{props.children as React.ReactNode}</>;\n const displayLabel = getMarkdownResourceDisplayLabel(resourceLink.label);\n\n const customNode = renderResourceLink?.(resourceLink);\n if (customNode) return customNode;\n\n return (\n <button\n type=\"button\"\n className={styles.resourceLink}\n onClick={() => onResourceLinkClick?.(resourceLink)}\n aria-label={displayLabel}\n data-xadk-resource-link={resourceLink.type}\n data-resource-markdown={`[${resourceLink.label}](${resourceLink.href})`}\n >\n {displayLabel}\n </button>\n );\n },\n [\n onResourceLinkClick,\n renderResourceLink,\n resourceLinkSchemes,\n styles.resourceLink,\n ],\n );\n\n const PlainMentionComponent = React.useCallback(\n (props: ComponentProps) => {\n const label =\n String((props.label as string) || \"\") || extractText(props.children);\n return (\n <span\n className={styles.resourceLink}\n aria-label={label}\n data-xadk-resource-link=\"true\"\n >\n {label}\n </span>\n );\n },\n [styles.resourceLink],\n );\n\n // 自定义 a 标签渲染:资源协议渲染为标签,文件链接渲染为 FileGallery,其余保持普通链接。\n const LinkComponent = React.useCallback(\n (props: ComponentProps) => {\n const href = String((props.href as string) || \"\");\n // 用递归提取纯文本,避免 children 是 React node 时 String() 得到 \"[object Object]\"\n const linkText = extractText(props.children);\n let resolvedHref = href;\n let resolvedLabel = linkText;\n try {\n const internalUrl = new URL(href);\n if (\n internalUrl.origin + internalUrl.pathname ===\n PLAIN_MENTION_SENTINEL\n ) {\n const label = internalUrl.searchParams.get(\"label\") || linkText;\n return (\n <span\n className={styles.resourceLink}\n aria-label={label}\n data-xadk-resource-link=\"true\"\n >\n {label}\n </span>\n );\n }\n if (\n internalUrl.origin + internalUrl.pathname ===\n RESOURCE_LINK_SENTINEL\n ) {\n resolvedHref = internalUrl.searchParams.get(\"href\") || \"\";\n resolvedLabel = internalUrl.searchParams.get(\"label\") || linkText;\n }\n } catch {\n // 相对链接及非标准 URL 继续走原有解析逻辑。\n }\n const resourceLink = parseMarkdownResourceHref(\n resolvedHref,\n resolvedLabel,\n {\n schemes: resourceLinkSchemes,\n },\n );\n\n if (resourceLink) {\n const displayLabel = getMarkdownResourceDisplayLabel(\n resourceLink.label,\n );\n const customNode = renderResourceLink?.(resourceLink);\n if (customNode) return customNode;\n\n return (\n <button\n type=\"button\"\n className={styles.resourceLink}\n onClick={() => onResourceLinkClick?.(resourceLink)}\n aria-label={displayLabel}\n data-xadk-resource-link={resourceLink.type}\n data-resource-markdown={`[${resourceLink.label}](${resourceLink.href})`}\n >\n {displayLabel}\n </button>\n );\n }\n\n // 先识别 name(链接文字),再识别 url(href)\n const ext = extractExt(linkText) || extractExt(href);\n\n if (ext) {\n // href 为空说明链接还在流式截断中,不渲染,避免显示出错误文字\n if (!href) return null;\n // 用户消息场景:裸 URL 不富化,直接展示为纯文本字符串\n if (bareUrlAsText) {\n return <>{linkText || href}</>;\n }\n const mimeType = MIME_MAP[ext] || \"\";\n const fileItem: FileItem = {\n displayName: linkText || href,\n mimeType,\n fileUri: href,\n };\n return (\n <FileGallery\n file={fileItem}\n onClick={onFileClick ? () => onFileClick(fileItem) : undefined}\n />\n );\n }\n\n return (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\">\n {props.children as React.ReactNode}\n </a>\n );\n },\n [\n onFileClick,\n onResourceLinkClick,\n renderResourceLink,\n resourceLinkSchemes,\n styles.resourceLink,\n bareUrlAsText,\n ],\n );\n\n const enabledMarkdownExtensions = React.useMemo(() => {\n const registeredTags = new Set<string>();\n return markdownExtensions.filter((extension) => {\n const tagName = extension.tagName.toLowerCase();\n if (!CUSTOM_TAG_NAME_REGEX.test(tagName) || registeredTags.has(tagName)) {\n return false;\n }\n registeredTags.add(tagName);\n return true;\n });\n }, [markdownExtensions]);\n const dompurifyConfig = React.useMemo(() => {\n const allowedAttributes = Array.from(\n new Set(\n enabledMarkdownExtensions.flatMap((extension) => [\n ...getAllowedExtensionAttributes(extension),\n ]),\n ),\n );\n return allowedAttributes.length\n ? { ADD_ATTR: allowedAttributes }\n : undefined;\n }, [enabledMarkdownExtensions]);\n const extensionComponents = React.useMemo(\n () =>\n Object.fromEntries(\n enabledMarkdownExtensions.map((extension) => [\n extension.tagName.toLowerCase(),\n createMarkdownExtensionComponent(extension),\n ]),\n ),\n [enabledMarkdownExtensions],\n );\n\n return (\n <div\n className={`${styles.markdownWrapper}${compact ? ` ${styles.markdownWrapperCompact}` : \"\"}`}\n >\n <div\n className={`${styles.markdownHost}${compact ? ` ${styles.markdownHostCompact}` : \"\"}`}\n >\n <XMarkdown\n content={markdown}\n className=\"x-markdown-light\"\n paragraphTag=\"div\"\n dompurifyConfig={dompurifyConfig}\n config={{\n extensions: Latex(),\n }}\n components={{\n tag: ThinkComponent,\n \"resource-link\": ResourceLinkComponent,\n \"plain-mention\": PlainMentionComponent,\n code: CodeComponent,\n a: LinkComponent,\n ...extensionComponents,\n }}\n streaming={{\n enableAnimation: true,\n animationConfig: {\n fadeDuration: 400,\n },\n }}\n />\n </div>\n </div>\n );\n};\n\nexport default MarkdownRender;\n"],
5
+ "mappings": "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",
6
6
  "names": ["React", "FileGallery", "XMarkdown", "Latex"]
7
7
  }
@@ -127,6 +127,39 @@ var useStyles = (0, import_common.withBasicStyles)(() => ({
127
127
  margin: 0;
128
128
  line-height: inherit;
129
129
  }
130
+
131
+ /* 用户消息里的普通资源引用保持蓝色;知识库引用用无底色灰字与输入框标签区分。 */
132
+ [data-xadk-resource-link] {
133
+ height: auto;
134
+ margin: 0 4px;
135
+ padding: 0;
136
+ border: 0;
137
+ border-radius: 0;
138
+ background: transparent;
139
+ color: #1677ff;
140
+ font-size: inherit;
141
+ font-weight: 500;
142
+ line-height: inherit;
143
+ cursor: default;
144
+
145
+ &:hover {
146
+ border-color: transparent;
147
+ background: transparent;
148
+ color: #1677ff;
149
+ }
150
+ }
151
+
152
+ && [data-xadk-resource-link="kb"] {
153
+ padding: 0;
154
+ border-radius: 0;
155
+ background: transparent;
156
+ color: #666666;
157
+
158
+ &:hover {
159
+ background: transparent;
160
+ color: #666666;
161
+ }
162
+ }
130
163
  `,
131
164
  resourceLink: import_css.css`
132
165
  display: inline-flex;
@@ -148,6 +181,17 @@ var useStyles = (0, import_common.withBasicStyles)(() => ({
148
181
  border-color: #91caff;
149
182
  background: #eaf3ff;
150
183
  }
184
+
185
+ &[data-xadk-resource-link="kb"] {
186
+ border-color: #f1f1f1;
187
+ background: #f1f1f1;
188
+ color: #1a1a1a;
189
+
190
+ &:hover {
191
+ border-color: #e5e5e5;
192
+ background: #e8e8e8;
193
+ }
194
+ }
151
195
  `
152
196
  }));
153
197
  var styles_default = useStyles;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/components/XAdkChatbot/components/MarkdownRender/styles.tsx"],
4
- "sourcesContent": ["import { css } from \"@emotion/css\";\nimport { withBasicStyles } from \"@/styles/common\";\n\nexport const useStyles = withBasicStyles(() => ({\n markdownWrapper: css`\n display: grid;\n grid-template-columns: minmax(0, 1fr); /* 关键:允许内容收缩 */\n max-width: 100%; /* 自定义最大宽度 */\n margin: 0 auto;\n `,\n\n markdownWrapperCompact: css`\n display: inline;\n margin: 0;\n max-width: none;\n `,\n\n markdownHost: css`\n container-type: inline-size;\n width: 100%;\n overflow: auto;\n\n /* ===== Markdown 基础排版 ===== */\n\n p {\n margin: 8px 0;\n line-height: 1.6;\n }\n\n ul,\n ol {\n padding-left: 20px;\n margin-top: 0;\n margin-bottom: 8px;\n }\n\n li {\n margin: 0 0 4px 0 !important;\n }\n\n u {\n text-decoration: underline;\n }\n\n em {\n font-style: italic;\n }\n\n /* ===== Table 样式 ===== */\n\n table {\n border-collapse: collapse;\n width: 100%;\n max-width: 100%;\n margin: 12px 0;\n font-size: 14px;\n }\n\n thead {\n background: #fafafa;\n }\n\n th,\n td {\n border: 1px solid #e5e6eb;\n padding: 8px 12px;\n text-align: left;\n }\n\n th {\n font-weight: 600;\n }\n\n tbody tr:hover {\n background: #fafafa;\n }\n\n /* ===== Code ===== */\n\n pre {\n margin: 12px 0;\n }\n\n ant-highlightCode {\n max-width: min(100%, 80ch);\n overflow-x: auto;\n }\n\n /* ===== 图片 ===== */\n\n img {\n max-width: 100%;\n border-radius: 6px;\n }\n `,\n\n markdownHostCompact: css`\n display: inline;\n width: auto;\n overflow: visible;\n\n .x-markdown-light,\n p,\n div {\n display: inline;\n margin: 0;\n line-height: inherit;\n }\n `,\n\n resourceLink: css`\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n height: 22px;\n margin: 0 2px;\n padding: 0 8px;\n border: 1px solid #d9e8ff;\n border-radius: 6px;\n background: #f5f9ff;\n color: #1f1f1f;\n font-size: 13px;\n line-height: 20px;\n vertical-align: baseline;\n cursor: pointer;\n\n &:hover {\n border-color: #91caff;\n background: #eaf3ff;\n }\n `,\n}));\n\nexport default useStyles;\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAgC;AAEzB,IAAM,gBAAY,+BAAgB,OAAO;AAAA,EAC9C,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+Ed,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcrB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBhB,EAAE;AAEF,IAAO,iBAAQ;",
4
+ "sourcesContent": ["import { css } from \"@emotion/css\";\nimport { withBasicStyles } from \"@/styles/common\";\n\nexport const useStyles = withBasicStyles(() => ({\n markdownWrapper: css`\n display: grid;\n grid-template-columns: minmax(0, 1fr); /* 关键:允许内容收缩 */\n max-width: 100%; /* 自定义最大宽度 */\n margin: 0 auto;\n `,\n\n markdownWrapperCompact: css`\n display: inline;\n margin: 0;\n max-width: none;\n `,\n\n markdownHost: css`\n container-type: inline-size;\n width: 100%;\n overflow: auto;\n\n /* ===== Markdown 基础排版 ===== */\n\n p {\n margin: 8px 0;\n line-height: 1.6;\n }\n\n ul,\n ol {\n padding-left: 20px;\n margin-top: 0;\n margin-bottom: 8px;\n }\n\n li {\n margin: 0 0 4px 0 !important;\n }\n\n u {\n text-decoration: underline;\n }\n\n em {\n font-style: italic;\n }\n\n /* ===== Table 样式 ===== */\n\n table {\n border-collapse: collapse;\n width: 100%;\n max-width: 100%;\n margin: 12px 0;\n font-size: 14px;\n }\n\n thead {\n background: #fafafa;\n }\n\n th,\n td {\n border: 1px solid #e5e6eb;\n padding: 8px 12px;\n text-align: left;\n }\n\n th {\n font-weight: 600;\n }\n\n tbody tr:hover {\n background: #fafafa;\n }\n\n /* ===== Code ===== */\n\n pre {\n margin: 12px 0;\n }\n\n ant-highlightCode {\n max-width: min(100%, 80ch);\n overflow-x: auto;\n }\n\n /* ===== 图片 ===== */\n\n img {\n max-width: 100%;\n border-radius: 6px;\n }\n `,\n\n markdownHostCompact: css`\n display: inline;\n width: auto;\n overflow: visible;\n\n .x-markdown-light,\n p,\n div {\n display: inline;\n margin: 0;\n line-height: inherit;\n }\n\n /* 用户消息里的普通资源引用保持蓝色;知识库引用用无底色灰字与输入框标签区分。 */\n [data-xadk-resource-link] {\n height: auto;\n margin: 0 4px;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #1677ff;\n font-size: inherit;\n font-weight: 500;\n line-height: inherit;\n cursor: default;\n\n &:hover {\n border-color: transparent;\n background: transparent;\n color: #1677ff;\n }\n }\n\n && [data-xadk-resource-link=\"kb\"] {\n padding: 0;\n border-radius: 0;\n background: transparent;\n color: #666666;\n\n &:hover {\n background: transparent;\n color: #666666;\n }\n }\n `,\n\n resourceLink: css`\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n height: 22px;\n margin: 0 2px;\n padding: 0 8px;\n border: 1px solid #d9e8ff;\n border-radius: 6px;\n background: #f5f9ff;\n color: #1f1f1f;\n font-size: 13px;\n line-height: 20px;\n vertical-align: baseline;\n cursor: pointer;\n\n &:hover {\n border-color: #91caff;\n background: #eaf3ff;\n }\n\n &[data-xadk-resource-link=\"kb\"] {\n border-color: #f1f1f1;\n background: #f1f1f1;\n color: #1a1a1a;\n\n &:hover {\n border-color: #e5e5e5;\n background: #e8e8e8;\n }\n }\n `,\n\n}));\n\nexport default useStyles;\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAoB;AACpB,oBAAgC;AAEzB,IAAM,gBAAY,+BAAgB,OAAO;AAAA,EAC9C,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+Ed,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA+CrB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiChB,EAAE;AAEF,IAAO,iBAAQ;",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ /// <reference types="react" />
2
2
  import type { XAdkChatbotProps, XAdkChatbotHandle } from "../../types";
3
3
  /**
4
4
  * XAdkChatbot - 增强版聊天组件
@@ -10,5 +10,5 @@ import type { XAdkChatbotProps, XAdkChatbotHandle } from "../../types";
10
10
  * - ✅ 操作栏 (重试/复制/日志)
11
11
  * - ✅ 欢迎页面 (agentName/agentIcon/description)
12
12
  */
13
- declare const XAdkChatbot: React.ForwardRefExoticComponent<XAdkChatbotProps & React.RefAttributes<XAdkChatbotHandle>>;
13
+ declare const XAdkChatbot: import("react").ForwardRefExoticComponent<XAdkChatbotProps & import("react").RefAttributes<XAdkChatbotHandle>>;
14
14
  export default XAdkChatbot;
@@ -75,6 +75,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
75
75
  onFileClick,
76
76
  onResourceLinkClick,
77
77
  renderResourceLink,
78
+ markdownExtensions,
78
79
  renderFunctionCall,
79
80
  toolKindResolver,
80
81
  strategies,
@@ -88,6 +89,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
88
89
  const messagesEndRef = (0, import_react.useRef)(null);
89
90
  const prevInitializedRef = (0, import_react.useRef)(false);
90
91
  const prevSessionIdRef = (0, import_react.useRef)(sessionId);
92
+ const previousMessageCountRef = (0, import_react.useRef)(messages.length);
91
93
  const scrollToBottom = (0, import_react.useCallback)((behavior = "auto") => {
92
94
  var _a;
93
95
  (_a = messagesEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior });
@@ -97,6 +99,10 @@ var XAdkChatbot = (0, import_react.forwardRef)(
97
99
  () => (0, import_xgroup.mergeChatStrategies)(preset, strategies),
98
100
  [preset, strategies]
99
101
  );
102
+ const mergedMarkdownExtensions = (0, import_react.useMemo)(
103
+ () => (0, import_xgroup.resolvePresetMarkdownExtensions)(preset, markdownExtensions),
104
+ [markdownExtensions, preset]
105
+ );
100
106
  const resolveToolKind = (0, import_react.useCallback)(
101
107
  (name, msg) => {
102
108
  var _a;
@@ -152,6 +158,12 @@ var XAdkChatbot = (0, import_react.forwardRef)(
152
158
  userHasScrolledRef.current = false;
153
159
  }, [sessionId]);
154
160
  (0, import_react.useEffect)(() => {
161
+ const previousCount = previousMessageCountRef.current;
162
+ previousMessageCountRef.current = messages.length;
163
+ const hasNewUserMessage = messages.slice(previousCount).some((message) => message.role === "user");
164
+ if (hasNewUserMessage) {
165
+ userHasScrolledRef.current = false;
166
+ }
155
167
  if (userHasScrolledRef.current)
156
168
  return;
157
169
  if (!messages.length)
@@ -260,7 +272,8 @@ var XAdkChatbot = (0, import_react.forwardRef)(
260
272
  resourceLinkSchemes,
261
273
  onFileClick,
262
274
  onResourceLinkClick,
263
- renderResourceLink
275
+ renderResourceLink,
276
+ markdownExtensions: mergedMarkdownExtensions
264
277
  },
265
278
  `${msg.id}-${i}`
266
279
  );
@@ -416,7 +429,8 @@ var XAdkChatbot = (0, import_react.forwardRef)(
416
429
  resourceLinkSchemes,
417
430
  onFileClick,
418
431
  onResourceLinkClick,
419
- renderResourceLink
432
+ renderResourceLink,
433
+ markdownExtensions: mergedMarkdownExtensions
420
434
  }
421
435
  ) }, node.key);
422
436
  }),
@@ -480,6 +494,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
480
494
  onFileClick,
481
495
  onResourceLinkClick,
482
496
  renderResourceLink,
497
+ mergedMarkdownExtensions,
483
498
  resourceLinkSchemes,
484
499
  styles,
485
500
  resolveToolKind,
@@ -499,17 +514,30 @@ var XAdkChatbot = (0, import_react.forwardRef)(
499
514
  },
500
515
  index
501
516
  )) }),
502
- m.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: styles.card, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
503
- import_MarkdownRender.default,
517
+ m.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
518
+ "div",
504
519
  {
505
- text: m.text,
506
- compact: true,
507
- resourceLinkSchemes,
508
- onFileClick,
509
- onResourceLinkClick,
510
- renderResourceLink
520
+ className: styles.card,
521
+ onCopy: (event) => {
522
+ event.preventDefault();
523
+ event.clipboardData.setData("text/plain", m.text || "");
524
+ },
525
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
526
+ import_MarkdownRender.default,
527
+ {
528
+ text: m.text,
529
+ compact: true,
530
+ bareUrlAsText: true,
531
+ highlightPlainMentions: true,
532
+ resourceLinkSchemes,
533
+ onFileClick,
534
+ onResourceLinkClick,
535
+ renderResourceLink,
536
+ markdownExtensions: mergedMarkdownExtensions
537
+ }
538
+ )
511
539
  }
512
- ) })
540
+ )
513
541
  ] }, m.id || i)) }, group.id);
514
542
  },
515
543
  [
@@ -517,6 +545,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
517
545
  onFileClick,
518
546
  onResourceLinkClick,
519
547
  renderResourceLink,
548
+ mergedMarkdownExtensions,
520
549
  resourceLinkSchemes
521
550
  ]
522
551
  );
@@ -528,7 +557,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
528
557
  {
529
558
  type: "text",
530
559
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.SwapRightOutlined, {}),
531
- iconPosition: "end",
560
+ iconPlacement: "end",
532
561
  onClick: () => {
533
562
  if (!item)
534
563
  return;
@@ -556,7 +585,8 @@ var XAdkChatbot = (0, import_react.forwardRef)(
556
585
  resourceLinkSchemes,
557
586
  onFileClick,
558
587
  onResourceLinkClick,
559
- renderResourceLink
588
+ renderResourceLink,
589
+ markdownExtensions: mergedMarkdownExtensions
560
590
  }
561
591
  ) }),
562
592
  chatGroups.map(