Skip to content

Commit

Permalink
Add README.md on /thread volume
Browse files Browse the repository at this point in the history
  • Loading branch information
slimslenderslacks committed Jul 23, 2024
1 parent 6f38c6d commit a647745
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 23 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ Prompts are fetched from a GitHub repository. The mandatory parts of the ref ar
but optional `path` and `ref` can be added to pull prompts from branches, and to specify a subdirectory
where the prompt files are located in the repo.

## Function volumes

Every function container will have a shared volume mounted into the container at `/thread`.
The volume is intended to be ephemeral and will be deleted at the end of the run. However, the volume
can be saved for inspection by passing the argument `--save-thread-volume`. The name of the shared volume
can also be controlled using `--thread-id <name>` but will normally just be a guid.

## Output json-rpc notifications

Add the flag `--jsonrpc` to the list of arguments to switch the stdout stream to be a series of `jsonrpc` notifications.
Expand Down
10 changes: 4 additions & 6 deletions src/docker.clj
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@
:headers {"Content-Type" "application/json"
"Content-Length" (count payload)}})))

(defn create-volume [{:keys [thread-volume-name]}]
(defn create-volume [{:keys [Name]}]
(curl/post "http://localhost/volumes/create"
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
:throw false
:body (json/generate-string {:Name thread-volume-name})
:body (json/generate-string {:Name Name})
:headers {"Content-Type" "application/json"}}))

(defn remove-volume [{:keys [thread-volume-name]}]
(curl/delete (format "http://localhost/volumes/%s" thread-volume-name)
(defn remove-volume [{:keys [Name]}]
(curl/delete (format "http://localhost/volumes/%s" Name)
{:raw-args ["--unix-socket" "/var/run/docker.sock"]
:throw false}))

Expand Down Expand Up @@ -178,15 +178,13 @@
(pull (assoc m :creds {:username (:user m)
:password (or (:pat m) (creds/credential-helper->jwt))
:serveraddress "https://index.docker.io/v1/"})))
(when (:thread-volume m) (thread-volume m))
(let [x (create m)]
(start x)
(wait x)
;; body is raw PTY output
(let [s (:body (attach x))
info (inspect x)]
(delete x)
(when (and (:thread-volume m) (not (true? (:save-thread-volume m)))) (delete-thread-volume m))
{:pty-output s
:exit-code (-> info :State :ExitCode)
:info info})))
Expand Down
47 changes: 30 additions & 17 deletions src/prompts.clj
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
function-name - the name of the function that the LLM has selected
json-arg-string - the JSON arg string that the LLM has generated
resolve fail - callbacks"
[{:keys [functions user pat thread-volume save-thread-volume] :as opts} function-name json-arg-string {:keys [resolve fail]}]
[{:keys [functions user pat thread-id offline] :as opts} function-name json-arg-string {:keys [resolve fail]}]
(if-let [definition (->
(->> (filter #(= function-name (-> % :function :name)) functions)
first)
Expand All @@ -175,21 +175,23 @@
(if json-arg-string [json-arg-string] ["{}"])
(when-let [c (-> definition :container :command)] c))}
(when user {:user user})
(when pat {:pat pat})
(when thread-volume {:thread-volume thread-volume})
(when (true? save-thread-volume) {:save-thread-volume true}))
(when pat {:pat pat}))
{:keys [pty-output exit-code]} (docker/run-function function-call)]
(if (= 0 exit-code)
(resolve pty-output)
(fail (format "call exited with non-zero code (%d): %s" exit-code pty-output))))
(= "prompt" (:type definition)) ;; asynchronous call to another agent - new conversation-loop
;; TODO set a custom map for prompts in the next conversation loop
(let [{:keys [messages _finish-reason] :as m}
(async/<!! (conversation-loop
(:host-dir opts)
(:user opts)
(:host-dir opts)
(:ref definition)))]
(async/<!! (apply conversation-loop
(concat
[(:host-dir opts)
(:user opts)
(:host-dir opts)
(:ref definition)]
(when pat [:pat pat])
(when offline [:offline true])
[:thread-id thread-id])))]
(jsonrpc/notify :message {:debug (with-out-str (pprint m))})
(resolve (->> messages
(filter #(= "assistant" (:role %)))
Expand All @@ -208,7 +210,7 @@
args for extracting functions, host-dir, user, platform
returns channel that will contain the final set of messages and a finish-reason"
[prompts & args]
(let [[host-dir user platform prompts-dir & {:keys [url pat save-thread-volume thread-id]}] args
(let [[host-dir user platform prompts-dir & {:keys [url pat save-thread-volume offline thread-id]}] args
prompt-dir (get-dir prompts-dir)
m (collect-metadata prompt-dir)
functions (collect-functions prompt-dir)
Expand All @@ -221,17 +223,16 @@
:platform platform}
(when pat {:pat pat})
(when save-thread-volume {:save-thread-volume true})
(if thread-id
{:thread-volume thread-id}
{:thread-volume (str (random-uuid))}))))]
(when offline {:offline true})
{:thread-id thread-id})))]
(try
(openai/openai
(merge
{:messages prompts}
(when (seq functions) {:tools functions})
(when url {:url url})
m) h)
(catch ConnectException t
(catch ConnectException _
;; when the conversation-loop can not connect to an openai compatible endpoint
(async/>!! c {:messages [{:role "assistant" :content "I cannot connect to an openai compatible endpoint."}]
:finish-reason "error"}))
Expand Down Expand Up @@ -262,6 +263,15 @@
(jsonrpc/notify :message {:debug (with-out-str (pprint m))})
{:messages (concat prompts messages) :done finish-reason})))))

(defn- with-volume [f & {:keys [thread-id save-thread-volume]}]
(let [thread-id (or thread-id (str (random-uuid)))]
(try
(docker/thread-volume {:Name thread-id})
(f thread-id)
(finally
(when (not (true? save-thread-volume))
(docker/delete-thread-volume {:Name thread-id}))))))

(defn- -run-command
" returns map result"
[& args]
Expand Down Expand Up @@ -290,9 +300,12 @@
(update-in m [:prompts] (fn [coll] (remove (fn [{:keys [type]}] (= type (second args))) coll)))))

(= "run" (first args))
(select-keys
(async/<!! (apply conversation-loop (rest args)))
[:done])
(with-volume
(fn [thread-id]
(select-keys
(async/<!! (apply conversation-loop (concat (rest args) [:thread-id thread-id])))
[:done]))
(rest args))

:else
(apply get-prompts args)))
Expand Down

0 comments on commit a647745

Please sign in to comment.