@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
|
@@ -1609,7 +1609,7 @@ var screenshotExecutor = async (args2) => {
|
|
|
1609
1609
|
if (!window.html2canvas) {
|
|
1610
1610
|
await new Promise((resolve, reject) => {
|
|
1611
1611
|
const script = document.createElement("script");
|
|
1612
|
-
script.src = "https://
|
|
1612
|
+
script.src = "https://cdn.jsdelivr.net/npm/html2canvas-pro@1.5.0/dist/html2canvas-pro.min.js";
|
|
1613
1613
|
script.onload = () => resolve();
|
|
1614
1614
|
script.onerror = () => reject(new Error("Failed to load html2canvas"));
|
|
1615
1615
|
document.head.appendChild(script);
|
|
@@ -3315,7 +3315,11 @@ var styles = {
|
|
|
3315
3315
|
border: "none",
|
|
3316
3316
|
borderRadius: 0,
|
|
3317
3317
|
color: tokens.colors.textTertiary,
|
|
3318
|
-
flexShrink: 0
|
|
3318
|
+
flexShrink: 0,
|
|
3319
|
+
display: "flex",
|
|
3320
|
+
alignItems: "center",
|
|
3321
|
+
justifyContent: "center",
|
|
3322
|
+
cursor: "pointer"
|
|
3319
3323
|
},
|
|
3320
3324
|
inputWrapper: {
|
|
3321
3325
|
flex: 1
|
|
@@ -3537,6 +3541,7 @@ function HustleChat({
|
|
|
3537
3541
|
isLoading,
|
|
3538
3542
|
error: error2,
|
|
3539
3543
|
models,
|
|
3544
|
+
client,
|
|
3540
3545
|
chatStream,
|
|
3541
3546
|
uploadFile,
|
|
3542
3547
|
selectedModel,
|
|
@@ -3563,6 +3568,8 @@ function HustleChat({
|
|
|
3563
3568
|
const [showSettingsPanel, setShowSettingsPanel] = react.useState(false);
|
|
3564
3569
|
const messagesEndRef = react.useRef(null);
|
|
3565
3570
|
const fileInputRef = react.useRef(null);
|
|
3571
|
+
const messagesRef = react.useRef(messages);
|
|
3572
|
+
const pendingAutoContinueRef = react.useRef(false);
|
|
3566
3573
|
react.useEffect(() => {
|
|
3567
3574
|
if (initialSystemPrompt && !systemPrompt) {
|
|
3568
3575
|
setSystemPrompt(initialSystemPrompt);
|
|
@@ -3571,6 +3578,9 @@ function HustleChat({
|
|
|
3571
3578
|
react.useEffect(() => {
|
|
3572
3579
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
3573
3580
|
}, [messages]);
|
|
3581
|
+
react.useEffect(() => {
|
|
3582
|
+
messagesRef.current = messages;
|
|
3583
|
+
}, [messages]);
|
|
3574
3584
|
const handleFileSelect = react.useCallback(
|
|
3575
3585
|
async (e) => {
|
|
3576
3586
|
const files = e.target.files;
|
|
@@ -3592,6 +3602,101 @@ function HustleChat({
|
|
|
3592
3602
|
const removeAttachment = react.useCallback((index) => {
|
|
3593
3603
|
setAttachments((prev) => prev.filter((_, i) => i !== index));
|
|
3594
3604
|
}, []);
|
|
3605
|
+
const sendContinue = react.useCallback(async () => {
|
|
3606
|
+
if (isStreaming || !isReady) return;
|
|
3607
|
+
console.log("[AUTO_CONTINUE] Sending continue message...");
|
|
3608
|
+
const userMessage = {
|
|
3609
|
+
id: generateId(),
|
|
3610
|
+
role: "user",
|
|
3611
|
+
content: "continue"
|
|
3612
|
+
};
|
|
3613
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
3614
|
+
onMessage?.(userMessage);
|
|
3615
|
+
const assistantMessage = {
|
|
3616
|
+
id: generateId(),
|
|
3617
|
+
role: "assistant",
|
|
3618
|
+
content: "",
|
|
3619
|
+
isStreaming: true,
|
|
3620
|
+
toolCalls: []
|
|
3621
|
+
};
|
|
3622
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
3623
|
+
setIsStreaming(true);
|
|
3624
|
+
setCurrentToolCalls([]);
|
|
3625
|
+
try {
|
|
3626
|
+
const chatMessages = messagesRef.current.filter((m) => !m.isStreaming).map((m) => ({ role: m.role, content: m.content }));
|
|
3627
|
+
chatMessages.push({ role: "user", content: "continue" });
|
|
3628
|
+
const stream = chatStream({
|
|
3629
|
+
messages: chatMessages,
|
|
3630
|
+
processChunks: true
|
|
3631
|
+
});
|
|
3632
|
+
let fullContent = "";
|
|
3633
|
+
const toolCallsAccumulated = [];
|
|
3634
|
+
for await (const chunk of stream) {
|
|
3635
|
+
if (chunk.type === "text") {
|
|
3636
|
+
fullContent += chunk.value;
|
|
3637
|
+
setMessages(
|
|
3638
|
+
(prev) => prev.map(
|
|
3639
|
+
(m) => m.id === assistantMessage.id ? { ...m, content: fullContent } : m
|
|
3640
|
+
)
|
|
3641
|
+
);
|
|
3642
|
+
} else if (chunk.type === "tool_call") {
|
|
3643
|
+
const toolCall = chunk.value;
|
|
3644
|
+
toolCallsAccumulated.push(toolCall);
|
|
3645
|
+
setCurrentToolCalls([...toolCallsAccumulated]);
|
|
3646
|
+
setMessages(
|
|
3647
|
+
(prev) => prev.map(
|
|
3648
|
+
(m) => m.id === assistantMessage.id ? { ...m, toolCalls: [...toolCallsAccumulated] } : m
|
|
3649
|
+
)
|
|
3650
|
+
);
|
|
3651
|
+
onToolCall?.(toolCall);
|
|
3652
|
+
} else if (chunk.type === "error") {
|
|
3653
|
+
console.error("Stream error:", chunk.value);
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
const processedResponse = await stream.response;
|
|
3657
|
+
const finalContent = processedResponse?.content || fullContent || "(No response)";
|
|
3658
|
+
setMessages(
|
|
3659
|
+
(prev) => prev.map(
|
|
3660
|
+
(m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: finalContent } : m
|
|
3661
|
+
)
|
|
3662
|
+
);
|
|
3663
|
+
onResponse?.(finalContent);
|
|
3664
|
+
} catch (err) {
|
|
3665
|
+
console.error("Continue error:", err);
|
|
3666
|
+
setMessages(
|
|
3667
|
+
(prev) => prev.map(
|
|
3668
|
+
(m) => m.id === assistantMessage.id ? { ...m, isStreaming: false, content: `Error: ${err instanceof Error ? err.message : "Unknown error"}` } : m
|
|
3669
|
+
)
|
|
3670
|
+
);
|
|
3671
|
+
} finally {
|
|
3672
|
+
setIsStreaming(false);
|
|
3673
|
+
setCurrentToolCalls([]);
|
|
3674
|
+
}
|
|
3675
|
+
}, [isStreaming, isReady, chatStream, onMessage, onToolCall, onResponse]);
|
|
3676
|
+
react.useEffect(() => {
|
|
3677
|
+
if (!client) return;
|
|
3678
|
+
const unsubMaxTools = client.on("max_tools_reached", (event) => {
|
|
3679
|
+
console.log(`[AUTO_CONTINUE] Max tools reached (${event.toolsExecuted}/${event.maxSteps}), queuing auto-continue...`);
|
|
3680
|
+
pendingAutoContinueRef.current = true;
|
|
3681
|
+
});
|
|
3682
|
+
const unsubTimeout = client.on("timeout", (event) => {
|
|
3683
|
+
console.log(`[AUTO_CONTINUE] Timeout: ${event.message}, queuing auto-continue...`);
|
|
3684
|
+
pendingAutoContinueRef.current = true;
|
|
3685
|
+
});
|
|
3686
|
+
return () => {
|
|
3687
|
+
unsubMaxTools();
|
|
3688
|
+
unsubTimeout();
|
|
3689
|
+
};
|
|
3690
|
+
}, [client]);
|
|
3691
|
+
react.useEffect(() => {
|
|
3692
|
+
if (!isStreaming && pendingAutoContinueRef.current && isReady) {
|
|
3693
|
+
console.log("[AUTO_CONTINUE] Streaming ended, triggering continue...");
|
|
3694
|
+
pendingAutoContinueRef.current = false;
|
|
3695
|
+
setTimeout(() => {
|
|
3696
|
+
sendContinue();
|
|
3697
|
+
}, 50);
|
|
3698
|
+
}
|
|
3699
|
+
}, [isStreaming, isReady, sendContinue]);
|
|
3595
3700
|
const sendMessage = react.useCallback(async () => {
|
|
3596
3701
|
const content = inputValue.trim();
|
|
3597
3702
|
if (!content || isStreaming || !isReady) return;
|