mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-10-04 02:52:55 +08:00
Merge pull request #384 from kevin9327/fix/bash-shell-alias
fix(tools): complete the bash shell alias in the tool codec
This commit is contained in:
@@ -167,7 +167,7 @@ pub fn tool_completed(call: &ToolCall, completion: &ToolCompletion) -> pb::Agent
|
||||
pub fn tool_placeholder(name: &str, call_id: &str) -> Result<pb::ToolCall> {
|
||||
use pb::tool_call::Tool;
|
||||
let tool = match normalized(name).as_str() {
|
||||
"shell" => Tool::ShellToolCall(pb::ShellToolCall::default()),
|
||||
"shell" | "bash" => Tool::ShellToolCall(pb::ShellToolCall::default()),
|
||||
"delete" => Tool::DeleteToolCall(pb::DeleteToolCall::default()),
|
||||
"glob" => Tool::GlobToolCall(pb::GlobToolCall::default()),
|
||||
"grep" => Tool::GrepToolCall(pb::GrepToolCall::default()),
|
||||
@@ -527,3 +527,23 @@ fn now_ms() -> u64 {
|
||||
.unwrap_or_default()
|
||||
.as_millis() as u64
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::tool_placeholder;
|
||||
use crate::cursor::protocol::proto::agent::v1 as pb;
|
||||
|
||||
#[test]
|
||||
fn bash_renders_as_a_shell_placeholder() {
|
||||
// The dispatcher treats `bash`/`Bash` as a Shell alias, so the streaming
|
||||
// placeholder must too; otherwise a `Bash` tool call aborts the turn with
|
||||
// `unsupported tool: bash` before it ever runs.
|
||||
for name in ["shell", "Shell", "bash", "Bash"] {
|
||||
let tool = tool_placeholder(name, "call-1").unwrap().tool;
|
||||
assert!(
|
||||
matches!(tool, Some(pb::tool_call::Tool::ShellToolCall(_))),
|
||||
"{name} should render as a Shell tool"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn request(id: u32, call: &ToolCall, context: &ExecContext) -> Result<pb::Ag
|
||||
.map(|v| v as i32)
|
||||
};
|
||||
let message = match normalize(&call.name).as_str() {
|
||||
"shell" => {
|
||||
"shell" | "bash" => {
|
||||
let command = string("command")?;
|
||||
let (simple_commands, parsing_result) = shell_command_metadata(&command);
|
||||
Message::ShellStreamArgs(pb::ShellArgs {
|
||||
@@ -520,3 +520,37 @@ fn prost_value(value: &Value) -> prost_types::Value {
|
||||
};
|
||||
ProstValue { kind: Some(kind) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
use super::request;
|
||||
use crate::cursor::protocol::proto::agent::v1 as pb;
|
||||
use crate::cursor::tools::runtime::ExecContext;
|
||||
use crate::model::ToolCall;
|
||||
|
||||
#[test]
|
||||
fn bash_is_encoded_as_a_shell_exec_request() {
|
||||
// The dispatcher routes `bash`/`Bash` to the shell executor, so the
|
||||
// request codec must encode it as a Shell stream instead of erroring
|
||||
// with `tool bash is not executed through ExecServerMessage`.
|
||||
let call = ToolCall {
|
||||
index: 0,
|
||||
call_id: "call-1".into(),
|
||||
model_call_id: "model-1".into(),
|
||||
name: "Bash".into(),
|
||||
arguments_text: String::new(),
|
||||
arguments: json!({ "command": "ls -la" }),
|
||||
};
|
||||
let message = request(1, &call, &ExecContext::default()).unwrap();
|
||||
let Some(pb::agent_server_message::Message::ExecServerMessage(exec)) = message.message
|
||||
else {
|
||||
panic!("expected an ExecServerMessage");
|
||||
};
|
||||
let Some(pb::exec_server_message::Message::ShellStreamArgs(args)) = exec.message else {
|
||||
panic!("expected ShellStreamArgs");
|
||||
};
|
||||
assert_eq!(args.command, "ls -la");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,8 @@ pub async fn stream_closed(id: u32, pending: &CursorToolRuntime) -> Result<Optio
|
||||
return Ok(None);
|
||||
};
|
||||
let error = "Cursor Exec stream closed before returning a terminal result";
|
||||
if entry.call.name.eq_ignore_ascii_case("Shell") {
|
||||
if entry.call.name.eq_ignore_ascii_case("Shell") || entry.call.name.eq_ignore_ascii_case("Bash")
|
||||
{
|
||||
let command = entry
|
||||
.call
|
||||
.arguments
|
||||
|
||||
Reference in New Issue
Block a user