Skip to content

Commit 57c0c84

Browse files
committed
ollama_eval refactor, rm SAFE_MODE
1 parent 19be792 commit 57c0c84

File tree

1 file changed

+159
-106
lines changed

1 file changed

+159
-106
lines changed

ollama_bash_lib.sh

Lines changed: 159 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55

66
OLLAMA_LIB_NAME='Ollama Bash Lib'
7-
OLLAMA_LIB_VERSION='0.45.2'
7+
OLLAMA_LIB_VERSION='0.45.3'
88
OLLAMA_LIB_URL='https://github.com/attogram/ollama-bash-lib'
99
OLLAMA_LIB_DISCORD='https://discord.gg/BGQJCbYVBa'
1010
OLLAMA_LIB_LICENSE='MIT'
@@ -19,7 +19,6 @@ OLLAMA_LIB_TOOLS_DEFINITION=() # Array of tool definitions
1919
OLLAMA_LIB_STREAM=0 # Streaming mode: 0 = No streaming, 1 = Yes streaming
2020
OLLAMA_LIB_THINKING="${OLLAMA_LIB_THINKING:-off}" # Thinking mode: off, on, hide
2121
OLLAMA_LIB_TIMEOUT="${OLLAMA_LIB_TIMEOUT:-300}" # Curl timeout in seconds
22-
OLLAMA_LIB_SAFE_MODE="${OLLAMA_LIB_SAFE_MODE:-0}" # Safe mode: 0 = off, 1 = disable ollama_eval and _debug
2322
set -o pipefail # Exit the pipeline if any command fails (instead of only the last one)
2423

