aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/declarations-util.sh4
-rwxr-xr-xscripts/run-bot.js107
-rwxr-xr-xscripts/run-bot.py105
-rwxr-xr-xscripts/run-bot.sh80
4 files changed, 294 insertions, 2 deletions
diff --git a/scripts/declarations-util.sh b/scripts/declarations-util.sh
index 2a0929d..7646500 100755
--- a/scripts/declarations-util.sh
+++ b/scripts/declarations-util.sh
@@ -15,8 +15,8 @@ pretty-print() {
# @cmd Generate placeholder json according to declarations
# Examples:
-# ./scripts/declarations.sh generate-json-data functions.json
-# cat functions.json | ./scripts/declarations.sh generate-json-data functions.json
+# ./scripts/declarations.sh generate-json functions.json
+# cat functions.json | ./scripts/declarations.sh generate-json functions.json
# @arg json-file The json file, Read stdin if omitted
generate-json() {
_run _generate_json
diff --git a/scripts/run-bot.js b/scripts/run-bot.js
new file mode 100755
index 0000000..7a5b70c
--- /dev/null
+++ b/scripts/run-bot.js
@@ -0,0 +1,107 @@
+#!/usr/bin/env node
+
+const path = require("path");
+const fs = require("fs");
+const os = require("os");
+
+async function main() {
+ const [botName, botFunc, rawData] = parseArgv("run-bot.js");
+ const botData = parseRawData(rawData);
+
+ const rootDir = path.resolve(__dirname, "..");
+ setupEnv(rootDir, botName);
+
+ const botToolsPath = path.resolve(rootDir, `bots/${botName}/tools.js`);
+ await run(botToolsPath, botFunc, botData);
+}
+
+function parseArgv(thisFileName) {
+ let botName = process.argv[1];
+ let botFunc = "";
+ let botData = null;
+
+ if (botName.endsWith(thisFileName)) {
+ botName = process.argv[2];
+ botFunc = process.argv[3];
+ botData = process.argv[4];
+ } else {
+ botName = path.basename(botName);
+ botFunc = process.argv[2];
+ botData = process.argv[3];
+ }
+
+ if (botName.endsWith(".js")) {
+ botName = botName.slice(0, -3);
+ }
+
+ return [botName, botFunc, botData];
+}
+
+function parseRawData(data) {
+ if (!data) {
+ throw new Error("No JSON data");
+ }
+ try {
+ return JSON.parse(data);
+ } catch {
+ throw new Error("Invalid JSON data");
+ }
+}
+
+function setupEnv(rootDir, botName) {
+ process.env["LLM_ROOT_DIR"] = rootDir;
+ loadEnv(path.resolve(rootDir, ".env"));
+ process.env["LLM_BOT_NAME"] = botName;
+ process.env["LLM_BOT_ROOT_DIR"] = path.resolve(rootDir, "bots", botName);
+ process.env["LLM_BOT_CACHE_DIR"] = path.resolve(rootDir, "cache", botName);
+}
+
+function loadEnv(filePath) {
+ try {
+ const data = fs.readFileSync(filePath, "utf-8");
+ const lines = data.split("\n");
+
+ lines.forEach((line) => {
+ if (line.trim().startsWith("#") || line.trim() === "") return;
+
+ const [key, ...value] = line.split("=");
+ process.env[key.trim()] = value.join("=").trim();
+ });
+ } catch {}
+}
+
+async function run(botPath, botFunc, botData) {
+ let mod;
+ if (os.platform() === "win32") {
+ botPath = `file://${botPath}`;
+ }
+ try {
+ mod = await import(botPath);
+ } catch {
+ throw new Error(`Unable to load bot tools at '${botPath}'`);
+ }
+ if (!mod || !mod[botFunc]) {
+ throw new Error(`Not module function '${botFunc}' at '${botPath}'`);
+ }
+ const value = await mod[botFunc](botData);
+ dumpValue(value);
+}
+
+function dumpValue(value) {
+ if (value === null || value === undefined) {
+ return;
+ }
+ const type = typeof value;
+ if (type === "string" || type === "number" || type === "boolean") {
+ console.log(value);
+ } 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));
+ console.log(valueStr);
+ }
+ }
+}
+
+main();
diff --git a/scripts/run-bot.py b/scripts/run-bot.py
new file mode 100755
index 0000000..d7c7ae1
--- /dev/null
+++ b/scripts/run-bot.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+import os
+import json
+import sys
+import importlib.util
+
+
+def main():
+ (bot_name, bot_func, raw_data) = parse_argv("run-bot.py")
+ bot_data = parse_raw_data(raw_data)
+
+ root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
+ setup_env(root_dir, bot_name)
+
+ bot_tools_path = os.path.join(root_dir, f"bots/{bot_name}/tools.py")
+ run(bot_tools_path, bot_func, bot_data)
+
+
+def parse_raw_data(data):
+ if not data:
+ raise ValueError("No JSON data")
+
+ try:
+ return json.loads(data)
+ except Exception:
+ raise ValueError("Invalid JSON data")
+
+
+def parse_argv(this_file_name):
+ argv = sys.argv[:] + [None] * max(0, 4 - len(sys.argv))
+
+ bot_name = argv[0]
+ bot_func = ""
+ bot_data = None
+
+ if bot_name.endswith(this_file_name):
+ bot_name = sys.argv[1]
+ bot_func = sys.argv[2]
+ bot_data = sys.argv[3]
+ else:
+ bot_name = os.path.basename(bot_name)
+ bot_func = sys.argv[1]
+ bot_data = sys.argv[2]
+
+ if bot_name.endswith(".py"):
+ bot_name = bot_name[:-3]
+
+ return bot_name, bot_func, bot_data
+
+
+def setup_env(root_dir, bot_name):
+ os.environ["LLM_ROOT_DIR"] = root_dir
+ load_env(os.path.join(root_dir, ".env"))
+ os.environ["LLM_BOT_NAME"] = bot_name
+ os.environ["LLM_BOT_ROOT_DIR"] = os.path.join(root_dir, "bots", bot_name)
+ os.environ["LLM_BOT_CACHE_DIR"] = os.path.join(root_dir, "cache", bot_name)
+
+
+def load_env(file_path):
+ try:
+ with open(file_path, "r") as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("#") or line == "":
+ continue
+
+ key, *value = line.split("=")
+ os.environ[key.strip()] = "=".join(value).strip()
+ except FileNotFoundError:
+ pass
+
+
+def run(bot_path, bot_func, bot_data):
+ try:
+ spec = importlib.util.spec_from_file_location(
+ os.path.basename(bot_path), bot_path
+ )
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+ except:
+ raise Exception(f"Unable to load bot tools at '{bot_path}'")
+
+ if not hasattr(mod, bot_func):
+ raise Exception(f"Not module function '{bot_func}' at '{bot_path}'")
+
+ value = getattr(mod, bot_func)(**bot_data)
+ dump_value(value)
+
+
+def dump_value(value):
+ if value is None:
+ return
+
+ value_type = type(value).__name__
+ if value_type in ("str", "int", "float", "bool"):
+ print(value)
+ elif value_type == "dict" or value_type == "list":
+ value_str = json.dumps(value, indent=2)
+ assert value == json.loads(value_str)
+ print(value_str)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/run-bot.sh b/scripts/run-bot.sh
new file mode 100755
index 0000000..a709453
--- /dev/null
+++ b/scripts/run-bot.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+set -e
+
+main() {
+ this_file_name=run-bot.sh
+ parse_argv "$@"
+ root_dir="$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )/.." &> /dev/null && pwd)"
+ setup_env
+ bot_tools_path="$root_dir/bots/$bot_name/tools.sh"
+ run
+}
+
+parse_argv() {
+ if [[ "$0" == *"$this_file_name" ]]; then
+ bot_name="$1"
+ bot_func="$2"
+ bot_data="$3"
+ else
+ bot_name="$(basename "$0")"
+ bot_func="$1"
+ bot_data="$2"
+ fi
+ if [[ "$bot_name" == *.sh ]]; then
+ bot_name="${bot_name:0:$((${#bot_name}-3))}"
+ fi
+}
+
+setup_env() {
+ export LLM_ROOT_DIR="$root_dir"
+ if [[ -f "$LLM_ROOT_DIR/.env" ]]; then
+ source "$LLM_ROOT_DIR/.env"
+ fi
+ export LLM_BOT_NAME="$bot_name"
+ export LLM_BOT_ROOT_DIR="$LLM_ROOT_DIR/bots/$bot_name"
+ export LLM_BOT_CACHE_DIR="$LLM_ROOT_DIR/cache/$bot_name"
+}
+
+run() {
+ if [[ -z "$bot_data" ]]; then
+ die "No JSON data"
+ fi
+
+ _jq=jq
+ if [[ "$OS" == "Windows_NT" ]]; then
+ _jq="jq -b"
+ bot_tools_path="$(cygpath -w "$bot_tools_path")"
+ fi
+
+ data="$(
+ echo "$bot_data" | \
+ $_jq -r '
+ to_entries | .[] |
+ (.key | split("_") | join("-")) as $key |
+ if .value | type == "array" then
+ .value | .[] | "--\($key)\n\(. | @json)"
+ elif .value | type == "boolean" then
+ if .value then "--\($key)" else "" end
+ else
+ "--\($key)\n\(.value | @json)"
+ end'
+ )" || {
+ die "Invalid JSON data"
+ }
+ while IFS= read -r line; do
+ if [[ "$line" == '--'* ]]; then
+ args+=("$line")
+ else
+ args+=("$(echo "$line" | $_jq -r '.')")
+ fi
+ done <<< "$data"
+ "$bot_tools_path" "$bot_func" "${args[@]}"
+}
+
+die() {
+ echo "$*" >&2
+ exit 1
+}
+
+main "$@"
+