feat(beaver): 完成Task Team功能v1实现,重构后端架构支持统一内核

新增内部Task系统,包括验证、反馈门控机制,实现自动质量验证
(通过率>=0.75)和用户反馈闭环(satisfied/revise/abandon)。

实现Agent Team v1协调器,支持sequence/parallel/dag执行策略,
sub-agent复用主AgentLoop,每个run使用独立memory snapshot。

建立Skill学习pipeline,包含draft/审核/发布/回滚完整生命周期,
通过Task验证通过且用户满意才生成学习候选。

重构目录结构,移除third_party依赖,建立统一engine内核,
所有agent共享运行时基础组件。

更新ContextBuilder清理provider消息字段,增强SkillContext版本管理,
集成TaskExecutionPlanner和TaskSkillResolver实现技能解析机制。
This commit is contained in:
2026-05-08 17:14:14 +08:00
parent 5ba5c7e4c1
commit 8a12c30141
93 changed files with 16724 additions and 1247 deletions

View File

@ -14,9 +14,11 @@ import {
createSession,
deleteSession,
getSession,
getSessionProcess,
listCommands,
listSessions,
sendMessage,
submitChatFeedback,
uploadFile,
wsManager,
} from '@/lib/api';
@ -79,6 +81,8 @@ export default function ChatPage() {
clearMessages,
setIsThinking,
setSelectedRunId,
setSessionProcess,
updateMessageFeedback,
} = useChatStore();
const [input, setInput] = useState('');
@ -155,9 +159,15 @@ export default function ChatPage() {
const localSnapshot = useChatStore.getState().messages;
const waitingForReply = useChatStore.getState().isLoading || useChatStore.getState().isThinking;
try {
const detail = await getSession(key);
const [detail, process] = await Promise.all([
getSession(key),
getSessionProcess(key).catch(() => null),
]);
if (reqSeq !== loadSessionReqSeq.current) return;
if (useChatStore.getState().sessionId !== key) return;
if (process) {
setSessionProcess(key, process);
}
const nextMessages = waitingForReply
? mergeServerWithPendingUsers(detail.messages, localSnapshot)
: detail.messages;
@ -172,7 +182,7 @@ export default function ChatPage() {
if (reqSeq !== loadSessionReqSeq.current) return;
if (useChatStore.getState().sessionId !== key) return;
}
}, [setIsLoading, setIsThinking, setMessages]);
}, [setIsLoading, setIsThinking, setMessages, setSessionProcess]);
const loadCommands = useCallback(async () => {
if (commandsLoadedRef.current) return;
@ -231,6 +241,12 @@ export default function ChatPage() {
if (data.type === 'status' && data.status === 'thinking') {
setIsThinking(true);
} else if (data.type === 'message' && data.role === 'assistant') {
const validationResult = data.validation_result ?? data.metadata?.validation_result;
const validationStatus = data.validation_status
? data.validation_status
: validationResult
? ((validationResult as Record<string, unknown>).accepted === true ? 'passed' : 'failed')
: 'unknown';
setIsThinking(false);
setIsLoading(false);
addMessage({
@ -238,7 +254,12 @@ export default function ChatPage() {
content: typeof data.content === 'string' ? data.content : '',
timestamp: new Date().toISOString(),
attachments: Array.isArray(data.attachments) ? data.attachments : undefined,
run_id: typeof data.run_id === 'string' ? data.run_id : undefined,
task_id: data.task_id ?? data.metadata?.task_id ?? null,
task_status: data.task_status ?? data.metadata?.task_status ?? null,
validation_status: validationStatus,
});
void loadSessionMessages(typeof data.session_id === 'string' ? data.session_id : useChatStore.getState().sessionId);
loadSessions();
}
});
@ -348,7 +369,14 @@ export default function ChatPage() {
role: 'assistant',
content: result.response,
timestamp: new Date().toISOString(),
run_id: result.run_id,
task_id: result.task_id,
task_status: result.task_status,
validation_status: result.validation_result
? (result.validation_result.accepted === true ? 'passed' : 'failed')
: 'unknown',
});
void getSessionProcess(sessionId).then((process) => setSessionProcess(sessionId, process)).catch(() => null);
loadSessions();
} else {
await loadSessionMessages(sessionId);
@ -367,7 +395,23 @@ export default function ChatPage() {
});
}
}
}, [addMessage, input, isLoading, loadSessionMessages, loadSessions, locale, pendingFiles, sessionId, setIsLoading, setIsThinking]);
}, [addMessage, input, isLoading, loadSessionMessages, loadSessions, locale, pendingFiles, sessionId, setIsLoading, setIsThinking, setSessionProcess]);
const handleFeedback = useCallback(async (runId: string, feedbackType: 'satisfied' | 'revise' | 'abandon') => {
updateMessageFeedback(runId, feedbackType);
try {
await submitChatFeedback({
sessionId,
runId,
feedbackType,
});
void loadSessionMessages(sessionId);
void getSessionProcess(sessionId).then((process) => setSessionProcess(sessionId, process)).catch(() => null);
void loadSessions();
} catch (err: any) {
updateMessageFeedback(runId, undefined, err?.message || pickAppText(locale, '反馈提交失败', 'Feedback failed'));
}
}, [loadSessionMessages, loadSessions, locale, sessionId, setSessionProcess, updateMessageFeedback]);
const handleKeyDown = (e: React.KeyboardEvent) => {
if (showCommandPicker && filteredCommands.length > 0) {
@ -575,6 +619,7 @@ export default function ChatPage() {
selectedRunId={selectedSessionRunId}
onSelectRun={(runId) => setSelectedRunId(selectedSessionRunId === runId ? null : runId)}
onCancelRun={handleCancelRun}
onFeedback={handleFeedback}
/>
</div>