吸收数字员工治理审计补齐
This commit is contained in:
@@ -1798,7 +1798,14 @@ describe("digital employee state service", () => {
|
||||
stepId: "step-governance",
|
||||
accepted: true,
|
||||
message: "跳过当前任务",
|
||||
payload: { reason: "用户选择跳过" },
|
||||
payload: {
|
||||
reason: "用户选择跳过",
|
||||
source: "qimingclaw-ingress-route",
|
||||
route_decision_id: "route-decision-skip",
|
||||
route_kind: "PlanControl",
|
||||
intent_kind: "control",
|
||||
risk_level: "medium",
|
||||
},
|
||||
result: { task_id: "task-governance", run_id: "run-governance", step_id: "step-governance" },
|
||||
});
|
||||
|
||||
@@ -1834,6 +1841,12 @@ describe("digital employee state service", () => {
|
||||
message: "跳过当前任务",
|
||||
task_id: "task-governance",
|
||||
});
|
||||
expect(JSON.parse(mockState.db?.events.get("run-governance:skip_task:command-skip-task")?.payload ?? "{}")).toMatchObject({
|
||||
routeDecisionId: "route-decision-skip",
|
||||
routeKind: "PlanControl",
|
||||
intentKind: "control",
|
||||
riskLevel: "medium",
|
||||
});
|
||||
expect(mockState.db?.outbox.get("task:upsert:task-governance")).toMatchObject({ entity_type: "task" });
|
||||
expect(mockState.db?.outbox.get("plan_step:upsert:step-governance")).toMatchObject({ entity_type: "plan_step" });
|
||||
expect(mockState.db?.outbox.get("run:upsert:run-governance")).toMatchObject({ entity_type: "run" });
|
||||
|
||||
@@ -4174,6 +4174,10 @@ export function recordDigitalEmployeeGovernanceCommand(
|
||||
commandId,
|
||||
correlationId: command.correlationId,
|
||||
planId,
|
||||
routeDecisionId: stringValue(payload.route_decision_id ?? payload.routeDecisionId) || null,
|
||||
routeKind: stringValue(payload.route_kind ?? payload.routeKind) || null,
|
||||
intentKind: stringValue(payload.intent_kind ?? payload.intentKind) || null,
|
||||
riskLevel: stringValue(payload.risk_level ?? payload.riskLevel) || null,
|
||||
scheduleId: command.scheduleId || stringValue(result.schedule_id) || null,
|
||||
accepted: command.accepted !== false,
|
||||
message: command.message,
|
||||
@@ -4333,6 +4337,10 @@ export function applyDigitalEmployeeTaskGovernanceCommand(
|
||||
taskId,
|
||||
stepId: stepId || null,
|
||||
runId,
|
||||
routeDecisionId: stringValue(payload.route_decision_id ?? payload.routeDecisionId) || null,
|
||||
routeKind: stringValue(payload.route_kind ?? payload.routeKind) || null,
|
||||
intentKind: stringValue(payload.intent_kind ?? payload.intentKind) || null,
|
||||
riskLevel: stringValue(payload.risk_level ?? payload.riskLevel) || null,
|
||||
sourceRunId: stringValue(targetRun?.id) || null,
|
||||
accepted: command.accepted !== false,
|
||||
message: command.message,
|
||||
|
||||
@@ -1348,6 +1348,50 @@ describe("digital employee sync service", () => {
|
||||
source: "qimingclaw-task-agent",
|
||||
},
|
||||
});
|
||||
insertEventEntity("event-governance-pause", "governance_pause_plan", {
|
||||
commandKind: "pause_plan",
|
||||
commandId: "command-pause-plan",
|
||||
correlationId: "route-1",
|
||||
planId: "plan-1",
|
||||
accepted: true,
|
||||
message: "暂停计划",
|
||||
riskLevel: "normal",
|
||||
payload: {
|
||||
source: "qimingclaw-ingress-route",
|
||||
route_decision_id: "route-1",
|
||||
route_kind: "PlanControl",
|
||||
intent_kind: "control",
|
||||
plan_id: "plan-1",
|
||||
},
|
||||
result: {
|
||||
plan_id: "plan-1",
|
||||
status: "accepted",
|
||||
source: "qimingclaw-adapter",
|
||||
},
|
||||
});
|
||||
insertEventEntity("event-governance-skip", "governance_skip_task", {
|
||||
command_kind: "skip_task",
|
||||
command_id: "command-skip-task",
|
||||
correlation_id: "route-2",
|
||||
plan_id: "plan-1",
|
||||
task_id: "task-1",
|
||||
run_id: "run-1",
|
||||
step_id: "step-1",
|
||||
accepted: false,
|
||||
error: "policy_blocked",
|
||||
risk_level: "medium",
|
||||
payload: {
|
||||
source: "qimingclaw-ingress-route",
|
||||
route_decision_id: "route-2",
|
||||
route_kind: "PlanControl",
|
||||
intent_kind: "control",
|
||||
task_id: "task-1",
|
||||
},
|
||||
result: {
|
||||
status: "rejected",
|
||||
error: "policy_blocked",
|
||||
},
|
||||
});
|
||||
insertEventEntity("event-notification-read", "digital_workday_notification_read", {
|
||||
metadata: {
|
||||
notification_id: "task:task-1",
|
||||
@@ -1498,6 +1542,8 @@ describe("digital employee sync service", () => {
|
||||
{ entity_type: "event", entity_id: "event-lease" },
|
||||
{ entity_type: "event", entity_id: "event-plan-step-ready" },
|
||||
{ entity_type: "event", entity_id: "event-governance-input" },
|
||||
{ entity_type: "event", entity_id: "event-governance-pause" },
|
||||
{ entity_type: "event", entity_id: "event-governance-skip" },
|
||||
{ entity_type: "event", entity_id: "event-notification-read" },
|
||||
{ entity_type: "event", entity_id: "event-notification-dismiss" },
|
||||
{ entity_type: "event", entity_id: "event-notification-reply" },
|
||||
@@ -1639,6 +1685,36 @@ describe("digital employee sync service", () => {
|
||||
input_length: 10,
|
||||
});
|
||||
expect(businessView("event-governance-input")).not.toHaveProperty("input");
|
||||
expect(businessView("event-governance-pause")).toMatchObject({
|
||||
category: "governance",
|
||||
command_kind: "pause_plan",
|
||||
accepted: true,
|
||||
command_id: "command-pause-plan",
|
||||
correlation_id: "route-1",
|
||||
plan_id: "plan-1",
|
||||
route_decision_id: "route-1",
|
||||
route_kind: "PlanControl",
|
||||
intent_kind: "control",
|
||||
source: "qimingclaw-ingress-route",
|
||||
status: "accepted",
|
||||
risk_level: "normal",
|
||||
});
|
||||
expect(businessView("event-governance-skip")).toMatchObject({
|
||||
category: "governance",
|
||||
command_kind: "skip_task",
|
||||
accepted: false,
|
||||
error: "policy_blocked",
|
||||
command_id: "command-skip-task",
|
||||
correlation_id: "route-2",
|
||||
plan_id: "plan-1",
|
||||
task_id: "task-1",
|
||||
run_id: "run-1",
|
||||
step_id: "step-1",
|
||||
route_decision_id: "route-2",
|
||||
route_kind: "PlanControl",
|
||||
intent_kind: "control",
|
||||
risk_level: "medium",
|
||||
});
|
||||
expect(businessView("event-notification-read")).toMatchObject({
|
||||
category: "notification",
|
||||
notification_id: "task:task-1",
|
||||
|
||||
@@ -1736,7 +1736,7 @@ function eventSpecificBusinessView(
|
||||
if (kind.startsWith("plan_step_dispatch_")) return planStepDispatchBusinessView(payload);
|
||||
if (isPlanStepLeaseEvent(kind)) return planStepLeaseBusinessView(payload);
|
||||
if (isPlanStepDispatchPolicyEvent(kind)) return planStepDispatchPolicyBusinessView(payload);
|
||||
if (kind === "governance_provide_task_input") return governanceProvideTaskInputBusinessView(payload);
|
||||
if (kind.startsWith("governance_")) return governanceCommandBusinessView(kind, payload);
|
||||
if (isNotificationEvent(kind)) return notificationBusinessView(payload);
|
||||
return {};
|
||||
}
|
||||
@@ -1989,18 +1989,35 @@ function planStepDispatchPolicyBusinessView(payload: Record<string, unknown>): R
|
||||
};
|
||||
}
|
||||
|
||||
function governanceProvideTaskInputBusinessView(payload: Record<string, unknown>): Record<string, unknown> {
|
||||
function governanceCommandBusinessView(kind: string, payload: Record<string, unknown>): Record<string, unknown> {
|
||||
const commandPayload = objectRecord(payload.payload) ?? {};
|
||||
const result = objectRecord(payload.result) ?? {};
|
||||
const commandKind = stringField(payload.commandKind ?? payload.command_kind) || kind.replace(/^governance_/, "");
|
||||
const input = stringField(commandPayload.input ?? payload.input);
|
||||
return {
|
||||
command_kind: stringField(payload.commandKind ?? payload.command_kind) || "provide_task_input",
|
||||
const view: Record<string, unknown> = {
|
||||
command_kind: commandKind,
|
||||
accepted: typeof payload.accepted === "boolean" ? payload.accepted : null,
|
||||
error: stringField(payload.error ?? result.error) || null,
|
||||
command_id: stringField(payload.commandId ?? payload.command_id) || null,
|
||||
correlation_id: stringField(payload.correlationId ?? payload.correlation_id) || null,
|
||||
plan_id: stringField(payload.planId ?? payload.plan_id ?? commandPayload.plan_id ?? result.plan_id) || null,
|
||||
task_id: stringField(payload.taskId ?? payload.task_id ?? commandPayload.task_id ?? result.task_id) || null,
|
||||
run_id: stringField(payload.runId ?? payload.run_id ?? commandPayload.run_id ?? result.run_id) || null,
|
||||
step_id: stringField(payload.stepId ?? payload.step_id ?? commandPayload.step_id ?? result.step_id) || null,
|
||||
schedule_id: stringField(payload.scheduleId ?? payload.schedule_id ?? commandPayload.schedule_id ?? result.schedule_id) || null,
|
||||
route_decision_id: stringField(payload.routeDecisionId ?? payload.route_decision_id ?? commandPayload.route_decision_id ?? result.route_decision_id) || null,
|
||||
route_kind: stringField(payload.routeKind ?? payload.route_kind ?? commandPayload.route_kind ?? result.route_kind) || null,
|
||||
intent_kind: stringField(payload.intentKind ?? payload.intent_kind ?? commandPayload.intent_kind ?? result.intent_kind) || null,
|
||||
source: stringField(commandPayload.source ?? result.source ?? payload.source) || null,
|
||||
notification_id: stringField(commandPayload.notification_id ?? payload.notification_id) || null,
|
||||
input_length: input ? input.length : null,
|
||||
status: stringField(payload.status ?? result.status) || null,
|
||||
next_action: stringField(payload.nextAction ?? payload.next_action ?? result.next_action) || null,
|
||||
risk_level: stringField(payload.riskLevel ?? payload.risk_level ?? commandPayload.risk_level ?? result.risk_level) || null,
|
||||
};
|
||||
if (commandKind === "provide_task_input") {
|
||||
view.notification_id = stringField(commandPayload.notification_id ?? payload.notification_id) || null;
|
||||
view.input_length = input ? input.length : null;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
function notificationBusinessView(payload: Record<string, unknown>): Record<string, unknown> {
|
||||
|
||||
Reference in New Issue
Block a user