fix: carry tool input in ApprovalRequired event so approval dialog always shows params
The ApprovalRequest params_display() relied on pending_tool_uses,
which gets drained by MessageComplete before ApprovalRequired arrives
in the TUI event loop. When the model streaming response contained a
text block, ContentBlockStop(Text) set pending_message_complete=true,
triggering the drain and leaving the approval dialog with empty {}.
Fix: add input: Value to Event::ApprovalRequired and populate it
from tool_input in the engine tool execution loop. The TUI now reads
params directly from the event instead of searching pending_tool_uses.
This commit is contained in:
@@ -1696,6 +1696,7 @@ impl Engine {
|
||||
.send(Event::ApprovalRequired {
|
||||
id: tool_id.clone(),
|
||||
tool_name: tool_name.clone(),
|
||||
input: tool_input.clone(),
|
||||
description: plan.approval_description.clone(),
|
||||
approval_key,
|
||||
approval_grouping_key,
|
||||
|
||||
@@ -226,6 +226,9 @@ pub enum Event {
|
||||
id: String,
|
||||
tool_name: String,
|
||||
description: String,
|
||||
/// Tool parameters for approval display. Carried on the event so the
|
||||
/// TUI does not need to reconstruct them from `pending_tool_uses`.
|
||||
input: Value,
|
||||
/// Exact-argument fingerprint, used to scope *denials* (#1617).
|
||||
approval_key: String,
|
||||
/// Lossy / arity-aware fingerprint, used to scope *approvals* so an
|
||||
|
||||
@@ -4172,6 +4172,7 @@ mod tests {
|
||||
id: "tool_stale".to_string(),
|
||||
tool_name: "exec_command".to_string(),
|
||||
description: "stale approval".to_string(),
|
||||
input: serde_json::json!({}),
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -4245,6 +4246,7 @@ mod tests {
|
||||
id: "tool_external_allow".to_string(),
|
||||
tool_name: "exec_command".to_string(),
|
||||
description: "external allow".to_string(),
|
||||
input: serde_json::json!({}),
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -4322,6 +4324,7 @@ mod tests {
|
||||
id: "tool_external_deny".to_string(),
|
||||
tool_name: "exec_command".to_string(),
|
||||
description: "external deny".to_string(),
|
||||
input: serde_json::json!({}),
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -4508,6 +4511,7 @@ mod tests {
|
||||
id: "tool_remember".to_string(),
|
||||
tool_name: "exec_command".to_string(),
|
||||
description: "remember=true".to_string(),
|
||||
input: serde_json::json!({}),
|
||||
})
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -1893,6 +1893,7 @@ async fn run_event_loop(
|
||||
id,
|
||||
tool_name,
|
||||
description,
|
||||
input,
|
||||
approval_key,
|
||||
approval_grouping_key,
|
||||
} => {
|
||||
@@ -1937,12 +1938,7 @@ async fn run_event_loop(
|
||||
app.status_message =
|
||||
Some(format!("Blocked tool '{tool_name}' (approval_mode=never)"));
|
||||
} else {
|
||||
let tool_input = app
|
||||
.pending_tool_uses
|
||||
.iter()
|
||||
.find(|(tool_id, _, _)| tool_id == &id)
|
||||
.map(|(_, _, input)| input.clone())
|
||||
.unwrap_or_else(|| serde_json::json!({}));
|
||||
let tool_input = input;
|
||||
|
||||
if tool_name == "apply_patch" {
|
||||
maybe_add_patch_preview(app, &tool_input);
|
||||
|
||||
Reference in New Issue
Block a user