@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.
Files changed (75) hide show
  1. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.d.ts +10 -0
  2. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js +89 -14
  3. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/index.js.map +2 -2
  4. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js +21 -0
  5. package/dist/cjs/components/XAdkChatbot/components/MarkdownRender/styles.js.map +2 -2
  6. package/dist/cjs/components/XAdkChatbot/index.js +36 -10
  7. package/dist/cjs/components/XAdkChatbot/index.js.map +2 -2
  8. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
  9. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js +59 -15
  10. package/dist/cjs/components/XAdkProvider/compound/DefaultLayout.js.map +2 -2
  11. package/dist/cjs/components/XAdkProvider/compound/Sender.d.ts +2 -1
  12. package/dist/cjs/components/XAdkProvider/compound/Sender.js.map +2 -2
  13. package/dist/cjs/components/XAdkProvider/compound/styles.d.ts +1 -0
  14. package/dist/cjs/components/XAdkProvider/compound/styles.js +16 -0
  15. package/dist/cjs/components/XAdkProvider/compound/styles.js.map +2 -2
  16. package/dist/cjs/components/XAdkSender/InlineTagInput.js +132 -2
  17. package/dist/cjs/components/XAdkSender/InlineTagInput.js.map +2 -2
  18. package/dist/cjs/components/XAdkSender/index.js +21 -55
  19. package/dist/cjs/components/XAdkSender/index.js.map +2 -2
  20. package/dist/cjs/hooks/useADKChat.js +5 -1
  21. package/dist/cjs/hooks/useADKChat.js.map +2 -2
  22. package/dist/cjs/index.d.ts +2 -2
  23. package/dist/cjs/index.js +4 -0
  24. package/dist/cjs/index.js.map +2 -2
  25. package/dist/cjs/presets/xgroup/preset.js +2 -1
  26. package/dist/cjs/presets/xgroup/preset.js.map +2 -2
  27. package/dist/cjs/presets/xgroup/strategies.d.ts +5 -1
  28. package/dist/cjs/presets/xgroup/strategies.js +16 -1
  29. package/dist/cjs/presets/xgroup/strategies.js.map +3 -3
  30. package/dist/cjs/types/ChatStrategies.d.ts +5 -0
  31. package/dist/cjs/types/ChatStrategies.js.map +1 -1
  32. package/dist/cjs/types/XAdkSender.d.ts +10 -3
  33. package/dist/cjs/types/XAdkSender.js.map +1 -1
  34. package/dist/cjs/utils/markdownResource.d.ts +12 -5
  35. package/dist/cjs/utils/markdownResource.js +66 -14
  36. package/dist/cjs/utils/markdownResource.js.map +2 -2
  37. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.d.ts +10 -0
  38. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js +76 -13
  39. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/index.js.map +1 -1
  40. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js +1 -1
  41. package/dist/esm/components/XAdkChatbot/components/MarkdownRender/styles.js.map +1 -1
  42. package/dist/esm/components/XAdkChatbot/index.js +27 -4
  43. package/dist/esm/components/XAdkChatbot/index.js.map +1 -1
  44. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.d.ts +6 -2
  45. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js +55 -12
  46. package/dist/esm/components/XAdkProvider/compound/DefaultLayout.js.map +1 -1
  47. package/dist/esm/components/XAdkProvider/compound/Sender.d.ts +2 -1
  48. package/dist/esm/components/XAdkProvider/compound/Sender.js +2 -1
  49. package/dist/esm/components/XAdkProvider/compound/Sender.js.map +1 -1
  50. package/dist/esm/components/XAdkProvider/compound/styles.d.ts +1 -0
  51. package/dist/esm/components/XAdkProvider/compound/styles.js +3 -2
  52. package/dist/esm/components/XAdkProvider/compound/styles.js.map +1 -1
  53. package/dist/esm/components/XAdkSender/InlineTagInput.js +154 -4
  54. package/dist/esm/components/XAdkSender/InlineTagInput.js.map +1 -1
  55. package/dist/esm/components/XAdkSender/index.js +25 -58
  56. package/dist/esm/components/XAdkSender/index.js.map +1 -1
  57. package/dist/esm/hooks/useADKChat.js +8 -2
  58. package/dist/esm/hooks/useADKChat.js.map +1 -1
  59. package/dist/esm/index.d.ts +2 -2
  60. package/dist/esm/index.js +2 -2
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/presets/xgroup/preset.js +3 -2
  63. package/dist/esm/presets/xgroup/preset.js.map +1 -1
  64. package/dist/esm/presets/xgroup/strategies.d.ts +5 -1
  65. package/dist/esm/presets/xgroup/strategies.js +12 -1
  66. package/dist/esm/presets/xgroup/strategies.js.map +1 -1
  67. package/dist/esm/types/ChatStrategies.d.ts +5 -0
  68. package/dist/esm/types/ChatStrategies.js.map +1 -1
  69. package/dist/esm/types/XAdkSender.d.ts +10 -3
  70. package/dist/esm/types/XAdkSender.js.map +1 -1
  71. package/dist/esm/utils/markdownResource.d.ts +12 -5
  72. package/dist/esm/utils/markdownResource.js +69 -7
  73. package/dist/esm/utils/markdownResource.js.map +1 -1
  74. package/dist/umd/chat-sdk.min.js +1 -1
  75. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/types/ChatStrategies.ts"],
4
- "sourcesContent": ["import type React from \"react\";\nimport type { ParseAgentMessageOptions, ParsedPart } from \"@/utils\";\nimport type { IMessage, FunctionCall, FunctionResponse } from \"./XAdkChatbot\";\nimport type { ToolRenderKind } from \"./FunctionCallRender\";\nimport type { UploadRequestFn } from \"./XAdkSender\";\n\nexport interface ToolKindResolveContext {\n name?: string;\n msg?: IMessage;\n}\n\nexport interface ChatStrategies {\n /**\n * 工具名/消息 -> 渲染类型解析策略。\n */\n resolveToolKind?: (ctx: ToolKindResolveContext) => ToolRenderKind;\n /**\n * 函数调用确认场景中,基于工具调用和用户选择生成 functionResponse。\n */\n createFunctionResponse?: (\n fnCall: FunctionCall,\n confirmed: boolean,\n ) => FunctionResponse;\n /**\n * 将模型文本拆分为过程节点和最终答案。\n */\n parseProcessMessage?: (\n text: string,\n options?: ParseAgentMessageOptions,\n ) => ParsedPart[];\n /**\n * 自定义 approval 场景渲染,返回 null 则使用默认渲染。\n */\n renderApproval?: (\n msg: IMessage,\n onConfirm?: (fnCall: FunctionCall, confirmed: boolean) => void,\n ) => React.ReactNode | null;\n /**\n * 自定义 handoff 场景渲染,返回 null 则使用默认渲染。\n */\n renderHandoff?: (msg: IMessage) => React.ReactNode | null;\n}\n\nexport interface ChatPreset {\n name: string;\n strategies?: ChatStrategies;\n /**\n * 基于当前协议预设创建默认文件上传函数。\n * 用户显式传入 config.uploadRequest 时优先使用用户配置。\n */\n createUploadRequest?: (context: {\n url: string;\n token?: string;\n appNo?: string;\n }) => UploadRequestFn | undefined;\n}\n\nexport type ChatPresetInput = \"base\" | \"xgroup-adk\" | ChatPreset;\n"],
4
+ "sourcesContent": ["import type React from \"react\";\nimport type { ParseAgentMessageOptions, ParsedPart } from \"@/utils\";\nimport type { IMessage, FunctionCall, FunctionResponse } from \"./XAdkChatbot\";\nimport type { ToolRenderKind } from \"./FunctionCallRender\";\nimport type { UploadRequestFn } from \"./XAdkSender\";\n\nexport interface ToolKindResolveContext {\n name?: string;\n msg?: IMessage;\n}\n\nexport interface ChatStrategies {\n /**\n * 工具名/消息 -> 渲染类型解析策略。\n */\n resolveToolKind?: (ctx: ToolKindResolveContext) => ToolRenderKind;\n /**\n * 函数调用确认场景中,基于工具调用和用户选择生成 functionResponse。\n */\n createFunctionResponse?: (\n fnCall: FunctionCall,\n confirmed: boolean,\n ) => FunctionResponse;\n /**\n * 将模型文本拆分为过程节点和最终答案。\n */\n parseProcessMessage?: (\n text: string,\n options?: ParseAgentMessageOptions,\n ) => ParsedPart[];\n /**\n * Markdown 资源链接协议白名单,如 skill://、plugin://。\n * 业务预设可在这里追加私有协议,例如 xgroup-adk 的 kb://。\n */\n markdownResourceLinkSchemes?: readonly string[];\n /**\n * 自定义 approval 场景渲染,返回 null 则使用默认渲染。\n */\n renderApproval?: (\n msg: IMessage,\n onConfirm?: (fnCall: FunctionCall, confirmed: boolean) => void,\n ) => React.ReactNode | null;\n /**\n * 自定义 handoff 场景渲染,返回 null 则使用默认渲染。\n */\n renderHandoff?: (msg: IMessage) => React.ReactNode | null;\n}\n\nexport interface ChatPreset {\n name: string;\n strategies?: ChatStrategies;\n /**\n * 基于当前协议预设创建默认文件上传函数。\n * 用户显式传入 config.uploadRequest 时优先使用用户配置。\n */\n createUploadRequest?: (context: {\n url: string;\n token?: string;\n appNo?: string;\n }) => UploadRequestFn | undefined;\n}\n\nexport type ChatPresetInput = \"base\" | \"xgroup-adk\" | ChatPreset;\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -146,7 +146,6 @@ export type FileValidator = (file: File, context: {
146
146
  }) => string | null;
