吸收数字员工诊断成本审计
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user