Function: gptel-request

gptel-request is a natively compiled function defined in gptel-request.el.

Signature

(gptel-request &optional PROMPT &key CALLBACK (BUFFER (current-buffer)) POSITION CONTEXT DRY-RUN (STREAM nil) (IN-PLACE nil) (SYSTEM gptel-system-prompt) SCHEMA TRANSFORMS (FSM (gptel-make-fsm)))

Documentation

Request a response from the gptel-backend for PROMPT.

The request is asynchronous, this function returns immediately.

If PROMPT is
- a string, it is used to create a full prompt suitable for
  sending to the LLM.
- A list of strings, it is interpreted as a conversation, i.e. a
  series of alternating user prompts and LLM responses.
  ("user msg 1" "llm msg 1" "user msg 2" "llm msg 2" ...)
- nil but region is active, the region contents are used.
- nil, the current buffer's contents up to (point) are used.
  Previous responses from the LLM are identified as responses.

Keyword arguments:

CALLBACK, if supplied, is a function of two arguments, called with the RESPONSE (usually a string) and INFO (a plist):

 (funcall CALLBACK RESPONSE INFO)

RESPONSE is

- A string if the request was successful
- nil if there was no response or an error.

These are the only two cases you typically need to consider, unless you need to clean up after aborted requests, use LLM tools, handle "reasoning" content specially or stream responses (see STREAM). In these cases, RESPONSE can be

- The symbol abort if the request is aborted, see gptel-abort.

- A cons cell of the form

  (tool-call . ((TOOL ARGS CB) ...))

  where TOOL is a gptel-tool struct, ARGS is a plist of
  arguments, and CB is a function for handling the results. You
  can call CB with the result of calling the tool to continue the
  request.

- A cons cell of the form

  (tool-result . ((TOOL ARGS RESULT) ...))

  where TOOL is a gptel-tool struct, ARGS is a plist of
  arguments, and RESULT was returned from calling the tool
  function.

- A cons cell of the form

  (reasoning . text)

  where text is the contents of the reasoning block. (Also see
  STREAM if you are using streaming.)

See gptel--insert-response for an example callback handling all cases.

The INFO plist has (at least) the following keys:
:data - The request data included with the query
:position - marker where the response will (nominally) be inserted.
                Of course, the insertion is left to the CALLBACK.
:buffer - The buffer current when the request was sent,
                unless BUFFER is specified.
:status - Short string describing the result of the request,
                including possible HTTP errors.

Example of a callback that messages the user with the response and info:

 (lambda (response info)
  (if (stringp response)
      (let ((posn (marker-position (plist-get info :position)))
            (buf (buffer-name (plist-get info :buffer))))
        (message "Response for request from %S at %d: %s"
                 buf posn response))
    (message "gptel-request failed with message: %s"
             (plist-get info :status))))

Or, for just the response:

 (lambda (response _)
  ;; Do something with response
  (message (rot13-string response)))

If CALLBACK is omitted, the response is inserted at the point the request was sent.

STREAM is a boolean that determines if the response should be streamed, as in gptel-stream. If the model or the backend does not support streaming, this will be ignored.

When streaming responses

- CALLBACK will be called repeatedly with each RESPONSE text
  chunk (a string) as it is received.
- When the HTTP request ends successfully, CALLBACK will be
  called with a RESPONSE argument of t to indicate success.
- Similarly, CALLBACK will be called with
  (reasoning . text-chunk) for each reasoning chunk, and
  (reasoning . t) to indicate the end of the reasoning block.

BUFFER and POSITION are the buffer and position (integer or marker) at which the response is inserted. If a CALLBACK is specified, no response is inserted and these arguments are ignored, but they are still available in the INFO plist passed to CALLBACK for you to use.

BUFFER defaults to the current buffer, and POSITION to the value of (point) or (region-end), depending on whether the region is active.

CONTEXT is any additional data needed for the callback to run. It is included in the INFO argument to the callback. Note: This is intended for storing Emacs state to be used by CALLBACK, and unrelated to the context supplied to the LLM.

SYSTEM is the system message or extended chat directive sent to the LLM. This can be a string, a list of strings or a function that returns either; see gptel-directives for more information. If SYSTEM is omitted, the value of gptel-system-prompt in the current buffer is used.

