fix(tui): clarify shell tool availability errors (#2412)
Harvested from #2402 with thanks to @axobase001. Keeps `allow_shell` guidance visible for gated shell tools even when missing-tool suggestions exist, removes the nonexistent task_shell_cancel matcher, and broadens regression coverage. Partially addresses #2328.
This commit is contained in:
@@ -2359,6 +2359,44 @@ fn missing_tool_error_message_includes_discovery_guidance_when_no_match() {
|
||||
assert!(message.contains(TOOL_SEARCH_BM25_NAME));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_shell_tool_error_message_names_allow_shell_gate() {
|
||||
let catalog = vec![api_tool("read_file")];
|
||||
|
||||
for tool_name in [
|
||||
"exec_shell",
|
||||
"exec_shell_wait",
|
||||
"exec_shell_interact",
|
||||
"task_shell_start",
|
||||
"task_shell_wait",
|
||||
] {
|
||||
let message = missing_tool_error_message(tool_name, &catalog);
|
||||
assert!(message.contains("not available in the current tool catalog"));
|
||||
assert!(message.contains("allow_shell"), "{tool_name}: {message}");
|
||||
assert!(
|
||||
message.contains("trusted workspaces"),
|
||||
"{tool_name}: {message}"
|
||||
);
|
||||
assert!(
|
||||
message.contains(TOOL_SEARCH_BM25_NAME),
|
||||
"{tool_name}: {message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_shell_tool_error_message_keeps_allow_shell_hint_with_suggestions() {
|
||||
let catalog = vec![api_tool("exec")];
|
||||
|
||||
let message = missing_tool_error_message("exec_shell", &catalog);
|
||||
|
||||
assert!(message.contains("Did you mean:"));
|
||||
assert!(message.contains("exec"));
|
||||
assert!(message.contains("allow_shell"));
|
||||
assert!(message.contains("trusted workspaces"));
|
||||
assert!(message.contains(TOOL_SEARCH_BM25_NAME));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_tool_call_delta_strips_bracket_marker() {
|
||||
let mut in_block = false;
|
||||
|
||||
@@ -438,17 +438,52 @@ fn suggest_tool_names(catalog: &[Tool], requested: &str, limit: usize) -> Vec<St
|
||||
|
||||
pub(super) fn missing_tool_error_message(tool_name: &str, catalog: &[Tool]) -> String {
|
||||
let suggestions = suggest_tool_names(catalog, tool_name, 3);
|
||||
let shell_hint = if is_shell_tool_name(tool_name) {
|
||||
Some(shell_tool_allow_shell_hint())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if suggestions.is_empty() {
|
||||
if let Some(shell_hint) = shell_hint {
|
||||
return format!(
|
||||
"Tool '{tool_name}' is not available in the current tool catalog. \
|
||||
{shell_hint}, or use {TOOL_SEARCH_BM25_NAME} with a short query."
|
||||
);
|
||||
}
|
||||
return format!(
|
||||
"Tool '{tool_name}' is not available in the current tool catalog. \
|
||||
Verify mode/feature flags, or use {TOOL_SEARCH_BM25_NAME} with a short query."
|
||||
);
|
||||
}
|
||||
|
||||
let suggestion_text = format!("Did you mean: {}?", suggestions.join(", "));
|
||||
if let Some(shell_hint) = shell_hint {
|
||||
return format!(
|
||||
"Tool '{tool_name}' is not available in the current tool catalog. \
|
||||
{suggestion_text} {shell_hint}. \
|
||||
You can also use {TOOL_SEARCH_BM25_NAME} to discover tools."
|
||||
);
|
||||
}
|
||||
|
||||
format!(
|
||||
"Tool '{tool_name}' is not available in the current tool catalog. \
|
||||
Did you mean: {}? You can also use {TOOL_SEARCH_BM25_NAME} to discover tools.",
|
||||
suggestions.join(", ")
|
||||
{suggestion_text} You can also use {TOOL_SEARCH_BM25_NAME} to discover tools."
|
||||
)
|
||||
}
|
||||
|
||||
fn shell_tool_allow_shell_hint() -> &'static str {
|
||||
"Shell tools are gated by `allow_shell`; enable `allow_shell = true` for trusted workspaces, \
|
||||
or switch to an auto-approve mode that permits shell access"
|
||||
}
|
||||
|
||||
fn is_shell_tool_name(tool_name: &str) -> bool {
|
||||
matches!(
|
||||
tool_name,
|
||||
"exec_shell"
|
||||
| "exec_shell_wait"
|
||||
| "exec_shell_interact"
|
||||
| "task_shell_start"
|
||||
| "task_shell_wait"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user