feat: adjust the way of obtaining function call results (#695)

pull/699/head^2
sigoden 2 months ago committed by GitHub
parent 48219d2808
commit 4ea6f3933f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -31,17 +31,12 @@ function_calling: true # Enables or disables function calling (Globall
mapping_tools: # Alias for a tool or toolset
# fs: 'fs_cat,fs_ls,fs_mkdir,fs_rm,fs_write'
use_tools: null # Which tools to use by default
# Regex for seletecting dangerous functions
# User confirmation is required when executing these functions
# e.g. 'execute_command|execute_js_code' 'execute_.*'
dangerously_functions_filter: null
# Per-Agent configuration
agents:
- name: todo-sh
model: null
temperature: null
top_p: null
dangerously_functions_filter: null
# ---- RAG ----
rag_embedding_model: null # Specifies the embedding model to use

@ -117,10 +117,6 @@ impl Agent {
&self.name
}
pub fn config(&self) -> &AgentConfig {
&self.config
}
pub fn functions(&self) -> &Functions {
&self.functions
}
@ -211,8 +207,6 @@ pub struct AgentConfig {
pub top_p: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
use_tools: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dangerously_functions_filter: Option<String>,
}
impl AgentConfig {

@ -18,7 +18,6 @@ use crate::render::{MarkdownRender, RenderOptions};
use crate::utils::*;
use anyhow::{anyhow, bail, Context, Result};
use fancy_regex::Regex;
use indexmap::IndexMap;
use inquire::{Confirm, Select};
use parking_lot::RwLock;
@ -107,7 +106,6 @@ pub struct Config {
pub function_calling: bool,
pub mapping_tools: IndexMap<String, String>,
pub use_tools: Option<String>,
pub dangerously_functions_filter: Option<String>,
pub agents: Vec<AgentConfig>,
pub rag_embedding_model: Option<String>,
@ -170,7 +168,6 @@ impl Default for Config {
function_calling: true,
mapping_tools: Default::default(),
use_tools: None,
dangerously_functions_filter: None,
agents: vec![],
rag_embedding_model: None,
@ -1146,26 +1143,6 @@ impl Config {
}
}
pub fn is_dangerously_function(&self, name: &str) -> bool {
if get_env_bool("no_dangerously_functions") {
return false;
}
let dangerously_functions_filter = match &self.agent {
Some(agent) => agent.config().dangerously_functions_filter.as_ref(),
None => self.dangerously_functions_filter.as_ref(),
};
match dangerously_functions_filter {
None => false,
Some(regex) => {
let regex = match Regex::new(&format!("^({regex})$")) {
Ok(v) => v,
Err(_) => return false,
};
regex.is_match(name).unwrap_or(false)
}
}
}
pub fn buffer_editor(&self) -> Option<String> {
self.buffer_editor
.clone()

@ -5,7 +5,6 @@ use crate::{
use anyhow::{anyhow, bail, Context, Result};
use indexmap::IndexMap;
use inquire::{validator::Validation, Text};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::{
@ -157,7 +156,6 @@ impl ToolCall {
pub fn eval(&self, config: &GlobalConfig) -> Result<Value> {
let function_name = self.name.clone();
let is_dangerously = config.read().is_dangerously_function(&function_name);
let (call_name, cmd_name, mut cmd_args) = match &config.read().agent {
Some(agent) => {
if let Some(true) = agent.functions().find(&function_name).map(|v| v.agent) {
@ -205,76 +203,28 @@ impl ToolCall {
if bin_dir.exists() {
envs.insert("PATH".into(), prepend_env_path(&bin_dir)?);
}
let temp_file = temp_file("-eval-", "");
envs.insert("LLM_OUTPUT".into(), temp_file.display().to_string());
#[cfg(windows)]
let cmd_name = polyfill_cmd_name(&cmd_name, &bin_dir);
let output = if is_dangerously {
if *IS_STDOUT_TERMINAL {
println!("{}", dimmed_text(&prompt));
let answer = Text::new("[1] Run, [2] Run & Retrieve, [3] Skip:")
.with_default("1")
.with_validator(|input: &str| match matches!(input, "1" | "2" | "3") {
true => Ok(Validation::Valid),
false => Ok(Validation::Invalid(
"Invalid input, please select 1, 2 or 3".into(),
)),
})
.prompt()?;
match answer.as_str() {
"1" => {
let exit_code = run_command(&cmd_name, &cmd_args, Some(envs))?;
if exit_code != 0 {
bail!("Exit {exit_code}");
}
Value::Null
}
"2" => run_and_retrieve(&cmd_name, &cmd_args, envs)?,
_ => Value::Null,
}
} else {
println!("Skipped {prompt}");
Value::Null
}
} else {
println!("{}", dimmed_text(&prompt));
run_and_retrieve(&cmd_name, &cmd_args, envs)?
};
Ok(output)
}
}
fn run_and_retrieve(
cmd_name: &str,
cmd_args: &[String],
envs: HashMap<String, String>,
) -> Result<Value> {
let (success, stdout, stderr) = run_command_with_output(cmd_name, cmd_args, Some(envs))?;
if success {
if !stderr.is_empty() {
eprintln!("{}", warning_text(&stderr));
println!("{}", dimmed_text(&prompt));
let exit_code = run_command(&cmd_name, &cmd_args, Some(envs))?;
if exit_code != 0 {
bail!("Tool call exit with {exit_code}");
}
let value = if !stdout.is_empty() {
serde_json::from_str(&stdout)
let output = if temp_file.exists() {
let contents =
fs::read_to_string(temp_file).context("Failed to retrieve tool call output")?;
serde_json::from_str(&contents)
.ok()
.unwrap_or_else(|| json!({"output": stdout}))
.unwrap_or_else(|| json!({"result": contents}))
} else {
Value::Null
};
Ok(value)
} else {
let err = if stderr.is_empty() {
if stdout.is_empty() {
"Something wrong"
} else {
&stdout
}
} else {
&stderr
};
bail!("{err}");
Ok(output)
}
}

@ -22,7 +22,7 @@ use anyhow::{Context, Result};
use fancy_regex::Regex;
use is_terminal::IsTerminal;
use lazy_static::lazy_static;
use std::{env, path::PathBuf};
use std::{env, path::PathBuf, process};
lazy_static! {
pub static ref CODE_BLOCK_RE: Regex = Regex::new(r"(?ms)```\w*(.*)```").unwrap();
@ -42,14 +42,6 @@ pub fn get_env_name(key: &str) -> String {
)
}
pub fn get_env_bool(key: &str) -> bool {
if let Ok(value) = env::var(get_env_name(key)) {
value == "1" || value == "true"
} else {
false
}
}
pub fn tokenize(text: &str) -> Vec<&str> {
if text.is_ascii() {
text.split_inclusive(|c: char| c.is_ascii_whitespace())
@ -158,8 +150,9 @@ pub fn dimmed_text(input: &str) -> String {
pub fn temp_file(prefix: &str, suffix: &str) -> PathBuf {
env::temp_dir().join(format!(
"{}{prefix}{}{suffix}",
"{}-{}{prefix}{}{suffix}",
env!("CARGO_CRATE_NAME").to_lowercase(),
process::id(),
uuid::Uuid::new_v4()
))
}

Loading…
Cancel
Save