fix: make binary shims for custom tools cross-device compatible so users can't accidentally break sandboxes via sbx cp ~/.config/coyote <sbx-name>:/home/agent/.config
This commit is contained in:
@@ -27,14 +27,30 @@ def _ensure_cwd_venv():
|
||||
_ensure_cwd_venv()
|
||||
|
||||
|
||||
def resolve_dir(env_name, default_path):
|
||||
"""Resolve a directory at run time.
|
||||
|
||||
Prefer the override env var when set, otherwise fall back to the default
|
||||
path derived from this script's own location, so the shim keeps working
|
||||
when the config dir moves or is shared across environments with different
|
||||
home directories.
|
||||
"""
|
||||
value = os.environ.get(env_name)
|
||||
if value:
|
||||
return value
|
||||
return os.path.normpath(default_path)
|
||||
|
||||
|
||||
def main():
|
||||
(agent_func, raw_data) = parse_argv()
|
||||
agent_data = parse_raw_data(raw_data)
|
||||
|
||||
root_dir = "{config_dir}"
|
||||
setup_env(root_dir, agent_func, raw_data)
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
agent_dir = os.path.normpath(os.path.join(self_dir, ".."))
|
||||
root_dir = resolve_dir("{root_dir_env}", os.path.join(self_dir, "{root_dir_rel}"))
|
||||
setup_env(root_dir, agent_dir, agent_func, raw_data)
|
||||
|
||||
agent_tools_path = os.path.join(root_dir, "agents/{agent_name}/tools.py")
|
||||
agent_tools_path = os.path.join(agent_dir, "tools.py")
|
||||
run(agent_tools_path, agent_func, agent_data)
|
||||
|
||||
|
||||
@@ -65,12 +81,12 @@ def parse_argv():
|
||||
return agent_func, agent_data
|
||||
|
||||
|
||||
def setup_env(root_dir, agent_func, raw_data):
|
||||
def setup_env(root_dir, agent_dir, agent_func, raw_data):
|
||||
load_env(os.path.join(root_dir, ".env"))
|
||||
os.environ["LLM_ROOT_DIR"] = root_dir
|
||||
os.environ["LLM_AGENT_NAME"] = "{agent_name}"
|
||||
os.environ["LLM_AGENT_FUNC"] = agent_func
|
||||
os.environ["LLM_AGENT_ROOT_DIR"] = os.path.join(root_dir, "agents", "{agent_name}")
|
||||
os.environ["LLM_AGENT_ROOT_DIR"] = agent_dir
|
||||
os.environ["LLM_AGENT_CACHE_DIR"] = os.path.join(root_dir, "cache", "{agent_name}")
|
||||
os.environ["LLM_AGENT_RAW_JSON"] = raw_data
|
||||
|
||||
|
||||
@@ -5,13 +5,30 @@
|
||||
set -e
|
||||
|
||||
main() {
|
||||
root_dir="{config_dir}"
|
||||
self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
agent_dir="$(cd "$self_dir/.." && pwd)"
|
||||
root_dir="$(resolve_dir "{root_dir_env}" "$self_dir/{root_dir_rel}")"
|
||||
functions_dir="$(resolve_dir "{functions_dir_env}" "$self_dir/{functions_dir_rel}")"
|
||||
parse_argv "$@"
|
||||
setup_env
|
||||
tools_path="$root_dir/agents/{agent_name}/tools.sh"
|
||||
tools_path="$agent_dir/tools.sh"
|
||||
run
|
||||
}
|
||||
|
||||
# Resolve a directory at run time: prefer the override env var ($1) when set,
|
||||
# otherwise fall back to the default path ($2) derived from this script's own
|
||||
# location, so the shim keeps working when the config dir moves or is shared
|
||||
# across environments with different home directories.
|
||||
resolve_dir() {
|
||||
local override
|
||||
override="$(printenv "$1" 2>/dev/null || true)"
|
||||
if [[ -n "$override" ]]; then
|
||||
echo "$override"
|
||||
else
|
||||
(cd "$2" 2>/dev/null && pwd) || echo "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
parse_argv() {
|
||||
agent_func="$1"
|
||||
if [[ -n "$LLM_TOOL_DATA_FILE" ]] && [[ -f "$LLM_TOOL_DATA_FILE" ]]; then
|
||||
@@ -29,9 +46,9 @@ setup_env() {
|
||||
export LLM_ROOT_DIR="$root_dir"
|
||||
export LLM_AGENT_NAME="{agent_name}"
|
||||
export LLM_AGENT_FUNC="$agent_func"
|
||||
export LLM_AGENT_ROOT_DIR="$LLM_ROOT_DIR/agents/{agent_name}"
|
||||
export LLM_AGENT_ROOT_DIR="$agent_dir"
|
||||
export LLM_AGENT_CACHE_DIR="$LLM_ROOT_DIR/cache/{agent_name}"
|
||||
export LLM_PROMPT_UTILS_FILE="{prompt_utils_file}"
|
||||
export LLM_PROMPT_UTILS_FILE="$functions_dir/utils/prompt-utils.sh"
|
||||
export LLM_AGENT_RAW_JSON="$agent_data"
|
||||
}
|
||||
|
||||
@@ -59,6 +76,10 @@ run() {
|
||||
die "error: no JSON data"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$tools_path" ]]; then
|
||||
die "error: agent tools script not found: $tools_path"
|
||||
fi
|
||||
|
||||
if [[ "$OS" == "Windows_NT" ]]; then
|
||||
set -o igncr
|
||||
tools_path="$(cygpath -w "$tools_path")"
|
||||
@@ -122,4 +143,3 @@ die() {
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
|
||||
@@ -3,17 +3,38 @@
|
||||
// Usage: ./{agent_name}.ts <agent-func> <agent-data>
|
||||
|
||||
import { readFileSync, writeFileSync, existsSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { pathToFileURL } from "url";
|
||||
import { dirname, join, resolve } from "path";
|
||||
import { fileURLToPath, pathToFileURL } from "url";
|
||||
|
||||
function selfDir(): string {
|
||||
if (typeof __dirname !== "undefined") {
|
||||
return __dirname;
|
||||
}
|
||||
return dirname(fileURLToPath(import.meta.url));
|
||||
}
|
||||
|
||||
// Resolve a directory at run time: prefer the override env var when set,
|
||||
// otherwise fall back to the default path derived from this script's own
|
||||
// location, so the shim keeps working when the config dir moves or is shared
|
||||
// across environments with different home directories.
|
||||
function resolveDir(envName: string, defaultPath: string): string {
|
||||
const value = process.env[envName];
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
return resolve(defaultPath);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const { agentFunc, rawData } = parseArgv();
|
||||
const agentData = parseRawData(rawData);
|
||||
|
||||
const configDir = "{config_dir}";
|
||||
setupEnv(configDir, agentFunc, rawData);
|
||||
const binDir = selfDir();
|
||||
const agentDir = resolve(binDir, "..");
|
||||
const configDir = resolveDir("{root_dir_env}", join(binDir, "{root_dir_rel}"));
|
||||
setupEnv(configDir, agentDir, agentFunc, rawData);
|
||||
|
||||
const agentToolsPath = join(configDir, "agents", "{agent_name}", "tools.ts");
|
||||
const agentToolsPath = join(agentDir, "tools.ts");
|
||||
await run(agentToolsPath, agentFunc, agentData);
|
||||
}
|
||||
|
||||
@@ -48,12 +69,17 @@ function parseArgv(): { agentFunc: string; rawData: string } {
|
||||
return { agentFunc, rawData: agentData };
|
||||
}
|
||||
|
||||
function setupEnv(configDir: string, agentFunc: string, rawData: string): void {
|
||||
function setupEnv(
|
||||
configDir: string,
|
||||
agentDir: string,
|
||||
agentFunc: string,
|
||||
rawData: string,
|
||||
): void {
|
||||
loadEnv(join(configDir, ".env"));
|
||||
process.env["LLM_ROOT_DIR"] = configDir;
|
||||
process.env["LLM_AGENT_NAME"] = "{agent_name}";
|
||||
process.env["LLM_AGENT_FUNC"] = agentFunc;
|
||||
process.env["LLM_AGENT_ROOT_DIR"] = join(configDir, "agents", "{agent_name}");
|
||||
process.env["LLM_AGENT_ROOT_DIR"] = agentDir;
|
||||
process.env["LLM_AGENT_CACHE_DIR"] = join(configDir, "cache", "{agent_name}");
|
||||
process.env["LLM_AGENT_RAW_JSON"] = rawData;
|
||||
}
|
||||
|
||||
@@ -27,14 +27,30 @@ def _ensure_cwd_venv():
|
||||
_ensure_cwd_venv()
|
||||
|
||||
|
||||
def resolve_dir(env_name, default_path):
|
||||
"""Resolve a directory at run time.
|
||||
|
||||
Prefer the override env var when set, otherwise fall back to the default
|
||||
path derived from this script's own location, so the shim keeps working
|
||||
when the config dir moves or is shared across environments with different
|
||||
home directories.
|
||||
"""
|
||||
value = os.environ.get(env_name)
|
||||
if value:
|
||||
return value
|
||||
return os.path.normpath(default_path)
|
||||
|
||||
|
||||
def main():
|
||||
raw_data = parse_argv()
|
||||
tool_data = parse_raw_data(raw_data)
|
||||
|
||||
root_dir = "{root_dir}"
|
||||
self_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
root_dir = resolve_dir("{root_dir_env}", os.path.join(self_dir, "{root_dir_rel}"))
|
||||
functions_dir = resolve_dir("{functions_dir_env}", os.path.join(self_dir, "{functions_dir_rel}"))
|
||||
setup_env(root_dir, raw_data)
|
||||
|
||||
tool_path = "{tool_path}.py"
|
||||
tool_path = os.path.join(functions_dir, "tools", "{function_name}.py")
|
||||
run(tool_path, "run", tool_data)
|
||||
|
||||
|
||||
|
||||
@@ -5,13 +5,29 @@
|
||||
set -e
|
||||
|
||||
main() {
|
||||
root_dir="{root_dir}"
|
||||
self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
root_dir="$(resolve_dir "{root_dir_env}" "$self_dir/{root_dir_rel}")"
|
||||
functions_dir="$(resolve_dir "{functions_dir_env}" "$self_dir/{functions_dir_rel}")"
|
||||
parse_argv "$@"
|
||||
setup_env
|
||||
tool_path="{tool_path}.sh"
|
||||
tool_path="$functions_dir/tools/{function_name}.sh"
|
||||
run
|
||||
}
|
||||
|
||||
# Resolve a directory at run time: prefer the override env var ($1) when set,
|
||||
# otherwise fall back to the default path ($2) derived from this script's own
|
||||
# location, so the shim keeps working when the config dir moves or is shared
|
||||
# across environments with different home directories.
|
||||
resolve_dir() {
|
||||
local override
|
||||
override="$(printenv "$1" 2>/dev/null || true)"
|
||||
if [[ -n "$override" ]]; then
|
||||
echo "$override"
|
||||
else
|
||||
(cd "$2" 2>/dev/null && pwd) || echo "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
parse_argv() {
|
||||
if [[ -n "$LLM_TOOL_DATA_FILE" ]] && [[ -f "$LLM_TOOL_DATA_FILE" ]]; then
|
||||
tool_data="$(cat "$LLM_TOOL_DATA_FILE")"
|
||||
@@ -28,7 +44,7 @@ setup_env() {
|
||||
export LLM_ROOT_DIR="$root_dir"
|
||||
export LLM_TOOL_NAME="{function_name}"
|
||||
export LLM_TOOL_CACHE_DIR="$LLM_ROOT_DIR/cache/{function_name}"
|
||||
export LLM_PROMPT_UTILS_FILE="{prompt_utils_file}"
|
||||
export LLM_PROMPT_UTILS_FILE="$functions_dir/utils/prompt-utils.sh"
|
||||
export LLM_TOOL_RAW_JSON="$tool_data"
|
||||
}
|
||||
|
||||
@@ -56,6 +72,10 @@ run() {
|
||||
die "error: no JSON data"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$tool_path" ]]; then
|
||||
die "error: tool script not found: $tool_path"
|
||||
fi
|
||||
|
||||
if [[ "$OS" == "Windows_NT" ]]; then
|
||||
set -o igncr
|
||||
tool_path="$(cygpath -w "$tool_path")"
|
||||
|
||||
@@ -3,17 +3,41 @@
|
||||
// Usage: ./{function_name}.ts <tool-data>
|
||||
|
||||
import { readFileSync, writeFileSync, existsSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { pathToFileURL } from "url";
|
||||
import { dirname, join, resolve } from "path";
|
||||
import { fileURLToPath, pathToFileURL } from "url";
|
||||
|
||||
function selfDir(): string {
|
||||
if (typeof __dirname !== "undefined") {
|
||||
return __dirname;
|
||||
}
|
||||
return dirname(fileURLToPath(import.meta.url));
|
||||
}
|
||||
|
||||
// Resolve a directory at run time: prefer the override env var when set,
|
||||
// otherwise fall back to the default path derived from this script's own
|
||||
// location, so the shim keeps working when the config dir moves or is shared
|
||||
// across environments with different home directories.
|
||||
function resolveDir(envName: string, defaultPath: string): string {
|
||||
const value = process.env[envName];
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
return resolve(defaultPath);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const rawData = parseArgv();
|
||||
const toolData = parseRawData(rawData);
|
||||
|
||||
const rootDir = "{root_dir}";
|
||||
const binDir = selfDir();
|
||||
const rootDir = resolveDir("{root_dir_env}", join(binDir, "{root_dir_rel}"));
|
||||
const functionsDir = resolveDir(
|
||||
"{functions_dir_env}",
|
||||
join(binDir, "{functions_dir_rel}"),
|
||||
);
|
||||
setupEnv(rootDir, rawData);
|
||||
|
||||
const toolPath = "{tool_path}.ts";
|
||||
const toolPath = join(functionsDir, "tools", "{function_name}.ts");
|
||||
await run(toolPath, "run", toolData);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user