|
51 | 51 | (logger/warn logger-tag "Error getting model:" (ex-message e)) |
52 | 52 | []))) |
53 | 53 |
|
54 | | -(defn ^:private base-chat-request! [{:keys [rid url body on-error on-response]}] |
55 | | - (llm-util/log-request logger-tag rid url body) |
| 54 | +(defn ^:private base-chat-request! [{:keys [rid url body on-error on-stream]}] |
56 | 55 | (let [reason-id (str (random-uuid)) |
57 | | - reasoning?* (atom false)] |
58 | | - (http/post |
59 | | - url |
60 | | - {:body (json/generate-string body) |
61 | | - :throw-exceptions? false |
62 | | - :async? true |
63 | | - :as :stream} |
64 | | - (fn [{:keys [status body]}] |
65 | | - (try |
66 | | - (if (not= 200 status) |
67 | | - (let [body-str (slurp body)] |
68 | | - (logger/warn logger-tag (format "Unexpected response status: %s body: %s" status body-str)) |
69 | | - (on-error {:message (format "Ollama response status: %s body: %s" status body-str)})) |
70 | | - (with-open [rdr (io/reader body)] |
71 | | - (doseq [[event data] (llm-util/event-data-seq rdr)] |
72 | | - (llm-util/log-response logger-tag rid event data) |
73 | | - (on-response rid event data reasoning?* reason-id)))) |
74 | | - (catch Exception e |
75 | | - (on-error {:exception e})))) |
76 | | - (fn [e] |
77 | | - (on-error {:exception e}))))) |
| 56 | + reasoning?* (atom false) |
| 57 | + response* (atom nil) |
| 58 | + on-error (if on-stream |
| 59 | + on-error |
| 60 | + (fn [error-data] |
| 61 | + (llm-util/log-response logger-tag rid "response-error" body) |
| 62 | + (reset! response* error-data)))] |
| 63 | + (llm-util/log-request logger-tag rid url body) |
| 64 | + @(http/post |
| 65 | + url |
| 66 | + {:body (json/generate-string body) |
| 67 | + :throw-exceptions? false |
| 68 | + :async? true |
| 69 | + :as (if on-stream :stream :json)} |
| 70 | + (fn [{:keys [status body]}] |
| 71 | + (try |
| 72 | + (if (not= 200 status) |
| 73 | + (let [body-str (if on-stream (slurp body) body)] |
| 74 | + (logger/warn logger-tag (format "Unexpected response status: %s body: %s" status body-str)) |
| 75 | + (on-error {:message (format "Ollama response status: %s body: %s" status body-str)})) |
| 76 | + (if on-stream |
| 77 | + (with-open [rdr (io/reader body)] |
| 78 | + (doseq [[event data] (llm-util/event-data-seq rdr)] |
| 79 | + (llm-util/log-response logger-tag rid event data) |
| 80 | + (on-stream rid event data reasoning?* reason-id))) |
| 81 | + (do |
| 82 | + (llm-util/log-response logger-tag rid "response" body) |
| 83 | + (reset! response* |
| 84 | + {:result (:content (:message body))})))) |
| 85 | + (catch Exception e |
| 86 | + (on-error {:exception e})))) |
| 87 | + (fn [e] |
| 88 | + (on-error {:exception e}))) |
| 89 | + @response*)) |
78 | 90 |
|
79 | 91 | (defn ^:private ->tools [tools] |
80 | 92 | (mapv (fn [tool] |
|
99 | 111 | past-messages)) |
100 | 112 |
|
101 | 113 | (defn chat! [{:keys [model user-messages reason? instructions api-url past-messages tools]} |
102 | | - {:keys [on-message-received on-error on-prepare-tool-call on-tools-called |
103 | | - on-reason extra-payload]}] |
| 114 | + {:keys [on-message-received on-error on-prepare-tool-call on-tools-called |
| 115 | + on-reason extra-payload] :as callbacks}] |
104 | 116 | (let [messages (concat |
105 | 117 | (normalize-messages (concat [{:role "system" :content instructions}] past-messages)) |
106 | 118 | (normalize-messages user-messages)) |
| 119 | + stream? (boolean callbacks) |
107 | 120 | body (deep-merge |
108 | 121 | {:model model |
109 | 122 | :messages messages |
110 | 123 | :think reason? |
111 | 124 | :tools (->tools tools) |
112 | | - :stream true} |
| 125 | + :stream stream?} |
113 | 126 | extra-payload) |
114 | 127 | url (format chat-url api-url) |
115 | 128 | tool-calls* (atom {}) |
116 | | - on-response-fn (fn handle-response [rid _event data reasoning?* reason-id] |
| 129 | + on-stream-fn (when stream? |
| 130 | + (fn handle-stream [rid _event data reasoning?* reason-id] |
117 | 131 | (let [{:keys [message done_reason]} data] |
118 | 132 | (cond |
119 | 133 | (seq (:tool_calls message)) |
|
127 | 141 |
|
128 | 142 | done_reason |
129 | 143 | (if-let [tool-call (get @tool-calls* rid)] |
130 | | - ;; TODO support multiple tool calls |
| 144 | + ;; TODO support multiple tool calls |
131 | 145 | (when-let [{:keys [new-messages]} (on-tools-called [tool-call])] |
132 | 146 | (swap! tool-calls* dissoc rid) |
133 | 147 | (base-chat-request! |
134 | 148 | {:rid (llm-util/gen-rid) |
135 | 149 | :url url |
136 | 150 | :body (assoc body :messages (normalize-messages new-messages)) |
137 | 151 | :on-error on-error |
138 | | - :on-response handle-response})) |
| 152 | + :on-stream handle-stream})) |
139 | 153 | (on-message-received {:type :finish |
140 | 154 | :finish-reason done_reason})) |
141 | 155 |
|
|
155 | 169 | :id reason-id}) |
156 | 170 | (reset! reasoning?* false)) |
157 | 171 | (on-message-received {:type :text |
158 | | - :text (:content message)}))))))] |
| 172 | + :text (:content message)})))))))] |
159 | 173 | (base-chat-request! |
160 | 174 | {:rid (llm-util/gen-rid) |
161 | 175 | :url url |
162 | 176 | :body body |
163 | 177 | :on-error on-error |
164 | | - :on-response on-response-fn}))) |
| 178 | + :on-stream on-stream-fn}))) |
0 commit comments