瀏覽代碼

feat: model tools assignment

Timothy J. Baek 10 月之前
父節點
當前提交
5cd28c04b8

+ 10 - 11
src/lib/components/chat/Chat.svelte

@@ -74,6 +74,9 @@
 	let selectedModels = [''];
 	let atSelectedModel: Model | undefined;
 
+	let selectedModelIds = [];
+	$: selectedModelIds = atSelectedModel !== undefined ? [atSelectedModel.id] : selectedModels;
+
 	let selectedToolIds = [];
 	let webSearchEnabled = false;
 
@@ -1281,17 +1284,13 @@
 				bind:selectedToolIds
 				bind:webSearchEnabled
 				bind:atSelectedModel
-				availableTools={$user.role === 'admin'
-					? $tools.reduce((a, e, i, arr) => {
-							a[e.id] = {
-								name: e.name,
-								description: e.meta.description,
-								enabled: false
-							};
-
-							return a;
-					  }, {})
-					: {}}
+				availableToolIds={selectedModelIds.reduce((a, e, i, arr) => {
+					const model = $models.find((m) => m.id === e);
+					if (model?.info?.meta?.toolIds ?? false) {
+						return [...new Set([...a, ...model.info.meta.toolIds])];
+					}
+					return a;
+				}, [])}
 				{selectedModels}
 				{messages}
 				{submitPrompt}

+ 13 - 3
src/lib/components/chat/MessageInput.svelte

@@ -9,7 +9,8 @@
 		models,
 		config,
 		showCallOverlay,
-		tools
+		tools,
+		user as _user
 	} from '$lib/stores';
 	import { blobToFile, calculateSHA256, findWordIndices } from '$lib/utils';
 
@@ -59,7 +60,7 @@
 
 	export let files = [];
 
-	export let availableTools = {};
+	export let availableToolIds = [];
 	export let selectedToolIds = [];
 	export let webSearchEnabled = false;
 
@@ -657,7 +658,16 @@
 									<InputMenu
 										bind:webSearchEnabled
 										bind:selectedToolIds
-										tools={availableTools}
+										tools={$tools.reduce((a, e, i, arr) => {
+											if (availableToolIds.includes(e.id) || ($_user?.role ?? 'user') === 'admin') {
+												a[e.id] = {
+													name: e.name,
+													description: e.meta.description,
+													enabled: false
+												};
+											}
+											return a;
+										}, {})}
 										uploadFilesHandler={() => {
 											filesInputElement.click();
 										}}

+ 57 - 0
src/lib/components/workspace/Models/ToolsSelector.svelte

@@ -0,0 +1,57 @@
+<script lang="ts">
+	import Checkbox from '$lib/components/common/Checkbox.svelte';
+	import { getContext, onMount } from 'svelte';
+
+	export let tools = [];
+
+	let _tools = {};
+
+	export let selectedToolIds = [];
+
+	const i18n = getContext('i18n');
+
+	onMount(() => {
+		_tools = tools.reduce((acc, tool) => {
+			acc[tool.id] = {
+				...tool,
+				selected: selectedToolIds.includes(tool.id)
+			};
+
+			return acc;
+		}, {});
+	});
+</script>
+
+<div>
+	<div class="flex w-full justify-between mb-1">
+		<div class=" self-center text-sm font-semibold">{$i18n.t('Tools')}</div>
+	</div>
+
+	<div class=" text-xs dark:text-gray-500">
+		{$i18n.t('To select toolkits here, add them to the "Tools" workspace first.')}
+	</div>
+
+	<div class="flex flex-col">
+		{#if tools.length > 0}
+			<div class=" flex items-center gap-2 mt-2">
+				{#each Object.keys(_tools) as tool, toolIdx}
+					<div class=" flex items-center gap-2">
+						<div class="self-center flex items-center">
+							<Checkbox
+								state={_tools[tool].selected ? 'checked' : 'unchecked'}
+								on:change={(e) => {
+									_tools[tool].selected = e.detail === 'checked';
+									selectedToolIds = Object.keys(_tools).filter((t) => _tools[t].selected);
+								}}
+							/>
+						</div>
+
+						<div class=" py-0.5 text-sm w-full capitalize font-medium">
+							{_tools[tool].name}
+						</div>
+					</div>
+				{/each}
+			</div>
+		{/if}
+	</div>
+</div>

+ 17 - 1
src/routes/(app)/workspace/models/create/+page.svelte

@@ -2,7 +2,7 @@
 	import { v4 as uuidv4 } from 'uuid';
 	import { toast } from 'svelte-sonner';
 	import { goto } from '$app/navigation';
-	import { settings, user, config, models } from '$lib/stores';
+	import { settings, user, config, models, tools } from '$lib/stores';
 
 	import { onMount, tick, getContext } from 'svelte';
 	import { addNewModel, getModelById, getModelInfos } from '$lib/apis/models';
@@ -12,6 +12,8 @@
 	import Checkbox from '$lib/components/common/Checkbox.svelte';
 	import Tags from '$lib/components/common/Tags.svelte';
 	import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte';
+	import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte';
+	import { stringify } from 'postcss';
 
 	const i18n = getContext('i18n');
 
@@ -54,6 +56,7 @@
 		vision: true
 	};
 
+	let toolIds = [];
 	let knowledge = [];
 
 	$: if (name) {
@@ -88,6 +91,14 @@
 			}
 		}
 
