@hkyhy/marsun-components-core 0.1.12 → 0.1.15

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 (149) hide show
  1. package/README.md +31 -6
  2. package/dist/components/AgentHub/Chat/Action/CreateButton.js +8 -0
  3. package/dist/components/AgentHub/Chat/Action/CreateButton.js.map +1 -0
  4. package/dist/components/AgentHub/Chat/Action/ManageActionButtons.js +20 -0
  5. package/dist/components/AgentHub/Chat/Action/ManageActionButtons.js.map +1 -0
  6. package/dist/components/AgentHub/Chat/Action/SessionActionButtons.js +24 -0
  7. package/dist/components/AgentHub/Chat/Action/SessionActionButtons.js.map +1 -0
  8. package/dist/components/AgentHub/Chat/Action/handlers.d.ts +0 -5
  9. package/dist/components/AgentHub/Chat/Detail/ChatInput/index.js +65 -0
  10. package/dist/components/AgentHub/Chat/Detail/ChatInput/index.js.map +1 -0
  11. package/dist/components/AgentHub/Chat/Detail/ChatInput/style.module.scss.js +12 -0
  12. package/dist/components/AgentHub/Chat/Detail/ChatInput/style.module.scss.js.map +1 -0
  13. package/dist/components/AgentHub/Chat/Detail/ChatPanel/index.d.ts +31 -0
  14. package/dist/components/AgentHub/Chat/Detail/ChatPanel/index.js +85 -0
  15. package/dist/components/AgentHub/Chat/Detail/ChatPanel/index.js.map +1 -0
  16. package/dist/components/AgentHub/Chat/Detail/ChatPanel/style.module.scss.js +14 -0
  17. package/dist/components/AgentHub/Chat/Detail/ChatPanel/style.module.scss.js.map +1 -0
  18. package/dist/components/AgentHub/Chat/Detail/ChatSuggestionRow/index.d.ts +9 -0
  19. package/dist/components/AgentHub/Chat/Detail/ChatSuggestionRow/index.js +22 -0
  20. package/dist/components/AgentHub/Chat/Detail/ChatSuggestionRow/index.js.map +1 -0
  21. package/dist/components/AgentHub/Chat/Detail/ChatSuggestionRow/style.module.scss.js +8 -0
  22. package/dist/components/AgentHub/Chat/Detail/ChatSuggestionRow/style.module.scss.js.map +1 -0
  23. package/dist/components/AgentHub/Chat/Detail/CitationContent/index.js +21 -0
  24. package/dist/components/AgentHub/Chat/Detail/CitationContent/index.js.map +1 -0
  25. package/dist/components/AgentHub/Chat/Detail/CitationContent/style.module.scss.js +8 -0
  26. package/dist/components/AgentHub/Chat/Detail/CitationContent/style.module.scss.js.map +1 -0
  27. package/dist/components/AgentHub/Chat/Detail/CitationInlineBadge/index.js +17 -0
  28. package/dist/components/AgentHub/Chat/Detail/CitationInlineBadge/index.js.map +1 -0
  29. package/dist/components/AgentHub/Chat/Detail/CitationInlineBadge/style.module.scss.js +7 -0
  30. package/dist/components/AgentHub/Chat/Detail/CitationInlineBadge/style.module.scss.js.map +1 -0
  31. package/dist/components/AgentHub/Chat/Detail/CitationMarkdownContent/index.js +68 -0
  32. package/dist/components/AgentHub/Chat/Detail/CitationMarkdownContent/index.js.map +1 -0
  33. package/dist/components/AgentHub/Chat/Detail/CitationMarkdownContent/style.module.scss.js +7 -0
  34. package/dist/components/AgentHub/Chat/Detail/CitationMarkdownContent/style.module.scss.js.map +1 -0
  35. package/dist/components/AgentHub/Chat/Detail/CitationPanel/index.js +247 -0
  36. package/dist/components/AgentHub/Chat/Detail/CitationPanel/index.js.map +1 -0
  37. package/dist/components/AgentHub/Chat/Detail/CitationPanel/style.module.scss.js +31 -0
  38. package/dist/components/AgentHub/Chat/Detail/CitationPanel/style.module.scss.js.map +1 -0
  39. package/dist/components/AgentHub/Chat/Detail/MermaidBlock/index.js +43 -0
  40. package/dist/components/AgentHub/Chat/Detail/MermaidBlock/index.js.map +1 -0
  41. package/dist/components/AgentHub/Chat/Detail/MermaidBlock/style.module.scss.js +8 -0
  42. package/dist/components/AgentHub/Chat/Detail/MermaidBlock/style.module.scss.js.map +1 -0
  43. package/dist/components/AgentHub/Chat/Detail/MessageActions/index.js +103 -0
  44. package/dist/components/AgentHub/Chat/Detail/MessageActions/index.js.map +1 -0
  45. package/dist/components/AgentHub/Chat/Detail/MessageActions/style.module.scss.js +14 -0
  46. package/dist/components/AgentHub/Chat/Detail/MessageActions/style.module.scss.js.map +1 -0
  47. package/dist/components/AgentHub/Chat/Detail/MessageEditPopover/index.js +58 -0
  48. package/dist/components/AgentHub/Chat/Detail/MessageEditPopover/index.js.map +1 -0
  49. package/dist/components/AgentHub/Chat/Detail/MessageEditPopover/style.module.scss.js +9 -0
  50. package/dist/components/AgentHub/Chat/Detail/MessageEditPopover/style.module.scss.js.map +1 -0
  51. package/dist/components/AgentHub/Chat/Detail/MessageItem/index.js +309 -0
  52. package/dist/components/AgentHub/Chat/Detail/MessageItem/index.js.map +1 -0
  53. package/dist/components/AgentHub/Chat/Detail/MessageItem/style.module.scss.js +24 -0
  54. package/dist/components/AgentHub/Chat/Detail/MessageItem/style.module.scss.js.map +1 -0
  55. package/dist/components/AgentHub/Chat/Detail/ThinkingSection/index.js +122 -0
  56. package/dist/components/AgentHub/Chat/Detail/ThinkingSection/index.js.map +1 -0
  57. package/dist/components/AgentHub/Chat/Detail/ThinkingSection/style.module.scss.js +25 -0
  58. package/dist/components/AgentHub/Chat/Detail/ThinkingSection/style.module.scss.js.map +1 -0
  59. package/dist/components/AgentHub/Chat/Detail/index.d.ts +12 -0
  60. package/dist/components/AgentHub/Chat/Form/Form.js +37 -0
  61. package/dist/components/AgentHub/Chat/Form/Form.js.map +1 -0
  62. package/dist/components/AgentHub/Chat/List/ChatCard/index.js +86 -0
  63. package/dist/components/AgentHub/Chat/List/ChatCard/index.js.map +1 -0
  64. package/dist/components/AgentHub/Chat/List/ChatCard/style.module.scss.js +25 -0
  65. package/dist/components/AgentHub/Chat/List/ChatCard/style.module.scss.js.map +1 -0
  66. package/dist/components/AgentHub/Chat/List/FilterBar.js +17 -0
  67. package/dist/components/AgentHub/Chat/List/FilterBar.js.map +1 -0
  68. package/dist/components/AgentHub/Chat/List/SessionSidebar/index.js +156 -0
  69. package/dist/components/AgentHub/Chat/List/SessionSidebar/index.js.map +1 -0
  70. package/dist/components/AgentHub/Chat/List/SessionSidebar/style.module.scss.js +28 -0
  71. package/dist/components/AgentHub/Chat/List/SessionSidebar/style.module.scss.js.map +1 -0
  72. package/dist/components/AgentHub/Chat/Modal/FormModal.js +58 -0
  73. package/dist/components/AgentHub/Chat/Modal/FormModal.js.map +1 -0
  74. package/dist/components/AgentHub/Chat/hooks/useAutoScrollToBottom.js +35 -0
  75. package/dist/components/AgentHub/Chat/hooks/useAutoScrollToBottom.js.map +1 -0
  76. package/dist/components/AgentHub/Chat/hooks/useChat.js +51 -0
  77. package/dist/components/AgentHub/Chat/hooks/useChat.js.map +1 -0
  78. package/dist/components/AgentHub/Chat/hooks/useChatSessions.js +60 -0
  79. package/dist/components/AgentHub/Chat/hooks/useChatSessions.js.map +1 -0
  80. package/dist/components/AgentHub/Chat/hooks/useSSECompletion.js +69 -0
  81. package/dist/components/AgentHub/Chat/hooks/useSSECompletion.js.map +1 -0
  82. package/dist/components/AgentHub/Chat/hooks/useTypewriter.js +39 -0
  83. package/dist/components/AgentHub/Chat/hooks/useTypewriter.js.map +1 -0
  84. package/dist/components/AgentHub/Chat/index.d.ts +1 -0
  85. package/dist/components/AgentHub/Chat/utils/citationContent.js +169 -0
  86. package/dist/components/AgentHub/Chat/utils/citationContent.js.map +1 -0
  87. package/dist/components/AgentHub/Chat/utils/messageContent.js +85 -0
  88. package/dist/components/AgentHub/Chat/utils/messageContent.js.map +1 -0
  89. package/dist/components/AgentHub/Chat/utils/sanitizeMermaidChart.js +22 -0
  90. package/dist/components/AgentHub/Chat/utils/sanitizeMermaidChart.js.map +1 -0
  91. package/dist/components/AgentHub/Chat/utils/sessionMessages.js +151 -0
  92. package/dist/components/AgentHub/Chat/utils/sessionMessages.js.map +1 -0
  93. package/dist/components/AgentHub/KnowledgeBase/Action/CreateButton.js +8 -0
  94. package/dist/components/AgentHub/KnowledgeBase/Action/CreateButton.js.map +1 -0
  95. package/dist/components/AgentHub/KnowledgeBase/Action/ManageActionButtons.js +20 -0
  96. package/dist/components/AgentHub/KnowledgeBase/Action/ManageActionButtons.js.map +1 -0
  97. package/dist/components/AgentHub/KnowledgeBase/Detail/DocumentTable/index.js +110 -0
  98. package/dist/components/AgentHub/KnowledgeBase/Detail/DocumentTable/index.js.map +1 -0
  99. package/dist/components/AgentHub/KnowledgeBase/Detail/DocumentTable/style.module.scss.js +7 -0
  100. package/dist/components/AgentHub/KnowledgeBase/Detail/DocumentTable/style.module.scss.js.map +1 -0
  101. package/dist/components/AgentHub/KnowledgeBase/Detail/ParseStatusTag/index.js +18 -0
  102. package/dist/components/AgentHub/KnowledgeBase/Detail/ParseStatusTag/index.js.map +1 -0
  103. package/dist/components/AgentHub/KnowledgeBase/Detail/ParseStatusTag/style.module.scss.js +7 -0
  104. package/dist/components/AgentHub/KnowledgeBase/Detail/ParseStatusTag/style.module.scss.js.map +1 -0
  105. package/dist/components/AgentHub/KnowledgeBase/Form/Form.js +31 -0
  106. package/dist/components/AgentHub/KnowledgeBase/Form/Form.js.map +1 -0
  107. package/dist/components/AgentHub/KnowledgeBase/List/FilterBar.js +17 -0
  108. package/dist/components/AgentHub/KnowledgeBase/List/FilterBar.js.map +1 -0
  109. package/dist/components/AgentHub/KnowledgeBase/List/KnowledgeCard/index.js +118 -0
  110. package/dist/components/AgentHub/KnowledgeBase/List/KnowledgeCard/index.js.map +1 -0
  111. package/dist/components/AgentHub/KnowledgeBase/List/KnowledgeCard/style.module.scss.js +23 -0
  112. package/dist/components/AgentHub/KnowledgeBase/List/KnowledgeCard/style.module.scss.js.map +1 -0
  113. package/dist/components/AgentHub/KnowledgeBase/Modal/FormModal.js +47 -0
  114. package/dist/components/AgentHub/KnowledgeBase/Modal/FormModal.js.map +1 -0
  115. package/dist/components/AgentHub/KnowledgeBase/constants/types.js +28 -0
  116. package/dist/components/AgentHub/KnowledgeBase/constants/types.js.map +1 -0
  117. package/dist/components/AgentHub/KnowledgeBase/hooks/useKBDocuments.js +21 -0
  118. package/dist/components/AgentHub/KnowledgeBase/hooks/useKBDocuments.js.map +1 -0
  119. package/dist/components/AgentHub/KnowledgeBase/hooks/useKnowledgeBase.js +32 -0
  120. package/dist/components/AgentHub/KnowledgeBase/hooks/useKnowledgeBase.js.map +1 -0
  121. package/dist/components/Filter/FilterDateRange/index.d.ts +2 -0
  122. package/dist/components/Filter/FilterDateRange/index.js +62 -51
  123. package/dist/components/Filter/FilterDateRange/index.js.map +1 -1
  124. package/dist/components/Filter/FilterSelect/index.d.ts +6 -2
  125. package/dist/components/Filter/FilterSelect/index.js +132 -107
  126. package/dist/components/Filter/FilterSelect/index.js.map +1 -1
  127. package/dist/components/Filter/FilterTrigger/index.d.ts +2 -2
  128. package/dist/components/Filter/FilterTrigger/index.js.map +1 -1
  129. package/dist/components/Filter/FilterTrigger/style.module.scss.js +4 -4
  130. package/dist/components/Filter/index.d.ts +1 -1
  131. package/dist/components/Icons/index.js +153 -145
  132. package/dist/components/Icons/index.js.map +1 -1
  133. package/dist/components/TooltipInfo/TooltipInfo.js +29 -20
  134. package/dist/components/TooltipInfo/TooltipInfo.js.map +1 -1
  135. package/dist/index.d.ts +3 -1
  136. package/dist/index.js +295 -186
  137. package/dist/index.js.map +1 -1
  138. package/dist/marsun-components-core.css +1 -1
  139. package/dist/styles/global.css +1 -1
  140. package/dist/theme/constants.d.ts +47 -1
  141. package/dist/theme/constants.js +50 -5
  142. package/dist/theme/constants.js.map +1 -1
  143. package/dist/theme/index.d.ts +2 -2
  144. package/dist/theme/index.js +8 -6
  145. package/dist/theme/theme.d.ts +10 -0
  146. package/dist/theme/theme.js +24 -34
  147. package/dist/theme/theme.js.map +1 -1
  148. package/dist/theme/tokens.css +139 -0
  149. package/package.json +6 -3
