@agentscope-ai/chat 1.1.39 → 1.1.41-beta.1764749089549

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 (233) hide show
  1. package/bin/starter_webui.zip +0 -0
  2. package/components/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Builder.tsx +8 -4
  3. package/components/ImageGenerator/index.tsx +1 -1
  4. package/components/Markdown/Markdown.tsx +105 -0
  5. package/components/Markdown/{Markdown/defaultComponents → core/components}/CodeBlock.tsx +1 -1
  6. package/components/Markdown/core/components/Null.tsx +1 -0
  7. package/components/Markdown/core/components/Raw.tsx +18 -0
  8. package/components/Markdown/{Markdown → core}/hooks/useCitationsData.tsx +3 -7
  9. package/components/Markdown/core/hooks/useCursorContent.tsx +15 -0
  10. package/components/Markdown/{Markdown/hooks/useTyping.ts → core/hooks/useTyping.tsx} +4 -1
  11. package/components/Markdown/core/index.tsx +18 -0
  12. package/components/Markdown/{plugins → core/plugins}/citations/CitationComponent.tsx +5 -3
  13. package/components/Markdown/{plugins → core/plugins}/citations/index.tsx +3 -4
  14. package/components/Markdown/{plugins → core/plugins}/cursor/Underline.tsx +1 -1
  15. package/components/Markdown/{plugins → core/plugins}/cursor/index.tsx +8 -8
  16. package/components/Markdown/demo/cursor.tsx +2 -3
  17. package/components/Markdown/index.en-US.md +1 -2
  18. package/components/Markdown/index.tsx +6 -0
  19. package/components/Markdown/index.zh-CN.md +1 -2
  20. package/components/Markdown/{Markdown/style.ts → styles.ts} +12 -21
  21. package/components/Markdown/types.tsx +94 -0
  22. package/components/index.ts +1 -3
  23. package/lib/AgentScopeRuntimeWebUI/core/AgentScopeRuntime/Response/Builder.js +5 -3
  24. package/lib/ImageGenerator/index.js +1 -1
  25. package/lib/Markdown/Markdown.d.ts +4 -0
  26. package/lib/Markdown/Markdown.js +110 -0
  27. package/lib/Markdown/core/components/Null.d.ts +2 -0
  28. package/lib/Markdown/core/components/Null.js +3 -0
  29. package/lib/Markdown/core/components/Raw.d.ts +8 -0
  30. package/lib/Markdown/core/components/Raw.js +13 -0
  31. package/lib/Markdown/core/hooks/useCitationsData.d.ts +6 -0
  32. package/lib/Markdown/{Markdown → core}/hooks/useCitationsData.js +1 -1
  33. package/lib/Markdown/core/hooks/useCursorContent.d.ts +4 -0
  34. package/lib/Markdown/core/hooks/useCursorContent.js +14 -0
  35. package/lib/Markdown/core/hooks/useTyping.d.ts +5 -0
  36. package/lib/Markdown/{Markdown → core}/hooks/useTyping.js +3 -2
  37. package/lib/Markdown/core/index.d.ts +2 -0
  38. package/lib/Markdown/{Markdown/hooks/useAnimation.js → core/index.js} +23 -23
  39. package/lib/Markdown/{plugins → core/plugins}/citations/CitationComponent.js +5 -5
  40. package/lib/Markdown/{plugins → core/plugins}/citations/index.d.ts +1 -2
  41. package/lib/Markdown/{plugins → core/plugins}/citations/index.js +1 -1
  42. package/lib/Markdown/{plugins → core/plugins}/cursor/Dot.js +1 -1
  43. package/lib/Markdown/{plugins → core/plugins}/cursor/Underline.js +1 -1
  44. package/lib/Markdown/{plugins → core/plugins}/cursor/index.js +4 -4
  45. package/lib/Markdown/index.d.ts +2 -1
  46. package/lib/Markdown/styles.js +32 -0
  47. package/lib/Markdown/types.d.ts +78 -0
  48. package/lib/index.d.ts +0 -2
  49. package/lib/index.js +0 -2
  50. package/package.json +7 -31
  51. package/components/AGUI/components/HelpModal/icons.tsx +0 -68
  52. package/components/AGUI/components/HelpModal/index.tsx +0 -1
  53. package/components/AGUI/components/HelpModal/modal.tsx +0 -101
  54. package/components/AGUI/components/chat/Button.tsx +0 -18
  55. package/components/AGUI/components/chat/Chat.tsx +0 -780
  56. package/components/AGUI/components/chat/ChatContext.tsx +0 -248
  57. package/components/AGUI/components/chat/CodeBlock.tsx +0 -406
  58. package/components/AGUI/components/chat/Header.tsx +0 -22
  59. package/components/AGUI/components/chat/Icons.tsx +0 -237
  60. package/components/AGUI/components/chat/ImageUploadQueue.tsx +0 -77
  61. package/components/AGUI/components/chat/Input.tsx +0 -24
  62. package/components/AGUI/components/chat/Markdown.tsx +0 -134
  63. package/components/AGUI/components/chat/Messages.tsx +0 -259
  64. package/components/AGUI/components/chat/Modal.tsx +0 -133
  65. package/components/AGUI/components/chat/Popup.tsx +0 -57
  66. package/components/AGUI/components/chat/PoweredByTag.tsx +0 -29
  67. package/components/AGUI/components/chat/Sidebar.tsx +0 -74
  68. package/components/AGUI/components/chat/Suggestion.tsx +0 -132
  69. package/components/AGUI/components/chat/Suggestions.tsx +0 -20
  70. package/components/AGUI/components/chat/Textarea.tsx +0 -61
  71. package/components/AGUI/components/chat/Window.tsx +0 -152
  72. package/components/AGUI/components/chat/index.tsx +0 -11
  73. package/components/AGUI/components/chat/messages/AssistantMessage.tsx +0 -69
  74. package/components/AGUI/components/chat/messages/RenderActionExecutionMessage.tsx +0 -129
  75. package/components/AGUI/components/chat/messages/RenderAgentStateMessage.tsx +0 -116
  76. package/components/AGUI/components/chat/messages/RenderImageMessage.tsx +0 -64
  77. package/components/AGUI/components/chat/messages/RenderResultMessage.tsx +0 -26
  78. package/components/AGUI/components/chat/messages/RenderTextMessage.tsx +0 -51
  79. package/components/AGUI/components/chat/messages/UserMessage.tsx +0 -10
  80. package/components/AGUI/components/chat/props.ts +0 -186
  81. package/components/AGUI/components/index.ts +0 -1
  82. package/components/AGUI/context/index.ts +0 -1
  83. package/components/AGUI/hooks/index.ts +0 -1
  84. package/components/AGUI/hooks/use-copilot-chat-suggestions.tsx +0 -122
  85. package/components/AGUI/hooks/use-copy-to-clipboard.tsx +0 -29
  86. package/components/AGUI/hooks/use-dark-mode.ts +0 -10
  87. package/components/AGUI/hooks/use-push-to-talk.tsx +0 -166
  88. package/components/AGUI/index.tsx +0 -4
  89. package/components/AGUI/lib/utils.test.ts +0 -7
  90. package/components/AGUI/lib/utils.ts +0 -27
  91. package/components/AGUI/styles.css +0 -0
  92. package/components/AGUI/types/css.ts +0 -0
  93. package/components/AGUI/types/index.ts +0 -1
  94. package/components/AGUI/types/suggestions.ts +0 -6
  95. package/components/Markdown/Markdown/AnimationNode.tsx +0 -89
  96. package/components/Markdown/Markdown/Markdown.tsx +0 -61
  97. package/components/Markdown/Markdown/core/Parser.ts +0 -52
  98. package/components/Markdown/Markdown/core/Renderer.ts +0 -121
  99. package/components/Markdown/Markdown/core/index.ts +0 -4
  100. package/components/Markdown/Markdown/hooks/index.ts +0 -4
  101. package/components/Markdown/Markdown/hooks/useAnimation.tsx +0 -27
  102. package/components/Markdown/Markdown/hooks/useStreaming.ts +0 -503
  103. package/components/Markdown/Markdown/index.tsx +0 -198
  104. package/components/Markdown/Markdown/interface.ts +0 -217
  105. package/components/Markdown/demo/typing.tsx +0 -82
  106. package/components/Markdown/index.ts +0 -1
  107. package/components/Markdown/plugins/latex/index.ts +0 -109
  108. package/components/Markdown/plugins/type.ts +0 -71
  109. package/lib/AGUI/components/HelpModal/icons.d.ts +0 -5
  110. package/lib/AGUI/components/HelpModal/icons.js +0 -84
  111. package/lib/AGUI/components/HelpModal/index.d.ts +0 -1
  112. package/lib/AGUI/components/HelpModal/index.js +0 -1
  113. package/lib/AGUI/components/HelpModal/modal.d.ts +0 -1
  114. package/lib/AGUI/components/HelpModal/modal.js +0 -104
  115. package/lib/AGUI/components/chat/Button.d.ts +0 -2
  116. package/lib/AGUI/components/chat/Button.js +0 -27
  117. package/lib/AGUI/components/chat/Chat.d.ts +0 -242
  118. package/lib/AGUI/components/chat/Chat.js +0 -634
  119. package/lib/AGUI/components/chat/ChatContext.d.ts +0 -142
  120. package/lib/AGUI/components/chat/ChatContext.js +0 -75
  121. package/lib/AGUI/components/chat/CodeBlock.d.ts +0 -12
  122. package/lib/AGUI/components/chat/CodeBlock.js +0 -398
  123. package/lib/AGUI/components/chat/Header.d.ts +0 -2
  124. package/lib/AGUI/components/chat/Header.js +0 -28
  125. package/lib/AGUI/components/chat/Icons.d.ts +0 -16
  126. package/lib/AGUI/components/chat/Icons.js +0 -247
  127. package/lib/AGUI/components/chat/ImageUploadQueue.d.ts +0 -11
  128. package/lib/AGUI/components/chat/ImageUploadQueue.js +0 -65
  129. package/lib/AGUI/components/chat/Input.d.ts +0 -2
  130. package/lib/AGUI/components/chat/Input.js +0 -30
  131. package/lib/AGUI/components/chat/Markdown.d.ts +0 -7
  132. package/lib/AGUI/components/chat/Markdown.js +0 -187
  133. package/lib/AGUI/components/chat/Messages.d.ts +0 -7
  134. package/lib/AGUI/components/chat/Messages.js +0 -242
  135. package/lib/AGUI/components/chat/Modal.d.ts +0 -43
  136. package/lib/AGUI/components/chat/Modal.js +0 -113
  137. package/lib/AGUI/components/chat/Popup.d.ts +0 -49
  138. package/lib/AGUI/components/chat/Popup.js +0 -64
  139. package/lib/AGUI/components/chat/PoweredByTag.d.ts +0 -3
  140. package/lib/AGUI/components/chat/PoweredByTag.js +0 -27
  141. package/lib/AGUI/components/chat/Sidebar.d.ts +0 -2
  142. package/lib/AGUI/components/chat/Sidebar.js +0 -85
  143. package/lib/AGUI/components/chat/Suggestion.d.ts +0 -16
  144. package/lib/AGUI/components/chat/Suggestion.js +0 -146
  145. package/lib/AGUI/components/chat/Suggestions.d.ts +0 -2
  146. package/lib/AGUI/components/chat/Suggestions.js +0 -21
  147. package/lib/AGUI/components/chat/Textarea.d.ts +0 -11
  148. package/lib/AGUI/components/chat/Textarea.js +0 -60
  149. package/lib/AGUI/components/chat/Window.d.ts +0 -2
  150. package/lib/AGUI/components/chat/Window.js +0 -115
  151. package/lib/AGUI/components/chat/index.d.ts +0 -11
  152. package/lib/AGUI/components/chat/index.js +0 -11
  153. package/lib/AGUI/components/chat/messages/AssistantMessage.d.ts +0 -2
  154. package/lib/AGUI/components/chat/messages/AssistantMessage.js +0 -56
  155. package/lib/AGUI/components/chat/messages/RenderActionExecutionMessage.d.ts +0 -2
  156. package/lib/AGUI/components/chat/messages/RenderActionExecutionMessage.js +0 -114
  157. package/lib/AGUI/components/chat/messages/RenderAgentStateMessage.d.ts +0 -2
  158. package/lib/AGUI/components/chat/messages/RenderAgentStateMessage.js +0 -97
  159. package/lib/AGUI/components/chat/messages/RenderImageMessage.d.ts +0 -2
  160. package/lib/AGUI/components/chat/messages/RenderImageMessage.js +0 -61
  161. package/lib/AGUI/components/chat/messages/RenderResultMessage.d.ts +0 -2
  162. package/lib/AGUI/components/chat/messages/RenderResultMessage.js +0 -27
  163. package/lib/AGUI/components/chat/messages/RenderTextMessage.d.ts +0 -2
  164. package/lib/AGUI/components/chat/messages/RenderTextMessage.js +0 -47
  165. package/lib/AGUI/components/chat/messages/UserMessage.d.ts +0 -2
  166. package/lib/AGUI/components/chat/messages/UserMessage.js +0 -9
  167. package/lib/AGUI/components/chat/props.d.ts +0 -157
  168. package/lib/AGUI/components/index.d.ts +0 -1
  169. package/lib/AGUI/components/index.js +0 -1
  170. package/lib/AGUI/context/index.d.ts +0 -1
  171. package/lib/AGUI/context/index.js +0 -1
  172. package/lib/AGUI/hooks/index.d.ts +0 -1
  173. package/lib/AGUI/hooks/index.js +0 -1
  174. package/lib/AGUI/hooks/use-copilot-chat-suggestions.d.ts +0 -87
  175. package/lib/AGUI/hooks/use-copilot-chat-suggestions.js +0 -95
  176. package/lib/AGUI/hooks/use-copy-to-clipboard.d.ts +0 -7
  177. package/lib/AGUI/hooks/use-copy-to-clipboard.js +0 -34
  178. package/lib/AGUI/hooks/use-dark-mode.d.ts +0 -1
  179. package/lib/AGUI/hooks/use-dark-mode.js +0 -4
  180. package/lib/AGUI/hooks/use-push-to-talk.d.ts +0 -16
  181. package/lib/AGUI/hooks/use-push-to-talk.js +0 -260
  182. package/lib/AGUI/index.d.ts +0 -4
  183. package/lib/AGUI/index.js +0 -4
  184. package/lib/AGUI/lib/utils.d.ts +0 -2
  185. package/lib/AGUI/lib/utils.js +0 -52
  186. package/lib/AGUI/styles.css +0 -0
  187. package/lib/AGUI/types/css.d.ts +0 -0
  188. package/lib/AGUI/types/css.js +0 -0
  189. package/lib/AGUI/types/index.d.ts +0 -1
  190. package/lib/AGUI/types/index.js +0 -1
  191. package/lib/AGUI/types/suggestions.d.ts +0 -6
  192. package/lib/AGUI/types/suggestions.js +0 -1
  193. package/lib/Markdown/Markdown/AnimationNode.d.ts +0 -20
  194. package/lib/Markdown/Markdown/AnimationNode.js +0 -84
  195. package/lib/Markdown/Markdown/Markdown.d.ts +0 -4
  196. package/lib/Markdown/Markdown/Markdown.js +0 -58
  197. package/lib/Markdown/Markdown/core/Parser.d.ts +0 -16
  198. package/lib/Markdown/Markdown/core/Parser.js +0 -65
  199. package/lib/Markdown/Markdown/core/Renderer.d.ts +0 -24
  200. package/lib/Markdown/Markdown/core/Renderer.js +0 -137
  201. package/lib/Markdown/Markdown/core/index.d.ts +0 -3
  202. package/lib/Markdown/Markdown/core/index.js +0 -3
  203. package/lib/Markdown/Markdown/hooks/index.d.ts +0 -3
  204. package/lib/Markdown/Markdown/hooks/index.js +0 -3
  205. package/lib/Markdown/Markdown/hooks/useAnimation.d.ts +0 -4
  206. package/lib/Markdown/Markdown/hooks/useCitationsData.d.ts +0 -7
  207. package/lib/Markdown/Markdown/hooks/useStreaming.d.ts +0 -3
  208. package/lib/Markdown/Markdown/hooks/useStreaming.js +0 -521
  209. package/lib/Markdown/Markdown/hooks/useTyping.d.ts +0 -4
  210. package/lib/Markdown/Markdown/index.d.ts +0 -84
  211. package/lib/Markdown/Markdown/index.js +0 -161
  212. package/lib/Markdown/Markdown/interface.d.ts +0 -203
  213. package/lib/Markdown/Markdown/interface.js +0 -1
  214. package/lib/Markdown/Markdown/style.js +0 -32
  215. package/lib/Markdown/plugins/latex/index.d.ts +0 -9
  216. package/lib/Markdown/plugins/latex/index.js +0 -97
  217. package/lib/Markdown/plugins/type.d.ts +0 -60
  218. package/lib/Markdown/plugins/type.js +0 -1
  219. /package/components/Markdown/{Markdown/defaultComponents/DisabledImage.tsx → core/components/DisableImage.tsx} +0 -0
  220. /package/components/Markdown/{Markdown/defaultComponents → core/components}/Media.tsx +0 -0
  221. /package/components/Markdown/{plugins → core/plugins}/cursor/Dot.tsx +0 -0
  222. /package/lib/Markdown/{Markdown/defaultComponents → core/components}/CodeBlock.d.ts +0 -0
  223. /package/lib/Markdown/{Markdown/defaultComponents → core/components}/CodeBlock.js +0 -0
  224. /package/lib/Markdown/{Markdown/defaultComponents/DisabledImage.d.ts → core/components/DisableImage.d.ts} +0 -0
  225. /package/lib/Markdown/{Markdown/defaultComponents/DisabledImage.js → core/components/DisableImage.js} +0 -0
  226. /package/lib/Markdown/{Markdown/defaultComponents → core/components}/Media.d.ts +0 -0
  227. /package/lib/Markdown/{Markdown/defaultComponents → core/components}/Media.js +0 -0
  228. /package/lib/Markdown/{plugins → core/plugins}/citations/CitationComponent.d.ts +0 -0
  229. /package/lib/Markdown/{plugins → core/plugins}/cursor/Dot.d.ts +0 -0
  230. /package/lib/Markdown/{plugins → core/plugins}/cursor/Underline.d.ts +0 -0
  231. /package/lib/Markdown/{plugins → core/plugins}/cursor/index.d.ts +0 -0
  232. /package/lib/Markdown/{Markdown/style.d.ts → styles.d.ts} +0 -0
  233. /package/lib/{AGUI/components/chat/props.js → Markdown/types.js} +0 -0
