@emblemvault/hustle-react 1.3.0 → 1.4.1
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/browser/hustle-react.js +108 -2
- package/dist/browser/hustle-react.js.map +1 -1
- package/dist/components/index.cjs +107 -2
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +107 -2
- package/dist/components/index.js.map +1 -1
- package/dist/index.cjs +107 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +107 -2
- package/dist/index.js.map +1 -1
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.cjs.map +1 -1
- package/dist/plugins/index.js +1 -1
- package/dist/plugins/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { createContext, useState, useEffect, useCallback, useRef, useMemo, useContext } from 'react';
|
|
2
3
|
import { HustleIncognitoClient } from 'hustle-incognito';
|
|
3
4
|
import { useEmblemAuthOptional } from '@emblemvault/emblem-auth-react';
|
|
@@ -3547,7 +3548,7 @@ var screenshotExecutor = async (args2) => {
|
|
|
3547
3548
|
if (!window.html2canvas) {
|
|
3548
3549
|
await new Promise((resolve, reject) => {
|
|
3549
3550
|
const script = document.createElement("script");
|
|
3550
|
-
script.src = "https://
|
|
3551
|
+
script.src = "https://cdn.jsdelivr.net/npm/html2canvas-pro@1.5.0/dist/html2canvas-pro.min.js";
|
|
3551
3552
|
script.onload = () => resolve();
|
|
3552
3553
|
script.onerror = () => reject(new Error("Failed to load html2canvas"));
|
|
3553
3554
|
document.head.appendChild(script);
|
|
@@ -14870,7 +14871,11 @@ var styles = {
|
|
|
14870
14871
|
border: "none",
|
|
14871
14872
|
borderRadius: 0,
|
|
14872
14873
|
color: tokens.colors.textTertiary,
|
|
14873
|
-
flexShrink: 0
|
|
14874
|
+
flexShrink: 0,
|
|
14875
|
+
display: "flex",
|
|
14876
|
+
alignItems: "center",
|
|
14877
|
+
justifyContent: "center",
|
|
14878
|
+
cursor: "pointer"
|
|
14874
14879
|
},
|
|
14875
14880
|
inputWrapper: {
|
|
14876
14881
|
flex: 1
|
|
@@ -15092,6 +15097,7 @@ function HustleChat({
|
|
|
15092
15097
|
isLoading,
|
|
15093
15098
|
error: error2,
|
|
15094
15099
|
models,
|
|
15100
|
+
client,
|
|
15095
15101
|
chatStream,
|
|
15096
15102
|
uploadFile,
|
|
15097
15103
|
selectedModel,
|
|
@@ -15118,6 +15124,8 @@ function HustleChat({
|
|
|
15118
15124
|
const [showSettingsPanel, setShowSettingsPanel] = useState(false);
|
|
15119
15125
|
const messagesEndRef = useRef(null);
|
|
15120
15126
|
const fileInputRef = useRef(null);
|
|
15127
|
+
const messagesRef = useRef(messages);
|
|
15128
|
+
const pendingAutoContinueRef = useRef(false);
|
|
15121
15129
|
useEffect(() => {
|
|
15122
15130
|
if (initialSystemPrompt && !systemPrompt) {
|
|
15123
15131
|
setSystemPrompt(initialSystemPrompt);
|
|
@@ -15126,6 +15134,9 @@ function HustleChat({
|
|
|
15126
15134
|
useEffect(() => {
|
|
15127
15135
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
15128
15136
|
}, [messages]);
|
|
15137
|
+
useEffect(() => {
|
|
15138
|
+
messagesRef.current = messages;
|
|
15139
|
+
}, [messages]);
|
|
15129
15140
|
const handleFileSelect = useCallback(
|
|
15130
15141
|
async (e) => {
|
|
15131
15142
|
const files = e.target.files;
|
|
@@ -15147,6 +15158,101 @@ function HustleChat({
|
|
|
15147
15158
|
const removeAttachment = useCallback((index) => {
|
|
15148
15159
|
setAttachments((prev) => prev.filter((_2, i) => i !== index));
|
|
15149
15160
|
}, []);
|
|
15161
|
+
const sendContinue = useCallback(async () => {
|
|
15162
|
+
if (isStreaming || !isReady) return;
|
|
15163
|
+
console.log("[AUTO_CONTINUE] Sending continue message...");
|
|
15164
|
+
const userMessage = {
|
|
15165
|
+
id: generateId(),
|
|
15166
|
+
role: "user",
|
|
15167
|
+
content: "continue"
|
|
15168
|
+
};
|
|
15169
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
15170
|
+
onMessage?.(userMessage);
|
|
15171
|
+
const assistantMessage = {
|
|
15172
|
+
id: generateId(),
|
|
15173
|
+
role: "assistant",
|
|
15174
|
+
content: "",
|
|
15175
|
+
isStreaming: true,
|
|
15176
|
+
toolCalls: []
|
|
15177
|
+
};
|
|
15178
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
15179
|
+
setIsStreaming(true);
|
|
15180
|
+
setCurrentToolCalls([]);
|
|
15181
|
+
try {
|
|
15182
|
+
const chatMessages = messagesRef.current.filter((m2) => !m2.isStreaming).map((m2) => ({ role: m2.role, content: m2.content }));
|
|
15183
|
+
chatMessages.push({ role: "user", content: "continue" });
|
|
15184
|
+
const stream = chatStream({
|
|
15185
|
+
messages: chatMessages,
|
|
15186
|
+
processChunks: true
|
|
15187
|
+
});
|
|
15188
|
+
let fullContent = "";
|
|
15189
|
+
const toolCallsAccumulated = [];
|
|
15190
|
+
for await (const chunk of stream) {
|
|
15191
|
+
if (chunk.type === "text") {
|
|
15192
|
+
fullContent += chunk.value;
|
|
15193
|
+
setMessages(
|
|
15194
|
+
(prev) => prev.map(
|
|
15195
|
+
(m2) => m2.id === assistantMessage.id ? { ...m2, content: fullContent } : m2
|
|
15196
|
+
)
|
|
15197
|
+
);
|
|
15198
|
+
} else if (chunk.type === "tool_call") {
|
|
15199
|
+
const toolCall = chunk.value;
|
|
15200
|
+
toolCallsAccumulated.push(toolCall);
|
|
15201
|
+
setCurrentToolCalls([...toolCallsAccumulated]);
|
|
15202
|
+
setMessages(
|
|
15203
|
+
(prev) => prev.map(
|
|
15204
|
+
(m2) => m2.id === assistantMessage.id ? { ...m2, toolCalls: [...toolCallsAccumulated] } : m2
|
|
15205
|
+
)
|
|
15206
|
+
);
|
|
15207
|
+
onToolCall?.(toolCall);
|
|
15208
|
+
} else if (chunk.type === "error") {
|
|
15209
|
+
console.error("Stream error:", chunk.value);
|
|
15210
|
+
}
|
|
15211
|
+
}
|
|
15212
|
+
const processedResponse = await stream.response;
|
|
15213
|
+
const finalContent = processedResponse?.content || fullContent || "(No response)";
|
|
15214
|
+
setMessages(
|
|
15215
|
+
(prev) => prev.map(
|
|
15216
|
+
(m2) => m2.id === assistantMessage.id ? { ...m2, isStreaming: false, content: finalContent } : m2
|
|
15217
|
+
)
|
|
15218
|
+
);
|
|
15219
|
+
onResponse?.(finalContent);
|
|
15220
|
+
} catch (err) {
|
|
15221
|
+
console.error("Continue error:", err);
|
|
15222
|
+
setMessages(
|
|
15223
|
+
(prev) => prev.map(
|
|
15224
|
+
(m2) => m2.id === assistantMessage.id ? { ...m2, isStreaming: false, content: `Error: ${err instanceof Error ? err.message : "Unknown error"}` } : m2
|
|
15225
|
+
)
|
|
15226
|
+
);
|
|
15227
|
+
} finally {
|
|
15228
|
+
setIsStreaming(false);
|
|
15229
|
+
setCurrentToolCalls([]);
|
|
15230
|
+
}
|
|
15231
|
+
}, [isStreaming, isReady, chatStream, onMessage, onToolCall, onResponse]);
|
|
15232
|
+
useEffect(() => {
|
|
15233
|
+
if (!client) return;
|
|
15234
|
+
const unsubMaxTools = client.on("max_tools_reached", (event) => {
|
|
15235
|
+
console.log(`[AUTO_CONTINUE] Max tools reached (${event.toolsExecuted}/${event.maxSteps}), queuing auto-continue...`);
|
|
15236
|
+
pendingAutoContinueRef.current = true;
|
|
15237
|
+
});
|
|
15238
|
+
const unsubTimeout = client.on("timeout", (event) => {
|
|
15239
|
+
console.log(`[AUTO_CONTINUE] Timeout: ${event.message}, queuing auto-continue...`);
|
|
15240
|
+
pendingAutoContinueRef.current = true;
|
|
15241
|
+
});
|
|
15242
|
+
return () => {
|
|
15243
|
+
unsubMaxTools();
|
|
15244
|
+
unsubTimeout();
|
|
15245
|
+
};
|
|
15246
|
+
}, [client]);
|
|
15247
|
+
useEffect(() => {
|
|
15248
|
+
if (!isStreaming && pendingAutoContinueRef.current && isReady) {
|
|
15249
|
+
console.log("[AUTO_CONTINUE] Streaming ended, triggering continue...");
|
|
15250
|
+
pendingAutoContinueRef.current = false;
|
|
15251
|
+
setTimeout(() => {
|
|
15252
|
+
sendContinue();
|
|
15253
|
+
}, 50);
|
|
15254
|
+
}
|
|
15255
|
+
}, [isStreaming, isReady, sendContinue]);
|
|
15150
15256
|
const sendMessage = useCallback(async () => {
|
|
15151
15257
|
const content = inputValue.trim();
|
|
15152
15258
|
if (!content || isStreaming || !isReady) return;
|