@ai-group/chat-sdk 3.7.1-alpha4 → 3.7.1-alpha7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.d.ts +10 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +89 -14
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js +21 -0
- package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
- package/dist/cjs/components/XAdkChatbot/index.js +36 -10
- package/dist/cjs/components/XAdkChatbot/index.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js +59 -15
- package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/Sender.d.ts +2 -1
- package/dist/cjs/components/XAdkProvider/compound/Sender.js.map +2 -2
- package/dist/cjs/components/XAdkProvider/compound/styles.d.ts +1 -0
- package/dist/cjs/components/XAdkProvider/compound/styles.js +16 -0
- package/dist/cjs/components/XAdkProvider/compound/styles.js.map +2 -2
- package/dist/cjs/components/XAdkSender/InlineTagInput.js +132 -2
- package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
- package/dist/cjs/components/XAdkSender/index.js +21 -55
- package/dist/cjs/components/XAdkSender/index.js.map +2 -2
- package/dist/cjs/hooks/useADKChat.js +5 -1
- package/dist/cjs/hooks/useADKChat.js.map +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/presets/xgroup/preset.js +2 -1
- package/dist/cjs/presets/xgroup/preset.js.map +2 -2
- package/dist/cjs/presets/xgroup/strategies.d.ts +5 -1
- package/dist/cjs/presets/xgroup/strategies.js +16 -1
- package/dist/cjs/presets/xgroup/strategies.js.map +3 -3
- package/dist/cjs/types/ChatStrategies.d.ts +5 -0
- package/dist/cjs/types/ChatStrategies.js.map +1 -1
- package/dist/cjs/types/XAdkSender.d.ts +10 -3
- package/dist/cjs/types/XAdkSender.js.map +1 -1
- package/dist/cjs/utils/markdownResource.d.ts +12 -5
- package/dist/cjs/utils/markdownResource.js +66 -14
- package/dist/cjs/utils/markdownResource.js.map +2 -2
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +10 -0
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +76 -13
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js +1 -1
- package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js.map +1 -1
- package/dist/esm/components/XAdkChatbot/index.js +27 -4
- package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js +55 -12
- package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.d.ts +2 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.js +2 -1
- package/dist/esm/components/XAdkProvider/compound/Sender.js.map +1 -1
- package/dist/esm/components/XAdkProvider/compound/styles.d.ts +1 -0
- package/dist/esm/components/XAdkProvider/compound/styles.js +3 -2
- package/dist/esm/components/XAdkProvider/compound/styles.js.map +1 -1
- package/dist/esm/components/XAdkSender/InlineTagInput.js +154 -4
- package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
- package/dist/esm/components/XAdkSender/index.js +25 -58
- package/dist/esm/components/XAdkSender/index.js.map +1 -1
- package/dist/esm/hooks/useADKChat.js +8 -2
- package/dist/esm/hooks/useADKChat.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/presets/xgroup/preset.js +3 -2
- package/dist/esm/presets/xgroup/preset.js.map +1 -1
- package/dist/esm/presets/xgroup/strategies.d.ts +5 -1
- package/dist/esm/presets/xgroup/strategies.js +12 -1
- package/dist/esm/presets/xgroup/strategies.js.map +1 -1
- package/dist/esm/types/ChatStrategies.d.ts +5 -0
- package/dist/esm/types/ChatStrategies.js.map +1 -1
- package/dist/esm/types/XAdkSender.d.ts +10 -3
- package/dist/esm/types/XAdkSender.js.map +1 -1
- package/dist/esm/utils/markdownResource.d.ts +12 -5
- package/dist/esm/utils/markdownResource.js +69 -7
- package/dist/esm/utils/markdownResource.js.map +1 -1
- package/dist/umd/chat-sdk.min.js +1 -1
- package/package.json +1 -1
|
@@ -5,12 +5,22 @@ export interface MarkdownRenderProps {
|
|
|
5
5
|
text: string;
|
|
6
6
|
/** 紧凑布局,适合用户消息气泡等内联场景 */
|
|
7
7
|
compact?: boolean;
|
|
8
|
+
/** Markdown 资源链接协议白名单,未命中的协议保持普通 Markdown 行为 */
|
|
9
|
+
resourceLinkSchemes?: readonly string[];
|
|
8
10
|
/** 点击 Markdown 中识别到的文件链接的回调 */
|
|
9
11
|
onFileClick?: (file: FileItem) => void;
|
|
10
12
|
/** 点击 Markdown 中识别到的资源链接标签,如 [@skill](skill://xxx) */
|
|
11
13
|
onResourceLinkClick?: (link: MarkdownResourceLink) => void;
|
|
12
14
|
/** 自定义资源链接渲染,返回 null 时使用默认标签样式 */
|
|
13
15
|
renderResourceLink?: RenderMarkdownResourceLink;
|
|
16
|
+
/**
|
|
17
|
+
* 将命中文件扩展名的裸 URL 当作纯文本展示,不升级为 FileGallery。
|
|
18
|
+
* 用户消息应如实展示输入文本,除资源链接等业务扩展外不做额外富化。
|
|
19
|
+
* 默认 false,保留 Agent 消息现有行为。
|
|
20
|
+
*/
|
|
21
|
+
bareUrlAsText?: boolean;
|
|
22
|
+
/** 将已经丢失资源 URI 的 @name 兼容渲染成只读高亮标签。 */
|
|
23
|
+
highlightPlainMentions?: boolean;
|
|
14
24
|
}
|
|
15
25
|
declare const MarkdownRender: React.FC<MarkdownRenderProps>;
|
|
16
26
|
export default MarkdownRender;
|
|
@@ -85,8 +85,9 @@ var extractExt = (str) => {
|
|
|
85
85
|
return "";
|
|
86
86
|
return match[1].toLowerCase();
|
|
87
87
|
};
|
|
88
|
-
var
|
|
89
|
-
var
|
|
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";
|
|
90
91
|
var CodeComponent = (props) => {
|
|
91
92
|
var _a;
|
|
92
93
|
const { className, children } = props;
|
|
@@ -130,14 +131,25 @@ var extractText = (children) => {
|
|
|
130
131
|
var MarkdownRender = ({
|
|
131
132
|
text,
|
|
132
133
|
compact = false,
|
|
134
|
+
resourceLinkSchemes,
|
|
133
135
|
onFileClick,
|
|
134
136
|
onResourceLinkClick,
|
|
135
|
-
renderResourceLink
|
|
137
|
+
renderResourceLink,
|
|
138
|
+
bareUrlAsText = false,
|
|
139
|
+
highlightPlainMentions = false
|
|
136
140
|
}) => {
|
|
137
141
|
const styles = (0, import_styles.useStyles)();
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
const displayText = highlightPlainMentions ? text.replace(
|
|
143
|
+
/(^|[^\[a-z0-9_])@([a-z0-9][a-z0-9._-]*)/gi,
|
|
144
|
+
(_source, prefix, label) => `${prefix}[${escapeMarkdownLabel(label)}](${PLAIN_MENTION_SENTINEL}?label=${encodeURIComponent(label)})`
|
|
145
|
+
) : text;
|
|
146
|
+
const markdown = (0, import_markdownResource.replaceMarkdownResourceLinks)(
|
|
147
|
+
displayText,
|
|
148
|
+
(link) => {
|
|
149
|
+
return `[${escapeMarkdownLabel(link.label)}](${RESOURCE_LINK_SENTINEL}?href=${encodeURIComponent(link.href)}&label=${encodeURIComponent(link.label)})`;
|
|
150
|
+
},
|
|
151
|
+
{ schemes: resourceLinkSchemes }
|
|
152
|
+
).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(
|
|
141
153
|
/\/\*\s*FINAL_ANSWER\s*\*\//g,
|
|
142
154
|
'<tag type="final_answer"></tag>'
|
|
143
155
|
);
|
|
@@ -145,9 +157,12 @@ var MarkdownRender = ({
|
|
|
145
157
|
(props) => {
|
|
146
158
|
const href = String(props.href || "");
|
|
147
159
|
const linkText = String(props.label || "") || extractText(props.children);
|
|
148
|
-
const resourceLink = (0, import_markdownResource.parseMarkdownResourceHref)(href, linkText
|
|
160
|
+
const resourceLink = (0, import_markdownResource.parseMarkdownResourceHref)(href, linkText, {
|
|
161
|
+
schemes: resourceLinkSchemes
|
|
162
|
+
});
|
|
149
163
|
if (!resourceLink)
|
|
150
164
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: props.children });
|
|
165
|
+
const displayLabel = (0, import_markdownResource.getMarkdownResourceDisplayLabel)(resourceLink.label);
|
|
151
166
|
const customNode = renderResourceLink == null ? void 0 : renderResourceLink(resourceLink);
|
|
152
167
|
if (customNode)
|
|
153
168
|
return customNode;
|
|
@@ -157,19 +172,66 @@ var MarkdownRender = ({
|
|
|
157
172
|
type: "button",
|
|
158
173
|
className: styles.resourceLink,
|
|
159
174
|
onClick: () => onResourceLinkClick == null ? void 0 : onResourceLinkClick(resourceLink),
|
|
160
|
-
"aria-label":
|
|
161
|
-
|
|
175
|
+
"aria-label": displayLabel,
|
|
176
|
+
"data-xadk-resource-link": "true",
|
|
177
|
+
"data-resource-markdown": `[${resourceLink.label}](${resourceLink.href})`,
|
|
178
|
+
children: displayLabel
|
|
162
179
|
}
|
|
163
180
|
);
|
|
164
181
|
},
|
|
165
|
-
[
|
|
182
|
+
[
|
|
183
|
+
onResourceLinkClick,
|
|
184
|
+
renderResourceLink,
|
|
185
|
+
resourceLinkSchemes,
|
|
186
|
+
styles.resourceLink
|
|
187
|
+
]
|
|
188
|
+
);
|
|
189
|
+
const PlainMentionComponent = import_react.default.useCallback(
|
|
190
|
+
(props) => {
|
|
191
|
+
const label = String(props.label || "") || extractText(props.children);
|
|
192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
193
|
+
"span",
|
|
194
|
+
{
|
|
195
|
+
className: styles.resourceLink,
|
|
196
|
+
"aria-label": label,
|
|
197
|
+
"data-xadk-resource-link": "true",
|
|
198
|
+
children: label
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
},
|
|
202
|
+
[styles.resourceLink]
|
|
166
203
|
);
|
|
167
204
|
const LinkComponent = import_react.default.useCallback(
|
|
168
205
|
(props) => {
|
|
169
206
|
const href = String(props.href || "");
|
|
170
207
|
const linkText = extractText(props.children);
|
|
171
|
-
|
|
208
|
+
let resolvedHref = href;
|
|
209
|
+
let resolvedLabel = linkText;
|
|
210
|
+
try {
|
|
211
|
+
const internalUrl = new URL(href);
|
|
212
|
+
if (internalUrl.origin + internalUrl.pathname === PLAIN_MENTION_SENTINEL) {
|
|
213
|
+
const label = internalUrl.searchParams.get("label") || linkText;
|
|
214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
215
|
+
"span",
|
|
216
|
+
{
|
|
217
|
+
className: styles.resourceLink,
|
|
218
|
+
"aria-label": label,
|
|
219
|
+
"data-xadk-resource-link": "true",
|
|
220
|
+
children: label
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (internalUrl.origin + internalUrl.pathname === RESOURCE_LINK_SENTINEL) {
|
|
225
|
+
resolvedHref = internalUrl.searchParams.get("href") || "";
|
|
226
|
+
resolvedLabel = internalUrl.searchParams.get("label") || linkText;
|
|
227
|
+
}
|
|
228
|
+
} catch {
|
|
229
|
+
}
|
|
230
|
+
const resourceLink = (0, import_markdownResource.parseMarkdownResourceHref)(resolvedHref, resolvedLabel, {
|
|
231
|
+
schemes: resourceLinkSchemes
|
|
232
|
+
});
|
|
172
233
|
if (resourceLink) {
|
|
234
|
+
const displayLabel = (0, import_markdownResource.getMarkdownResourceDisplayLabel)(resourceLink.label);
|
|
173
235
|
const customNode = renderResourceLink == null ? void 0 : renderResourceLink(resourceLink);
|
|
174
236
|
if (customNode)
|
|
175
237
|
return customNode;
|
|
@@ -179,8 +241,10 @@ var MarkdownRender = ({
|
|
|
179
241
|
type: "button",
|
|
180
242
|
className: styles.resourceLink,
|
|
181
243
|
onClick: () => onResourceLinkClick == null ? void 0 : onResourceLinkClick(resourceLink),
|
|
182
|
-
"aria-label":
|
|
183
|
-
|
|
244
|
+
"aria-label": displayLabel,
|
|
245
|
+
"data-xadk-resource-link": "true",
|
|
246
|
+
"data-resource-markdown": `[${resourceLink.label}](${resourceLink.href})`,
|
|
247
|
+
children: displayLabel
|
|
184
248
|
}
|
|
185
249
|
);
|
|
186
250
|
}
|
|
@@ -188,6 +252,9 @@ var MarkdownRender = ({
|
|
|
188
252
|
if (ext) {
|
|
189
253
|
if (!href)
|
|
190
254
|
return null;
|
|
255
|
+
if (bareUrlAsText) {
|
|
256
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: linkText || href });
|
|
257
|
+
}
|
|
191
258
|
const mimeType = MIME_MAP[ext] || "";
|
|
192
259
|
const fileItem = {
|
|
193
260
|
displayName: linkText || href,
|
|
@@ -204,7 +271,14 @@ var MarkdownRender = ({
|
|
|
204
271
|
}
|
|
205
272
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, target: "_blank", rel: "noopener noreferrer", children: props.children });
|
|
206
273
|
},
|
|
207
|
-
[
|
|
274
|
+
[
|
|
275
|
+
onFileClick,
|
|
276
|
+
onResourceLinkClick,
|
|
277
|
+
renderResourceLink,
|
|
278
|
+
resourceLinkSchemes,
|
|
279
|
+
styles.resourceLink,
|
|
280
|
+
bareUrlAsText
|
|
281
|
+
]
|
|
208
282
|
);
|
|
209
283
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
210
284
|
"div",
|
|
@@ -226,6 +300,7 @@ var MarkdownRender = ({
|
|
|
226
300
|
components: {
|
|
227
301
|
tag: ThinkComponent,
|
|
228
302
|
"resource-link": ResourceLinkComponent,
|
|
303
|
+
"plain-mention": PlainMentionComponent,
|
|
229
304
|
code: CodeComponent,
|
|
230
305
|
a: LinkComponent
|
|
231
306
|
},
|
|
@@ -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\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n\nconst escapeAttr = (value: string) =>\n escapeHtml(value).replace(/\"/g, \""\").replace(/'/g, \"'\");\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 中识别到的文件链接的回调 */\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 onFileClick,\n onResourceLinkClick,\n renderResourceLink,\n}) => {\n const styles = useStyles();\n const markdown = replaceMarkdownResourceLinks(text, (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 .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 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 [onResourceLinkClick, renderResourceLink, 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 const resourceLink = parseMarkdownResourceHref(href, linkText);\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 [onFileClick, onResourceLinkClick, renderResourceLink, styles.resourceLink],\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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkB;AAClB,wBAA+C;AAC/C,mBAAO;AACP,eAAgC;AAChC,kBAAqB;AACrB,mBAAkB;AAClB,oBAA0B;AAC1B,mBAKO;AACP,yBAAwB;AAMxB,
|
|
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 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 escapeHtml = (value: string) =>\n value.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n\nconst escapeAttr = (value: string) =>\n escapeHtml(value).replace(/\"/g, \""\").replace(/'/g, \"'\");\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\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 * 将命中文件扩展名的裸 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\nconst MarkdownRender: React.FC<MarkdownRenderProps> = ({\n text,\n compact = false,\n resourceLinkSchemes,\n onFileClick,\n onResourceLinkClick,\n renderResourceLink,\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=\"true\"\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 = 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 (internalUrl.origin + internalUrl.pathname === PLAIN_MENTION_SENTINEL) {\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 (internalUrl.origin + internalUrl.pathname === RESOURCE_LINK_SENTINEL) {\n resolvedHref = internalUrl.searchParams.get(\"href\") || \"\";\n resolvedLabel = internalUrl.searchParams.get(\"label\") || linkText;\n }\n } catch {\n // 相对链接及非标准 URL 继续走原有解析逻辑。\n }\n const resourceLink = parseMarkdownResourceHref(resolvedHref, resolvedLabel, {\n schemes: resourceLinkSchemes,\n });\n\n if (resourceLink) {\n const displayLabel = getMarkdownResourceDisplayLabel(resourceLink.label);\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=\"true\"\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 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 \"plain-mention\": PlainMentionComponent,\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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",
|
|
6
6
|
"names": ["React", "FileGallery", "XMarkdown", "Latex"]
|
|
7
7
|
}
|
|
@@ -127,6 +127,27 @@ var useStyles = (0, import_common.withBasicStyles)(() => ({
|
|
|
127
127
|
margin: 0;
|
|
128
128
|
line-height: inherit;
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
/* 用户消息里的资源引用采用 Codex 风格:蓝色文字高亮,不额外套标签底色或图标。 */
|
|
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
|
+
}
|
|
130
151
|
`,
|
|
131
152
|
resourceLink: import_css.css`
|
|
132
153
|
display: inline-flex;
|
|
@@ -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,
|
|
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 /* 用户消息里的资源引用采用 Codex 风格:蓝色文字高亮,不额外套标签底色或图标。 */\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\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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCrB,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;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -88,6 +88,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
88
88
|
const messagesEndRef = (0, import_react.useRef)(null);
|
|
89
89
|
const prevInitializedRef = (0, import_react.useRef)(false);
|
|
90
90
|
const prevSessionIdRef = (0, import_react.useRef)(sessionId);
|
|
91
|
+
const previousMessageCountRef = (0, import_react.useRef)(messages.length);
|
|
91
92
|
const scrollToBottom = (0, import_react.useCallback)((behavior = "auto") => {
|
|
92
93
|
var _a;
|
|
93
94
|
(_a = messagesEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior });
|
|
@@ -105,6 +106,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
105
106
|
[toolKindResolver, mergedStrategies]
|
|
106
107
|
);
|
|
107
108
|
const parseProcessMessage = mergedStrategies.parseProcessMessage ?? import_utils.parseAgentMessage;
|
|
109
|
+
const resourceLinkSchemes = mergedStrategies.markdownResourceLinkSchemes;
|
|
108
110
|
(0, import_react.useEffect)(() => {
|
|
109
111
|
if (!initialized)
|
|
110
112
|
return;
|
|
@@ -151,6 +153,12 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
151
153
|
userHasScrolledRef.current = false;
|
|
152
154
|
}, [sessionId]);
|
|
153
155
|
(0, import_react.useEffect)(() => {
|
|
156
|
+
const previousCount = previousMessageCountRef.current;
|
|
157
|
+
previousMessageCountRef.current = messages.length;
|
|
158
|
+
const hasNewUserMessage = messages.slice(previousCount).some((message) => message.role === "user");
|
|
159
|
+
if (hasNewUserMessage) {
|
|
160
|
+
userHasScrolledRef.current = false;
|
|
161
|
+
}
|
|
154
162
|
if (userHasScrolledRef.current)
|
|
155
163
|
return;
|
|
156
164
|
if (!messages.length)
|
|
@@ -256,6 +264,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
256
264
|
import_MarkdownRender.default,
|
|
257
265
|
{
|
|
258
266
|
text: msg.text,
|
|
267
|
+
resourceLinkSchemes,
|
|
259
268
|
onFileClick,
|
|
260
269
|
onResourceLinkClick,
|
|
261
270
|
renderResourceLink
|
|
@@ -411,6 +420,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
411
420
|
import_MarkdownRender.default,
|
|
412
421
|
{
|
|
413
422
|
text: node.content,
|
|
423
|
+
resourceLinkSchemes,
|
|
414
424
|
onFileClick,
|
|
415
425
|
onResourceLinkClick,
|
|
416
426
|
renderResourceLink
|
|
@@ -477,6 +487,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
477
487
|
onFileClick,
|
|
478
488
|
onResourceLinkClick,
|
|
479
489
|
renderResourceLink,
|
|
490
|
+
resourceLinkSchemes,
|
|
480
491
|
styles,
|
|
481
492
|
resolveToolKind,
|
|
482
493
|
mergedStrategies
|
|
@@ -495,23 +506,37 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
495
506
|
},
|
|
496
507
|
index
|
|
497
508
|
)) }),
|
|
498
|
-
m.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
499
|
-
|
|
509
|
+
m.text && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
510
|
+
"div",
|
|
500
511
|
{
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
512
|
+
className: styles.card,
|
|
513
|
+
onCopy: (event) => {
|
|
514
|
+
event.preventDefault();
|
|
515
|
+
event.clipboardData.setData("text/plain", m.text || "");
|
|
516
|
+
},
|
|
517
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
518
|
+
import_MarkdownRender.default,
|
|
519
|
+
{
|
|
520
|
+
text: m.text,
|
|
521
|
+
compact: true,
|
|
522
|
+
bareUrlAsText: true,
|
|
523
|
+
highlightPlainMentions: true,
|
|
524
|
+
resourceLinkSchemes,
|
|
525
|
+
onFileClick,
|
|
526
|
+
onResourceLinkClick,
|
|
527
|
+
renderResourceLink
|
|
528
|
+
}
|
|
529
|
+
)
|
|
506
530
|
}
|
|
507
|
-
)
|
|
531
|
+
)
|
|
508
532
|
] }, m.id || i)) }, group.id);
|
|
509
533
|
},
|
|
510
534
|
[
|
|
511
535
|
styles,
|
|
512
536
|
onFileClick,
|
|
513
537
|
onResourceLinkClick,
|
|
514
|
-
renderResourceLink
|
|
538
|
+
renderResourceLink,
|
|
539
|
+
resourceLinkSchemes
|
|
515
540
|
]
|
|
516
541
|
);
|
|
517
542
|
const renderSuggestions = () => {
|
|
@@ -522,7 +547,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
522
547
|
{
|
|
523
548
|
type: "text",
|
|
524
549
|
icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icons.SwapRightOutlined, {}),
|
|
525
|
-
|
|
550
|
+
iconPlacement: "end",
|
|
526
551
|
onClick: () => {
|
|
527
552
|
if (!item)
|
|
528
553
|
return;
|
|
@@ -547,6 +572,7 @@ var XAdkChatbot = (0, import_react.forwardRef)(
|
|
|
547
572
|
import_MarkdownRender.default,
|
|
548
573
|
{
|
|
549
574
|
text: prologue,
|
|
575
|
+
resourceLinkSchemes,
|
|
550
576
|
onFileClick,
|
|
551
577
|
onResourceLinkClick,
|
|
552
578
|
renderResourceLink
|