@@ -0,0 +1,69 @@
1
+ import { normalizeCitation as J } from "../utils/citationContent.js";
2
+ import { useState as P, useRef as W, useCallback as S } from "react";
3
+ import { useMarsunFetch as q } from "../../../../provider/context.js";
4
+ const _ = ({ completionUrl: e, getAuthHeaders: n }) => {
5
+ const [C, o] = P(!1), a = W(null), i = q(), T = S(
6
+ async (r, x, N, O, c, k) => {
7
+ var u, d, m, b;
8
+ (u = a.current) == null || u.abort();
9
+ const l = new AbortController();
10
+ a.current = l, o(!0);
11
+ const R = ((d = [...r].reverse().find((t) => t.role === "user")) == null ? void 0 : d.content) ?? "", $ = e.startsWith("http") ? e : `${i.baseUrl ?? ""}${e}`;
12
+ try {
13
+ const t = await fetch($, {
14
+ method: "POST",
15
+ headers: {
16
+ "Content-Type": "application/json",
17
+ ...i.headers,
18
+ ...n == null ? void 0 : n()
19
+ },
20
+ body: JSON.stringify({ question: R, stream: !0, session_id: k }),
21
+ signal: l.signal
22
+ });
23
+ if (!t.ok) {
24
+ c(await t.text() || `HTTP ${t.status}`);
25
+ return;
26
+ }
27
+ const p = (m = t.body) == null ? void 0 : m.getReader();
28
+ if (!p) {
29
+ c("No response body");
30
+ return;
31
+ }
32
+ const j = new TextDecoder();
33
+ let f = "";
34
+ for (; ; ) {
35
+ const { done: v, value: D } = await p.read();
36
+ if (v) break;
37
+ f += j.decode(D, { stream: !0 });
38
+ const y = f.split(`
39
+ `);
40
+ f = y.pop() ?? "";
41
+ for (const h of y) {
42
+ if (!h.startsWith("data:")) continue;
43
+ const w = h.slice(5).trim();
44
+ if (w !== "[DONE]")
45
+ try {
46
+ const s = JSON.parse(w);
47
+ s.answer && x(s.answer), (b = s.citations) != null && b.length && N(s.citations.map((E) => J(E)));
48
+ } catch {
49
+ }
50
+ }
51
+ }
52
+ O();
53
+ } catch (t) {
54
+ t.name !== "AbortError" && c(t instanceof Error ? t.message : String(t));
55
+ } finally {
56
+ o(!1);
57
+ }
58
+ },
59
+ [e, i, n]
60
+ ), g = S(() => {
61
+ var r;
62
+ (r = a.current) == null || r.abort(), o(!1);
63
+ }, []);
64
+ return { send: T, streaming: C, abort: g };
65
+ };
66
+ export {
67
+ _ as useSSECompletion
68
+ };
69
+ //# sourceMappingURL=useSSECompletion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSSECompletion.js","sources":["../../../../../src/components/AgentHub/Chat/hooks/useSSECompletion.ts"],"sourcesContent":["import { normalizeCitation } from '@/components/AgentHub/Chat/utils/citationContent';\nimport { useMarsunFetch } from '@/provider';\nimport type { Citation } from '@/components/AgentHub/types';\nimport { useCallback, useRef, useState } from 'react';\n\nexport type SSECompletionOptions = {\n completionUrl: string;\n getAuthHeaders?: () => Record<string, string>;\n};\n\nexport const useSSECompletion = ({ completionUrl, getAuthHeaders }: SSECompletionOptions) => {\n const [streaming, setStreaming] = useState(false);\n const abortRef = useRef<AbortController | null>(null);\n const fetchCtx = useMarsunFetch();\n\n const send = useCallback(\n async (\n messages: { role: 'user' | 'assistant'; content: string }[],\n onChunk: (text: string) => void,\n onCitations: (citations: Citation[]) => void,\n onDone: () => void,\n onError: (err: string) => void,\n sessionId?: string,\n ) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n setStreaming(true);\n\n const question = [...messages].reverse().find((m) => m.role === 'user')?.content ?? '';\n const url = completionUrl.startsWith('http')\n ? completionUrl\n : `${fetchCtx.baseUrl ?? ''}${completionUrl}`;\n\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...fetchCtx.headers,\n ...getAuthHeaders?.(),\n },\n body: JSON.stringify({ question, stream: true, session_id: sessionId }),\n signal: controller.signal,\n });\n\n if (!res.ok) {\n onError(await res.text() || `HTTP ${res.status}`);\n return;\n }\n\n const reader = res.body?.getReader();\n if (!reader) {\n onError('No response body');\n return;\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (!line.startsWith('data:')) continue;\n const payload = line.slice(5).trim();\n if (payload === '[DONE]') continue;\n try {\n const json = JSON.parse(payload) as {\n answer?: string;\n citations?: Citation[];\n };\n if (json.answer) onChunk(json.answer);\n if (json.citations?.length) {\n onCitations(json.citations.map((c) => normalizeCitation(c as Record<string, unknown>)));\n }\n } catch {\n // skip malformed chunk\n }\n }\n }\n onDone();\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n onError(err instanceof Error ? err.message : String(err));\n }\n } finally {\n setStreaming(false);\n }\n },\n [completionUrl, fetchCtx, getAuthHeaders],\n );\n\n const abort = useCallback(() => {\n abortRef.current?.abort();\n setStreaming(false);\n }, []);\n\n return { send, streaming, abort };\n};\n"],"names":["useSSECompletion","completionUrl","getAuthHeaders","streaming","setStreaming","useState","abortRef","useRef","fetchCtx","useMarsunFetch","send","useCallback","messages","onChunk","onCitations","onDone","onError","sessionId","_a","controller","question","_b","m","url","res","reader","_c","decoder","buffer","done","value","lines","line","payload","json","_d","c","normalizeCitation","err","abort"],"mappings":";;;AAUO,MAAMA,IAAmB,CAAC,EAAE,eAAAC,GAAe,gBAAAC,QAA2C;AAC3F,QAAM,CAACC,GAAWC,CAAY,IAAIC,EAAS,EAAK,GAC1CC,IAAWC,EAA+B,IAAI,GAC9CC,IAAWC,EAAA,GAEXC,IAAOC;AAAA,IACX,OACEC,GACAC,GACAC,GACAC,GACAC,GACAC,MACG;;AACH,OAAAC,IAAAZ,EAAS,YAAT,QAAAY,EAAkB;AAClB,YAAMC,IAAa,IAAI,gBAAA;AACvB,MAAAb,EAAS,UAAUa,GACnBf,EAAa,EAAI;AAEjB,YAAMgB,MAAWC,IAAA,CAAC,GAAGT,CAAQ,EAAE,QAAA,EAAU,KAAK,CAACU,MAAMA,EAAE,SAAS,MAAM,MAArD,gBAAAD,EAAwD,YAAW,IAC9EE,IAAMtB,EAAc,WAAW,MAAM,IACvCA,IACA,GAAGO,EAAS,WAAW,EAAE,GAAGP,CAAa;AAE7C,UAAI;AACF,cAAMuB,IAAM,MAAM,MAAMD,GAAK;AAAA,UAC3B,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,GAAGf,EAAS;AAAA,YACZ,GAAGN,KAAA,gBAAAA;AAAA,UAAiB;AAAA,UAEtB,MAAM,KAAK,UAAU,EAAE,UAAAkB,GAAU,QAAQ,IAAM,YAAYH,GAAW;AAAA,UACtE,QAAQE,EAAW;AAAA,QAAA,CACpB;AAED,YAAI,CAACK,EAAI,IAAI;AACX,UAAAR,EAAQ,MAAMQ,EAAI,KAAA,KAAU,QAAQA,EAAI,MAAM,EAAE;AAChD;AAAA,QACF;AAEA,cAAMC,KAASC,IAAAF,EAAI,SAAJ,gBAAAE,EAAU;AACzB,YAAI,CAACD,GAAQ;AACX,UAAAT,EAAQ,kBAAkB;AAC1B;AAAA,QACF;AAEA,cAAMW,IAAU,IAAI,YAAA;AACpB,YAAIC,IAAS;AAEb,mBAAa;AACX,gBAAM,EAAE,MAAAC,GAAM,OAAAC,EAAA,IAAU,MAAML,EAAO,KAAA;AACrC,cAAII,EAAM;AACV,UAAAD,KAAUD,EAAQ,OAAOG,GAAO,EAAE,QAAQ,IAAM;AAChD,gBAAMC,IAAQH,EAAO,MAAM;AAAA,CAAI;AAC/B,UAAAA,IAASG,EAAM,SAAS;AACxB,qBAAWC,KAAQD,GAAO;AACxB,gBAAI,CAACC,EAAK,WAAW,OAAO,EAAG;AAC/B,kBAAMC,IAAUD,EAAK,MAAM,CAAC,EAAE,KAAA;AAC9B,gBAAIC,MAAY;AAChB,kBAAI;AACF,sBAAMC,IAAO,KAAK,MAAMD,CAAO;AAI/B,gBAAIC,EAAK,UAAQrB,EAAQqB,EAAK,MAAM,IAChCC,IAAAD,EAAK,cAAL,QAAAC,EAAgB,UAClBrB,EAAYoB,EAAK,UAAU,IAAI,CAACE,MAAMC,EAAkBD,CAA4B,CAAC,CAAC;AAAA,cAE1F,QAAQ;AAAA,cAER;AAAA,UACF;AAAA,QACF;AACA,QAAArB,EAAA;AAAA,MACF,SAASuB,GAAK;AACZ,QAAKA,EAAc,SAAS,gBAC1BtB,EAAQsB,aAAe,QAAQA,EAAI,UAAU,OAAOA,CAAG,CAAC;AAAA,MAE5D,UAAA;AACE,QAAAlC,EAAa,EAAK;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAACH,GAAeO,GAAUN,CAAc;AAAA,EAAA,GAGpCqC,IAAQ5B,EAAY,MAAM;;AAC9B,KAAAO,IAAAZ,EAAS,YAAT,QAAAY,EAAkB,SAClBd,EAAa,EAAK;AAAA,EACpB,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,MAAAM,GAAM,WAAAP,GAAW,OAAAoC,EAAA;AAC5B;"}
@@ -0,0 +1,39 @@
1
+ import { useRef as t, useState as M, useEffect as s } from "react";
2
+ function q(e, u, w = {}) {
3
+ const { charsPerSecond: h = 60 } = w, n = t(u), [r, g] = M(() => u ? 0 : e.length), f = t(0), p = t(0), i = t(0), l = t(performance.now()), a = t(e.length), c = t(r);
4
+ a.current = e.length, c.current = r, s(() => {
5
+ u && (n.current = !0);
6
+ }, [u]);
7
+ const d = n.current && r < e.length;
8
+ return s(() => {
9
+ if (!d) return;
10
+ let m = !0;
11
+ const R = (y) => {
12
+ if (!m) return;
13
+ const L = a.current, A = c.current;
14
+ if (A >= L) return;
15
+ const F = y - l.current;
16
+ l.current = y;
17
+ const T = h * F / 1e3 + i.current, o = Math.floor(T);
18
+ if (i.current = T - o, o > 0) {
19
+ const v = Math.min(A + o, L);
20
+ c.current = v, g(v);
21
+ }
22
+ c.current < a.current && (f.current = requestAnimationFrame(R));
23
+ };
24
+ return l.current = performance.now(), f.current = requestAnimationFrame(R), () => {
25
+ m = !1, cancelAnimationFrame(f.current);
26
+ };
27
+ }, [e.length, h, d]), s(() => {
28
+ r >= e.length && e.length > 0 && (n.current = !1);
29
+ }, [r, e.length]), s(() => {
30
+ e.length === 0 && p.current > 0 && (n.current = !1, c.current = 0, g(0), i.current = 0), p.current = e.length;
31
+ }, [e.length]), {
32
+ displayed: e.slice(0, r),
33
+ isTyping: n.current && r < e.length
34
+ };
35
+ }
36
+ export {
37
+ q as useTypewriter
38
+ };
39
+ //# sourceMappingURL=useTypewriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTypewriter.js","sources":["../../../../../src/components/AgentHub/Chat/hooks/useTypewriter.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\n\ninterface UseTypewriterOptions {\n /** Fixed reveal rate in characters per second. Default: 60 */\n charsPerSecond?: number;\n}\n\n/**\n * Smoothly reveals streaming text character-by-character using requestAnimationFrame.\n *\n * Live streaming messages animate from empty; once the stream ends, any remaining\n * characters continue at the same rate until fully revealed. Historical messages\n * with `streaming: false` that were never streamed show in full immediately.\n */\nexport function useTypewriter(\n content: string,\n streaming: boolean,\n options: UseTypewriterOptions = {},\n) {\n const { charsPerSecond = 60 } = options;\n\n const wasStreamingRef = useRef(streaming);\n const [displayedLength, setDisplayedLength] = useState(() => (streaming ? 0 : content.length));\n const rafRef = useRef<number>(0);\n const prevContentLenRef = useRef(0);\n const carryRef = useRef(0);\n const lastTimeRef = useRef(performance.now());\n const contentLengthRef = useRef(content.length);\n const displayedLengthRef = useRef(displayedLength);\n\n contentLengthRef.current = content.length;\n displayedLengthRef.current = displayedLength;\n\n useEffect(() => {\n if (streaming) {\n wasStreamingRef.current = true;\n }\n }, [streaming]);\n\n const isPendingReveal =\n wasStreamingRef.current && displayedLength < content.length;\n\n useEffect(() => {\n if (!isPendingReveal) return;\n\n let running = true;\n\n const loop = (now: number) => {\n if (!running) return;\n\n const target = contentLengthRef.current;\n const prev = displayedLengthRef.current;\n if (prev >= target) return;\n\n const deltaMs = now - lastTimeRef.current;\n lastTimeRef.current = now;\n\n const charsToAdd = (charsPerSecond * deltaMs) / 1000 + carryRef.current;\n const step = Math.floor(charsToAdd);\n carryRef.current = charsToAdd - step;\n\n if (step > 0) {\n const next = Math.min(prev + step, target);\n displayedLengthRef.current = next;\n setDisplayedLength(next);\n }\n\n if (displayedLengthRef.current < contentLengthRef.current) {\n rafRef.current = requestAnimationFrame(loop);\n }\n };\n\n lastTimeRef.current = performance.now();\n rafRef.current = requestAnimationFrame(loop);\n\n return () => {\n running = false;\n cancelAnimationFrame(rafRef.current);\n };\n }, [content.length, charsPerSecond, isPendingReveal]);\n\n useEffect(() => {\n if (displayedLength >= content.length && content.length > 0) {\n wasStreamingRef.current = false;\n }\n }, [displayedLength, content.length]);\n\n useEffect(() => {\n if (content.length === 0 && prevContentLenRef.current > 0) {\n wasStreamingRef.current = false;\n displayedLengthRef.current = 0;\n setDisplayedLength(0);\n carryRef.current = 0;\n }\n prevContentLenRef.current = content.length;\n }, [content.length]);\n\n return {\n displayed: content.slice(0, displayedLength),\n isTyping: wasStreamingRef.current && displayedLength < content.length,\n };\n}\n"],"names":["useTypewriter","content","streaming","options","charsPerSecond","wasStreamingRef","useRef","displayedLength","setDisplayedLength","useState","rafRef","prevContentLenRef","carryRef","lastTimeRef","contentLengthRef","displayedLengthRef","useEffect","isPendingReveal","running","loop","now","target","prev","deltaMs","charsToAdd","step","next"],"mappings":";AAcO,SAASA,EACdC,GACAC,GACAC,IAAgC,CAAA,GAChC;AACA,QAAM,EAAE,gBAAAC,IAAiB,GAAA,IAAOD,GAE1BE,IAAkBC,EAAOJ,CAAS,GAClC,CAACK,GAAiBC,CAAkB,IAAIC,EAAS,MAAOP,IAAY,IAAID,EAAQ,MAAO,GACvFS,IAASJ,EAAe,CAAC,GACzBK,IAAoBL,EAAO,CAAC,GAC5BM,IAAWN,EAAO,CAAC,GACnBO,IAAcP,EAAO,YAAY,IAAA,CAAK,GACtCQ,IAAmBR,EAAOL,EAAQ,MAAM,GACxCc,IAAqBT,EAAOC,CAAe;AAEjD,EAAAO,EAAiB,UAAUb,EAAQ,QACnCc,EAAmB,UAAUR,GAE7BS,EAAU,MAAM;AACd,IAAId,MACFG,EAAgB,UAAU;AAAA,EAE9B,GAAG,CAACH,CAAS,CAAC;AAEd,QAAMe,IACJZ,EAAgB,WAAWE,IAAkBN,EAAQ;AAEvD,SAAAe,EAAU,MAAM;AACd,QAAI,CAACC,EAAiB;AAEtB,QAAIC,IAAU;AAEd,UAAMC,IAAO,CAACC,MAAgB;AAC5B,UAAI,CAACF,EAAS;AAEd,YAAMG,IAASP,EAAiB,SAC1BQ,IAAOP,EAAmB;AAChC,UAAIO,KAAQD,EAAQ;AAEpB,YAAME,IAAUH,IAAMP,EAAY;AAClC,MAAAA,EAAY,UAAUO;AAEtB,YAAMI,IAAcpB,IAAiBmB,IAAW,MAAOX,EAAS,SAC1Da,IAAO,KAAK,MAAMD,CAAU;AAGlC,UAFAZ,EAAS,UAAUY,IAAaC,GAE5BA,IAAO,GAAG;AACZ,cAAMC,IAAO,KAAK,IAAIJ,IAAOG,GAAMJ,CAAM;AACzC,QAAAN,EAAmB,UAAUW,GAC7BlB,EAAmBkB,CAAI;AAAA,MACzB;AAEA,MAAIX,EAAmB,UAAUD,EAAiB,YAChDJ,EAAO,UAAU,sBAAsBS,CAAI;AAAA,IAE/C;AAEA,WAAAN,EAAY,UAAU,YAAY,IAAA,GAClCH,EAAO,UAAU,sBAAsBS,CAAI,GAEpC,MAAM;AACX,MAAAD,IAAU,IACV,qBAAqBR,EAAO,OAAO;AAAA,IACrC;AAAA,EACF,GAAG,CAACT,EAAQ,QAAQG,GAAgBa,CAAe,CAAC,GAEpDD,EAAU,MAAM;AACd,IAAIT,KAAmBN,EAAQ,UAAUA,EAAQ,SAAS,MACxDI,EAAgB,UAAU;AAAA,EAE9B,GAAG,CAACE,GAAiBN,EAAQ,MAAM,CAAC,GAEpCe,EAAU,MAAM;AACd,IAAIf,EAAQ,WAAW,KAAKU,EAAkB,UAAU,MACtDN,EAAgB,UAAU,IAC1BU,EAAmB,UAAU,GAC7BP,EAAmB,CAAC,GACpBI,EAAS,UAAU,IAErBD,EAAkB,UAAUV,EAAQ;AAAA,EACtC,GAAG,CAACA,EAAQ,MAAM,CAAC,GAEZ;AAAA,IACL,WAAWA,EAAQ,MAAM,GAAGM,CAAe;AAAA,IAC3C,UAAUF,EAAgB,WAAWE,IAAkBN,EAAQ;AAAA,EAAA;AAEnE;"}
@@ -5,3 +5,4 @@ export * from './Form';
5
5
  export * from './hooks';
