吸收数字员工步骤治理闭环
This commit is contained in:
@@ -174,6 +174,9 @@ interface QimingclawGovernanceCommandRecord {
|
||||
commandId: string;
|
||||
correlationId?: string;
|
||||
planId?: string | null;
|
||||
taskId?: string | null;
|
||||
runId?: string | null;
|
||||
stepId?: string | null;
|
||||
scheduleId?: string | null;
|
||||
accepted?: boolean;
|
||||
message?: string;
|
||||
@@ -695,6 +698,20 @@ async function recordGovernanceCommand(
|
||||
|| stringFromUnknown(body.context_refs?.plan_id)
|
||||
|| stringFromUnknown(body.payload?.plan_id)
|
||||
|| null,
|
||||
taskId: stringFromUnknown(response.result?.task_id)
|
||||
|| stringFromUnknown(body.context_refs?.task_id)
|
||||
|| stringFromUnknown(body.payload?.task_id)
|
||||
|| null,
|
||||
runId: stringFromUnknown(response.result?.run_id)
|
||||
|| stringFromUnknown(body.context_refs?.run_id)
|
||||
|| stringFromUnknown(body.payload?.run_id)
|
||||
|| stringFromUnknown(body.payload?.latest_run_id)
|
||||
|| null,
|
||||
stepId: stringFromUnknown(response.result?.step_id)
|
||||
|| stringFromUnknown(body.context_refs?.step_id)
|
||||
|| stringFromUnknown(body.payload?.step_id)
|
||||
|| stringFromUnknown(body.payload?.stepId)
|
||||
|| null,
|
||||
scheduleId: stringFromUnknown(response.result?.schedule_id)
|
||||
|| stringFromUnknown(body.context_refs?.schedule_id)
|
||||
|| stringFromUnknown(body.payload?.schedule_id)
|
||||
@@ -1041,12 +1058,16 @@ function latestRuntimeTime(plan: QimingclawPlanRecord, tasks: QimingclawTaskReco
|
||||
function taskStatusTone(status: string): 'running' | 'success' | 'danger' | 'waiting' {
|
||||
const normalized = status.toLowerCase();
|
||||
if (['completed', 'succeeded', 'success', 'done'].includes(normalized)) return 'success';
|
||||
if (['failed', 'error', 'rejected'].includes(normalized)) return 'danger';
|
||||
if (['failed', 'error', 'rejected', 'cancelled'].includes(normalized)) return 'danger';
|
||||
if (['running', 'active', 'leased', 'syncing'].includes(normalized)) return 'running';
|
||||
return 'waiting';
|
||||
}
|
||||
|
||||
function taskStatusLabel(status: string): string {
|
||||
const normalized = status.toLowerCase();
|
||||
if (normalized === 'skipped') return '已跳过';
|
||||
if (normalized === 'cancelled') return '已取消';
|
||||
if (normalized === 'paused') return '已暂停';
|
||||
const tone = taskStatusTone(status);
|
||||
if (tone === 'success') return '已完成';
|
||||
if (tone === 'danger') return '异常';
|
||||
@@ -1107,25 +1128,39 @@ function buildTaskAgents(snapshot: QimingclawSnapshot | null): DigitalEmployeeTa
|
||||
return runtimeTasks(snapshot).map((task) => {
|
||||
const latestRun = latestRunForTask(runs, task.id);
|
||||
const tone = taskStatusTone(task.status);
|
||||
const normalizedStatus = task.status.toLowerCase();
|
||||
const stepId = taskStepId(task);
|
||||
return {
|
||||
agent_id: `task-agent-${slugifyIdPart(task.id)}`,
|
||||
task_id: task.id,
|
||||
plan_id: task.planId ?? null,
|
||||
step_id: stepId,
|
||||
title: task.title,
|
||||
execution_state: task.status,
|
||||
status_label: taskStatusLabel(task.status),
|
||||
status_tone: tone,
|
||||
assigned_skill_id: task.assignedSkillId ?? null,
|
||||
latest_run_id: latestRun?.id ?? null,
|
||||
can_retry: tone === 'danger',
|
||||
can_skip: tone === 'danger' || tone === 'waiting',
|
||||
can_cancel: tone === 'running',
|
||||
next_action: tone === 'danger' ? 'retry_or_skip' : tone === 'running' ? 'watch_progress' : tone === 'success' ? 'collect_artifacts' : 'start_run',
|
||||
can_retry: ['failed', 'cancelled', 'skipped'].includes(normalizedStatus),
|
||||
can_skip: ['pending', 'running'].includes(normalizedStatus),
|
||||
can_cancel: ['pending', 'running', 'paused'].includes(normalizedStatus),
|
||||
next_action: taskAgentNextAction(normalizedStatus, tone),
|
||||
updated_at: latestRun?.updatedAt ?? task.updatedAt,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function taskAgentNextAction(
|
||||
status: string,
|
||||
tone: ReturnType<typeof taskStatusTone>,
|
||||
): string {
|
||||
if (['failed', 'cancelled', 'skipped'].includes(status)) return 'retry_or_review';
|
||||
if (status === 'paused') return 'resume_or_cancel';
|
||||
if (tone === 'running') return 'watch_progress';
|
||||
if (tone === 'success') return 'collect_artifacts';
|
||||
return 'start_run';
|
||||
}
|
||||
|
||||
function latestRunForTask(runs: QimingclawRunRecord[], taskId: string): QimingclawRunRecord | null {
|
||||
const sorted = runs
|
||||
.filter((run) => run.taskId === taskId)
|
||||
@@ -2457,6 +2492,12 @@ async function handleGovernanceCommand(
|
||||
const taskId = stringFromUnknown(body.context_refs?.task_id)
|
||||
|| stringFromUnknown(body.payload?.task_id)
|
||||
|| stringFromUnknown(body.payload?.original_task_id);
|
||||
const runId = stringFromUnknown(body.context_refs?.run_id)
|
||||
|| stringFromUnknown(body.payload?.run_id)
|
||||
|| stringFromUnknown(body.payload?.latest_run_id);
|
||||
const stepId = stringFromUnknown(body.context_refs?.step_id)
|
||||
|| stringFromUnknown(body.payload?.step_id)
|
||||
|| stringFromUnknown(body.payload?.stepId);
|
||||
const scheduleId = stringFromUnknown(body.context_refs?.schedule_id)
|
||||
|| stringFromUnknown(body.payload?.schedule_id);
|
||||
|
||||
@@ -2529,9 +2570,14 @@ async function handleGovernanceCommand(
|
||||
|
||||
if (['retry_task', 'skip_task', 'pause_task', 'resume_task', 'provide_task_input', 'cancel_task', 'start_run', 'cancel_run'].includes(body.command_kind)) {
|
||||
const targetTask = taskId || runtimeTasks(snapshot)[0]?.id || 'qimingclaw-task-agent';
|
||||
const runtimeTask = runtimeTasks(snapshot).find((task) => task.id === targetTask);
|
||||
const targetRunId = runId || latestRunForTask(runtimeRuns(snapshot), targetTask)?.id || null;
|
||||
const targetStepId = stepId || (runtimeTask ? taskStepId(runtimeTask) : null);
|
||||
const response = governanceAccepted(commandId, correlationId, `已接受 ${body.command_kind},并记录到 qimingclaw Task Agent 控制平面。`, {
|
||||
plan_id: planId || runtimeTasks(snapshot).find((task) => task.id === targetTask)?.planId || 'qimingclaw-task-agent-plan',
|
||||
plan_id: planId || runtimeTask?.planId || 'qimingclaw-task-agent-plan',
|
||||
task_id: targetTask,
|
||||
run_id: targetRunId,
|
||||
step_id: targetStepId,
|
||||
task_agent_id: `task-agent-${slugifyIdPart(targetTask)}`,
|
||||
status: taskGovernanceStatus(body.command_kind),
|
||||
next_action: taskGovernanceNextAction(body.command_kind),
|
||||
|
||||
@@ -1356,6 +1356,7 @@ export default function CommandDeck({ onNavigate }: { onNavigate: (target: Digit
|
||||
plan_id: agent.plan_id,
|
||||
task_id: agent.task_id,
|
||||
run_id: agent.latest_run_id,
|
||||
step_id: agent.step_id,
|
||||
task_agent_id: agent.agent_id,
|
||||
},
|
||||
payload: {
|
||||
@@ -1363,6 +1364,7 @@ export default function CommandDeck({ onNavigate }: { onNavigate: (target: Digit
|
||||
task_agent_id: agent.agent_id,
|
||||
task_id: agent.task_id,
|
||||
plan_id: agent.plan_id,
|
||||
step_id: agent.step_id,
|
||||
latest_run_id: agent.latest_run_id,
|
||||
title: agent.title,
|
||||
requested_action: command,
|
||||
|
||||
@@ -629,6 +629,7 @@ export interface DigitalEmployeeTaskAgentState {
|
||||
agent_id: string;
|
||||
task_id: string;
|
||||
plan_id?: string | null;
|
||||
step_id?: string | null;
|
||||
title: string;
|
||||
execution_state: string;
|
||||
status_label: string;
|
||||
|
||||
Reference in New Issue
Block a user