2524
# Internal Functions
@@ -47,7 +46,6 @@ _redact() {
4746
# Requires: none
4847
# Returns: 0 on success, 1 on error
4948
_debug() {
50-
(( OLLAMA_LIB_SAFE_MODE )) || return 0 # _debug is disabled in safe mode
5149
(( OLLAMA_LIB_DEBUG )) || return 0 # DEBUG must be 1 or higher to show debug messages
5250
local date_string # some date implementations do not support %N nanoseconds
5351
date_string="$(if ! date '+%H:%M:%S:%N' 2>/dev/null; then date '+%H:%M:%S'; fi)"
@@ -2008,7 +2006,130 @@ ollama_lib_version() {
20082006
printf '%s\n' "$OLLAMA_LIB_VERSION"
20092007
}
20102008

2011-
# Helper Functions
2009+
# Ollama Eval - Command Line eval tool
2010+
2011+
# Sets global vars _eval_model and _eval_prompt
2012+
_ollama_eval_prompt() {
2013+
local task="$1"
2014+
if [[ -z "$task" ]]; then
2015+
_error 'ollama_eval: Task Not Found. Usage: oe "task" "model"'
2016+
return 1
2017+
fi
2018+
2019+
_eval_model="$(_is_valid_model "$2")"
2020+
if [[ -z "$_eval_model" ]]; then
2021+
_error 'ollama_eval: No Models Found'
2022+
return 1
2023+
fi
2024+
2025+
_eval_prompt='Write a bash one-liner to do the following task:\n\n'
2026+
_eval_prompt+="$task\n\n"
2027+
_eval_prompt+="You are on a $(uname -s) system, with bash version ${BASH_VERSION:-$(bash --version | head -n1)}.\n"
2028+
_eval_prompt+="If you can not do the task but you can instruct the user how to do it, then reply with an 'echo' command with your instructions.\n"
2029+
_eval_prompt+="If you can not do the task for any other reason, then reply with an 'echo' command with your reason.\n"
2030+
_eval_prompt+="Reply ONLY with the ready-to-run bash one-liner.\n"
2031+
_eval_prompt+='Do NOT add any commentary, description, markdown formatting or anything extraneous.\n'
2032+
2033+
}
2034+
2035+
_ollama_eval_sanity_check() {
2036+
local cmd="$1"
2037+
local first_word
2038+
read -r first_word _ <<<"$cmd"
2039+
if [[ "$first_word" =~ ^[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*\(\) ]]; then
2040+
printf ' ✅ Valid start: function definition OK: %s\n' "$first_word"
2041+
return 0
2042+
fi
2043+
if [[ "$first_word" =~ ^[a-zA-Z_][a-zA-Z0-9_]*= ]]; then
2044+
printf ' ✅ Valid start: variable assignment OK: %s\n' "$first_word"
2045+
return 0
2046+
fi
2047+
if _exists "$first_word"; then
2048+
printf ' ✅ Valid start: %s\n' "$first_word"
2049+
return 0
2050+
fi
2051+
printf ' ❌ Invalid start: %s\n' "$first_word"
2052+
return 1
2053+
}
2054+
2055+
_ollama_eval_syntax_check() {
2056+
local cmd="$1"
2057+
local errors
2058+
if _exists 'timeout'; then
2059+
if ! errors=$(timeout 1 bash -n <<<"$cmd" 2>&1); then
2060+
local rc=$?
2061+
printf " ❌ Invalid Bash Syntax (code $rc)\n%s\n" "$errors"
2062+
return 1
2063+
fi
2064+
printf " ✅ Valid Bash Syntax\n"
2065+
return 0
2066+
fi
2067+
2068+
# TODO - if no timeout available, use bash subshell + timer subshell
2069+
_debug 'ollama_eval: timeout command not found'
2070+
if ! errors=$(bash -n <<<"$cmd" 2>&1); then
2071+
local rc=$?
2072+
printf " ❌ Invalid Bash Syntax (code $rc)\n%s\n" "$errors"
2073+
return 1
2074+
fi
2075+
printf " ✅ Valid Bash Syntax (checked without timeout)\n"
2076+
return 0
2077+
}
2078+
2079+
_ollama_eval_danger_check() {
2080+
local cmd="$1"
2081+
local dangerous=(
2082+
'rm' 'mv' 'dd' 'mkfs' 'shred' 'shutdown' 'reboot' 'init' 'kill' 'pkill' 'killall'
2083+
'umount' 'mount' 'userdel' 'groupdel' 'passwd' 'su' 'sudo' 'systemctl'
2084+
'bash' '/bin/sh' '-delete' 'exec' 'eval' 'source' '\.'
2085+
)
2086+
local IFS='|'
2087+
local danger_regex="(^|[^[:alnum:]_])(${dangerous[*]})($|[^[:alnum:]_])"
2088+
if [[ "$cmd" =~ $danger_regex ]]; then
2089+
local bad="${BASH_REMATCH[2]}"
2090+
printf ' ⚠️ WARNING: The generated command contains a potentially dangerous token: "%s"\n' "$bad"
2091+
return 1
2092+
fi
2093+
printf ' ✅ No dangerous commands found\n'
2094+
return 0
2095+
}
2096+
2097+
# Returns: 0 on Sandbox run, 1 on Abort, 2 on Request for dangerous mode
2098+
_ollama_eval_permission_sandbox() {
2099+
local cmd="$cmd"
2100+
printf '\nRun command in sandbox (y/N/eval)? '
2101+
read -r permission
2102+
case "$permission" in
2103+
y|Y)
2104+
_debug "ollama_eval: sandboxed eval cmd: [${cmd:0:240}]"
2105+
echo
2106+
printf 'Running command in a sandboxed environment...\n\n'
2107+
env -i PATH="/bin:/usr/bin" bash -r -c "$cmd"
2108+
#return $? # return sandboxed eval error status
2109+
return 0 # ran in sandbox
2110+
;;
2111+
eval|EVAL)
2112+
_debug 'eval here'
2113+
return 2 # request to run in dangerous mode
2114+
;;
2115+
esac
2116+
return 1 # user aborted
2117+
}
2118+
2119+
_ollama_eval_permission_dangerous_eval() {
2120+
local cmd="$cmd"
2121+
printf '\nAre you sure you want to use the DANGEROUS eval mode? [y/N] '
2122+
read -r permission
2123+
case "$permission" in
2124+
y|Y)
2125+
_debug "ollama_eval: dangerous eval cmd: [${cmd:0:240}]"
2126+
printf '\nRunning command in DANGEROUS eval mode...\n\n'
2127+
eval "$cmd"
2128+
return 0 # command was run in dangerous mode
2129+
;;
2130+
esac
2131+
return 1 # user aborted
2132+
}
20122133