The following keywords are mainly for internal use:

IN-PLACE is a boolean used by the default callback when inserting the response to determine if delimiters are needed between the prompt and the response.

If DRY-RUN is non-nil, do not send the request. Construct and return a state machine object that can be introspected and resumed.

TRANSFORMS is a list of functions used to transform the prompt or query parameters dynamically. Each function is called in a temporary buffer containing the prompt to be sent, and can conditionally modify this buffer. This can include changing the (buffer-local) values of the model, backend or system prompt, or augmenting the prompt with additional information (such as from a RAG engine).

- Synchronous transformers are called with zero or one argument, the
  state machine for the request.

- Asynchronous transformers are called with two arguments, a callback
  and the state machine. It should run the callback after finishing its
  transformation.

See gptel-prompt-transform-functions for more.

If provided, SCHEMA forces the LLM to generate JSON output. Its value is a JSON schema, which can be provided as
- an elisp object, a nested plist structure.
- A JSON schema serialized to a string
- A shorthand object/array description, see gptel--dispatch-schema-type.
See the manual or the wiki for examples.

Note: SCHEMA is presently experimental and subject to change, and not all providers support structured output.

FSM is the state machine driving the request. This can be used to define a custom request control flow, see gptel-fsm for details. You can safely ignore this -- FSM is an unstable feature and subject to change.

Note:

1. This function is not fully self-contained. Consider
let-binding the parameters gptel-backend, gptel-model, gptel-use-tools and gptel-use-context around calls to it as required.

2. The return value of this function is a state machine that may
be used to rerun or continue the request at a later time.

Source Code