147
147
  export interface ActionsComponents {
148
148
  SendButton: React.ComponentType<any>;
149
- UploadButton: React.ComponentType<any>;
150
149
  ClearButton: React.ComponentType<any>;
151
150
  }
152
151
  export type SlotRenderFunction = (oriNode: React.ReactNode, info: {
@@ -164,9 +163,17 @@ export interface UploaderCoreProps {
164
163
  }
165
164
  export interface SenderUIProps {
166
165
  clearBtnShow?: boolean;
167
- allowUpload?: boolean;
168
- /** 是否启用 Sender 自身的拖拽上传,设为 false 时由外层(如 DefaultLayout)管理拖拽 */
166
+ /**
167
+ * 是否启用 Sender 自身的拖拽上传。
168
+ * 拖拽产生的文件通过 onFileSelect 回调交给业务/外层处理;
169
+ * 默认 false,由外层(如 DefaultLayout)管理拖拽时无需开启。
170
+ */
169
171
  draggable?: boolean;
172
+ /**
173
+ * 拖拽文件回调:当 draggable 为 true 且用户向输入区拖拽文件时触发。
174
+ * 业务/外层在此回调中决定如何处理文件(通常调用 senderRef.addFiles 注入)。
175
+ */
176
+ onFileSelect?: (files: File[]) => void;
170
177
  loading?: boolean;
171
178
  disabled?: boolean;
172
179
  placeholder?: string;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/types/XAdkSender.ts"],
4
- "sourcesContent": ["// types/XAdkSender.ts\nimport React from \"react\";\n\n// ===================== 快捷键/Mention 相关类型 =====================\n\n/** 快捷键触发的列表项 */\nexport interface QuickListOption {\n id: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n /** 分组名(用于聚合列表,子分组通过下划线分割) */\n group?: string;\n [key: string]: any;\n}\n\n/** 快捷键配置 */\nexport interface QuickKeyConfig {\n /** 触发字符,如 '@', '#', '$' */\n key: string;\n /** 选中后写入 MentionTag.type 的语义类型,不传时回退为 key */\n mentionType?: string;\n /** @deprecated 请使用 mentionType。 */\n tagType?: string;\n /** 列表标题 */\n title?: string;\n /** 列表数据 */\n options: QuickListOption[];\n /** 自定义列表项渲染 */\n renderItem?: (option: QuickListOption) => React.ReactNode;\n /** 选中回调 */\n onSelect?: (option: QuickListOption) => void;\n}\n\n/** 输入框内的资源引用。SDK 只理解通用 Mention,业务语义可放入 data 或可选语义字段。 */\nexport interface MentionTag {\n id: string;\n label: string;\n /** Mention 类型,如 'knowledge', 'skill', 'plugin', 'agent' */\n type: string;\n /** 资源 URI,如 skill://skillNo、kb://kb/knNo/dir/docs/2024 */\n uri?: string;\n /** 业务资源 ID,如 skillNo、knowledgeNo */\n targetId?: string;\n /** 展示名;不传时回退 label */\n displayName?: string;\n /** 提交为纯文本/Markdown/XML 时使用的业务值,不传时回退 uri/targetId/label */\n value?: string;\n /** 触发字符,如 '@', '#', '$',用于业务方区分来源 */\n trigger?: string;\n color?: string;\n icon?: React.ReactNode;\n /** 业务扩展上下文,例如知识库目录 scope */\n scope?: any;\n /** 原始数据 */\n data?: any;\n}\n\n/** @deprecated 请使用 MentionTag。 */\nexport type InputTag = MentionTag;\n\nexport interface InlineTagRenderInfo {\n onRemove: () => void;\n}\n\nexport type XAdkSenderSubmitFormat = \"text\" | \"structured\" | \"markdown\" | \"xml\";\n\nexport type XAdkSenderSubmitPart =\n | { type: \"text\"; text: string }\n | { type: \"mention\"; mention: MentionTag };\n\n/** @deprecated 旧 tag part,仅用于兼容 defaultInputParts 历史传入。 */\nexport type XAdkSenderLegacyTagPart = { type: \"tag\"; tag: MentionTag };\n\n/** 输入框文本/Mention 有序片段,表示用户正在编辑的输入内容 */\nexport type XAdkSenderInputPart =\n | XAdkSenderSubmitPart\n | XAdkSenderLegacyTagPart;\n\nexport interface XAdkSenderFormatMentionContext {\n format: Exclude<XAdkSenderSubmitFormat, \"structured\">;\n index: number;\n}\n\n/** @deprecated 请使用 XAdkSenderFormatMentionContext。 */\nexport type XAdkSenderFormatTagContext = XAdkSenderFormatMentionContext;\n\nexport interface XAdkSenderSubmitData<TPayload = unknown> {\n /** 根据 submitFormat 生成的最终内容,默认是纯文本 */\n text: string;\n /** 去掉标签后的用户原始输入文本 */\n rawText: string;\n /** 当前提交格式 */\n format: XAdkSenderSubmitFormat;\n /** 文本与 Mention 的有序片段,inlineTags 模式下可还原资源引用在输入框中的位置 */\n parts: XAdkSenderSubmitPart[];\n files: ServerFile[];\n /** 当前 Mention 列表 */\n mentions?: MentionTag[];\n /** @deprecated 请使用 mentions。 */\n tags?: MentionTag[];\n /** 业务方通过 transformSubmitData 派生出的自定义提交结构 */\n payload?: TPayload;\n}\n\n// ===================== 上传相关类型 =====================\n\nexport interface UploadFileResult {\n fileName?: string;\n fileId?: string | number;\n tempUrl?: string;\n url?: string;\n fileUrl?: string;\n fileType?: string;\n fileSize?: number;\n mimeType?: string;\n [key: string]: any;\n}\n\nexport interface UploadSuccessResponse {\n data?: UploadFileResult | UploadFileResult[];\n [key: string]: any;\n}\n\ninterface uploadRequestProps {\n (options: {\n file: File;\n onProgress?: (e: { percent: number }) => void;\n onSuccess?: (\n response: UploadFileResult | UploadFileResult[] | UploadSuccessResponse,\n ) => void;\n onError?: (error: Error) => void;\n }): Promise<void> | void;\n}\n\nexport type UploadRequestFn = uploadRequestProps;\n\nexport interface ServerFile {\n fileName: string;\n fileId: string | number;\n tempUrl: string;\n type: string;\n size?: number;\n mimeType: string;\n raw?: UploadFileResult;\n}\n\nexport interface LocalFile {\n id: string;\n uid: string;\n name: string;\n file: File;\n size: number;\n type: string;\n progress: number;\n status: \"pending\" | \"uploading\" | \"success\" | \"error\";\n // 服务器返回字段\n fileId?: string | number;\n tempUrl?: string;\n response?: any;\n errorMessage?: string; // 上传错误信息\n}\n\nexport type FileValidator = (\n file: File,\n context: { files: LocalFile[] },\n) => string | null;\n\nexport interface ActionsComponents {\n SendButton: React.ComponentType<any>;\n UploadButton: React.ComponentType<any>;\n ClearButton: React.ComponentType<any>;\n}\n\nexport type SlotRenderFunction = (\n oriNode: React.ReactNode,\n info: { components: ActionsComponents },\n) => React.ReactNode | false;\n\n// 上传相关\nexport interface UploaderCoreProps {\n uploadRequest?: uploadRequestProps;\n\n maxFileSize?: number;\n allowedFileTypes?: string[];\n maxFiles?: number;\n\n validators?: FileValidator[];\n\n // 数据层回调\n onFilesChange?: (files: LocalFile[]) => void;\n onUploadSuccess?: (file: LocalFile) => void;\n onUploadError?: (file: LocalFile, error: Error) => void;\n}\n\n// UI 相关\nexport interface SenderUIProps {\n clearBtnShow?: boolean;\n allowUpload?: boolean;\n /** 是否启用 Sender 自身的拖拽上传,设为 false 时由外层(如 DefaultLayout)管理拖拽 */\n draggable?: boolean;\n loading?: boolean;\n disabled?: boolean; // 只读状态\n placeholder?: string;\n /** 受控:输入框的值 */\n value?: string;\n /** 非受控:输入框默认值 */\n defaultValue?: string;\n onClear?: () => void;\n onChange?: (value: string) => void;\n onSubmit?: (data: XAdkSenderSubmitData) => void;\n onStop?: () => void;\n\n /** 自定义发送按钮渲染 */\n sendButtonRender?: (info: {\n loading: boolean;\n disabled: boolean;\n /** 当前是否可以发送(文本非空或有已上传的文件) */\n canSend: boolean;\n onSend: () => void;\n onStop?: () => void;\n }) => React.ReactNode;\n\n // UI插槽功能\n /** 后缀内容,默认展示操作按钮,设为 false 时不显示 */\n suffix?: React.ReactNode | false | SlotRenderFunction;\n /** 输入主体内部的头部内容 */\n header?: React.ReactNode | false | SlotRenderFunction;\n /** 前缀内容 */\n prefix?: React.ReactNode | false | SlotRenderFunction;\n /** 底部内容 */\n footer?: React.ReactNode | false | SlotRenderFunction;\n /** 底部左侧拓展区域,不传时 footer 保持原有居中布局 */\n footerLeft?: React.ReactNode | false | SlotRenderFunction;\n\n // 快捷键/Mention 功能\n /** 快捷键配置列表 */\n quickKeys?: QuickKeyConfig[];\n /** 是否把 Mention 以内联 token 形式展示在输入区内;默认 false 保持历史 textarea 行为 */\n inlineTags?: boolean;\n /** 自定义内联 Mention 渲染 */\n renderMention?: (\n mention: MentionTag,\n info: InlineTagRenderInfo,\n ) => React.ReactNode;\n /** @deprecated 请使用 renderMention。 */\n renderTag?: (\n mention: MentionTag,\n info: InlineTagRenderInfo,\n ) => React.ReactNode;\n /** 受控:Mention 列表 */\n mentions?: MentionTag[];\n /** @deprecated 请使用 mentions。 */\n tags?: MentionTag[];\n /** 非受控:默认 Mention 列表 */\n defaultMentions?: MentionTag[];\n /** @deprecated 请使用 defaultMentions。 */\n defaultTags?: MentionTag[];\n /** 非受控:默认输入内容片段,用于初始化内联 Mention 输入区 */\n defaultInputParts?: XAdkSenderInputPart[];\n /** Mention 变化回调 */\n onMentionsChange?: (mentions: MentionTag[]) => void;\n /** @deprecated 请使用 onMentionsChange。 */\n onTagsChange?: (mentions: MentionTag[]) => void;\n /** 快捷键触发回调(业务方可在此处理搜索等逻辑) */\n onQuickKeyTrigger?: (key: string, keyword: string) => void;\n /**\n * 提交内容格式:\n * - text: 默认,输出文字 + Mention 文本(如 @生图技能)\n * - structured: 保留 parts/mentions/files 结构化数据,text 为 rawText\n * - markdown/xml: 输出对应标记文本\n */\n submitFormat?: XAdkSenderSubmitFormat;\n /** 自定义 Mention 在 text/markdown/xml 格式中的序列化结果 */\n formatMention?: (\n mention: MentionTag,\n context: XAdkSenderFormatMentionContext,\n ) => string;\n /** @deprecated 请使用 formatMention。 */\n formatTag?: (\n mention: MentionTag,\n context: XAdkSenderFormatMentionContext,\n ) => string;\n /**\n * 基于 SDK 标准提交结构派生业务 payload。\n * SDK 不理解 knowledge/skill/agent 等业务字段,只负责把 payload 原样放入 onSubmit 数据中。\n */\n transformSubmitData?: (\n data: Omit<XAdkSenderSubmitData, \"payload\">,\n ) => unknown;\n}\n\nexport type XAdkSenderProps = SenderUIProps & UploaderCoreProps;\n\nexport interface XAdkSenderHandle {\n addFiles: (files: File[]) => void;\n /** 向当前光标位置插入一个内联 Mention;未启用 inlineTags 时会退化为追加 Mention。 */\n insertMention: (mention: MentionTag) => void;\n /** @deprecated 请使用 insertMention。 */\n insertTag: (mention: MentionTag) => void;\n /** 聚焦输入区 */\n focus: () => void;\n}\n"],
4
+ "sourcesContent": ["// types/XAdkSender.ts\nimport React from \"react\";\n\n// ===================== 快捷键/Mention 相关类型 =====================\n\n/** 快捷键触发的列表项 */\nexport interface QuickListOption {\n id: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n /** 分组名(用于聚合列表,子分组通过下划线分割) */\n group?: string;\n [key: string]: any;\n}\n\n/** 快捷键配置 */\nexport interface QuickKeyConfig {\n /** 触发字符,如 '@', '#', '$' */\n key: string;\n /** 选中后写入 MentionTag.type 的语义类型,不传时回退为 key */\n mentionType?: string;\n /** @deprecated 请使用 mentionType。 */\n tagType?: string;\n /** 列表标题 */\n title?: string;\n /** 列表数据 */\n options: QuickListOption[];\n /** 自定义列表项渲染 */\n renderItem?: (option: QuickListOption) => React.ReactNode;\n /** 选中回调 */\n onSelect?: (option: QuickListOption) => void;\n}\n\n/** 输入框内的资源引用。SDK 只理解通用 Mention,业务语义可放入 data 或可选语义字段。 */\nexport interface MentionTag {\n id: string;\n label: string;\n /** Mention 类型,如 'knowledge', 'skill', 'plugin', 'agent' */\n type: string;\n /** 资源 URI,如 skill://skillNo、kb://kb/knNo/dir/docs/2024 */\n uri?: string;\n /** 业务资源 ID,如 skillNo、knowledgeNo */\n targetId?: string;\n /** 展示名;不传时回退 label */\n displayName?: string;\n /** 提交为纯文本/Markdown/XML 时使用的业务值,不传时回退 uri/targetId/label */\n value?: string;\n /** 触发字符,如 '@', '#', '$',用于业务方区分来源 */\n trigger?: string;\n color?: string;\n icon?: React.ReactNode;\n /** 业务扩展上下文,例如知识库目录 scope */\n scope?: any;\n /** 原始数据 */\n data?: any;\n}\n\n/** @deprecated 请使用 MentionTag。 */\nexport type InputTag = MentionTag;\n\nexport interface InlineTagRenderInfo {\n onRemove: () => void;\n}\n\nexport type XAdkSenderSubmitFormat = \"text\" | \"structured\" | \"markdown\" | \"xml\";\n\nexport type XAdkSenderSubmitPart =\n | { type: \"text\"; text: string }\n | { type: \"mention\"; mention: MentionTag };\n\n/** @deprecated 旧 tag part,仅用于兼容 defaultInputParts 历史传入。 */\nexport type XAdkSenderLegacyTagPart = { type: \"tag\"; tag: MentionTag };\n\n/** 输入框文本/Mention 有序片段,表示用户正在编辑的输入内容 */\nexport type XAdkSenderInputPart =\n | XAdkSenderSubmitPart\n | XAdkSenderLegacyTagPart;\n\nexport interface XAdkSenderFormatMentionContext {\n format: Exclude<XAdkSenderSubmitFormat, \"structured\">;\n index: number;\n}\n\n/** @deprecated 请使用 XAdkSenderFormatMentionContext。 */\nexport type XAdkSenderFormatTagContext = XAdkSenderFormatMentionContext;\n\nexport interface XAdkSenderSubmitData<TPayload = unknown> {\n /** 根据 submitFormat 生成的最终内容,默认是纯文本 */\n text: string;\n /** 去掉标签后的用户原始输入文本 */\n rawText: string;\n /** 当前提交格式 */\n format: XAdkSenderSubmitFormat;\n /** 文本与 Mention 的有序片段,inlineTags 模式下可还原资源引用在输入框中的位置 */\n parts: XAdkSenderSubmitPart[];\n files: ServerFile[];\n /** 当前 Mention 列表 */\n mentions?: MentionTag[];\n /** @deprecated 请使用 mentions。 */\n tags?: MentionTag[];\n /** 业务方通过 transformSubmitData 派生出的自定义提交结构 */\n payload?: TPayload;\n}\n\n// ===================== 上传相关类型 =====================\n\nexport interface UploadFileResult {\n fileName?: string;\n fileId?: string | number;\n tempUrl?: string;\n url?: string;\n fileUrl?: string;\n fileType?: string;\n fileSize?: number;\n mimeType?: string;\n [key: string]: any;\n}\n\nexport interface UploadSuccessResponse {\n data?: UploadFileResult | UploadFileResult[];\n [key: string]: any;\n}\n\ninterface uploadRequestProps {\n (options: {\n file: File;\n onProgress?: (e: { percent: number }) => void;\n onSuccess?: (\n response: UploadFileResult | UploadFileResult[] | UploadSuccessResponse,\n ) => void;\n onError?: (error: Error) => void;\n }): Promise<void> | void;\n}\n\nexport type UploadRequestFn = uploadRequestProps;\n\nexport interface ServerFile {\n fileName: string;\n fileId: string | number;\n tempUrl: string;\n type: string;\n size?: number;\n mimeType: string;\n raw?: UploadFileResult;\n}\n\nexport interface LocalFile {\n id: string;\n uid: string;\n name: string;\n file: File;\n size: number;\n type: string;\n progress: number;\n status: \"pending\" | \"uploading\" | \"success\" | \"error\";\n // 服务器返回字段\n fileId?: string | number;\n tempUrl?: string;\n response?: any;\n errorMessage?: string; // 上传错误信息\n}\n\nexport type FileValidator = (\n file: File,\n context: { files: LocalFile[] },\n) => string | null;\n\nexport interface ActionsComponents {\n SendButton: React.ComponentType<any>;\n ClearButton: React.ComponentType<any>;\n}\n\nexport type SlotRenderFunction = (\n oriNode: React.ReactNode,\n info: { components: ActionsComponents },\n) => React.ReactNode | false;\n\n// 上传相关\nexport interface UploaderCoreProps {\n uploadRequest?: uploadRequestProps;\n\n maxFileSize?: number;\n allowedFileTypes?: string[];\n maxFiles?: number;\n\n validators?: FileValidator[];\n\n // 数据层回调\n onFilesChange?: (files: LocalFile[]) => void;\n onUploadSuccess?: (file: LocalFile) => void;\n onUploadError?: (file: LocalFile, error: Error) => void;\n}\n\n// UI 相关\nexport interface SenderUIProps {\n clearBtnShow?: boolean;\n /**\n * 是否启用 Sender 自身的拖拽上传。\n * 拖拽产生的文件通过 onFileSelect 回调交给业务/外层处理;\n * 默认 false,由外层(如 DefaultLayout)管理拖拽时无需开启。\n */\n draggable?: boolean;\n /**\n * 拖拽文件回调:当 draggable 为 true 且用户向输入区拖拽文件时触发。\n * 业务/外层在此回调中决定如何处理文件(通常调用 senderRef.addFiles 注入)。\n */\n onFileSelect?: (files: File[]) => void;\n loading?: boolean;\n disabled?: boolean; // 只读状态\n placeholder?: string;\n /** 受控:输入框的值 */\n value?: string;\n /** 非受控:输入框默认值 */\n defaultValue?: string;\n onClear?: () => void;\n onChange?: (value: string) => void;\n onSubmit?: (data: XAdkSenderSubmitData) => void;\n onStop?: () => void;\n\n /** 自定义发送按钮渲染 */\n sendButtonRender?: (info: {\n loading: boolean;\n disabled: boolean;\n /** 当前是否可以发送(文本非空或有已上传的文件) */\n canSend: boolean;\n onSend: () => void;\n onStop?: () => void;\n }) => React.ReactNode;\n\n // UI插槽功能\n /** 后缀内容,默认展示操作按钮,设为 false 时不显示 */\n suffix?: React.ReactNode | false | SlotRenderFunction;\n /** 输入主体内部的头部内容 */\n header?: React.ReactNode | false | SlotRenderFunction;\n /** 前缀内容 */\n prefix?: React.ReactNode | false | SlotRenderFunction;\n /** 底部内容 */\n footer?: React.ReactNode | false | SlotRenderFunction;\n /** 底部左侧拓展区域,不传时 footer 保持原有居中布局 */\n footerLeft?: React.ReactNode | false | SlotRenderFunction;\n\n // 快捷键/Mention 功能\n /** 快捷键配置列表 */\n quickKeys?: QuickKeyConfig[];\n /** 是否把 Mention 以内联 token 形式展示在输入区内;默认 false 保持历史 textarea 行为 */\n inlineTags?: boolean;\n /** 自定义内联 Mention 渲染 */\n renderMention?: (\n mention: MentionTag,\n info: InlineTagRenderInfo,\n ) => React.ReactNode;\n /** @deprecated 请使用 renderMention。 */\n renderTag?: (\n mention: MentionTag,\n info: InlineTagRenderInfo,\n ) => React.ReactNode;\n /** 受控:Mention 列表 */\n mentions?: MentionTag[];\n /** @deprecated 请使用 mentions。 */\n tags?: MentionTag[];\n /** 非受控:默认 Mention 列表 */\n defaultMentions?: MentionTag[];\n /** @deprecated 请使用 defaultMentions。 */\n defaultTags?: MentionTag[];\n /** 非受控:默认输入内容片段,用于初始化内联 Mention 输入区 */\n defaultInputParts?: XAdkSenderInputPart[];\n /** Mention 变化回调 */\n onMentionsChange?: (mentions: MentionTag[]) => void;\n /** @deprecated 请使用 onMentionsChange。 */\n onTagsChange?: (mentions: MentionTag[]) => void;\n /** 快捷键触发回调(业务方可在此处理搜索等逻辑) */\n onQuickKeyTrigger?: (key: string, keyword: string) => void;\n /**\n * 提交内容格式:\n * - text: 默认,输出文字 + Mention 文本(如 @生图技能)\n * - structured: 保留 parts/mentions/files 结构化数据,text 为 rawText\n * - markdown/xml: 输出对应标记文本\n */\n submitFormat?: XAdkSenderSubmitFormat;\n /** 自定义 Mention 在 text/markdown/xml 格式中的序列化结果 */\n formatMention?: (\n mention: MentionTag,\n context: XAdkSenderFormatMentionContext,\n ) => string;\n /** @deprecated 请使用 formatMention。 */\n formatTag?: (\n mention: MentionTag,\n context: XAdkSenderFormatMentionContext,\n ) => string;\n /**\n * 基于 SDK 标准提交结构派生业务 payload。\n * SDK 不理解 knowledge/skill/agent 等业务字段,只负责把 payload 原样放入 onSubmit 数据中。\n */\n transformSubmitData?: (\n data: Omit<XAdkSenderSubmitData, \"payload\">,\n ) => unknown;\n}\n\nexport type XAdkSenderProps = SenderUIProps & UploaderCoreProps;\n\nexport interface XAdkSenderHandle {\n addFiles: (files: File[]) => void;\n /** 向当前光标位置插入一个内联 Mention;未启用 inlineTags 时会退化为追加 Mention。 */\n insertMention: (mention: MentionTag) => void;\n /** @deprecated 请使用 insertMention。 */\n insertTag: (mention: MentionTag) => void;\n /** 聚焦输入区 */\n focus: () => void;\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,14 @@
1
- import type { MarkdownResourceLink } from "../types";
2
- export declare const MARKDOWN_RESOURCE_LINK_SCHEMES: readonly ["skill", "plugin", "tool", "knowledge", "kb", "agent", "model"];
3
- export declare const parseMarkdownResourceHref: (href: string, label?: string) => MarkdownResourceLink | null;
4
- export declare const replaceMarkdownResourceLinks: (text: string, replacer: (link: MarkdownResourceLink) => string) => string;
5
- export declare const formatMarkdownResourceLinksAsText: (text: string, options?: {
1
+ import type { MarkdownResourceLink, XAdkSenderSubmitPart } from "../types";
2
+ export declare const MARKDOWN_RESOURCE_LINK_SCHEMES: readonly ["skill", "plugin", "tool", "knowledge", "agent", "model"];
3
+ export type MarkdownResourceLinkScheme = (typeof MARKDOWN_RESOURCE_LINK_SCHEMES)[number] | (string & {});
4
+ export interface MarkdownResourceLinkOptions {
5
+ schemes?: readonly MarkdownResourceLinkScheme[];
6
+ }
7
+ export declare const getMarkdownResourceDisplayLabel: (label: string) => string;
8
+ /** 将包含资源链接的 Markdown 还原成 Sender 可编辑的有序片段。 */
9
+ export declare const parseMarkdownResourceLinksAsParts: (text: string, options?: MarkdownResourceLinkOptions) => XAdkSenderSubmitPart[];
10
+ export declare const parseMarkdownResourceHref: (href: string, label?: string, options?: MarkdownResourceLinkOptions) => MarkdownResourceLink | null;
11
+ export declare const replaceMarkdownResourceLinks: (text: string, replacer: (link: MarkdownResourceLink) => string, options?: MarkdownResourceLinkOptions) => string;
12
+ export declare const formatMarkdownResourceLinksAsText: (text: string, options?: MarkdownResourceLinkOptions & {
6
13
  stripTrigger?: boolean;
7
14
  }) => string;
@@ -21,7 +21,9 @@ var markdownResource_exports = {};
21
21
  __export(markdownResource_exports, {
22
22
  MARKDOWN_RESOURCE_LINK_SCHEMES: () => MARKDOWN_RESOURCE_LINK_SCHEMES,
23
23
  formatMarkdownResourceLinksAsText: () => formatMarkdownResourceLinksAsText,
24
+ getMarkdownResourceDisplayLabel: () => getMarkdownResourceDisplayLabel,
24
25
  parseMarkdownResourceHref: () => parseMarkdownResourceHref,
26
+ parseMarkdownResourceLinksAsParts: () => parseMarkdownResourceLinksAsParts,
25
27
  replaceMarkdownResourceLinks: () => replaceMarkdownResourceLinks
26
28
  });
27
29
  module.exports = __toCommonJS(markdownResource_exports);
@@ -30,19 +32,60 @@ var MARKDOWN_RESOURCE_LINK_SCHEMES = [
30
32
  "plugin",
31
33
  "tool",
32
34
  "knowledge",
33
- "kb",
34
35
  "agent",
35
36
  "model"
36
37
  ];
37
- var RESOURCE_LINK_SCHEME_SET = new Set(MARKDOWN_RESOURCE_LINK_SCHEMES);
38
- var RESOURCE_LINK_REGEX = /\[([^\]\n]+)\]\(((?:skill|plugin|tool|knowledge|kb|agent|model):\/{2,3}[^)\s]+)\)/gi;
38
+ var getResourceLinkSchemeSet = (options) => new Set((options == null ? void 0 : options.schemes) || MARKDOWN_RESOURCE_LINK_SCHEMES);
39
+ var RESOURCE_LINK_REGEX = /\[([^\]\n]+)\]\(([a-z][a-z0-9+.-]*:\/{2,3}[^)\s]+)\)/gi;
39
40
  var stripTriggerPrefix = (label) => label.replace(/^[@/#$]+/, "");
40
- var parseMarkdownResourceHref = (href, label = "") => {
41
+ var getMarkdownResourceDisplayLabel = (label) => stripTriggerPrefix(label).trim();
42
+ var parseMarkdownResourceLinksAsParts = (text, options) => {
43
+ var _a;
44
+ if (!text)
45
+ return [];
46
+ const parts = [];
47
+ let lastIndex = 0;
48
+ let mentionIndex = 0;
49
+ const regex = new RegExp(RESOURCE_LINK_REGEX.source, RESOURCE_LINK_REGEX.flags);
50
+ let match;
51
+ while ((match = regex.exec(text)) !== null) {
52
+ const source = match[0];
53
+ const label = match[1] || "";
54
+ const href = match[2] || "";
55
+ const start = match.index ?? 0;
56
+ const link = parseMarkdownResourceHref(href, label, options);
57
+ if (!link)
58
+ continue;
59
+ if (start > lastIndex) {
60
+ parts.push({ type: "text", text: text.slice(lastIndex, start) });
61
+ }
62
+ const displayName = getMarkdownResourceDisplayLabel(link.label || link.value);
63
+ const mention = {
64
+ id: `pasted-${link.type}-${mentionIndex}-${Date.now().toString(36)}`,
65
+ label: displayName,
66
+ displayName,
67
+ type: link.type,
68
+ uri: link.href,
69
+ targetId: link.value,
70
+ value: link.value,
71
+ trigger: (_a = label.match(/^[@/#$]+/)) == null ? void 0 : _a[0],
72
+ data: { uri: link.href, value: link.value }
73
+ };
74
+ parts.push({ type: "mention", mention });
75
+ mentionIndex += 1;
76
+ lastIndex = start + source.length;
77
+ }
78
+ if (lastIndex < text.length) {
79
+ parts.push({ type: "text", text: text.slice(lastIndex) });
80
+ }
81
+ return parts.length > 0 ? parts : [{ type: "text", text }];
82
+ };
83
+ var parseMarkdownResourceHref = (href, label = "", options) => {
41
84
  const match = href.match(/^([a-z][a-z0-9+.-]*):\/{2,3}(.+)$/i);
42
85
  if (!match)
43
86
  return null;
44
87
  const type = match[1].toLowerCase();
45
- if (!RESOURCE_LINK_SCHEME_SET.has(type))
88
+ if (!getResourceLinkSchemeSet(options).has(type))
46
89
  return null;
47
90
  return {
48
91
  href,
@@ -51,23 +94,32 @@ var parseMarkdownResourceHref = (href, label = "") => {
51
94
  value: decodeURIComponent(match[2])
52
95
  };
53
96
  };
54
- var replaceMarkdownResourceLinks = (text, replacer) => {
97
+ var replaceMarkdownResourceLinks = (text, replacer, options) => {
55
98
  if (!text)
56
99
  return "";
57
- return text.replace(RESOURCE_LINK_REGEX, (source, label, href) => {
58
- const link = parseMarkdownResourceHref(href, label);
59
- return link ? replacer(link) : source;
60
- });
100
+ return text.replace(
101
+ RESOURCE_LINK_REGEX,
102
+ (source, label, href) => {
103
+ const link = parseMarkdownResourceHref(href, label, options);
104
+ return link ? replacer(link) : source;
105
+ }
106
+ );
61
107
  };
62
- var formatMarkdownResourceLinksAsText = (text, options) => replaceMarkdownResourceLinks(text, (link) => {
63
- const label = link.label || link.value;
64
- return (options == null ? void 0 : options.stripTrigger) === false ? label : stripTriggerPrefix(label);
65
- });
108
+ var formatMarkdownResourceLinksAsText = (text, options) => replaceMarkdownResourceLinks(
109
+ text,
110
+ (link) => {
111
+ const label = link.label || link.value;
112
+ return (options == null ? void 0 : options.stripTrigger) === false ? label : stripTriggerPrefix(label);
113
+ },
114
+ options
115
+ );
66
116
  // Annotate the CommonJS export names for ESM import in node:
67
117
  0 && (module.exports = {
68
118
  MARKDOWN_RESOURCE_LINK_SCHEMES,
69
119
  formatMarkdownResourceLinksAsText,
120
+ getMarkdownResourceDisplayLabel,
70
121
  parseMarkdownResourceHref,
122
+ parseMarkdownResourceLinksAsParts,
71
123
  replaceMarkdownResourceLinks
72
124
  });
73
125
  //# sourceMappingURL=markdownResource.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/markdownResource.ts"],
4
- "sourcesContent": ["import type { MarkdownResourceLink } from \"@/types\";\n\nexport const MARKDOWN_RESOURCE_LINK_SCHEMES = [\n \"skill\",\n \"plugin\",\n \"tool\",\n \"knowledge\",\n \"kb\",\n \"agent\",\n \"model\",\n] as const;\n\nconst RESOURCE_LINK_SCHEME_SET = new Set<string>(MARKDOWN_RESOURCE_LINK_SCHEMES);\nconst RESOURCE_LINK_REGEX =\n /\\[([^\\]\\n]+)\\]\\(((?:skill|plugin|tool|knowledge|kb|agent|model):\\/{2,3}[^)\\s]+)\\)/gi;\n\nconst stripTriggerPrefix = (label: string) => label.replace(/^[@/#$]+/, \"\");\n\nexport const parseMarkdownResourceHref = (\n href: string,\n label = \"\",\n): MarkdownResourceLink | null => {\n const match = href.match(/^([a-z][a-z0-9+.-]*):\\/{2,3}(.+)$/i);\n if (!match) return null;\n\n const type = match[1].toLowerCase();\n if (!RESOURCE_LINK_SCHEME_SET.has(type)) return null;\n\n return {\n href,\n label: label || href,\n type,\n value: decodeURIComponent(match[2]),\n };\n};\n\nexport const replaceMarkdownResourceLinks = (\n text: string,\n replacer: (link: MarkdownResourceLink) => string,\n) => {\n if (!text) return \"\";\n return text.replace(RESOURCE_LINK_REGEX, (source, label: string, href: string) => {\n const link = parseMarkdownResourceHref(href, label);\n return link ? replacer(link) : source;\n });\n};\n\nexport const formatMarkdownResourceLinksAsText = (\n text: string,\n options?: { stripTrigger?: boolean },\n) =>\n replaceMarkdownResourceLinks(text, (link) => {\n const label = link.label || link.value;\n return options?.stripTrigger === false ? label : stripTriggerPrefix(label);\n });\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,iCAAiC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,2BAA2B,IAAI,IAAY,8BAA8B;AAC/E,IAAM,sBACJ;AAEF,IAAM,qBAAqB,CAAC,UAAkB,MAAM,QAAQ,YAAY,EAAE;AAEnE,IAAM,4BAA4B,CACvC,MACA,QAAQ,OACwB;AAChC,QAAM,QAAQ,KAAK,MAAM,oCAAoC;AAC7D,MAAI,CAAC;AAAO,WAAO;AAEnB,QAAM,OAAO,MAAM,CAAC,EAAE,YAAY;AAClC,MAAI,CAAC,yBAAyB,IAAI,IAAI;AAAG,WAAO;AAEhD,SAAO;AAAA,IACL;AAAA,IACA,OAAO,SAAS;AAAA,IAChB;AAAA,IACA,OAAO,mBAAmB,MAAM,CAAC,CAAC;AAAA,EACpC;AACF;AAEO,IAAM,+BAA+B,CAC1C,MACA,aACG;AACH,MAAI,CAAC;AAAM,WAAO;AAClB,SAAO,KAAK,QAAQ,qBAAqB,CAAC,QAAQ,OAAe,SAAiB;AAChF,UAAM,OAAO,0BAA0B,MAAM,KAAK;AAClD,WAAO,OAAO,SAAS,IAAI,IAAI;AAAA,EACjC,CAAC;AACH;AAEO,IAAM,oCAAoC,CAC/C,MACA,YAEA,6BAA6B,MAAM,CAAC,SAAS;AAC3C,QAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,UAAO,mCAAS,kBAAiB,QAAQ,QAAQ,mBAAmB,KAAK;AAC3E,CAAC;",
4
+ "sourcesContent": ["import type {\n MarkdownResourceLink,\n MentionTag,\n XAdkSenderSubmitPart,\n} from \"@/types\";\n\nexport const MARKDOWN_RESOURCE_LINK_SCHEMES = [\n \"skill\",\n \"plugin\",\n \"tool\",\n \"knowledge\",\n \"agent\",\n \"model\",\n] as const;\n\nexport type MarkdownResourceLinkScheme =\n | (typeof MARKDOWN_RESOURCE_LINK_SCHEMES)[number]\n | (string & {});\n\nexport interface MarkdownResourceLinkOptions {\n schemes?: readonly MarkdownResourceLinkScheme[];\n}\n\nconst getResourceLinkSchemeSet = (options?: MarkdownResourceLinkOptions) =>\n new Set<string>(options?.schemes || MARKDOWN_RESOURCE_LINK_SCHEMES);\n\nconst RESOURCE_LINK_REGEX =\n /\\[([^\\]\\n]+)\\]\\(([a-z][a-z0-9+.-]*:\\/{2,3}[^)\\s]+)\\)/gi;\n\nconst stripTriggerPrefix = (label: string) => label.replace(/^[@/#$]+/, \"\");\n\nexport const getMarkdownResourceDisplayLabel = (label: string) =>\n stripTriggerPrefix(label).trim();\n\n/** 将包含资源链接的 Markdown 还原成 Sender 可编辑的有序片段。 */\nexport const parseMarkdownResourceLinksAsParts = (\n text: string,\n options?: MarkdownResourceLinkOptions,\n): XAdkSenderSubmitPart[] => {\n if (!text) return [];\n\n const parts: XAdkSenderSubmitPart[] = [];\n let lastIndex = 0;\n let mentionIndex = 0;\n const regex = new RegExp(RESOURCE_LINK_REGEX.source, RESOURCE_LINK_REGEX.flags);\n\n let match: RegExpExecArray | null;\n while ((match = regex.exec(text)) !== null) {\n const source = match[0];\n const label = match[1] || \"\";\n const href = match[2] || \"\";\n const start = match.index ?? 0;\n const link = parseMarkdownResourceHref(href, label, options);\n if (!link) continue;\n\n if (start > lastIndex) {\n parts.push({ type: \"text\", text: text.slice(lastIndex, start) });\n }\n\n const displayName = getMarkdownResourceDisplayLabel(link.label || link.value);\n const mention: MentionTag = {\n id: `pasted-${link.type}-${mentionIndex}-${Date.now().toString(36)}`,\n label: displayName,\n displayName,\n type: link.type,\n uri: link.href,\n targetId: link.value,\n value: link.value,\n trigger: label.match(/^[@/#$]+/)?.[0],\n data: { uri: link.href, value: link.value },\n };\n parts.push({ type: \"mention\", mention });\n mentionIndex += 1;\n lastIndex = start + source.length;\n }\n\n if (lastIndex < text.length) {\n parts.push({ type: \"text\", text: text.slice(lastIndex) });\n }\n return parts.length > 0 ? parts : [{ type: \"text\", text }];\n};\n\nexport const parseMarkdownResourceHref = (\n href: string,\n label = \"\",\n options?: MarkdownResourceLinkOptions,\n): MarkdownResourceLink | null => {\n const match = href.match(/^([a-z][a-z0-9+.-]*):\\/{2,3}(.+)$/i);\n if (!match) return null;\n\n const type = match[1].toLowerCase();\n if (!getResourceLinkSchemeSet(options).has(type)) return null;\n\n return {\n href,\n label: label || href,\n type,\n value: decodeURIComponent(match[2]),\n };\n};\n\nexport const replaceMarkdownResourceLinks = (\n text: string,\n replacer: (link: MarkdownResourceLink) => string,\n options?: MarkdownResourceLinkOptions,\n) => {\n if (!text) return \"\";\n return text.replace(\n RESOURCE_LINK_REGEX,\n (source, label: string, href: string) => {\n const link = parseMarkdownResourceHref(href, label, options);\n return link ? replacer(link) : source;\n },\n );\n};\n\nexport const formatMarkdownResourceLinksAsText = (\n text: string,\n options?: MarkdownResourceLinkOptions & { stripTrigger?: boolean },\n) =>\n replaceMarkdownResourceLinks(\n text,\n (link) => {\n const label = link.label || link.value;\n return options?.stripTrigger === false\n ? label\n : stripTriggerPrefix(label);\n },\n options,\n );\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -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;
@@ -7,7 +7,7 @@ import Latex from "@ant-design/x-markdown/plugins/Latex";
7
7
  import { useStyles } from "./styles";
8
8
  import { BarsOutlined, BulbOutlined, ThunderboltOutlined, CheckCircleOutlined } from "@ant-design/icons";
9
9
  import FileGallery from "../../../FileGallery";
10
- import { parseMarkdownResourceHref, replaceMarkdownResourceLinks } from "../../../../utils/markdownResource";
10
+ import { parseMarkdownResourceHref, getMarkdownResourceDisplayLabel, replaceMarkdownResourceLinks } from "../../../../utils/markdownResource";
11
11
 
12
12
  // 支持识别的文件扩展名
13
13
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -64,6 +64,13 @@ var escapeHtml = function escapeHtml(value) {
64
64
  var escapeAttr = function escapeAttr(value) {
65
65
  return escapeHtml(value).replace(/"/g, "&quot;").replace(/'/g, "&#39;");
66
66
  };
67
+ var escapeMarkdownLabel = function escapeMarkdownLabel(value) {
68
+ return value.replace(/\\/g, "\\\\").replace(/\]/g, "\\]");
69
+ };
70
+
71
+ // 使用标准 https 链接作为 Markdown AST 的内部载体,避免自定义 HTML 标签被解析器降级成纯文本。
72
+ var RESOURCE_LINK_SENTINEL = "https://xadk.local/resource";
73
+ var PLAIN_MENTION_SENTINEL = "https://xadk.local/mention";
67
74
  var CodeComponent = function CodeComponent(props) {
68
75
  var _className$match;
69
76
  var className = props.className,
@@ -118,21 +125,34 @@ var MarkdownRender = function MarkdownRender(_ref) {
118
125
  var text = _ref.text,
119
126
  _ref$compact = _ref.compact,
120
127
  compact = _ref$compact === void 0 ? false : _ref$compact,
128
+ resourceLinkSchemes = _ref.resourceLinkSchemes,
121
129
  onFileClick = _ref.onFileClick,
122
130
  onResourceLinkClick = _ref.onResourceLinkClick,
123
- renderResourceLink = _ref.renderResourceLink;
131
+ renderResourceLink = _ref.renderResourceLink,
132
+ _ref$bareUrlAsText = _ref.bareUrlAsText,
133
+ bareUrlAsText = _ref$bareUrlAsText === void 0 ? false : _ref$bareUrlAsText,
134
+ _ref$highlightPlainMe = _ref.highlightPlainMentions,
135
+ highlightPlainMentions = _ref$highlightPlainMe === void 0 ? false : _ref$highlightPlainMe;
124
136
  var styles = useStyles();
125
- var markdown = replaceMarkdownResourceLinks(text, function (link) {
126
- // 非 http(s) 协议容易被 Markdown 引擎清洗成普通文本,先转为内部自定义标签再交给 XMarkdown。
127
- return "<resource-link href=\"".concat(escapeAttr(link.href), "\" label=\"").concat(escapeAttr(link.label), "\" type=\"").concat(escapeAttr(link.type), "\" value=\"").concat(escapeAttr(link.value), "\">").concat(escapeHtml(link.label), "</resource-link>");
137
+ var displayText = highlightPlainMentions ? text.replace(/(^|[^\[a-z0-9_])@([a-z0-9][a-z0-9._-]*)/gi, function (_source, prefix, label) {
138
+ return "".concat(prefix, "[").concat(escapeMarkdownLabel(label), "](").concat(PLAIN_MENTION_SENTINEL, "?label=").concat(encodeURIComponent(label), ")");
139
+ }) : text;
140
+ var markdown = replaceMarkdownResourceLinks(displayText, function (link) {
141
+ // 非 http(s) 协议会被 Markdown 引擎清洗,先编码到内部标准链接中交给 a renderer 恢复。
142
+ return "[".concat(escapeMarkdownLabel(link.label), "](").concat(RESOURCE_LINK_SENTINEL, "?href=").concat(encodeURIComponent(link.href), "&label=").concat(encodeURIComponent(link.label), ")");
143
+ }, {
144
+ schemes: resourceLinkSchemes
128
145
  }).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(/\/\*\s*FINAL_ANSWER\s*\*\//g, '<tag type="final_answer"></tag>');
129
146
  var ResourceLinkComponent = React.useCallback(function (props) {
130
147
  var href = String(props.href || "");
131
148
  var linkText = String(props.label || "") || extractText(props.children);
132
- var resourceLink = parseMarkdownResourceHref(href, linkText);
149
+ var resourceLink = parseMarkdownResourceHref(href, linkText, {
150
+ schemes: resourceLinkSchemes
151
+ });
133
152
  if (!resourceLink) return /*#__PURE__*/_jsx(_Fragment, {
134
153
  children: props.children
135
154
  });
155
+ var displayLabel = getMarkdownResourceDisplayLabel(resourceLink.label);
136
156
  var customNode = renderResourceLink === null || renderResourceLink === void 0 ? void 0 : renderResourceLink(resourceLink);
137
157
  if (customNode) return customNode;
138
158
  return /*#__PURE__*/_jsx("button", {
@@ -141,18 +161,52 @@ var MarkdownRender = function MarkdownRender(_ref) {
141
161
  onClick: function onClick() {
142
162
  return onResourceLinkClick === null || onResourceLinkClick === void 0 ? void 0 : onResourceLinkClick(resourceLink);
143
163
  },
144
- "aria-label": resourceLink.label,
145
- children: resourceLink.label
164
+ "aria-label": displayLabel,
165
+ "data-xadk-resource-link": "true",
166
+ "data-resource-markdown": "[".concat(resourceLink.label, "](").concat(resourceLink.href, ")"),
167
+ children: displayLabel
146
168
  });
147
- }, [onResourceLinkClick, renderResourceLink, styles.resourceLink]);
169
+ }, [onResourceLinkClick, renderResourceLink, resourceLinkSchemes, styles.resourceLink]);
170
+ var PlainMentionComponent = React.useCallback(function (props) {
171
+ var label = String(props.label || "") || extractText(props.children);
172
+ return /*#__PURE__*/_jsx("span", {
173
+ className: styles.resourceLink,
174
+ "aria-label": label,
175
+ "data-xadk-resource-link": "true",
176
+ children: label
177
+ });
178
+ }, [styles.resourceLink]);
148
179
 
149
180
  // 自定义 a 标签渲染:资源协议渲染为标签,文件链接渲染为 FileGallery,其余保持普通链接。
150
181
  var LinkComponent = React.useCallback(function (props) {
151
182
  var href = String(props.href || "");
152
183
  // 用递归提取纯文本,避免 children 是 React node 时 String() 得到 "[object Object]"
153
184
  var linkText = extractText(props.children);
154
- var resourceLink = parseMarkdownResourceHref(href, linkText);
185
+ var resolvedHref = href;
186
+ var resolvedLabel = linkText;
187
+ try {
188
+ var internalUrl = new URL(href);
189
+ if (internalUrl.origin + internalUrl.pathname === PLAIN_MENTION_SENTINEL) {
190
+ var label = internalUrl.searchParams.get("label") || linkText;
191
+ return /*#__PURE__*/_jsx("span", {
192
+ className: styles.resourceLink,
193
+ "aria-label": label,
194
+ "data-xadk-resource-link": "true",
195
+ children: label
196
+ });
197
+ }
198
+ if (internalUrl.origin + internalUrl.pathname === RESOURCE_LINK_SENTINEL) {
199
+ resolvedHref = internalUrl.searchParams.get("href") || "";
200
+ resolvedLabel = internalUrl.searchParams.get("label") || linkText;
201
+ }
202
+ } catch (_unused) {
203
+ // 相对链接及非标准 URL 继续走原有解析逻辑。
204
+ }
205
+ var resourceLink = parseMarkdownResourceHref(resolvedHref, resolvedLabel, {
206
+ schemes: resourceLinkSchemes
207
+ });
155
208
  if (resourceLink) {
209
+ var displayLabel = getMarkdownResourceDisplayLabel(resourceLink.label);
156
210
  var customNode = renderResourceLink === null || renderResourceLink === void 0 ? void 0 : renderResourceLink(resourceLink);
157
211
  if (customNode) return customNode;
158
212
  return /*#__PURE__*/_jsx("button", {
@@ -161,8 +215,10 @@ var MarkdownRender = function MarkdownRender(_ref) {
161
215
  onClick: function onClick() {
162
216
  return onResourceLinkClick === null || onResourceLinkClick === void 0 ? void 0 : onResourceLinkClick(resourceLink);
163
217
  },
164
- "aria-label": resourceLink.label,
165
- children: resourceLink.label
218
+ "aria-label": displayLabel,
219
+ "data-xadk-resource-link": "true",
220
+ "data-resource-markdown": "[".concat(resourceLink.label, "](").concat(resourceLink.href, ")"),
221
+ children: displayLabel
166
222
  });
167
223
  }
168
224
 
@@ -171,6 +227,12 @@ var MarkdownRender = function MarkdownRender(_ref) {
171
227
  if (ext) {
172
228
  // href 为空说明链接还在流式截断中,不渲染,避免显示出错误文字
173
229
  if (!href) return null;
230
+ // 用户消息场景:裸 URL 不富化,直接展示为纯文本字符串
231
+ if (bareUrlAsText) {
232
+ return /*#__PURE__*/_jsx(_Fragment, {
233
+ children: linkText || href
234
+ });
235
+ }
174
236
  var mimeType = MIME_MAP[ext] || "";
175
237
  var fileItem = {
176
238
  displayName: linkText || href,
@@ -190,7 +252,7 @@ var MarkdownRender = function MarkdownRender(_ref) {
190
252
  rel: "noopener noreferrer",
191
253
  children: props.children
192
254
  });
193
- }, [onFileClick, onResourceLinkClick, renderResourceLink, styles.resourceLink]);
255
+ }, [onFileClick, onResourceLinkClick, renderResourceLink, resourceLinkSchemes, styles.resourceLink, bareUrlAsText]);
194
256
  return /*#__PURE__*/_jsx("div", {
195
257
  className: "".concat(styles.markdownWrapper).concat(compact ? " ".concat(styles.markdownWrapperCompact) : ""),
196
258
  children: /*#__PURE__*/_jsx("div", {
@@ -205,6 +267,7 @@ var MarkdownRender = function MarkdownRender(_ref) {
205
267
  components: {
206
268
  tag: ThinkComponent,
207
269
  "resource-link": ResourceLinkComponent,
270
+ "plain-mention": PlainMentionComponent,
208
271
  code: CodeComponent,
209
272
  a: LinkComponent
210
273
  },
@@ -1 +1 @@
1
- {"version":3,"names":["React","XMarkdown","CodeHighlighter","Flex","Latex","useStyles","BarsOutlined","BulbOutlined","ThunderboltOutlined","CheckCircleOutlined","FileGallery","parseMarkdownResourceHref","replaceMarkdownResourceLinks","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","FILE_EXT_REGEX","MIME_MAP","pdf","doc","docx","xls","xlsx","csv","ppt","pptx","zip","rar","txt","md","json","xml","mp3","wav","m4a","aac","ogg","flac","mp4","mov","webm","mkv","avi","png","jpg","jpeg","gif","webp","bmp","svg","extractExt","str","match","toLowerCase","escapeHtml","value","replace","escapeAttr","CodeComponent","props","_className$match","className","children","lang","ThinkComponent","memo","type","titleMap","planning","replanning","reasoning","action","final_answer","iconMap","align","gap","style","color","margin","extractText","String","Array","isArray","map","join","isValidElement","MarkdownRender","_ref","text","_ref$compact","compact","onFileClick","onResourceLinkClick","renderResourceLink","styles","markdown","link","concat","href","label","replaceAll","ResourceLinkComponent","useCallback","linkText","resourceLink","customNode","onClick","LinkComponent","ext","mimeType","fileItem","displayName","fileUri","file","undefined","target","rel","markdownWrapper","markdownWrapperCompact","markdownHost","markdownHostCompact","content","paragraphTag","config","extensions","components","tag","code","a","streaming","enableAnimation","animationConfig","fadeDuration"],"sources":["../../../../../../src/components/XAdkChatbot/components/MarkdownRender/index.tsx"],"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, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .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 中识别到的文件链接的回调 */\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"],"mappings":"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"}
1
+ {"version":3,"names":["React","XMarkdown","CodeHighlighter","Flex","Latex","useStyles","BarsOutlined","BulbOutlined","ThunderboltOutlined","CheckCircleOutlined","FileGallery","parseMarkdownResourceHref","getMarkdownResourceDisplayLabel","replaceMarkdownResourceLinks","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","FILE_EXT_REGEX","MIME_MAP","pdf","doc","docx","xls","xlsx","csv","ppt","pptx","zip","rar","txt","md","json","xml","mp3","wav","m4a","aac","ogg","flac","mp4","mov","webm","mkv","avi","png","jpg","jpeg","gif","webp","bmp","svg","extractExt","str","match","toLowerCase","escapeHtml","value","replace","escapeAttr","escapeMarkdownLabel","RESOURCE_LINK_SENTINEL","PLAIN_MENTION_SENTINEL","CodeComponent","props","_className$match","className","children","lang","ThinkComponent","memo","type","titleMap","planning","replanning","reasoning","action","final_answer","iconMap","align","gap","style","color","margin","extractText","String","Array","isArray","map","join","isValidElement","MarkdownRender","_ref","text","_ref$compact","compact","resourceLinkSchemes","onFileClick","onResourceLinkClick","renderResourceLink","_ref$bareUrlAsText","bareUrlAsText","_ref$highlightPlainMe","highlightPlainMentions","styles","displayText","_source","prefix","label","concat","encodeURIComponent","markdown","link","href","schemes","replaceAll","ResourceLinkComponent","useCallback","linkText","resourceLink","displayLabel","customNode","onClick","PlainMentionComponent","LinkComponent","resolvedHref","resolvedLabel","internalUrl","URL","origin","pathname","searchParams","get","_unused","ext","mimeType","fileItem","displayName","fileUri","file","undefined","target","rel","markdownWrapper","markdownWrapperCompact","markdownHost","markdownHostCompact","content","paragraphTag","config","extensions","components","tag","code","a","streaming","enableAnimation","animationConfig","fadeDuration"],"sources":["../../../../../../src/components/XAdkChatbot/components/MarkdownRender/index.tsx"],"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, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\nconst escapeAttr = (value: string) =>\n escapeHtml(value).replace(/\"/g, \"&quot;\").replace(/'/g, \"&#39;\");\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"],"mappings":"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"}
@@ -7,7 +7,7 @@ export var useStyles = withBasicStyles(function () {
7
7
  markdownWrapper: css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n display: grid;\n grid-template-columns: minmax(0, 1fr); /* \u5173\u952E\uFF1A\u5141\u8BB8\u5185\u5BB9\u6536\u7F29 */\n max-width: 100%; /* \u81EA\u5B9A\u4E49\u6700\u5927\u5BBD\u5EA6 */\n margin: 0 auto;\n "]))),
8
8
  markdownWrapperCompact: css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n display: inline;\n margin: 0;\n max-width: none;\n "]))),
9
9
  markdownHost: css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n container-type: inline-size;\n width: 100%;\n overflow: auto;\n\n /* ===== Markdown \u57FA\u7840\u6392\u7248 ===== */\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 \u6837\u5F0F ===== */\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 /* ===== \u56FE\u7247 ===== */\n\n img {\n max-width: 100%;\n border-radius: 6px;\n }\n "]))),
10
- markdownHostCompact: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\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 "]))),
10
+ markdownHostCompact: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\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 /* \u7528\u6237\u6D88\u606F\u91CC\u7684\u8D44\u6E90\u5F15\u7528\u91C7\u7528 Codex \u98CE\u683C\uFF1A\u84DD\u8272\u6587\u5B57\u9AD8\u4EAE\uFF0C\u4E0D\u989D\u5916\u5957\u6807\u7B7E\u5E95\u8272\u6216\u56FE\u6807\u3002 */\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 "]))),
11
11
  resourceLink: css(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\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 "])))
12
12
  };
13
13
  });
@@ -1 +1 @@
1
- {"version":3,"names":["css","withBasicStyles","useStyles","markdownWrapper","_templateObject","_taggedTemplateLiteral","markdownWrapperCompact","_templateObject2","markdownHost","_templateObject3","markdownHostCompact","_templateObject4","resourceLink","_templateObject5"],"sources":["../../../../../../src/components/XAdkChatbot/components/MarkdownRender/styles.tsx"],"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"],"mappings":";;AAAA,SAASA,GAAG,QAAQ,cAAc;AAClC,SAASC,eAAe;AAExB,OAAO,IAAMC,SAAS,GAAGD,eAAe,CAAC;EAAA,OAAO;IAC9CE,eAAe,EAAEH,GAAG,CAAAI,eAAA,KAAAA,eAAA,GAAAC,sBAAA,qOAKnB;IAEDC,sBAAsB,EAAEN,GAAG,CAAAO,gBAAA,KAAAA,gBAAA,GAAAF,sBAAA,wEAI1B;IAEDG,YAAY,EAAER,GAAG,CAAAS,gBAAA,KAAAA,gBAAA,GAAAJ,sBAAA,irCA6EhB;IAEDK,mBAAmB,EAAEV,GAAG,CAAAW,gBAAA,KAAAA,gBAAA,GAAAN,sBAAA,uMAYvB;IAEDO,YAAY,EAAEZ,GAAG,CAAAa,gBAAA,KAAAA,gBAAA,GAAAR,sBAAA;EAqBnB,CAAC;AAAA,CAAC,CAAC;AAEH,eAAeH,SAAS"}
1
+ {"version":3,"names":["css","withBasicStyles","useStyles","markdownWrapper","_templateObject","_taggedTemplateLiteral","markdownWrapperCompact","_templateObject2","markdownHost","_templateObject3","markdownHostCompact","_templateObject4","resourceLink","_templateObject5"],"sources":["../../../../../../src/components/XAdkChatbot/components/MarkdownRender/styles.tsx"],"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"],"mappings":";;AAAA,SAASA,GAAG,QAAQ,cAAc;AAClC,SAASC,eAAe;AAExB,OAAO,IAAMC,SAAS,GAAGD,eAAe,CAAC;EAAA,OAAO;IAC9CE,eAAe,EAAEH,GAAG,CAAAI,eAAA,KAAAA,eAAA,GAAAC,sBAAA,qOAKnB;IAEDC,sBAAsB,EAAEN,GAAG,CAAAO,gBAAA,KAAAA,gBAAA,GAAAF,sBAAA,wEAI1B;IAEDG,YAAY,EAAER,GAAG,CAAAS,gBAAA,KAAAA,gBAAA,GAAAJ,sBAAA,irCA6EhB;IAEDK,mBAAmB,EAAEV,GAAG,CAAAW,gBAAA,KAAAA,gBAAA,GAAAN,sBAAA,o1BAiCvB;IAEDO,YAAY,EAAEZ,GAAG,CAAAa,gBAAA,KAAAA,gBAAA,GAAAR,sBAAA;EAqBnB,CAAC;AAAA,CAAC,CAAC;AAEH,eAAeH,SAAS"}