Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support env var LLM_DUMP_RESULTS #144

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Argcfile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ run@tool() {
fi
lang="${argc_tool##*.}"
cmd="$(_lang_to_cmd "$lang")"
run_tool_script="$PWD/scripts/run-tool.$lang"
run_tool_script="scripts/run-tool.$lang"
[[ -n "$argc_cwd" ]] && cd "$argc_cwd"
exec "$cmd" "$run_tool_script" "$argc_tool" "$argc_json"
}
Expand All @@ -52,7 +52,7 @@ run@agent() {
tools_path="$(_get_agent_tools_path "$argc_agent")"
lang="${tools_path##*.}"
cmd="$(_lang_to_cmd "$lang")"
run_agent_script="$PWD/scripts/run-agent.$lang"
run_agent_script="scripts/run-agent.$lang"
[[ -n "$argc_cwd" ]] && cd "$argc_cwd"
exec "$cmd" "$run_agent_script" "$argc_agent" "$argc_action" "$argc_json"
}
Expand Down Expand Up @@ -163,7 +163,7 @@ build-declarations@tool() {
build_failed_tools+=("$name")
}
if [[ "$json_data" == "null" ]]; then
_die "error: failed to build declartions for tool $name"
_die "error: failed to build declarations for tool $name"
fi
json_list+=("$json_data")
done
Expand Down
20 changes: 10 additions & 10 deletions docs/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

## Injected by `run-tool.*`/`run-agent.*`

| Name | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `LLM_ROOT_DIR` | Path to `<llm-functions-dir>` |
| `LLM_TOOL_NAME` | Tool name, such as `execute_command` |
| `LLM_TOOL_CACHE_DIR` | Path to `<llm-functions-dir>/cache/<tool-name>`,<br>The tool script can use this directory to store some cache data |
| `LLM_AGENT_NAME` | Agent name, such as `todo` |
| `LLM_AGENT_FUNC` | Agent function, such as `list_todos` |
| `LLM_AGENT_ROOT_DIR` | Path to `<llm-functions-dir>/agents/<agent-name>` |
| `LLM_AGENT_CACHE_DIR` | Path to `<llm-functions-dir>/cache/<agent-name>`,<br>The tool script can use this directory to store some cache data |
| Name | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `LLM_ROOT_DIR` | Path to `<llm-functions-dir>` |
| `LLM_TOOL_NAME` | Tool name, such as `execute_command` |
| `LLM_TOOL_CACHE_DIR` | Path to `<llm-functions-dir>/cache/<tool-name>`,<br>The tool script can use this directory to store some cache data |
| `LLM_AGENT_NAME` | Agent name, such as `todo` |
| `LLM_AGENT_FUNC` | Agent function, such as `list_todos` |
| `LLM_AGENT_ROOT_DIR` | Path to `<llm-functions-dir>/agents/<agent-name>` |
| `LLM_AGENT_CACHE_DIR` | Path to `<llm-functions-dir>/cache/<agent-name>`,<br>The agent tool script can use this directory to store some cache data |

## Injected by runtime (AIChat)

Expand All @@ -23,4 +23,4 @@

| Name | Description |
| ------------------ | --------------------------------------------------------------------------------------------- |
| `LLM_DUMP_RESULTS` | Controls whether to print the execution results of the tool, e.g. `get_current_weather\|fs.*` |
| `LLM_DUMP_RESULTS` | Controls whether to print the execution results of the tool, e.g. `get_current_weather\|fs.*\|todo:.*`, `.*` |
53 changes: 22 additions & 31 deletions scripts/run-agent.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env node

// Usage: ./run-agent.js <agent-name> <agent-func> <agent-data>

const path = require("path");
const { createWriteStream } = require("fs");
const { readFile } = require("fs/promises");
const { readFile, writeFile } = require("fs/promises");
const os = require("os");