6
6
  export * from './List';
7
7
  export * from './Modal';
8
+ export * from './utils';
@@ -0,0 +1,169 @@
1
+ const a = "#cite-", f = new RegExp("\\[ID[:-](\\d+)\\]|[((]ID[:-](\\d+)[))]|(?<![\\w\\[((])ID[:-](\\d+)(?![\\w])", "g");
2
+ function d(t) {
3
+ const n = [], e = new RegExp(f.source, f.flags);
4
+ let i = e.exec(t);
5
+ for (; i; ) {
6
+ const o = i[1] ?? i[2] ?? i[3];
7
+ n.push(parseInt(o, 10)), i = e.exec(t);
8
+ }
9
+ return n;
10
+ }
11
+ function _(t) {
12
+ return d(t);
13
+ }
14
+ function v(t, n) {
15
+ if (n <= 0) return 0;
16
+ const e = d(t).map(
17
+ (i) => p(i, n, t)
18
+ );
19
+ return new Set(e).size;
20
+ }
21
+ function g(t, n) {
22
+ const e = _(t);
23
+ if (e.length === 0 || n <= 0 || e.some((s) => s === 0)) return "zero";
24
+ if (e.some((s) => s === n)) return "one";
25
+ const i = e.every((s) => s >= 0 && s < n), o = e.every((s) => s >= 1 && s <= n);
26
+ if (o && !i) return "one";
27
+ if (i && !o) return "zero";
28
+ const c = [...new Set(e)].sort((s, r) => s - r);
29
+ return c[0] === 1 && c.length > 0 && c.every((s, r) => s === r + 1) ? "one" : "zero";
30
+ }
31
+ function A(t) {
32
+ return t.replace(f, (n, e, i, o) => {
33
+ const c = e ?? i ?? o;
34
+ return `[${c}](${a}${c})`;
35
+ });
36
+ }
37
+ function S(t) {
38
+ if (!(t != null && t.startsWith(a))) return null;
39
+ const n = parseInt(t.slice(a.length), 10);
40
+ return Number.isNaN(n) ? null : n;
41
+ }
42
+ function p(t, n, e) {
43
+ if (n <= 0) return 0;
44
+ const o = (e ? g(e, n) : "zero") === "one" ? t - 1 : t;
45
+ return o >= 0 && o < n ? o : Math.max(0, Math.min(o, n - 1));
46
+ }
47
+ function E(t, n, e) {
48
+ return p(t, n, e) + 1;
49
+ }
50
+ function m(t) {
51
+ return t.replace(/^\s*---[\s\S]*?---\s*/m, "").trim();
52
+ }
53
+ const y = /^<\/?[\w-]+(?:\s[^>]*)?>$/, T = /^\|?\s*:?-{3,}/, l = (t) => t.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim(), u = (t) => {
54
+ const n = t.trim();
55
+ return !(!n || n.length > 48 || y.test(n) || /^<\w/.test(n));
56
+ }, h = (t) => t.replace(/^<p[^>]*>/i, "").replace(/<\/p>$/i, "").trim(), b = (t) => {
57
+ const n = t.match(/<tbody[^>]*>[\s\S]*?<tr[^>]*>[\s\S]*?<td[^>]*>([\s\S]*?)<\/td>/i);
58
+ if (n != null && n[1]) {
59
+ const i = l(n[1]);
60
+ if (i) return i;
61
+ }
62
+ const e = t.match(/<th[^>]*>([\s\S]*?)<\/th>/i);
63
+ if (e != null && e[1]) {
64
+ const i = l(e[1]);
65
+ if (i) return i;
66
+ }
67
+ return null;
68
+ }, x = (t) => {
69
+ var e, i;
70
+ const n = [];
71
+ return t.split(`
72
+ `).forEach((o) => {
73
+ const c = o.trim();
74
+ if (!c.includes("|") || T.test(c.replace(/\|/g, ""))) return;
75
+ const s = c.split("|").map((r) => r.trim()).filter((r) => r.length > 0);
76
+ s.length >= 2 && n.push(s);
77
+ }), n.length >= 2 ? ((e = n[1]) == null ? void 0 : e[0]) ?? null : n.length === 1 ? ((i = n[0]) == null ? void 0 : i[0]) ?? null : null;
78
+ };
79
+ function M(t) {
80
+ if (!(t != null && t.trim())) return;
81
+ const n = t.trim().replace(/\\/g, "/"), e = n.split("/").pop() ?? n;
82
+ return e.replace(/\.(md|pdf|txt|docx?)$/i, "") || e;
83
+ }
84
+ function $(t) {
85
+ const n = t.doc_name ?? t.document_name, e = t.doc_id ?? t.document_id, i = typeof t.score == "number" ? t.score : typeof t.similarity == "number" ? t.similarity : void 0;
86
+ let o = t.page_no;
87
+ if (o == null && Array.isArray(t.positions) && t.positions.length > 0) {
88
+ const c = t.positions[0];
89
+ Array.isArray(c) && typeof c[0] == "number" && c[0] > 0 && (o = c[0]);
90
+ }
91
+ return {
92
+ id: typeof t.id == "string" ? t.id : String(t.doc_id ?? t.document_id ?? Math.random()),
93
+ doc_id: typeof e == "string" ? e : void 0,
94
+ doc_name: typeof n == "string" ? n : void 0,
95
+ dataset_id: typeof t.dataset_id == "string" ? t.dataset_id : void 0,
96
+ content: typeof t.content == "string" ? t.content : void 0,
97
+ score: i,
98
+ positions: Array.isArray(t.positions) ? t.positions : void 0,
99
+ page_no: o ?? null
100
+ };
101
+ }
102
+ function R(t, n) {
103
+ const e = m(t), i = e.match(/^#{1,6}\s+(.+)$/m);
104
+ if (i != null && i[1] && u(i[1])) return i[1].trim();
105
+ const o = e.match(/<h[1-6][^>]*>([\s\S]*?)<\/h[1-6]>/i);
106
+ if (o != null && o[1]) {
107
+ const r = l(o[1]);
108
+ if (u(r)) return r;
109
+ }
110
+ if (/<table/i.test(e)) {
111
+ const r = b(e);
112
+ if (r && u(r)) return r;
113
+ }
114
+ const c = h(e);
115
+ if (c.includes("|")) {
116
+ const r = x(c);
117
+ if (r && u(r)) return r;
118
+ }
119
+ const s = e.split(`
120
+ `).map((r) => l(r.trim())).find((r) => r.length > 0 && !r.startsWith("|") && u(r));
121
+ return s || n;
122
+ }
123
+ function z(t, n) {
124
+ var e;
125
+ return ((e = t.doc_name) == null ? void 0 : e.trim()) || `来源 ${n + 1}`;
126
+ }
127
+ function C(t) {
128
+ const n = t;
129
+ if (!(n != null && n.length)) return;
130
+ const e = n[0];
131
+ if (!(e != null && e.length)) return;
132
+ const i = e[0];
133
+ return typeof i == "number" && i > 0 ? `第 ${i} 页` : `位置 ${e.join(", ")}`;
134
+ }
135
+ function N(t) {
136
+ const n = [], e = C(t.positions);
137
+ return e && n.push(e), t.score !== void 0 && n.push(`匹配 ${(t.score * 100).toFixed(0)}%`), n.join(" · ");
138
+ }
139
+ const I = /<\s*(table|thead|tbody|tr|td|th|div|p|span|ul|ol|li|h[1-6]|br)\b/i;
140
+ function O(t) {
141
+ const n = m(t);
142
+ return {
143
+ body: n,
144
+ isHtml: I.test(n)
145
+ };
146
+ }
147
+ function D(t) {
148
+ return t.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<iframe[\s\S]*?<\/iframe>/gi, "").replace(/\son\w+\s*=\s*(['"])[^'"]*\1/gi, "");
149
+ }
150
+ export {
151
+ a as CITATION_LINK_PREFIX,
152
+ E as citationDisplayNumber,
153
+ p as citationIdToIndex,
154
+ v as countUniqueCitedSources,
155
+ g as detectCitationIdBase,
156
+ _ as extractCitationIdsFromContent,
157
+ R as extractCitationTitle,
158
+ M as formatCitationDocBasename,
159
+ N as formatCitationMeta,
160
+ C as formatCitationPositions,
161
+ A as injectCitationMarkdownLinks,
162
+ $ as normalizeCitation,
163
+ S as parseCitationLinkHref,
164
+ O as prepareCitationContent,
165
+ z as resolveCitationTitle,
166
+ D as sanitizeCitationHtml,
167
+ m as stripCitationFrontmatter
168
+ };
169
+ //# sourceMappingURL=citationContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citationContent.js","sources":["../../../../../src/components/AgentHub/Chat/utils/citationContent.ts"],"sourcesContent":["import type { Citation } from '@/components/AgentHub/types';\n\nexport const CITATION_LINK_PREFIX = '#cite-';\n\n/** RAGFlow / LLM 可能输出的引用标记(单次匹配,避免重复识别) */\nconst CITATION_MARKER_RE =\n /\\[ID[:-](\\d+)\\]|[((]ID[:-](\\d+)[))]|(?<![\\w\\[((])ID[:-](\\d+)(?![\\w])/g;\n\nfunction collectCitationIds(content: string): number[] {\n const ids: number[] = [];\n const re = new RegExp(CITATION_MARKER_RE.source, CITATION_MARKER_RE.flags);\n let match = re.exec(content);\n while (match) {\n const id = match[1] ?? match[2] ?? match[3];\n ids.push(parseInt(id!, 10));\n match = re.exec(content);\n }\n return ids;\n}\n\n/** 从正文中提取所有引用 ID(支持 [ID:n]、(ID:n)、ID:n 等格式) */\nexport function extractCitationIdsFromContent(content: string): number[] {\n return collectCitationIds(content);\n}\n\n/** 正文中实际引用到的来源数量(去重后的 citations 下标) */\nexport function countUniqueCitedSources(content: string, citationsLength: number): number {\n if (citationsLength <= 0) return 0;\n const indices = collectCitationIds(content).map((id) =>\n citationIdToIndex(id, citationsLength, content),\n );\n return new Set(indices).size;\n}\n\n/** 判断 [ID:n] 是 0-based 还是 1-based(RAGFlow 用 0-based,部分 mock/旧数据用 1-based) */\nexport function detectCitationIdBase(content: string, citationsLength: number): 'zero' | 'one' {\n const ids = extractCitationIdsFromContent(content);\n if (ids.length === 0 || citationsLength <= 0) return 'zero';\n\n if (ids.some((id) => id === 0)) return 'zero';\n\n // n === citationsLength 仅 1-based 合法(如 2 条来源时的 [ID:2])\n if (ids.some((id) => id === citationsLength)) return 'one';\n\n const allZeroBasedValid = ids.every((id) => id >= 0 && id < citationsLength);\n const allOneBasedValid = ids.every((id) => id >= 1 && id <= citationsLength);\n\n if (allOneBasedValid && !allZeroBasedValid) return 'one';\n if (allZeroBasedValid && !allOneBasedValid) return 'zero';\n\n const uniqueSorted = [...new Set(ids)].sort((a, b) => a - b);\n if (\n uniqueSorted[0] === 1 &&\n uniqueSorted.length > 0 &&\n uniqueSorted.every((id, i) => id === i + 1)\n ) {\n return 'one';\n }\n\n return 'zero';\n}\n\n/** 将正文中的引用标记转为可自定义渲染的 markdown 链接 */\nexport function injectCitationMarkdownLinks(content: string): string {\n return content.replace(CITATION_MARKER_RE, (_, id1, id2, id3) => {\n const id = id1 ?? id2 ?? id3;\n return `[${id}](${CITATION_LINK_PREFIX}${id})`;\n });\n}\n\nexport function parseCitationLinkHref(href?: string): number | null {\n if (!href?.startsWith(CITATION_LINK_PREFIX)) return null;\n const id = parseInt(href.slice(CITATION_LINK_PREFIX.length), 10);\n return Number.isNaN(id) ? null : id;\n}\n\n/** [ID:n] 映射到 citations 数组下标 */\nexport function citationIdToIndex(id: number, citationsLength: number, content?: string): number {\n if (citationsLength <= 0) return 0;\n const base = content ? detectCitationIdBase(content, citationsLength) : 'zero';\n const index = base === 'one' ? id - 1 : id;\n if (index >= 0 && index < citationsLength) return index;\n return Math.max(0, Math.min(index, citationsLength - 1));\n}\n\n/** 与侧栏 panel 一致的 1-based 展示序号 */\nexport function citationDisplayNumber(\n citationId: number,\n citationsLength: number,\n content?: string,\n): number {\n return citationIdToIndex(citationId, citationsLength, content) + 1;\n}\n\n/** 去掉 RAG chunk 顶部的 YAML frontmatter */\nexport function stripCitationFrontmatter(content: string): string {\n return content.replace(/^\\s*---[\\s\\S]*?---\\s*/m, '').trim();\n}\n\nconst HTML_TAG_ONLY_RE = /^<\\/?[\\w-]+(?:\\s[^>]*)?>$/;\nconst MARKDOWN_TABLE_SEPARATOR_RE = /^\\|?\\s*:?-{3,}/;\n\nconst stripHtmlText = (html: string): string =>\n html\n .replace(/<[^>]+>/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n\nconst isMeaningfulTitle = (text: string): boolean => {\n const trimmed = text.trim();\n if (!trimmed || trimmed.length > 48) return false;\n if (HTML_TAG_ONLY_RE.test(trimmed)) return false;\n if (/^<\\w/.test(trimmed)) return false;\n return true;\n};\n\nconst unwrapParagraphWrapper = (content: string): string =>\n content\n .replace(/^<p[^>]*>/i, '')\n .replace(/<\\/p>$/i, '')\n .trim();\n\nconst extractHtmlTableTitle = (html: string): string | null => {\n const tbodyRow = html.match(/<tbody[^>]*>[\\s\\S]*?<tr[^>]*>[\\s\\S]*?<td[^>]*>([\\s\\S]*?)<\\/td>/i);\n if (tbodyRow?.[1]) {\n const text = stripHtmlText(tbodyRow[1]);\n if (text) return text;\n }\n\n const th = html.match(/<th[^>]*>([\\s\\S]*?)<\\/th>/i);\n if (th?.[1]) {\n const text = stripHtmlText(th[1]);\n if (text) return text;\n }\n\n return null;\n};\n\nconst extractMarkdownTableTitle = (content: string): string | null => {\n const rows: string[][] = [];\n\n content.split('\\n').forEach((line) => {\n const trimmed = line.trim();\n if (!trimmed.includes('|')) return;\n if (MARKDOWN_TABLE_SEPARATOR_RE.test(trimmed.replace(/\\|/g, ''))) return;\n\n const cells = trimmed\n .split('|')\n .map((cell) => cell.trim())\n .filter((cell) => cell.length > 0);\n if (cells.length >= 2) rows.push(cells);\n });\n\n if (rows.length >= 2) return rows[1]?.[0] ?? null;\n if (rows.length === 1) return rows[0]?.[0] ?? null;\n return null;\n};\n\n/** 文档路径取文件名(去扩展名) */\nexport function formatCitationDocBasename(docName?: string): string | undefined {\n if (!docName?.trim()) return undefined;\n\n const normalized = docName.trim().replace(/\\\\/g, '/');\n const basename = normalized.split('/').pop() ?? normalized;\n const withoutExt = basename.replace(/\\.(md|pdf|txt|docx?)$/i, '');\n return withoutExt || basename;\n}\n\n/** 将 RAGFlow chunk 字段归一化为 Citation */\nexport function normalizeCitation(raw: Record<string, unknown>): Citation {\n const docName = raw.doc_name ?? raw.document_name;\n const docId = raw.doc_id ?? raw.document_id;\n const score =\n typeof raw.score === 'number'\n ? raw.score\n : typeof raw.similarity === 'number'\n ? raw.similarity\n : undefined;\n\n let pageNo = raw.page_no as number | null | undefined;\n if (pageNo == null && Array.isArray(raw.positions) && raw.positions.length > 0) {\n const firstPos = raw.positions[0];\n if (Array.isArray(firstPos) && typeof firstPos[0] === 'number' && firstPos[0] > 0) {\n pageNo = firstPos[0];\n }\n }\n\n return {\n id: typeof raw.id === 'string' ? raw.id : String(raw.doc_id ?? raw.document_id ?? Math.random()),\n doc_id: typeof docId === 'string' ? docId : undefined,\n doc_name: typeof docName === 'string' ? docName : undefined,\n dataset_id: typeof raw.dataset_id === 'string' ? raw.dataset_id : undefined,\n content: typeof raw.content === 'string' ? raw.content : undefined,\n score,\n positions: Array.isArray(raw.positions) ? (raw.positions as number[][]) : undefined,\n page_no: pageNo ?? null,\n };\n}\n\n/** 从 chunk 正文提取展示标题 */\nexport function extractCitationTitle(content: string, fallback: string): string {\n const body = stripCitationFrontmatter(content);\n\n const heading = body.match(/^#{1,6}\\s+(.+)$/m);\n if (heading?.[1] && isMeaningfulTitle(heading[1])) return heading[1].trim();\n\n const htmlHeading = body.match(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/i);\n if (htmlHeading?.[1]) {\n const text = stripHtmlText(htmlHeading[1]);\n if (isMeaningfulTitle(text)) return text;\n }\n\n if (/<table/i.test(body)) {\n const tableTitle = extractHtmlTableTitle(body);\n if (tableTitle && isMeaningfulTitle(tableTitle)) return tableTitle;\n }\n\n const unwrapped = unwrapParagraphWrapper(body);\n if (unwrapped.includes('|')) {\n const tableTitle = extractMarkdownTableTitle(unwrapped);\n if (tableTitle && isMeaningfulTitle(tableTitle)) return tableTitle;\n }\n\n const firstLine = body\n .split('\\n')\n .map((line) => stripHtmlText(line.trim()))\n .find((line) => line.length > 0 && !line.startsWith('|') && isMeaningfulTitle(line));\n if (firstLine) return firstLine;\n\n return fallback;\n}\n\n/** 引用侧栏标题:展示 document_name */\nexport function resolveCitationTitle(citation: Citation, index: number): string {\n return citation.doc_name?.trim() || `来源 ${index + 1}`;\n}\n\n/** 格式化 chunk positions(RAGFlow: [页码, left, right, top, bottom]) */\nexport function formatCitationPositions(positions?: unknown): string | undefined {\n const pos = positions as number[][] | undefined;\n if (!pos?.length) return undefined;\n\n const first = pos[0];\n if (!first?.length) return undefined;\n\n const page = first[0];\n if (typeof page === 'number' && page > 0) {\n return `第 ${page} 页`;\n }\n\n return `位置 ${first.join(', ')}`;\n}\n\n/** 引用侧栏元信息:positions · 匹配度 */\nexport function formatCitationMeta(citation: Citation): string {\n const parts: string[] = [];\n const positionLabel = formatCitationPositions(citation.positions);\n if (positionLabel) parts.push(positionLabel);\n if (citation.score !== undefined) parts.push(`匹配 ${(citation.score * 100).toFixed(0)}%`);\n return parts.join(' · ');\n}\n\nexport interface PreparedCitationContent {\n body: string;\n isHtml: boolean;\n}\n\nconst HTML_CONTENT_PATTERN = /<\\s*(table|thead|tbody|tr|td|th|div|p|span|ul|ol|li|h[1-6]|br)\\b/i;\n\n/** 预处理引用正文,供 Markdown / HTML 分支渲染 */\nexport function prepareCitationContent(content: string): PreparedCitationContent {\n const body = stripCitationFrontmatter(content);\n return {\n body,\n isHtml: HTML_CONTENT_PATTERN.test(body),\n };\n}\n\n/** 引用 HTML 仅做基础清理(内容来自可信 RAG 知识库) */\nexport function sanitizeCitationHtml(html: string): string {\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<iframe[\\s\\S]*?<\\/iframe>/gi, '')\n .replace(/\\son\\w+\\s*=\\s*(['\"])[^'\"]*\\1/gi, '');\n}\n"],"names":["CITATION_LINK_PREFIX","CITATION_MARKER_RE","collectCitationIds","content","ids","re","match","id","extractCitationIdsFromContent","countUniqueCitedSources","citationsLength","indices","citationIdToIndex","detectCitationIdBase","allZeroBasedValid","allOneBasedValid","uniqueSorted","a","b","i","injectCitationMarkdownLinks","_","id1","id2","id3","parseCitationLinkHref","href","index","citationDisplayNumber","citationId","stripCitationFrontmatter","HTML_TAG_ONLY_RE","MARKDOWN_TABLE_SEPARATOR_RE","stripHtmlText","html","isMeaningfulTitle","text","trimmed","unwrapParagraphWrapper","extractHtmlTableTitle","tbodyRow","th","extractMarkdownTableTitle","_a","_b","rows","line","cells","cell","formatCitationDocBasename","docName","normalized","basename","normalizeCitation","raw","docId","score","pageNo","firstPos","extractCitationTitle","fallback","body","heading","htmlHeading","tableTitle","unwrapped","firstLine","resolveCitationTitle","citation","formatCitationPositions","positions","pos","first","page","formatCitationMeta","parts","positionLabel","HTML_CONTENT_PATTERN","prepareCitationContent","sanitizeCitationHtml"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ const h = "<think>", m = "</think>", p = new RegExp(
2
+ h.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "([\\s\\S]*?)" + m.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
3
+ "gi"
4
+ ), c = /<\/?think>/gi;
5
+ function t(n) {
6
+ return n.replace(/\n{3,}/g, `
7
+
8
+ `).trimEnd();
9
+ }
10
+ const u = /\[ID[:-]\d+\]/;
11
+ function T(n) {
12
+ if (!n) return n;
13
+ let i = n.replace(/\r\n/g, `
14
+ `);
15
+ return i = i.replace(/```\s*mermaid[ \t]*(?!\n)/gi, "```mermaid\n"), i = i.replace(
16
+ /```mermaid\n([\s\S]*?)(\n(?:风格说明|Style)[^\n`]*[\s\S]*?)(?=```|$)/gi,
17
+ (o, r, s) => `\`\`\`mermaid
18
+ ${r.trimEnd()}
19
+ \`\`\`
20
+ ${s.trim()}`
21
+ ), i;
22
+ }
23
+ function d(n) {
24
+ return u.test(n);
25
+ }
26
+ function w(n, i = !1) {
27
+ var g;
28
+ if (!n)
29
+ return { thinking: "", answer: "", isThinking: i };
30
+ const o = n.toLowerCase(), r = o.lastIndexOf(m), s = o.lastIndexOf(h), a = [];
31
+ for (const e of n.matchAll(p)) {
32
+ const l = (g = e[1]) == null ? void 0 : g.trim();
33
+ l && a.push(l);
34
+ }
35
+ if (i && r === -1)
36
+ return {
37
+ thinking: t(n.replace(c, "").trim()),
38
+ answer: "",
39
+ isThinking: !0
40
+ };
41
+ if (s > r) {
42
+ const e = n.slice(0, s).replace(c, "").trim(), l = n.slice(s + h.length).replace(c, "").trim(), k = [
43
+ ...e ? [e] : [],
44
+ ...a,
45
+ ...l ? [l] : []
46
+ ].join(`
47
+
48
+ `);
49
+ return {
50
+ thinking: t(k),
51
+ answer: "",
52
+ isThinking: i
53
+ };
54
+ }
55
+ if (r !== -1) {
56
+ const e = t(
57
+ n.slice(r + m.length).replace(c, "").trim()
58
+ );
59
+ if (e)
60
+ return {
61
+ thinking: t(a.join(`
62
+
63
+ `)),
64
+ answer: e,
65
+ isThinking: !1
66
+ };
67
+ }
68
+ const f = t(
69
+ n.replace(p, "").replace(c, "").trim()
70
+ );
71
+ return {
72
+ thinking: t(a.join(`
73
+
74
+ `)),
75
+ answer: f,
76
+ isThinking: !1
77
+ };
78
+ }
79
+ export {
80
+ d as hasCitationMarkers,
81
+ T as normalizeAssistantMarkdown,
82
+ t as normalizeDisplayText,
83
+ w as parseAssistantContent
84
+ };
85
+ //# sourceMappingURL=messageContent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messageContent.js","sources":["../../../../../src/components/AgentHub/Chat/utils/messageContent.ts"],"sourcesContent":["const THINK_OPEN = '<' + 'think>';\nconst THINK_CLOSE = '<' + '/think>';\nconst THINK_BLOCK_RE = new RegExp(\n THINK_OPEN.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&') +\n '([\\\\s\\\\S]*?)' +\n THINK_CLOSE.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n 'gi',\n);\nconst THINK_TAG_RE = /<\\/?think>/gi;\n\nexport interface ParsedAssistantContent {\n /** Reasoning text extracted from think blocks */\n thinking: string;\n /** User-facing answer (outside think blocks) */\n answer: string;\n /** Stream still inside an unclosed think block */\n isThinking: boolean;\n}\n\n/** Collapse excessive blank lines and trim trailing whitespace for display */\nexport function normalizeDisplayText(text: string): string {\n return text.replace(/\\n{3,}/g, '\\n\\n').trimEnd();\n}\n\nconst CITATION_MARKER_TEST_RE = /\\[ID[:-]\\d+\\]/;\n\n/** Normalize assistant markdown from persisted sessions (fences, mermaid blocks). */\nexport function normalizeAssistantMarkdown(content: string): string {\n if (!content) return content;\n\n let text = content.replace(/\\r\\n/g, '\\n');\n\n // Ensure newline after ```mermaid opening fence\n text = text.replace(/```\\s*mermaid[ \\t]*(?!\\n)/gi, '```mermaid\\n');\n\n // Move trailing prose after mermaid block out of the fence when closing ``` is missing\n text = text.replace(\n /```mermaid\\n([\\s\\S]*?)(\\n(?:风格说明|Style)[^\\n`]*[\\s\\S]*?)(?=```|$)/gi,\n (_, chart, prose) => {\n const trimmedChart = chart.trimEnd();\n return `\\`\\`\\`mermaid\\n${trimmedChart}\\n\\`\\`\\`\\n${prose.trim()}`;\n },\n );\n\n return text;\n}\n\nexport function hasCitationMarkers(content: string): boolean {\n return CITATION_MARKER_TEST_RE.test(content);\n}\n\n/**\n * Split assistant output into hidden reasoning and visible answer.\n * RAGFlow / reasoning models may wrap chain-of-thought in think tags.\n */\nexport function parseAssistantContent(content: string, streaming = false): ParsedAssistantContent {\n if (!content) {\n return { thinking: '', answer: '', isThinking: streaming };\n }\n\n const lower = content.toLowerCase();\n const lastClose = lower.lastIndexOf(THINK_CLOSE);\n const lastOpen = lower.lastIndexOf(THINK_OPEN);\n\n const thinkingParts: string[] = [];\n for (const match of content.matchAll(THINK_BLOCK_RE)) {\n const part = match[1]?.trim();\n if (part) thinkingParts.push(part);\n }\n\n // Streaming: before arrives, treat all output as reasoning\n if (streaming && lastClose === -1) {\n return {\n thinking: normalizeDisplayText(content.replace(THINK_TAG_RE, '').trim()),\n answer: '',\n isThinking: true,\n };\n }\n\n // Streaming: unclosed think block at the end\n if (lastOpen > lastClose) {\n const beforeOpen = content.slice(0, lastOpen).replace(THINK_TAG_RE, '').trim();\n const insideThink = content\n .slice(lastOpen + THINK_OPEN.length)\n .replace(THINK_TAG_RE, '')\n .trim();\n const thinking = [\n ...(beforeOpen ? [beforeOpen] : []),\n ...thinkingParts,\n ...(insideThink ? [insideThink] : []),\n ].join('\\n\\n');\n\n return {\n thinking: normalizeDisplayText(thinking),\n answer: '',\n isThinking: streaming,\n };\n }\n\n // Prefer final answer after the last closing think tag\n if (lastClose !== -1) {\n const answer = normalizeDisplayText(\n content\n .slice(lastClose + THINK_CLOSE.length)\n .replace(THINK_TAG_RE, '')\n .trim(),\n );\n if (answer) {\n return {\n thinking: normalizeDisplayText(thinkingParts.join('\\n\\n')),\n answer,\n isThinking: false,\n };\n }\n }\n\n const answer = normalizeDisplayText(\n content.replace(THINK_BLOCK_RE, '').replace(THINK_TAG_RE, '').trim(),\n );\n\n return {\n thinking: normalizeDisplayText(thinkingParts.join('\\n\\n')),\n answer,\n isThinking: false,\n };\n}\n"],"names":["THINK_OPEN","THINK_CLOSE","THINK_BLOCK_RE","THINK_TAG_RE","normalizeDisplayText","text","CITATION_MARKER_TEST_RE","normalizeAssistantMarkdown","content","_","chart","prose","hasCitationMarkers","parseAssistantContent","streaming","_a","lower","lastClose","lastOpen","thinkingParts","match","part","beforeOpen","insideThink","thinking","answer"],"mappings":"AAAA,MAAMA,IAAa,WACbC,IAAc,YACdC,IAAiB,IAAI;AAAA,EACzBF,EAAW,QAAQ,uBAAuB,MAAM,IAC9C,iBACAC,EAAY,QAAQ,uBAAuB,MAAM;AAAA,EACnD;AACF,GACME,IAAe;AAYd,SAASC,EAAqBC,GAAsB;AACzD,SAAOA,EAAK,QAAQ,WAAW;AAAA;AAAA,CAAM,EAAE,QAAA;AACzC;AAEA,MAAMC,IAA0B;AAGzB,SAASC,EAA2BC,GAAyB;AAClE,MAAI,CAACA,EAAS,QAAOA;AAErB,MAAIH,IAAOG,EAAQ,QAAQ,SAAS;AAAA,CAAI;AAGxC,SAAAH,IAAOA,EAAK,QAAQ,+BAA+B,cAAc,GAGjEA,IAAOA,EAAK;AAAA,IACV;AAAA,IACA,CAACI,GAAGC,GAAOC,MAEF;AAAA,EADcD,EAAM,QAAA,CACU;AAAA;AAAA,EAAaC,EAAM,MAAM;AAAA,EAChE,GAGKN;AACT;AAEO,SAASO,EAAmBJ,GAA0B;AAC3D,SAAOF,EAAwB,KAAKE,CAAO;AAC7C;AAMO,SAASK,EAAsBL,GAAiBM,IAAY,IAA+B;AAvDlG,MAAAC;AAwDE,MAAI,CAACP;AACH,WAAO,EAAE,UAAU,IAAI,QAAQ,IAAI,YAAYM,EAAA;AAGjD,QAAME,IAAQR,EAAQ,YAAA,GAChBS,IAAYD,EAAM,YAAYf,CAAW,GACzCiB,IAAWF,EAAM,YAAYhB,CAAU,GAEvCmB,IAA0B,CAAA;AAChC,aAAWC,KAASZ,EAAQ,SAASN,CAAc,GAAG;AACpD,UAAMmB,KAAON,IAAAK,EAAM,CAAC,MAAP,gBAAAL,EAAU;AACvB,IAAIM,KAAMF,EAAc,KAAKE,CAAI;AAAA,EACnC;AAGA,MAAIP,KAAaG,MAAc;AAC7B,WAAO;AAAA,MACL,UAAUb,EAAqBI,EAAQ,QAAQL,GAAc,EAAE,EAAE,MAAM;AAAA,MACvE,QAAQ;AAAA,MACR,YAAY;AAAA,IAAA;AAKhB,MAAIe,IAAWD,GAAW;AACxB,UAAMK,IAAad,EAAQ,MAAM,GAAGU,CAAQ,EAAE,QAAQf,GAAc,EAAE,EAAE,KAAA,GAClEoB,IAAcf,EACjB,MAAMU,IAAWlB,EAAW,MAAM,EAClC,QAAQG,GAAc,EAAE,EACxB,KAAA,GACGqB,IAAW;AAAA,MACf,GAAIF,IAAa,CAACA,CAAU,IAAI,CAAA;AAAA,MAChC,GAAGH;AAAA,MACH,GAAII,IAAc,CAACA,CAAW,IAAI,CAAA;AAAA,IAAC,EACnC,KAAK;AAAA;AAAA,CAAM;AAEb,WAAO;AAAA,MACL,UAAUnB,EAAqBoB,CAAQ;AAAA,MACvC,QAAQ;AAAA,MACR,YAAYV;AAAA,IAAA;AAAA,EAEhB;AAGA,MAAIG,MAAc,IAAI;AACpB,UAAMQ,IAASrB;AAAA,MACbI,EACG,MAAMS,IAAYhB,EAAY,MAAM,EACpC,QAAQE,GAAc,EAAE,EACxB,KAAA;AAAA,IAAK;AAEV,QAAIsB;AACF,aAAO;AAAA,QACL,UAAUrB,EAAqBe,EAAc,KAAK;AAAA;AAAA,CAAM,CAAC;AAAA,QACzD,QAAAM;AAAAA,QACA,YAAY;AAAA,MAAA;AAAA,EAGlB;AAEA,QAAMA,IAASrB;AAAA,IACbI,EAAQ,QAAQN,GAAgB,EAAE,EAAE,QAAQC,GAAc,EAAE,EAAE,KAAA;AAAA,EAAK;AAGrE,SAAO;AAAA,IACL,UAAUC,EAAqBe,EAAc,KAAK;AAAA;AAAA,CAAM,CAAC;AAAA,IACzD,QAAAM;AAAA,IACA,YAAY;AAAA,EAAA;AAEhB;"}
@@ -0,0 +1,22 @@
1
+ const a = /[(),():;#]/, u = /^(graph|flowchart|sequenceDiagram|classDiagram|stateDiagram|erDiagram|gantt|pie|mindmap|timeline|gitGraph|C4Context|subgraph|end|style|classDef|class|linkStyle|click|direction|%%)/i, c = /(-->|---|-\.->|==>|===|-\.-)/;
2
+ function m(e) {
3
+ return e.split(`
4
+ `).filter((r) => {
5
+ const t = r.trim();
6
+ return !!(!t || u.test(t) || c.test(t) || /^[A-Za-z0-9_]+[\[\{(]/.test(t) || /^[A-Za-z0-9_[\](){}<>"'\\.:;+\-/%&|=\s]+$/.test(t));
7
+ }).join(`
8
+ `).trim();
9
+ }
10
+ function n(e) {
11
+ const r = e.trim();
12
+ return !r || r.startsWith('"') || r.startsWith("'") || !a.test(r) ? e : `"${r.replace(/"/g, '\\"')}"`;
13
+ }
14
+ function o(e) {
15
+ let t = m(e).replace(/\[([^\]"]+)\]/g, (s, i) => `[${n(i)}]`);
16
+ return t = t.replace(/\{([^}"]+)\}/g, (s, i) => `{${n(i)}}`), t;
17
+ }
18
+ export {
19
+ o as sanitizeMermaidChart,
20
+ m as stripProseFromMermaid
21
+ };
22
+ //# sourceMappingURL=sanitizeMermaidChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizeMermaidChart.js","sources":["../../../../../src/components/AgentHub/Chat/utils/sanitizeMermaidChart.ts"],"sourcesContent":["/** Characters inside node labels that require double-quoting in Mermaid. */\nconst LABEL_NEEDS_QUOTING_RE = /[(),():;#]/;\n\n/** Fix AI-generated Mermaid blocks: quote labels, drop prose lines mistakenly inside the chart. */\nconst MERMAID_LINE_RE =\n /^(graph|flowchart|sequenceDiagram|classDiagram|stateDiagram|erDiagram|gantt|pie|mindmap|timeline|gitGraph|C4Context|subgraph|end|style|classDef|class|linkStyle|click|direction|%%)/i;\nconst MERMAID_EDGE_RE = /(-->|---|-\\.->|==>|===|-\\.-)/;\n\n/** Remove non-Mermaid prose lines (e.g. 风格说明) that LLMs append inside code blocks. */\nexport function stripProseFromMermaid(chart: string): string {\n return chart\n .split('\\n')\n .filter((line) => {\n const trimmed = line.trim();\n if (!trimmed) return true;\n if (MERMAID_LINE_RE.test(trimmed)) return true;\n if (MERMAID_EDGE_RE.test(trimmed)) return true;\n if (/^[A-Za-z0-9_]+[\\[\\{(]/.test(trimmed)) return true;\n if (/^[A-Za-z0-9_[\\](){}<>\"'\\\\.:;+\\-/%&|=\\s]+$/.test(trimmed)) return true;\n return false;\n })\n .join('\\n')\n .trim();\n}\n\nfunction quoteLabelContent(label: string): string {\n const trimmed = label.trim();\n if (!trimmed || trimmed.startsWith('\"') || trimmed.startsWith(\"'\")) {\n return label;\n }\n if (!LABEL_NEEDS_QUOTING_RE.test(trimmed)) {\n return label;\n }\n return `\"${trimmed.replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Fix common AI-generated Mermaid syntax issues before rendering.\n * e.g. C[梳理(生條)] → C[\"梳理(生條)\"]\n */\nexport function sanitizeMermaidChart(chart: string): string {\n const stripped = stripProseFromMermaid(chart);\n let result = stripped.replace(/\\[([^\\]\"]+)\\]/g, (_match, label: string) => {\n return `[${quoteLabelContent(label)}]`;\n });\n\n result = result.replace(/\\{([^}\"]+)\\}/g, (_match, label: string) => {\n return `{${quoteLabelContent(label)}}`;\n });\n\n return result;\n}\n"],"names":["LABEL_NEEDS_QUOTING_RE","MERMAID_LINE_RE","MERMAID_EDGE_RE","stripProseFromMermaid","chart","line","trimmed","quoteLabelContent","label","sanitizeMermaidChart","result","_match"],"mappings":"AACA,MAAMA,IAAyB,cAGzBC,IACJ,wLACIC,IAAkB;AAGjB,SAASC,EAAsBC,GAAuB;AAC3D,SAAOA,EACJ,MAAM;AAAA,CAAI,EACV,OAAO,CAACC,MAAS;AAChB,UAAMC,IAAUD,EAAK,KAAA;AAKrB,WAJI,IAACC,KACDL,EAAgB,KAAKK,CAAO,KAC5BJ,EAAgB,KAAKI,CAAO,KAC5B,wBAAwB,KAAKA,CAAO,KACpC,4CAA4C,KAAKA,CAAO;AAAA,EAE9D,CAAC,EACA,KAAK;AAAA,CAAI,EACT,KAAA;AACL;AAEA,SAASC,EAAkBC,GAAuB;AAChD,QAAMF,IAAUE,EAAM,KAAA;AAItB,SAHI,CAACF,KAAWA,EAAQ,WAAW,GAAG,KAAKA,EAAQ,WAAW,GAAG,KAG7D,CAACN,EAAuB,KAAKM,CAAO,IAC/BE,IAEF,IAAIF,EAAQ,QAAQ,MAAM,KAAK,CAAC;AACzC;AAMO,SAASG,EAAqBL,GAAuB;AAE1D,MAAIM,IADaP,EAAsBC,CAAK,EACtB,QAAQ,kBAAkB,CAACO,GAAQH,MAChD,IAAID,EAAkBC,CAAK,CAAC,GACpC;AAED,SAAAE,IAASA,EAAO,QAAQ,iBAAiB,CAACC,GAAQH,MACzC,IAAID,EAAkBC,CAAK,CAAC,GACpC,GAEME;AACT;"}
@@ -0,0 +1,151 @@
1
+ import { normalizeCitation as h } from "./citationContent.js";
2
+ import { hasCitationMarkers as p } from "./messageContent.js";
3
+ const S = /* @__PURE__ */ new Set(["New session", "新会话"]), d = /^\d{1,4}$/, E = (e) => {
4
+ if (e == null) return "";
5
+ const t = new Date(typeof e == "number" && e < 1e12 ? e * 1e3 : e);
6
+ if (Number.isNaN(t.getTime())) return "";
7
+ const n = /* @__PURE__ */ new Date();
8
+ return t.getFullYear() === n.getFullYear() && t.getMonth() === n.getMonth() && t.getDate() === n.getDate() ? t.toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }) : t.toLocaleString("zh-CN", {
9
+ month: "2-digit",
10
+ day: "2-digit",
11
+ hour: "2-digit",
12
+ minute: "2-digit"
13
+ });
14
+ }, y = (e) => {
15
+ if (e == null) return "";
16
+ if (typeof e == "string") return e;
17
+ if (typeof e == "number" || typeof e == "boolean") return String(e);
18
+ if (Array.isArray(e))
19
+ return e.map((t) => {
20
+ if (typeof t == "string") return t;
21
+ if (t && typeof t == "object") {
22
+ const n = t;
23
+ if (typeof n.text == "string") return n.text;
24
+ if (typeof n.content == "string") return n.content;
25
+ }
26
+ return "";
27
+ }).filter(Boolean).join(`
28
+ `);
29
+ if (typeof e == "object") {
30
+ const t = e;
31
+ if (typeof t.text == "string") return t.text;
32
+ if (typeof t.content == "string") return t.content;
33
+ if (typeof t.answer == "string") return t.answer;
34
+ }
35
+ return "";
36
+ }, f = (e) => {
37
+ const t = e.created_at ?? e.create_time;
38
+ return typeof t == "number" ? t : void 0;
39
+ }, b = (e) => {
40
+ const t = e.filter((n) => f(n) != null);
41
+ return t.length < 2 || t.length < e.length ? e : [...e].sort((n, r) => {
42
+ const i = f(n), o = f(r);
43
+ return i - o;
44
+ });
45
+ }, w = (e) => {
46
+ const t = e.trim();
47
+ return t ? !/[\S\u4e00-\u9fff]/.test(t) : !0;
48
+ }, D = (e) => {
49
+ var o;
50
+ const t = (o = e.name) == null ? void 0 : o.trim();
51
+ if (t && !S.has(t))
52
+ return t;
53
+ const r = (e.messages ?? e.message ?? []).find((s) => s.role === "user"), i = y(r == null ? void 0 : r.content).trim();
54
+ return i ? i.length > 24 ? `${i.slice(0, 24)}…` : i : "新会话";
55
+ }, M = (e, t) => {
56
+ var r;
57
+ if (e.length === 0) return !0;
58
+ if (e.length !== 1 || ((r = e[0]) == null ? void 0 : r.role) !== "assistant") return !1;
59
+ const n = e[0].content.trim();
60
+ return n ? t != null && t.trim() ? n === t.trim() : !1 : !0;
61
+ }, g = (e) => {
62
+ const t = /* @__PURE__ */ new Set();
63
+ return e.filter((n) => {
64
+ var i;
65
+ const r = `${n.doc_id ?? ""}:${n.id ?? ""}:${((i = n.content) == null ? void 0 : i.slice(0, 80)) ?? ""}`;
66
+ return t.has(r) ? !1 : (t.add(r), !0);
67
+ });
68
+ }, m = (e) => Array.isArray(e) ? e.filter((t) => t && typeof t == "object").map((t) => h(t)) : e && typeof e == "object" ? Object.values(e).filter((t) => t && typeof t == "object").map((t) => h(t)) : [], a = (e) => {
69
+ if (e == null) return;
70
+ if (Array.isArray(e)) {
71
+ const n = m(e);
72
+ return n.length > 0 ? g(n) : void 0;
73
+ }
74
+ if (typeof e != "object" || !("chunks" in e))
75
+ return;
76
+ const t = m(e.chunks);
77
+ return t.length > 0 ? g(t) : void 0;
78
+ }, C = (e) => {
79
+ const t = [];
80
+ return e.forEach((n) => {
81
+ const r = a(n);
82
+ r && t.push(...r);
83
+ }), g(t);
84
+ }, N = (e, t) => e.slice(0, t).filter((n) => n.role === "user").length, T = (e, t, n, r, i, o) => {
85
+ if (e.role !== "assistant") return;
86
+ const s = a(e.reference);
87
+ if (s != null && s.length) return s;
88
+ const u = N(n, t);
89
+ if (u === 0) return;
90
+ const c = a(r[t]);
91
+ if (c != null && c.length) return c;
92
+ const l = a(r[u - 1]);
93
+ if (l != null && l.length) return l;
94
+ if (p(o) && i.length)
95
+ return i;
96
+ }, $ = (e = [], t = []) => {
97
+ const n = C(t), r = b(e);
98
+ return r.filter((i) => i.role === "user" || i.role === "assistant").map((i, o) => {
99
+ const s = y(i.content);
100
+ return {
101
+ id: i.id ?? `msg_${o}_${i.role}`,
102
+ role: i.role,
103
+ content: s,
104
+ citations: T(
105
+ i,
106
+ o,
107
+ r,
108
+ t,
109
+ n,
110
+ s
111
+ ),
112
+ thumbup: typeof i.thumbup == "boolean" ? i.thumbup : void 0
113
+ };
114
+ }).filter((i) => !w(i.content));
115
+ }, _ = (e, t) => {
116
+ var i, o, s, u;
117
+ if (!(t != null && t.trim()) || e.length === 0) return e;
118
+ const n = t.trim();
119
+ let r = [...e];
120
+ for (; r.length > 0 && ((i = r[0]) == null ? void 0 : i.role) === "assistant" && ((o = r[0]) == null ? void 0 : o.content.trim()) === n; )
121
+ r = r.slice(1);
122
+ for (; r.length > 1 && ((s = r[r.length - 1]) == null ? void 0 : s.role) === "assistant" && ((u = r[r.length - 1]) == null ? void 0 : u.content.trim()) === n; )
123
+ r = r.slice(0, -1);
124
+ return r;
125
+ }, A = (e) => {
126
+ const t = /* @__PURE__ */ new Map();
127
+ e.forEach((r) => {
128
+ if (r.role !== "user") return;
129
+ const i = r.content.trim();
130
+ d.test(i) && t.set(i, (t.get(i) ?? 0) + 1);
131
+ });
132
+ const n = new Set(
133
+ [...t.entries()].filter(([, r]) => r > 1).map(([r]) => r)
134
+ );
135
+ return n.size === 0 ? e : e.filter(
136
+ (r) => !(r.role === "user" && n.has(r.content.trim()) && d.test(r.content.trim()))
137
+ );
138
+ }, U = (e, t) => {
139
+ const n = _(e, t), r = A(n);
140
+ return r.some((i) => i.role === "user") ? M(r, t) ? [] : r : [];
141
+ };
142
+ export {
143
+ a as extractCitations,
144
+ E as formatSessionTime,
145
+ D as getSessionDisplayName,
146
+ M as isWelcomeOnlyMessages,
147
+ y as normalizeMessageContent,
148
+ $ as parseSessionMessages,
149
+ U as toDisplayMessages
150
+ };
151
+ //# sourceMappingURL=sessionMessages.js.map