@@ -1,503 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
- import { MarkdownProps } from '../interface';
3
-
4
- enum TokenType {
5
- Text = 0,
6
- Link = 1,
7
- Image = 2,
8
- Heading = 3,
9
- MaybeEmphasis = 4,
10
- Emphasis = 5,
11
- Strong = 6,
12
- XML = 7,
13
- MaybeCode = 8,
14
- Code = 9,
15
- MaybeHr = 10,
16
- MaybeList = 11,
17
- MaybeInlineMath = 12,
18
- InlineMath = 13,
19
- MaybeBlockMath = 14,
20
- BlockMath = 15,
21
- MaybeBackslashMath = 16,
22
- Word = 17,
23
- }
24
-
25
- const Markdown_Symbols = {
26
- emphasis: ['*', '_'],
27
- code: ['`'],
28
- list: ['-', '+', '*'],
29
- };
30
-
31
- // 辅助函数:判断是否是英文字母
32
- const isEnglishLetter = (char: string): boolean => {
33
- const code = char.charCodeAt(0);
34
- return (code >= 65 && code <= 90) || (code >= 97 && code <= 122); // A-Z or a-z
35
- };
36
-
37
- // 辅助函数:判断是否是单词的一部分(字母、数字、连字符、撇号)
38
- const isWordChar = (char: string): boolean => {
39
- const code = char.charCodeAt(0);
40
- return (
41
- (code >= 65 && code <= 90) || // A-Z
42
- (code >= 97 && code <= 122) || // a-z
43
- (code >= 48 && code <= 57) || // 0-9
44
- char === '-' || // 连字符 (well-known)
45
- char === "'" // 撇号 (don't)
46
- );
47
- };
48
-
49
- // 辅助函数:判断是否是单词分隔符
50
- const isWordSeparator = (char: string): boolean => {
51
- return (
52
- char === ' ' ||
53
- char === '\n' ||
54
- char === '\t' ||
55
- char === ',' ||
56
- char === '.' ||
57
- char === '!' ||
58
- char === '?' ||
59
- char === ';' ||
60
- char === ':' ||
61
- char === ')' ||
62
- char === ']' ||
63
- char === '}' ||
64
- char === '"' ||
65
- char === "'" ||
66
- char === '>' ||
67
- char === '<'
68
- );
69
- };
70
-
71
- const STREAM_BUFFER_INIT = {
72
- processedLength: 0,
73
- rawStream: '',
74
- pending: '',
75
- token: TokenType.Text,
76
- tokens: [TokenType.Text],
77
- headingLevel: 0,
78
- emphasisCount: 0,
79
- backtickCount: 0,
80
- dollarCount: 0,
81
- mathDelimiter: '' as '$' | '$$' | '\\(' | '\\[' | '',
82
- blockMathEnding: false, // 标记是否遇到了结束的 $$
83
- };
84
-
85
- const useStreaming = (input: string, config?: MarkdownProps['streaming'], cursor?: MarkdownProps['cursor']) => {
86
- const { hasNextChunk = false, enableWordCaching = false, enableMathCaching = true } = config || {};
87
-
88
- const [output, setOutput] = useState('');
89
- const streamBuffer = useRef({ ...STREAM_BUFFER_INIT });
90
-
91
- const pushToken = useCallback((type: TokenType) => {
92
- streamBuffer.current.tokens = [...streamBuffer.current.tokens, type];
93
- streamBuffer.current.token = type;
94
- }, []);
95
-
96
- const popToken = useCallback(() => {
97
- const { tokens } = streamBuffer.current;
98
- if (tokens.length <= 1) return;
99
-
100
- const newTokens = [...tokens.slice(0, -1)];
101
- streamBuffer.current.tokens = newTokens;
102
- streamBuffer.current.token = newTokens[newTokens.length - 1];
103
- }, []);
104
-
105
- const flushOutput = (needPopToken = true) => {
106
- if (needPopToken) popToken();
107
-
108
- streamBuffer.current.pending = '';
109
- streamBuffer.current.blockMathEnding = false;
110
- const renderText = streamBuffer.current.rawStream;
111
- if (renderText) {
112
- setOutput(renderText);
113
- }
114
- };
115
-
116
- const handleChunk = (chunk: string) => {
117
- const buffer = streamBuffer.current;
118
- for (const char of chunk) {
119
- buffer.rawStream += char;
120
- buffer.pending += char;
121
-
122
- const { token, pending, tokens, emphasisCount } = buffer;
123
- switch (token) {
124
- case TokenType.Image: {
125
- /**
126
- * \![
127
- * ^
128
- */
129
- const isInvalidStart = pending.indexOf('![') === -1;
130
- /**
131
- * \![image]()
132
- * ^
133
- */
134
- const isImageEnd = char === ')' || char === '\n';
135
- if (isInvalidStart || isImageEnd) {
136
- if (tokens[tokens.length - 2] === TokenType.Link) {
137
- popToken();
138
- } else {
139
- flushOutput();
140
- }
141
- }
142
- break;
143
- }
144
- case TokenType.Link: {
145
- // not support link reference definitions, [foo]: /url "title" \n[foo]
146
- const isReferenceLink = pending.endsWith(']:');
147
- const isLinkEnd = char === ')' || char === '\n';
148
- const isImageInLink = char === '!';
149
- if (isImageInLink) {
150
- pushToken(TokenType.Image);
151
- } else if (isLinkEnd || isReferenceLink) {
152
- flushOutput();
153
- }
154
- break;
155
- }
156
- case TokenType.Heading: {
157
- /**
158
- * # token / ## token / #####token
159
- * ^ ^ ^
160
- */
161
- buffer.headingLevel++;
162
-
163
- const shouldFlushOutput = char !== '#' || buffer.headingLevel >= 6;
164
- if (shouldFlushOutput) {
165
- flushOutput();
166
- buffer.headingLevel = 0;
167
- }
168
- break;
169
- }
170
- case TokenType.MaybeEmphasis: {
171
- /**
172
- * /* / *\/n
173
- ^ ^
174
- */
175
- const shouldFlushOutput = char === ' ' || char === '\n';
176
- if (shouldFlushOutput) {
177
- flushOutput();
178
- } else if (Markdown_Symbols.emphasis.includes(char)) {
179
- buffer.emphasisCount++;
180
- } else {
181
- popToken();
182
- if (emphasisCount === 1) {
183
- /**
184
- * _token_ / *token*
185
- * ^ ^
186
- */
187
- pushToken(TokenType.Emphasis);
188
- } else if (emphasisCount === 2) {
189
- /**
190
- * __token__ / **token**
191
- * ^ ^
192
- */
193
- pushToken(TokenType.Strong);
194
- } else if (emphasisCount === 3) {
195
- /**
196
- * ___token___ / ***token***
197
- * ^ ^
198
- */
199
- pushToken(TokenType.Emphasis);
200
- pushToken(TokenType.Strong);
201
- } else {
202
- // no more than 3
203
- buffer.emphasisCount = 0;
204
- }
205
- }
206
-
207
- break;
208
- }
209
- case TokenType.Strong: {
210
- /**
211
- * __token__ / **token**
212
- * ^ ^
213
- */
214
- if (char === '\n') {
215
- flushOutput();
216
- } else if (pending.endsWith('**') || pending.endsWith('__')) {
217
- if (tokens[tokens.length - 2] === TokenType.Emphasis) {
218
- popToken();
219
- } else {
220
- flushOutput();
221
- }
222
- }
223
-
224
- break;
225
- }
226
- case TokenType.Emphasis: {
227
- /**
228
- * _token_ / *token*
229
- * ^ ^
230
- */
231
- if (char === '\n') {
232
- flushOutput();
233
- buffer.emphasisCount = 0;
234
- } else if (Markdown_Symbols.emphasis.includes(char)) {
235
- flushOutput();
236
- buffer.emphasisCount = 0;
237
- }
238
-
239
- break;
240
- }
241
- case TokenType.XML: {
242
- /**
243
- * <XML /> /<XML></XML>
244
- * ^ ^
245
- */
246
- const shouldFlushOutput = char === '>' || pending === '< ' || char === '\n';
247
- if (shouldFlushOutput) {
248
- flushOutput();
249
- continue;
250
- }
251
- break;
252
- }
253
- case TokenType.MaybeCode: {
254
- if (char === '`') {
255
- buffer.backtickCount++;
256
- } else {
257
- if (buffer.backtickCount > 2) {
258
- /**
259
- * ```
260
- * ^
261
- */
262
- flushOutput();
263
- buffer.backtickCount = 0;
264
- } else {
265
- /**
266
- * ``
267
- * ^
268
- */
269
- popToken();
270
- pushToken(TokenType.Code);
271
- }
272
- }
273
- break;
274
- }
275
- case TokenType.Code: {
276
- if (char === '`') {
277
- buffer.backtickCount--;
278
- }
279
-
280
- if (buffer.backtickCount === 0) {
281
- flushOutput();
282
- buffer.backtickCount = 0;
283
- }
284
- break;
285
- }
286
- case TokenType.MaybeHr: {
287
- if (char !== '-' && char !== '=') {
288
- flushOutput();
289
- }
290
- break;
291
- }
292
- case TokenType.MaybeList: {
293
- if (char !== ' ') {
294
- flushOutput();
295
- }
296
- break;
297
- }
298
- case TokenType.MaybeInlineMath: {
299
- /**
300
- * $ / $$
301
- * ^ ^
302
- */
303
- if (char === '$') {
304
- buffer.dollarCount++;
305
- if (buffer.dollarCount === 2) {
306
- // $$ 块级公式
307
- popToken();
308
- pushToken(TokenType.MaybeBlockMath);
309
- buffer.mathDelimiter = '$$';
310
- }
311
- } else if (char === '\n') {
312
- // $ 后跟换行,不是有效的公式
313
- flushOutput();
314
- buffer.dollarCount = 0;
315
- buffer.mathDelimiter = '';
316
- } else {
317
- // 确认为行内公式
318
- popToken();
319
- pushToken(TokenType.InlineMath);
320
- buffer.mathDelimiter = '$';
321
- }
322
- break;
323
- }
324
- case TokenType.InlineMath: {
325
- /**
326
- * $x^2$ / \(x^2\)
327
- * ^ ^
328
- */
329
- if (buffer.mathDelimiter === '$') {
330
- if (char === '$') {
331
- flushOutput();
332
- buffer.dollarCount = 0;
333
- buffer.mathDelimiter = '';
334
- } else if (char === '\n') {
335
- // 行内公式不应跨行
336
- flushOutput();
337
- buffer.dollarCount = 0;
338
- buffer.mathDelimiter = '';
339
- }
340
- } else if (buffer.mathDelimiter === '\\(') {
341
- if (pending.endsWith('\\)')) {
342
- flushOutput();
343
- buffer.mathDelimiter = '';
344
- }
345
- }
346
- break;
347
- }
348
- case TokenType.MaybeBlockMath: {
349
- /**
350
- * $$
351
- * ^
352
- */
353
- if (char !== '$') {
354
- // $$ 后跟任何非 $ 字符,确认为块级公式
355
- popToken();
356
- pushToken(TokenType.BlockMath);
357
- }
358
- break;
359
- }
360
- case TokenType.BlockMath: {
361
- /**
362
- * $$E=mc^2$$
363
- * ^^
364
- */
365
- // 处理 $$ 块级公式
366
- if (buffer.mathDelimiter === '$$') {
367
- // 检测是否遇到结束的 $$
368
- if (char === '$') {
369
- buffer.dollarCount++;
370
- if (buffer.dollarCount === 2) {
371
- // 遇到了结束 $$,立即释放缓存
372
- flushOutput();
373
- buffer.dollarCount = 0;
374
- buffer.mathDelimiter = '';
375
- }
376
- } else {
377
- buffer.dollarCount = 0;
378
- }
379
- } else if (buffer.mathDelimiter === '\\[') {
380
- // 处理 \[...\] 块级公式
381
- if (pending.endsWith('\\]')) {
382
- flushOutput();
383
- buffer.mathDelimiter = '';
384
- }
385
- }
386
- break;
387
- }
388
- case TokenType.MaybeBackslashMath: {
389
- /**
390
- * \( / \[
391
- * ^ ^
392
- */
393
- if (char === '(') {
394
- // \( 行内公式
395
- popToken();
396
- pushToken(TokenType.InlineMath);
397
- buffer.mathDelimiter = '\\(';
398
- } else if (char === '[') {
399
- // \[ 块级公式
400
- popToken();
401
- pushToken(TokenType.BlockMath);
402
- buffer.mathDelimiter = '\\[';
403
- } else {
404
- // 不是数学公式,普通反斜杠
405
- flushOutput();
406
- buffer.mathDelimiter = '';
407
- }
408
- break;
409
- }
410
- case TokenType.Word: {
411
- /**
412
- * Hello world
413
- * ^
414
- * 缓存英文单词,直到遇到分隔符(空格、标点等)
415
- */
416
- if (isWordSeparator(char)) {
417
- // 遇到分隔符,释放缓存显示完整单词
418
- flushOutput();
419
- } else if (!isWordChar(char)) {
420
- // 遇到非单词字符且非分隔符(如 Markdown 符号),也释放缓存
421
- flushOutput();
422
- }
423
- // 否则继续缓存单词字符
424
- break;
425
- }
426
- default: {
427
- buffer.pending = char;
428
-
429
- if (char === '!') {
430
- pushToken(TokenType.Image);
431
- } else if (char === '[') {
432
- pushToken(TokenType.Link);
433
- } else if (char === '#') {
434
- pushToken(TokenType.Heading);
435
- } else if (char === '_' || char === '*') {
436
- pushToken(TokenType.MaybeEmphasis);
437
- buffer.emphasisCount = 1;
438
- } else if (char === '<') {
439
- pushToken(TokenType.XML);
440
- } else if (char === '`') {
441
- pushToken(TokenType.MaybeCode);
442
- buffer.backtickCount = 1;
443
- } else if (char === '-' || char === '=') {
444
- pushToken(TokenType.MaybeHr);
445
- } else if (Markdown_Symbols.list.includes(char)) {
446
- pushToken(TokenType.MaybeList);
447
- } else if (enableMathCaching && char === '$') {
448
- // 只有启用公式缓存时,才缓存 $ 符号的公式
449
- pushToken(TokenType.MaybeInlineMath);
450
- buffer.dollarCount = 1;
451
- buffer.mathDelimiter = '';
452
- } else if (enableMathCaching && char === '\\') {
453
- // 只有启用公式缓存时,才缓存 \ 开头的公式
454
- pushToken(TokenType.MaybeBackslashMath);
455
- } else if (enableWordCaching && isEnglishLetter(char)) {
456
- // 只有启用单词缓存时,才缓存英文单词
457
- pushToken(TokenType.Word);
458
- } else {
459
- flushOutput(false);
460
- }
461
- }
462
- }
463
- }
464
- };
465
-
466
- const cursorContent = useMemo(() => {
467
- if (config?.enableAnimation) return '';
468
- if (cursor) {
469
- if (cursor === 'dot') return ' :dot:';
470
- if (cursor === 'underline') return ' :underline:';
471
- return ' :dot:';
472
- }
473
- return '';
474
- }, [cursor]);
475
-
476
- useEffect(() => {
477
- if (!input) {
478
- setOutput('');
479
- streamBuffer.current = { ...STREAM_BUFFER_INIT };
480
- return;
481
- }
482
-
483
- if (typeof input !== 'string') {
484
- console.error(`X-Markdown: input must be string, not ${typeof input}.`);
485
- return;
486
- }
487
-
488
- if (!hasNextChunk) {
489
- setOutput(input);
490
- return;
491
- }
492
-
493
- const chunk = input.slice(streamBuffer.current.processedLength);
494
- if (chunk.length) {
495
- streamBuffer.current.processedLength += chunk.length;
496
- handleChunk(chunk);
497
- }
498
- }, [input, hasNextChunk]);
499
-
500
- return output + cursorContent;
501
- };
502
-
503
- export default useStreaming;
@@ -1,198 +0,0 @@
1
- import Markdown from './Markdown';
2
- import CodeBlock from './defaultComponents/CodeBlock';
3
- import Media from './defaultComponents/Media';
4
- import DisabledImage from './defaultComponents/DisabledImage';
5
- import { useGlobalContext, useProviderContext } from '@agentscope-ai/chat';
6
- import { useTyping } from './hooks/useTyping';
7
- import type { MarkdownProps as InnerMarkdownProps } from './interface';
8
- import { cursorExtension, CursorComponent } from '../plugins/cursor';
9
- import { citationsExtension } from '../plugins/citations';
10
- import latex from '../plugins/latex';
11
- import useCitationsData from './hooks/useCitationsData';
12
- import classnames from 'classnames';
13
- import { ErrorBoundary } from "react-error-boundary";
14
- import { memo, useMemo } from 'react';
15
-
16
- export interface MarkdownProps {
17
- /**
18
- * @description 需要渲染的 Markdown 内容
19
- * @descriptionEn Markdown content to be rendered
20
- */
21
- content?: InnerMarkdownProps['content'];
22
- /**
23
- * @description 光标样式类型,支持点状、下划线或布尔值控制
24
- * @descriptionEn Cursor style type, supports dot, underline, or boolean control
25
- */
26
- cursor?: boolean | 'dot' | 'underline';
27
- /**
28
- * @description 基础字体大小,影响整个Markdown内容的字体大小
29
- * @descriptionEn Base font size that affects the font size of the entire Markdown content
30
- */
31
- baseFontSize?: InnerMarkdownProps['baseFontSize'];
32
- /**
33
- * @description 基础行高,影响文本的行间距
34
- * @descriptionEn Base line height that affects text line spacing
35
- */
36
- baseLineHeight?: InnerMarkdownProps['baseLineHeight'];
37
- /**
38
- * @description 引用数据数组,用于显示引用信息
39
- * @descriptionEn Citation data array for displaying reference information
40
- */
41
- citations?: InnerMarkdownProps['citations'];
42
- /**
43
- * @description 引用映射对象,用于快速查找引用信息
44
- * @descriptionEn Citation mapping object for quick lookup of reference information
45
- */
46
- citationsMap?: InnerMarkdownProps['citationsMap'];
47
- /**
48
- * @description 用于替换 HTML 元素的自定义 React 组件映射,组件会接收 domNode、streamStatus 等属性
49
- * @descriptionEn Custom React components to replace HTML elements, components receive domNode, streamStatus, etc.
50
- */
51
- components?: InnerMarkdownProps['components'];
52
- /**
53
- * @description 是否允许渲染HTML标签,影响安全性
54
- * @descriptionEn Whether to allow rendering HTML tags, affects security
55
- */
56
- allowHtml?: boolean;
57
- /**
58
- * @description 是否禁用图片渲染
59
- * @descriptionEn Whether to disable image rendering
60
- */
61
- disableImage?: boolean;
62
- /**
63
- * @description 是否启用打字机效果,逐字显示内容
64
- * @descriptionEn Whether to enable typewriter effect for character-by-character display
65
- */
66
- typing?: boolean | number;
67
- /**
68
- * @description 是否以原始文本形式显示,跳过Markdown解析
69
- * @descriptionEn Whether to display as raw text, skipping Markdown parsing
70
- */
71
- raw?: boolean;
72
- /**
73
- * @description 组件的CSS类名
74
- * @descriptionEn CSS class name for the component
75
- */
76
- className?: string;
77
- /**
78
- * @description 启用英文单词缓存,单词会在遇到空格或标点后才整体显示(仅在 typing 为 true 时生效)
79
- * @descriptionEn Enable English word caching, words will be displayed as a whole after encountering spaces or punctuation (only works when typing is true)
80
- * @default false
81
- */
82
- enableWordCaching?: boolean;
83
- /**
84
- * @description 启用 LaTeX 公式缓存,公式会在完整后才整体显示(仅在 typing 为 true 时生效)
85
- * @descriptionEn Enable LaTeX formula caching, formulas will be displayed as a whole when complete (only works when typing is true)
86
- * @default true
87
- */
88
- enableMathCaching?: boolean;
89
- /**
90
- * @description 启用文字出现动画效果
91
- * @descriptionEn Enable text appearance animation effects
92
- * @default false
93
- */
94
- enableAnimation?: boolean;
95
- }
96
-
97
- const Null = () => null;
98
-
99
- // 缓存不变的 dompurify 配置
100
- const EMPTY_DOMPURIFY_CONFIG = {
101
- ALLOWED_TAGS: [],
102
- };
103
-
104
-
105
- /**
106
- * 检测浏览器是否支持正则表达式的 lookbehind assertions
107
- * iOS Safari < 16.4 不支持此特性
108
- */
109
- function supportsLookbehindAssertions(): boolean {
110
- try {
111
- // 尝试创建包含正向后行断言的正则表达式
112
- new RegExp('(?<=a)b');
113
- return true;
114
- } catch (e) {
115
- return false;
116
- }
117
- }
118
-
119
- const isSupportsLookbehindAssertions = supportsLookbehindAssertions();
120
-
121
- console.log({ isSupportsLookbehindAssertions });
122
-
123
- export default memo(function (props: MarkdownProps) {
124
- const baseFontSize = props.baseFontSize || 14;
125
- const baseLineHeight = props.baseLineHeight || 1.7;
126
- const { getPrefixCls, } = useProviderContext();
127
- const prefixCls = getPrefixCls('markdown');
128
- const {
129
- className,
130
- allowHtml = true,
131
- content: _content = '',
132
- typing = false,
133
- cursor = false,
134
- enableWordCaching = false,
135
- enableMathCaching = true,
136
- enableAnimation = false,
137
- ...restProps
138
- } = props;
139
- const content = useTyping({ content: _content, typing });
140
- const { citationsData, citationsDataCount, CitationComponent } = useCitationsData({ citations: props.citations, citationsMap: props.citationsMap });
141
-
142
-
143
- if (props.raw || !isSupportsLookbehindAssertions) return <div className={prefixCls} style={{ fontSize: baseFontSize, lineHeight: baseLineHeight }}>{content}</div>;
144
-
145
- // 使用 useMemo 缓存 extensions 配置
146
- const extensions = useMemo(() => {
147
- const exts = [
148
- cursorExtension(),
149
- ...latex()
150
- ];
151
- if (citationsDataCount > 0) exts.push(citationsExtension(citationsData));
152
- return exts;
153
- }, [citationsDataCount, citationsData]);
154
-
155
- // 使用 useMemo 缓存 config 对象
156
- const config = useMemo(() => ({
157
- extensions,
158
- }), [extensions]);
159
-
160
- // 使用 useMemo 缓存 streaming 配置
161
- const streaming = useMemo(() => ({
162
- hasNextChunk: Boolean(typing),
163
- enableWordCaching,
164
- enableMathCaching,
165
- enableAnimation
166
- }), [typing, enableWordCaching, enableMathCaching, enableAnimation]);
167
-
168
- // 使用 useMemo 缓存 components 对象
169
- const components = useMemo(() => ({
170
- // @ts-ignore
171
- pre: CodeBlock,
172
- style: Null,
173
- script: Null,
174
- img: props.disableImage ? DisabledImage : Media,
175
- cursor: CursorComponent,
176
- // @ts-ignore
177
- citation: CitationComponent,
178
- }), [props.disableImage, CitationComponent]);
179
-
180
- // 使用 useMemo 缓存 dompurifyConfig
181
- const dompurifyConfig = useMemo(() =>
182
- allowHtml ? undefined : EMPTY_DOMPURIFY_CONFIG
183
- , [allowHtml]);
184
-
185
- return <ErrorBoundary fallback={<div className={prefixCls} style={{ fontSize: baseFontSize, lineHeight: baseLineHeight }}>{content}</div>}>
186
- <Markdown
187
- baseFontSize={baseFontSize}
188
- baseLineHeight={baseLineHeight}
189
- dompurifyConfig={dompurifyConfig}
190
- streaming={streaming}
191
- cursor={cursor}
192
- className={classnames(prefixCls, className)}
193
- components={components as unknown as InnerMarkdownProps['components']}
194
- content={content}
195
- config={config}
196
- {...restProps}
197
- /></ErrorBoundary>
198
- });