20132134
# Command Line Eval
20142135
#
@@ -2026,143 +2147,75 @@ ollama_eval() {
20262147
usage+="Generate and evaluate a command-line task.\n\n"
20272148
usage+="This function takes a description of a task, sends it to a model to generate a shell command, and then prompts the user for permission to execute it.\n\n"
20282149
usage+="It includes safety features like syntax checking and a sandbox mode for execution. This is a powerful tool for converting natural language into shell commands."
2150+
20292151
for arg in "$@"; do
20302152
if [[ "$arg" == "-h" || "$arg" == "--help" ]]; then
20312153
printf '%b\n' "$usage"
20322154
return 0
20332155
fi
20342156
done
2035-
if (( OLLAMA_LIB_SAFE_MODE )); then _error "ollama_eval is disabled in safe mode."; return 1; fi
2036-
if ! _exists 'jq'; then _error 'ollama_eval: jq Not Found'; return 1; fi
20372157

20382158
_debug "ollama_eval: [${1:0:42}] [${2:0:42}]"
20392159

2040-
local task="$1"
2041-
if [[ -z "$task" ]]; then
2042-
_error 'ollama_eval: Task Not Found. Usage: oe "task" "model"'
2043-
return 1
2044-
fi
2160+
if ! _exists 'jq'; then _error 'ollama_eval: jq Not Found'; return 1; fi
20452161

2046-
local model
2047-
model="$(_is_valid_model "$2")"
2048-
_debug "ollama_eval: model: [${model:0:120}]"
2049-
if [[ -z "$model" ]]; then
2050-
_error 'ollama_eval: No Models Found'
2162+
if ! _ollama_eval_prompt "$1" "$2"; then
2163+
_error 'ollama_eval: _ollama_eval_prompt failed'
20512164
return 1
20522165
fi
20532166

2054-
local prompt='Write a bash one-liner to do the following task:\n\n'
2055-
prompt+="$task\n\n"
2056-
prompt+="You are on a $(uname -s) system, with bash version ${BASH_VERSION:-$(bash --version | head -n1)}.\n"
2057-
prompt+="If you can not do the task but you can instruct the user how to do it, then reply with an 'echo' command with your instructions.\n"
2058-
prompt+="If you can not do the task for any other reason, then reply with an 'echo' command with your reason.\n"
2059-
prompt+="Reply ONLY with the ready-to-run bash one-liner.\n"
2060-
prompt+='Do NOT add any commentary, description, markdown formatting or anything extraneous.\n'
2061-
_debug "ollama_eval: prompt: [${prompt:0:240}]"
2167+
_debug "ollama_eval: _eval_model: [${_eval_model:0:240}]"
2168+
_debug "ollama_eval: _eval_prompt: [${_eval_prompt:0:240}]"
20622169

2063-
printf "\n%s generated the command:\n\n" "$model"
2170+
printf "\n%s generated the command:\n\n" "$_eval_model"
20642171

20652172
OLLAMA_LIB_STREAM=0
2066-
20672173
local json_result
2068-
json_result="$(ollama_generate_json "$model" "$prompt")"
2174+
json_result="$(ollama_generate_json "$_eval_model" "$_eval_prompt")"
2175+
20692176
if [[ -z "$json_result" ]]; then
2070-
_error 'ollama_eval: ollama_generate_json failed'
2177+
_error 'ollama_eval: ollama_generate_json response empty'
20712178
return 1
20722179
fi
2180+
20732181
if ! _is_valid_json "$json_result"; then
2074-
_error 'ollama_eval: received invalid json result'
2182+
_error 'ollama_eval: ollama_generate_json response invalid json'
20752183
return 1
20762184
fi
20772185

20782186
local cmd
20792187
cmd="$(printf '%s' "$json_result" | jq -r '.response // empty')"
2188+
_debug "ollama_eval: cmd: [${cmd:0:240}]"
20802189
if [[ -z "$cmd" ]]; then
2081-
_error 'ollama_eval: error extracting response from model'
2190+
_error 'ollama_eval: error extracting response'
20822191
return 1
20832192
fi
20842193

20852194
printf "%s\n\n" "$cmd"
20862195

2087-
local first_word
2088-
read -r first_word _ <<<"$cmd"
2089-
2090-
if [[ "$first_word" =~ ^[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*\(\) ]]; then
2091-
printf " ✅ Valid start: function definition OK: %s\n" "$first_word"
2092-
elif [[ "$first_word" =~ ^[a-zA-Z_][a-zA-Z0-9_]*= ]]; then
2093-
printf " ✅ Valid start: variable assignment OK: %s\n" "$first_word"
2094-
elif _exists "$first_word"; then
2095-
printf " ✅ Valid start: %s\n" "$first_word"
2096-
else
2097-
printf " ❌ Invalid start: %s\n" "$first_word"
2196+
if ! _ollama_eval_sanity_check "$cmd"; then
2197+
_error 'ollama_eval: cmd failed sanity check'
20982198
return 1
20992199
fi
21002200

2101-
local errors
2102-
if _exists 'timeout'; then
2103-
if ! errors=$(timeout 1 bash -n <<<"$cmd" 2>&1); then
2104-
local rc=$?
2105-
printf " ❌ Invalid Bash Syntax (code $rc)\n%s\n" "$errors"
2106-
return 1
2107-
else
2108-
printf " ✅ Valid Bash Syntax\n"
2109-
fi
2110-
else
2111-
# TODO - if no timeout available, use bash subshell + timer subshell
2112-
_debug "ollama_eval: 'timeout' command not found, skipping syntax check."
2113-
if ! errors=$(bash -n <<<"$cmd" 2>&1); then
2114-
local rc=$?
2115-
printf " ❌ Invalid Bash Syntax (code $rc)\n%s\n" "$errors"
2116-
return 1
2117-
else
2118-
printf " ✅ Valid Bash Syntax (checked without timeout)\n"
2119-
fi
2120-
fi
2201+
if ! _ollama_eval_syntax_check "$cmd"; then
2202+
_error 'ollama_eval: cmd failed syntax check'
2203+
return 1
2204+
fi
21212205

2122-
local dangerous=(
2123-
rm mv dd mkfs shred shutdown reboot init kill pkill killall umount mount userdel groupdel passwd su sudo systemctl
2124-
bash '/bin/sh' '-delete' exec eval source '\.'
2125-
)
2126-
local IFS='|'
2127-
local danger_regex="(^|[^[:alnum:]_])(${dangerous[*]})($|[^[:alnum:]_])"
2128-
if [[ "$cmd" =~ $danger_regex ]]; then
2129-
local bad="${BASH_REMATCH[2]}"
2130-
printf " ⚠️ WARNING: The generated command contains a potentially dangerous token: \"%s\"\n" "$bad"
2131-
else
2132-
printf " ✅ No dangerous commands found\n"
2133-
fi
2206+
if ! _ollama_eval_danger_check "$cmd"; then
2207+
_error 'ollama_eval: cmd failed danger check'
2208+
return 1
2209+
fi
21342210

2135-
printf '\nRun command in sandbox (y/N/eval)? '
2136-
read -r permission
2137-
case "$permission" in
2138-
[Yy])
2139-
_debug "ollama_eval: sandboxed eval cmd: [${cmd:0:240}]"
2140-
echo
2141-
printf 'Running command in a sandboxed environment...\n\n'
2142-
env -i PATH="/bin:/usr/bin" bash -r -c "$cmd"
2143-
return $? # return sandboxed eval error status
2144-
;;
2145-
eval)
2146-
printf '\nAre you sure you want to use the DANGEROUS eval mode? [y/N] '
2147-
read -r permission2
2148-
case "$permission2" in
2149-
[Yy])
2150-
_debug "ollama_eval: dangerous eval cmd: [${cmd:0:240}]"
2151-
printf '\nRunning command in DANGEROUS eval mode...\n\n'
2152-
eval "$cmd"
2153-
return $?
2154-
;;
2155-
*)
2156-
echo "Aborted."
2157-
return 0
2158-
;;
2159-
esac
2160-
;;
2161-
*)
2162-
echo "Aborted."
2163-
return 0
2164-
;;
2211+
_ollama_eval_permission_sandbox "$cmd"
2212+
case $? in
2213+
0) return 0 ;; # Command was run in sandbox
2214+
1) return 1 ;; # User aborted
2215+
2) : ;; # User requested dangerous mode
21652216
esac
2217+
2218+
_ollama_eval_permission_dangerous_eval "$cmd"
21662219
}
21672220

21682221
# Aliases
@@ -2205,6 +2258,9 @@ omco() { ollama_messages_count "$@"; }
22052258
omr() { ollama_model_random "$@"; }
22062259
omu() { ollama_model_unload "$@"; }
22072260

2261+
op() { ollama_ps "$@"; }
2262+
opj() { ollama_ps_json "$@"; }
2263+
22082264
os() { ollama_show "$@"; }
22092265
osj() { ollama_show_json "$@"; }
22102266

@@ -2217,9 +2273,6 @@ otc() { ollama_tools_clear "$@"; }
22172273
otic() { ollama_tools_is_call "$@"; }
22182274
otr() { ollama_tools_run "$@"; }
22192275

2220-
op() { ollama_ps "$@"; }
2221-
opj() { ollama_ps_json "$@"; }
2222-
22232276
#
22242277
# Enjoying Ollama Bash Lib?
22252278
#

0 commit comments

Comments
 (0)