ollama on Plan 9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/rc | |
| # This script was written entirely out of perversity: | |
| # it is LLM code-completion for acme under Plan 9. | |
| # It will attempt to fill in a chunk of code under the cursor, | |
| # in acme | |
| # under Plan 9 | |
| # using only tools available in Plan 9 | |
| # to talk to ollama. | |
| # I have mixed the sacred and the profane. | |
| # You just put it in the tag in the acme window, and then you | |
| # middle-click it and it will complete a configurable number of | |
| # tokens. The result will be highlighted. | |
| # The only thing you need that doesn't come with Plan 9 is the Go port of jq. | |
| out=wrsel | |
| host=kan:11434 | |
| diag=/dev/null | |
| temp=0.15 | |
| tokens=64 | |
| window=auto | |
| model=qwen2.5-coder:14b | |
| while(! ~ $#* 0){ | |
| switch($1) { | |
| case -i ; out=wrsel; shift | |
| case -e ; out=/fd/1; shift | |
| case -a ; shift; host=$1; shift | |
| case -m ; shift; model=$1; shift | |
| case -t ; shift; temp=$1; shift | |
| case -n ; shift; tokens=$1; shift | |
| case -w ; shift; window=$1; shift | |
| case -W ; shift; window=auto | |
| case -v ; diag=/fd/2; shift | |
| case *; echo bad args: $* >[1=2]; exit usage | |
| } | |
| } | |
| cd /mnt/acme/$winid || exit winid | |
| addrs = `{{echo -n 'addr=dot' >[1=3];cat <[0=4]} >[3]ctl <[4]addr} | |
| if(~ $window auto) { | |
| hget -p '{"verbose":false,"name":"' ^ $model ^ '"}' \ | |
| http:// ^ $host ^ /api/show > \ | |
| /tmp/last-ollama-show.js | |
| pfx = `{gojq -r .details.family < /tmp/last-ollama-show.js | tee $diag} | |
| window = `{gojq -r '.model_info["' ^ $pfx ^ '.context_length"]' < /tmp/last-ollama-show.js | tee $diag} | |
| } | |
| body = `''{awk -v 'si=' ^ $addrs(1) -v 'ei=' ^ $addrs(2) -v 'w=' ^ $window ' | |
| {f=f $0 "\n"} | |
| function fix(str) { | |
| # For whatever reason, \ and " behave differently in substitutions. | |
| gsub(/\\/, "\\\\", str) | |
| gsub(/"/, "\\\"", str) | |
| gsub(/\n/, "\\n", str) | |
| gsub(/\t/, "\\t", str) | |
| return str | |
| } | |
| END{ | |
| s = substr(f, 1, si) | |
| e = substr(f, ei+1) | |
| if(w && (length(s) > w)) | |
| s = substr(s, 1+length(s)-w) | |
| if(w && (length(e) > w)) | |
| e = substr(e, 1, w) | |
| printf "si: %d (%d), ei: %d (%d), w: %d\n", si, length(s), ei, length(e), w > "' ^ $diag ^ '" | |
| printf "\"prompt\":\"%s\",\"suffix\":\"%s\"", fix(s), fix(e) | |
| } | |
| ' body} | |
| wopt = '' | |
| if(! ~ $window 0) { | |
| wopt = '"num_ctx":' ^ $window ^ , | |
| } | |
| bpl = '{"model":"' ^ $model ^ '","stream":false,"options":{' ^ $wopt ^ '"num_predict":' ^ $tokens ^ ',"temperature":' ^ $temp ^ ',"top_p":0.9,"stop":["<EOT>"]},' ^ $body ^ '}' | |
| echo $bpl > /tmp/last-ollama-payload.js | |
| echo http:// ^ $host ^ /api/generate → $model > $diag | |
| echo ' ' $bpl > $diag | |
| hget -p $bpl http:// ^ $host ^ /api/generate |\ | |
| tee /tmp/last-ollama-resp.js |\ | |
| gojq -r .response > $out |