Claude: Support stopping the conversation

This commit is contained in:
Alessandro Pignotti 2025-03-03 09:34:59 +01:00
parent 2f672a597d
commit 5ba38a80ac
3 changed files with 46 additions and 2 deletions

View File

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

View File

@ -1,8 +1,11 @@
<script> <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 { tick } from 'svelte';
import { get } from 'svelte/store';
import PanelButton from './PanelButton.svelte'; import PanelButton from './PanelButton.svelte';
import { aiActivity } from './activities.js';
export let handleTool; export let handleTool;
let stopRequested = false;
function handleKeyEnter(e) function handleKeyEnter(e)
{ {
if(e.key != "Enter") if(e.key != "Enter")
@ -35,8 +38,10 @@
{ {
await tick(); await tick();
node.scrollTop = node.scrollHeight; node.scrollTop = node.scrollHeight;
if (!get(aiActivity)) {
document.getElementById("ai-input").focus(); document.getElementById("ai-input").focus();
} }
}
function scrollMessage(node, messageList) function scrollMessage(node, messageList)
{ {
// Make sure the messages are always scrolled to the bottom // Make sure the messages are always scrolled to the bottom
@ -96,6 +101,11 @@
role: msg.role role: msg.role
}; };
} }
async function handleStop() {
stopRequested = true;
await forceStop();
stopRequested = false;
}
</script> </script>
<h1 class="text-lg font-bold">Claude AI Integration</h1> <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> <p>WebVM is integrated with Claude by Anthropic AI. You can prompt the AI to control the system.</p>
@ -116,6 +126,14 @@
</div> </div>
{#if $apiState == "KEY_REQUIRED"} {#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"/> <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} {: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"/> <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} {/if}

View File

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