Spaces:
Paused
Paused
Download src/lib/components/agent/AgentQueue.svelte from Mike0021/chat-ui-agent-demo: direct link, hf CLI and curl.
- Browser
- Download file 6.83 kB
-
https://huggingface.co/spaces/Mike0021/chat-ui-agent-demo/resolve/main/src/lib/components/agent/AgentQueue.svelte
- Command line
-
hf download hf://spaces/Mike0021/chat-ui-agent-demo/src/lib/components/agent/AgentQueue.svelte
-
curl -L -o AgentQueue.svelte https://huggingface.co/spaces/Mike0021/chat-ui-agent-demo/resolve/main/src/lib/components/agent/AgentQueue.svelte
6.83 kB
| <script lang="ts"> | |
| import type { MessageAgentQueueUpdate } from "$lib/types/MessageUpdate"; | |
| import type { AgentQueueMutation, AgentQueueReplacement } from "./activityTypes"; | |
| import { | |
| agentQueueMatchesSnapshot, | |
| captureAgentQueueMutationTarget, | |
| createAgentQueueReplacement, | |
| type AgentQueueMutationTarget, | |
| } from "./agentQueueMutations"; | |
| import CarbonEdit from "~icons/carbon/edit"; | |
| import CarbonTrashCan from "~icons/carbon/trash-can"; | |
| import CarbonCheckmark from "~icons/carbon/checkmark"; | |
| import CarbonClose from "~icons/carbon/close"; | |
| interface Props { | |
| update: MessageAgentQueueUpdate; | |
| onchange?: (replacement: AgentQueueReplacement) => void | Promise<void>; | |
| } | |
| let { update, onchange }: Props = $props(); | |
| let editingTarget = $state<AgentQueueMutationTarget | undefined>(); | |
| let editValue = $state(""); | |
| let mutationBusy = $state(false); | |
| let mutationError = $state(""); | |
| function startEdit(queue: AgentQueueMutation["queue"], index: number) { | |
| const target = captureAgentQueueMutationTarget(update, queue, index); | |
| if (!target) return; | |
| editingTarget = target; | |
| editValue = target.value; | |
| mutationError = ""; | |
| } | |
| async function submitEdit() { | |
| const value = editValue.trim(); | |
| const target = editingTarget; | |
| if (!value || !target || !onchange || mutationBusy) return; | |
| await replaceQueue(target, "edit", value); | |
| } | |
| async function replaceQueue( | |
| target: AgentQueueMutationTarget, | |
| action: AgentQueueMutation["action"], | |
| value?: string | |
| ) { | |
| if (!onchange || mutationBusy || update.truncated) return; | |
| const change = createAgentQueueReplacement(target, action, value); | |
| if (!change) return; | |
| mutationBusy = true; | |
| mutationError = ""; | |
| try { | |
| await onchange(change); | |
| editingTarget = undefined; | |
| } catch (error) { | |
| mutationError = | |
| error instanceof Error ? error.message : "Unable to update pending instructions."; | |
| } finally { | |
| mutationBusy = false; | |
| } | |
| } | |
| function cancelEdit() { | |
| editingTarget = undefined; | |
| editValue = ""; | |
| } | |
| $effect(() => { | |
| const target = editingTarget; | |
| if (!target || mutationBusy || agentQueueMatchesSnapshot(update, target.expected)) return; | |
| cancelEdit(); | |
| mutationError = | |
| "Pending instructions changed while you were editing. Review the updated queue and try again."; | |
| }); | |
| const groups = $derived([ | |
| { key: "steering" as const, label: "Steering now", values: update.steering }, | |
| { key: "followUp" as const, label: "Queued for after", values: update.followUp }, | |
| ]); | |
| </script> | |
| {#if update.steering.length || update.followUp.length} | |
| <section | |
| aria-label="Pending agent instructions" | |
| class="rounded-xl border border-blue-200 bg-blue-50/60 p-3 dark:border-blue-900 dark:bg-blue-950/20" | |
| > | |
| <h3 class="mb-2 text-xs font-semibold text-blue-900 dark:text-blue-200"> | |
| Pending instructions | |
| </h3> | |
| <div class="space-y-2.5"> | |
| {#each groups as group (group.key)} | |
| {#if group.values.length} | |
| <div> | |
| <p | |
| class="mb-1 text-[10px] font-semibold tracking-wide text-blue-700 uppercase dark:text-blue-300" | |
| > | |
| {group.label} | |
| </p> | |
| <ul class="space-y-1.5"> | |
| {#each group.values as value, index (`${group.key}-${index}-${value}`)} | |
| <li | |
| class="rounded-lg border border-blue-200 bg-white/80 p-2 dark:border-blue-900 dark:bg-gray-900/60" | |
| > | |
| {#if editingTarget?.queue === group.key && editingTarget.index === index && editingTarget.value === value} | |
| <form | |
| class="flex flex-col gap-2 sm:flex-row" | |
| onsubmit={(event) => { | |
| event.preventDefault(); | |
| submitEdit(); | |
| }} | |
| > | |
| <label class="min-w-0 flex-1"> | |
| <span class="sr-only">Edit pending instruction</span> | |
| <input | |
| bind:value={editValue} | |
| maxlength="1024" | |
| disabled={mutationBusy} | |
| class="min-h-11 w-full rounded-lg border border-blue-300 bg-white px-2 text-sm outline-hidden focus:ring-2 focus:ring-blue-500 dark:border-blue-700 dark:bg-gray-900" | |
| /> | |
| </label> | |
| <button | |
| type="submit" | |
| disabled={mutationBusy || !editValue.trim()} | |
| class="grid min-h-11 min-w-11 place-items-center rounded-lg text-blue-700 hover:bg-blue-100 focus-visible:ring-2 focus-visible:ring-blue-500 dark:text-blue-300 dark:hover:bg-blue-900/40" | |
| aria-label="Save pending instruction" | |
| > | |
| <CarbonCheckmark class="size-4" /> | |
| </button> | |
| <button | |
| type="button" | |
| disabled={mutationBusy} | |
| class="grid min-h-11 min-w-11 place-items-center rounded-lg text-gray-500 hover:bg-gray-100 focus-visible:ring-2 focus-visible:ring-blue-500 dark:hover:bg-gray-800" | |
| aria-label="Cancel editing" | |
| onclick={cancelEdit} | |
| > | |
| <CarbonClose class="size-4" /> | |
| </button> | |
| </form> | |
| {:else} | |
| <div class="flex items-start gap-1.5"> | |
| <span | |
| class="min-w-0 flex-1 text-xs leading-relaxed text-gray-700 dark:text-gray-200" | |
| >{value}</span | |
| > | |
| {#if onchange && !update.truncated} | |
| <button | |
| type="button" | |
| disabled={mutationBusy} | |
| class="grid size-9 shrink-0 place-items-center rounded-lg text-gray-500 hover:bg-blue-100 hover:text-blue-800 focus-visible:ring-2 focus-visible:ring-blue-500 dark:hover:bg-blue-900/40 dark:hover:text-blue-200" | |
| aria-label="Edit pending instruction" | |
| onclick={() => startEdit(group.key, index)} | |
| > | |
| <CarbonEdit class="size-4" /> | |
| </button> | |
| <button | |
| type="button" | |
| disabled={mutationBusy} | |
| class="grid size-9 shrink-0 place-items-center rounded-lg text-gray-500 hover:bg-red-100 hover:text-red-700 focus-visible:ring-2 focus-visible:ring-blue-500 dark:hover:bg-red-950/40 dark:hover:text-red-300" | |
| aria-label="Remove pending instruction" | |
| onclick={() => { | |
| const target = captureAgentQueueMutationTarget( | |
| update, | |
| group.key, | |
| index | |
| ); | |
| if (target) void replaceQueue(target, "remove"); | |
| }} | |
| > | |
| <CarbonTrashCan class="size-4" /> | |
| </button> | |
| {/if} | |
| </div> | |
| {/if} | |
| </li> | |
| {/each} | |
| </ul> | |
| </div> | |
| {/if} | |
| {/each} | |
| </div> | |
| {#if update.truncated} | |
| <p class="mt-2 text-[11px] text-amber-700 dark:text-amber-300"> | |
| Queue truncated. Editing is disabled until the full queue is visible. | |
| </p> | |
| {/if} | |
| {#if mutationError} | |
| <p role="alert" class="mt-2 text-[11px] text-red-700 dark:text-red-300"> | |
| {mutationError} | |
| </p> | |
| {/if} | |
| </section> | |
| {/if} | |