bloby-bot 0.21.5 → 0.21.6
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
|
@@ -37,11 +37,7 @@ export function useChat(ws: WsClient | null) {
|
|
|
37
37
|
const [streamBuffer, setStreamBuffer] = useState('');
|
|
38
38
|
const [tools, setTools] = useState<ToolActivity[]>([]);
|
|
39
39
|
const loaded = useRef(false);
|
|
40
|
-
/**
|
|
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) */
|
|
40
|
+
/** Ref to current streamBuffer (avoids stale closures in callbacks) */
|
|
45
41
|
const streamBufferRef = useRef('');
|
|
46
42
|
|
|
47
43
|
// Load current conversation from DB on mount
|
|
@@ -130,11 +126,12 @@ export function useChat(ws: WsClient | null) {
|
|
|
130
126
|
|
|
131
127
|
const unsubs = [
|
|
132
128
|
ws.on('bot:typing', () => {
|
|
129
|
+
console.log('[useChat] bot:typing → streaming=true');
|
|
133
130
|
setStreaming(true);
|
|
134
131
|
setTools([]);
|
|
135
132
|
}),
|
|
136
133
|
ws.on('bot:token', (data: { token: string }) => {
|
|
137
|
-
// Auto-detect new turn —
|
|
134
|
+
// Auto-detect new turn — tokens arriving means agent is working
|
|
138
135
|
setStreaming(true);
|
|
139
136
|
setStreamBuffer((buf) => {
|
|
140
137
|
const next = buf + data.token;
|
|
@@ -150,44 +147,36 @@ export function useChat(ws: WsClient | null) {
|
|
|
150
147
|
});
|
|
151
148
|
}),
|
|
152
149
|
ws.on('bot:response', (data: { conversationId: string; messageId?: string; content: string }) => {
|
|
150
|
+
console.log('[useChat] bot:response — adding message bubble');
|
|
153
151
|
setConversationId(data.conversationId);
|
|
154
152
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
}
|
|
153
|
+
// Always add as a new bubble
|
|
154
|
+
setMessages((msgs) => [
|
|
155
|
+
...msgs,
|
|
156
|
+
{
|
|
157
|
+
id: data.messageId || Date.now().toString(),
|
|
158
|
+
role: 'assistant',
|
|
159
|
+
content: data.content,
|
|
160
|
+
timestamp: new Date().toISOString(),
|
|
161
|
+
},
|
|
162
|
+
]);
|
|
174
163
|
|
|
175
164
|
setStreamBuffer('');
|
|
176
165
|
streamBufferRef.current = '';
|
|
177
166
|
setTools([]);
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
167
|
+
// Don't clear streaming here — wait for bot:idle from the server
|
|
168
|
+
}),
|
|
169
|
+
ws.on('bot:idle', () => {
|
|
170
|
+
// Server confirmed agent is idle — safe to stop streaming
|
|
171
|
+
console.log('[useChat] bot:idle → streaming=false');
|
|
172
|
+
setStreaming(false);
|
|
183
173
|
}),
|
|
184
174
|
ws.on('bot:error', (data: { error: string }) => {
|
|
175
|
+
console.log('[useChat] bot:error');
|
|
185
176
|
setStreamBuffer('');
|
|
177
|
+
streamBufferRef.current = '';
|
|
178
|
+
setStreaming(false);
|
|
186
179
|
setTools([]);
|
|
187
|
-
pendingMessages.current = Math.max(0, pendingMessages.current - 1);
|
|
188
|
-
if (pendingMessages.current === 0) {
|
|
189
|
-
setStreaming(false);
|
|
190
|
-
}
|
|
191
180
|
setMessages((msgs) => [
|
|
192
181
|
...msgs,
|
|
193
182
|
{
|
|
@@ -222,28 +211,28 @@ export function useChat(ws: WsClient | null) {
|
|
|
222
211
|
audioData: audioData ? (audioData.startsWith('data:') ? audioData : `data:audio/webm;base64,${audioData}`) : undefined,
|
|
223
212
|
attachments: optimisticAttachments,
|
|
224
213
|
};
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
214
|
+
|
|
215
|
+
// If bot is currently streaming, commit the partial response as a completed message
|
|
216
|
+
// so the user's new message appears BELOW the bot's in-progress text (chronological order)
|
|
217
|
+
const partialContent = streamBufferRef.current;
|
|
218
|
+
if (partialContent) {
|
|
219
|
+
console.log('[useChat] Committing partial stream buffer as message before user send');
|
|
231
220
|
setMessages((msgs) => [
|
|
232
221
|
...msgs,
|
|
233
222
|
{
|
|
234
|
-
id:
|
|
223
|
+
id: 'partial-' + Date.now(),
|
|
235
224
|
role: 'assistant' as const,
|
|
236
225
|
content: partialContent,
|
|
237
226
|
timestamp: new Date().toISOString(),
|
|
238
227
|
},
|
|
228
|
+
userMsg,
|
|
239
229
|
]);
|
|
240
230
|
setStreamBuffer('');
|
|
241
231
|
streamBufferRef.current = '';
|
|
232
|
+
} else {
|
|
233
|
+
setMessages((msgs) => [...msgs, userMsg]);
|
|
242
234
|
}
|
|
243
235
|
|
|
244
|
-
setMessages((msgs) => [...msgs, userMsg]);
|
|
245
|
-
pendingMessages.current += 1;
|
|
246
|
-
|
|
247
236
|
// Build WS payload
|
|
248
237
|
const payload: any = { conversationId, content };
|
|
249
238
|
if (audioData) {
|
|
@@ -273,8 +262,6 @@ export function useChat(ws: WsClient | null) {
|
|
|
273
262
|
setStreamBuffer('');
|
|
274
263
|
streamBufferRef.current = '';
|
|
275
264
|
setTools([]);
|
|
276
|
-
pendingMessages.current = 0;
|
|
277
|
-
partialMsgId.current = null;
|
|
278
265
|
}, [ws, conversationId]);
|
|
279
266
|
|
|
280
267
|
const clearContext = useCallback(() => {
|
|
@@ -284,8 +271,6 @@ export function useChat(ws: WsClient | null) {
|
|
|
284
271
|
streamBufferRef.current = '';
|
|
285
272
|
setStreaming(false);
|
|
286
273
|
setTools([]);
|
|
287
|
-
pendingMessages.current = 0;
|
|
288
|
-
partialMsgId.current = null;
|
|
289
274
|
prevConvId.current = null;
|
|
290
275
|
loaded.current = false;
|
|
291
276
|
fetch('/api/context/clear', { method: 'POST' }).catch(() => {});
|
package/supervisor/index.ts
CHANGED
|
@@ -1167,7 +1167,7 @@ ${!connected ? '<script>setTimeout(()=>location.reload(),4000)</script>' : ''}
|
|
|
1167
1167
|
waChunkBuf = '';
|
|
1168
1168
|
}
|
|
1169
1169
|
|
|
1170
|
-
// Agent finished a turn — handle backend restart +
|
|
1170
|
+
// Agent finished a turn — handle backend restart + notify client
|
|
1171
1171
|
if (type === 'bot:turn-complete') {
|
|
1172
1172
|
log.info(`[orchestrator] ──── TURN COMPLETE ────`);
|
|
1173
1173
|
log.info(`[orchestrator] File tools used: ${eventData.usedFileTools}`);
|
|
@@ -1186,7 +1186,9 @@ ${!connected ? '<script>setTimeout(()=>location.reload(),4000)</script>' : ''}
|
|
|
1186
1186
|
pendingUpdate = false;
|
|
1187
1187
|
runDeferredUpdate();
|
|
1188
1188
|
}
|
|
1189
|
-
|
|
1189
|
+
// Tell the client the agent is idle — streaming can stop
|
|
1190
|
+
broadcastBloby('bot:idle', { conversationId: convId });
|
|
1191
|
+
return;
|
|
1190
1192
|
}
|
|
1191
1193
|
|
|
1192
1194
|
// Conversation ended (query loop exited)
|