Function: gptel-curl--stream-filter
gptel-curl--stream-filter is a natively compiled function defined in
gptel-request.el.
Signature
(gptel-curl--stream-filter PROCESS OUTPUT)
Documentation
Process OUTPUT from a Curl PROCESS for gptel.
Run the response callback with any completed chunks in OUTPUT.
Source Code
;; Defined in /nix/store/q3r7g81pvghw7a523kjk2k2zih3pfk8z-emacs-packages-deps/share/emacs/site-lisp/elpa/gptel-20261002.545/gptel-request.el
(defun gptel-curl--stream-filter (process output)
"Process OUTPUT from a Curl PROCESS for gptel.
Run the response callback with any completed chunks in OUTPUT."
(let* ((fsm (car (alist-get process gptel--request-alist)))
(proc-info (gptel-fsm-info fsm))
(callback (or (plist-get proc-info :callback)
#'gptel-curl--stream-insert-response)))
(with-current-buffer (process-buffer process)
;; Insert output
(save-excursion
(goto-char (process-mark process))
(insert output)
(set-marker (process-mark process) (point)))
;; Find HTTP status
(unless (plist-get proc-info :http-status)
(save-excursion
(goto-char (point-min))
(when-let* (((not (= (line-end-position) (point-max))))
(http-msg (buffer-substring (line-beginning-position)
(line-end-position)))
(http-status
(save-match-data
(and (string-match "HTTP/[.0-9]+ +\\([0-9]+\\)" http-msg)
(match-string 1 http-msg)))))
(plist-put proc-info :http-status http-status)
(plist-put proc-info :status (string-trim http-msg))
(gptel--fsm-transition fsm)))) ;Response started, WAIT -> TYPE
(when-let* ((http-msg (plist-get proc-info :status))
(http-status (plist-get proc-info :http-status)))
;; Find data chunk(s) and run callback
;; FIXME Handle the case where HTTP 100 is followed by HTTP (not 200) BUG #194
(when (member http-status '("200" "100"))
(let ((response (gptel-curl--parse-stream
(plist-get proc-info :backend) proc-info))
(reasoning-block (plist-get proc-info :reasoning-block)))
;; Depending on the API, there are two modes that reasoning or
;; chain-of-thought content appears: as part of the main response
;; but surrounded by <think>...</think> tags, or as a separate
;; JSON field in the response stream.
;;
;; These cases are handled using two PROC-INFO keys:
;;
;; :reasoning-block is nil before checking for reasoning, 'in when
;; in a reasoning block, t when we reach the end of the block, and
;; 'done afterwards or if no reasoning block is found. This
;; applies to both the modes above.
;;
;; :reasoning contains the reasoning text parsed from the separate
;; JSON field.
;;
;; NOTE: We assume here that the reasoning block always
;; precedes the main response block.
(unless (eq reasoning-block 'done)
(let ((reasoning (plist-get proc-info :reasoning)))
(cond
((stringp reasoning)
;; Obtained from separate JSON field in response
(funcall callback (cons 'reasoning reasoning) proc-info)
(unless reasoning-block ;Record that we're in a reasoning block (#709)
(plist-put proc-info :reasoning-block 'in))
(plist-put proc-info :reasoning nil)) ;Reset for next parsing round
((and (string-blank-p response) ;Defer checking if response is blank
(not reasoning-block))) ;unless we're in a reasoning block already
((and (null reasoning-block) (length> response 0))
;; Obtained from main response stream: reasoning block start
(if-let* ((idx (string-match-p "<think>" response)))
(progn
(when (> idx 0) ;Collect leading whitespace before <think>
(funcall callback (substring response 0 idx) proc-info)
(setq response (substring response idx)))
(setq response (cons 'reasoning response))
(plist-put proc-info :reasoning-block 'in))
(plist-put proc-info :reasoning-block 'done)))
((and (not (eq reasoning-block t)) (length> response 0))
(if-let* ((idx (string-match-p "</think>" response)))
(progn
(funcall callback
(cons 'reasoning (substring response nil (+ idx 8)))
proc-info)
(setq reasoning-block t) ;Signal end of reasoning stream
(plist-put proc-info :reasoning-block t)
(setq response (substring response (+ idx 8))))
(setq response (cons 'reasoning response)))))
(when (eq reasoning-block t) ;End of reasoning block
(funcall callback '(reasoning . t) proc-info)
(plist-put proc-info :reasoning-block 'done))))
(unless (equal response "") ;Response callback
(funcall callback response proc-info))))))))