吸收数字员工PlanStep本地软租约
This commit is contained in:
@@ -2582,6 +2582,7 @@ function planStepRows(snapshot: QimingclawSnapshot | null): BusinessViewRow[] {
|
||||
const payload = asRecord(step.payload) ?? {};
|
||||
const dependencyGraph = asRecord(payload.dependencyGraph ?? payload.dependency_graph) ?? {};
|
||||
const lastDispatch = asRecord(payload.lastDispatch ?? payload.last_dispatch) ?? {};
|
||||
const lease = activePlanStepDispatchLease(payload);
|
||||
const readiness = planStepDispatchReadiness(step, snapshot, payload);
|
||||
const blockedDependencies = uniqueStrings(arrayValue(dependencyGraph.blockedDependencies ?? dependencyGraph.blocked_dependencies));
|
||||
const waitingDependencies = uniqueStrings(arrayValue(dependencyGraph.waitingDependencies ?? dependencyGraph.waiting_dependencies));
|
||||
@@ -2610,6 +2611,15 @@ function planStepRows(snapshot: QimingclawSnapshot | null): BusinessViewRow[] {
|
||||
skip_reason: readiness.skipReason,
|
||||
last_dispatch_status: stringValue(lastDispatch.status) || null,
|
||||
last_dispatch_at: stringValue(lastDispatch.occurredAt ?? lastDispatch.occurred_at) || null,
|
||||
lease,
|
||||
lease_id: stringValue(lease?.lease_id ?? lease?.leaseId) || null,
|
||||
lease_state: stringValue(lease?.state) || null,
|
||||
lease_owner_device_id: stringValue(lease?.owner_device_id ?? lease?.ownerDeviceId) || null,
|
||||
lease_acquired_at: stringValue(lease?.acquired_at ?? lease?.acquiredAt) || null,
|
||||
lease_expires_at: stringValue(lease?.expires_at ?? lease?.expiresAt) || null,
|
||||
lease_released_at: stringValue(lease?.released_at ?? lease?.releasedAt) || null,
|
||||
lease_release_reason: stringValue(lease?.release_reason ?? lease?.releaseReason) || null,
|
||||
lease_active: Boolean(lease),
|
||||
sync_status: step.syncStatus,
|
||||
last_synced_at: step.lastSyncedAt ?? null,
|
||||
sync_error: step.syncError ?? null,
|
||||
@@ -2641,6 +2651,15 @@ function planStepGraphRows(snapshot: QimingclawSnapshot | null): BusinessViewRow
|
||||
latest_run_id: stringValue(row.latest_run_id) || null,
|
||||
dispatchable: row.dispatchable === true,
|
||||
skip_reason: stringValue(row.skip_reason) || null,
|
||||
lease: asRecord(row.lease) ?? null,
|
||||
lease_id: stringValue(row.lease_id) || null,
|
||||
lease_state: stringValue(row.lease_state) || null,
|
||||
lease_owner_device_id: stringValue(row.lease_owner_device_id) || null,
|
||||
lease_acquired_at: stringValue(row.lease_acquired_at) || null,
|
||||
lease_expires_at: stringValue(row.lease_expires_at) || null,
|
||||
lease_released_at: stringValue(row.lease_released_at) || null,
|
||||
lease_release_reason: stringValue(row.lease_release_reason) || null,
|
||||
lease_active: row.lease_active === true,
|
||||
sync_status: stringValue(row.sync_status) || null,
|
||||
updated_at: stringValue(row.updated_at) || null,
|
||||
entity_type: 'plan_step_graph_node',
|
||||
@@ -2679,8 +2698,10 @@ function planStepDispatchReadiness(
|
||||
?? null;
|
||||
const taskId = task?.id ?? null;
|
||||
const latestRunId = task ? latestRunForTask(runtimeRuns(snapshot), task.id)?.id ?? null : null;
|
||||
const lease = activePlanStepDispatchLease(payload);
|
||||
let skipReason: string | null = null;
|
||||
if (step.status.toLowerCase() !== 'ready') skipReason = 'not_ready';
|
||||
if (lease) skipReason = 'lease_active';
|
||||
else if (step.status.toLowerCase() !== 'ready') skipReason = 'not_ready';
|
||||
else if (!task) skipReason = 'missing_task';
|
||||
else if (isTerminalRuntimeTaskStatus(task.status)) skipReason = 'task_terminal';
|
||||
else if (runtimeRuns(snapshot).some((run) => run.taskId === task.id && isActiveRuntimeRunStatus(run.status))) skipReason = 'task_already_running';
|
||||
@@ -2707,6 +2728,7 @@ function planStepDependencyDetails(dependencyIds: string[], snapshot: Qimingclaw
|
||||
}
|
||||
const payload = asRecord(dependency.payload) ?? {};
|
||||
const graph = asRecord(payload.dependencyGraph ?? payload.dependency_graph) ?? {};
|
||||
const lease = activePlanStepDispatchLease(payload);
|
||||
const readiness = planStepDispatchReadiness(dependency, snapshot, payload);
|
||||
return {
|
||||
step_id: dependency.id,
|
||||
@@ -2717,10 +2739,23 @@ function planStepDependencyDetails(dependencyIds: string[], snapshot: Qimingclaw
|
||||
dependency_status: stringValue(graph.status) || dependency.status,
|
||||
dispatchable: readiness.dispatchable,
|
||||
skip_reason: readiness.skipReason,
|
||||
lease_state: stringValue(lease?.state) || null,
|
||||
lease_active: Boolean(lease),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function activePlanStepDispatchLease(payload: Record<string, unknown>): Record<string, unknown> | null {
|
||||
const lease = asRecord(payload.dispatchLease ?? payload.dispatch_lease);
|
||||
if (!lease) return null;
|
||||
const state = stringValue(lease.state) || 'active';
|
||||
const expiresAt = stringValue(lease.expires_at ?? lease.expiresAt);
|
||||
const leaseId = stringValue(lease.lease_id ?? lease.leaseId);
|
||||
const ownerDeviceId = stringValue(lease.owner_device_id ?? lease.ownerDeviceId);
|
||||
if (state !== 'active' || !expiresAt || expiresAt <= new Date().toISOString() || !leaseId || !ownerDeviceId) return null;
|
||||
return lease;
|
||||
}
|
||||
|
||||
function isTerminalRuntimeTaskStatus(status: string): boolean {
|
||||
return ['completed', 'succeeded', 'success', 'done', 'skipped', 'cancelled', 'canceled'].includes(status.toLowerCase());
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ interface DigitalPlanItem {
|
||||
readyStepCount: number;
|
||||
runningStepCount: number;
|
||||
blockedStepCount: number;
|
||||
leasedStepCount: number;
|
||||
schedulerJob?: CronJob | null;
|
||||
source: 'plan_template';
|
||||
}
|
||||
@@ -71,6 +72,7 @@ interface PlanStepOrchestrationSummary {
|
||||
ready: number;
|
||||
running: number;
|
||||
blocked: number;
|
||||
leased: number;
|
||||
}
|
||||
|
||||
interface BlockedPlanStepInputTarget {
|
||||
@@ -417,6 +419,7 @@ function buildPlanTemplateItem(job: CronJob, duties: DigitalEmployeeDuty[], sele
|
||||
readyStepCount: 0,
|
||||
runningStepCount: 0,
|
||||
blockedStepCount: 0,
|
||||
leasedStepCount: 0,
|
||||
schedulerJob: job,
|
||||
source: 'plan_template',
|
||||
};
|
||||
@@ -441,9 +444,12 @@ function planStepOrchestrationSummary(rows: PlanStepBusinessRow[]): Map<string,
|
||||
rows.forEach((step) => {
|
||||
const planId = step.plan_id || '';
|
||||
if (!planId) return;
|
||||
const current = summary.get(planId) ?? { ready: 0, running: 0, blocked: 0 };
|
||||
const current = summary.get(planId) ?? { ready: 0, running: 0, blocked: 0, leased: 0 };
|
||||
const status = step.status.toLowerCase();
|
||||
if (status === 'ready') current.ready += 1;
|
||||
if (step.lease_active || step.skip_reason === 'lease_active') {
|
||||
current.leased += 1;
|
||||
current.running += 1;
|
||||
} else if (status === 'ready' && step.dispatchable) current.ready += 1;
|
||||
else if (['running', 'active', 'leased', 'queued'].includes(status)) current.running += 1;
|
||||
else if (status === 'blocked') current.blocked += 1;
|
||||
summary.set(planId, current);
|
||||
@@ -1128,8 +1134,9 @@ export default function CommandDeck({ onNavigate }: { onNavigate: (target: Digit
|
||||
readyStepCount: orchestration.ready,
|
||||
runningStepCount: orchestration.running,
|
||||
blockedStepCount: orchestration.blocked,
|
||||
resultText: orchestration.ready > 0 || orchestration.running > 0 || orchestration.blocked > 0
|
||||
? `Ready ${orchestration.ready} · 运行 ${orchestration.running} · 阻塞 ${orchestration.blocked}`
|
||||
leasedStepCount: orchestration.leased,
|
||||
resultText: orchestration.ready > 0 || orchestration.running > 0 || orchestration.blocked > 0 || orchestration.leased > 0
|
||||
? `Ready ${orchestration.ready} · 运行 ${orchestration.running} · 阻塞 ${orchestration.blocked}${orchestration.leased > 0 ? ` · 租约 ${orchestration.leased}` : ''}`
|
||||
: item.resultText,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -211,6 +211,21 @@ export interface PlanStepDependencyDetail {
|
||||
dependency_status: string | null;
|
||||
dispatchable: boolean;
|
||||
skip_reason: string | null;
|
||||
lease_state?: string | null;
|
||||
lease_active?: boolean;
|
||||
}
|
||||
|
||||
export interface PlanStepLeaseSummary {
|
||||
lease_id?: string | null;
|
||||
state?: string | null;
|
||||
owner_device_id?: string | null;
|
||||
acquired_at?: string | null;
|
||||
expires_at?: string | null;
|
||||
released_at?: string | null;
|
||||
release_reason?: string | null;
|
||||
trigger_source?: string | null;
|
||||
orchestration_id?: string | null;
|
||||
candidate_count?: number | null;
|
||||
}
|
||||
|
||||
export interface PlanStepBusinessRow {
|
||||
@@ -230,6 +245,15 @@ export interface PlanStepBusinessRow {
|
||||
blocked_dependency_details?: PlanStepDependencyDetail[];
|
||||
dispatchable: boolean;
|
||||
skip_reason: string | null;
|
||||
lease?: PlanStepLeaseSummary | null;
|
||||
lease_id?: string | null;
|
||||
lease_state?: string | null;
|
||||
lease_owner_device_id?: string | null;
|
||||
lease_acquired_at?: string | null;
|
||||
lease_expires_at?: string | null;
|
||||
lease_released_at?: string | null;
|
||||
lease_release_reason?: string | null;
|
||||
lease_active?: boolean;
|
||||
sync_status?: string | null;
|
||||
updated_at?: string | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user