From 02e335c99526fe52dee0d0a016aee6bf62d874c2 Mon Sep 17 00:00:00 2001 From: sigoden Date: Tue, 9 Jul 2024 21:17:12 +0800 Subject: refactor: demo tools/agents (#67) --- Argcfile.sh | 51 ++++++++++++++++++++------------------------------ README.md | 2 +- agents/demo/README.md | 44 +++++++++++++++++++++++++++++++++++++++++++ agents/demo/index.yaml | 17 +++++++++++++++++ agents/demo/tools.js | 9 +++++++++ agents/demo/tools.py | 12 ++++++++++++ agents/demo/tools.sh | 12 ++++++++++++ agents/demo/tools.txt | 1 + tools/demo_js.js | 24 ++++++++++++++++++++++++ tools/demo_py.py | 30 +++++++++++++++++++++++++++++ tools/demo_sh.sh | 16 ++++++++++++++++ tools/demo_tool.js | 24 ------------------------ tools/demo_tool.py | 30 ----------------------------- tools/demo_tool.sh | 16 ---------------- 14 files changed, 186 insertions(+), 102 deletions(-) create mode 100644 agents/demo/README.md create mode 100644 agents/demo/index.yaml create mode 100644 agents/demo/tools.js create mode 100644 agents/demo/tools.py create mode 100755 agents/demo/tools.sh create mode 100644 agents/demo/tools.txt create mode 100644 tools/demo_js.js create mode 100644 tools/demo_py.py create mode 100755 tools/demo_sh.sh delete mode 100644 tools/demo_tool.js delete mode 100644 tools/demo_tool.py delete mode 100755 tools/demo_tool.sh diff --git a/Argcfile.sh b/Argcfile.sh index 72b9894..5a9fcce 100644 --- a/Argcfile.sh +++ b/Argcfile.sh @@ -289,7 +289,7 @@ build-declarations@agent() { fi if [[ "$ok" == "true" ]]; then if [[ -n "$agent_json_data" ]] && [[ -n "$tools_json_data" ]]; then - json_data="$(jq -s '.[0] + .[1]' <(echo "$agent_json_data") <(echo "$tools_json_data"))" + json_data="$(echo "[$agent_json_data,$tools_json_data]" | jq 'flatten')" elif [[ -n "$agent_json_data" ]]; then json_data="$agent_json_data" elif [[ -n "$tools_json_data" ]]; then @@ -397,9 +397,10 @@ test-execute-code-tools() { test-demo-tools() { for item in "${LANG_CMDS[@]}"; do lang="${item%:*}" - echo "---- Test demo_tool.$lang ---" - argc build-bin@tool "demo_tool.$lang" - argc run@tool demo_tool '{ + tool="demo_$lang.$lang" + echo "---- Test $tool ---" + argc build-bin@tool "$tool" + argc run@tool $tool '{ "boolean": true, "string": "Hello", "string_enum": "foo", @@ -428,37 +429,24 @@ test@agent() { names_file="$tmp_dir/agents.txt" argc list@agent > "$names_file" argc build@agent --names-file "$names_file" - test-todo-agents + test-demo-agents } -# @cmd Test todo-* agents -# @alias agent:test-todo -test-todo-agents() { - if _is_win; then - ext=".cmd" - fi - test_cases=( \ - 'add_todo#{"desc":"Add a todo item"}' \ - 'add_todo#{"desc":"Add another todo item"}' \ - 'del_todo#{"id":1}' \ - 'list_todos#{}' \ - 'clear_todos#{}' \ - ) +# @cmd Test demo agents +# @alias agent:test-demo +test-demo-agents() { + echo "Test demo agent:" + argc run@agent demo get_sysinfo '{}' for item in "${LANG_CMDS[@]}"; do cmd="${item#*:}" - if command -v "$cmd" &> /dev/null; then - lang="${item%:*}" - agent_name="todo-$lang" - rm -rf "cache/$agent_name/todos.json" - for test_case in "${test_cases[@]}"; do - IFS='#' read -r action data <<<"${test_case}" - cmd_path="$BIN_DIR/$agent_name$ext" - echo "Test $cmd_path: " - "$cmd_path" "$action" "$data" - done + lang="${item%:*}" + echo "Test agents/demo/tools.$lang:" + if [[ "$cmd" == "sh" ]]; then + "$(argc --argc-shell-path)" ./scripts/run-agent.sh demo get_sysinfo '{}' + elif command -v "$cmd" &> /dev/null; then + $cmd ./scripts/run-agent.$lang demo get_sysinfo '{}' fi done - } # @cmd Clean tools @@ -475,7 +463,7 @@ clean@agent() { _choice_agent | xargs -I{} rm -rf agents/{}/functions.json } -# @cmd Symlink web_search tool +# @cmd Link a tool as web_search tool # # Example: # argc link-web-search search_bing.sh @@ -484,7 +472,7 @@ link-web-search() { _link_tool $1 web_search } -# @cmd Symlink code_interpreter tool +# @cmd Link a tool as code_interpreter tool # # Example: # argc link-code-interpreter execute_py_code.py @@ -550,6 +538,7 @@ _get_agent_tools_path() { entry_file="agents/$name/tools.$lang" if [[ -f "agents/$name/tools.$lang" ]]; then echo "$entry_file" + break fi done } diff --git a/README.md b/README.md index 10a6656..cccf5f5 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ The agent definition file (`index.yaml`) defines crucial aspects of your agent: ```yaml name: TestAgent description: This is test agent -version: v0.1.0 +version: 0.1.0 instructions: You are a test ai agent to ... conversation_starters: - What can you do? diff --git a/agents/demo/README.md b/agents/demo/README.md new file mode 100644 index 0000000..888b236 --- /dev/null +++ b/agents/demo/README.md @@ -0,0 +1,44 @@ +# Demo + +This is demo agent. + +## tools.{sh,js,py} + +You only need one of the `tools.sh`, `tools.js`, or `tools.py` files. All three are provided so that everyone can understand how to implement the tools in each language. + +## tools.txt + +The `tools.txt` is used to reuse the tools in the `tools/` directory. + +## index.yaml + +This document is essential as it defines the agent. + +### variables + +Variables are generally used to record a certain behavior or preference of a user. + +```yaml +variables: + - name: foo + description: This is a foo + - name: bar + description: This is a bar with default value + default: val +``` + +Variables can be used in the `instructions`. + +```yaml +instructions: | + The instructions can inline {{foo}} and {{bar}} variables. +``` + +### documents + +Documents are used for RAG. + +```yaml +documents: + - https://raw.githubusercontent.com/sigoden/llm-functions/main/README.md +``` \ No newline at end of file diff --git a/agents/demo/index.yaml b/agents/demo/index.yaml new file mode 100644 index 0000000..44cd616 --- /dev/null +++ b/agents/demo/index.yaml @@ -0,0 +1,17 @@ +name: Demo +description: This is demo agent. +version: 0.1.0 +instructions: | + You are a AI agent designed to demonstrate agent capabilities. + Use prefer language {{lang}} to answer the question, regardless of the input language. + When the user asks for the system info, retrieve it by running the get_sysinfo tool. + When the user asks for the current time, retrieve it by using the get_current_time tool. +variables: + - name: lang + description: Your prefer language +conversation_starters: + - What is the prefer language + - Show me the system info + - Tell me the current time +documents: + - https://raw.githubusercontent.com/sigoden/llm-functions/main/README.md \ No newline at end of file diff --git a/agents/demo/tools.js b/agents/demo/tools.js new file mode 100644 index 0000000..37f8937 --- /dev/null +++ b/agents/demo/tools.js @@ -0,0 +1,9 @@ +const os = require("node:os"); +/** + * Get the system info + */ +exports.get_sysinfo = function getSysinfo() { + return `OS: ${os.type()} +Arch: ${os.arch()} +User: ${process.env["USER"]}` +} diff --git a/agents/demo/tools.py b/agents/demo/tools.py new file mode 100644 index 0000000..5f1a4fc --- /dev/null +++ b/agents/demo/tools.py @@ -0,0 +1,12 @@ +import os +import platform + +def get_sysinfo(): + """ + Get the system info + """ + return "\n".join([ + f"OS: {platform.system()}", + f"Arch: {platform.machine()}", + f"User: {os.environ.get('USER')}" + ]) \ No newline at end of file diff --git a/agents/demo/tools.sh b/agents/demo/tools.sh new file mode 100755 index 0000000..4b5849b --- /dev/null +++ b/agents/demo/tools.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e + +# @cmd Get the system info +get_sysinfo() { + echo "OS: $(uname)" + echo "Arch: $(arch)" + echo "User: $USER" +} + +# See more details at https://github.com/sigoden/argc +eval "$(argc --argc-eval "$0" "$@")" diff --git a/agents/demo/tools.txt b/agents/demo/tools.txt new file mode 100644 index 0000000..35fdac3 --- /dev/null +++ b/agents/demo/tools.txt @@ -0,0 +1 @@ +get_current_time.sh \ No newline at end of file diff --git a/tools/demo_js.js b/tools/demo_js.js new file mode 100644 index 0000000..c8b7237 --- /dev/null +++ b/tools/demo_js.js @@ -0,0 +1,24 @@ +/** + * Demonstrate how to create a tool using Javascript and how to use comments. + * @typedef {Object} Args + * @property {string} string - Define a required string property + * @property {'foo'|'bar'} string_enum - Define a required string property with enum + * @property {string} [string_optional] - Define a optional string property + * @property {boolean} boolean - Define a required boolean property + * @property {Integer} integer - Define a required integer property + * @property {number} number - Define a required number property + * @property {string[]} array - Define a required string array property + * @property {string[]} [array_optional] - Define a optional string array property + * @param {Args} args + */ +exports.run = function run(args) { + for (const [key, value] of Object.entries(args)) { + console.log(`${key}: ${JSON.stringify(value)}`); + } + + for (const [key, value] of Object.entries(process.env)) { + if (key.startsWith("LLM_")) { + console.log(`${key}: ${value}`); + } + } +} diff --git a/tools/demo_py.py b/tools/demo_py.py new file mode 100644 index 0000000..d53cd0b --- /dev/null +++ b/tools/demo_py.py @@ -0,0 +1,30 @@ +import os +from typing import List, Literal, Optional + +def run( + boolean: bool, + string: str, + string_enum: Literal["foo", "bar"], + integer: int, + number: float, + array: List[str], + string_optional: Optional[str] = None, + array_optional: Optional[List[str]] = None, +) -> None: + """Demonstrate how to create a tool using Python and how to use comments. + Args: + boolean: Define a required boolean property + string: Define a required string property + string_enum: Define a required string property with enum + integer: Define a required integer property + number: Define a required number property + array: Define a required string array property + string_optional: Define a optional string property + array_optional: Define a optional string array property + """ + for key, value in locals().items(): + print(f"{key}: {value}") + + for key, value in os.environ.items(): + if key.startswith("LLM_"): + print(f"{key}: {value}") \ No newline at end of file diff --git a/tools/demo_sh.sh b/tools/demo_sh.sh new file mode 100755 index 0000000..da35e8f --- /dev/null +++ b/tools/demo_sh.sh @@ -0,0 +1,16 @@ +# @describe Demonstrate how to create a tool using Bash and how to use comment tags. +# @option --string! Define a required string property +# @option --string-enum![foo|bar] Define a required string property with enum +# @option --string-optional Define a optional string property +# @flag --boolean Define a boolean property +# @option --integer! Define a required integer property +# @option --number! Define a required number property +# @option --array+ Define a required string array property +# @option --array-optional* Define a optional string array property + +main() { + ( set -o posix ; set ) | grep ^argc_ + printenv | grep '^LLM_' +} + +eval "$(argc --argc-eval "$0" "$@")" \ No newline at end of file diff --git a/tools/demo_tool.js b/tools/demo_tool.js deleted file mode 100644 index c8b7237..0000000 --- a/tools/demo_tool.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Demonstrate how to create a tool using Javascript and how to use comments. - * @typedef {Object} Args - * @property {string} string - Define a required string property - * @property {'foo'|'bar'} string_enum - Define a required string property with enum - * @property {string} [string_optional] - Define a optional string property - * @property {boolean} boolean - Define a required boolean property - * @property {Integer} integer - Define a required integer property - * @property {number} number - Define a required number property - * @property {string[]} array - Define a required string array property - * @property {string[]} [array_optional] - Define a optional string array property - * @param {Args} args - */ -exports.run = function run(args) { - for (const [key, value] of Object.entries(args)) { - console.log(`${key}: ${JSON.stringify(value)}`); - } - - for (const [key, value] of Object.entries(process.env)) { - if (key.startsWith("LLM_")) { - console.log(`${key}: ${value}`); - } - } -} diff --git a/tools/demo_tool.py b/tools/demo_tool.py deleted file mode 100644 index d53cd0b..0000000 --- a/tools/demo_tool.py +++ /dev/null @@ -1,30 +0,0 @@ -import os -from typing import List, Literal, Optional - -def run( - boolean: bool, - string: str, - string_enum: Literal["foo", "bar"], - integer: int, - number: float, - array: List[str], - string_optional: Optional[str] = None, - array_optional: Optional[List[str]] = None, -) -> None: - """Demonstrate how to create a tool using Python and how to use comments. - Args: - boolean: Define a required boolean property - string: Define a required string property - string_enum: Define a required string property with enum - integer: Define a required integer property - number: Define a required number property - array: Define a required string array property - string_optional: Define a optional string property - array_optional: Define a optional string array property - """ - for key, value in locals().items(): - print(f"{key}: {value}") - - for key, value in os.environ.items(): - if key.startswith("LLM_"): - print(f"{key}: {value}") \ No newline at end of file diff --git a/tools/demo_tool.sh b/tools/demo_tool.sh deleted file mode 100755 index da35e8f..0000000 --- a/tools/demo_tool.sh +++ /dev/null @@ -1,16 +0,0 @@ -# @describe Demonstrate how to create a tool using Bash and how to use comment tags. -# @option --string! Define a required string property -# @option --string-enum![foo|bar] Define a required string property with enum -# @option --string-optional Define a optional string property -# @flag --boolean Define a boolean property -# @option --integer! Define a required integer property -# @option --number! Define a required number property -# @option --array+ Define a required string array property -# @option --array-optional* Define a optional string array property - -main() { - ( set -o posix ; set ) | grep ^argc_ - printenv | grep '^LLM_' -} - -eval "$(argc --argc-eval "$0" "$@")" \ No newline at end of file -- cgit v1.2.3