Tool config using db
This commit is contained in:
@@ -2,17 +2,8 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { Plus, Search, Play, Copy, Trash2, Mic, MessageSquare, Save, Video, PhoneOff, Camera, ArrowLeftRight, Send, Phone, Rocket, AlertTriangle, PhoneCall, CameraOff, Image, Images, CloudSun, Calendar, TrendingUp, Coins, Wrench, Globe, Terminal, X, ClipboardCheck, Sparkles, Volume2, Timer, ChevronDown, Database, Server, Zap, ExternalLink, Key, BrainCircuit, Ear, Book, Filter } from 'lucide-react';
|
import { Plus, Search, Play, Copy, Trash2, Mic, MessageSquare, Save, Video, PhoneOff, Camera, ArrowLeftRight, Send, Phone, Rocket, AlertTriangle, PhoneCall, CameraOff, Image, Images, CloudSun, Calendar, TrendingUp, Coins, Wrench, Globe, Terminal, X, ClipboardCheck, Sparkles, Volume2, Timer, ChevronDown, Database, Server, Zap, ExternalLink, Key, BrainCircuit, Ear, Book, Filter } from 'lucide-react';
|
||||||
import { Button, Input, Badge, Drawer, Dialog } from '../components/UI';
|
import { Button, Input, Badge, Drawer, Dialog } from '../components/UI';
|
||||||
import { ASRModel, Assistant, KnowledgeBase, LLMModel, TabValue, Voice } from '../types';
|
import { ASRModel, Assistant, KnowledgeBase, LLMModel, TabValue, Tool, Voice } from '../types';
|
||||||
import { createAssistant, deleteAssistant, fetchASRModels, fetchAssistants, fetchKnowledgeBases, fetchLLMModels, fetchVoices, updateAssistant as updateAssistantApi } from '../services/backendApi';
|
import { createAssistant, deleteAssistant, fetchASRModels, fetchAssistants, fetchKnowledgeBases, fetchLLMModels, fetchTools, fetchVoices, updateAssistant as updateAssistantApi } from '../services/backendApi';
|
||||||
|
|
||||||
interface ToolItem {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
icon: React.ReactNode;
|
|
||||||
desc: string;
|
|
||||||
category: 'system' | 'query';
|
|
||||||
isCustom?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSiliconflowVendor = (vendor?: string) => {
|
const isSiliconflowVendor = (vendor?: string) => {
|
||||||
const normalized = String(vendor || '').trim().toLowerCase();
|
const normalized = String(vendor || '').trim().toLowerCase();
|
||||||
@@ -42,12 +33,31 @@ const resolveRuntimeTtsVoice = (selectedVoiceId: string, voice: Voice) => {
|
|||||||
return explicitKey || buildSiliconflowVoiceKey(selectedVoiceId, voice.model);
|
return explicitKey || buildSiliconflowVoiceKey(selectedVoiceId, voice.model);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderToolIcon = (icon: string) => {
|
||||||
|
const className = 'w-4 h-4';
|
||||||
|
const map: Record<string, React.ReactNode> = {
|
||||||
|
Camera: <Camera className={className} />,
|
||||||
|
CameraOff: <CameraOff className={className} />,
|
||||||
|
Image: <Image className={className} />,
|
||||||
|
Images: <Images className={className} />,
|
||||||
|
CloudSun: <CloudSun className={className} />,
|
||||||
|
Calendar: <Calendar className={className} />,
|
||||||
|
TrendingUp: <TrendingUp className={className} />,
|
||||||
|
Coins: <Coins className={className} />,
|
||||||
|
Terminal: <Terminal className={className} />,
|
||||||
|
Globe: <Globe className={className} />,
|
||||||
|
Wrench: <Wrench className={className} />,
|
||||||
|
};
|
||||||
|
return map[icon] || <Wrench className={className} />;
|
||||||
|
};
|
||||||
|
|
||||||
export const AssistantsPage: React.FC = () => {
|
export const AssistantsPage: React.FC = () => {
|
||||||
const [assistants, setAssistants] = useState<Assistant[]>([]);
|
const [assistants, setAssistants] = useState<Assistant[]>([]);
|
||||||
const [voices, setVoices] = useState<Voice[]>([]);
|
const [voices, setVoices] = useState<Voice[]>([]);
|
||||||
const [knowledgeBases, setKnowledgeBases] = useState<KnowledgeBase[]>([]);
|
const [knowledgeBases, setKnowledgeBases] = useState<KnowledgeBase[]>([]);
|
||||||
const [llmModels, setLlmModels] = useState<LLMModel[]>([]);
|
const [llmModels, setLlmModels] = useState<LLMModel[]>([]);
|
||||||
const [asrModels, setAsrModels] = useState<ASRModel[]>([]);
|
const [asrModels, setAsrModels] = useState<ASRModel[]>([]);
|
||||||
|
const [tools, setTools] = useState<Tool[]>([]);
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||||
const [activeTab, setActiveTab] = useState<TabValue>(TabValue.GLOBAL);
|
const [activeTab, setActiveTab] = useState<TabValue>(TabValue.GLOBAL);
|
||||||
@@ -58,16 +68,6 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
const [isPublishModalOpen, setIsPublishModalOpen] = useState(false);
|
const [isPublishModalOpen, setIsPublishModalOpen] = useState(false);
|
||||||
const [publishTab, setPublishTab] = useState<'web' | 'api'>('web');
|
const [publishTab, setPublishTab] = useState<'web' | 'api'>('web');
|
||||||
|
|
||||||
// Custom Tools State
|
|
||||||
const [customTools, setCustomTools] = useState<ToolItem[]>([]);
|
|
||||||
const [hiddenToolIds, setHiddenToolIds] = useState<string[]>([]);
|
|
||||||
const [isAddToolModalOpen, setIsAddToolModalOpen] = useState(false);
|
|
||||||
const [addingToCategory, setAddingToCategory] = useState<'system' | 'query'>('system');
|
|
||||||
|
|
||||||
// New Tool Form State
|
|
||||||
const [newToolName, setNewToolName] = useState('');
|
|
||||||
const [newToolDesc, setNewToolDesc] = useState('');
|
|
||||||
|
|
||||||
const [deleteId, setDeleteId] = useState<string | null>(null);
|
const [deleteId, setDeleteId] = useState<string | null>(null);
|
||||||
const [copySuccess, setCopySuccess] = useState(false);
|
const [copySuccess, setCopySuccess] = useState(false);
|
||||||
const [saveLoading, setSaveLoading] = useState(false);
|
const [saveLoading, setSaveLoading] = useState(false);
|
||||||
@@ -83,18 +83,20 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
const loadInitialData = async () => {
|
const loadInitialData = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const [assistantList, voiceList, kbList, llmList, asrList] = await Promise.all([
|
const [assistantList, voiceList, kbList, llmList, asrList, toolList] = await Promise.all([
|
||||||
fetchAssistants(),
|
fetchAssistants(),
|
||||||
fetchVoices(),
|
fetchVoices(),
|
||||||
fetchKnowledgeBases(),
|
fetchKnowledgeBases(),
|
||||||
fetchLLMModels(),
|
fetchLLMModels(),
|
||||||
fetchASRModels(),
|
fetchASRModels(),
|
||||||
|
fetchTools(),
|
||||||
]);
|
]);
|
||||||
setAssistants(assistantList);
|
setAssistants(assistantList);
|
||||||
setVoices(voiceList);
|
setVoices(voiceList);
|
||||||
setKnowledgeBases(kbList);
|
setKnowledgeBases(kbList);
|
||||||
setLlmModels(llmList);
|
setLlmModels(llmList);
|
||||||
setAsrModels(asrList);
|
setAsrModels(asrList);
|
||||||
|
setTools(toolList);
|
||||||
if (assistantList.length > 0) {
|
if (assistantList.length > 0) {
|
||||||
setSelectedId(assistantList[0].id);
|
setSelectedId(assistantList[0].id);
|
||||||
}
|
}
|
||||||
@@ -209,18 +211,10 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
updateAssistant('tools', newTools);
|
updateAssistant('tools', newTools);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteTool = (e: React.MouseEvent, toolId: string) => {
|
const removeImportedTool = (e: React.MouseEvent, tool: Tool) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setAssistants(prev => prev.map(a => ({
|
if (!selectedAssistant) return;
|
||||||
...a,
|
updateAssistant('tools', (selectedAssistant.tools || []).filter((id) => id !== tool.id));
|
||||||
tools: a.tools?.filter(id => id !== toolId) || []
|
|
||||||
})));
|
|
||||||
|
|
||||||
if (customTools.some(t => t.id === toolId)) {
|
|
||||||
setCustomTools(prev => prev.filter(t => t.id !== toolId));
|
|
||||||
} else {
|
|
||||||
setHiddenToolIds(prev => [...prev, toolId]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const addHotword = () => {
|
const addHotword = () => {
|
||||||
@@ -236,44 +230,8 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddCustomTool = () => {
|
const systemTools = tools.filter((t) => t.enabled !== false && t.category === 'system');
|
||||||
if (!newToolName.trim()) return;
|
const queryTools = tools.filter((t) => t.enabled !== false && t.category === 'query');
|
||||||
const newTool: ToolItem = {
|
|
||||||
id: `custom_${Date.now()}`,
|
|
||||||
name: newToolName,
|
|
||||||
desc: newToolDesc,
|
|
||||||
category: addingToCategory,
|
|
||||||
icon: addingToCategory === 'system' ? <Terminal className="w-4 h-4" /> : <Globe className="w-4 h-4" />,
|
|
||||||
isCustom: true
|
|
||||||
};
|
|
||||||
setCustomTools([...customTools, newTool]);
|
|
||||||
setIsAddToolModalOpen(false);
|
|
||||||
setNewToolName('');
|
|
||||||
setNewToolDesc('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const openAddToolModal = (e: React.MouseEvent, cat: 'system' | 'query') => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setAddingToCategory(cat);
|
|
||||||
setIsAddToolModalOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const baseSystemTools: ToolItem[] = [
|
|
||||||
{ id: 'cam_open', name: '打开相机', icon: <Camera className="w-4 h-4" />, desc: '允许 AI 开启摄像头流', category: 'system' },
|
|
||||||
{ id: 'cam_close', name: '关闭相机', icon: <CameraOff className="w-4 h-4" />, desc: '允许 AI 停止摄像头流', category: 'system' },
|
|
||||||
{ id: 'take_photo', name: '拍照', icon: <Image className="w-4 h-4" />, desc: 'AI 触发单张拍摄', category: 'system' },
|
|
||||||
{ id: 'burst_3', name: '连拍三张', icon: <Images className="w-4 h-4" />, desc: 'AI 触发快速连拍', category: 'system' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const baseQueryTools: ToolItem[] = [
|
|
||||||
{ id: 'q_weather', name: '天气查询', icon: <CloudSun className="w-4 h-4" />, desc: '查询实时及未来天气', category: 'query' },
|
|
||||||
{ id: 'q_calendar', name: '日历查询', icon: <Calendar className="w-4 h-4" />, desc: '查询日程及节假日信息', category: 'query' },
|
|
||||||
{ id: 'q_stock', name: '股价查询', icon: <TrendingUp className="w-4 h-4" />, desc: '查询股票实时行情', category: 'query' },
|
|
||||||
{ id: 'q_exchange', name: '汇率查询', icon: <Coins className="w-4 h-4" />, desc: '查询多国货币汇率', category: 'query' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const systemTools = [...baseSystemTools, ...customTools.filter(t => t.category === 'system')].filter(t => !hiddenToolIds.includes(t.id));
|
|
||||||
const queryTools = [...baseQueryTools, ...customTools.filter(t => t.category === 'query')].filter(t => !hiddenToolIds.includes(t.id));
|
|
||||||
|
|
||||||
const isExternalConfig = selectedAssistant?.configMode === 'dify' || selectedAssistant?.configMode === 'fastgpt';
|
const isExternalConfig = selectedAssistant?.configMode === 'dify' || selectedAssistant?.configMode === 'fastgpt';
|
||||||
const isNoneConfig = selectedAssistant?.configMode === 'none' || !selectedAssistant?.configMode;
|
const isNoneConfig = selectedAssistant?.configMode === 'none' || !selectedAssistant?.configMode;
|
||||||
@@ -766,12 +724,6 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
<h3 className="text-[10px] font-black flex items-center text-primary uppercase tracking-[0.2em]">
|
<h3 className="text-[10px] font-black flex items-center text-primary uppercase tracking-[0.2em]">
|
||||||
<Wrench className="w-3.5 h-3.5 mr-2" /> 系统指令
|
<Wrench className="w-3.5 h-3.5 mr-2" /> 系统指令
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
|
||||||
onClick={(e) => openAddToolModal(e, 'system')}
|
|
||||||
className="p-1 rounded-full bg-primary/10 text-primary hover:bg-primary/20 transition-colors shadow-sm"
|
|
||||||
>
|
|
||||||
<Plus className="w-3.5 h-3.5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
{systemTools.map(tool => (
|
{systemTools.map(tool => (
|
||||||
@@ -781,7 +733,7 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
className={`p-4 rounded-xl border transition-all cursor-pointer group relative flex items-start space-x-3 ${selectedAssistant.tools?.includes(tool.id) ? 'bg-primary/10 border-primary/40 shadow-[0_0_15px_rgba(6,182,212,0.1)]' : 'bg-card/30 border-white/5 hover:bg-white/5 hover:border-white/10'}`}
|
className={`p-4 rounded-xl border transition-all cursor-pointer group relative flex items-start space-x-3 ${selectedAssistant.tools?.includes(tool.id) ? 'bg-primary/10 border-primary/40 shadow-[0_0_15px_rgba(6,182,212,0.1)]' : 'bg-card/30 border-white/5 hover:bg-white/5 hover:border-white/10'}`}
|
||||||
>
|
>
|
||||||
<div className={`p-2 rounded-lg shrink-0 transition-colors ${selectedAssistant.tools?.includes(tool.id) ? 'bg-primary text-primary-foreground' : 'bg-white/5 text-muted-foreground'}`}>
|
<div className={`p-2 rounded-lg shrink-0 transition-colors ${selectedAssistant.tools?.includes(tool.id) ? 'bg-primary text-primary-foreground' : 'bg-white/5 text-muted-foreground'}`}>
|
||||||
{tool.icon}
|
{renderToolIcon(tool.icon)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center justify-between mb-0.5">
|
<div className="flex items-center justify-between mb-0.5">
|
||||||
@@ -790,15 +742,17 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
{selectedAssistant.tools?.includes(tool.id) && <div className="w-1.5 h-1.5 bg-white rounded-full"></div>}
|
{selectedAssistant.tools?.includes(tool.id) && <div className="w-1.5 h-1.5 bg-white rounded-full"></div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[10px] text-muted-foreground line-clamp-1 opacity-70">{tool.desc}</p>
|
<p className="text-[10px] text-muted-foreground line-clamp-1 opacity-70">{tool.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
{selectedAssistant.tools?.includes(tool.id) && (
|
||||||
onClick={(e) => deleteTool(e, tool.id)}
|
<button
|
||||||
className="absolute -top-1 -right-1 p-0.5 rounded-full bg-destructive text-white opacity-0 group-hover:opacity-100 transition-opacity hover:scale-110 shadow-lg z-10"
|
onClick={(e) => removeImportedTool(e, tool)}
|
||||||
title="删除工具"
|
className="absolute -top-1 -right-1 p-0.5 rounded-full bg-destructive text-white opacity-0 group-hover:opacity-100 transition-opacity hover:scale-110 shadow-lg z-10"
|
||||||
>
|
title="从当前小助手移除"
|
||||||
<X className="w-3 h-3" />
|
>
|
||||||
</button>
|
<X className="w-3 h-3" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -809,12 +763,6 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
<h3 className="text-[10px] font-black flex items-center text-blue-400 uppercase tracking-[0.2em]">
|
<h3 className="text-[10px] font-black flex items-center text-blue-400 uppercase tracking-[0.2em]">
|
||||||
<TrendingUp className="w-3.5 h-3.5 mr-2" /> 信息查询
|
<TrendingUp className="w-3.5 h-3.5 mr-2" /> 信息查询
|
||||||
</h3>
|
</h3>
|
||||||
<button
|
|
||||||
onClick={(e) => openAddToolModal(e, 'query')}
|
|
||||||
className="p-1 rounded-full bg-blue-500/10 text-blue-400 hover:bg-blue-500/20 transition-colors shadow-sm"
|
|
||||||
>
|
|
||||||
<Plus className="w-3.5 h-3.5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
{queryTools.map(tool => (
|
{queryTools.map(tool => (
|
||||||
@@ -824,7 +772,7 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
className={`p-4 rounded-xl border transition-all cursor-pointer group relative flex items-start space-x-3 ${selectedAssistant.tools?.includes(tool.id) ? 'bg-blue-500/10 border-blue-500/40 shadow-[0_0_15px_rgba(59,130,246,0.1)]' : 'bg-card/30 border-white/5 hover:bg-white/5 hover:border-white/10'}`}
|
className={`p-4 rounded-xl border transition-all cursor-pointer group relative flex items-start space-x-3 ${selectedAssistant.tools?.includes(tool.id) ? 'bg-blue-500/10 border-blue-500/40 shadow-[0_0_15px_rgba(59,130,246,0.1)]' : 'bg-card/30 border-white/5 hover:bg-white/5 hover:border-white/10'}`}
|
||||||
>
|
>
|
||||||
<div className={`p-2 rounded-lg shrink-0 transition-colors ${selectedAssistant.tools?.includes(tool.id) ? 'bg-blue-500 text-white' : 'bg-white/5 text-muted-foreground'}`}>
|
<div className={`p-2 rounded-lg shrink-0 transition-colors ${selectedAssistant.tools?.includes(tool.id) ? 'bg-blue-500 text-white' : 'bg-white/5 text-muted-foreground'}`}>
|
||||||
{tool.icon}
|
{renderToolIcon(tool.icon)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center justify-between mb-0.5">
|
<div className="flex items-center justify-between mb-0.5">
|
||||||
@@ -833,22 +781,24 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
{selectedAssistant.tools?.includes(tool.id) && <div className="w-1.5 h-1.5 bg-white rounded-full"></div>}
|
{selectedAssistant.tools?.includes(tool.id) && <div className="w-1.5 h-1.5 bg-white rounded-full"></div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[10px] text-muted-foreground line-clamp-1 opacity-70">{tool.desc}</p>
|
<p className="text-[10px] text-muted-foreground line-clamp-1 opacity-70">{tool.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<button
|
{selectedAssistant.tools?.includes(tool.id) && (
|
||||||
onClick={(e) => deleteTool(e, tool.id)}
|
<button
|
||||||
className="absolute -top-1 -right-1 p-0.5 rounded-full bg-destructive text-white opacity-0 group-hover:opacity-100 transition-opacity hover:scale-110 shadow-lg z-10"
|
onClick={(e) => removeImportedTool(e, tool)}
|
||||||
title="删除工具"
|
className="absolute -top-1 -right-1 p-0.5 rounded-full bg-destructive text-white opacity-0 group-hover:opacity-100 transition-opacity hover:scale-110 shadow-lg z-10"
|
||||||
>
|
title="从当前小助手移除"
|
||||||
<X className="w-3 h-3" />
|
>
|
||||||
</button>
|
<X className="w-3 h-3" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 bg-white/5 border border-white/5 rounded-xl text-[10px] text-muted-foreground flex items-center gap-3">
|
<div className="p-4 bg-white/5 border border-white/5 rounded-xl text-[10px] text-muted-foreground flex items-center gap-3">
|
||||||
<Rocket className="w-4 h-4 text-primary shrink-0" />
|
<Rocket className="w-4 h-4 text-primary shrink-0" />
|
||||||
<span>提示:启用工具后,AI 将能在对话中自动识别并调用相关功能以协助用户。</span>
|
<span>提示:此处仅导入工具库中的已有工具。移除仅对当前小助手生效,不会删除工具库。</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -968,44 +918,6 @@ export const AssistantsPage: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Add Custom Tool Modal */}
|
|
||||||
<Dialog
|
|
||||||
isOpen={isAddToolModalOpen}
|
|
||||||
onClose={() => setIsAddToolModalOpen(false)}
|
|
||||||
title={addingToCategory === 'system' ? '添加自定义系统指令' : '添加自定义信息查询'}
|
|
||||||
footer={
|
|
||||||
<>
|
|
||||||
<Button variant="ghost" onClick={() => setIsAddToolModalOpen(false)}>取消</Button>
|
|
||||||
<Button onClick={handleAddCustomTool}>确认添加</Button>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="space-y-1.5">
|
|
||||||
<label className="text-[10px] font-black text-muted-foreground uppercase tracking-widest block">工具名称</label>
|
|
||||||
<Input
|
|
||||||
value={newToolName}
|
|
||||||
onChange={e => setNewToolName(e.target.value)}
|
|
||||||
placeholder="例如: 智能家居控制"
|
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-1.5">
|
|
||||||
<label className="text-[10px] font-black text-muted-foreground uppercase tracking-widest block">工具描述 (给 AI 的说明)</label>
|
|
||||||
<textarea
|
|
||||||
className="flex min-h-[100px] w-full rounded-md border border-white/10 bg-white/5 px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/50 text-white"
|
|
||||||
value={newToolDesc}
|
|
||||||
onChange={e => setNewToolDesc(e.target.value)}
|
|
||||||
placeholder="描述该工具的功能,以及 AI 应该在什么情况下调用它..."
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="p-3 bg-primary/5 border border-primary/20 rounded-lg text-[10px] text-muted-foreground flex items-start gap-2">
|
|
||||||
<Wrench className="w-3.5 h-3.5 text-primary shrink-0 mt-0.5" />
|
|
||||||
<p>自定义工具将通过其名称 and 描述告知 AI 它的用途。您可以在后续的工作流中进一步定义 these 工具的具体行为逻辑。</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
{/* Delete Confirmation Dialog */}
|
{/* Delete Confirmation Dialog */}
|
||||||
<Dialog
|
<Dialog
|
||||||
isOpen={!!deleteId}
|
isOpen={!!deleteId}
|
||||||
|
|||||||
Reference in New Issue
Block a user