@emblemvault/hustle-react 1.3.0 → 1.4.0

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