Watch
0
0
Fork
You've already forked hyperhive
0

hive-runtime: log the acp permission decision at the point it is made

This commit is contained in:
damocles 2026-10-08 08:33:27 +02:00 • committed by mara
commit c433bdef92

View file

@ -252,15 +252,17 @@ pub(super) fn permission_outcome(
let tool_call = params.get("toolCall");
let field = |k: &str| tool_call.and_then(|t| t.get(k)).and_then(Value::as_str);
let kind = field("kind").unwrap_or("other");
let title = field("title");
let ask = PermissionAsk {
kind,
// MCP tool calls are kind `other`; a title alone must not lift another
// kind (`execute`, `fetch`) into one.
mcp_server: (kind == "other")
.then(|| field("title").and_then(|title| mcp_server_of(title, servers)))
.then(|| title.and_then(|title| mcp_server_of(title, servers)))
.flatten(),
};
let wanted = if permit(&ask) {
let permitted = permit(&ask);
let wanted = if permitted {
["allow_once", "allow_always"]
} else {
["reject_once", "reject_always"]
@ -275,6 +277,30 @@ pub(super) fn permission_outcome(
.find(|o| o.get("kind").and_then(Value::as_str) == Some(want))
.and_then(|o| o.get("optionId"))
});
// Log what the agent was actually told, not just the policy's
// pre-resolution answer: `permit` saying yes doesn't mean the agent
// offered a matching `allow_*` option, and that silent-cancel case is
// exactly the shape a reporter sees as "tool call refused, nothing
// actionable in the logs" — the earlier version of this log line
// reported `permitted` and would have called that case "allowed".
// `title` is only logged for `kind == "other"` (it identifies the MCP
// tool/server) — an `execute` title can carry a command line and must
// not land in the journal at this level.
let other_title = (kind == "other").then_some(title).flatten();
match chosen {
Some(option) if permitted => {
tracing::debug!(kind, mcp_server = ?ask.mcp_server, option = %option, "ACP permission request allowed");
}
Some(option) => {
tracing::info!(kind, mcp_server = ?ask.mcp_server, title = other_title, option = %option, "ACP permission request denied by policy");
}
None => {
// An anomaly, not a policy decision: the agent offered no
// option matching what the policy wanted, so the request is
// cancelled regardless of `permitted`.
tracing::warn!(kind, mcp_server = ?ask.mcp_server, title = other_title, permitted, "ACP permission request cancelled — agent offered no matching option");
}
}
match chosen {
Some(option) => json!({ "outcome": { "outcome": "selected", "optionId": option } }),
None => json!({ "outcome": { "outcome": "cancelled" } }),