fix: Tool call improvements for Windows systems
This commit is contained in:
Generated
+1
@@ -3137,6 +3137,7 @@ dependencies = [
|
||||
"crossterm 0.28.1",
|
||||
"dirs",
|
||||
"duct",
|
||||
"dunce",
|
||||
"fancy-regex",
|
||||
"futures-util",
|
||||
"fuzzy-matcher",
|
||||
|
||||
@@ -18,6 +18,7 @@ anyhow = "1.0.69"
|
||||
bytes = "1.4.0"
|
||||
clap = { version = "4.5.40", features = ["cargo", "derive", "wrap_help"] }
|
||||
dirs = "6.0.0"
|
||||
dunce = "1.0.5"
|
||||
futures-util = "0.3.29"
|
||||
inquire = "0.9.4"
|
||||
is-terminal = "0.4.9"
|
||||
|
||||
@@ -50,7 +50,13 @@ def parse_raw_data(data):
|
||||
|
||||
def parse_argv():
|
||||
agent_func = sys.argv[1]
|
||||
agent_data = sys.argv[2]
|
||||
|
||||
tool_data_file = os.environ.get("LLM_TOOL_DATA_FILE")
|
||||
if tool_data_file and os.path.isfile(tool_data_file):
|
||||
with open(tool_data_file, "r", encoding="utf-8") as f:
|
||||
agent_data = f.read()
|
||||
else:
|
||||
agent_data = sys.argv[2]
|
||||
|
||||
if (not agent_data) or (not agent_func):
|
||||
print("Usage: ./{agent_name}.py <agent-func> <agent-data>", file=sys.stderr)
|
||||
|
||||
@@ -14,7 +14,11 @@ main() {
|
||||
|
||||
parse_argv() {
|
||||
agent_func="$1"
|
||||
agent_data="$2"
|
||||
if [[ -n "$LLM_TOOL_DATA_FILE" ]] && [[ -f "$LLM_TOOL_DATA_FILE" ]]; then
|
||||
agent_data="$(cat "$LLM_TOOL_DATA_FILE")"
|
||||
else
|
||||
agent_data="$2"
|
||||
fi
|
||||
if [[ -z "$agent_data" ]] || [[ -z "$agent_func" ]]; then
|
||||
die "usage: ./{agent_name}.sh <agent-func> <agent-data>"
|
||||
fi
|
||||
@@ -57,7 +61,6 @@ run() {
|
||||
if [[ "$OS" == "Windows_NT" ]]; then
|
||||
set -o igncr
|
||||
tools_path="$(cygpath -w "$tools_path")"
|
||||
tool_data="$(echo "$tool_data" | sed 's/\\/\\\\/g')"
|
||||
fi
|
||||
|
||||
jq_script="$(cat <<-'EOF'
|
||||
|
||||
@@ -49,6 +49,11 @@ def parse_raw_data(data):
|
||||
|
||||
|
||||
def parse_argv():
|
||||
tool_data_file = os.environ.get("LLM_TOOL_DATA_FILE")
|
||||
if tool_data_file and os.path.isfile(tool_data_file):
|
||||
with open(tool_data_file, "r", encoding="utf-8") as f:
|
||||
return f.read()
|
||||
|
||||
argv = sys.argv[:] + [None] * max(0, 2 - len(sys.argv))
|
||||
|
||||
tool_data = argv[1]
|
||||
|
||||
@@ -13,7 +13,11 @@ main() {
|
||||
}
|
||||
|
||||
parse_argv() {
|
||||
tool_data="$1"
|
||||
if [[ -n "$LLM_TOOL_DATA_FILE" ]] && [[ -f "$LLM_TOOL_DATA_FILE" ]]; then
|
||||
tool_data="$(cat "$LLM_TOOL_DATA_FILE")"
|
||||
else
|
||||
tool_data="$1"
|
||||
fi
|
||||
if [[ -z "$tool_data" ]]; then
|
||||
die "usage: ./{function_name}.sh <tool-data>"
|
||||
fi
|
||||
@@ -54,7 +58,6 @@ run() {
|
||||
if [[ "$OS" == "Windows_NT" ]]; then
|
||||
set -o igncr
|
||||
tool_path="$(cygpath -w "$tool_path")"
|
||||
tool_data="$(echo "$tool_data" | sed 's/\\/\\\\/g')"
|
||||
fi
|
||||
|
||||
jq_script="$(cat <<-'EOF'
|
||||
|
||||
@@ -107,6 +107,7 @@ The following variables can be used to change the log level of Loki or the locat
|
||||
can also pass the `--disable-log-colors` flag as well.
|
||||
|
||||
## Miscellaneous Variables
|
||||
| Environment Variable | Description | Default Value |
|
||||
|----------------------|--------------------------------------------------------------------------------------------------|---------------|
|
||||
| `AUTO_CONFIRM` | Bypass all `guard_*` checks in the bash prompt helpers; useful for agent composition and routing | |
|
||||
| Environment Variable | Description | Default Value |
|
||||
|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
|
||||
| `AUTO_CONFIRM` | Bypass all `guard_*` checks in the bash prompt helpers; useful for agent composition and routing | |
|
||||
| `LLM_TOOL_DATA_FILE` | Set automatically by Loki on Windows. Points to a temporary file containing the JSON tool call data. <br>Tool scripts (`run-tool.sh`, `run-agent.sh`, etc.) read from this file instead of command-line args <br>to avoid JSON escaping issues when data passes through `cmd.exe` → bash. **Not intended to be set by users.** | |
|
||||
+29
-14
@@ -613,6 +613,7 @@ impl Functions {
|
||||
)
|
||||
})?;
|
||||
let content_template = unsafe { std::str::from_utf8_unchecked(&embedded_file.data) };
|
||||
let to_script_path = |p: &str| -> String { p.replace('\\', "/") };
|
||||
let content = match binary_type {
|
||||
BinaryType::Tool(None) => {
|
||||
let root_dir = Config::functions_dir();
|
||||
@@ -622,8 +623,8 @@ impl Functions {
|
||||
);
|
||||
content_template
|
||||
.replace("{function_name}", binary_name)
|
||||
.replace("{root_dir}", &root_dir.to_string_lossy())
|
||||
.replace("{tool_path}", &tool_path)
|
||||
.replace("{root_dir}", &to_script_path(&root_dir.to_string_lossy()))
|
||||
.replace("{tool_path}", &to_script_path(&tool_path))
|
||||
}
|
||||
BinaryType::Tool(Some(agent_name)) => {
|
||||
let root_dir = Config::agent_data_dir(agent_name);
|
||||
@@ -633,16 +634,19 @@ impl Functions {
|
||||
);
|
||||
content_template
|
||||
.replace("{function_name}", binary_name)
|
||||
.replace("{root_dir}", &root_dir.to_string_lossy())
|
||||
.replace("{tool_path}", &tool_path)
|
||||
.replace("{root_dir}", &to_script_path(&root_dir.to_string_lossy()))
|
||||
.replace("{tool_path}", &to_script_path(&tool_path))
|
||||
}
|
||||
BinaryType::Agent => content_template
|
||||
.replace("{agent_name}", binary_name)
|
||||
.replace("{config_dir}", &Config::config_dir().to_string_lossy()),
|
||||
.replace(
|
||||
"{config_dir}",
|
||||
&to_script_path(&Config::config_dir().to_string_lossy()),
|
||||
),
|
||||
}
|
||||
.replace(
|
||||
"{prompt_utils_file}",
|
||||
&Config::bash_prompt_utils_file().to_string_lossy(),
|
||||
&to_script_path(&Config::bash_prompt_utils_file().to_string_lossy()),
|
||||
);
|
||||
if binary_script_file.exists() {
|
||||
fs::remove_file(&binary_script_file)?;
|
||||
@@ -666,7 +670,7 @@ impl Functions {
|
||||
.join(".venv")
|
||||
.join("Scripts")
|
||||
.join("activate.bat");
|
||||
let canonicalized_path = fs::canonicalize(&executable_path)?;
|
||||
let canonicalized_path = dunce::canonicalize(&executable_path)?;
|
||||
format!(
|
||||
"call \"{}\" && {}",
|
||||
canonicalized_path.to_string_lossy(),
|
||||
@@ -677,19 +681,16 @@ impl Functions {
|
||||
let executable_path = which::which("python")
|
||||
.or_else(|_| which::which("python3"))
|
||||
.map_err(|_| anyhow!("Python executable not found in PATH"))?;
|
||||
let canonicalized_path = fs::canonicalize(&executable_path)?;
|
||||
let canonicalized_path = dunce::canonicalize(&executable_path)?;
|
||||
canonicalized_path.to_string_lossy().into_owned()
|
||||
}
|
||||
_ => bail!("Unsupported language: {}", language.as_ref()),
|
||||
};
|
||||
let bin_dir = binary_file
|
||||
.parent()
|
||||
.expect("Failed to get parent directory of binary file")
|
||||
.canonicalize()?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let wrapper_binary = binary_script_file
|
||||
.canonicalize()?
|
||||
.expect("Failed to get parent directory of binary file");
|
||||
let bin_dir = dunce::canonicalize(bin_dir)?.to_string_lossy().into_owned();
|
||||
let wrapper_binary = dunce::canonicalize(&binary_script_file)?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let content = formatdoc!(
|
||||
@@ -1117,6 +1118,20 @@ pub fn run_llm_function(
|
||||
#[cfg(windows)]
|
||||
let cmd_name = polyfill_cmd_name(&cmd_name, &bin_dirs);
|
||||
|
||||
#[cfg(windows)]
|
||||
let cmd_args = {
|
||||
let mut args = cmd_args;
|
||||
if let Some(json_data) = args.pop() {
|
||||
let tool_data_file = temp_file("-tool-data-", ".json");
|
||||
fs::write(&tool_data_file, &json_data)?;
|
||||
envs.insert(
|
||||
"LLM_TOOL_DATA_FILE".into(),
|
||||
tool_data_file.display().to_string(),
|
||||
);
|
||||
}
|
||||
args
|
||||
};
|
||||
|
||||
envs.insert("CLICOLOR_FORCE".into(), "1".into());
|
||||
envs.insert("FORCE_COLOR".into(), "1".into());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user