From 7a74eed86c78f1addebd58e7c6f2d6398e86c97e Mon Sep 17 00:00:00 2001 From: sigoden Date: Thu, 12 Dec 2024 11:48:36 +0800 Subject: [PATCH 1/3] feat: support env var `LLM_DUMP_RESULTS` --- Argcfile.sh | 2 +- docs/environment-variables.md | 20 +++++------ scripts/run-agent.js | 53 ++++++++++++---------------- scripts/run-agent.py | 65 +++++++++++++++-------------------- scripts/run-agent.sh | 37 +++++--------------- scripts/run-mcp-tool.sh | 37 +++++--------------- scripts/run-tool.js | 49 ++++++++++++-------------- scripts/run-tool.py | 29 +++++++--------- scripts/run-tool.sh | 35 +++++-------------- 9 files changed, 122 insertions(+), 205 deletions(-) diff --git a/Argcfile.sh b/Argcfile.sh index 9863c29..1d2eae3 100644 --- a/Argcfile.sh +++ b/Argcfile.sh @@ -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 diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 8c13b64..a3216b9 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -2,15 +2,15 @@ ## Injected by `run-tool.*`/`run-agent.*` -| Name | Description | -| --------------------- | -------------------------------------------------------------------------------------------------------------------- | -| `LLM_ROOT_DIR` | Path to `` | -| `LLM_TOOL_NAME` | Tool name, such as `execute_command` | -| `LLM_TOOL_CACHE_DIR` | Path to `/cache/`,
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 `/agents/` | -| `LLM_AGENT_CACHE_DIR` | Path to `/cache/`,
The tool script can use this directory to store some cache data | +| Name | Description | +| --------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `LLM_ROOT_DIR` | Path to `` | +| `LLM_TOOL_NAME` | Tool name, such as `execute_command` | +| `LLM_TOOL_CACHE_DIR` | Path to `/cache/`,
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 `/agents/` | +| `LLM_AGENT_CACHE_DIR` | Path to `/cache/`,
The agent tool script can use this directory to store some cache data | ## Injected by runtime (AIChat) @@ -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:.*`, `.*` | diff --git a/scripts/run-agent.js b/scripts/run-agent.js index 44cc39f..6a14990 100755 --- a/scripts/run-agent.js +++ b/scripts/run-agent.js @@ -1,8 +1,9 @@ #!/usr/bin/env node +// Usage: ./run-agent.js + 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() { @@ -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) { @@ -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}`; @@ -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; } diff --git a/scripts/run-agent.py b/scripts/run-agent.py index c58612a..9367ea5 100755 --- a/scripts/run-agent.py +++ b/scripts/run-agent.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +# Usage: ./run-agent.py + import os +import re import json import sys import importlib.util @@ -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): @@ -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 @@ -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 @@ -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() \ No newline at end of file diff --git a/scripts/run-agent.sh b/scripts/run-agent.sh index d7f9a20..b5973e6 100755 --- a/scripts/run-agent.sh +++ b/scripts/run-agent.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash + +# Usage: ./run-agent.sh + set -e main() { @@ -88,46 +91,24 @@ EOF die "error: invalid JSON data" } - no_llm_output=0 if [[ -z "$LLM_OUTPUT" ]]; then - no_llm_output=1 - export LLM_OUTPUT="$(mktemp)" + export LLM_OUTPUT="/dev/stdout" fi eval "'$tools_path' '$agent_func' $args" - if [[ "$no_llm_output" -eq 1 ]]; then - cat "$LLM_OUTPUT" - else - dump_result - fi + dump_result "${LLM_AGENT_NAME}:${LLM_AGENT_FUNC}" } 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 < + set -e main() { @@ -53,50 +56,28 @@ run() { tool_data="$(echo "$tool_data" | sed 's/\\/\\\\/g')" fi - no_llm_output=0 if [[ -z "$LLM_OUTPUT" ]]; then - no_llm_output=1 - export LLM_OUTPUT="$(mktemp)" + export LLM_OUTPUT="/dev/stdout" 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 - cat "$LLM_OUTPUT" - else - dump_result - fi + dump_result "$tool_name" } 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 < + 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() { @@ -13,7 +14,7 @@ async function main() { await setupEnv(rootDir, toolName); const toolPath = path.resolve(rootDir, `tools/${toolName}.js`); - await run(toolPath, "run", toolData); + await run(toolName, toolPath, "run", toolData); } function parseArgv(thisFileName) { @@ -91,7 +92,7 @@ async function loadEnv(filePath) { } } -async function run(toolPath, toolFunc, toolData) { +async function run(toolName, toolPath, toolFunc, toolData) { let mod; if (os.platform() === "win32") { toolPath = `file://${toolPath}`; @@ -105,51 +106,45 @@ async function run(toolPath, toolFunc, toolData) { throw new Error(`Not module function '${toolFunc}' at '${toolPath}'`); } const value = await mod[toolFunc](toolData); - returnToLLM(value); - await dumpResult(); + await returnToLLM(value); + await dumpResult(toolName); } -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 toolName = process.env["LLM_TOOL_NAME"].toUpperCase().replace(/-/g, '_'); - const envName = `LLM_TOOL_DUMP_RESULT_${toolName}`; - const envValue = process.env[envName]; - if (process.env.LLM_TOOL_DUMP_RESULT === '1' || process.env.LLM_TOOL_DUMP_RESULT === 'true') { - if (envValue !== '0' && envValue !== 'false') { - showResult = true; - } - } else { - if (envValue === '1' || envValue === 'true') { + try { + if (new RegExp(`\\b(${process.env["LLM_DUMP_RESULTS"]})\\b`).test(name)) { showResult = true; } - } + } catch { } + if (!showResult) { return; } diff --git a/scripts/run-tool.py b/scripts/run-tool.py index a64ce0e..f0f2917 100755 --- a/scripts/run-tool.py +++ b/scripts/run-tool.py @@ -1,6 +1,9 @@ #!/usr/bin/env python +# Usage: ./run-tool.py + import os +import re import json import sys import importlib.util @@ -14,7 +17,7 @@ def main(): setup_env(root_dir, tool_name) tool_path = os.path.join(root_dir, f"tools/{tool_name}.py") - run(tool_path, "run", tool_data) + run(tool_name, tool_path, "run", tool_data) def parse_raw_data(data): @@ -85,7 +88,7 @@ def load_env(file_path): os.environ.update(env_vars) -def run(tool_path, tool_func, tool_data): +def run(tool_name, tool_path, tool_func, tool_data): try: spec = importlib.util.spec_from_file_location( os.path.basename(tool_path), tool_path @@ -100,7 +103,7 @@ def run(tool_path, tool_func, tool_data): value = getattr(mod, tool_func)(**tool_data) return_to_llm(value) - dump_result() + dump_result(tool_name) def return_to_llm(value): @@ -121,24 +124,16 @@ def return_to_llm(value): writer.write(value_str) -def dump_result(): - if not os.isatty(1): - return - - if not os.getenv("LLM_OUTPUT"): +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 - tool_name = os.environ["LLM_TOOL_NAME"].upper().replace("-", "_") - env_name = f"LLM_TOOL_DUMP_RESULT_{tool_name}" - env_value = os.getenv(env_name) - - if os.getenv("LLM_TOOL_DUMP_RESULT") in ("1", "true"): - if env_value not in ("0", "false"): - show_result = True - else: - if env_value in ("1", "true"): + try: + if re.search(rf'\b({os.environ["LLM_DUMP_RESULTS"]})\b', name): show_result = True + except: + pass if not show_result: return diff --git a/scripts/run-tool.sh b/scripts/run-tool.sh index 1662a26..7cb2dee 100755 --- a/scripts/run-tool.sh +++ b/scripts/run-tool.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash + +# Usage: ./run-tool.sh + set -e main() { @@ -83,44 +86,24 @@ EOF args="$(echo "$tool_data" | jq -r "$jq_script" 2>/dev/null)" || { die "error: invalid JSON data" } - - no_llm_output=0 if [[ -z "$LLM_OUTPUT" ]]; then - no_llm_output=1 - export LLM_OUTPUT="$(mktemp)" + export LLM_OUTPUT="/dev/stdout" fi eval "'$tool_path' $args" - if [[ "$no_llm_output" -eq 1 ]]; then - cat "$LLM_OUTPUT" - else - dump_result - fi + dump_result "$tool_name" } dump_result() { - if [ ! -t 1 ]; then + if [[ "$LLM_OUTPUT" == "/dev/stdout" ]] || [[ -z "$LLM_DUMP_RESULTS" ]] || [[ ! -t 1 ]]; then return; fi - local env_name env_value show_result=0 - env_name="LLM_TOOL_DUMP_RESULT_$(echo "$LLM_TOOL_NAME" | tr '[:lower:]' '[:upper:]' | tr '-' '_')" - env_value="${!env_name}" - if [[ "$LLM_TOOL_DUMP_RESULT" == "1" || "$LLM_TOOL_DUMP_RESULT" == "true" ]]; then - if [[ "$env_value" != "0" && "$env_value" != "false" ]]; then - show_result=1 - fi - else - if [[ "$env_value" == "1" || "$env_value" == "true" ]]; then - show_result=1 - fi - fi - if [[ "$show_result" -ne 1 ]]; then - return - fi - cat < Date: Thu, 12 Dec 2024 12:02:19 +0800 Subject: [PATCH 2/3] update --- Argcfile.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Argcfile.sh b/Argcfile.sh index 1d2eae3..c124434 100644 --- a/Argcfile.sh +++ b/Argcfile.sh @@ -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" } @@ -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" } From cfd83fcef75cedbb2f192754a6de7e7fee687c68 Mon Sep 17 00:00:00 2001 From: sigoden Date: Thu, 12 Dec 2024 12:20:54 +0800 Subject: [PATCH 3/3] update --- scripts/run-agent.sh | 9 +++++++-- scripts/run-mcp-tool.sh | 9 +++++++-- scripts/run-tool.sh | 9 +++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/scripts/run-agent.sh b/scripts/run-agent.sh index b5973e6..b832577 100755 --- a/scripts/run-agent.sh +++ b/scripts/run-agent.sh @@ -92,10 +92,15 @@ EOF } if [[ -z "$LLM_OUTPUT" ]]; then - export LLM_OUTPUT="/dev/stdout" + is_temp_llm_output=1 + export LLM_OUTPUT="$(mktemp)" fi eval "'$tools_path' '$agent_func' $args" - dump_result "${LLM_AGENT_NAME}:${LLM_AGENT_FUNC}" + if [[ "$is_temp_llm_output" -eq 1 ]]; then + cat "$LLM_OUTPUT" + else + dump_result "${LLM_AGENT_NAME}:${LLM_AGENT_FUNC}" + fi } dump_result() { diff --git a/scripts/run-mcp-tool.sh b/scripts/run-mcp-tool.sh index f2c2023..08beafd 100755 --- a/scripts/run-mcp-tool.sh +++ b/scripts/run-mcp-tool.sh @@ -57,14 +57,19 @@ run() { fi if [[ -z "$LLM_OUTPUT" ]]; then - export LLM_OUTPUT="/dev/stdout" + 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" - dump_result "$tool_name" + if [[ "$is_temp_llm_output" -eq 1 ]]; then + cat "$LLM_OUTPUT" + else + dump_result "$tool_name" + fi } dump_result() { diff --git a/scripts/run-tool.sh b/scripts/run-tool.sh index 7cb2dee..50f8597 100755 --- a/scripts/run-tool.sh +++ b/scripts/run-tool.sh @@ -87,10 +87,15 @@ EOF die "error: invalid JSON data" } if [[ -z "$LLM_OUTPUT" ]]; then - export LLM_OUTPUT="/dev/stdout" + is_temp_llm_output=1 + export LLM_OUTPUT="$(mktemp)" fi eval "'$tool_path' $args" - dump_result "$tool_name" + if [[ "$is_temp_llm_output" -eq 1 ]]; then + cat "$LLM_OUTPUT" + else + dump_result "$tool_name" + fi } dump_result() {