Преглед изворни кода

Claude: Support stopping the conversation

Alessandro Pignotti пре 4 месеци
родитељ
комит
5ba38a80ac
3 измењених фајлова са 46 додато и 2 уклоњено
  1. 1 0
      postcss.config.js
  2. 20 2
      src/lib/AnthropicTab.svelte
  3. 25 0
      src/lib/anthropic.js

+ 1 - 0
postcss.config.js

@@ -23,6 +23,7 @@ export default {
 				case '.fa-desktop:before':
 				case '.fa-mouse-pointer:before':
 				case '.fa-hourglass-half:before':
+				case '.fa-hand:before':
 				case '.fa-keyboard:before':
 				case '.fa-brands:before':
 				case '.fa-solid:before':

+ 20 - 2
src/lib/AnthropicTab.svelte

@@ -1,8 +1,11 @@
 <script>
-	import { apiState, setApiKey, addMessage, messageList, currentMessage } from '$lib/anthropic.js'
+	import { apiState, setApiKey, addMessage, forceStop, messageList, currentMessage } from '$lib/anthropic.js';
 	import { tick } from 'svelte';
+	import { get } from 'svelte/store';
 	import PanelButton from './PanelButton.svelte';
+	import { aiActivity } from './activities.js';
 	export let handleTool;
+	let stopRequested = false;
 	function handleKeyEnter(e)
 	{
 		if(e.key != "Enter")
@@ -35,7 +38,9 @@
 	{
 		await tick();
 		node.scrollTop = node.scrollHeight;
-		document.getElementById("ai-input").focus();
+		if (!get(aiActivity)) {
+			document.getElementById("ai-input").focus();
+		}
 	}
 	function scrollMessage(node, messageList)
 	{
@@ -96,6 +101,11 @@
 			role: msg.role
 		};
 	}
+	async function handleStop() {
+		stopRequested = true;
+		await forceStop();
+		stopRequested = false;
+	}
 </script>
 <h1 class="text-lg font-bold">Claude AI Integration</h1>
 <p>WebVM is integrated with Claude by Anthropic AI. You can prompt the AI to control the system.</p>
@@ -116,6 +126,14 @@
 </div>
 {#if $apiState == "KEY_REQUIRED"}
 	<textarea class="bg-neutral-700 p-2 rounded-md placeholder-gray-400 resize-none shrink-0" placeholder="Insert your Claude API Key" rows="1" on:keydown={handleKeyEnter} on:input={handleResize} id="ai-input"/>
+{:else if $aiActivity}
+	{#if stopRequested }
+		<PanelButton buttonIcon="fa-solid fa-hand" buttonText="Stopping...">
+		</PanelButton>
+	{:else}
+		<PanelButton buttonIcon="fa-solid fa-hand" clickHandler={handleStop} buttonText="Stop">
+		</PanelButton>
+	{/if}
 {:else}
 	<textarea class="bg-neutral-700 p-2 rounded-md placeholder-gray-400 resize-none shrink-0" placeholder="Prompt..." rows="1" on:keydown={handleMessage} on:input={handleResize} bind:value={$currentMessage} id="ai-input"/>
 {/if}

+ 25 - 0
src/lib/anthropic.js

@@ -6,6 +6,7 @@ import Anthropic from '@anthropic-ai/sdk';
 
 var client = null;
 var messages = [];
+var stopFlag = false;
 
 export function setApiKey(key)
 {
@@ -45,6 +46,11 @@ async function sendMessages(handleTool)
 									tool_choice: {type: "auto", disable_parallel_tool_use: true},
 									betas: ["computer-use-2025-01-24"]
 								});
+		if(stopFlag)
+		{
+			aiActivity.set(false);
+			return;
+		}
 		// Remove all the image payloads, we don't want to send them over and over again
 		for(var i=0;i<messages.length;i++)
 		{
@@ -83,6 +89,12 @@ async function sendMessages(handleTool)
 					}
 				}
 				addMessageInternal("user", [responseObj]);
+				if(stopFlag)
+				{
+					// Maintain state consitency by stopping after adding a valid response
+					aiActivity.set(false);
+					return;
+				}
 				sendMessages(handleTool);
 			}
 			else
@@ -115,6 +127,19 @@ export function addMessage(text, handleTool)
 	plausible("ClaudeAI Use");
 }
 
+export function forceStop() {
+    stopFlag = true;
+    return new Promise((resolve) => {
+        const unsubscribe = aiActivity.subscribe((value) => {
+            if (!value) {
+                unsubscribe();
+				stopFlag = false;
+                resolve();
+            }
+        });
+    });
+}
+
 function initialize()
 {
 	var savedApiKey = localStorage.getItem("anthropic-api-key");