async function main() {
Expand All @@ -13,7 +14,7 @@ async function main() {
await setupEnv(rootDir, agentName, agentFunc);

const agentToolsPath = path.resolve(rootDir, `agents/${agentName}/tools.js`);
await run(agentToolsPath, agentFunc, agentData);
await run(agentName, agentToolsPath, agentFunc, agentData);
}

function parseArgv(thisFileName) {
Expand Down Expand Up @@ -104,7 +105,7 @@ async function loadEnv(filePath) {
}
}

async function run(agentPath, agentFunc, agentData) {
async function run(agentName, agentPath, agentFunc, agentData) {
let mod;
if (os.platform() === "win32") {
agentPath = `file://${agentPath}`;
Expand All @@ -118,55 +119,45 @@ async function run(agentPath, agentFunc, agentData) {
throw new Error(`Not module function '${agentFunc}' at '${agentPath}'`);
}
const value = await mod[agentFunc](agentData);
returnToLLM(value);
await dumpResult();
await returnToLLM(value);
await dumpResult(`${agentName}:${agentFunc}`);
}

function returnToLLM(value) {
async function returnToLLM(value) {
if (value === null || value === undefined) {
return;
}
let writer = process.stdout;
if (process.env["LLM_OUTPUT"]) {
writer = createWriteStream(process.env["LLM_OUTPUT"]);
const write = async (value) => {
if (process.env["LLM_OUTPUT"]) {
await writeFile(process.env["LLM_OUTPUT"], value);
} else {
process.stdout.write(value);
}
}
const type = typeof value;
if (type === "string" || type === "number" || type === "boolean") {
writer.write(value.toString());
await write(value.toString());
} else if (type === "object") {
const proto = Object.prototype.toString.call(value);
if (proto === "[object Object]" || proto === "[object Array]") {
const valueStr = JSON.stringify(value, null, 2);
require("assert").deepStrictEqual(value, JSON.parse(valueStr));
writer.write(valueStr);
await write(valueStr);
}
}
}

async function dumpResult() {
if (!process.stdout.isTTY) {
return;
}
if (!process.env["LLM_OUTPUT"]) {
async function dumpResult(name) {
if (!process.env["LLM_DUMP_RESULTS"] || !process.env["LLM_OUTPUT"] || !process.stdout.isTTY) {
return;
}
let showResult = false;
const agentName = process.env["LLM_AGENT_NAME"].toUpperCase().replace(/-/g, '_');
const agentEnvName = `LLM_AGENT_DUMP_RESULT_${agentName}`;
const agentEnvValue = process.env[agentEnvName] || process.env["LLM_AGENT_DUMP_RESULT"];

const funcName = process.env["LLM_AGENT_FUNC"].toUpperCase().replace(/-/g, '_');
const funcEnvName = `${agentEnvName}_${funcName}`;
const funcEnvValue = process.env[funcEnvName];
if (agentEnvValue === '1' || agentEnvValue === 'true') {
if (funcEnvValue !== '0' && funcEnvValue !== 'false') {
showResult = true;
}
} else {
if (funcEnvValue === '1' || funcEnvValue === 'true') {
try {
if (new RegExp(`\\b(${process.env["LLM_DUMP_RESULTS"]})\\b`).test(name)) {
showResult = true;
}
}
} catch { }

if (!showResult) {
return;
}
Expand Down
65 changes: 28 additions & 37 deletions scripts/run-agent.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env python

# Usage: ./run-agent.py <agent-name> <agent-func> <agent-data>

import os
import re
import json
import sys
import importlib.util
Expand All @@ -14,7 +17,7 @@ def main():
setup_env(root_dir, agent_name, agent_func)

agent_tools_path = os.path.join(root_dir, f"agents/{agent_name}/tools.py")
run(agent_tools_path, agent_func, agent_data)
run(agent_name, agent_tools_path, agent_func, agent_data)


def parse_raw_data(data):
Expand Down Expand Up @@ -90,7 +93,7 @@ def load_env(file_path):
os.environ.update(env_vars)


def run(agent_path, agent_func, agent_data):
def run(agent_name, agent_path, agent_func, agent_data):
try:
spec = importlib.util.spec_from_file_location(
os.path.basename(agent_path), agent_path
Expand All @@ -105,31 +108,37 @@ def run(agent_path, agent_func, agent_data):

value = getattr(mod, agent_func)(**agent_data)
return_to_llm(value)
dump_result()
dump_result(rf'{agent_name}:{agent_func}')


def dump_result():
if not os.isatty(1):
def return_to_llm(value):
if value is None:
return

if not os.getenv("LLM_OUTPUT"):
return
if "LLM_OUTPUT" in os.environ:
writer = open(os.environ["LLM_OUTPUT"], "w")
else:
writer = sys.stdout

show_result = False
agent_name = os.environ["LLM_AGENT_NAME"].upper().replace("-", "_")
agent_env_name = f"LLM_AGENT_DUMP_RESULT_{agent_name}"
agent_env_value = os.getenv(agent_env_name, os.getenv("LLM_AGENT_DUMP_RESULT"))
value_type = type(value).__name__
if value_type in ("str", "int", "float", "bool"):
writer.write(str(value))
elif value_type == "dict" or value_type == "list":
value_str = json.dumps(value, indent=2)
assert value == json.loads(value_str)
writer.write(value_str)

func_name = os.environ["LLM_AGENT_FUNC"].upper().replace("-", "_")
func_env_name = f"{agent_env_name}_{func_name}"
func_env_value = os.getenv(func_env_name)

if agent_env_value in ("1", "true"):
if func_env_value not in ("0", "false"):
show_result = True
else:
if func_env_value in ("1", "true"):
def dump_result(name):
if (not os.getenv("LLM_DUMP_RESULTS")) or (not os.getenv("LLM_OUTPUT")) or (not os.isatty(1)):
return

show_result = False
try:
if re.search(rf'\b({os.environ["LLM_DUMP_RESULTS"]})\b', name):
show_result = True
except:
pass

if not show_result:
return
Expand All @@ -143,23 +152,5 @@ def dump_result():
print(f"\x1b[2m----------------------\n{data}\n----------------------\x1b[0m")


def return_to_llm(value):
if value is None:
return

if "LLM_OUTPUT" in os.environ:
writer = open(os.environ["LLM_OUTPUT"], "w")
else:
writer = sys.stdout

value_type = type(value).__name__
if value_type in ("str", "int", "float", "bool"):
writer.write(str(value))
elif value_type == "dict" or value_type == "list":
value_str = json.dumps(value, indent=2)
assert value == json.loads(value_str)
writer.write(value_str)


if __name__ == "__main__":
main()
34 changes: 10 additions & 24 deletions scripts/run-agent.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env bash

# Usage: ./run-agent.sh <agent-name> <agent-func> <agent-data>

set -e

main() {
Expand Down Expand Up @@ -88,46 +91,29 @@ EOF
die "error: invalid JSON data"
}

no_llm_output=0
if [[ -z "$LLM_OUTPUT" ]]; then
no_llm_output=1
is_temp_llm_output=1
export LLM_OUTPUT="$(mktemp)"
fi
eval "'$tools_path' '$agent_func' $args"
if [[ "$no_llm_output" -eq 1 ]]; then
if [[ "$is_temp_llm_output" -eq 1 ]]; then
cat "$LLM_OUTPUT"
else
dump_result
dump_result "${LLM_AGENT_NAME}:${LLM_AGENT_FUNC}"
fi
}

dump_result() {
if [ ! -t 1 ]; then
if [[ "$LLM_OUTPUT" == "/dev/stdout" ]] || [[ -z "$LLM_DUMP_RESULTS" ]] || [[ ! -t 1 ]]; then
return;
fi

local agent_env_name agent_env_value func_env_name func_env_value show_result=0
agent_env_name="LLM_AGENT_DUMP_RESULT_$(echo "$LLM_AGENT_NAME" | tr '[:lower:]' '[:upper:]' | tr '-' '_')"
agent_env_value="${!agent_env_name:-"$LLM_AGENT_DUMP_RESULT"}"
func_env_name="${agent_env_name}_$(echo "$LLM_AGENT_FUNC" | tr '[:lower:]' '[:upper:]' | tr '-' '_')"
func_env_value="${!func_env_name}"
if [[ "$agent_env_value" == "1" || "$agent_env_value" == "true" ]]; then
if [[ "$func_env_value" != "0" && "$func_env_value" != "false" ]]; then
show_result=1
fi
else
if [[ "$func_env_value" == "1" || "$func_env_value" == "true" ]]; then
show_result=1
fi
fi
if [[ "$show_result" -ne 1 ]]; then
return
fi
cat <<EOF
if grep -q -w -E "$LLM_DUMP_RESULTS" <<<"$1"; then
cat <<EOF
$(echo -e "\e[2m")----------------------
$(cat "$LLM_OUTPUT")
----------------------$(echo -e "\e[0m")
EOF
fi
}

die() {
Expand Down
34 changes: 10 additions & 24 deletions scripts/run-mcp-tool.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env bash

# Usage: ./run-mcp-tool.sh <tool-name> <tool-data>

set -e

main() {
Expand Down Expand Up @@ -53,50 +56,33 @@ run() {
tool_data="$(echo "$tool_data" | sed 's/\\/\\\\/g')"
fi

no_llm_output=0
if [[ -z "$LLM_OUTPUT" ]]; then
no_llm_output=1
is_temp_llm_output=1
export LLM_OUTPUT="$(mktemp)"
fi
curl -sS "http://localhost:${MCP_BRIDGE_PORT:-8808}/tools/$tool_name" \
-X POST \
-H 'content-type: application/json' \
-d "$tool_data" > "$LLM_OUTPUT"

if [[ "$no_llm_output" -eq 1 ]]; then
if [[ "$is_temp_llm_output" -eq 1 ]]; then
cat "$LLM_OUTPUT"
else
dump_result
dump_result "$tool_name"
fi
}

dump_result() {
if [ ! -t 1 ]; then
if [[ "$LLM_OUTPUT" == "/dev/stdout" ]] || [[ -z "$LLM_DUMP_RESULTS" ]] || [[ ! -t 1 ]]; then
return;
fi

local agent_env_name agent_env_value func_env_name func_env_value show_result=0
agent_env_name="LLM_AGENT_DUMP_RESULT_$(echo "$LLM_AGENT_NAME" | tr '[:lower:]' '[:upper:]' | tr '-' '_')"
agent_env_value="${!agent_env_name:-"$LLM_AGENT_DUMP_RESULT"}"
func_env_name="${agent_env_name}_$(echo "$LLM_AGENT_FUNC" | tr '[:lower:]' '[:upper:]' | tr '-' '_')"
func_env_value="${!func_env_name}"
if [[ "$agent_env_value" == "1" || "$agent_env_value" == "true" ]]; then
if [[ "$func_env_value" != "0" && "$func_env_value" != "false" ]]; then
show_result=1
fi
else
if [[ "$func_env_value" == "1" || "$func_env_value" == "true" ]]; then
show_result=1
fi
fi
if [[ "$show_result" -ne 1 ]]; then
return
fi
cat <<EOF
if grep -q -w -E "$LLM_DUMP_RESULTS" <<<"$1"; then
cat <<EOF
$(echo -e "\e[2m")----------------------
$(cat "$LLM_OUTPUT")
----------------------$(echo -e "\e[0m")
EOF
fi
}

main "$@"
Loading
Loading