Fix Ollama streaming: terminate TCP loop and return status

ober

a14acc20fd95650392f63589d60b4a6df66c0120

diff --git a/lib/jcode/provider/provider.sls b/lib/jcode/provider/provider.sls
index faa0de0..70e9c6b 100644
--- a/lib/jcode/provider/provider.sls
+++ b/lib/jcode/provider/provider.sls
@@ -331,8 +331,10 @@
                          (let ([c (peek-char in)])
                            (unless (eof-object? c)
                              (let ([line (port-read-line in)])
-                               (line-cb line)
-                               (loop)))))))
+                               (unless (equal? line "0")
+                                 (line-cb line)
+                                 (loop))))))
+                       status))
                    (lambda () (close-port in) (close-port out))))))))
   (def (openai-chat provider messages tools)
        (let* ([url (string-append
@@ -734,12 +736,27 @@
                                                                  choice
                                                                  "delta"))])
                                               (when delta
-                                                (let ([content (hash-get
-                                                                 delta
-                                                                 "content")])
-                                                  (when (and content
-                                                             (not (eq? content
-                                                                       (void))))
+                                                (let ([content (let ([c (hash-get
+                                                                          delta
+                                                                          "content")]
+                                                                     [r (hash-get
+                                                                          delta
+                                                                          "reasoning")])
+                                                                 (if (and c
+                                                                          (string?
+                                                                            c)
+                                                                          (> (string-length
+                                                                               c)
+                                                                             0))
+                                                                     c
+                                                                     (and r
+                                                                          (string?
+                                                                            r)
+                                                                          (> (string-length
+                                                                               r)
+                                                                             0)
+                                                                          r)))])
+                                                  (when content
                                                     (put-string
                                                       text-acc
                                                       content)
diff --git a/src/jcode/provider/provider.ss b/src/jcode/provider/provider.ss
index abae66d..493f2ab 100644
--- a/src/jcode/provider/provider.ss
+++ b/src/jcode/provider/provider.ss
@@ -15,7 +15,9 @@
         :std/misc/string
         :std/misc/retry
         :jcode/core/log
-        :jcode/core/message)
+        :jcode/core/message
+        :jerboa/core
+        :jerboa/runtime)
 
 (def logger (make-logger "provider"))
 
@@ -316,13 +318,15 @@
                   (let ((body (port-read-all in)))
                     (error 'jcode-http-post-stream
                       (format "API error ~a: ~a" status body))))
-                ;; Read SSE lines
+                ;; Read SSE lines until EOF or chunked terminator
                 (let loop ()
                   (let ((c (peek-char in)))
                     (unless (eof-object? c)
                       (let ((line (port-read-line in)))
-                        (line-cb line)
-                        (loop)))))))
+                        (unless (equal? line "0")
+                          (line-cb line)
+                          (loop))))))
+                status))
             (lambda ()
               (close-port in)
               (close-port out))))))))
@@ -657,9 +661,13 @@
                           (choice  (and (pair? choices) (car choices)))
                           (delta   (and choice (hash-get choice "delta"))))
                      (when delta
-                       ;; Text content token
-                       (let ((content (hash-get delta "content")))
-                         (when (and content (not (eq? content (void))))
+                       ;; Text content token (fall back to reasoning for models like Gemma4)
+                       (let ((content (let ((c (hash-get delta "content"))
+                                           (r (hash-get delta "reasoning")))
+                                        (if (and c (string? c) (> (string-length c) 0))
+                                          c
+                                          (and r (string? r) (> (string-length r) 0) r)))))
+                         (when content
                            (put-string text-acc content)
                            (token-cb content)))
                        ;; Tool call fragments