吸收数字员工诊断成本审计

This commit is contained in:
baiyanyun
2026-06-12 10:52:35 +08:00
parent 3a159e2f5a
commit 9011b91dba
9 changed files with 343 additions and 57 deletions

View File

@@ -1279,6 +1279,39 @@ describe("digital employee sync service", () => {
decision: "rejected",
reason_codes: ["skill_disabled"],
});
insertEventEntity("event-sandbox-audit", "sandbox_audit", {
session_id: "sandbox-session-1",
operation: "execute",
status: "failed",
exit_code: 126,
duration_ms: 2400,
command: "curl https://example.com --header Authorization: Bearer secret-token",
command_preview: "curl https://example.com",
reason_codes: ["permission_denied"],
authorization: "Bearer secret-token",
});
insertEventEntity("event-token-cost", "token_cost", {
session_id: "session-cost-1",
model: "gpt-4.1-mini",
input_tokens: 120,
output_tokens: 80,
total_tokens: 200,
estimated_cost_usd: 0.0125,
prompt: "完整客户资料和敏感输入不应同步",
raw_input: { token: "raw-secret" },
token: "secret-token",
});
insertEventEntity("event-tool-audit", "tool_call_audit", {
session_id: "session-tool-1",
server_id: "crm-server",
tool_name: "crm.search",
operation: "tool_call",
status: "allowed",
duration_ms: 640,
input_length: 36,
raw_input: { customer_phone: "13800000000" },
authorization: "Bearer tool-secret",
});
insertEventEntity("event-dispatch", "plan_step_dispatch_failed", {
step_id: "step-1",
plan_id: "plan-1",
@@ -1538,6 +1571,9 @@ describe("digital employee sync service", () => {
{ entity_type: "event", entity_id: "event-approval-decision" },
{ entity_type: "event", entity_id: "event-artifact" },
{ entity_type: "event", entity_id: "event-skill" },
{ entity_type: "event", entity_id: "event-sandbox-audit" },
{ entity_type: "event", entity_id: "event-token-cost" },
{ entity_type: "event", entity_id: "event-tool-audit" },
{ entity_type: "event", entity_id: "event-dispatch" },
{ entity_type: "event", entity_id: "event-lease" },
{ entity_type: "event", entity_id: "event-plan-step-ready" },
@@ -1635,6 +1671,42 @@ describe("digital employee sync service", () => {
decision: "rejected",
reason_codes: ["skill_disabled"],
});
expect(businessView("event-sandbox-audit")).toMatchObject({
category: "sandbox_audit",
session_id: "sandbox-session-1",
operation: "execute",
status: "failed",
exit_code: 126,
duration_ms: 2400,
command_preview: "curl https://example.com",
reason_codes: ["permission_denied"],
});
expect(JSON.stringify(businessView("event-sandbox-audit"))).not.toContain("secret-token");
expect(JSON.stringify(businessView("event-sandbox-audit"))).not.toContain("Authorization");
expect(businessView("event-token-cost")).toMatchObject({
category: "token_cost",
session_id: "session-cost-1",
model: "gpt-4.1-mini",
input_tokens: 120,
output_tokens: 80,
total_tokens: 200,
estimated_cost_usd: 0.0125,
estimated: false,
});
expect(JSON.stringify(businessView("event-token-cost"))).not.toContain("完整客户资料");
expect(JSON.stringify(businessView("event-token-cost"))).not.toContain("raw-secret");
expect(businessView("event-tool-audit")).toMatchObject({
category: "tool_call_audit",
session_id: "session-tool-1",
server_id: "crm-server",
tool_name: "crm.search",
operation: "tool_call",
status: "allowed",
duration_ms: 640,
input_length: 36,
});
expect(JSON.stringify(businessView("event-tool-audit"))).not.toContain("13800000000");
expect(JSON.stringify(businessView("event-tool-audit"))).not.toContain("tool-secret");
expect(businessView("event-dispatch")).toMatchObject({
category: "dispatch",
step_id: "step-1",

View File

@@ -1737,6 +1737,9 @@ function eventSpecificBusinessView(
if (isPlanStepLeaseEvent(kind)) return planStepLeaseBusinessView(payload);
if (isPlanStepDispatchPolicyEvent(kind)) return planStepDispatchPolicyBusinessView(payload);
if (kind.startsWith("governance_")) return governanceCommandBusinessView(kind, payload);
if (kind === "sandbox_audit") return sandboxAuditBusinessView(payload);
if (kind === "token_cost") return tokenCostBusinessView(payload);
if (kind === "tool_call_audit") return toolCallAuditBusinessView(payload);
if (isNotificationEvent(kind)) return notificationBusinessView(payload);
return {};
}
@@ -2020,6 +2023,49 @@ function governanceCommandBusinessView(kind: string, payload: Record<string, unk
return view;
}
function sandboxAuditBusinessView(payload: Record<string, unknown>): Record<string, unknown> {
return {
session_id: stringField(payload.session_id ?? payload.sessionId) || null,
operation: stringField(payload.operation ?? payload.action) || null,
status: stringField(payload.status) || null,
exit_code: numberField(payload.exit_code ?? payload.exitCode),
duration_ms: numberField(payload.duration_ms ?? payload.durationMs),
command_preview: compactPreview(stringField(payload.command_preview ?? payload.commandPreview) || ""),
reason_codes: stringArrayField(payload.reason_codes ?? payload.reasonCodes),
};
}
function tokenCostBusinessView(payload: Record<string, unknown>): Record<string, unknown> {
const inputTokens = numberField(payload.input_tokens ?? payload.inputTokens);
const outputTokens = numberField(payload.output_tokens ?? payload.outputTokens);
const totalTokens = numberField(payload.total_tokens ?? payload.totalTokens) ?? ((inputTokens ?? 0) + (outputTokens ?? 0) || null);
const estimatedCostUsd = numberField(payload.estimated_cost_usd ?? payload.estimatedCostUsd ?? payload.cost_usd ?? payload.costUsd);
return {
session_id: stringField(payload.session_id ?? payload.sessionId) || null,
model: stringField(payload.model) || null,
status: stringField(payload.status) || null,
input_tokens: inputTokens,
output_tokens: outputTokens,
total_tokens: totalTokens,
estimated_cost_usd: estimatedCostUsd,
estimated: typeof payload.estimated === "boolean" ? payload.estimated : estimatedCostUsd === null,
};
}
function toolCallAuditBusinessView(payload: Record<string, unknown>): Record<string, unknown> {
return {
session_id: stringField(payload.session_id ?? payload.sessionId) || null,
server_id: stringField(payload.server_id ?? payload.serverId) || null,
tool_name: stringField(payload.tool_name ?? payload.toolName) || null,
operation: stringField(payload.operation ?? payload.action) || null,
status: stringField(payload.status) || null,
exit_code: numberField(payload.exit_code ?? payload.exitCode),
duration_ms: numberField(payload.duration_ms ?? payload.durationMs),
input_length: numberField(payload.input_length ?? payload.inputLength),
reason_codes: stringArrayField(payload.reason_codes ?? payload.reasonCodes),
};
}
function notificationBusinessView(payload: Record<string, unknown>): Record<string, unknown> {
const metadata = objectRecord(payload.metadata) ?? {};
const state = objectRecord(payload.state) ?? {};
@@ -2063,6 +2109,9 @@ function eventBusinessCategory(kind: string): string {
if (isPlanStepDispatchPolicyEvent(kind)) return "dispatch";
if (isNotificationEvent(kind)) return "notification";
if (kind.startsWith("governance_")) return "governance";
if (kind === "sandbox_audit") return "sandbox_audit";
if (kind === "token_cost") return "token_cost";
if (kind === "tool_call_audit") return "tool_call_audit";
return "runtime";
}