44#
55
66OLLAMA_LIB_NAME=' Ollama Bash Lib'
7- OLLAMA_LIB_VERSION=' 0.45.2 '
7+ OLLAMA_LIB_VERSION=' 0.45.3 '
88OLLAMA_LIB_URL=' https://github.com/attogram/ollama-bash-lib'
99OLLAMA_LIB_DISCORD=' https://discord.gg/BGQJCbYVBa'
1010OLLAMA_LIB_LICENSE=' MIT'
@@ -19,7 +19,6 @@ OLLAMA_LIB_TOOLS_DEFINITION=() # Array of tool definitions
1919OLLAMA_LIB_STREAM=0 # Streaming mode: 0 = No streaming, 1 = Yes streaming
2020OLLAMA_LIB_THINKING=" ${OLLAMA_LIB_THINKING:- off} " # Thinking mode: off, on, hide
2121OLLAMA_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
2322set -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 "$@"; }
22052258omr () { ollama_model_random " $@ " ; }
22062259omu () { ollama_model_unload " $@ " ; }
22072260
2261+ op () { ollama_ps " $@ " ; }
2262+ opj () { ollama_ps_json " $@ " ; }
2263+
22082264os () { ollama_show " $@ " ; }
22092265osj () { ollama_show_json " $@ " ; }
22102266
@@ -2217,9 +2273,6 @@ otc() { ollama_tools_clear "$@"; }
22172273otic () { ollama_tools_is_call " $@ " ; }
22182274otr () { ollama_tools_run " $@ " ; }
22192275
2220- op () { ollama_ps " $@ " ; }
2221- opj () { ollama_ps_json " $@ " ; }
2222-
22232276#
22242277# Enjoying Ollama Bash Lib?
22252278#
0 commit comments