From 21a3c90a1c73c33552637ce1079c7171bd104e2f Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Thu, 3 Oct 2024 22:20:34 +0100 Subject: [PATCH] `agent`: tool tweaks (remove ansi escapes from python output, update env keys + provider docs) --- examples/agent/README.md | 8 +++++--- examples/agent/run.py | 10 +++++----- examples/agent/serve_tools.py | 1 + examples/agent/serve_tools_inside_docker.sh | 8 +++++++- examples/agent/tools/fetch.py | 4 ++-- examples/agent/tools/python.py | 16 ++++++++++++---- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/examples/agent/README.md b/examples/agent/README.md index 575fdeaff..aa04f0a96 100644 --- a/examples/agent/README.md +++ b/examples/agent/README.md @@ -39,6 +39,7 @@ - Run the tools in [examples/agent/tools](./examples/agent/tools) inside a docker container (check http://localhost:8088/docs once running): ```bash + export BRAVE_SEARCH_API_KEY=... # https://api.search.brave.com/ # Shorthand: ./examples/agent/serve_tools_inside_docker.sh docker run -p 8088:8088 -w /src -v $PWD/examples/agent:/src \ --env BRAVE_SEARCH_API_KEY=$BRAVE_SEARCH_API_KEY \ @@ -103,9 +104,10 @@ - To compare the above results w/ a cloud provider's tool usage behaviour, just set the `--provider` flag (accepts `openai`, `together`, `groq`) and/or use `--endpoint`, `--api-key`, and `--model` ```bash - export OPENAI_API_KEY=... # for --provider=openai - # export TOGETHER_API_KEY=... # for --provider=together - # export GROQ_API_KEY=... # for --provider=groq + export LLAMA_API_KEY=... # for --provider=llama.cpp https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md + export OPENAI_API_KEY=... # for --provider=openai https://platform.openai.com/api-keys + export TOGETHER_API_KEY=... # for --provider=together https://api.together.ai/settings/api-keys + export GROQ_API_KEY=... # for --provider=groq https://console.groq.com/keys uv run examples/agent/run.py --tools http://localhost:8088 \ "Search for, fetch and summarize the homepage of llama.cpp" \ --provider=openai diff --git a/examples/agent/run.py b/examples/agent/run.py index 796d40996..c89bf3b16 100644 --- a/examples/agent/run.py +++ b/examples/agent/run.py @@ -146,22 +146,22 @@ def typer_async_workaround(): _PROVIDERS = { 'llama.cpp': { 'endpoint': 'http://localhost:8080/v1/', - 'api_key_env': 'LLAMACPP_API_KEY', + 'api_key_env': 'LLAMA_API_KEY', # https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md }, 'openai': { 'endpoint': 'https://api.openai.com/v1/', 'default_model': 'gpt-4o', - 'api_key_env': 'OPENAI_API_KEY', + 'api_key_env': 'OPENAI_API_KEY', # https://platform.openai.com/api-keys }, 'together': { 'endpoint': 'https://api.together.xyz', 'default_model': 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo', - 'api_key_env': 'TOGETHER_API_KEY', + 'api_key_env': 'TOGETHER_API_KEY', # https://api.together.ai/settings/api-keys }, 'groq': { 'endpoint': 'https://api.groq.com/openai', 'default_model': 'llama-3.1-70b-versatile', - 'api_key_env': 'GROQ_API_KEY', + 'api_key_env': 'GROQ_API_KEY', # https://console.groq.com/keys }, } @@ -245,7 +245,7 @@ async def main( def describe(res, res_str): if isinstance(res, list): return f'{len(res)} items' - return f'{len(res_str)} chars' + return f'{len(res_str)} chars\n {res_str[:1000]}' print(f' → {describe(tool_result, tool_result_str)}', file=sys.stderr) if verbose: print(tool_result_str, file=sys.stderr) diff --git a/examples/agent/serve_tools.py b/examples/agent/serve_tools.py index 89565dc44..64f15a580 100644 --- a/examples/agent/serve_tools.py +++ b/examples/agent/serve_tools.py @@ -2,6 +2,7 @@ # requires-python = ">=3.11" # dependencies = [ # "aiohttp", +# "beautifulsoup4", # "fastapi", # "html2text", # "ipython", diff --git a/examples/agent/serve_tools_inside_docker.sh b/examples/agent/serve_tools_inside_docker.sh index 550587d82..5146d3160 100755 --- a/examples/agent/serve_tools_inside_docker.sh +++ b/examples/agent/serve_tools_inside_docker.sh @@ -1,4 +1,10 @@ #!/bin/bash +# +# Serves tools inside a docker container +# +# Usage: +# examples/agent/serve_tools_inside_docker.sh [--verbose] [--include="tool1|tool2|..."] [--exclude="tool1|tool2|..."] +# set -euo pipefail PORT=${PORT:-8088} @@ -8,4 +14,4 @@ docker run -p $PORT:$PORT \ -v $PWD/examples/agent:/src \ --env BRAVE_SEARCH_API_KEY=$BRAVE_SEARCH_API_KEY \ --rm -it ghcr.io/astral-sh/uv:python3.12-alpine \ - uv run serve_tools.py --port $PORT + uv run serve_tools.py --port $PORT "$@" diff --git a/examples/agent/tools/fetch.py b/examples/agent/tools/fetch.py index b825c0356..b354c4911 100644 --- a/examples/agent/tools/fetch.py +++ b/examples/agent/tools/fetch.py @@ -3,9 +3,9 @@ import html2text import logging -async def fetch_page(url: str) -> str: +async def fetch_page(url: str): ''' - Fetch a web page (convert it to markdown if possible). + Fetch a web page (convert it to markdown if possible), using aiohttp. ''' try: diff --git a/examples/agent/tools/python.py b/examples/agent/tools/python.py index bf797db3b..4dd2d9cc5 100644 --- a/examples/agent/tools/python.py +++ b/examples/agent/tools/python.py @@ -1,3 +1,4 @@ +import re from IPython.core.interactiveshell import InteractiveShell from io import StringIO import logging @@ -7,6 +8,11 @@ import sys python_tools = {} +def _strip_ansi_codes(text): + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + return ansi_escape.sub('', text) + + def python(code: str) -> str: ''' Execute Python code in a siloed environment using IPython and returns the output. @@ -18,7 +24,9 @@ def python(code: str) -> str: str: The output of the executed code. ''' logging.debug('[python] Executing %s', code) - shell = InteractiveShell() + shell = InteractiveShell( + colors='neutral', + ) shell.user_global_ns.update(python_tools) old_stdout = sys.stdout @@ -27,9 +35,9 @@ def python(code: str) -> str: try: shell.run_cell(code) except Exception as e: - logging.debug('[python] Execution failed: %s\nCode: %s', e, code) - return f'An error occurred: {e}' + # logging.debug('[python] Execution failed: %s\nCode: %s', e, code) + return f'An error occurred:\n{_strip_ansi_codes(str(e))}' finally: sys.stdout = old_stdout - return out.getvalue() + return _strip_ansi_codes(out.getvalue())