|
37 | 37 |
|
38 | 38 | (defn ^:private base-completion-request! [{:keys [rid url body on-error on-response]}] |
39 | 39 | (llm-util/log-request logger-tag rid url body) |
40 | | - (http/post |
41 | | - url |
42 | | - {:body (json/generate-string body) |
43 | | - :throw-exceptions? false |
44 | | - :async? true |
45 | | - :as :stream} |
46 | | - (fn [{:keys [status body]}] |
47 | | - (try |
48 | | - (if (not= 200 status) |
49 | | - (let [body-str (slurp body)] |
50 | | - (logger/warn logger-tag "Unexpected response status: %s body: %s" status body-str) |
51 | | - (on-error {:message (format "Ollama response status: %s body: %s" status body-str)})) |
52 | | - (with-open [rdr (io/reader body)] |
53 | | - (doseq [[event data] (llm-util/event-data-seq rdr)] |
54 | | - (llm-util/log-response logger-tag rid event data) |
55 | | - (on-response rid event data)))) |
56 | | - (catch Exception e |
57 | | - (on-error {:exception e})))) |
58 | | - (fn [e] |
59 | | - (on-error {:exception e})))) |
| 40 | + (let [reason-id (str (random-uuid)) |
| 41 | + reasoning?* (atom false)] |
| 42 | + (http/post |
| 43 | + url |
| 44 | + {:body (json/generate-string body) |
| 45 | + :throw-exceptions? false |
| 46 | + :async? true |
| 47 | + :as :stream} |
| 48 | + (fn [{:keys [status body]}] |
| 49 | + (try |
| 50 | + (if (not= 200 status) |
| 51 | + (let [body-str (slurp body)] |
| 52 | + (logger/warn logger-tag "Unexpected response status: %s body: %s" status body-str) |
| 53 | + (on-error {:message (format "Ollama response status: %s body: %s" status body-str)})) |
| 54 | + (with-open [rdr (io/reader body)] |
| 55 | + (doseq [[event data] (llm-util/event-data-seq rdr)] |
| 56 | + (llm-util/log-response logger-tag rid event data) |
| 57 | + (on-response rid event data reasoning?* reason-id)))) |
| 58 | + (catch Exception e |
| 59 | + (on-error {:exception e})))) |
| 60 | + (fn [e] |
| 61 | + (on-error {:exception e}))))) |
60 | 62 |
|
61 | 63 | (defn ^:private ->tools [tools] |
62 | 64 | (mapv (fn [tool] |
|
70 | 72 | "tool_call" {:role "assistant" :tool-calls [{:type "function" |
71 | 73 | :function content}]} |
72 | 74 | "tool_call_output" {:role "tool" :content (llm-util/stringfy-tool-result content)} |
| 75 | + "reason" {:role "assistant" :content (:text content)} |
73 | 76 | msg)) |
74 | 77 | past-messages)) |
75 | 78 |
|
76 | | -(defn completion! [{:keys [model user-messages instructions host port past-messages tools]} |
77 | | - {:keys [on-message-received on-error on-prepare-tool-call on-tool-called]}] |
| 79 | +(defn completion! [{:keys [model user-messages reason? instructions host port past-messages tools]} |
| 80 | + {:keys [on-message-received on-error on-prepare-tool-call on-tool-called |
| 81 | + on-reason]}] |
78 | 82 | (let [messages (concat |
79 | 83 | (normalize-messages (concat [{:role "system" :content instructions}] past-messages)) |
80 | 84 | (normalize-messages user-messages)) |
81 | 85 | body {:model model |
82 | 86 | :messages messages |
83 | | - :think false |
| 87 | + :think reason? |
84 | 88 | :tools (->tools tools) |
85 | 89 | :stream true} |
86 | 90 | url (format chat-url (base-url host port)) |
87 | 91 | tool-calls* (atom {}) |
88 | | - on-response-fn (fn handle-response [rid _event data] |
| 92 | + on-response-fn (fn handle-response [rid _event data reasoning?* reason-id] |
89 | 93 | (let [{:keys [message done_reason]} data] |
90 | 94 | (cond |
91 | 95 | (seq (:tool_calls message)) |
|
111 | 115 | :finish-reason done_reason})) |
112 | 116 |
|
113 | 117 | message |
114 | | - (on-message-received {:type :text |
115 | | - :text (:content message)}))))] |
| 118 | + (if (:thinking message) |
| 119 | + (do |
| 120 | + (when-not @reasoning?* |
| 121 | + (on-reason {:status :started |
| 122 | + :id reason-id}) |
| 123 | + (reset! reasoning?* true)) |
| 124 | + (on-reason {:status :thinking |
| 125 | + :id reason-id |
| 126 | + :text (:thinking message)})) |
| 127 | + (do |
| 128 | + (when @reasoning?* |
| 129 | + (on-reason {:status :finished |
| 130 | + :id reason-id}) |
| 131 | + (reset! reasoning?* false)) |
| 132 | + (on-message-received {:type :text |
| 133 | + :text (:content message)}))))))] |
116 | 134 | (base-completion-request! |
117 | 135 | {:rid (llm-util/gen-rid) |
118 | 136 | :url url |
|
0 commit comments