;; Defined in /nix/store/q3r7g81pvghw7a523kjk2k2zih3pfk8z-emacs-packages-deps/share/emacs/site-lisp/elpa/gptel-20261002.545/gptel-request.el
;;; Send gptel requests
(cl-defun gptel-request
    (&optional prompt &key callback
               (buffer (current-buffer))
               position context dry-run
               (stream nil) (in-place nil)
               (system gptel-system-prompt)
               schema transforms (fsm (gptel-make-fsm)))
  "Request a response from the `gptel-backend' for PROMPT.

The request is asynchronous, this function returns immediately.

If PROMPT is
- a string, it is used to create a full prompt suitable for
  sending to the LLM.
- A list of strings, it is interpreted as a conversation, i.e. a
  series of alternating user prompts and LLM responses.
  (\"user msg 1\" \"llm msg 1\" \"user msg 2\" \"llm msg 2\" ...)
- nil but region is active, the region contents are used.
- nil, the current buffer's contents up to (point) are used.
  Previous responses from the LLM are identified as responses.

Keyword arguments:

CALLBACK, if supplied, is a function of two arguments, called
with the RESPONSE (usually a string) and INFO (a plist):

 (funcall CALLBACK RESPONSE INFO)

RESPONSE is

- A string if the request was successful
- nil if there was no response or an error.

These are the only two cases you typically need to consider,
unless you need to clean up after aborted requests, use LLM
tools, handle \"reasoning\" content specially or stream
responses (see STREAM).  In these cases, RESPONSE can be

- The symbol `abort' if the request is aborted, see `gptel-abort'.

- A cons cell of the form

  (tool-call . ((TOOL ARGS CB) ...))

  where TOOL is a gptel-tool struct, ARGS is a plist of
  arguments, and CB is a function for handling the results.  You
  can call CB with the result of calling the tool to continue the
  request.

- A cons cell of the form

  (tool-result . ((TOOL ARGS RESULT) ...))

  where TOOL is a gptel-tool struct, ARGS is a plist of
  arguments, and RESULT was returned from calling the tool
  function.

- A cons cell of the form

  (reasoning . text)

  where text is the contents of the reasoning block.  (Also see
  STREAM if you are using streaming.)

See `gptel--insert-response' for an example callback handling all
cases.

The INFO plist has (at least) the following keys:
:data         - The request data included with the query
:position     - marker where the response will (nominally) be inserted.
                Of course, the insertion is left to the CALLBACK.
:buffer       - The buffer current when the request was sent,
                unless BUFFER is specified.
:status       - Short string describing the result of the request,
                including possible HTTP errors.

Example of a callback that messages the user with the response
and info:

 (lambda (response info)
  (if (stringp response)
      (let ((posn (marker-position (plist-get info :position)))
            (buf  (buffer-name (plist-get info :buffer))))
        (message \"Response for request from %S at %d: %s\"
                 buf posn response))
    (message \"gptel-request failed with message: %s\"
             (plist-get info :status))))

Or, for just the response:

 (lambda (response _)
  ;; Do something with response
  (message (rot13-string response)))

If CALLBACK is omitted, the response is inserted at the point the
request was sent.

STREAM is a boolean that determines if the response should be
streamed, as in `gptel-stream'.  If the model or the backend does
not support streaming, this will be ignored.

When streaming responses

- CALLBACK will be called repeatedly with each RESPONSE text
  chunk (a string) as it is received.
- When the HTTP request ends successfully, CALLBACK will be
  called with a RESPONSE argument of t to indicate success.
- Similarly, CALLBACK will be called with
  (reasoning . text-chunk) for each reasoning chunk, and
  (reasoning . t) to indicate the end of the reasoning block.

BUFFER and POSITION are the buffer and position (integer or
marker) at which the response is inserted.  If a CALLBACK is
specified, no response is inserted and these arguments are
ignored, but they are still available in the INFO plist passed
to CALLBACK for you to use.

BUFFER defaults to the current buffer, and POSITION to the value
of (point) or (region-end), depending on whether the region is
active.

CONTEXT is any additional data needed for the callback to run. It
is included in the INFO argument to the callback.
Note: This is intended for storing Emacs state to be used by
CALLBACK, and unrelated to the context supplied to the LLM.

SYSTEM is the system message or extended chat directive sent to
the LLM.  This can be a string, a list of strings or a function
that returns either; see `gptel-directives' for more
information. If SYSTEM is omitted, the value of
`gptel-system-prompt' in the current buffer is used.

The following keywords are mainly for internal use:

IN-PLACE is a boolean used by the default callback when inserting
the response to determine if delimiters are needed between the
prompt and the response.

If DRY-RUN is non-nil, do not send the request.  Construct and
return a state machine object that can be introspected and
resumed.

TRANSFORMS is a list of functions used to transform the prompt or query
parameters dynamically.  Each function is called in a temporary buffer
containing the prompt to be sent, and can conditionally modify this
buffer.  This can include changing the (buffer-local) values of the
model, backend or system prompt, or augmenting the prompt with
additional information (such as from a RAG engine).

- Synchronous transformers are called with zero or one argument, the
  state machine for the request.

- Asynchronous transformers are called with two arguments, a callback
  and the state machine.  It should run the callback after finishing its
  transformation.

See `gptel-prompt-transform-functions' for more.

If provided, SCHEMA forces the LLM to generate JSON output.  Its value
is a JSON schema, which can be provided as
- an elisp object, a nested plist structure.
- A JSON schema serialized to a string
- A shorthand object/array description, see `gptel--dispatch-schema-type'.
See the manual or the wiki for examples.

Note: SCHEMA is presently experimental and subject to change, and not
all providers support structured output.

FSM is the state machine driving the request.  This can be used
to define a custom request control flow, see `gptel-fsm' for
details.  You can safely ignore this -- FSM is an unstable
feature and subject to change.

Note:

1. This function is not fully self-contained.  Consider
let-binding the parameters `gptel-backend', `gptel-model',
`gptel-use-tools' and `gptel-use-context' around calls to it as
required.

2. The return value of this function is a state machine that may
be used to rerun or continue the request at a later time."
  (declare (indent 1))
  ;; TODO Remove this check in version 1.0
  (gptel--sanitize-model)
  (let* ((start-marker
          (cond
           ((null position)
            (if (use-region-p)
                (set-marker (make-marker) (region-end))
              (gptel--at-word-end (point-marker))))
           ((markerp position) position)
           ((integerp position)
            (set-marker (make-marker) position buffer))))
         (gptel-system-prompt system) ;Required for copying into the prompt buffer
         (gptel--schema schema)
         (prompt-buffer
          (cond                       ;prompt from buffer or explicitly supplied
           ((null prompt)           ;Send text up to end of word (for evil-mode users)
            (with-current-buffer buffer
              (gptel--create-prompt-buffer (gptel--at-word-end (point)))))
           ((stringp prompt)
            (gptel--with-buffer-copy buffer nil nil
              (insert prompt)
              (setq major-mode 'fundamental-mode) ;Avoid mode-specific behavior
              (current-buffer)))
           ((consp prompt)
            ;; (gptel--parse-list gptel-backend prompt)
            (gptel--with-buffer-copy buffer nil nil
              ;; TEMP Decide on the annotated prompt-list format
              (gptel--parse-list-and-insert prompt)
              (setq major-mode 'fundamental-mode) ;Avoid mode-specific behavior
              (current-buffer)))))
         (info (list :data prompt-buffer
                     :buffer buffer
                     :position start-marker)))
    (when transforms (plist-put info :transforms transforms))
    ;; Evaluate function valued system prompts in the request buffer, but then
    ;; set it in the prompt construction buffer
    (when-let* ((system (buffer-local-value 'gptel-system-prompt prompt-buffer))
                ((functionp system)))
      (let ((system-list (with-current-buffer buffer
                           (gptel--parse-directive system 'raw))))
        (with-current-buffer prompt-buffer ;and then set the result in the prompt buffer
          (setq gptel-system-prompt        ;guaranteed to be buffer-local
                ;; Retain single-part system messages as strings to avoid surprises
                ;; when applying presets
                (if (cdr system-list) system-list (car system-list))))))
    (when stream (plist-put info :stream stream))
    ;; This context should not be confused with the context aggregation context!
    (when callback (plist-put info :callback callback))
    (when context (plist-put info :context context))
    (when in-place (plist-put info :in-place in-place))
    ;; Add info to state machine context
    (when dry-run (plist-put info :dry-run dry-run))
    (setf (gptel-fsm-info fsm) info))

  ;; TEMP: Augment in separate let block for now.  Are we overcapturing?
  ;; FIXME(augment): Call augmentors with INFO, not FSM
  (let ((info (gptel-fsm-info fsm)))
    (with-current-buffer (plist-get info :data)
      (setq-local gptel-prompt-transform-functions (plist-get info :transforms))
      ;; Preset has highest priority because it can change prompt-transform-functions
      (when (memq 'gptel--transform-apply-preset gptel-prompt-transform-functions)
        (gptel--transform-apply-preset fsm)
        (setq gptel-prompt-transform-functions ;avoid mutation, copy transforms
              (remq 'gptel--transform-apply-preset gptel-prompt-transform-functions)))
      (let ((augment-total              ;act like a hook, count total
             (if (memq t gptel-prompt-transform-functions)
                 (length
                  (setq gptel-prompt-transform-functions
                        (nconc (remq t gptel-prompt-transform-functions)
                               (default-value 'gptel-prompt-transform-functions))))
               (length gptel-prompt-transform-functions)))
            (augment-idx 0))
        (if (null gptel-prompt-transform-functions)
            (gptel--realize-query fsm)
          ;; FIXME(request-lib): Cannot use gptel--update-status from this file
          ;; (with-current-buffer (plist-get info :buffer) ;Apply prompt transformations
          ;;   (gptel--update-status " Augmenting..." 'mode-line-emphasis))

          ;; FIXME(augment): This needs to be converted into a linear callback
          ;; chain to avoid race conditions with multiple async augmentors.
          (run-hook-wrapped
           'gptel-prompt-transform-functions
           (lambda (func fsm-arg)
             (with-current-buffer (plist-get info :data)
               (goto-char (point-max))
               (if (= (car (func-arity func)) 2) ;async augmentor
                   (funcall func (lambda ()
                                   (cl-incf augment-idx)
                                   (when (>= augment-idx augment-total) ;All augmentors have run
                                     (gptel--realize-query fsm-arg)))
                            fsm-arg)
                 (if (= (car (func-arity func)) 0)
                     (funcall func)
                   (funcall func fsm-arg)) ;sync augmentor
                 (cl-incf augment-idx)
                 (when (>= augment-idx augment-total) ;All augmentors have run
                   (gptel--realize-query fsm-arg))))
             nil)           ;always return nil so run-hook-wrapped doesn't abort
           fsm)))))
  fsm)