Files
2026-09-15 15:24:03 -04:00

61 lines
2.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Call one tool by hand, the way Open WebUI would.
#
# ./tests/try-tool.sh is the server up?
# ./tests/try-tool.sh web_search '{"query":"systemd socket activation"}'
# ./tests/try-tool.sh subnet_calc '{"network":"192.168.1.0/24"}'
#
# WHY THIS IS NOT `curl http://localhost:8000/...`
#
# Because that does not work, and worse, it can appear to. NOTHING in
# this stack publishes a port to the host: the app container has no
# default route and the gateway is only on Open WebUI's docker network.
# A curl to localhost:8000 reaches whatever else happens to be listening
# there - on the machine this was written on, something answered "OK" and
# looked for all the world like a healthy tool server.
#
# So the call is made from inside the api container, which is where the
# token already is. Same code path a real tool call takes, minus nginx.
set -euo pipefail
cd "$(dirname "$0")/.."
TOOL="${1:-}"
BODY="${2:-{\}}"
if [ -z "$TOOL" ]; then
docker compose exec -T api python -c \
"import urllib.request;print(urllib.request.urlopen('http://127.0.0.1:8000/health').read().decode())"
exit 0
fi
docker compose exec -T -e TOOL="$TOOL" -e BODY="$BODY" api python - <<'PY'
import json, os, sys, urllib.error, urllib.request
tool, body = os.environ["TOOL"], os.environ["BODY"]
try:
json.loads(body)
except ValueError as exc:
sys.exit(f"the second argument is not valid JSON: {exc}")
request = urllib.request.Request(
f"http://127.0.0.1:8000/tools/{tool}",
data=body.encode(),
headers={"Authorization": "Bearer " + os.environ["OWUITOOLS_AUTH_TOKEN"],
"Content-Type": "application/json"},
)
try:
answer = urllib.request.urlopen(request, timeout=120).read().decode()
except urllib.error.HTTPError as exc:
if exc.code == 404:
sys.exit(f"there is no tool called {tool!r}. It may be switched off in "
"configs/tools.toml - see docs/tools.md.")
sys.exit(f"HTTP {exc.code}: {exc.read().decode()[:400]}")
# Tools return a JSON string; print what the model would actually read.
try:
answer = json.loads(answer)
except ValueError:
pass
print(answer if isinstance(answer, str) else json.dumps(answer, indent=2))
PY