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:
@ -12,10 +12,17 @@ import type {
|
||||
Marketplace,
|
||||
MarketplacePlugin,
|
||||
PluginInfo,
|
||||
ProviderConfigPayload,
|
||||
Session,
|
||||
SessionDetail,
|
||||
Skill,
|
||||
SkillDraft,
|
||||
SkillDraftEvalReport,
|
||||
SkillDraftSafetyReport,
|
||||
SkillLearningCandidate,
|
||||
SkillReviewRecord,
|
||||
SlashCommand,
|
||||
SessionProcessProjection,
|
||||
SystemStatus,
|
||||
TokenResponse,
|
||||
OutlookConnectionPayload,
|
||||
@ -246,7 +253,15 @@ export async function sendMessage(
|
||||
message: string,
|
||||
sessionId: string = 'web:default',
|
||||
attachments?: FileAttachment[]
|
||||
): Promise<{ response?: string; status?: string; session_id: string }> {
|
||||
): Promise<{
|
||||
response?: string;
|
||||
status?: string;
|
||||
session_id: string;
|
||||
run_id?: string;
|
||||
task_id?: string | null;
|
||||
task_status?: string | null;
|
||||
validation_result?: Record<string, unknown> | null;
|
||||
}> {
|
||||
const body: Record<string, unknown> = { message, session_id: sessionId };
|
||||
if (attachments && attachments.length > 0) {
|
||||
body.attachments = attachments;
|
||||
@ -255,8 +270,12 @@ export async function sendMessage(
|
||||
response?: string;
|
||||
status?: string;
|
||||
session_id: string;
|
||||
run_id?: string;
|
||||
output_text?: string;
|
||||
finish_reason?: string;
|
||||
task_id?: string | null;
|
||||
task_status?: string | null;
|
||||
validation_result?: Record<string, unknown> | null;
|
||||
}>('/api/chat', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
@ -265,9 +284,36 @@ export async function sendMessage(
|
||||
response: result.response ?? result.output_text,
|
||||
status: result.status ?? result.finish_reason,
|
||||
session_id: result.session_id,
|
||||
run_id: result.run_id,
|
||||
task_id: result.task_id,
|
||||
task_status: result.task_status,
|
||||
validation_result: result.validation_result,
|
||||
};
|
||||
}
|
||||
|
||||
export async function submitChatFeedback(params: {
|
||||
sessionId: string;
|
||||
runId: string;
|
||||
feedbackType: 'satisfied' | 'revise' | 'abandon';
|
||||
comment?: string;
|
||||
}): Promise<{
|
||||
session_id: string;
|
||||
run_id: string;
|
||||
task_id: string;
|
||||
task_status: string;
|
||||
feedback_type: string;
|
||||
}> {
|
||||
return fetchJSON('/api/chat/feedback', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
session_id: params.sessionId,
|
||||
run_id: params.runId,
|
||||
feedback_type: params.feedbackType,
|
||||
comment: params.comment,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
export function streamMessage(
|
||||
message: string,
|
||||
sessionId: string,
|
||||
@ -533,6 +579,10 @@ export async function getSession(key: string): Promise<SessionDetail> {
|
||||
return fetchJSON(`/api/sessions/${encodeURIComponent(key)}`);
|
||||
}
|
||||
|
||||
export async function getSessionProcess(key: string): Promise<SessionProcessProjection> {
|
||||
return fetchJSON(`/api/sessions/${encodeURIComponent(key)}/process`);
|
||||
}
|
||||
|
||||
export async function deleteSession(key: string): Promise<void> {
|
||||
await fetchJSON(`/api/sessions/${encodeURIComponent(key)}`, { method: 'DELETE' });
|
||||
}
|
||||
@ -545,6 +595,16 @@ export async function getStatus(): Promise<SystemStatus> {
|
||||
return fetchJSON('/api/status');
|
||||
}
|
||||
|
||||
export async function updateProviderConfig(
|
||||
providerId: string,
|
||||
payload: ProviderConfigPayload
|
||||
): Promise<{ ok: boolean; provider: string; enabled: boolean }> {
|
||||
return fetchJSON(`/api/providers/${encodeURIComponent(providerId)}/config`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function restartSystem(): Promise<{
|
||||
ok: boolean;
|
||||
restarting: boolean;
|
||||
@ -604,6 +664,117 @@ export async function listSkills(): Promise<Skill[]> {
|
||||
return fetchJSON('/api/skills');
|
||||
}
|
||||
|
||||
export async function listSkillCandidates(status?: string): Promise<SkillLearningCandidate[]> {
|
||||
const query = status ? `?status=${encodeURIComponent(status)}` : '';
|
||||
return fetchJSON(`/api/skills/candidates${query}`);
|
||||
}
|
||||
|
||||
export async function synthesizeSkillDraft(candidateId: string): Promise<SkillDraft> {
|
||||
return fetchJSON(`/api/skills/candidates/${encodeURIComponent(candidateId)}/draft`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function regenerateSkillDraft(candidateId: string): Promise<SkillDraft> {
|
||||
return fetchJSON(`/api/skills/candidates/${encodeURIComponent(candidateId)}/regenerate`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function runSkillLearningOnce(): Promise<{
|
||||
processed: number;
|
||||
succeeded: number;
|
||||
failed: number;
|
||||
skipped: number;
|
||||
failures: Array<Record<string, string>>;
|
||||
}> {
|
||||
return fetchJSON('/api/skills/learning/run-once', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function listSkillDrafts(): Promise<SkillDraft[]> {
|
||||
return fetchJSON('/api/skills/drafts');
|
||||
}
|
||||
|
||||
export async function getSkillDraft(skillName: string, draftId: string): Promise<SkillDraft> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}`);
|
||||
}
|
||||
|
||||
export async function getSkillDraftSafety(skillName: string, draftId: string): Promise<SkillDraftSafetyReport> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}/safety`);
|
||||
}
|
||||
|
||||
export async function getSkillDraftEval(skillName: string, draftId: string): Promise<SkillDraftEvalReport> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}/eval`);
|
||||
}
|
||||
|
||||
export async function submitSkillDraft(
|
||||
skillName: string,
|
||||
draftId: string,
|
||||
notes: string = ''
|
||||
): Promise<SkillReviewRecord> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}/submit`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ notes }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function approveSkillDraft(
|
||||
skillName: string,
|
||||
draftId: string,
|
||||
notes: string = ''
|
||||
): Promise<SkillReviewRecord> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}/approve`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ notes }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function rejectSkillDraft(
|
||||
skillName: string,
|
||||
draftId: string,
|
||||
notes: string = ''
|
||||
): Promise<SkillReviewRecord> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}/reject`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ notes }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function publishSkillDraft(
|
||||
skillName: string,
|
||||
draftId: string,
|
||||
notes: string = '',
|
||||
confirmHighRisk: boolean = false
|
||||
): Promise<Record<string, unknown>> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/drafts/${encodeURIComponent(draftId)}/publish`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ notes, confirm_high_risk: confirmHighRisk }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function disablePublishedSkill(skillName: string, reason: string = ''): Promise<Record<string, unknown>> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/disable`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ reason }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function rollbackPublishedSkill(
|
||||
skillName: string,
|
||||
targetVersion: string,
|
||||
reason: string = ''
|
||||
): Promise<Record<string, unknown>> {
|
||||
return fetchJSON(`/api/skills/${encodeURIComponent(skillName)}/rollback`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ target_version: targetVersion, reason }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function listCommands(): Promise<SlashCommand[]> {
|
||||
return fetchJSON('/api/commands');
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import type {
|
||||
ProcessRun,
|
||||
ProcessWsEvent,
|
||||
Session,
|
||||
SessionProcessProjection,
|
||||
UiAgentDescriptor,
|
||||
UiMcpServerDescriptor,
|
||||
} from '@/types';
|
||||
@ -55,6 +56,11 @@ interface ChatStore {
|
||||
setSessionId: (id: string) => void;
|
||||
setMessages: (msgs: ChatMessage[]) => void;
|
||||
addMessage: (msg: ChatMessage) => void;
|
||||
updateMessageFeedback: (
|
||||
runId: string,
|
||||
feedbackState: ChatMessage['feedback_state'],
|
||||
error?: string
|
||||
) => void;
|
||||
setIsLoading: (loading: boolean) => void;
|
||||
setStreamingContent: (content: string) => void;
|
||||
appendStreamingContent: (chunk: string) => void;
|
||||
@ -65,6 +71,7 @@ interface ChatStore {
|
||||
setNanobotReady: (ready: boolean | null) => void;
|
||||
resetProcessState: () => void;
|
||||
ingestProcessEvent: (event: ProcessWsEvent) => void;
|
||||
setSessionProcess: (sessionId: string, projection: SessionProcessProjection) => void;
|
||||
setSelectedRunId: (runId: string | null) => void;
|
||||
setSelectedArtifactId: (artifactId: string | null) => void;
|
||||
setAgentRegistry: (agents: UiAgentDescriptor[]) => void;
|
||||
@ -148,6 +155,18 @@ export const useChatStore = create<ChatStore>((set) => ({
|
||||
},
|
||||
setMessages: (msgs) => set({ messages: msgs }),
|
||||
addMessage: (msg) => set((s) => ({ messages: [...s.messages, msg] })),
|
||||
updateMessageFeedback: (runId, feedbackState, error) =>
|
||||
set((s) => ({
|
||||
messages: s.messages.map((message) =>
|
||||
message.run_id === runId
|
||||
? {
|
||||
...message,
|
||||
feedback_state: feedbackState,
|
||||
feedback_error: error,
|
||||
}
|
||||
: message
|
||||
),
|
||||
})),
|
||||
setIsLoading: (loading) => set({ isLoading: loading }),
|
||||
setStreamingContent: (content) => set({ streamingContent: content }),
|
||||
appendStreamingContent: (chunk) =>
|
||||
@ -345,6 +364,37 @@ export const useChatStore = create<ChatStore>((set) => ({
|
||||
selectedRunId: nextSelectedRunId,
|
||||
};
|
||||
}),
|
||||
setSessionProcess: (sessionId, projection) =>
|
||||
set((state) => {
|
||||
const incomingRuns = projection.runs || [];
|
||||
const incomingEvents = projection.events || [];
|
||||
const incomingArtifacts = projection.artifacts || [];
|
||||
const incomingRunIds = new Set(incomingRuns.map((run) => run.run_id));
|
||||
const nextRuns = [
|
||||
...state.processRuns.filter((run) => run.session_id !== sessionId && !incomingRunIds.has(run.run_id)),
|
||||
...incomingRuns,
|
||||
];
|
||||
const liveRunIds = new Set(nextRuns.map((run) => run.run_id));
|
||||
const incomingEventIds = new Set(incomingEvents.map((event) => event.event_id));
|
||||
const nextEvents = [
|
||||
...state.processEvents.filter(
|
||||
(event) => liveRunIds.has(event.run_id) && !incomingEventIds.has(event.event_id)
|
||||
),
|
||||
...incomingEvents,
|
||||
];
|
||||
const incomingArtifactIds = new Set(incomingArtifacts.map((artifact) => artifact.artifact_id));
|
||||
const nextArtifacts = [
|
||||
...state.processArtifacts.filter(
|
||||
(artifact) => liveRunIds.has(artifact.run_id) && !incomingArtifactIds.has(artifact.artifact_id)
|
||||
),
|
||||
...incomingArtifacts,
|
||||
];
|
||||
return {
|
||||
processRuns: nextRuns,
|
||||
processEvents: nextEvents,
|
||||
processArtifacts: nextArtifacts,
|
||||
};
|
||||
}),
|
||||
setSelectedRunId: (runId) => set({ selectedRunId: runId }),
|
||||
setSelectedArtifactId: (artifactId) => set({ selectedArtifactId: artifactId }),
|
||||
setAgentRegistry: (agents) => set({ agentRegistry: agents }),
|
||||
|
||||
Reference in New Issue
Block a user