summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsigoden <sigoden@gmail.com>2024-07-10 18:53:58 +0800
committerGitHub <noreply@github.com>2024-07-10 18:53:58 +0800
commit4ea6f3933fff4974334e3f9ecb2a423aab43a787 (patch)
tree37e27557072165ebd7a61b27e21b7e3e55d713dd /src
parent48219d2808bafc88fa4fa4d6997aa9dc92e6f686 (diff)
downloadaichat-4ea6f3933fff4974334e3f9ecb2a423aab43a787.tar.gz
feat: adjust the way of obtaining function call results (#695)
Diffstat (limited to 'src')
-rw-r--r--src/config/agent.rs6
-rw-r--r--src/config/mod.rs23
-rw-r--r--src/function.rs78
-rw-r--r--src/utils/mod.rs13
4 files changed, 17 insertions, 103 deletions
diff --git a/src/config/agent.rs b/src/config/agent.rs
index 7a065e7..7d1a43b 100644
--- a/src/config/agent.rs
+++ b/src/config/agent.rs
@@ -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 {
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 154dcd9..220b7c8 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -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()
diff --git a/src/function.rs b/src/function.rs
index 0016405..6a7e81e 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -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)
}
}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
index 40967ab..35f41a2 100644
--- a/src/utils/mod.rs
+++ b/src/utils/mod.rs
@@ -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()
))
}