Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 5,384 Bytes
2e21e16 09ed06c d433b55 15baec4 f940e40 2e21e16 a1a6daf 2e21e16 0c3e3b2 a1a6daf 2e21e16 a1a6daf 15baec4 d433b55 2e21e16 a1a6daf 15baec4 2e21e16 a1a6daf 2e21e16 0c3e3b2 2e21e16 a1a6daf 2e21e16 0c3e3b2 2e21e16 a1a6daf 2e21e16 0c3e3b2 2e21e16 a1a6daf 2e21e16 09ed06c a1a6daf 09ed06c 2e21e16 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
<script lang="ts">
import { MessageToolUpdateType, type MessageToolUpdate } from "$lib/types/MessageUpdate";
import {
isMessageToolCallUpdate,
isMessageToolErrorUpdate,
isMessageToolResultUpdate,
} from "$lib/utils/messageUpdates";
import CarbonTools from "~icons/carbon/tools";
import { ToolResultStatus, type ToolFront } from "$lib/types/Tool";
import { page } from "$app/state";
import { onDestroy } from "svelte";
import { browser } from "$app/environment";
interface Props {
tool: MessageToolUpdate[];
loading?: boolean;
}
let { tool, loading = false }: Props = $props();
const toolFnName = tool.find(isMessageToolCallUpdate)?.call.name;
let toolError = $derived(tool.some(isMessageToolErrorUpdate));
let toolDone = $derived(tool.some(isMessageToolResultUpdate));
let eta = $derived(tool.find((el) => el.subtype === MessageToolUpdateType.ETA)?.eta);
const availableTools: ToolFront[] = page.data.tools;
let loadingBarEl: HTMLDivElement | undefined = $state();
let animation: Animation | undefined = $state(undefined);
let isShowingLoadingBar = $state(false);
$effect(() => {
!toolError &&
!toolDone &&
loading &&
loadingBarEl &&
eta &&
(() => {
loadingBarEl.classList.remove("hidden");
isShowingLoadingBar = true;
animation = loadingBarEl.animate([{ width: "0%" }, { width: "calc(100%+1rem)" }], {
duration: eta * 1000,
fill: "forwards",
});
})();
});
onDestroy(() => {
if (animation) {
animation.cancel();
}
});
// go to 100% quickly if loading is done
$effect(() => {
(!loading || toolDone || toolError) &&
browser &&
loadingBarEl &&
isShowingLoadingBar &&
(() => {
isShowingLoadingBar = false;
loadingBarEl.classList.remove("hidden");
animation?.cancel();
animation = loadingBarEl.animate(
[{ width: loadingBarEl.style.width }, { width: "calc(100%+1rem)" }],
{
duration: 300,
fill: "forwards",
}
);
setTimeout(() => {
loadingBarEl?.classList.add("hidden");
}, 300);
})();
});
</script>
{#if toolFnName && toolFnName !== "websearch"}
<details
class="group/tool my-2.5 w-fit cursor-pointer rounded-lg border border-gray-200 bg-white pl-1 pr-2.5 text-sm shadow-sm transition-all open:mb-3
open:border-purple-500/10 open:bg-purple-600/5 open:shadow-sm dark:border-gray-800 dark:bg-gray-900 open:dark:border-purple-800/40 open:dark:bg-purple-800/10"
>
<summary
class="relative flex select-none list-none items-center gap-1.5 py-1 group-open/tool:text-purple-700 group-open/tool:dark:text-purple-300"
>
<div
bind:this={loadingBarEl}
class="absolute -m-1 hidden h-full w-[calc(100%+1rem)] rounded-lg bg-purple-500/5 transition-all dark:bg-purple-500/10"
></div>
<div
class="relative grid size-[22px] place-items-center rounded bg-purple-600/10 dark:bg-purple-600/20"
>
<svg
class="absolute inset-0 text-purple-500/40 transition-opacity"
class:invisible={toolDone || toolError}
width="22"
height="22"
viewBox="0 0 38 38"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
class="loading-path"
d="M8 2.5H30C30 2.5 35.5 2.5 35.5 8V30C35.5 30 35.5 35.5 30 35.5H8C8 35.5 2.5 35.5 2.5 30V8C2.5 8 2.5 2.5 8 2.5Z"
stroke="currentColor"
stroke-width="1"
stroke-linecap="round"
id="shape"
/>
</svg>
<CarbonTools class="text-xs text-purple-700 dark:text-purple-500" />
</div>
<span>
{toolError ? "Error calling" : toolDone ? "Called" : "Calling"} tool
<span class="font-semibold"
>{availableTools.find((tool) => tool.name === toolFnName)?.displayName ??
toolFnName}</span
>
</span>
</summary>
{#each tool as toolUpdate}
{#if toolUpdate.subtype === MessageToolUpdateType.Call}
<div class="mt-1 flex items-center gap-2 opacity-80">
<h3 class="text-sm">Parameters</h3>
<div class="h-px flex-1 bg-gradient-to-r from-gray-500/20"></div>
</div>
<ul class="py-1 text-sm">
{#each Object.entries(toolUpdate.call.parameters ?? {}) as [k, v]}
{#if v !== null}
<li>
<span class="font-semibold">{k}</span>:
<span>{v}</span>
</li>
{/if}
{/each}
</ul>
{:else if toolUpdate.subtype === MessageToolUpdateType.Error}
<div class="mt-1 flex items-center gap-2 opacity-80">
<h3 class="text-sm">Error</h3>
<div class="h-px flex-1 bg-gradient-to-r from-gray-500/20"></div>
</div>
<p class="text-sm">{toolUpdate.message}</p>
{:else if isMessageToolResultUpdate(toolUpdate) && toolUpdate.result.status === ToolResultStatus.Success && toolUpdate.result.display}
<div class="mt-1 flex items-center gap-2 opacity-80">
<h3 class="text-sm">Result</h3>
<div class="h-px flex-1 bg-gradient-to-r from-gray-500/20"></div>
</div>
<ul class="py-1 text-sm">
{#each toolUpdate.result.outputs as output}
{#each Object.entries(output) as [k, v]}
{#if v !== null}
<li>
<span class="font-semibold">{k}</span>:
<span>{v}</span>
</li>
{/if}
{/each}
{/each}
</ul>
{/if}
{/each}
</details>
{/if}
<style>
details summary::-webkit-details-marker {
display: none;
}
.loading-path {
stroke-dasharray: 61.45;
animation: loading 2s linear infinite;
}
</style>
|