From da254a48a88f85ee6a77d39d5c8dc38b07e5f105 Mon Sep 17 00:00:00 2001 From: silentoplayz Date: Thu, 4 Jun 2026 05:22:11 -0400 Subject: [PATCH] feat(ui): add tag suggestions dropdown to model editor --- src/lib/components/common/Tags.svelte | 16 +++++++++++++ .../workspace/Models/ModelEditor.svelte | 23 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/lib/components/common/Tags.svelte b/src/lib/components/common/Tags.svelte index 65340f3320..53c958e161 100644 --- a/src/lib/components/common/Tags.svelte +++ b/src/lib/components/common/Tags.svelte @@ -9,6 +9,9 @@ export let suggestionTags = []; export let disabled = false; + $: tagNames = new Set(tags.map((t) => t.name)); + $: filteredSuggestionTags = suggestionTags.filter((t) => !tagNames.has(t.name)); + let inputValue = ''; const addTag = () => { @@ -36,12 +39,25 @@ ? 'px-0.5' : ''} text-xs bg-transparent outline-hidden placeholder:text-gray-400 dark:placeholder:text-gray-500" placeholder={$i18n.t('Add a tag...')} + list="suggestionTagOptions" on:keydown={(event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); addTag(); } }} + on:input={() => { + const value = inputValue.trim(); + if (value !== '' && filteredSuggestionTags.some((t) => t.name === value)) { + addTag(); + } + }} /> {/if} + + + {#each filteredSuggestionTags as tag} + diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index 9c41aff0dd..f028bdcef8 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -29,6 +29,7 @@ import TerminalSelector from './TerminalSelector.svelte'; import AccessControlModal from '../common/AccessControlModal.svelte'; import LockClosed from '$lib/components/icons/LockClosed.svelte'; + import { getModelTags } from '$lib/apis/models'; const i18n = getContext('i18n'); @@ -106,6 +107,7 @@ let accessGrants = []; let terminalId = ''; let tts = { voice: '' }; + export let suggestionTags: { name: string }[] = []; const submitHandler = async () => { loading = true; @@ -256,6 +258,26 @@ await functions.set(await getFunctions(localStorage.token)); } + if (suggestionTags.length === 0) { + if (preset) { + // Workspace context: use workspace-only tags API + const modelTags = await getModelTags(localStorage.token).catch(() => null); + if (modelTags) { + suggestionTags = modelTags.map((t) => ({ name: t })); + } + } else { + // Admin context: compute tags from all models in the store + const tagSet = new Set(); + for (const m of $models) { + for (const t of m?.info?.meta?.tags ?? []) { + const name = typeof t === 'string' ? t : t?.name; + if (name) tagSet.add(name); + } + } + suggestionTags = [...tagSet].sort().map((t) => ({ name: t })); + } + } + // Fetch admin-configured default model metadata so the editor // reflects the actual defaults rather than hardcoded values const modelsConfig = await getModelsDefaults(localStorage.token).catch(() => null); @@ -651,6 +673,7 @@
{ const tagName = e.detail; info.meta.tags = info.meta.tags.filter((tag) => tag.name !== tagName);