bloby-bot 0.21.4 → 0.21.5
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/package.json
CHANGED
|
@@ -39,6 +39,10 @@ export function useChat(ws: WsClient | null) {
|
|
|
39
39
|
const loaded = useRef(false);
|
|
40
40
|
/** Count of user messages awaiting a bot response — keeps typing indicator alive across turns */
|
|
41
41
|
const pendingMessages = useRef(0);
|
|
42
|
+
/** ID of a partial assistant message committed early (when user sends while bot is streaming) */
|
|
43
|
+
const partialMsgId = useRef<string | null>(null);
|
|
44
|
+
/** Ref to current streamBuffer value (accessible in callbacks without stale closures) */
|
|
45
|
+
const streamBufferRef = useRef('');
|
|
42
46
|
|
|
43
47
|
// Load current conversation from DB on mount
|
|
44
48
|
useEffect(() => {
|
|
@@ -132,7 +136,11 @@ export function useChat(ws: WsClient | null) {
|
|
|
132
136
|
ws.on('bot:token', (data: { token: string }) => {
|
|
133
137
|
// Auto-detect new turn — if tokens arrive after a response cleared streaming
|
|
134
138
|
setStreaming(true);
|
|
135
|
-
setStreamBuffer((buf) =>
|
|
139
|
+
setStreamBuffer((buf) => {
|
|
140
|
+
const next = buf + data.token;
|
|
141
|
+
streamBufferRef.current = next;
|
|
142
|
+
return next;
|
|
143
|
+
});
|
|
136
144
|
}),
|
|
137
145
|
ws.on('bot:tool', (data: { name: string; input?: any; status?: string }) => {
|
|
138
146
|
setTools((prev) => {
|
|
@@ -143,16 +151,29 @@ export function useChat(ws: WsClient | null) {
|
|
|
143
151
|
}),
|
|
144
152
|
ws.on('bot:response', (data: { conversationId: string; messageId?: string; content: string }) => {
|
|
145
153
|
setConversationId(data.conversationId);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
|
|
155
|
+
if (partialMsgId.current) {
|
|
156
|
+
// A partial message was committed — update it with the full response
|
|
157
|
+
const pid = partialMsgId.current;
|
|
158
|
+
partialMsgId.current = null;
|
|
159
|
+
setMessages((msgs) => msgs.map((m) =>
|
|
160
|
+
m.id === pid ? { ...m, content: data.content } : m,
|
|
161
|
+
));
|
|
162
|
+
} else {
|
|
163
|
+
// Normal: add new message bubble
|
|
164
|
+
setMessages((msgs) => [
|
|
165
|
+
...msgs,
|
|
166
|
+
{
|
|
167
|
+
id: data.messageId || Date.now().toString(),
|
|
168
|
+
role: 'assistant',
|
|
169
|
+
content: data.content,
|
|
170
|
+
timestamp: new Date().toISOString(),
|
|
171
|
+
},
|
|
172
|
+
]);
|
|
173
|
+
}
|
|
174
|
+
|
|
155
175
|
setStreamBuffer('');
|
|
176
|
+
streamBufferRef.current = '';
|
|
156
177
|
setTools([]);
|
|
157
178
|
// Only stop streaming when all pending messages have been answered
|
|
158
179
|
pendingMessages.current = Math.max(0, pendingMessages.current - 1);
|
|
@@ -201,6 +222,25 @@ export function useChat(ws: WsClient | null) {
|
|
|
201
222
|
audioData: audioData ? (audioData.startsWith('data:') ? audioData : `data:audio/webm;base64,${audioData}`) : undefined,
|
|
202
223
|
attachments: optimisticAttachments,
|
|
203
224
|
};
|
|
225
|
+
// If bot is currently streaming, commit the partial response as a message
|
|
226
|
+
// so the user's new message appears BELOW the bot's in-progress text
|
|
227
|
+
if (streamBufferRef.current) {
|
|
228
|
+
const pid = 'partial-' + Date.now();
|
|
229
|
+
partialMsgId.current = pid;
|
|
230
|
+
const partialContent = streamBufferRef.current;
|
|
231
|
+
setMessages((msgs) => [
|
|
232
|
+
...msgs,
|
|
233
|
+
{
|
|
234
|
+
id: pid,
|
|
235
|
+
role: 'assistant' as const,
|
|
236
|
+
content: partialContent,
|
|
237
|
+
timestamp: new Date().toISOString(),
|
|
238
|
+
},
|
|
239
|
+
]);
|
|
240
|
+
setStreamBuffer('');
|
|
241
|
+
streamBufferRef.current = '';
|
|
242
|
+
}
|
|
243
|
+
|
|
204
244
|
setMessages((msgs) => [...msgs, userMsg]);
|
|
205
245
|
pendingMessages.current += 1;
|
|
206
246
|
|
|
@@ -231,17 +271,21 @@ export function useChat(ws: WsClient | null) {
|
|
|
231
271
|
ws.send('user:stop', { conversationId });
|
|
232
272
|
setStreaming(false);
|
|
233
273
|
setStreamBuffer('');
|
|
274
|
+
streamBufferRef.current = '';
|
|
234
275
|
setTools([]);
|
|
235
276
|
pendingMessages.current = 0;
|
|
277
|
+
partialMsgId.current = null;
|
|
236
278
|
}, [ws, conversationId]);
|
|
237
279
|
|
|
238
280
|
const clearContext = useCallback(() => {
|
|
239
281
|
setMessages([]);
|
|
240
282
|
setConversationId(null);
|
|
241
283
|
setStreamBuffer('');
|
|
284
|
+
streamBufferRef.current = '';
|
|
242
285
|
setStreaming(false);
|
|
243
286
|
setTools([]);
|
|
244
287
|
pendingMessages.current = 0;
|
|
288
|
+
partialMsgId.current = null;
|
|
245
289
|
prevConvId.current = null;
|
|
246
290
|
loaded.current = false;
|
|
247
291
|
fetch('/api/context/clear', { method: 'POST' }).catch(() => {});
|
package/supervisor/index.ts
CHANGED
|
@@ -80,7 +80,7 @@ const SW_JS = `// Service worker — app-shell caching + push notifications
|
|
|
80
80
|
// JS/CSS modules → stale-while-revalidate
|
|
81
81
|
// API, WebSocket, Vite internals → network-only (no cache)
|
|
82
82
|
|
|
83
|
-
var CACHE = 'bloby-
|
|
83
|
+
var CACHE = 'bloby-v6';
|
|
84
84
|
var HASHED_RE = new RegExp('/assets/.+-[a-zA-Z0-9]{6,}[.](js|css)$');
|
|
85
85
|
|
|
86
86
|
// Precache the HTML shell on install so the cache is never empty.
|