'use client' import { useState } from 'react' import useSWR from 'swr' import { api } from '@/lib/api-client' import type { AgentTemplate } from '@/lib/types' import { ErrorBanner, EmptyState } from '@/components/ui/state' import { TableSkeleton } from '@/components/ui/skeleton' export default function AgentTemplatesPage() { const [page, setPage] = useState(1) const [error, setError] = useState('') const [showCreate, setShowCreate] = useState(false) const [editingId, setEditingId] = useState(null) const { data, isLoading, mutate } = useSWR( ['agentTemplates.list', page], () => api.agentTemplates.list({ page, page_size: 50 }), ) const templates = data?.items ?? [] const total = data?.total ?? 0 const handleCreate = async (e: React.FormEvent) => { e.preventDefault() const fd = new FormData(e.currentTarget) try { const tools = (fd.get('tools') as string || '').split(',').map(s => s.trim()).filter(Boolean) const capabilities = (fd.get('capabilities') as string || '').split(',').map(s => s.trim()).filter(Boolean) await api.agentTemplates.create({ name: fd.get('name') as string, description: (fd.get('description') as string) || undefined, category: (fd.get('category') as string) || 'general', model: (fd.get('model') as string) || undefined, system_prompt: (fd.get('system_prompt') as string) || undefined, tools: tools.length > 0 ? tools : undefined, capabilities: capabilities.length > 0 ? capabilities : undefined, temperature: (fd.get('temperature') as string) ? parseFloat(fd.get('temperature') as string) : undefined, max_tokens: (fd.get('max_tokens') as string) ? parseInt(fd.get('max_tokens') as string, 10) : undefined, visibility: (fd.get('visibility') as string) || 'public', }) setShowCreate(false) mutate() } catch { setError('创建失败') } } const handleArchive = async (id: string, name: string) => { if (!confirm(`确认归档模板 "${name}"?`)) return try { await api.agentTemplates.archive(id) mutate() } catch { setError('归档失败') } } const statusBadge = (status: string) => { const colors: Record = { active: 'bg-emerald-500/20 text-emerald-400', archived: 'bg-zinc-500/20 text-zinc-400', } return {status} } const sourceBadge = (source: string) => { const colors: Record = { builtin: 'bg-blue-500/20 text-blue-400', custom: 'bg-purple-500/20 text-purple-400', } return ( {source === 'builtin' ? '内置' : '自定义'} ) } return (

Agent 配置模板

管理 Agent 配置模板,支持团队共享和一键复用

{error && setError('')} />}
{isLoading ? ( ) : templates.length === 0 ? ( ) : ( templates.map(t => ( )) )}
名称 分类 来源 模型 工具数 可见性 状态 更新时间 操作
{t.name} {t.description && (

{t.description}

)}
{t.category} {sourceBadge(t.source)} {t.model || '-'} {t.tools.length} {t.visibility} {statusBadge(t.status)} {new Date(t.updated_at).toLocaleString('zh-CN')} {t.source === 'custom' && ( )}
共 {total} 个模板
{/* 展开详情 */} {editingId && (() => { const t = templates.find(t => t.id === editingId) if (!t) return null return (

{t.name} — 详情

分类: {t.category}
模型: {t.model || '未指定'}
温度: {t.temperature?.toFixed(2) || '默认'}
最大 Token: {t.max_tokens || '未限制'}
工具:
{t.tools.length > 0 ? t.tools.map(tool => ( {tool} )) : }
能力:
{t.capabilities.length > 0 ? t.capabilities.map(cap => ( {cap} )) : }
{t.system_prompt && (
系统提示词:
                    {t.system_prompt.substring(0, 500)}{t.system_prompt.length > 500 ? '...' : ''}
                  
)}
) })()} {/* Create Modal */} {showCreate && (

新建 Agent 模板