From b6b0a9dcb3a815b3e4732793fa5afd1ed921c5b3 Mon Sep 17 00:00:00 2001 From: baiyanyun Date: Sat, 13 Jun 2026 14:07:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=B8=E6=94=B6=E6=95=B0=E5=AD=97=E5=91=98?= =?UTF-8?q?=E5=B7=A5=E7=AE=A1=E7=90=86=E7=AB=AF=E6=B2=BB=E7=90=86=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E9=A2=84=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...talEmployeeSyncApplicationServiceImpl.java | 7 ++ ...mployeeSyncApplicationServiceImplTest.java | 70 +++++++++++++++++++ .../Content/DigitalEmployeeOps/index.tsx | 21 ++++++ qiming/src/types/interfaces/systemManage.ts | 1 + .../scripts/check-digital-employee.js | 67 ++++++++++++++++++ ...ital-employee-frontend-integration-plan.md | 2 +- 6 files changed, 167 insertions(+), 1 deletion(-) diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java index 44dc490c..eb36bfed 100644 --- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java +++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java @@ -1003,6 +1003,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye case "notifications" -> isNotificationRow(row); case "audits" -> isAuditRow(row); case "daily_reports" -> isDailyReportRow(row); + case "governance_commands" -> isGovernanceCommandRow(row); case "route_governance" -> isRouteGovernanceRow(row); default -> true; }; @@ -1072,6 +1073,12 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye || StringUtils.isNotBlank(row.getReportId()); } + private boolean isGovernanceCommandRow(DigitalEmployeeAdminWorkbenchRowDto row) { + return StringUtils.equals(row.getCategory(), "governance") + || startsWithAny(row.getKind(), "governance_") + || StringUtils.isNotBlank(firstString(row.getBusinessView().get("command_id"), row.getPayload().get("command_id"))); + } + private boolean isRouteGovernanceRow(DigitalEmployeeAdminWorkbenchRowDto row) { return StringUtils.equals(row.getCategory(), "route_governance") || StringUtils.equals(row.getCategory(), "route_intervention") diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java index 9a976741..4bb9c1b7 100644 --- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java +++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java @@ -468,6 +468,76 @@ class DigitalEmployeeSyncApplicationServiceImplTest { assertThat(result.getRecords().get(2).getRouteDecisionId()).isEqualTo("route-3"); } + @Test + void queryAdminWorkbenchGovernanceCommandsReturnsGovernanceRowsOnly() { + when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L))) + .thenReturn(page(List.of( + record("outbox-governance-pause", "event", "event-governance-1", 101L, new Date(10_000), + Map.of( + "entity_type", "event", + "category", "governance", + "kind", "governance_pause_plan", + "status", "recorded", + "title", "暂停计划命令", + "summary", "低风险治理命令已记录", + "command_id", "command-1", + "plan_id", "plan-1", + "risk_level", "low" + ), + Map.of("id", "event-governance-1", "kind", "governance_pause_plan")), + record("outbox-governance-input", "event", "event-governance-2", 101L, new Date(11_000), + Map.of( + "entity_type", "event", + "kind", "governance_provide_task_input", + "status", "accepted", + "title", "补充任务输入", + "command_id", "command-2", + "task_id", "task-1", + "input_length", 18 + ), + Map.of("id", "event-governance-2", "kind", "governance_provide_task_input")), + record("outbox-governance-rejected", "event", "event-governance-3", 101L, new Date(12_000), + Map.of( + "entity_type", "event", + "category", "governance", + "kind", "governance_cancel_task", + "status", "rejected", + "title", "取消任务被拒绝", + "command_id", "command-3", + "task_id", "task-2", + "error", "approval_required" + ), + Map.of("id", "event-governance-3", "kind", "governance_cancel_task")), + record("outbox-route", "event", "event-route-1", 101L, new Date(13_000), + Map.of("entity_type", "event", "category", "route_governance", "title", "路由", "status", "blocked"), + Map.of("id", "event-route-1", "status", "blocked")), + record("outbox-task", "task", "task-1", 101L, new Date(14_000), + Map.of("entity_type", "task", "title", "普通任务", "status", "running"), + Map.of("id", "task-1", "status", "running")), + record("outbox-approval", "approval", "approval-1", 101L, new Date(15_000), + Map.of("entity_type", "approval", "title", "普通审批", "status", "pending"), + Map.of("id", "approval-1", "status", "pending")), + record("outbox-notification", "notification", "notification-1", 101L, new Date(16_000), + Map.of("entity_type", "notification", "title", "普通通知", "status", "unread"), + Map.of("id", "notification-1", "status", "unread")) + ))); + + DigitalEmployeeAdminWorkbenchPageDto result = service.queryAdminWorkbench( + "governance_commands", null, null, null, null, null, null, null, null, null, null, null, 1L, 20L + ); + + assertThat(result.getTotal()).isEqualTo(3); + assertThat(result.getRecords()).extracting(DigitalEmployeeAdminWorkbenchRowDto::getEntityId) + .containsExactly("event-governance-1", "event-governance-2", "event-governance-3"); + assertThat(result.getRecords().get(0).getView()).isEqualTo("governance_commands"); + assertThat(result.getRecords().get(0).getCategory()).isEqualTo("governance"); + assertThat(result.getRecords().get(0).getStatus()).isEqualTo("recorded"); + assertThat(result.getRecords().get(0).getSummary()).isEqualTo("低风险治理命令已记录"); + assertThat(result.getRecords().get(0).getBusinessView()).containsEntry("command_id", "command-1"); + assertThat(result.getRecords().get(1).getBusinessView()).containsEntry("input_length", 18); + assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("error", "approval_required"); + } + @Test void queryAdminWorkbenchNotificationsReturnsNotificationRowsOnly() { when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L))) diff --git a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx index 78197654..9b733a47 100644 --- a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx +++ b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx @@ -44,6 +44,7 @@ const WORKBENCH_TABS: Array<{ { key: 'notifications', label: '通知运营' }, { key: 'audits', label: '审计诊断' }, { key: 'daily_reports', label: '日报运营' }, + { key: 'governance_commands', label: '治理命令' }, { key: 'route_governance', label: '路由治理' }, { key: 'policy_conflicts', label: '策略冲突' }, ]; @@ -168,6 +169,9 @@ function actionTarget(record: DigitalEmployeeAdminWorkbenchRow, view: DigitalEmp if (view === 'audits') { return { entityType: 'audit', entityId: record.entity_id }; } + if (view === 'governance_commands') { + return { entityType: 'event', entityId: record.entity_id }; + } if (view === 'policy_conflicts') { return { entityType: 'policy_snapshot', @@ -242,6 +246,12 @@ function allowedActions(record: DigitalEmployeeAdminWorkbenchRow, view: DigitalE { action: 'dismiss', label: '忽略' }, ]; } + if (view === 'governance_commands') { + return [ + { action: 'mark_reviewed', label: '标记已看' }, + { action: 'dismiss', label: '忽略' }, + ]; + } return []; } @@ -749,6 +759,17 @@ const DigitalEmployeeOps: React.FC = () => { )} + {activeView === 'governance_commands' && ( + + 治理命令: + {detailRecord.kind || detailRecord.category || detailRecord.entity_id || '--'} + {detailRecord.status && ` · ${detailRecord.status}`} + + {' '} + · 只记录复核/忽略意图,不开放 ACP 硬中断或高风险执行。 + + + )} {allowedActions(detailRecord, activeView).length > 0 && (
低风险动作 diff --git a/qiming/src/types/interfaces/systemManage.ts b/qiming/src/types/interfaces/systemManage.ts index 679ac3d4..00990db5 100644 --- a/qiming/src/types/interfaces/systemManage.ts +++ b/qiming/src/types/interfaces/systemManage.ts @@ -565,6 +565,7 @@ export type DigitalEmployeeAdminWorkbenchView = | 'notifications' | 'audits' | 'daily_reports' + | 'governance_commands' | 'route_governance' | 'policy_conflicts'; diff --git a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js index a22c67fb..9a3ffcdc 100644 --- a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js +++ b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js @@ -1924,6 +1924,72 @@ function checkDigitalAdminDailyReportWorkbench() { console.log("[DigitalEmployeeCheck] admin daily report workbench hooks OK"); } +function checkDigitalAdminGovernanceCommandWorkbench() { + console.log("\n[DigitalEmployeeCheck] Verify admin governance command workbench hooks"); + const backendRoot = path.resolve(packageRoot, "..", "..", "..", "qiming-backend"); + const qimingRoot = path.resolve(packageRoot, "..", "..", "..", "qiming"); + const servicePath = path.join( + backendRoot, + "app-platform-modules", + "app-platform-agent", + "app-platform-agent-core-application", + "src", + "main", + "java", + "com", + "xspaceagi", + "agent", + "core", + "application", + "service", + "DigitalEmployeeSyncApplicationServiceImpl.java", + ); + const testPath = path.join( + backendRoot, + "app-platform-modules", + "app-platform-agent", + "app-platform-agent-core-application", + "src", + "test", + "java", + "com", + "xspaceagi", + "agent", + "core", + "application", + "service", + "DigitalEmployeeSyncApplicationServiceImplTest.java", + ); + const qimingOpsPath = path.join(qimingRoot, "src", "pages", "SystemManagement", "Content", "DigitalEmployeeOps", "index.tsx"); + const qimingTypesPath = path.join(qimingRoot, "src", "types", "interfaces", "systemManage.ts"); + const docsPath = path.resolve(packageRoot, "..", "..", "docs", "digital-employee-frontend-integration-plan.md"); + const service = fs.readFileSync(servicePath, "utf8"); + const test = fs.readFileSync(testPath, "utf8"); + const qimingOps = fs.readFileSync(qimingOpsPath, "utf8"); + const qimingTypes = fs.readFileSync(qimingTypesPath, "utf8"); + const docs = fs.readFileSync(docsPath, "utf8"); + const requiredSnippets = [ + [service, "governance_commands", "backend governance command view"], + [service, "isGovernanceCommandRow", "backend governance command matcher"], + [service, "governance_", "backend governance command kind classifier"], + [service, "command_id", "backend governance command id classifier"], + [test, "queryAdminWorkbenchGovernanceCommandsReturnsGovernanceRowsOnly", "backend governance command test"], + [qimingTypes, "governance_commands", "qiming governance command view type"], + [qimingOps, "治理命令", "qiming governance command tab"], + [qimingOps, "标记已看", "qiming governance reviewed action"], + [qimingOps, "忽略", "qiming governance dismiss action"], + [qimingOps, "ACP 硬中断", "qiming high-risk governance copy"], + [docs, "正式管理端治理命令预览", "docs governance command absorption"], + ]; + const missing = requiredSnippets + .filter(([content, snippet]) => !content.includes(snippet)) + .map(([, , label]) => label); + if (missing.length > 0) { + throw new Error(`Missing admin governance command workbench hooks: ${missing.join(", ")}`); + } + console.log("[DigitalEmployeeCheck] admin governance command workbench hooks OK"); +} + function checkLocalDatabaseSchema() { console.log("\n[DigitalEmployeeCheck] Verify local SQLite digital schema"); const dbPath = path.join(os.homedir(), ".qimingclaw", "qimingclaw.db"); @@ -1993,6 +2059,7 @@ function main() { checkDigitalAdminArtifactLifecycleWorkbench(); checkDigitalAdminAuditDiagnosticsWorkbench(); checkDigitalAdminDailyReportWorkbench(); + checkDigitalAdminGovernanceCommandWorkbench(); checkLocalDatabaseSchema(); console.log("\n[DigitalEmployeeCheck] All checks passed"); } catch (error) { diff --git a/qimingclaw/docs/digital-employee-frontend-integration-plan.md b/qimingclaw/docs/digital-employee-frontend-integration-plan.md index bd938dda..b486f36e 100644 --- a/qimingclaw/docs/digital-employee-frontend-integration-plan.md +++ b/qimingclaw/docs/digital-employee-frontend-integration-plan.md @@ -568,7 +568,7 @@ GET /api/digital-employee/approvals 4. **治理命令完整生命周期** - 已吸收:`create_plan`、`submit_plan`、`approve_plan`、`activate_plan` 等基础命令可记录本地运行事实;任务级 `retry_task`、`skip_task`、`pause_task`、`resume_task`、`provide_task_input`、`cancel_task`、`start_run`、`cancel_run` 已具备本地事实闭环;embedded plan / task action endpoint 已开始映射为正式 governance command;治理审计链和低风险 action policy 已开始吸收,route decision 自动映射 governance command 前会先经过低风险/受保护高风险 action guard,未命中的动作写入 `route_action_policy_blocked`,所有 `governance_*` event 的同步 `business_view` 会提炼 command、route、实体目标、风险等级和结果字段,`provide_task_input` 只同步 `input_length`。 - - 当前能力:`/api/plan/:id/submit`、`/api/debug/plan/:id/:action`、`/api/task/:id/:action` 会进入 qimingclaw 本地治理记录;plan revision v1 可从 `governance_*` 事件投影只读时间线;数字员工首页会展示“治理审计/治理拦截”摘要,管理端通用 sync record 可通过 `business_view.category = governance` 消费治理命令审计字段。 + - 当前能力:`/api/plan/:id/submit`、`/api/debug/plan/:id/:action`、`/api/task/:id/:action` 会进入 qimingclaw 本地治理记录;plan revision v1 可从 `governance_*` 事件投影只读时间线;数字员工首页会展示“治理审计/治理拦截”摘要,管理端通用 sync record 可通过 `business_view.category = governance` 消费治理命令审计字段。正式管理端治理命令预览已开始吸收,qiming-backend 的 `governance_commands` 运营台视图会聚合治理命令记录、拒绝和低风险输入审计,qiming“数字员工运营台”的“治理命令”tab 只开放标记已看和忽略意图,不开放 ACP 硬中断或高风险执行。 - 缺口:`escalate`、正式计划 revision 表、正式管理端治理工作台和对真实 ACP 执行流的硬中断仍不完整。 - 建议:下一轮围绕正式管理端治理工作台和 ACP 硬中断,把本地治理审计推进到完整跨端裁决与执行控制。