feat: 添加swarms团队编排功能并优化agent委派系统
- 引入AgentTeamOrchestrator支持多agent协同任务执行 - 增加第三方swarms库依赖并配置git协议替换以改善包管理 - 扩展DelegationManager支持团队任务调度和进度跟踪 - 实现中文bigram分词算法提升中文任务检索准确性 - 调整A2AClient和DelegationManager超时时间从30秒增至600秒 - 优化AgentRunResult状态判断逻辑增加有意义摘要检测 - 修改Dockerfile配置npm仓库镜像地址和git协议映射 - 更新CLI命令行接口支持网关端口配置传递 - 调整提供者超时配置机制增强请求稳定性 - 移除过时的support_group字段简化agent描述符结构 - 增强错误处理和进度事件报告机制改进用户体验
This commit is contained in:
@ -24,8 +24,11 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import type { Skill } from '@/types';
|
||||
import { pickAppText } from '@/lib/i18n/core';
|
||||
import { useAppI18n } from '@/lib/i18n/provider';
|
||||
|
||||
export default function SkillsPage() {
|
||||
const { locale } = useAppI18n();
|
||||
const [skills, setSkills] = useState<Skill[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@ -39,7 +42,7 @@ export default function SkillsPage() {
|
||||
const data = await listSkills();
|
||||
setSkills(Array.isArray(data) ? data : []);
|
||||
} catch (err: any) {
|
||||
setError(err.message || '加载技能失败');
|
||||
setError(err.message || pickAppText(locale, '加载技能失败', 'Failed to load skills'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@ -59,7 +62,7 @@ export default function SkillsPage() {
|
||||
setDeleting(null);
|
||||
loadSkills();
|
||||
} catch (err: any) {
|
||||
setError(err.message || '删除技能失败');
|
||||
setError(err.message || pickAppText(locale, '删除技能失败', 'Failed to delete the skill'));
|
||||
setDeleting(null);
|
||||
}
|
||||
};
|
||||
@ -82,16 +85,16 @@ export default function SkillsPage() {
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-2xl font-bold flex items-center gap-2">
|
||||
<Puzzle className="w-6 h-6" />
|
||||
技能
|
||||
{pickAppText(locale, '技能', 'Skills')}
|
||||
</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button onClick={loadSkills} variant="outline" size="sm">
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
刷新
|
||||
{pickAppText(locale, '刷新', 'Refresh')}
|
||||
</Button>
|
||||
<Button onClick={() => setShowUpload(true)} size="sm">
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
上传技能
|
||||
{pickAppText(locale, '上传技能', 'Upload skill')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -122,7 +125,7 @@ export default function SkillsPage() {
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm">
|
||||
确定删除技能 <strong>{deleting}</strong> 吗?此操作不可撤销。
|
||||
{pickAppText(locale, '确定删除技能', 'Delete skill')} <strong>{deleting}</strong> {pickAppText(locale, '吗?此操作不可撤销。', '? This action cannot be undone.')}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
@ -130,14 +133,14 @@ export default function SkillsPage() {
|
||||
size="sm"
|
||||
onClick={() => setDeleting(null)}
|
||||
>
|
||||
取消
|
||||
{pickAppText(locale, '取消', 'Cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => confirmDelete(deleting)}
|
||||
>
|
||||
删除
|
||||
{pickAppText(locale, '删除', 'Delete')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -151,18 +154,18 @@ export default function SkillsPage() {
|
||||
{skills.length === 0 ? (
|
||||
<div className="py-12 text-center text-muted-foreground">
|
||||
<Puzzle className="w-10 h-10 mx-auto mb-3 opacity-30" />
|
||||
<p className="font-medium">暂无技能</p>
|
||||
<p className="text-sm mt-1">上传一个技能 zip 包即可开始使用。</p>
|
||||
<p className="font-medium">{pickAppText(locale, '暂无技能', 'No skills yet')}</p>
|
||||
<p className="text-sm mt-1">{pickAppText(locale, '上传一个技能 zip 包即可开始使用。', 'Upload a skill zip package to get started.')}</p>
|
||||
</div>
|
||||
) : (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>名称</TableHead>
|
||||
<TableHead>描述</TableHead>
|
||||
<TableHead>来源</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead className="w-24">操作</TableHead>
|
||||
<TableHead>{pickAppText(locale, '名称', 'Name')}</TableHead>
|
||||
<TableHead>{pickAppText(locale, '描述', 'Description')}</TableHead>
|
||||
<TableHead>{pickAppText(locale, '来源', 'Source')}</TableHead>
|
||||
<TableHead>{pickAppText(locale, '状态', 'Status')}</TableHead>
|
||||
<TableHead className="w-24">{pickAppText(locale, '操作', 'Actions')}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@ -177,22 +180,22 @@ export default function SkillsPage() {
|
||||
<TableCell>
|
||||
{skill.source === 'builtin' ? (
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
内置
|
||||
{pickAppText(locale, '内置', 'Built in')}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="default" className="text-xs">
|
||||
工作区
|
||||
{pickAppText(locale, '工作区', 'Workspace')}
|
||||
</Badge>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{skill.available ? (
|
||||
<Badge variant="default" className="text-xs bg-green-600">
|
||||
可用
|
||||
{pickAppText(locale, '可用', 'Available')}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="outline" className="text-xs text-muted-foreground">
|
||||
不可用
|
||||
{pickAppText(locale, '不可用', 'Unavailable')}
|
||||
</Badge>
|
||||
)}
|
||||
</TableCell>
|
||||
@ -202,7 +205,7 @@ export default function SkillsPage() {
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7"
|
||||
title="下载"
|
||||
title={pickAppText(locale, '下载', 'Download')}
|
||||
onClick={() => downloadSkill(skill.name).catch((e) => setError(e.message))}
|
||||
>
|
||||
<Download className="w-3.5 h-3.5" />
|
||||
@ -213,7 +216,7 @@ export default function SkillsPage() {
|
||||
size="icon"
|
||||
className="h-7 w-7 text-destructive hover:text-destructive"
|
||||
onClick={() => handleDelete(skill.name)}
|
||||
title="删除"
|
||||
title={pickAppText(locale, '删除', 'Delete')}
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
@ -240,6 +243,7 @@ function UploadSkillForm({
|
||||
onCancel: () => void;
|
||||
onError: (msg: string) => void;
|
||||
}) {
|
||||
const { locale } = useAppI18n();
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const fileRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
@ -253,7 +257,7 @@ function UploadSkillForm({
|
||||
await uploadSkill(file);
|
||||
onDone();
|
||||
} catch (err: any) {
|
||||
onError(err.message || '上传失败');
|
||||
onError(err.message || pickAppText(locale, '上传失败', 'Upload failed'));
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
@ -263,7 +267,7 @@ function UploadSkillForm({
|
||||
<Card>
|
||||
<CardHeader className="pb-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-base">上传技能</CardTitle>
|
||||
<CardTitle className="text-base">{pickAppText(locale, '上传技能', 'Upload skill')}</CardTitle>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7" onClick={onCancel}>
|
||||
<X className="w-4 h-4" />
|
||||
</Button>
|
||||
@ -273,7 +277,7 @@ function UploadSkillForm({
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium" htmlFor="skill-zip">
|
||||
技能压缩包
|
||||
{pickAppText(locale, '技能压缩包', 'Skill archive')}
|
||||
</label>
|
||||
<input
|
||||
id="skill-zip"
|
||||
@ -283,23 +287,23 @@ function UploadSkillForm({
|
||||
className="block w-full text-sm text-muted-foreground file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-primary file:text-primary-foreground hover:file:bg-primary/90 cursor-pointer"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
压缩包中必须包含 `SKILL.md` 文件
|
||||
{pickAppText(locale, '压缩包中必须包含 `SKILL.md` 文件', 'The archive must contain a `SKILL.md` file')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button type="button" variant="outline" onClick={onCancel}>
|
||||
取消
|
||||
{pickAppText(locale, '取消', 'Cancel')}
|
||||
</Button>
|
||||
<Button type="submit" disabled={uploading}>
|
||||
{uploading ? (
|
||||
<>
|
||||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||||
上传中...
|
||||
{pickAppText(locale, '上传中...', 'Uploading...')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Upload className="w-4 h-4 mr-2" />
|
||||
上传
|
||||
{pickAppText(locale, '上传', 'Upload')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user