From 0109d0d1c067aee8fc3228f1f34d766043258cc3 Mon Sep 17 00:00:00 2001 From: Karthik Chikmagalur Date: Wed, 8 Nov 2023 13:29:39 -0800 Subject: [PATCH] gptel: API agnostic response error handling * gptel.el (gptel--url-get-response, gptel--url-parse-response): - When the query fails, the error message format (in the JSON) differs between APIs. Ultimately it may be required to dispatch error handling via a generic function, but for now: try to make the error handling API agnostic. - Mention the backend name in the error message. Pass the backend to the (non-streaming response) parsers to be able to do this. * gptel-curl.el (gptel-curl--stream-cleanup, gptel-curl--parse-response): Same changes. --- gptel-curl.el | 36 +++++++++++++++++++++++++----------- gptel.el | 21 ++++++++++++++------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/gptel-curl.el b/gptel-curl.el index ae4c993..dc0b1f3 100644 --- a/gptel-curl.el +++ b/gptel-curl.el @@ -155,6 +155,9 @@ PROCESS and _STATUS are process parameters." (clone-buffer "*gptel-error*" 'show))) (let* ((info (alist-get process gptel-curl--process-alist)) (gptel-buffer (plist-get info :buffer)) + (backend-name + (gptel-backend-name + (buffer-local-value 'gptel-backend gptel-buffer))) (tracking-marker (plist-get info :tracking-marker)) (start-marker (plist-get info :position)) (http-status (plist-get info :http-status)) @@ -177,14 +180,16 @@ PROCESS and _STATUS are process parameters." (json-object-type 'plist) (response (progn (goto-char header-size) (condition-case nil (json-read) - (json-readtable-error 'json-read-error))))) + (json-readtable-error 'json-read-error)))) + (error-data (plist-get response :error))) (cond - ((plist-get response :error) - (let* ((error-plist (plist-get response :error)) - (error-msg (plist-get error-plist :message)) - (error-type (plist-get error-plist :type))) - (message "ChatGPT error: (%s) %s" http-msg error-msg) - (setq http-msg (concat "(" http-msg ") " (string-trim error-type))))) + (error-data + (if (stringp error-data) + (message "%s error: (%s) %s" backend-name http-msg error-data) + (when-let ((error-msg (plist-get error-data :message))) + (message "%s error: (%s) %s" backend-name http-msg error-msg)) + (when-let ((error-type (plist-get error-data :type))) + (setq http-msg (concat "(" http-msg ") " (string-trim error-type)))))) ((eq response 'json-read-error) (message "ChatGPT error (%s): Malformed JSON in response." http-msg)) (t (message "ChatGPT error (%s): Could not parse HTTP response." http-msg))))) @@ -339,10 +344,19 @@ buffer." (funcall parser nil response proc-info)) http-msg)) ((plist-get response :error) - (let* ((error-plist (plist-get response :error)) - (error-msg (plist-get error-plist :message)) - (error-type (plist-get error-plist :type))) - (list nil (concat "(" http-msg ") " (string-trim error-type)) error-msg))) + (let* ((error-data (plist-get response :error)) + (error-msg (plist-get error-data :message)) + (error-type (plist-get error-data :type)) + (backend-name + (gptel-backend-name + (buffer-local-value 'gptel-backend (plist-get proc-info :buffer))))) + (if (stringp error-data) + (progn (message "%s error: (%s) %s" backend-name http-msg error-data) + (setq error-msg (string-trim error-data))) + (when (stringp error-msg) + (message "%s error: (%s) %s" backend-name http-msg (string-trim error-msg))) + (when error-type (setq http-msg (concat "(" http-msg ") " (string-trim error-type))))) + (list nil (concat "(" http-msg ") " (or error-msg ""))))) ((eq response 'json-read-error) (list nil (concat "(" http-msg ") Malformed JSON in response.") "Malformed JSON in response")) diff --git a/gptel.el b/gptel.el index 95c9fde..6db4eb5 100644 --- a/gptel.el +++ b/gptel.el @@ -855,7 +855,7 @@ the response is inserted into the current buffer after point." (url-retrieve (gptel-backend-url gptel-backend) (lambda (_) (pcase-let ((`(,response ,http-msg ,error) - (gptel--url-parse-response (current-buffer)))) + (gptel--url-parse-response backend (current-buffer)))) (plist-put info :status http-msg) (when error (plist-put info :error error)) (funcall (or callback #'gptel--insert-response) @@ -873,7 +873,7 @@ RESPONSE is the parsed JSON of the response, as a plist. PROC-INFO is a plist with process information and other context. See `gptel-curl--get-response' for its contents.") -(defun gptel--url-parse-response (response-buffer) +(defun gptel--url-parse-response (backend response-buffer) "Parse response in RESPONSE-BUFFER." (when (buffer-live-p response-buffer) (when gptel--debug @@ -892,14 +892,21 @@ See `gptel-curl--get-response' for its contents.") (json-readtable-error 'json-read-error)))))) (cond ((string-match-p "200 OK" http-msg) - (list (string-trim (gptel--parse-response gptel-backend response + (list (string-trim (gptel--parse-response backend response '(:buffer response-buffer))) http-msg)) ((plist-get response :error) - (let* ((error-plist (plist-get response :error)) - (error-msg (plist-get error-plist :message)) - (error-type (plist-get error-plist :type))) - (list nil (concat "(" http-msg ") " error-type) error-msg))) + (let* ((error-data (plist-get response :error)) + (error-msg (plist-get error-data :message)) + (error-type (plist-get error-data :type)) + (backend-name (gptel-backend-name backend))) + (if (stringp error-data) + (progn (message "%s error: (%s) %s" backend-name http-msg error-data) + (setq error-msg (string-trim error-data))) + (when (stringp error-msg) + (message "%s error: (%s) %s" backend-name http-msg (string-trim error-msg))) + (when error-type (setq http-msg (concat "(" http-msg ") " (string-trim error-type))))) + (list nil (concat "(" http-msg ") " (or error-msg ""))))) ((eq response 'json-read-error) (list nil (concat "(" http-msg ") Malformed JSON in response.") "json-read-error")) (t (list nil (concat "(" http-msg ") Could not parse HTTP response.")