Fixing bug where canceled tool calls may cause terminal to freeze

This commit is contained in:
Ryan Ward
2026-05-15 16:18:24 -05:00
parent 76b727c5af
commit 95b4708e44
3 changed files with 42 additions and 4 deletions
+1 -1
View File
@@ -500,7 +500,7 @@ fn build_tool_call_message(
api::message::tool_call::RunShellCommand { api::message::tool_call::RunShellCommand {
command, command,
is_read_only: false, is_read_only: false,
uses_pager: false, uses_pager: true,
citations: vec![], citations: vec![],
is_risky: false, is_risky: false,
risk_category: 0, risk_category: 0,
@@ -236,9 +236,16 @@ impl ShellCommandExecutor {
.active_block() .active_block()
.is_active_and_long_running() .is_active_and_long_running()
{ {
// If there is an active block, we can't execute another command. // Another command is still running (e.g. stuck in a pager). Return an error
// result so the model receives feedback and can adapt. Using Completed with a
// non-zero exit code ensures a follow-up request is triggered.
return ActionExecution::Sync(AIAgentActionResultType::RequestCommandOutput( return ActionExecution::Sync(AIAgentActionResultType::RequestCommandOutput(
RequestCommandOutputResult::CancelledBeforeExecution, RequestCommandOutputResult::Completed {
command: command.clone(),
block_id: model.block_list().active_block().id().clone(),
output: "Error: Cannot execute command because another command is still running in the terminal.".to_string(),
exit_code: ExitCode::from(1),
},
)); ));
} }
// If the command might use pager and can't be interacted with, // If the command might use pager and can't be interacted with,
+32 -1
View File
@@ -2417,7 +2417,11 @@ impl BlocklistAIController {
log::warn!("Conversation not found."); log::warn!("Conversation not found.");
return; return;
}; };
let new_exchange_ids = conversation.new_exchange_ids_for_response(&stream_id); let new_exchange_ids: Vec<_> = conversation.new_exchange_ids_for_response(&stream_id).collect();
log::info!(
"[bedrock-debug] AfterStreamFinished: stream_id={:?}, conversation_id={:?}, new_exchange_ids count={}",
stream_id, conversation_id, new_exchange_ids.len()
);
let mut was_passive_request = false; let mut was_passive_request = false;
let mut is_any_exchange_unfinished = false; let mut is_any_exchange_unfinished = false;
let mut actions_to_queue = vec![]; let mut actions_to_queue = vec![];
@@ -2429,12 +2433,30 @@ impl BlocklistAIController {
}; };
was_passive_request |= exchange.has_passive_request(); was_passive_request |= exchange.has_passive_request();
is_any_exchange_unfinished |= !exchange.output_status.is_finished(); is_any_exchange_unfinished |= !exchange.output_status.is_finished();
log::info!(
"[bedrock-debug] AfterStreamFinished: exchange_id={:?}, is_finished={}, output_status={:?}",
new_exchange_id,
exchange.output_status.is_finished(),
std::mem::discriminant(&exchange.output_status)
);
if let AIAgentOutputStatus::Finished { if let AIAgentOutputStatus::Finished {
finished_output: FinishedAIAgentOutput::Success { output }, finished_output: FinishedAIAgentOutput::Success { output },
.. ..
} = &exchange.output_status } = &exchange.output_status
{ {
let action_count = output.get().actions().count();
let msg_count = output.get().messages.len();
log::info!(
"[bedrock-debug] AfterStreamFinished: output has {} messages, {} actions",
msg_count, action_count
);
for msg in output.get().messages.iter() {
log::info!(
"[bedrock-debug] AfterStreamFinished: msg type={:?}",
std::mem::discriminant(&msg.message)
);
}
actions_to_queue.extend(output.get().actions().cloned()); actions_to_queue.extend(output.get().actions().cloned());
} }
} }
@@ -2484,9 +2506,18 @@ impl BlocklistAIController {
); );
}); });
} else if !actions_to_queue.is_empty() { } else if !actions_to_queue.is_empty() {
log::info!(
"[bedrock-debug] AfterStreamFinished: queuing {} actions",
actions_to_queue.len()
);
self.action_model.update(ctx, |action_model, ctx| { self.action_model.update(ctx, |action_model, ctx| {
action_model.queue_actions(actions_to_queue, conversation_id, ctx); action_model.queue_actions(actions_to_queue, conversation_id, ctx);
}); });
} else {
log::warn!(
"[bedrock-debug] AfterStreamFinished: NO actions to queue, was_passive={}, is_any_unfinished={}",
was_passive_request, is_any_exchange_unfinished
);
} }
// Cancelled streams will handle pending_response_stream updates synchronously. // Cancelled streams will handle pending_response_stream updates synchronously.