From d4de2d761bba9d1c0bd1972113c76cc64720392c Mon Sep 17 00:00:00 2001 From: sigoden Date: Mon, 20 May 2024 17:27:34 +0800 Subject: [PATCH] refactor: no export LLM_FUNCTION_DATA, pass json as command arg (#528) --- src/function.rs | 79 ++++++++----------------------------------------- 1 file changed, 13 insertions(+), 66 deletions(-) diff --git a/src/function.rs b/src/function.rs index 708321f..fe7f088 100644 --- a/src/function.rs +++ b/src/function.rs @@ -218,47 +218,42 @@ impl ToolCall { } else { bail!("The {name} call has invalid arguments: {}", self.arguments); }; - let arguments = convert_arguments(&arguments); - let prompt_text = format!( - "Call {} {}", - name, - arguments - .iter() - .map(|v| shell_words::quote(v).to_string()) - .collect::>() - .join(" ") - ); + let arguments = arguments.to_string(); + let prompt = format!("Call {name} '{arguments}'",); let mut envs = HashMap::new(); - envs.insert("LLM_FUNCTION_DATA".into(), self.arguments.to_string()); if let Some(env_path) = config.read().function.env_path.clone() { envs.insert("PATH".into(), env_path); }; let output = if self.is_execute_type() { let proceed = if stdout().is_terminal() { - Confirm::new(&prompt_text).with_default(true).prompt()? + Confirm::new(&prompt).with_default(true).prompt()? } else { - println!("{}", dimmed_text(&prompt_text)); + println!("{}", dimmed_text(&prompt)); true }; if proceed { #[cfg(windows)] let name = polyfill_cmd_name(&name, &config.read().function.bin_dir); - run_command(&name, &arguments, Some(envs))?; + let exit_code = run_command(&name, &[&arguments], Some(envs))?; + if exit_code != 0 { + bail!("Exit {exit_code}"); + } } Value::Null } else { - println!("{}", dimmed_text(&prompt_text)); + println!("{}", dimmed_text(&prompt)); #[cfg(windows)] let name = polyfill_cmd_name(&name, &config.read().function.bin_dir); - let (success, stdout, stderr) = run_command_with_output(&name, &arguments, Some(envs))?; + let (success, stdout, stderr) = + run_command_with_output(&name, &[arguments], Some(envs))?; if success { if !stderr.is_empty() { eprintln!( "{}", - warning_text(&format!("{prompt_text}:\n{}", indent_text(&stderr, 4))) + warning_text(&format!("{prompt}:\n{}", indent_text(&stderr, 4))) ); } if !stdout.is_empty() { @@ -278,7 +273,7 @@ impl ToolCall { } else { &stderr }; - bail!("{}", &format!("{prompt_text}:\n{}", indent_text(err, 4))); + bail!("{}", &format!("{prompt}:\n{}", indent_text(err, 4))); } }; @@ -290,35 +285,6 @@ impl ToolCall { } } -fn convert_arguments(args: &Value) -> Vec { - let mut options: Vec = Vec::new(); - - if let Value::Object(map) = args { - for (key, value) in map { - let key = key.replace('_', "-"); - match value { - Value::Bool(true) => { - options.push(format!("--{key}")); - } - Value::String(s) => { - options.push(format!("--{key}")); - options.push(s.to_string()); - } - Value::Array(arr) => { - for item in arr { - if let Value::String(s) = item { - options.push(format!("--{key}")); - options.push(s.to_string()); - } - } - } - _ => {} // Ignore other types - } - } - } - options -} - fn prepend_env_path(bin_dir: &Path) -> Result { let current_path = std::env::var("PATH").context("No PATH environment variable")?; @@ -344,22 +310,3 @@ fn polyfill_cmd_name(name: &str, bin_dir: &std::path::Path) -> String { } name } - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - fn test_convert_args() { - let args = serde_json::json!({ - "foo": true, - "bar": "val", - "baz": ["v1", "v2"] - }); - assert_eq!( - convert_arguments(&args), - vec!["--foo", "--bar", "val", "--baz", "v1", "--baz", "v2"] - ); - } -}