|
52 | 52 | ; be merged into the conversation state |
53 | 53 | ; ===================================================== |
54 | 54 |
|
55 | | -(defn start |
| 55 | +(defn start |
56 | 56 | "create starting messages, metadata, and functions to bootstrap the thread" |
57 | 57 | [{:keys [prompts] :as opts} _] |
58 | 58 | (let [c (async/promise-chan)] |
|
70 | 70 | (async/put! c {:messages [] :done "error"}))) |
71 | 71 | c)) |
72 | 72 |
|
73 | | -(defn end |
| 73 | +(defn end |
74 | 74 | "merge the :done signal" |
75 | 75 | [state] |
76 | 76 | (let [c (async/promise-chan)] |
77 | 77 | ;; this is a normal ending and we try to add a :done key to the state for this |
78 | 78 | (async/put! c (assoc state :done (:finish-reason state))) |
79 | 79 | c)) |
80 | 80 |
|
81 | | -(defn completion |
| 81 | +(defn completion |
82 | 82 | "get the next llm completion" |
83 | 83 | [state] |
84 | 84 | (run-llm (:messages state) (:metadata state) (:functions state) (:opts state))) |
85 | 85 |
|
86 | | -(defn tool |
| 86 | +(defn tool |
87 | 87 | "make docker container tool calls" |
88 | 88 | [state] |
89 | 89 | (let [calls (-> (:messages state) last :tool_calls)] |
|
102 | 102 |
|
103 | 103 | ; tool_calls are maps with an id and a function with arguments an name |
104 | 104 | ; look up the full tool definition using the name |
105 | | -(defn sub-graph |
| 105 | +(defn sub-graph |
106 | 106 | "answer a tool call by processing a sub-graph" |
107 | 107 | [state] |
108 | 108 | (async/go |
|
126 | 126 | ; edge functions takes state and returns next node |
127 | 127 | ; ===================================================== |
128 | 128 |
|
129 | | -(defn tool-or-end |
| 129 | +(defn tool-or-end |
130 | 130 | "after a completion, check whether you need to make a tool call" |
131 | 131 | [state] |
132 | 132 | (let [finish-reason (-> state :finish-reason)] |
|
148 | 148 | (defn add-conditional-edges [graph s1 f & [m]] |
149 | 149 | (assoc-in graph [:edges s1] ((or m identity) f))) |
150 | 150 |
|
151 | | -(defn state-reducer |
| 151 | +(defn state-reducer |
152 | 152 | "reduce the state with the change from running a node" |
153 | 153 | [state change] |
154 | 154 | (-> state |
|
157 | 157 |
|
158 | 158 | (defn stream |
159 | 159 | "start streaming a conversation" |
160 | | - [graph] |
161 | | - (async/go-loop |
162 | | - [state {} |
163 | | - node "start"] |
164 | | - (jsonrpc/notify :message {:debug (format "\n-> entering %s\n\n" node)}) |
165 | | - ;; TODO handling bad graphs with missing nodes |
166 | | - (let [enter-node (get-in graph [:nodes node]) |
167 | | - new-state (state-reducer state (async/<! (enter-node state)))] |
168 | | - (if (= "end" node) |
169 | | - new-state |
170 | | - ;; TODO check for :done keys and possibly bail |
171 | | - ;; transition to the next state |
172 | | - ;; TODO handling missing edges |
173 | | - (recur new-state ((get-in graph [:edges node]) new-state)))))) |
| 160 | + ([graph] (stream graph {})) |
| 161 | + ([graph m] |
| 162 | + (async/go-loop |
| 163 | + [state m |
| 164 | + node "start"] |
| 165 | + (jsonrpc/notify :message {:debug (format "\n-> entering %s\n\n" node)}) |
| 166 | + ;; TODO handling bad graphs with missing nodes |
| 167 | + (let [enter-node (get-in graph [:nodes node]) |
| 168 | + new-state (state-reducer state (async/<! (enter-node state)))] |
| 169 | + (if (= "end" node) |
| 170 | + new-state |
| 171 | + ;; TODO check for :done keys and possibly bail |
| 172 | + ;; transition to the next state |
| 173 | + ;; TODO handling missing edges |
| 174 | + (recur new-state ((get-in graph [:edges node]) new-state))))))) |
174 | 175 |
|
175 | 176 | ; ============================================================ |
176 | 177 | ; this is the graph we tend to use in our experiments thus far |
|
0 commit comments