|
34 | 34 |
|
35 | 35 | (def ^:private logger-tag "[CHAT]") |
36 | 36 |
|
37 | | -(def ^:private max-auto-continues |
38 | | - "Max times a single prompt chain is auto-continued after interrupted or |
39 | | - truncated responses (e.g. proxies dropping long streaming connections #547)." |
40 | | - 3) |
| 37 | +(def ^:private default-max-auto-continues 3) |
| 38 | + |
| 39 | +(defn ^:private provider-max-auto-continues [config provider] |
| 40 | + (let [configured (get-in config [:providers provider :retry :maxAutoContinues])] |
| 41 | + (if (and (integer? configured) (not (neg? configured))) |
| 42 | + (long configured) |
| 43 | + default-max-auto-continues))) |
| 44 | + |
| 45 | +(defn ^:private prompt-error-data |
| 46 | + "Returns serializable terminal prompt error details for chat state." |
| 47 | + [{:keys [message exception status code request-id response-id rate-limit-resets-at]} error-type] |
| 48 | + (assoc-some {:message (or (shared/not-blank message) |
| 49 | + (some-> exception ex-message shared/not-blank) |
| 50 | + "Unknown provider error") |
| 51 | + :error-type error-type} |
| 52 | + :status status |
| 53 | + :code code |
| 54 | + :request-id request-id |
| 55 | + :response-id response-id |
| 56 | + :rate-limit-resets-at rate-limit-resets-at)) |
41 | 57 |
|
42 | 58 | (defn ^:private tool-output-text [msg] |
43 | 59 | (let [contents (get-in msg [:content :output :contents])] |
|
902 | 918 | (logger/info logger-tag "Superseding active prompt" {:chat-id chat-id |
903 | 919 | :status (get-in @db* [:chats chat-id :status])})) |
904 | 920 | (swap! db* assoc-in [:chats chat-id :status] :running) |
905 | | - (swap! db* update-in [:chats chat-id] dissoc :prompt-finished?) |
| 921 | + (swap! db* update-in [:chats chat-id] dissoc :prompt-finished? :prompt-error) |
906 | 922 | (swap! db* assoc-in [:chats chat-id :updated-at] (System/currentTimeMillis)) |
907 | 923 | (messenger/chat-status-changed messenger {:chat-id chat-id :status :running}) |
908 | 924 | (lifecycle/trigger-chat-status-hook! chat-ctx) |
|
922 | 938 | model-capabilities (get-in db [:models full-model]) |
923 | 939 | provider-auth (get-in @db* [:auth provider]) |
924 | 940 | all-tools (f.tools/all-tools chat-id agent @db* config) |
| 941 | + auto-continue-limit (provider-max-auto-continues config provider) |
925 | 942 | received-msgs* (atom "") |
926 | 943 | reasonings* (atom {}) |
927 | 944 | server-tool-times* (atom {}) |
|
1141 | 1158 | (not (string/blank? response-text)) |
1142 | 1159 | (or (:premature? msg) |
1143 | 1160 | (truncated-response? response-text)) |
1144 | | - (< (:auto-continue-count chat-ctx 0) max-auto-continues) |
| 1161 | + (< (:auto-continue-count chat-ctx 0) auto-continue-limit) |
1145 | 1162 | (not (or (:on-finished-side-effect chat-ctx) |
1146 | 1163 | (:on-after-finish! chat-ctx)))) |
1147 | 1164 | (do |
|
1430 | 1447 | (let [partial-text @received-msgs* |
1431 | 1448 | transient-error? (contains? #{:overloaded :premature-stop} error-type) |
1432 | 1449 | stopping? (identical? :stopping (get-in @db* [:chats chat-id :status])) |
| 1450 | + user-messages-recorded? (boolean |
| 1451 | + (when-let [user-content-id (:user-content-id chat-ctx)] |
| 1452 | + (some #(= user-content-id (:content-id %)) |
| 1453 | + (get-in @db* [:chats chat-id :messages])))) |
| 1454 | + continue-existing-response? (or (not (string/blank? partial-text)) |
| 1455 | + user-messages-recorded?) |
| 1456 | + retry-messages (if continue-existing-response? |
| 1457 | + [{:role "user" |
| 1458 | + :content [{:type :text |
| 1459 | + :text "Your previous response was interrupted mid-stream. Continue from where you left off, do not redo completed steps."}]}] |
| 1460 | + user-messages) |
| 1461 | + retry-source-type (if continue-existing-response? |
| 1462 | + :auto-continue |
| 1463 | + :transient-error-retry) |
1433 | 1464 | can-auto-continue? (and (not stopping?) |
1434 | 1465 | (or transient-error? |
1435 | 1466 | (string/includes? (or message "") "idle timeout")) |
1436 | | - (< (:auto-continue-count chat-ctx 0) max-auto-continues) |
| 1467 | + (< (:auto-continue-count chat-ctx 0) auto-continue-limit) |
1437 | 1468 | (not (or (:on-finished-side-effect chat-ctx) |
1438 | 1469 | (:on-after-finish! chat-ctx))) |
1439 | 1470 | (not compacting?))] |
|
1447 | 1478 | (logger/info logger-tag "Transient error during response, auto-continuing" |
1448 | 1479 | {:chat-id chat-id :error-type error-type}) |
1449 | 1480 | (lifecycle/send-content! chat-ctx :system |
1450 | | - {:type :progress :state :running :text (str (or message "Connection interrupted") ", continuing...")}) |
| 1481 | + {:type :progress |
| 1482 | + :state :running |
| 1483 | + :text (str (or message "Connection interrupted") |
| 1484 | + (if continue-existing-response? |
| 1485 | + ", continuing..." |
| 1486 | + ", retrying original request..."))}) |
1451 | 1487 | (swap! db* assoc-in [:chats chat-id :auto-compacting?] true) |
1452 | 1488 | (lifecycle/finish-chat-prompt! :idle |
1453 | 1489 | (assoc chat-ctx |
|
1457 | 1493 | :on-after-finish! |
1458 | 1494 | (fn [] |
1459 | 1495 | (prompt-messages! |
1460 | | - [{:role "user" |
1461 | | - :content [{:type :text |
1462 | | - :text "Your previous response was interrupted mid-stream. Continue from where you left off, do not redo completed steps."}]}] |
1463 | | - :auto-continue |
| 1496 | + retry-messages |
| 1497 | + retry-source-type |
1464 | 1498 | (update chat-ctx :auto-continue-count (fnil inc 0))))))) |
1465 | 1499 | (do |
1466 | 1500 | (when-not stopping? |
| 1501 | + (swap! db* assoc-in [:chats chat-id :prompt-error] |
| 1502 | + (prompt-error-data error-data error-type)) |
1467 | 1503 | (lifecycle/send-content! chat-ctx :system |
1468 | 1504 | {:type :text |
1469 | 1505 | :text (if (= :context-overflow error-type) |
|
1485 | 1521 | (catch Exception e |
1486 | 1522 | (when-not (:silent? (ex-data e)) |
1487 | 1523 | (logger/error e) |
| 1524 | + (swap! db* assoc-in [:chats chat-id :prompt-error] |
| 1525 | + (prompt-error-data {:exception e} :unknown)) |
1488 | 1526 | (swap! db* update-in [:chats chat-id] dissoc :auto-compacting? :compacting?) |
1489 | 1527 | (when-not (string/blank? @received-msgs*) |
1490 | 1528 | (add-to-history! {:role "assistant" |
|
0 commit comments