|
120 | 120 | (:workspace-folders db) |
121 | 121 | {:behavior (behavior->behavior-str (or behavior (:chat-default-behavior db)))}) |
122 | 122 | refined-contexts (raw-contexts->refined contexts) |
| 123 | + manual-approval? (get-in config [:toolCall :manualApproval] false) |
123 | 124 | context-str (build-context-str refined-contexts rules) |
124 | 125 | chosen-model (or model (default-model db config)) |
125 | 126 | past-messages (get-in db [:chats chat-id :messages] []) |
|
221 | 222 | :origin (tool-name->origin name all-tools) |
222 | 223 | :arguments-text (get @tool-call-args-by-id* id) |
223 | 224 | :id id |
224 | | - :manual-approval false}})) |
| 225 | + :manual-approval manual-approval?}})) |
225 | 226 | :on-tool-called (fn [{:keys [id name arguments] :as tool-call}] |
226 | 227 | (assert-chat-not-stopped! chat-id db* messenger) |
227 | 228 | (messenger/chat-content-received |
|
234 | 235 | :origin (tool-name->origin name all-tools) |
235 | 236 | :arguments arguments |
236 | 237 | :id id |
237 | | - :manual-approval false}}) |
238 | | - (let [result (f.tools/call-tool! name arguments @db* config)] |
| 238 | + :manual-approval manual-approval?}}) |
| 239 | + (let [approved?* (promise)] |
| 240 | + (swap! db* assoc-in [:chats chat-id :tool-calls id :approved?*] approved?*) |
239 | 241 | (when-not (string/blank? @received-msgs*) |
240 | 242 | (add-to-history! {:role "assistant" :content @received-msgs*}) |
241 | 243 | (reset! received-msgs* "")) |
242 | | - (add-to-history! {:role "tool_call" :content tool-call}) |
243 | | - (add-to-history! {:role "tool_call_output" :content (assoc tool-call :output result)}) |
244 | | - (swap! tool-call-args-by-id* dissoc id) |
245 | | - (messenger/chat-content-received |
246 | | - messenger |
247 | | - {:chat-id chat-id |
248 | | - :request-id request-id |
249 | | - :role :assistant |
250 | | - :content {:type :toolCalled |
251 | | - :origin (tool-name->origin name all-tools) |
252 | | - :name name |
253 | | - :arguments arguments |
254 | | - :id id |
255 | | - :outputs (:contents result)}}) |
256 | | - {:result result |
257 | | - :past-messages (get-in @db* [:chats chat-id :messages] [])})) |
| 244 | + (if manual-approval? |
| 245 | + (messenger/chat-content-received |
| 246 | + messenger |
| 247 | + {:chat-id chat-id |
| 248 | + :request-id request-id |
| 249 | + :role :system |
| 250 | + :content {:type :progress |
| 251 | + :state :running |
| 252 | + :text "Waiting for tool call approval"}}) |
| 253 | + ;; Otherwise auto approve |
| 254 | + (deliver approved?* true)) |
| 255 | + (if @approved?* |
| 256 | + (let [output (f.tools/call-tool! name arguments @db* config)] |
| 257 | + (add-to-history! {:role "tool_call" :content tool-call}) |
| 258 | + (add-to-history! {:role "tool_call_output" :content (assoc tool-call :output output)}) |
| 259 | + (swap! tool-call-args-by-id* dissoc id) |
| 260 | + (messenger/chat-content-received |
| 261 | + messenger |
| 262 | + {:chat-id chat-id |
| 263 | + :request-id request-id |
| 264 | + :role :assistant |
| 265 | + :content {:type :toolCalled |
| 266 | + :origin (tool-name->origin name all-tools) |
| 267 | + :name name |
| 268 | + :arguments arguments |
| 269 | + :id id |
| 270 | + :outputs (:contents output)}}) |
| 271 | + {:new-messages (get-in @db* [:chats chat-id :messages])}) |
| 272 | + (do |
| 273 | + (add-to-history! {:role "tool_call" :content tool-call}) |
| 274 | + (add-to-history! {:role "tool_call_output" :content (assoc tool-call :output {:contents [{:content "Tool call rejected by user" |
| 275 | + :error true |
| 276 | + :type :text}]})}) |
| 277 | + (swap! tool-call-args-by-id* dissoc id) |
| 278 | + (messenger/chat-content-received |
| 279 | + messenger |
| 280 | + {:chat-id chat-id |
| 281 | + :request-id request-id |
| 282 | + :role :system |
| 283 | + :content {:type :progress |
| 284 | + :state :running |
| 285 | + :text "Generating"}}) |
| 286 | + (messenger/chat-content-received |
| 287 | + messenger |
| 288 | + {:chat-id chat-id |
| 289 | + :request-id request-id |
| 290 | + :role :assistant |
| 291 | + :content {:type :toolCallRejected |
| 292 | + :origin (tool-name->origin name all-tools) |
| 293 | + :name name |
| 294 | + :arguments arguments |
| 295 | + :reason :user |
| 296 | + :id id}}) |
| 297 | + {:new-messages (get-in @db* [:chats chat-id :messages])})))) |
258 | 298 | :on-reason (fn [{:keys [status]}] |
259 | 299 | (assert-chat-not-stopped! chat-id db* messenger) |
260 | 300 | (let [msg (case status |
|
282 | 322 | :model chosen-model |
283 | 323 | :status :success})) |
284 | 324 |
|
| 325 | +(defn tool-call-approve [{:keys [chat-id tool-call-id]} db*] |
| 326 | + (deliver (get-in @db* [:chats chat-id :tool-calls tool-call-id :approved?*]) true)) |
| 327 | + |
| 328 | +(defn tool-call-reject [{:keys [chat-id tool-call-id]} db*] |
| 329 | + (deliver (get-in @db* [:chats chat-id :tool-calls tool-call-id :approved?*]) false)) |
| 330 | + |
285 | 331 | (defn ^:private contexts-for [root-filename query config] |
286 | 332 | (let [all-files (fs/glob root-filename (str "**" (or query "") "**")) |
287 | 333 | allowed-files (f.index/filter-allowed all-files root-filename config)] |
|
0 commit comments