fix(approval): persist the real pendingId on guard audit rows

This commit is contained in:
matevip 2026-07-23 11:46:22 +08:00
parent 8174006b01
commit 49f7a74386
2 changed files with 19 additions and 18 deletions

View File

@ -1083,14 +1083,12 @@ public class ToolExecutionExecutor {
}
List<AssistantMessage.ToolCall> remaining = allToolCalls.subList(currentIndex + 1, allToolCalls.size());
String approvalResponse = ToolExecutionGuardHelper.handleToolApproval(
ToolExecutionGuardHelper.ApprovalRequest approval = ToolExecutionGuardHelper.handleToolApproval(
toolCall, toolName, arguments, evaluation,
conversationId, agentId, requesterId, approvalService, streamTracker,
events, remaining);
// Extract pendingId from response (format: "[APPROVAL_PENDING] tool=xxx awaiting user decision")
String pendingId = extractPendingId(approvalResponse);
toolGuardService.recordApprovalAudit(guardCtx, evaluation, pendingId, autoOutcome);
return GuardDecision.needsApproval(approvalResponse, pendingId);
toolGuardService.recordApprovalAudit(guardCtx, evaluation, approval.pendingId(), autoOutcome);
return GuardDecision.needsApproval(approval.response(), approval.pendingId());
}
} else if (toolGuard != null) {
ToolGuardResult guardResult = toolGuard.check(toolName, arguments);
@ -1111,7 +1109,9 @@ public class ToolExecutionExecutor {
toolCall, toolName, arguments, guardResult,
conversationId, agentId, requesterId, approvalService, streamTracker,
events, remaining);
return GuardDecision.needsApproval(approvalResponse, extractPendingId(approvalResponse));
// Legacy path never persisted a pendingId to carry here; the value
// is unused downstream (only the boolean awaitingApproval is read).
return GuardDecision.needsApproval(approvalResponse, null);
}
}
@ -1207,14 +1207,6 @@ public class ToolExecutionExecutor {
return "Tool execution failed: " + message;
}
/**
* approval response 中提取 pendingIdbest-effort
*/
private String extractPendingId(String approvalResponse) {
// handleToolApproval 内部已经创建了 pending这里只做标记
return approvalResponse;
}
/**
* Issue #46 when a tool callback miss happens, check whether the
* unrecognized name actually matches an active skill. If it does, return

View File

@ -27,7 +27,15 @@ public final class ToolExecutionGuardHelper {
*
* @return 审批提示文本作为 tool response 返回给 LLM
*/
public static String handleToolApproval(
/**
* Outcome of {@link #handleToolApproval}: the tool-response text handed back
* to the LLM plus the persisted pending-approval id. {@code pendingId} is
* null when the approval service is unavailable and the call degraded to a
* block-style message.
*/
public record ApprovalRequest(String response, String pendingId) {}
public static ApprovalRequest handleToolApproval(
AssistantMessage.ToolCall toolCall, String toolName, String arguments,
GuardEvaluation evaluation, String conversationId, String agentId,
String requesterId,
@ -39,8 +47,8 @@ public final class ToolExecutionGuardHelper {
log.warn("[GuardHelper] ApprovalService not available, falling back to BLOCK for tool={}", toolName);
events.add(GraphEventPublisher.toolComplete(toolName,
evaluation.summary() != null ? evaluation.summary() : "需要审批", false));
return "[安全拦截] " + (evaluation.summary() != null ? evaluation.summary() : "需要审批")
+ "。审批服务不可用,请联系管理员。";
return new ApprovalRequest("[安全拦截] " + (evaluation.summary() != null ? evaluation.summary() : "需要审批")
+ "。审批服务不可用,请联系管理员。", null);
}
String toolCallPayload = serializeToolCall(toolCall);
@ -78,7 +86,8 @@ public final class ToolExecutionGuardHelper {
log.info("[GuardHelper] Approval pending created: pendingId={}, tool={}, findings={}",
pendingId, toolName, evaluation.hasFindings() ? evaluation.findings().size() : 0);
return "[APPROVAL_PENDING] tool=" + toolName + " awaiting user decision";
return new ApprovalRequest(
"[APPROVAL_PENDING] tool=" + toolName + " awaiting user decision", pendingId);
}
/**