Add Ollama support and fix macOS build
ober
769cf5d0f88e32012f2d494cf8abb55e47dd33e3
--- a/lib/jcode/provider/provider.sls +++ b/lib/jcode/provider/provider.sls @@ -60,7 +60,8 @@ [else (error 'provider-default-url "Unknown provider" name)])) (def (provider-chat provider messages tools) - (unless (provider-api-key provider) + (unless (or (provider-api-key provider) + (equal? (provider-name provider) "ollama")) (error 'provider-chat (format "No API key configured for provider '~a'. Set the appropriate env var or add it to jcode.json." @@ -287,7 +288,7 @@ [body (port-read-all in)]) (values status body))) (lambda () (close-port in) (close-port out)))))))) - (def (http-post-stream url headers body-json line-cb) + (def (jcode-http-post-stream url headers body-json line-cb) (let-values ([(scheme host port path) (parse-url-parts url)]) (let ([req (build-http-request "POST" path host headers @@ -303,7 +304,7 @@ [_headers (read-tls-headers conn)]) (unless (= status 200) (let ([body (tls-read-all conn)]) - (error 'http-post-stream + (error 'jcode-http-post-stream (format "API error ~a: ~a" status body)))) (let loop () (let ([line (tls-read-line conn)]) @@ -323,7 +324,7 @@ [_headers (port-read-headers in)]) (unless (= status 200) (let ([body (port-read-all in)]) - (error 'http-post-stream + (error 'jcode-http-post-stream (format "API error ~a: ~a" status body)))) (let loop () (let ([c (peek-char in)]) @@ -676,7 +677,7 @@ "stream-request" `((url . ,url) (body-len . ,(string-length body-json))))] - [http-status (http-post-stream + [http-status (jcode-http-post-stream url headers body-json @@ -703,7 +704,7 @@ (cond [(equal? data "[DONE]") (void)] [else - (let ([json (guard (e [list #t #f]) + (let ([json (guard (e [#t #f]) (string->json-object data))]) (when (and json @@ -856,7 +857,7 @@ [current-idx (make-parameter #f)] [usage-acc (make-hash-table)] [event-type #f]) - (let ([http-status (http-post-stream + (let ([http-status (jcode-http-post-stream url headers (json-object->string body) @@ -883,7 +884,7 @@ (string-length line)))])) lines) (when (and event-type data-str) - (let ([json (guard (e [list #t #f]) + (let ([json (guard (e [#t #f]) (string->json-object data-str))]) (when (and json (hash-table? json)) @@ -1033,7 +1034,8 @@ (or (hash-get usage-acc "output_tokens") 0)) (cons 'cost 0)))))) (def (provider-stream-chat provider messages tools token-cb) - (unless (provider-api-key provider) + (unless (or (provider-api-key provider) + (equal? (provider-name provider) "ollama")) (error 'provider-stream-chat (format "No API key configured for provider '~a'. Set the appropriate env var or add it to jcode.json." --- a/src/jcode/provider/provider.ss +++ b/src/jcode/provider/provider.ss @@ -67,7 +67,8 @@ (else (error 'provider-default-url "Unknown provider" name)))) (def (provider-chat provider messages tools) - (unless (provider-api-key provider) + (unless (or (provider-api-key provider) + (equal? (provider-name provider) "ollama")) (error 'provider-chat (format "No API key configured for provider '~a'. Set the appropriate env var or add it to jcode.json." (provider-name provider)))) @@ -275,7 +276,7 @@ ;; Streaming HTTP POST: calls line-cb with each line of the response body. ;; Used for SSE (Server-Sent Events) streaming from LLM APIs. -(def (http-post-stream url headers body-json line-cb) +(def (jcode-http-post-stream url headers body-json line-cb) (let-values (((scheme host port path) (parse-url-parts url))) (let ((req (build-http-request "POST" path host headers body-json))) (if (equal? scheme "https") @@ -290,7 +291,7 @@ (_headers (read-tls-headers conn))) (unless (= status 200) (let ((body (tls-read-all conn))) - (error 'http-post-stream + (error 'jcode-http-post-stream (format "API error ~a: ~a" status body)))) ;; Read SSE lines until EOF or chunked terminator (let loop () @@ -312,7 +313,7 @@ (_headers (port-read-headers in))) (unless (= status 200) (let ((body (port-read-all in))) - (error 'http-post-stream + (error 'jcode-http-post-stream (format "API error ~a: ~a" status body)))) ;; Read SSE lines (let loop () @@ -631,7 +632,7 @@ (dummy (log-info logger "stream-request" `((url . ,url) (body-len . ,(string-length body-json))))) (http-status - (http-post-stream url headers body-json + (jcode-http-post-stream url headers body-json (lambda (event-str) (when event-str (log-info logger "sse-event" `((data . ,(if (> (string-length event-str) 120) @@ -733,7 +734,7 @@ (usage-acc (make-hash-table)) (event-type #f)) (let ((http-status - (http-post-stream url headers (json-object->string body) + (jcode-http-post-stream url headers (json-object->string body) (lambda (event-str) (when event-str ;; Anthropic SSE uses multiple lines per event: "event: ...\ndata: ..." @@ -820,7 +821,8 @@ ;; provider-stream-chat: stream text tokens to token-cb, accumulate tool calls. ;; Returns (values content-str tool-call-list usage-alist). (def (provider-stream-chat provider messages tools token-cb) - (unless (provider-api-key provider) + (unless (or (provider-api-key provider) + (equal? (provider-name provider) "ollama")) (error 'provider-stream-chat (format "No API key configured for provider '~a'. Set the appropriate env var or add it to jcode.json." (provider-name provider))))