吸收数字员工PlanStep远端策略拉取

This commit is contained in:
baiyanyun
2026-06-10 23:15:51 +08:00
parent 6f2ccdf783
commit c400367d22
17 changed files with 776 additions and 205 deletions

View File

@@ -16,6 +16,7 @@ import type {
BusinessViewResponse,
PlanStepBusinessRow,
PlanStepDispatchPolicy,
PlanStepDispatchPolicyPullResult,
ReadyStepDispatchResult,
NotificationPreferences,
UserNotification,
@@ -612,6 +613,12 @@ export function patchPlanStepDispatchPolicy(
});
}
export function pullPlanStepDispatchPolicy(): Promise<PlanStepDispatchPolicyPullResult> {
return apiFetch<PlanStepDispatchPolicyPullResult>('/api/plan-step/dispatch-policy/pull', {
method: 'POST',
});
}
export function getPlanSteps(params: Record<string, string | number | null | undefined> = {}): Promise<BusinessViewResponse<PlanStepBusinessRow>> {
const query = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {

View File

@@ -36,6 +36,7 @@ import type {
PlanDispatchResponse,
ReadyStepDispatchResult,
PlanStepDispatchPolicy,
PlanStepDispatchPolicyPullResult,
PlanStepSummary,
RouteDecisionRecord,
RouteDecisionTimelineResponse,
@@ -60,6 +61,7 @@ declare global {
saveUiState?: (update: { state: AdapterState; action?: string; date?: string; metadata?: Record<string, unknown> }) => Promise<AdapterState>;
getSyncStatus?: () => Promise<QimingclawSyncStatus>;
flushSync?: () => Promise<QimingclawSyncStatus>;
pullPlanStepDispatchPolicy?: () => Promise<PlanStepDispatchPolicyPullResult>;
getCronSettings?: () => Promise<QimingclawCronSettings>;
saveCronSettings?: (patch: Partial<QimingclawCronSettings>) => Promise<QimingclawCronSettings>;
runSchedulerCheck?: () => Promise<{ activated: number; due?: number; skipped?: number }>;
@@ -791,6 +793,9 @@ export async function handleQimingclawDigitalApi<T>(
if (method === 'GET' && pathname === '/api/plan-step/dispatch-policy') {
return planStepDispatchPolicy(notificationAdapterState(await readQimingclawSnapshot())) as T;
}
if (method === 'POST' && pathname === '/api/plan-step/dispatch-policy/pull') {
return await handlePlanStepDispatchPolicyPull(await readQimingclawSnapshot()) as T;
}
if (method === 'PATCH' && pathname === '/api/plan-step/dispatch-policy') {
return await handlePlanStepDispatchPolicyPatch(
parseJsonBody<Partial<PlanStepDispatchPolicy>>(options.body),
@@ -3883,6 +3888,10 @@ function defaultPlanStepDispatchPolicy(): PlanStepDispatchPolicy {
max_per_sweep: 3,
auto_dispatch_ready_steps: true,
updated_at: null,
source: 'local',
remote_updated_at: null,
last_pulled_at: null,
last_pull_error: null,
};
}
@@ -3915,6 +3924,10 @@ function planStepDispatchPolicy(state: Partial<AdapterState> | null | undefined)
max_per_sweep: Number.isFinite(maxPerSweep) ? Math.max(1, Math.min(Math.floor(maxPerSweep), 10)) : fallback.max_per_sweep,
auto_dispatch_ready_steps: stored.auto_dispatch_ready_steps !== false,
updated_at: typeof stored.updated_at === 'string' ? stored.updated_at : fallback.updated_at,
source: stored.source === 'remote' ? 'remote' : 'local',
remote_updated_at: typeof stored.remote_updated_at === 'string' ? stored.remote_updated_at : null,
last_pulled_at: typeof stored.last_pulled_at === 'string' ? stored.last_pulled_at : null,
last_pull_error: typeof stored.last_pull_error === 'string' ? stored.last_pull_error : null,
};
}
@@ -4021,6 +4034,27 @@ async function handlePlanStepDispatchPolicyPatch(
return next;
}
async function handlePlanStepDispatchPolicyPull(
snapshot: QimingclawSnapshot | null,
): Promise<PlanStepDispatchPolicyPullResult> {
const fallbackPolicy = planStepDispatchPolicy(snapshot?.uiState ?? readState());
const bridgeResult = await window.QimingClawBridge?.digital?.pullPlanStepDispatchPolicy?.().catch((error) => ({
ok: false,
endpoint: null,
pulled_at: new Date().toISOString(),
policy: fallbackPolicy,
error: error instanceof Error ? error.message : 'plan step dispatch policy pull failed',
}));
if (bridgeResult) return bridgeResult;
return {
ok: false,
endpoint: null,
pulled_at: new Date().toISOString(),
policy: fallbackPolicy,
error: 'qimingclaw_bridge_unavailable',
};
}
function approvalNotifications(snapshot: QimingclawSnapshot | null): UserNotification[] {
const summaries = new Map(businessApprovalRows(snapshot).map((approval) => [stringValue(approval.approval_id), approval]));
return buildApprovals(snapshot)