Files
deerflow-code/web-code/pages/AgentDetail.tsx
T
2026-05-27 19:43:15 +08:00

878 lines
50 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { useTheme } from '../contexts/ThemeContext';
import {
ArrowLeft,
Save,
RotateCcw,
Power,
Trash2,
Copy,
ChevronDown,
ChevronRight,
Bot,
Target,
Brain,
Database,
Box,
Route,
FileOutput,
Sparkles,
Lightbulb,
MessageSquare,
Play,
Send,
Plus,
X,
Check,
AlertCircle,
Wrench,
Layers,
Zap,
Clock,
} from 'lucide-react';
interface AgentDetailProps {
agentId: string | null;
onBack: () => void;
}
interface ExpandedSection {
basic: boolean;
responsibility: boolean;
skills: boolean;
datasource: boolean;
function: boolean;
thinking: boolean;
output: boolean;
}
const AgentDetail: React.FC<AgentDetailProps> = ({ agentId, onBack }) => {
const { theme } = useTheme();
const isDark = theme === 'dark';
// 主题颜色类
const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white';
const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-200';
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
const textMuted = isDark ? 'text-slate-500' : 'text-gray-500';
const btnSecondary = isDark ? 'bg-slate-700/50 hover:bg-slate-600/50 border-blue-800/30 text-slate-300' : 'bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700';
const btnPrimary = isDark ? 'bg-blue-600 hover:bg-blue-500' : 'bg-red-600 hover:bg-red-500';
const inputBg = isDark ? 'bg-slate-900/50' : 'bg-gray-50';
const inputBorder = isDark ? 'border-blue-800/30' : 'border-gray-300';
const [isEnabled, setIsEnabled] = useState(true);
const [expandedSections, setExpandedSections] = useState<ExpandedSection>({
basic: true,
responsibility: true,
skills: true,
datasource: true,
function: true,
thinking: true,
output: true,
});
const [chatMessages, setChatMessages] = useState<{role: 'user' | 'agent'; content: string}[]>([
{ role: 'agent', content: '核心受众应聚焦18-25岁基层青年群体,原因是该群体社交媒体活跃度高、注重性价比、偏好真实有态度的品牌叙事。' }
]);
const [chatInput, setChatInput] = useState('');
const [aiSuggestion, setAiSuggestion] = useState('');
const [showGeneratedConfig, setShowGeneratedConfig] = useState(false);
const toggleSection = (section: keyof ExpandedSection) => {
setExpandedSections(prev => ({ ...prev, [section]: !prev[section] }));
};
const skills = [
{ name: '受众分层', type: '分析类', enabled: true, trigger: '自动', priority: 1 },
{ name: '核心受众识别', type: '推断类', enabled: true, trigger: '自动', priority: 1 },
{ name: '受众画像抽取', type: '抽取类', enabled: true, trigger: '条件触发', priority: 2 },
{ name: '阻力因素提炼', type: '分析类', enabled: true, trigger: '手动', priority: 3 },
];
const dataSources = [
{ name: '宣传知识库', type: '知识库', status: 'connected', permission: '只读', trigger: '自动', access: '品牌案例、活动方法论、历史策略' },
{ name: 'Y系统', type: '业务系统', status: 'connected', permission: '只读', trigger: '条件触发', access: '用户标签、传播数据' },
{ name: 'A系统', type: '业务系统', status: 'disconnected', permission: '无', trigger: '不可用', access: '—' },
{ name: '市场数据库', type: '外部数据源', status: 'connected', permission: '只读', trigger: '手动', access: '市场报告、用户研究摘要' },
];
const functions = [
{ name: '信息抽取器', type: '抽取', enabled: true, trigger: '自动', usage: '提取任务中的受众相关信息' },
{ name: '标签聚类器', type: '分析', enabled: true, trigger: '条件触发', usage: '辅助进行受众分层' },
{ name: '案例检索器', type: '检索', enabled: true, trigger: '手动', usage: '调用历史案例进行参照' },
{ name: '结构化输出器', type: '格式化', enabled: true, trigger: '自动', usage: '输出标准JSON字段' },
];
const thinkingSteps = [
{ step: 1, name: '识别任务中的目标对象', desc: '提取任务中明确或隐含的目标受众信息', required: true, skill: '受众分层', func: '信息抽取器', ds: '无' },
{ step: 2, name: '判断是否需要分层', desc: '根据任务目标判断是否区分核心/次级/影响者受众', required: true, skill: '核心受众识别', func: '标签聚类器', ds: 'Y系统' },
{ step: 3, name: '提取核心受众特征', desc: '分析年龄、身份、关切与行为特征', required: true, skill: '画像抽取', func: '结构化输出器', ds: '宣传知识库' },
{ step: 4, name: '输出结构化结果', desc: '形成标准受众分析输出', required: true, skill: '—', func: '结构化输出器', ds: '—' },
];
const outputFields = [
{ name: 'core_audience', type: '文本', required: true },
{ name: 'secondary_audience', type: '文本', required: false },
{ name: 'key_traits', type: '数组', required: true },
{ name: 'concerns', type: '数组', required: false },
{ name: 'barriers', type: '数组', required: false },
{ name: 'trust_sources', type: '数组', required: false },
];
const aiOptimizations = [
{ issue: '当前已配置"受众画像抽取"技能,但未配置对应输出字段', canFix: true },
{ issue: '思考路径中"判断是否需要分层"步骤未绑定功能调用', canFix: true },
{ issue: '已绑定A系统,但当前无任何步骤使用该数据源', canFix: false },
];
const executionDetails = {
dataSources: ['宣传知识库', 'Y系统'],
skills: ['受众分层', '核心受众识别', '画像抽取'],
functions: ['信息抽取器', '标签聚类器', '结构化输出器'],
outputs: ['core_audience', 'key_traits', 'barriers'],
};
const handleSendMessage = () => {
if (chatInput.trim()) {
setChatMessages([...chatMessages, { role: 'user', content: chatInput }]);
setChatInput('');
setTimeout(() => {
setChatMessages(prev => [...prev, {
role: 'agent',
content: '核心受众应聚焦18-25岁基层青年群体,原因是该群体社交媒体活跃度高、注重性价比、偏好真实有态度的品牌叙事。'
}]);
}, 1000);
}
};
const handleGenerateConfig = () => {
setAiSuggestion('正在分析职责、技能、数据源...');
setTimeout(() => {
setShowGeneratedConfig(true);
setAiSuggestion('');
}, 1500);
};
const SectionHeader = ({
title,
subtitle,
icon: Icon,
section,
children
}: {
title: string;
subtitle: string;
icon: React.ElementType;
section: keyof ExpandedSection;
children: React.ReactNode;
}) => (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl`}>
<button
onClick={() => toggleSection(section)}
className={`w-full flex items-center justify-between p-4 ${isDark ? 'hover:bg-slate-800/50' : 'hover:bg-gray-100'} transition-colors sticky top-0 z-10 ${cardBg} backdrop-blur-xl`}
>
<div className="flex items-center gap-3">
<div className={`w-10 h-10 rounded-lg ${isDark ? 'bg-blue-500/20' : 'bg-red-100'} flex items-center justify-center`}>
<Icon className={`w-5 h-5 ${isDark ? 'text-blue-400' : 'text-red-500'}`} />
</div>
<div className="text-left">
<h3 className={`${textPrimary} font-semibold`}>{title}</h3>
<p className={`${textMuted} text-xs`}>{subtitle}</p>
</div>
</div>
{expandedSections[section] ? (
<ChevronDown className={`w-5 h-5 ${textSecondary}`} />
) : (
<ChevronRight className={`w-5 h-5 ${textSecondary}`} />
)}
</button>
{expandedSections[section] && (
<div className="px-4 pb-4">
{children}
</div>
)}
</div>
);
return (
<div className="h-[calc(100vh-140px)] flex flex-col overflow-hidden">
{/* 顶部操作栏 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} p-4 flex-shrink-0`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<button onClick={onBack} className={`p-2 ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-gray-200'} rounded-lg transition-colors`}>
<ArrowLeft className={`w-5 h-5 ${textSecondary}`} />
</button>
<div>
<p className={`${textSecondary} text-xs`}>智能体能力配置</p>
<div className="flex items-center gap-2 mt-0.5">
<Bot className={`w-4 h-4 ${isDark ? 'text-blue-400' : 'text-red-500'}`} />
<span className={`${textPrimary} font-semibold`}>AudienceAgent</span>
<span className={`px-2 py-0.5 rounded-full text-xs font-medium ${
isEnabled
? isDark ? 'bg-green-500/20 text-green-400' : 'bg-green-100 text-green-600'
: isDark ? 'bg-slate-500/20 text-slate-400' : 'bg-gray-200 text-gray-500'
}`}>
{isEnabled ? '启用' : '停用'}
</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<button className={`flex items-center gap-2 px-4 py-2 ${btnPrimary} text-white rounded-lg text-sm transition-colors`}>
<Save className="w-4 h-4" />
保存
</button>
<button className={`flex items-center gap-2 px-4 py-2 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<RotateCcw className="w-4 h-4" />
重置
</button>
<button
onClick={() => setIsEnabled(!isEnabled)}
className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors ${
isEnabled
? isDark ? 'bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/30 text-amber-400' : 'bg-amber-100 hover:bg-amber-200 border border-amber-200 text-amber-600'
: isDark ? 'bg-green-500/20 hover:bg-green-500/30 border border-green-500/30 text-green-400' : 'bg-green-100 hover:bg-green-200 border border-green-200 text-green-600'
}`}
>
<Power className="w-4 h-4" />
{isEnabled ? '停用' : '启用'}
</button>
<button className={`flex items-center gap-2 px-4 py-2 ${btnSecondary} ${isDark ? 'hover:text-red-400' : 'hover:text-red-500'} rounded-lg text-sm transition-colors`}>
<Trash2 className="w-4 h-4" />
删除
</button>
<button className={`flex items-center gap-2 px-4 py-2 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<Copy className="w-4 h-4" />
复制
</button>
</div>
</div>
</div>
{/* 主内容区:三栏布局 */}
<div className="flex-1 grid grid-cols-12 gap-4 mt-4 min-h-0">
{/* 左侧主配置区 (65%) - 带自定义滚动条 */}
<div className="col-span-8 flex flex-col gap-4 h-full overflow-y-auto scrollbar-thin scrollbar-thumb-slate-600 scrollbar-track-transparent hover:scrollbar-thumb-slate-500">
{/* 模块1:基本信息 */}
<SectionHeader
title="基本信息"
subtitle="定义智能体的基本身份、用途和交互属性"
icon={Bot}
section="basic"
>
<div className="space-y-4 pt-2">
<div className="grid grid-cols-2 gap-4">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>智能体名称</label>
<input
type="text"
defaultValue="AudienceAgent"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>智能体编码</label>
<input
type="text"
defaultValue="AGENT_AUDIENCE_001"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>智能体分类</label>
<select className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}>
<option>分析类</option>
<option>编排类</option>
<option>叙事类</option>
<option>校验类</option>
<option>成稿类</option>
</select>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>默认交互模式</label>
<select className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}>
<option>分析式</option>
<option>对话式</option>
<option>指令式</option>
</select>
</div>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>智能体说明</label>
<textarea
rows={2}
defaultValue="负责分析核心受众特征,输出受众画像和行为特征,为后续策略制定提供数据支持"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'} resize-none`}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>专业标签</label>
<div className={`flex flex-wrap gap-2 p-3 ${inputBg} ${inputBorder} rounded-lg min-h-[46px]`}>
{['受众分析', '用户画像', '分层识别'].map((tag) => (
<span key={tag} className={`px-2 py-1 ${isDark ? 'bg-blue-500/20 text-blue-400' : 'bg-red-100 text-red-600'} rounded text-xs flex items-center gap-1`}>
{tag}
<button className={`hover:${isDark ? 'text-blue-300' : 'text-red-400'}`}><X className="w-3 h-3" /></button>
</span>
))}
<button className={`px-2 py-1 ${textSecondary} hover:${textPrimary} text-xs flex items-center gap-1`}>
<Plus className="w-3 h-3" /> 添加
</button>
</div>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>适用任务关键词</label>
<div className={`flex flex-wrap gap-2 p-3 ${inputBg} ${inputBorder} rounded-lg min-h-[46px]`}>
{['宣传对象分析', '核心人群识别'].map((tag) => (
<span key={tag} className={`px-2 py-1 ${isDark ? 'bg-cyan-500/20 text-cyan-400' : 'bg-orange-100 text-orange-600'} rounded text-xs flex items-center gap-1`}>
{tag}
<button className={`hover:${isDark ? 'text-cyan-300' : 'text-orange-400'}`}><X className="w-3 h-3" /></button>
</span>
))}
<button className={`px-2 py-1 ${textSecondary} hover:${textPrimary} text-xs flex items-center gap-1`}>
<Plus className="w-3 h-3" /> 添加
</button>
</div>
</div>
</div>
<div className={`flex items-center gap-6 pt-2 border-t ${cardBorder}`}>
<div className="flex items-center gap-3">
<span className={`${textSecondary} text-sm`}>支持单独问答</span>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className={`w-11 h-6 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all ${isDark ? 'peer-checked:bg-blue-600' : 'peer-checked:bg-red-500'}`}></div>
</label>
</div>
<div className="flex items-center gap-3">
<span className={`${textSecondary} text-sm`}>支持单独任务执行</span>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className={`w-11 h-6 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all ${isDark ? 'peer-checked:bg-blue-600' : 'peer-checked:bg-red-500'}`}></div>
</label>
</div>
</div>
</div>
</SectionHeader>
{/* 模块2:职责与边界 */}
<SectionHeader
title="职责与边界"
subtitle="明确智能体的工作范围、边界与禁止事项"
icon={Target}
section="responsibility"
>
<div className="space-y-4 pt-2">
<div className="grid grid-cols-2 gap-4">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>核心职责</label>
<textarea
rows={3}
defaultValue="识别任务中的关键受众群体,对受众进行分层,并提炼特征、关切与阻力,形成完整的受众画像报告。"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'} resize-none`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>职责边界</label>
<textarea
rows={3}
defaultValue="不直接生成叙事方案;不负责风险最终审核;不替代行为分析;不在缺少依据时擅自扩大受众范围。"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'} resize-none`}
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>禁止事项</label>
<textarea
rows={2}
defaultValue="不得在缺少依据时擅自扩大受众范围;不得输出与任务无关的人群判断;不得更改任务目标。"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'} resize-none`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>典型任务</label>
<textarea
rows={2}
defaultValue="分析某宣传任务的核心受众是谁;输出受众画像;识别影响者与阻力群体;提炼受众关切与信任来源。"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'} resize-none`}
/>
</div>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>不处理的问题</label>
<textarea
rows={2}
defaultValue="不负责撰写传播文案;不负责渠道投放建议;不生成具体执行方案;不进行风险评估。"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'} resize-none`}
/>
</div>
<div className={`flex items-center gap-2 pt-2 border-t ${cardBorder}`}>
<button className={`flex items-center gap-2 px-3 py-1.5 ${isDark ? 'bg-blue-500/20 hover:bg-blue-500/30 border border-blue-500/30 text-blue-400' : 'bg-red-100 hover:bg-red-200 border border-red-200 text-red-600'} rounded-lg text-xs transition-colors`}>
<Sparkles className="w-3 h-3" /> AI生成职责
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Lightbulb className="w-3 h-3" /> AI补全边界
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<AlertCircle className="w-3 h-3" /> AI发现冲突
</button>
</div>
</div>
</SectionHeader>
{/* 模块3:技能配置 */}
<SectionHeader
title="技能配置"
subtitle="定义智能体当前启用的技能及其触发方式"
icon={Layers}
section="skills"
>
<div className="space-y-3 pt-2">
{skills.map((skill, index) => (
<div key={index} className={`p-3 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className={`w-8 h-8 rounded ${isDark ? 'bg-purple-500/20' : 'bg-purple-100'} flex items-center justify-center`}>
<Brain className={`w-4 h-4 ${isDark ? 'text-purple-400' : 'text-purple-600'}`} />
</div>
<div>
<p className={`${textPrimary} text-sm font-medium`}>{skill.name}</p>
<p className={`${textMuted} text-xs`}>类型:{skill.type} · 触发:{skill.trigger} · 优先级:{skill.priority}</p>
</div>
</div>
<div className="flex items-center gap-2">
<button className={`p-1.5 ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-gray-200'} rounded transition-colors`}>
<Wrench className={`w-4 h-4 ${textSecondary}`} />
</button>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked={skill.enabled} />
<div className={`w-9 h-5 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all ${isDark ? 'peer-checked:bg-green-600' : 'peer-checked:bg-green-500'}`}></div>
</label>
</div>
</div>
</div>
))}
<div className={`flex items-center gap-2 pt-2 border-t ${cardBorder}`}>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Plus className="w-3 h-3" /> 新增Skill
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${isDark ? 'bg-blue-500/20 hover:bg-blue-500/30 border border-blue-500/30 text-blue-400' : 'bg-red-100 hover:bg-red-200 border border-red-200 text-red-600'} rounded-lg text-xs transition-colors`}>
<Sparkles className="w-3 h-3" /> AI推荐Skill
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Zap className="w-3 h-3" /> AI生成技能组
</button>
</div>
</div>
</SectionHeader>
{/* 模块4:数据源访问 */}
<SectionHeader
title="数据源访问"
subtitle="定义智能体可读取的知识与系统数据"
icon={Database}
section="datasource"
>
<div className="space-y-3 pt-2">
{dataSources.map((ds, index) => (
<div key={index} className={`p-3 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className={`w-8 h-8 rounded flex items-center justify-center ${
ds.status === 'connected' ? (isDark ? 'bg-green-500/20' : 'bg-green-100') : (isDark ? 'bg-slate-500/20' : 'bg-gray-200')
}`}>
<Database className={`w-4 h-4 ${ds.status === 'connected' ? (isDark ? 'text-green-400' : 'text-green-600') : textSecondary}`} />
</div>
<div>
<p className={`${textPrimary} text-sm font-medium`}>{ds.name}</p>
<p className={`${textMuted} text-xs`}>类型:{ds.type} · 权限:{ds.permission} · 调用:{ds.trigger}</p>
</div>
</div>
<span className={`px-2 py-0.5 rounded text-xs ${
ds.status === 'connected'
? isDark ? 'bg-green-500/20 text-green-400' : 'bg-green-100 text-green-600'
: isDark ? 'bg-slate-500/20 text-slate-400' : 'bg-gray-200 text-gray-500'
}`}>
{ds.status === 'connected' ? '已连接' : '未连接'}
</span>
</div>
<p className={`${textSecondary} text-xs mt-2`}>可访问:{ds.access}</p>
</div>
))}
<div className={`flex items-center gap-2 pt-2 border-t ${cardBorder}`}>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Plus className="w-3 h-3" /> 绑定数据源
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${isDark ? 'bg-blue-500/20 hover:bg-blue-500/30 border border-blue-500/30 text-blue-400' : 'bg-red-100 hover:bg-red-200 border border-red-200 text-red-600'} rounded-lg text-xs transition-colors`}>
<Sparkles className="w-3 h-3" /> AI推荐数据源
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<AlertCircle className="w-3 h-3" /> AI识别缺失
</button>
</div>
</div>
</SectionHeader>
{/* 模块5:功能调用 */}
<SectionHeader
title="功能调用"
subtitle="定义智能体可调配的处理功能与工具能力"
icon={Box}
section="function"
>
<div className="space-y-3 pt-2">
{functions.map((func, index) => (
<div key={index} className={`p-3 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className={`w-8 h-8 rounded ${isDark ? 'bg-cyan-500/20' : 'bg-cyan-100'} flex items-center justify-center`}>
<Box className={`w-4 h-4 ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`} />
</div>
<div>
<p className={`${textPrimary} text-sm font-medium`}>{func.name}</p>
<p className={`${textMuted} text-xs`}>类型:{func.type} · 调用:{func.trigger}</p>
</div>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked={func.enabled} />
<div className={`w-9 h-5 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all ${isDark ? 'peer-checked:bg-green-600' : 'peer-checked:bg-green-500'}`}></div>
</label>
</div>
<p className={`${textSecondary} text-xs mt-2`}>用途:{func.usage}</p>
</div>
))}
<div className={`flex items-center gap-2 pt-2 border-t ${cardBorder}`}>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Plus className="w-3 h-3" /> 新增功能
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${isDark ? 'bg-blue-500/20 hover:bg-blue-500/30 border border-blue-500/30 text-blue-400' : 'bg-red-100 hover:bg-red-200 border border-red-200 text-red-600'} rounded-lg text-xs transition-colors`}>
<Sparkles className="w-3 h-3" /> AI推荐功能
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Zap className="w-3 h-3" /> AI检查冗余
</button>
</div>
</div>
</SectionHeader>
{/* 模块6:思考路径 */}
<SectionHeader
title="思考路径"
subtitle="定义智能体处理任务时的默认分析顺序"
icon={Route}
section="thinking"
>
<div className="space-y-3 pt-2">
{thinkingSteps.map((step) => (
<div key={step.step} className={`p-3 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-start gap-3">
<div className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0 mt-0.5 ${
step.step <= 2
? isDark ? 'bg-green-500 text-white' : 'bg-green-500 text-white'
: isDark ? 'bg-blue-500 text-white' : 'bg-blue-500 text-white'
}`}>
{step.step}
</div>
<div className="flex-1">
<div className="flex items-center justify-between">
<p className={`${textPrimary} text-sm font-medium`}>{step.name}</p>
{step.required && (
<span className={`px-1.5 py-0.5 ${isDark ? 'bg-red-500/20 text-red-400' : 'bg-red-100 text-red-600'} rounded text-[10px]`}>必选</span>
)}
</div>
<p className={`${textSecondary} text-xs mt-1`}>{step.desc}</p>
<div className="flex items-center gap-4 mt-2 text-xs">
<span className={`${textMuted}`}>Skill: <span className={isDark ? 'text-purple-400' : 'text-purple-600'}>{step.skill}</span></span>
<span className={`${textMuted}`}>功能: <span className={isDark ? 'text-cyan-400' : 'text-cyan-600'}>{step.func}</span></span>
<span className={`${textMuted}`}>数据源: <span className={isDark ? 'text-green-400' : 'text-green-600'}>{step.ds}</span></span>
</div>
</div>
<button className={`p-1.5 ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-gray-200'} rounded transition-colors`}>
<Wrench className={`w-4 h-4 ${textSecondary}`} />
</button>
</div>
</div>
))}
<div className={`flex items-center gap-2 pt-2 border-t ${cardBorder}`}>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Plus className="w-3 h-3" /> 新增步骤
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${isDark ? 'bg-blue-500/20 hover:bg-blue-500/30 border border-blue-500/30 text-blue-400' : 'bg-red-100 hover:bg-red-200 border border-red-200 text-red-600'} rounded-lg text-xs transition-colors`}>
<Sparkles className="w-3 h-3" /> AI生成思考路径
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Route className="w-3 h-3" /> AI优化顺序
</button>
</div>
</div>
</SectionHeader>
{/* 模块7:输出结构 */}
<SectionHeader
title="输出结构"
subtitle="定义对话输出、结构化输出与可复用片段"
icon={FileOutput}
section="output"
>
<div className="space-y-4 pt-2">
<div className={`p-3 ${isDark ? 'bg-blue-500/10 border border-blue-500/30' : 'bg-red-50 border border-red-200'} rounded-lg`}>
<p className={`${isDark ? 'text-blue-400' : 'text-red-600'} text-sm font-medium mb-2`}>A. 对话摘要输出</p>
<p className={`${textSecondary} text-xs`}>核心受众结论 · 结论理由摘要</p>
</div>
<div>
<p className={`${isDark ? 'text-cyan-400' : 'text-orange-600'} text-sm font-medium mb-3`}>B. 结构化输出字段</p>
<div className="space-y-2">
{outputFields.map((field, index) => (
<div key={index} className={`flex items-center gap-3 p-2 ${inputBg} ${inputBorder} rounded-lg`}>
<input
type="text"
defaultValue={field.name}
className={`flex-1 px-3 py-1.5 ${isDark ? 'bg-slate-800/50' : 'bg-white'} ${inputBorder} rounded ${isDark ? 'text-cyan-400' : 'text-orange-600'} text-sm font-mono focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}
/>
<select className={`px-3 py-1.5 ${isDark ? 'bg-slate-800/50' : 'bg-white'} ${inputBorder} rounded ${textPrimary} text-xs`}>
<option selected={field.type === '文本'}>文本</option>
<option selected={field.type === '数组'}>数组</option>
<option>对象</option>
</select>
<label className="flex items-center gap-2 cursor-pointer">
<span className={`${textSecondary} text-xs`}>{field.required ? '必填' : '可选'}</span>
<input type="checkbox" className="sr-only peer" defaultChecked={field.required} />
<div className={`w-9 h-5 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all ${isDark ? 'peer-checked:bg-blue-600' : 'peer-checked:bg-red-500'}`}></div>
</label>
</div>
))}
</div>
</div>
<div className={`p-3 ${inputBg} ${inputBorder} rounded-lg`}>
<p className={`${isDark ? 'text-green-400' : 'text-green-600'} text-sm font-medium mb-2`}>C. 报告片段输出</p>
<div className="space-y-2">
<div>
<label className={`${textMuted} text-xs`}>字段名</label>
<input
type="text"
defaultValue="audience_analysis_paragraph"
className={`w-full px-3 py-1.5 ${isDark ? 'bg-slate-800/50' : 'bg-white'} ${inputBorder} rounded ${isDark ? 'text-cyan-400' : 'text-orange-600'} text-sm font-mono focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}
/>
</div>
<div>
<label className={`${textMuted} text-xs`}>用途说明</label>
<input
type="text"
defaultValue={'用于写入正式方案中的"受众分析"段落'}
className={`w-full px-3 py-1.5 ${isDark ? 'bg-slate-800/50' : 'bg-white'} ${inputBorder} rounded ${textPrimary} text-sm focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}
/>
</div>
</div>
</div>
<div className={`flex items-center gap-2 pt-2 border-t ${cardBorder}`}>
<button className={`flex items-center gap-2 px-3 py-1.5 ${isDark ? 'bg-blue-500/20 hover:bg-blue-500/30 border border-blue-500/30 text-blue-400' : 'bg-red-100 hover:bg-red-200 border border-red-200 text-red-600'} rounded-lg text-xs transition-colors`}>
<Sparkles className="w-3 h-3" /> AI生成输出字段
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Lightbulb className="w-3 h-3" /> AI补全字段说明
</button>
<button className={`flex items-center gap-2 px-3 py-1.5 ${btnSecondary} rounded-lg text-xs transition-colors`}>
<Check className="w-3 h-3" /> AI校验完整性
</button>
</div>
</div>
</SectionHeader>
</div>
{/* 右侧辅助区 (35%) */}
<div className="col-span-4 flex flex-col gap-4 min-h-0 overflow-y-auto pl-2">
{/* 卡片1:AI辅助生成 */}
<div className={`${isDark ? 'bg-gradient-to-br from-purple-600/20 to-blue-600/20' : 'bg-gradient-to-br from-purple-100 to-blue-100'} backdrop-blur-xl ${isDark ? 'border border-purple-500/30' : 'border border-purple-300'} rounded-xl p-4`}>
<h3 className={`${textPrimary} font-semibold mb-3 flex items-center gap-2`}>
<Sparkles className={`w-4 h-4 ${isDark ? 'text-purple-400' : 'text-purple-600'}`} />
AI辅助生成
</h3>
<div className="space-y-3">
<div>
<label className={`block ${textSecondary} text-xs mb-1.5`}>一句话描述</label>
<textarea
rows={2}
placeholder="例如:这是一个负责识别宣传任务核心受众并输出画像的分析型智能体..."
className={`w-full px-3 py-2 ${inputBg} ${isDark ? 'border-purple-500/30' : 'border-purple-300'} rounded-lg ${textPrimary} text-xs focus:outline-none ${isDark ? 'focus:border-purple-500/50' : 'focus:border-purple-400'} resize-none`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-xs mb-1.5`}>示例任务</label>
<textarea
rows={2}
placeholder="例如:请分析某青年节宣传活动的核心受众、次级受众及其主要关切..."
className={`w-full px-3 py-2 ${inputBg} ${isDark ? 'border-purple-500/30' : 'border-purple-300'} rounded-lg ${textPrimary} text-xs focus:outline-none ${isDark ? 'focus:border-purple-500/50' : 'focus:border-purple-400'} resize-none`}
/>
</div>
<button
onClick={handleGenerateConfig}
className={`w-full px-4 py-2 ${isDark ? 'bg-purple-600 hover:bg-purple-500' : 'bg-purple-500 hover:bg-purple-400'} text-white rounded-lg text-sm font-medium transition-colors flex items-center justify-center gap-2`}
>
<Zap className="w-4 h-4" />
一键生成配置
</button>
{showGeneratedConfig && (
<div className={`p-3 ${inputBg} ${isDark ? 'border-purple-500/30' : 'border-purple-300'} rounded-lg space-y-2`}>
<p className={`${isDark ? 'text-purple-400' : 'text-purple-600'} text-xs font-medium`}>生成建议:</p>
<div className={`space-y-1 text-xs ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
<p>• 推荐职责:受众识别与画像输出</p>
<p>• 推荐技能:分层识别、特征抽取</p>
<p>• 推荐数据源:Y系统、宣传知识库</p>
<p>• 推荐思考路径:4步法</p>
</div>
<div className={`flex items-center gap-2 pt-2 border-t ${isDark ? 'border-purple-500/30' : 'border-purple-300'}`}>
<button className={`flex-1 px-3 py-1.5 ${isDark ? 'bg-green-600 hover:bg-green-500' : 'bg-green-500 hover:bg-green-400'} text-white rounded text-xs transition-colors`}>
采纳全部
</button>
<button className={`flex-1 px-3 py-1.5 ${btnSecondary} rounded text-xs transition-colors`}>
逐项插入
</button>
<button className={`px-3 py-1.5 ${btnSecondary} rounded text-xs transition-colors`}>
忽略
</button>
</div>
</div>
)}
</div>
</div>
{/* 卡片2:AI优化建议 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<h3 className={`${textPrimary} font-semibold mb-3 flex items-center gap-2`}>
<Lightbulb className={`w-4 h-4 ${isDark ? 'text-yellow-400' : 'text-yellow-500'}`} />
AI优化建议
</h3>
<div className="space-y-3">
{aiOptimizations.map((opt, index) => (
<div key={index} className={`p-2 ${isDark ? 'bg-amber-500/10 border border-amber-500/30' : 'bg-amber-50 border border-amber-200'} rounded-lg`}>
<p className={`${isDark ? 'text-slate-300' : 'text-gray-700'} text-xs mb-2`}>{opt.issue}</p>
<div className="flex items-center gap-2">
{opt.canFix && (
<button className={`px-2 py-1 ${btnPrimary} text-white rounded text-xs transition-colors`}>
一键修复
</button>
)}
<button className={`px-2 py-1 ${btnSecondary} rounded text-xs transition-colors`}>
忽略
</button>
</div>
</div>
))}
</div>
</div>
{/* 卡片3:对话试用 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4 flex flex-col`}>
<h3 className={`${textPrimary} font-semibold mb-3 flex items-center gap-2`}>
<MessageSquare className={`w-4 h-4 ${isDark ? 'text-cyan-400' : 'text-cyan-600'}`} />
对话试用
</h3>
<div className="flex items-center gap-3 mb-3">
<div className="flex-1">
<label className={`${textMuted} text-xs mb-1`}>模式</label>
<select className={`w-full px-2 py-1.5 ${inputBg} ${inputBorder} rounded ${textPrimary} text-xs`}>
<option>问答</option>
<option>任务</option>
</select>
</div>
<div className="flex items-center gap-1">
<span className={`${textSecondary} text-xs`}>数据源</span>
<label className="relative inline-flex items-center cursor-pointer mx-1">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className={`w-9 h-5 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all ${isDark ? 'peer-checked:bg-green-600' : 'peer-checked:bg-green-500'}`}></div>
</label>
</div>
<div className="flex items-center gap-1">
<span className={`${textSecondary} text-xs`}>功能</span>
<label className="relative inline-flex items-center cursor-pointer mx-1">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className={`w-9 h-5 ${isDark ? 'bg-slate-700' : 'bg-gray-300'} peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all ${isDark ? 'peer-checked:bg-green-600' : 'peer-checked:bg-green-500'}`}></div>
</label>
</div>
</div>
<div className={`flex-1 min-h-[180px] max-h-[180px] overflow-y-auto p-3 ${inputBg} ${inputBorder} rounded-lg mb-3 space-y-3`}>
{chatMessages.map((msg, index) => (
<div key={index} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div className={`max-w-[85%] p-2.5 rounded-lg text-xs ${
msg.role === 'user'
? isDark ? 'bg-blue-600 text-white' : 'bg-red-500 text-white'
: isDark ? 'bg-slate-800 text-slate-300' : 'bg-gray-200 text-gray-800'
}`}>
{msg.content}
</div>
</div>
))}
</div>
<div className="flex gap-2">
<input
type="text"
value={chatInput}
onChange={(e) => setChatInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSendMessage()}
placeholder="请输入问题或任务要求..."
className={`flex-1 px-3 py-2 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-xs focus:outline-none ${isDark ? 'focus:border-blue-500/50' : 'focus:border-red-400'}`}
/>
<button
onClick={handleSendMessage}
className={`px-3 py-2 ${btnPrimary} text-white rounded-lg transition-colors`}
>
<Send className="w-4 h-4" />
</button>
</div>
<button className={`mt-2 w-full px-3 py-1.5 ${btnSecondary} rounded text-xs transition-colors`}>
插入示例任务
</button>
</div>
{/* 卡片4:本轮执行详情 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-4`}>
<h3 className={`${textPrimary} font-semibold mb-3 flex items-center gap-2`}>
<Clock className={`w-4 h-4 ${isDark ? 'text-green-400' : 'text-green-600'}`} />
本轮执行详情
</h3>
<div className="space-y-3 text-xs">
<div>
<p className={`${textMuted} mb-1.5`}>调用数据源</p>
<div className="flex flex-wrap gap-1">
{executionDetails.dataSources.map((ds) => (
<span key={ds} className={`px-2 py-0.5 ${isDark ? 'bg-green-500/20 text-green-400' : 'bg-green-100 text-green-600'} rounded`}>{ds}</span>
))}
</div>
</div>
<div>
<p className={`${textMuted} mb-1.5`}>启用技能</p>
<div className="flex flex-wrap gap-1">
{executionDetails.skills.map((skill) => (
<span key={skill} className={`px-2 py-0.5 ${isDark ? 'bg-purple-500/20 text-purple-400' : 'bg-purple-100 text-purple-600'} rounded`}>{skill}</span>
))}
</div>
</div>
<div>
<p className={`${textMuted} mb-1.5`}>调用功能</p>
<div className="flex flex-wrap gap-1">
{executionDetails.functions.map((func) => (
<span key={func} className={`px-2 py-0.5 ${isDark ? 'bg-cyan-500/20 text-cyan-400' : 'bg-cyan-100 text-cyan-600'} rounded`}>{func}</span>
))}
</div>
</div>
<div>
<p className={`${textMuted} mb-1.5`}>输出字段</p>
<div className="flex flex-wrap gap-1">
{executionDetails.outputs.map((out) => (
<span key={out} className={`px-2 py-0.5 ${isDark ? 'bg-blue-500/20 text-blue-400' : 'bg-blue-100 text-blue-600'} rounded font-mono`}>{out}</span>
))}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default AgentDetail;