+		if (toolIds.length > 0) {
+			info.meta.toolIds = toolIds;
+		} else {
+			if (info.meta.toolIds) {
+				delete info.meta.toolIds;
+			}
+		}
+
 		info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
 		Object.keys(info.params).forEach((key) => {
 			if (info.params[key] === '' || info.params[key] === null) {
@@ -154,6 +165,7 @@
 		params.stop = params?.stop ? (params?.stop ?? []).join(',') : null;
 
 		capabilities = { ...capabilities, ...(model?.info?.meta?.capabilities ?? {}) };
+		toolIds = model?.info?.meta?.toolIds ?? [];
 
 		info = {
 			...info,
@@ -554,6 +566,10 @@
 			<Knowledge bind:knowledge />
 		</div>
 
+		<div class="my-2">
+			<ToolsSelector bind:selectedToolIds={toolIds} tools={$tools} />
+		</div>
+
 		<div class="my-1">
 			<div class="flex w-full justify-between mb-1">
 				<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>

+ 19 - 1
src/routes/(app)/workspace/models/edit/+page.svelte

@@ -5,7 +5,7 @@
 
 	import { onMount, getContext } from 'svelte';
 	import { page } from '$app/stores';
-	import { settings, user, config, models } from '$lib/stores';
+	import { settings, user, config, models, tools } from '$lib/stores';
 	import { splitStream } from '$lib/utils';
 
 	import { getModelInfos, updateModelById } from '$lib/apis/models';
@@ -15,6 +15,7 @@
 	import Checkbox from '$lib/components/common/Checkbox.svelte';
 	import Tags from '$lib/components/common/Tags.svelte';
 	import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte';
+	import ToolsSelector from '$lib/components/workspace/Models/ToolsSelector.svelte';
 
 	const i18n = getContext('i18n');
 
@@ -60,6 +61,7 @@
 	};
 
 	let knowledge = [];
+	let toolIds = [];
 
 	const updateHandler = async () => {
 		loading = true;
@@ -76,6 +78,14 @@
 			}
 		}
 
+		if (toolIds.length > 0) {
+			info.meta.toolIds = toolIds;
+		} else {
+			if (info.meta.toolIds) {
+				delete info.meta.toolIds;
+			}
+		}
+
 		info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null;
 		Object.keys(info.params).forEach((key) => {
 			if (info.params[key] === '' || info.params[key] === null) {
@@ -133,6 +143,10 @@
 					knowledge = [...model?.info?.meta?.knowledge];
 				}
 
+				if (model?.info?.meta?.toolIds) {
+					toolIds = [...model?.info?.meta?.toolIds];
+				}
+
 				if (model?.owned_by === 'openai') {
 					capabilities.usage = false;
 				}
@@ -515,6 +529,10 @@
 				<Knowledge bind:knowledge />
 			</div>
 
+			<div class="my-2">
+				<ToolsSelector bind:selectedToolIds={toolIds} tools={$tools} />
+			</div>
+
 			<div class="my-2">
 				<div class="flex w-full justify-between mb-1">
 					<div class=" self-center text-sm font-semibold">{$i18n.t('Capabilities')}</div>