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

@ -8,6 +8,8 @@ import { getAccessToken, getFileUrl } from '@/lib/api';
import { AgentTeamBlock } from '@/components/chat-workbench/AgentTeamBlock';
import { MarkdownContent } from '@/components/chat-workbench/MarkdownContent';
import { ScrollArea } from '@/components/ui/scroll-area';
import { pickAppText } from '@/lib/i18n/core';
import { useAppI18n } from '@/lib/i18n/provider';
function AuthImage({ src, alt, className }: { src: string; alt: string; className?: string }) {
const [blobUrl, setBlobUrl] = React.useState<string | null>(null);
@ -115,6 +117,20 @@ type AgentTeamGroup = {
startedAt: string;
};
const TERMINAL_RUN_STATUSES = new Set<ProcessRun['status']>(['done', 'error', 'cancelled']);
function shouldHideSystemAgentMessage(message: ChatMessage): boolean {
if (message.role !== 'assistant' || typeof message.content !== 'string') {
return false;
}
const content = message.content.trim();
return (
/^\[(Agent team|Subagent)\s+['"][^'"]+['"]\s+(completed|failed|cancelled|finished)\]/i.test(content)
|| (content.startsWith('[Agent team ') && content.includes('\nTask:'))
);
}
function parseTimelineTime(value?: string | null): number | null {
if (!value) return null;
const parsed = new Date(value).getTime();
@ -194,9 +210,20 @@ export function MessageList({
onSelectRun: (runId: string) => void;
onCancelRun: (runId: string) => void;
}) {
const teamGroups = React.useMemo(() => buildAgentTeamGroups(processRuns), [processRuns]);
const { locale } = useAppI18n();
const visibleMessages = React.useMemo(
() => messages.filter((message) => !shouldHideSystemAgentMessage(message)),
[messages]
);
const teamGroups = React.useMemo(
() =>
buildAgentTeamGroups(processRuns).filter((group) =>
group.memberRuns.some((run) => !TERMINAL_RUN_STATUSES.has(run.status))
),
[processRuns]
);
const timelineItems = React.useMemo(() => {
const messageItems = messages.map((message, index) => ({
const messageItems = visibleMessages.map((message, index) => ({
kind: 'message' as const,
key: `${message.role}:${message.timestamp || index}:${index}`,
sortTime: parseTimelineTime(message.timestamp) ?? Number.MAX_SAFE_INTEGER / 2 + index,
@ -204,12 +231,12 @@ export function MessageList({
message,
}));
const teamItems = teamGroups.map((group, index) => ({
kind: 'team' as const,
key: `team:${group.rootRun.run_id}`,
sortTime: parseTimelineTime(group.startedAt) ?? Number.MAX_SAFE_INTEGER / 2 + messages.length + index,
order: messages.length + index,
group,
}));
kind: 'team' as const,
key: `team:${group.rootRun.run_id}`,
sortTime: parseTimelineTime(group.startedAt) ?? Number.MAX_SAFE_INTEGER / 2 + visibleMessages.length + index,
order: visibleMessages.length + index,
group,
}));
return [...messageItems, ...teamItems].sort((a, b) => {
if (a.sortTime !== b.sortTime) {
@ -217,16 +244,16 @@ export function MessageList({
}
return a.order - b.order;
});
}, [messages, teamGroups]);
}, [teamGroups, visibleMessages]);
return (
<ScrollArea className="h-full px-4" viewportRef={viewportRef}>
<div className="max-w-6xl mx-auto py-4 space-y-4">
{messages.length === 0 && teamGroups.length === 0 && !isThinking && (
{visibleMessages.length === 0 && teamGroups.length === 0 && !isThinking && (
<div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
<Bot className="w-12 h-12 mb-4 opacity-50" />
<p className="text-lg font-medium">Boardware Agent Sandbox</p>
<p className="text-sm"></p>
<p className="text-sm">{pickAppText(locale, '发送消息开始对话', 'Send a message to start the conversation')}</p>
</div>
)}
@ -251,7 +278,7 @@ export function MessageList({
<div className="flex items-center gap-2 text-muted-foreground px-1">
<Bot className="w-5 h-5" />
<Loader2 className="w-4 h-4 animate-spin" />
<span className="text-sm">...</span>
<span className="text-sm">{pickAppText(locale, '思考中...', 'Thinking...')}</span>
</div>
)}