@yushaw/sanqian-chat 0.2.42 → 0.2.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.mts +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/main/index.d.mts +1 -0
- package/dist/main/index.d.ts +1 -0
- package/dist/preload/factories.d.mts +1 -0
- package/dist/preload/factories.d.ts +1 -0
- package/dist/renderer/index.d.mts +2 -0
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.js +208 -35
- package/dist/renderer/index.mjs +208 -35
- package/package.json +2 -1
- package/src/renderer/styles/chat.css +53 -15
- package/src/renderer/styles/coreCss.ts +53 -15
- package/src/renderer/styles/safe.css +53 -15
package/dist/renderer/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { useState, useCallback, useRef, useEffect } from "react";
|
|
3
3
|
var TYPEWRITER_DELAYS = { VERY_FAST: 2, FAST: 5, NORMAL: 10, SLOW: 20 };
|
|
4
4
|
var TYPEWRITER_THRESHOLDS = { VERY_FAST: 100, FAST: 50, NORMAL: 20 };
|
|
5
|
+
var MAX_DETACHED_SNAPSHOTS = 30;
|
|
5
6
|
var findToolCallIndex = (toolCalls, toolId, toolName) => {
|
|
6
7
|
if (!toolCalls || toolCalls.length === 0) return -1;
|
|
7
8
|
if (toolId) {
|
|
@@ -19,6 +20,34 @@ var findLastBlock = (blocks, predicate) => {
|
|
|
19
20
|
}
|
|
20
21
|
return void 0;
|
|
21
22
|
};
|
|
23
|
+
function cloneBlocks(blocks) {
|
|
24
|
+
return blocks?.map((block) => ({
|
|
25
|
+
...block,
|
|
26
|
+
toolArgs: block.toolArgs ? { ...block.toolArgs } : block.toolArgs
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
function cloneMessages(messages) {
|
|
30
|
+
return messages.map((message) => ({
|
|
31
|
+
...message,
|
|
32
|
+
toolCalls: message.toolCalls?.map((toolCall) => ({
|
|
33
|
+
...toolCall,
|
|
34
|
+
args: toolCall.args ? { ...toolCall.args } : toolCall.args
|
|
35
|
+
})),
|
|
36
|
+
blocks: cloneBlocks(message.blocks),
|
|
37
|
+
filePaths: message.filePaths ? [...message.filePaths] : message.filePaths,
|
|
38
|
+
attachedResources: message.attachedResources?.map((resource) => ({ ...resource }))
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
function normalizeConversationMessages(messages) {
|
|
42
|
+
return messages.filter((message) => message.role !== "tool").map((message) => ({
|
|
43
|
+
...message,
|
|
44
|
+
isStreaming: false,
|
|
45
|
+
isComplete: true
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
function delay(ms) {
|
|
49
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
|
+
}
|
|
22
51
|
var CHAT_CAPABILITIES = {
|
|
23
52
|
conversationSwitch: {
|
|
24
53
|
supportsCancelActiveStream: true,
|
|
@@ -39,6 +68,7 @@ function useChat(options) {
|
|
|
39
68
|
const isMountedRef = useRef(true);
|
|
40
69
|
const messagesRef = useRef(messages);
|
|
41
70
|
const conversationIdRef = useRef(conversationId);
|
|
71
|
+
const detachedConversationSnapshotsRef = useRef(/* @__PURE__ */ new Map());
|
|
42
72
|
const currentRunIdRef = useRef(null);
|
|
43
73
|
const pendingInterruptStreamIdRef = useRef(null);
|
|
44
74
|
const currentAgentIdRef = useRef(null);
|
|
@@ -133,11 +163,49 @@ function useChat(options) {
|
|
|
133
163
|
pendingCancelRef.current = false;
|
|
134
164
|
pendingCancelFnRef.current = null;
|
|
135
165
|
}, []);
|
|
166
|
+
const setDetachedConversationSnapshot = useCallback((id, snapshot) => {
|
|
167
|
+
if (!id || snapshot.length === 0) return;
|
|
168
|
+
const map = detachedConversationSnapshotsRef.current;
|
|
169
|
+
if (map.has(id)) {
|
|
170
|
+
map.delete(id);
|
|
171
|
+
}
|
|
172
|
+
map.set(id, cloneMessages(snapshot));
|
|
173
|
+
while (map.size > MAX_DETACHED_SNAPSHOTS) {
|
|
174
|
+
const oldestKey = map.keys().next().value;
|
|
175
|
+
if (!oldestKey) break;
|
|
176
|
+
map.delete(oldestKey);
|
|
177
|
+
}
|
|
178
|
+
}, []);
|
|
136
179
|
const detachActiveStream = useCallback((detachContext) => {
|
|
137
180
|
const context = activeStreamContextRef.current;
|
|
138
181
|
if (!context || context.detached) {
|
|
139
182
|
return;
|
|
140
183
|
}
|
|
184
|
+
const detachedSnapshot = cloneMessages(normalizeConversationMessages(messagesRef.current));
|
|
185
|
+
const detachedAssistantMessageIndex = detachedSnapshot.findIndex(
|
|
186
|
+
(message) => message.id === context.assistantMessageId
|
|
187
|
+
);
|
|
188
|
+
if (detachedAssistantMessageIndex !== -1) {
|
|
189
|
+
const detachedAssistantMessage = detachedSnapshot[detachedAssistantMessageIndex];
|
|
190
|
+
const detachedContent = fullContentRef.current || displayedContentRef.current || detachedAssistantMessage.content;
|
|
191
|
+
detachedSnapshot[detachedAssistantMessageIndex] = {
|
|
192
|
+
...detachedAssistantMessage,
|
|
193
|
+
content: detachedContent,
|
|
194
|
+
finalContent: detachedContent || detachedAssistantMessage.finalContent,
|
|
195
|
+
blocks: currentBlocksRef.current.length > 0 ? cloneBlocks(currentBlocksRef.current) : detachedAssistantMessage.blocks,
|
|
196
|
+
thinking: detachedAssistantMessage.thinking?.trimEnd(),
|
|
197
|
+
currentThinking: void 0,
|
|
198
|
+
isStreaming: false,
|
|
199
|
+
isThinkingStreaming: false,
|
|
200
|
+
isThinkingPaused: false,
|
|
201
|
+
isToolCallsStreaming: false,
|
|
202
|
+
isComplete: true
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (detachedSnapshot.length > 0) {
|
|
206
|
+
context.detachedSnapshot = detachedSnapshot;
|
|
207
|
+
setDetachedConversationSnapshot(context.conversationId, detachedSnapshot);
|
|
208
|
+
}
|
|
141
209
|
context.detached = true;
|
|
142
210
|
context.detachContext = detachContext;
|
|
143
211
|
if (typewriterIntervalRef.current) {
|
|
@@ -153,19 +221,72 @@ function useChat(options) {
|
|
|
153
221
|
pendingInterruptStreamIdRef.current = null;
|
|
154
222
|
clearPendingCancel();
|
|
155
223
|
suppressStreamRef.current = false;
|
|
156
|
-
}, [clearPendingCancel, resetStreamBuffers]);
|
|
224
|
+
}, [clearPendingCancel, resetStreamBuffers, setDetachedConversationSnapshot]);
|
|
225
|
+
const refreshConversationIfVisible = useCallback(async (id) => {
|
|
226
|
+
if (!id || conversationIdRef.current !== id) return false;
|
|
227
|
+
try {
|
|
228
|
+
const detail = await adapter.getConversation(id);
|
|
229
|
+
if (!isMountedRef.current || conversationIdRef.current !== id) return false;
|
|
230
|
+
const normalizedMessages = normalizeConversationMessages(detail.messages);
|
|
231
|
+
if (normalizedMessages.length === 0) return false;
|
|
232
|
+
detachedConversationSnapshotsRef.current.delete(id);
|
|
233
|
+
setMessages(normalizedMessages);
|
|
234
|
+
setConversationTitle(detail.title ?? null);
|
|
235
|
+
return true;
|
|
236
|
+
} catch (refreshError) {
|
|
237
|
+
console.warn("[useChat] Failed to refresh conversation after detached stream completion:", refreshError);
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}, [adapter]);
|
|
241
|
+
const refreshConversationIfVisibleWithRetry = useCallback((id, retryDelaysMs) => {
|
|
242
|
+
if (!id) return;
|
|
243
|
+
void (async () => {
|
|
244
|
+
for (const retryDelayMs of retryDelaysMs) {
|
|
245
|
+
if (retryDelayMs > 0) {
|
|
246
|
+
await delay(retryDelayMs);
|
|
247
|
+
}
|
|
248
|
+
if (!isMountedRef.current || conversationIdRef.current !== id) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const refreshed = await refreshConversationIfVisible(id);
|
|
252
|
+
if (refreshed) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
})();
|
|
257
|
+
}, [refreshConversationIfVisible]);
|
|
157
258
|
const handleStreamEvent = useCallback((event, streamContext) => {
|
|
158
259
|
if (!isMountedRef.current) return;
|
|
159
260
|
const isActiveStream = activeStreamContextRef.current?.token === streamContext.token && !streamContext.detached;
|
|
160
261
|
if (!isActiveStream) {
|
|
161
262
|
if (event.type === "done" && event.conversationId && !streamContext.didReportConversationChange) {
|
|
263
|
+
if (streamContext.conversationId && streamContext.conversationId !== event.conversationId) {
|
|
264
|
+
detachedConversationSnapshotsRef.current.delete(streamContext.conversationId);
|
|
265
|
+
}
|
|
266
|
+
streamContext.conversationId = event.conversationId;
|
|
162
267
|
streamContext.didReportConversationChange = true;
|
|
268
|
+
if (streamContext.detachedSnapshot?.length) {
|
|
269
|
+
setDetachedConversationSnapshot(event.conversationId, streamContext.detachedSnapshot);
|
|
270
|
+
}
|
|
163
271
|
onConversationChange?.(event.conversationId, event.title, {
|
|
164
272
|
source: "background",
|
|
165
273
|
streamToken: streamContext.token,
|
|
166
274
|
detached: true,
|
|
167
275
|
detachContext: streamContext.detachContext
|
|
168
276
|
});
|
|
277
|
+
refreshConversationIfVisibleWithRetry(event.conversationId, [0, 300, 900]);
|
|
278
|
+
} else if (event.type === "done" && event.conversationId && streamContext.didReportConversationChange) {
|
|
279
|
+
if (streamContext.detachedSnapshot?.length) {
|
|
280
|
+
setDetachedConversationSnapshot(event.conversationId, streamContext.detachedSnapshot);
|
|
281
|
+
}
|
|
282
|
+
refreshConversationIfVisibleWithRetry(event.conversationId, [0, 300, 900]);
|
|
283
|
+
}
|
|
284
|
+
const isTerminalEvent = event.type === "done" || event.type === "cancelled" || event.type === "error";
|
|
285
|
+
if (isTerminalEvent) {
|
|
286
|
+
streamContext.detachedSnapshot = void 0;
|
|
287
|
+
}
|
|
288
|
+
if (isTerminalEvent && activeStreamContextRef.current?.token === streamContext.token) {
|
|
289
|
+
activeStreamContextRef.current = null;
|
|
169
290
|
}
|
|
170
291
|
return;
|
|
171
292
|
}
|
|
@@ -250,9 +371,9 @@ function useChat(options) {
|
|
|
250
371
|
return updated;
|
|
251
372
|
});
|
|
252
373
|
const qLen = tokenQueueRef.current.length;
|
|
253
|
-
const
|
|
374
|
+
const delay2 = qLen > TYPEWRITER_THRESHOLDS.VERY_FAST ? TYPEWRITER_DELAYS.VERY_FAST : qLen > TYPEWRITER_THRESHOLDS.FAST ? TYPEWRITER_DELAYS.FAST : qLen > TYPEWRITER_THRESHOLDS.NORMAL ? TYPEWRITER_DELAYS.NORMAL : TYPEWRITER_DELAYS.SLOW;
|
|
254
375
|
if (typewriterIntervalRef.current !== null) {
|
|
255
|
-
typewriterIntervalRef.current = setTimeout(tick,
|
|
376
|
+
typewriterIntervalRef.current = setTimeout(tick, delay2);
|
|
256
377
|
}
|
|
257
378
|
} else {
|
|
258
379
|
typewriterIntervalRef.current = null;
|
|
@@ -515,6 +636,7 @@ function useChat(options) {
|
|
|
515
636
|
});
|
|
516
637
|
resetStreamBuffers();
|
|
517
638
|
if (event.conversationId) {
|
|
639
|
+
streamContext.conversationId = event.conversationId;
|
|
518
640
|
streamContext.didReportConversationChange = true;
|
|
519
641
|
setConversationId(event.conversationId);
|
|
520
642
|
onConversationChange?.(event.conversationId, event.title, {
|
|
@@ -615,7 +737,7 @@ function useChat(options) {
|
|
|
615
737
|
break;
|
|
616
738
|
}
|
|
617
739
|
}
|
|
618
|
-
}, [clearPendingCancel, flushTypewriter, onConversationChange, onError, resetStreamBuffers]);
|
|
740
|
+
}, [clearPendingCancel, flushTypewriter, onConversationChange, onError, refreshConversationIfVisibleWithRetry, resetStreamBuffers, setDetachedConversationSnapshot]);
|
|
619
741
|
const trySendMessage = useCallback(async (content, sendOptions) => {
|
|
620
742
|
const trimmedContent = content.trim();
|
|
621
743
|
const hasAttachedResources = (sendOptions?.attachedResources?.length ?? 0) > 0;
|
|
@@ -651,6 +773,7 @@ function useChat(options) {
|
|
|
651
773
|
const streamContext = {
|
|
652
774
|
token: crypto.randomUUID(),
|
|
653
775
|
assistantMessageId: assistantMessage.id,
|
|
776
|
+
conversationId: conversationIdRef.current,
|
|
654
777
|
detached: false,
|
|
655
778
|
didReportConversationChange: false
|
|
656
779
|
};
|
|
@@ -773,6 +896,7 @@ function useChat(options) {
|
|
|
773
896
|
activeStreamContextRef.current = null;
|
|
774
897
|
clearPendingCancel();
|
|
775
898
|
suppressStreamRef.current = false;
|
|
899
|
+
detachedConversationSnapshotsRef.current.clear();
|
|
776
900
|
}, [clearPendingCancel, resetStreamBuffers]);
|
|
777
901
|
const loadConversation = useCallback(async (id, optionsArg) => {
|
|
778
902
|
const cancelActiveStream = optionsArg?.cancelActiveStream ?? true;
|
|
@@ -789,11 +913,16 @@ function useChat(options) {
|
|
|
789
913
|
setError(null);
|
|
790
914
|
const detail = await adapter.getConversation(id);
|
|
791
915
|
if (!isMountedRef.current) return;
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
916
|
+
const normalizedMessages = normalizeConversationMessages(detail.messages);
|
|
917
|
+
const detachedSnapshot = detachedConversationSnapshotsRef.current.get(id);
|
|
918
|
+
const shouldUseDetachedSnapshot = normalizedMessages.length === 0 && !!detachedSnapshot?.length;
|
|
919
|
+
const nextMessages = shouldUseDetachedSnapshot ? cloneMessages(detachedSnapshot) : normalizedMessages;
|
|
920
|
+
if (!shouldUseDetachedSnapshot) {
|
|
921
|
+
detachedConversationSnapshotsRef.current.delete(id);
|
|
922
|
+
} else {
|
|
923
|
+
refreshConversationIfVisibleWithRetry(id, [250, 800, 1800]);
|
|
924
|
+
}
|
|
925
|
+
setMessages(nextMessages);
|
|
797
926
|
setConversationId(detail.id);
|
|
798
927
|
setConversationTitle(detail.title);
|
|
799
928
|
currentAgentIdRef.current = detail.agentId ?? currentAgentIdRef.current;
|
|
@@ -804,7 +933,7 @@ function useChat(options) {
|
|
|
804
933
|
} finally {
|
|
805
934
|
if (isMountedRef.current) setIsLoading(false);
|
|
806
935
|
}
|
|
807
|
-
}, [adapter, detachActiveStream, onError, stopStreaming]);
|
|
936
|
+
}, [adapter, detachActiveStream, onError, refreshConversationIfVisibleWithRetry, stopStreaming]);
|
|
808
937
|
const newConversation = useCallback((optionsArg) => {
|
|
809
938
|
const cancelActiveStream = optionsArg?.cancelActiveStream ?? true;
|
|
810
939
|
const activeStream = activeStreamContextRef.current;
|
|
@@ -1063,6 +1192,7 @@ var CHAT_UI_STRINGS = {
|
|
|
1063
1192
|
embedWindow: "Embed",
|
|
1064
1193
|
collapseSidebar: "Collapse",
|
|
1065
1194
|
history: "History",
|
|
1195
|
+
related: "RELATED",
|
|
1066
1196
|
// Resource
|
|
1067
1197
|
remove: "Remove"
|
|
1068
1198
|
},
|
|
@@ -1122,6 +1252,7 @@ var CHAT_UI_STRINGS = {
|
|
|
1122
1252
|
embedWindow: "\u5D4C\u5165",
|
|
1123
1253
|
collapseSidebar: "\u6536\u8D77",
|
|
1124
1254
|
history: "\u5386\u53F2",
|
|
1255
|
+
related: "\u76F8\u5173",
|
|
1125
1256
|
// Resource
|
|
1126
1257
|
remove: "\u79FB\u9664"
|
|
1127
1258
|
}
|
|
@@ -1273,13 +1404,13 @@ function useConnection(options) {
|
|
|
1273
1404
|
const isFirstAttempt = status === "disconnected" && reconnectAttemptsRef.current === 0;
|
|
1274
1405
|
const baseDelay = isFirstAttempt ? 0 : Math.min(500 * Math.pow(2, reconnectAttemptsRef.current), 5e3);
|
|
1275
1406
|
const jitter = isFirstAttempt ? 0 : Math.random() * 500;
|
|
1276
|
-
const
|
|
1407
|
+
const delay2 = baseDelay + jitter;
|
|
1277
1408
|
const timer = setTimeout(() => {
|
|
1278
1409
|
if (!isMountedRef.current) return;
|
|
1279
1410
|
reconnectAttemptsRef.current++;
|
|
1280
1411
|
adapter.connect().catch(() => {
|
|
1281
1412
|
});
|
|
1282
|
-
},
|
|
1413
|
+
}, delay2);
|
|
1283
1414
|
return () => clearTimeout(timer);
|
|
1284
1415
|
}, [status, autoConnect, adapter]);
|
|
1285
1416
|
useEffect3(() => {
|
|
@@ -1827,13 +1958,15 @@ code {
|
|
|
1827
1958
|
border-radius: 6px !important;
|
|
1828
1959
|
overflow: visible !important;
|
|
1829
1960
|
background: transparent !important;
|
|
1830
|
-
margin:
|
|
1961
|
+
margin: 4px 0 !important;
|
|
1962
|
+
padding: 0 !important;
|
|
1963
|
+
gap: 0 !important;
|
|
1831
1964
|
}
|
|
1832
1965
|
|
|
1833
1966
|
[data-streamdown="code-block-header"] {
|
|
1834
1967
|
position: absolute !important;
|
|
1835
|
-
top:
|
|
1836
|
-
left:
|
|
1968
|
+
top: 4px !important;
|
|
1969
|
+
left: 10px !important;
|
|
1837
1970
|
right: auto !important;
|
|
1838
1971
|
z-index: 10;
|
|
1839
1972
|
padding: 0 !important;
|
|
@@ -1846,8 +1979,8 @@ code {
|
|
|
1846
1979
|
|
|
1847
1980
|
[data-streamdown="code-block-actions"] {
|
|
1848
1981
|
position: absolute !important;
|
|
1849
|
-
top:
|
|
1850
|
-
right:
|
|
1982
|
+
top: 4px !important;
|
|
1983
|
+
right: 6px !important;
|
|
1851
1984
|
z-index: 11;
|
|
1852
1985
|
display: flex !important;
|
|
1853
1986
|
align-items: center;
|
|
@@ -1867,7 +2000,7 @@ code {
|
|
|
1867
2000
|
|
|
1868
2001
|
[data-streamdown="code-block-header"] > span:first-child {
|
|
1869
2002
|
display: inline-flex;
|
|
1870
|
-
font-size:
|
|
2003
|
+
font-size: 10px;
|
|
1871
2004
|
color: var(--color-muted);
|
|
1872
2005
|
text-transform: lowercase;
|
|
1873
2006
|
}
|
|
@@ -1882,7 +2015,7 @@ code {
|
|
|
1882
2015
|
/* Normalize action buttons for both streamdown v1 (header>div) and v2 (code-block-actions). */
|
|
1883
2016
|
[data-streamdown="code-block-header"] button,
|
|
1884
2017
|
[data-streamdown="code-block-actions"] button {
|
|
1885
|
-
padding:
|
|
2018
|
+
padding: 2px !important;
|
|
1886
2019
|
border: none !important;
|
|
1887
2020
|
border-radius: 4px !important;
|
|
1888
2021
|
background: var(--color-surface) !important;
|
|
@@ -1899,8 +2032,8 @@ code {
|
|
|
1899
2032
|
[data-streamdown="code-block-header"] svg,
|
|
1900
2033
|
[data-streamdown="code-block-actions"] svg {
|
|
1901
2034
|
color: var(--color-muted) !important;
|
|
1902
|
-
width:
|
|
1903
|
-
height:
|
|
2035
|
+
width: 11px !important;
|
|
2036
|
+
height: 11px !important;
|
|
1904
2037
|
}
|
|
1905
2038
|
|
|
1906
2039
|
[data-streamdown="code-block-header"] button:hover svg,
|
|
@@ -1909,18 +2042,33 @@ code {
|
|
|
1909
2042
|
}
|
|
1910
2043
|
|
|
1911
2044
|
[data-streamdown="code-block-body"] {
|
|
1912
|
-
padding:
|
|
2045
|
+
padding: 18px 12px 8px !important;
|
|
1913
2046
|
background: rgba(0, 0, 0, 0.02) !important;
|
|
1914
2047
|
border-radius: 6px !important;
|
|
2048
|
+
border: none !important;
|
|
2049
|
+
box-shadow: none !important;
|
|
1915
2050
|
font-size: 13px !important;
|
|
1916
2051
|
line-height: 1.5 !important;
|
|
1917
2052
|
white-space: pre !important;
|
|
1918
2053
|
overflow-x: auto !important;
|
|
1919
2054
|
}
|
|
1920
2055
|
|
|
2056
|
+
[data-streamdown="code-block-body"] pre {
|
|
2057
|
+
margin: 0 !important;
|
|
2058
|
+
padding: 0 !important;
|
|
2059
|
+
border: none !important;
|
|
2060
|
+
background: transparent !important;
|
|
2061
|
+
border-radius: 0 !important;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
1921
2064
|
[data-streamdown="code-block-body"] code {
|
|
1922
2065
|
white-space: pre !important;
|
|
1923
2066
|
display: block !important;
|
|
2067
|
+
color: var(--color-text);
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
[data-streamdown="code-block-body"] code > span {
|
|
2071
|
+
display: block;
|
|
1924
2072
|
}
|
|
1925
2073
|
|
|
1926
2074
|
.dark [data-streamdown="code-block-body"],
|
|
@@ -1934,17 +2082,38 @@ code {
|
|
|
1934
2082
|
|
|
1935
2083
|
[data-streamdown="code-block-body"],
|
|
1936
2084
|
[data-streamdown="code-block-body"] code {
|
|
1937
|
-
|
|
1938
|
-
opacity: 0.85;
|
|
2085
|
+
opacity: 1;
|
|
1939
2086
|
}
|
|
1940
2087
|
|
|
1941
2088
|
[data-streamdown="code-block-body"] code span[style] {
|
|
1942
2089
|
background-color: transparent !important;
|
|
1943
2090
|
}
|
|
1944
2091
|
|
|
1945
|
-
|
|
1946
|
-
:
|
|
1947
|
-
|
|
2092
|
+
[data-streamdown="code-block-body"] pre[style*="--sdm-bg"] {
|
|
2093
|
+
background-color: var(--sdm-bg) !important;
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
.dark [data-streamdown="code-block-body"] pre[style*="--sdm-bg"],
|
|
2097
|
+
:root.dark [data-streamdown="code-block-body"] pre[style*="--sdm-bg"] {
|
|
2098
|
+
background-color: var(--shiki-dark-bg, var(--sdm-bg)) !important;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
[data-streamdown="code-block-body"] code span[style*="--sdm-c"] {
|
|
2102
|
+
color: var(--sdm-c) !important;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
.dark [data-streamdown="code-block-body"] code span[style*="--sdm-c"],
|
|
2106
|
+
:root.dark [data-streamdown="code-block-body"] code span[style*="--sdm-c"] {
|
|
2107
|
+
color: var(--shiki-dark, var(--sdm-c)) !important;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
[data-streamdown="code-block-body"] code span[style*="--sdm-tbg"] {
|
|
2111
|
+
background-color: var(--sdm-tbg) !important;
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
.dark [data-streamdown="code-block-body"] code span[style*="--sdm-tbg"],
|
|
2115
|
+
:root.dark [data-streamdown="code-block-body"] code span[style*="--sdm-tbg"] {
|
|
2116
|
+
background-color: var(--shiki-dark-bg, var(--sdm-tbg)) !important;
|
|
1948
2117
|
}
|
|
1949
2118
|
|
|
1950
2119
|
[data-streamdown="table-wrapper"].my-4 {
|
|
@@ -6945,6 +7114,7 @@ import { memo as memo6 } from "react";
|
|
|
6945
7114
|
// src/renderer/renderers/MarkdownRenderer.tsx
|
|
6946
7115
|
import { memo as memo3, useMemo as useMemo5, useCallback as useCallback11 } from "react";
|
|
6947
7116
|
import { Streamdown, defaultRehypePlugins } from "streamdown";
|
|
7117
|
+
import { code as streamdownCode } from "@streamdown/code";
|
|
6948
7118
|
import { harden } from "rehype-harden";
|
|
6949
7119
|
import remarkGfm from "remark-gfm";
|
|
6950
7120
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
@@ -7003,6 +7173,7 @@ var MarkdownRenderer = memo3(function MarkdownRenderer2({
|
|
|
7003
7173
|
const remarkPlugins = useMemo5(() => {
|
|
7004
7174
|
return [remarkGfm];
|
|
7005
7175
|
}, []);
|
|
7176
|
+
const streamdownPlugins = useMemo5(() => ({ code: streamdownCode }), []);
|
|
7006
7177
|
const customComponents = useMemo5(() => {
|
|
7007
7178
|
const comps = {};
|
|
7008
7179
|
comps.p = ({ children }) => {
|
|
@@ -7055,6 +7226,7 @@ var MarkdownRenderer = memo3(function MarkdownRenderer2({
|
|
|
7055
7226
|
{
|
|
7056
7227
|
remarkPlugins,
|
|
7057
7228
|
rehypePlugins,
|
|
7229
|
+
plugins: streamdownPlugins,
|
|
7058
7230
|
components: customComponents,
|
|
7059
7231
|
mode: isStreaming ? "streaming" : "static",
|
|
7060
7232
|
isAnimating: isStreaming,
|
|
@@ -7790,7 +7962,7 @@ var SanqianChatMessage = memo6(function SanqianChatMessage2({ message }) {
|
|
|
7790
7962
|
"div",
|
|
7791
7963
|
{
|
|
7792
7964
|
className: `message-bubble-wrapper ${isUser ? "rounded-2xl shadow-sm bg-[var(--chat-accent)] text-white px-4 py-3 whitespace-pre-wrap break-words" : "text-[var(--chat-text)] break-words"}`,
|
|
7793
|
-
children: isUser ? /* @__PURE__ */ jsx9("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content ? /* @__PURE__ */ jsx9(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-
|
|
7965
|
+
children: isUser ? /* @__PURE__ */ jsx9("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content ? /* @__PURE__ */ jsx9(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-0" }) : showStreamingPlaceholder ? /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 text-[var(--chat-muted)] italic min-h-[1.5rem]", children: [
|
|
7794
7966
|
/* @__PURE__ */ jsxs4("div", { className: "flex gap-1 items-center", children: [
|
|
7795
7967
|
/* @__PURE__ */ jsx9("span", { className: "w-1.5 h-1.5 bg-[var(--chat-accent)] rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
|
|
7796
7968
|
/* @__PURE__ */ jsx9("span", { className: "w-1.5 h-1.5 bg-[var(--chat-accent)] rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
|
|
@@ -10001,7 +10173,7 @@ var FloatingChat = memo15(function FloatingChat2({
|
|
|
10001
10173
|
"div",
|
|
10002
10174
|
{
|
|
10003
10175
|
className: `message-bubble-wrapper ${isUser ? "rounded-2xl shadow-sm bg-[var(--chat-accent)] text-white px-4 py-3 whitespace-pre-wrap break-words" : "text-[var(--chat-text)] break-words"}`,
|
|
10004
|
-
children: isUser ? /* @__PURE__ */ jsx22("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && (renderContent ? /* @__PURE__ */ jsx22("div", { className: "prose prose-chat dark:prose-invert max-w-none px-
|
|
10176
|
+
children: isUser ? /* @__PURE__ */ jsx22("span", { className: "whitespace-pre-wrap", children: message.content }) : message.content && (renderContent ? /* @__PURE__ */ jsx22("div", { className: "prose prose-chat dark:prose-invert max-w-none px-0", children: renderContent(message.content, message.isStreaming ?? false) }) : /* @__PURE__ */ jsx22(MarkdownRenderer, { content: message.content, isStreaming: message.isStreaming, className: "px-0" }))
|
|
10005
10177
|
}
|
|
10006
10178
|
) }) }) });
|
|
10007
10179
|
},
|
|
@@ -10239,7 +10411,7 @@ var HistoryList = memo16(function HistoryList2({
|
|
|
10239
10411
|
deleteText: "#ef4444",
|
|
10240
10412
|
loadingDot: isDarkMode ? "rgba(255, 255, 255, 0.3)" : "rgba(0, 0, 0, 0.2)"
|
|
10241
10413
|
};
|
|
10242
|
-
const loadingDots = /* @__PURE__ */ jsx23("div", { style: { display: "flex", justifyContent: "center", padding: "1.5rem 0" }, children: /* @__PURE__ */ jsx23("div", { style: { display: "flex", gap: "0.25rem" }, children: [0, 150, 300].map((
|
|
10414
|
+
const loadingDots = /* @__PURE__ */ jsx23("div", { style: { display: "flex", justifyContent: "center", padding: "1.5rem 0" }, children: /* @__PURE__ */ jsx23("div", { style: { display: "flex", gap: "0.25rem" }, children: [0, 150, 300].map((delay2) => /* @__PURE__ */ jsx23(
|
|
10243
10415
|
"span",
|
|
10244
10416
|
{
|
|
10245
10417
|
style: {
|
|
@@ -10248,10 +10420,10 @@ var HistoryList = memo16(function HistoryList2({
|
|
|
10248
10420
|
borderRadius: "50%",
|
|
10249
10421
|
background: colors.loadingDot,
|
|
10250
10422
|
animation: "bounce 1s infinite",
|
|
10251
|
-
animationDelay: `${
|
|
10423
|
+
animationDelay: `${delay2}ms`
|
|
10252
10424
|
}
|
|
10253
10425
|
},
|
|
10254
|
-
|
|
10426
|
+
delay2
|
|
10255
10427
|
)) }) });
|
|
10256
10428
|
if (isLoading && conversations.length === 0) {
|
|
10257
10429
|
return loadingDots;
|
|
@@ -10264,7 +10436,7 @@ var HistoryList = memo16(function HistoryList2({
|
|
|
10264
10436
|
const isSelected = conv.id === selectedId;
|
|
10265
10437
|
const isHovered = conv.id === hoveredId;
|
|
10266
10438
|
const isHighlighted = isConversationHighlighted?.(conv) === true;
|
|
10267
|
-
const resolvedHighlightLabel = isHighlighted ? (typeof highlightedLabel === "function" ? highlightedLabel(conv) : highlightedLabel) ?? "RELATED" : null;
|
|
10439
|
+
const resolvedHighlightLabel = isHighlighted ? (typeof highlightedLabel === "function" ? highlightedLabel(conv) : highlightedLabel) ?? strings.related ?? "RELATED" : null;
|
|
10268
10440
|
return /* @__PURE__ */ jsxs17(
|
|
10269
10441
|
"div",
|
|
10270
10442
|
{
|
|
@@ -10915,7 +11087,7 @@ var CompactChat = memo18(function CompactChat2({
|
|
|
10915
11087
|
content: message.content,
|
|
10916
11088
|
isStreaming: message.isStreaming,
|
|
10917
11089
|
linkHandler,
|
|
10918
|
-
className: "px-
|
|
11090
|
+
className: "px-0"
|
|
10919
11091
|
}
|
|
10920
11092
|
)
|
|
10921
11093
|
}
|
|
@@ -11115,7 +11287,8 @@ var CompactChat = memo18(function CompactChat2({
|
|
|
11115
11287
|
loadMore: mergedStrings.loadMore,
|
|
11116
11288
|
today: mergedStrings.today,
|
|
11117
11289
|
yesterday: mergedStrings.yesterday,
|
|
11118
|
-
delete: mergedStrings.delete
|
|
11290
|
+
delete: mergedStrings.delete,
|
|
11291
|
+
related: mergedStrings.related
|
|
11119
11292
|
}
|
|
11120
11293
|
}
|
|
11121
11294
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yushaw/sanqian-chat",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"description": "Floating chat window SDK for Sanqian AI Assistant",
|
|
5
5
|
"main": "./dist/main/index.js",
|
|
6
6
|
"types": "./dist/main/index.d.ts",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"test:watch": "vitest"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@streamdown/code": "^1.0.3",
|
|
47
48
|
"@yushaw/sanqian-sdk": "^0.3.26",
|
|
48
49
|
"react-virtuoso": "^4.15.0",
|
|
49
50
|
"rehype-harden": "^1.1.6",
|
|
@@ -408,13 +408,15 @@ code {
|
|
|
408
408
|
border-radius: 6px !important;
|
|
409
409
|
overflow: visible !important;
|
|
410
410
|
background: transparent !important;
|
|
411
|
-
margin:
|
|
411
|
+
margin: 4px 0 !important;
|
|
412
|
+
padding: 0 !important;
|
|
413
|
+
gap: 0 !important;
|
|
412
414
|
}
|
|
413
415
|
|
|
414
416
|
[data-streamdown="code-block-header"] {
|
|
415
417
|
position: absolute !important;
|
|
416
|
-
top:
|
|
417
|
-
left:
|
|
418
|
+
top: 4px !important;
|
|
419
|
+
left: 10px !important;
|
|
418
420
|
right: auto !important;
|
|
419
421
|
z-index: 10;
|
|
420
422
|
padding: 0 !important;
|
|
@@ -427,8 +429,8 @@ code {
|
|
|
427
429
|
|
|
428
430
|
[data-streamdown="code-block-actions"] {
|
|
429
431
|
position: absolute !important;
|
|
430
|
-
top:
|
|
431
|
-
right:
|
|
432
|
+
top: 4px !important;
|
|
433
|
+
right: 6px !important;
|
|
432
434
|
z-index: 11;
|
|
433
435
|
display: flex !important;
|
|
434
436
|
align-items: center;
|
|
@@ -448,7 +450,7 @@ code {
|
|
|
448
450
|
|
|
449
451
|
[data-streamdown="code-block-header"] > span:first-child {
|
|
450
452
|
display: inline-flex;
|
|
451
|
-
font-size:
|
|
453
|
+
font-size: 10px;
|
|
452
454
|
color: var(--color-muted);
|
|
453
455
|
text-transform: lowercase;
|
|
454
456
|
}
|
|
@@ -463,7 +465,7 @@ code {
|
|
|
463
465
|
/* Normalize action buttons for both streamdown v1 (header>div) and v2 (code-block-actions). */
|
|
464
466
|
[data-streamdown="code-block-header"] button,
|
|
465
467
|
[data-streamdown="code-block-actions"] button {
|
|
466
|
-
padding:
|
|
468
|
+
padding: 2px !important;
|
|
467
469
|
border: none !important;
|
|
468
470
|
border-radius: 4px !important;
|
|
469
471
|
background: var(--color-surface) !important;
|
|
@@ -480,8 +482,8 @@ code {
|
|
|
480
482
|
[data-streamdown="code-block-header"] svg,
|
|
481
483
|
[data-streamdown="code-block-actions"] svg {
|
|
482
484
|
color: var(--color-muted) !important;
|
|
483
|
-
width:
|
|
484
|
-
height:
|
|
485
|
+
width: 11px !important;
|
|
486
|
+
height: 11px !important;
|
|
485
487
|
}
|
|
486
488
|
|
|
487
489
|
[data-streamdown="code-block-header"] button:hover svg,
|
|
@@ -490,18 +492,33 @@ code {
|
|
|
490
492
|
}
|
|
491
493
|
|
|
492
494
|
[data-streamdown="code-block-body"] {
|
|
493
|
-
padding:
|
|
495
|
+
padding: 18px 12px 8px !important;
|
|
494
496
|
background: rgba(0, 0, 0, 0.02) !important;
|
|
495
497
|
border-radius: 6px !important;
|
|
498
|
+
border: none !important;
|
|
499
|
+
box-shadow: none !important;
|
|
496
500
|
font-size: 13px !important;
|
|
497
501
|
line-height: 1.5 !important;
|
|
498
502
|
white-space: pre !important;
|
|
499
503
|
overflow-x: auto !important;
|
|
500
504
|
}
|
|
501
505
|
|
|
506
|
+
[data-streamdown="code-block-body"] pre {
|
|
507
|
+
margin: 0 !important;
|
|
508
|
+
padding: 0 !important;
|
|
509
|
+
border: none !important;
|
|
510
|
+
background: transparent !important;
|
|
511
|
+
border-radius: 0 !important;
|
|
512
|
+
}
|
|
513
|
+
|
|
502
514
|
[data-streamdown="code-block-body"] code {
|
|
503
515
|
white-space: pre !important;
|
|
504
516
|
display: block !important;
|
|
517
|
+
color: var(--color-text);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
[data-streamdown="code-block-body"] code > span {
|
|
521
|
+
display: block;
|
|
505
522
|
}
|
|
506
523
|
|
|
507
524
|
.dark [data-streamdown="code-block-body"],
|
|
@@ -515,17 +532,38 @@ code {
|
|
|
515
532
|
|
|
516
533
|
[data-streamdown="code-block-body"],
|
|
517
534
|
[data-streamdown="code-block-body"] code {
|
|
518
|
-
|
|
519
|
-
opacity: 0.85;
|
|
535
|
+
opacity: 1;
|
|
520
536
|
}
|
|
521
537
|
|
|
522
538
|
[data-streamdown="code-block-body"] code span[style] {
|
|
523
539
|
background-color: transparent !important;
|
|
524
540
|
}
|
|
525
541
|
|
|
526
|
-
|
|
527
|
-
:
|
|
528
|
-
|
|
542
|
+
[data-streamdown="code-block-body"] pre[style*="--sdm-bg"] {
|
|
543
|
+
background-color: var(--sdm-bg) !important;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.dark [data-streamdown="code-block-body"] pre[style*="--sdm-bg"],
|
|
547
|
+
:root.dark [data-streamdown="code-block-body"] pre[style*="--sdm-bg"] {
|
|
548
|
+
background-color: var(--shiki-dark-bg, var(--sdm-bg)) !important;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
[data-streamdown="code-block-body"] code span[style*="--sdm-c"] {
|
|
552
|
+
color: var(--sdm-c) !important;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.dark [data-streamdown="code-block-body"] code span[style*="--sdm-c"],
|
|
556
|
+
:root.dark [data-streamdown="code-block-body"] code span[style*="--sdm-c"] {
|
|
557
|
+
color: var(--shiki-dark, var(--sdm-c)) !important;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
[data-streamdown="code-block-body"] code span[style*="--sdm-tbg"] {
|
|
561
|
+
background-color: var(--sdm-tbg) !important;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.dark [data-streamdown="code-block-body"] code span[style*="--sdm-tbg"],
|
|
565
|
+
:root.dark [data-streamdown="code-block-body"] code span[style*="--sdm-tbg"] {
|
|
566
|
+
background-color: var(--shiki-dark-bg, var(--sdm-tbg)) !important;
|
|
529
567
|
}
|
|
530
568
|
|
|
531
569
|
[data-streamdown="table-wrapper"].my-4 {
|