|
69 | 69 | (defn ^:private real-model-name [model model-capabilities] |
70 | 70 | (or (:model-name model-capabilities) model)) |
71 | 71 |
|
72 | | -(defn chat! |
73 | | - [{:keys [provider model model-capabilities instructions user-messages config on-first-response-received |
| 72 | +(defn ^:private prompt! |
| 73 | + [{:keys [provider model model-capabilities instructions user-messages config |
74 | 74 | on-message-received on-error on-prepare-tool-call on-tools-called on-reason on-usage-updated |
75 | | - past-messages tools provider-auth] |
76 | | - :or {on-first-response-received identity |
77 | | - on-message-received identity |
78 | | - on-error identity |
79 | | - on-prepare-tool-call identity |
80 | | - on-tools-called identity |
81 | | - on-reason identity |
82 | | - on-usage-updated identity}}] |
83 | | - (let [first-response-received* (atom false) |
84 | | - emit-first-message-fn (fn [& args] |
85 | | - (when-not @first-response-received* |
86 | | - (reset! first-response-received* true) |
87 | | - (apply on-first-response-received args))) |
88 | | - on-message-received-wrapper (fn [& args] |
89 | | - (apply emit-first-message-fn args) |
90 | | - (apply on-message-received args)) |
91 | | - on-reason-wrapper (fn [& args] |
92 | | - (apply emit-first-message-fn args) |
93 | | - (apply on-reason args)) |
94 | | - on-prepare-tool-call-wrapper (fn [& args] |
95 | | - (apply emit-first-message-fn args) |
96 | | - (apply on-prepare-tool-call args)) |
97 | | - on-error-wrapper (fn [{:keys [exception] :as args}] |
98 | | - (when-not (:silent? (ex-data exception)) |
99 | | - (logger/error args) |
100 | | - (on-error args))) |
101 | | - real-model (real-model-name model model-capabilities) |
| 75 | + past-messages tools provider-auth sync?]}] |
| 76 | + (let [real-model (real-model-name model model-capabilities) |
102 | 77 | tools (when (:tools model-capabilities) |
103 | 78 | (mapv tool->llm-tool tools)) |
104 | 79 | reason? (:reason? model-capabilities) |
|
111 | 86 | api-key (llm-util/provider-api-key provider provider-auth config) |
112 | 87 | api-url (llm-util/provider-api-url provider config) |
113 | 88 | provider-auth-type (:type provider-auth) |
114 | | - callbacks {:on-message-received on-message-received-wrapper |
115 | | - :on-error on-error-wrapper |
116 | | - :on-prepare-tool-call on-prepare-tool-call-wrapper |
117 | | - :on-tools-called on-tools-called |
118 | | - :on-reason on-reason-wrapper |
119 | | - :on-usage-updated on-usage-updated}] |
| 89 | + callbacks (when-not sync? |
| 90 | + {:on-message-received on-message-received |
| 91 | + :on-error on-error |
| 92 | + :on-prepare-tool-call on-prepare-tool-call |
| 93 | + :on-tools-called on-tools-called |
| 94 | + :on-reason on-reason |
| 95 | + :on-usage-updated on-usage-updated})] |
120 | 96 | (try |
121 | 97 | (when-not api-url (throw (ex-info (format "API url not found.\nMake sure you have provider '%s' configured properly." provider) {}))) |
122 | 98 | (cond |
|
215 | 191 | "openai") llm-providers.openai/create-response! |
216 | 192 | "anthropic" llm-providers.anthropic/chat! |
217 | 193 | "openai-chat" llm-providers.openai-chat/chat-completion! |
218 | | - (on-error-wrapper {:message (format "Unknown model %s for provider %s" (:api provider-config) provider)})) |
| 194 | + (on-error {:message (format "Unknown model %s for provider %s" (:api provider-config) provider)})) |
219 | 195 | url-relative-path (:completionUrlRelativePath provider-config)] |
220 | 196 | (provider-fn |
221 | 197 | {:model real-model |
|
234 | 210 | callbacks)) |
235 | 211 |
|
236 | 212 | :else |
237 | | - (on-error-wrapper {:message (format "ECA Unsupported model %s for provider %s" real-model provider)})) |
| 213 | + (on-error {:message (format "ECA Unsupported model %s for provider %s" real-model provider)})) |
238 | 214 | (catch Exception e |
239 | | - (on-error-wrapper {:exception e}))))) |
| 215 | + (on-error {:exception e}))))) |
240 | 216 |
|
241 | | -(defn complete! |
242 | | - [{:keys [provider model model-capabilities instructions input-code config provider-auth]}] |
243 | | - (let [reason? (:reason? model-capabilities) |
244 | | - provider-config (get-in config [:providers provider]) |
245 | | - model-config (get-in provider-config [:models model]) |
246 | | - real-model (real-model-name model model-capabilities) |
247 | | - max-output-tokens (:max-output-tokens model-capabilities) |
248 | | - extra-payload (:extraPayload model-config) |
249 | | - api-key (llm-util/provider-api-key provider provider-auth config) |
250 | | - api-url (llm-util/provider-api-url provider config) |
251 | | - provider-auth-type (:type provider-auth) |
252 | | - user-messages [{:role "user" :content [{:type :text :text input-code}]}]] |
253 | | - (try |
254 | | - (when-not api-url (throw (ex-info (format "API url not found.\nMake sure you have provider '%s' configured properly." provider) {}))) |
255 | | - (cond |
256 | | - (= "openai" provider) |
257 | | - (llm-providers.openai/create-response! |
258 | | - {:model real-model |
259 | | - :instructions instructions |
260 | | - :user-messages user-messages |
261 | | - :past-messages [] |
262 | | - :tools [] |
263 | | - :web-search false |
264 | | - :max-output-tokens max-output-tokens |
265 | | - :reason? reason? |
266 | | - :extra-payload extra-payload |
267 | | - :api-url api-url |
268 | | - :api-key api-key |
269 | | - :auth-type provider-auth-type} |
270 | | - nil) |
271 | | - |
272 | | - (= "github-copilot" provider) |
273 | | - (llm-providers.openai-chat/chat-completion! |
274 | | - {:model real-model |
275 | | - :instructions instructions |
276 | | - :user-messages user-messages |
277 | | - :past-messages [] |
278 | | - :tools [] |
279 | | - :max-output-tokens max-output-tokens |
280 | | - :reason? reason? |
281 | | - :extra-payload extra-payload |
282 | | - :api-url api-url |
283 | | - :api-key api-key |
284 | | - :extra-headers {"openai-intent" "conversation-panel" |
285 | | - "x-request-id" (str (random-uuid)) |
286 | | - "vscode-sessionid" "" |
287 | | - "vscode-machineid" "" |
288 | | - "Copilot-Vision-Request" "true" |
289 | | - "copilot-integration-id" "vscode-chat"}} |
290 | | - nil) |
291 | | - |
292 | | - (= "google" provider) |
293 | | - (llm-providers.openai-chat/chat-completion! |
294 | | - {:model real-model |
295 | | - :instructions instructions |
296 | | - :user-messages user-messages |
297 | | - :max-output-tokens max-output-tokens |
298 | | - :reason? reason? |
299 | | - :past-messages [] |
300 | | - :tools [] |
301 | | - :thinking-tag "thought" |
302 | | - :extra-payload (merge {:parallel_tool_calls false} |
303 | | - (when reason? |
304 | | - {:extra_body {:google {:thinking_config {:include_thoughts true}}}}) |
305 | | - extra-payload) |
306 | | - :api-url api-url |
307 | | - :api-key api-key} |
308 | | - nil) |
309 | | - |
310 | | - model-config |
311 | | - (let [provider-fn (case (:api provider-config) |
312 | | - "openai-responses" llm-providers.openai/create-response! |
313 | | - "openai-chat" llm-providers.openai-chat/chat-completion! |
314 | | - {:error-message (format "Unknown model %s for provider %s" (:api provider-config) provider)}) |
315 | | - url-relative-path (:completionUrlRelativePath provider-config)] |
316 | | - (provider-fn |
317 | | - {:model real-model |
318 | | - :instructions instructions |
319 | | - :web-search false |
320 | | - :max-output-tokens max-output-tokens |
321 | | - :user-messages user-messages |
322 | | - :past-messages [] |
323 | | - :tools [] |
324 | | - :reason? reason? |
325 | | - :extra-payload extra-payload |
326 | | - :url-relative-path url-relative-path |
327 | | - :api-url api-url |
328 | | - :api-key api-key} |
329 | | - nil)) |
330 | | - |
331 | | - :else |
332 | | - {:error-message (format "ECA Unsupported model %s for provider %s" model provider)}) |
333 | | - (catch Exception e |
334 | | - (logger/warn logger-tag "Error completing: %s" (.getMessage e)) |
335 | | - {:error-message (.getMessage e)})))) |
336 | | - |
337 | | -(defn simple-prompt |
338 | | - [{:keys [provider model model-capabilities instructions |
339 | | - prompt user-messages config tools provider-auth]}] |
340 | | - (let [result-p (promise) |
341 | | - output* (atom "")] |
342 | | - (chat! |
343 | | - {:provider provider |
| 217 | +(defn async-prompt! [{:keys [provider model model-capabilities instructions user-messages config on-first-response-received |
| 218 | + on-message-received on-error on-prepare-tool-call on-tools-called on-reason on-usage-updated |
| 219 | + past-messages tools provider-auth] |
| 220 | + :or {on-first-response-received identity |
| 221 | + on-message-received identity |
| 222 | + on-error identity |
| 223 | + on-prepare-tool-call identity |
| 224 | + on-tools-called identity |
| 225 | + on-reason identity |
| 226 | + on-usage-updated identity}}] |
| 227 | + (let [first-response-received* (atom false) |
| 228 | + emit-first-message-fn (fn [& args] |
| 229 | + (when-not @first-response-received* |
| 230 | + (reset! first-response-received* true) |
| 231 | + (apply on-first-response-received args))) |
| 232 | + on-message-received-wrapper (fn [& args] |
| 233 | + (apply emit-first-message-fn args) |
| 234 | + (apply on-message-received args)) |
| 235 | + on-reason-wrapper (fn [& args] |
| 236 | + (apply emit-first-message-fn args) |
| 237 | + (apply on-reason args)) |
| 238 | + on-prepare-tool-call-wrapper (fn [& args] |
| 239 | + (apply emit-first-message-fn args) |
| 240 | + (apply on-prepare-tool-call args)) |
| 241 | + on-error-wrapper (fn [{:keys [exception] :as args}] |
| 242 | + (when-not (:silent? (ex-data exception)) |
| 243 | + (logger/error args) |
| 244 | + (on-error args)))] |
| 245 | + (prompt! |
| 246 | + {:sync? false |
| 247 | + :provider provider |
344 | 248 | :model model |
345 | 249 | :model-capabilities model-capabilities |
346 | 250 | :instructions instructions |
347 | 251 | :tools tools |
348 | 252 | :provider-auth provider-auth |
349 | | - :past-messages [] |
350 | | - :user-messages (or user-messages |
351 | | - [{:role "user" :content [{:type :text :text prompt}]}]) |
352 | | - :config config |
353 | | - :on-message-received (fn [{:keys [type] :as msg}] |
354 | | - (case type |
355 | | - :text (swap! output* str (:text msg)) |
356 | | - :finish (deliver result-p @output*) |
357 | | - nil)) |
358 | | - :on-error (fn [_] |
359 | | - (deliver result-p nil))}) |
360 | | - result-p)) |
| 253 | + :past-messages past-messages |
| 254 | + :user-messages user-messages |
| 255 | + :on-message-received on-message-received-wrapper |
| 256 | + :on-prepare-tool-call on-prepare-tool-call-wrapper |
| 257 | + :on-tools-called on-tools-called |
| 258 | + :on-usage-updated on-usage-updated |
| 259 | + :on-reason on-reason-wrapper |
| 260 | + :on-error on-error-wrapper |
| 261 | + :config config}))) |
| 262 | + |
| 263 | +(defn sync-prompt! |
| 264 | + [{:keys [provider model model-capabilities instructions |
| 265 | + prompt past-messages user-messages config tools provider-auth]}] |
| 266 | + (prompt! |
| 267 | + {:sync? true |
| 268 | + :provider provider |
| 269 | + :model model |
| 270 | + :model-capabilities model-capabilities |
| 271 | + :instructions instructions |
| 272 | + :tools tools |
| 273 | + :provider-auth provider-auth |
| 274 | + :past-messages past-messages |
| 275 | + :user-messages (or user-messages |
| 276 | + [{:role "user" :content [{:type :text :text prompt}]}]) |
| 277 | + :config config |
| 278 | + :on-error identity})) |
0 commit comments