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:
2026-04-14 14:34:23 +08:00
parent fee9007da6
commit cdfc222c9f
85 changed files with 5443 additions and 1392 deletions

View File

@ -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>