branch: externals/llm
commit 46feff756f76b29ff544dc7936f20cd5499fc156
Author: Andrew Hyatt <[email protected]>
Commit: Andrew Hyatt <[email protected]>

    Change request functionality to better handle streaming
    
    Streaming does not yet exist in the llm package, this is the first change 
to enable it.
---
 NEWS.org       |  2 ++
 llm-request.el | 44 +++++++++++++++++++++++++++++++++-----------
 2 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/NEWS.org b/NEWS.org
index 484483d2fb..d25a09086b 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -1,2 +1,4 @@
+* Version 0.2.1
+- Changes in how we make and listen to requests, in preparation for streaming 
functionality.
 * Version 0.2
 - Remove the dependency on non-GNU request library.
diff --git a/llm-request.el b/llm-request.el
index 2f57822c78..9a50beaf45 100644
--- a/llm-request.el
+++ b/llm-request.el
@@ -26,12 +26,19 @@
 
 (defun llm-request--content ()
   "From the current buffer, return the content of the response."
-  (goto-char (point-min))
-    (re-search-forward (rx (seq line-start
-                                (zero-or-one control)
-                                line-end)))
-    (forward-line)
-    (buffer-substring-no-properties (point) (point-max)))
+  (message "llm-request--content for buffer %s" (current-buffer))
+  (buffer-substring-no-properties
+   (or (and (boundp 'url-http-end-of-headers) url-http-end-of-headers)
+      (save-match-data
+        (save-excursion
+          (goto-char (point-min))
+          (search-forward "\n\n" nil t)
+          (forward-line)
+          (point))))
+    (point-max)))
+
+(defvar-local llm-request--partial-callback nil
+  "The callback to call when a partial response is received.")
 
 (cl-defun llm-request-sync (url &key headers data timeout)
   "Make a request to URL.  The parsed response will be returned.
@@ -53,7 +60,15 @@ TIMEOUT is the number of seconds to wait for a response."
             (json-read-from-string (llm-request--content)))
         (error "LLM request timed out")))))
 
-(cl-defun llm-request-async (url &key headers data on-success on-error 
on-chunk)
+(defun llm-request--handle-new-content (&rest _)
+  "Handle new content in the current buffer."
+  (save-match-data
+    (save-excursion
+      (with-auto-compression-mode
+        (when llm-request--partial-callback
+          (funcall llm-request--partial-callback (llm-request--content)))))))
+
+(cl-defun llm-request-async (url &key headers data on-success on-error 
on-partial)
   "Make a request to URL.
 Nothing will be returned.
 
@@ -69,9 +84,13 @@ This is required.
 ON-ERROR will be called with the error code and a response-body.
 This is required.
 
-ON-CHUNK will be called with the potentially incomplete response
+ON-PARTIAL will be called with the potentially incomplete response
 body as a string.  This is an optional argument."
   (let ((url-request-method "POST")
+        ;; This is necessary for streaming, otherwise we get gzip'd data that 
is
+        ;; unparseable until the end. The responses should be small enough that
+        ;; this should not be any big loss.
+        (url-mime-encoding-string "identity")
         (url-request-extra-headers
          (append headers '(("Content-Type" . "application/json"))))
         (url-request-data (json-encode data)))
@@ -80,6 +99,8 @@ body as a string.  This is an optional argument."
             url
             ;; For some reason the closure you'd expect did not work here.
             (lambda (_ on-success on-error)
+              ;; No matter what, we need to stop listening for changes.
+              (remove-hook 'after-change-functions 
#'llm-request--handle-new-content t)
               (let ((code (url-http-parse-response)))
                 (if (eq code 200)
                     (funcall on-success (json-read-from-string 
(llm-request--content)))
@@ -87,11 +108,12 @@ body as a string.  This is an optional argument."
                                            (json-read-from-string 
(llm-request--content)))))))
             (list on-success on-error)
             t)))
-      (when on-chunk
+      (when (and buffer on-partial)
         (with-current-buffer buffer
+          (setq llm-request--partial-callback on-partial)
           (add-hook 'after-change-functions
-                    (lambda (_ _ _)
-                      (funcall on-chunk (llm-request--content)))))))))
+                    #'llm-request--handle-new-content
+                    nil t))))))
 
 (provide 'llm-request)
 ;;; llm-request.el ends here

Reply via email to