feat: add skills management to chat component (#25037)

- Introduced skills functionality in Chat.svelte, MessageInput.svelte, and related components.
- Added SkillsModal for displaying and managing available skills.
- Updated state management to include selectedSkillIds and integrate skills API.
- Enhanced UI to show available skills and their descriptions.
- Updated translations to support skills-related text.
This commit is contained in:
Mr. Meowgi
2026-06-01 12:53:30 -07:00
committed by GitHub
parent 42c2393f8e
commit a9da054572
6 changed files with 233 additions and 3 deletions
+37 -1
View File
@@ -27,6 +27,7 @@
config,
showCallOverlay,
tools,
skills,
toolServers,
terminalServers,
user as _user,
@@ -58,6 +59,7 @@
import { getChatById } from '$lib/apis/chats';
import { getSessionUser } from '$lib/apis/auths';
import { getTools } from '$lib/apis/tools';
import { getSkills } from '$lib/apis/skills';
import { WEBUI_BASE_URL, WEBUI_API_BASE_URL, PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants';
import { getOAuthClientAuthorizationUrl } from '$lib/apis/configs';
@@ -69,6 +71,7 @@
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
import ToolServersModal from './ToolServersModal.svelte';
import SkillsModal from './SkillsModal.svelte';
import RichTextInput from '../common/RichTextInput.svelte';
import Tooltip from '../common/Tooltip.svelte';
@@ -80,6 +83,7 @@
import GlobeAlt from '../icons/GlobeAlt.svelte';
import Photo from '../icons/Photo.svelte';
import Wrench from '../icons/Wrench.svelte';
import Keyframes from '../icons/Keyframes.svelte';
import Sparkles from '../icons/Sparkles.svelte';
import InputVariablesModal from './MessageInput/InputVariablesModal.svelte';
@@ -131,6 +135,7 @@
export let files = [];
export let selectedToolIds = [];
export let selectedSkillIds = [];
export let selectedFilterIds = [];
export let imageGenerationEnabled = false;
@@ -176,6 +181,7 @@
};
}),
selectedToolIds,
selectedSkillIds,
selectedFilterIds,
imageGenerationEnabled,
webSearchEnabled,
@@ -418,6 +424,7 @@
let suggestions = null;
let showTools = false;
let showSkills = false;
let loaded = false;
let recording = false;
@@ -508,6 +515,9 @@
let showToolsButton = false;
$: showToolsButton = ($tools ?? []).length > 0 || ($toolServers ?? []).length > 0;
let showSkillsButton = false;
$: showSkillsButton = ($skills ?? []).some((skill) => skill.is_active);
let showWebSearchButton = false;
$: showWebSearchButton =
(atSelectedModel?.id ? [atSelectedModel.id] : selectedModels).length ===
@@ -1098,6 +1108,7 @@
}
tools.set(await getTools(localStorage.token));
skills.set(await getSkills(localStorage.token));
};
initialize();
@@ -1120,6 +1131,7 @@
</script>
<ToolServersModal bind:show={showTools} {selectedToolIds} />
<SkillsModal bind:show={showSkills} {selectedSkillIds} />
<InputVariablesModal
bind:show={showInputVariablesModal}
@@ -1668,7 +1680,7 @@
</div>
</InputMenu>
{#if showWebSearchButton || showImageGenerationButton || showCodeInterpreterButton || showToolsButton || (toggleFilters && toggleFilters.length > 0)}
{#if showWebSearchButton || showImageGenerationButton || showCodeInterpreterButton || showToolsButton || showSkillsButton || (toggleFilters && toggleFilters.length > 0)}
<div
class="flex self-center w-[1px] h-4 mx-1 bg-gray-200/50 dark:bg-gray-800/50"
/>
@@ -1680,6 +1692,7 @@
{showImageGenerationButton}
{showCodeInterpreterButton}
bind:selectedToolIds
bind:selectedSkillIds
bind:selectedFilterIds
bind:webSearchEnabled
bind:imageGenerationEnabled
@@ -1751,6 +1764,29 @@
</Tooltip>
{/if}
{#if (selectedSkillIds ?? []).length > 0}
<Tooltip
content={$i18n.t('{{COUNT}} Available Skills', {
COUNT: (selectedSkillIds ?? []).length
})}
>
<button
class="translate-y-[0.5px] px-1 flex gap-1 items-center text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 rounded-lg self-center transition"
aria-label="Available Skills"
type="button"
on:click={() => {
showSkills = !showSkills;
}}
>
<Keyframes className="size-4" strokeWidth="1.75" />
<span class="text-sm">
{(selectedSkillIds ?? []).length}
</span>
</button>
</Tooltip>
{/if}
{#each selectedFilterIds as filterId (filterId)}
{@const filter = toggleFilters.find((f) => f.id === filterId)}
{#if filter}