branch: elpa/gptel commit 135063383230d6ba341e18d32efae030cadc6d6a Author: Karthik Chikmagalur <karthikchikmaga...@gmail.com> Commit: Karthik Chikmagalur <karthikchikmaga...@gmail.com>
gptel: Fix dispatch on prompt types in gptel--parse-list `gptel-request' accepts two kinds of prompt lists as arguments -- a list of strings and a list of lists/cons cells. (The second kind is currently experimental and undocumented.) In `gptel--parse-list', we distinguish between them by checking if the car of the prompt is a string. But the car can also be nil, and this check fails. Fix by checking if the car of the prompts list is a cons instead. * gptel-anthropic.el (gptel--parse-list): Make the change. * gptel-gemini.el (gptel--parse-list): Make the change. * gptel-ollama.el (gptel--parse-list): Make the change. * gptel-openai.el (gptel--parse-list): Make the change. --- gptel-anthropic.el | 54 +++++++++++++++++++++++++++--------------------------- gptel-gemini.el | 52 ++++++++++++++++++++++++++-------------------------- gptel-ollama.el | 46 +++++++++++++++++++++++----------------------- gptel-openai.el | 54 +++++++++++++++++++++++++++--------------------------- 4 files changed, 103 insertions(+), 103 deletions(-) diff --git a/gptel-anthropic.el b/gptel-anthropic.el index fcc2f67543..0e9b8743ca 100644 --- a/gptel-anthropic.el +++ b/gptel-anthropic.el @@ -314,33 +314,33 @@ TOOL-USE is a list of plists containing tool names, arguments and call results." (cl-defmethod gptel--parse-list ((backend gptel-anthropic) prompt-list) (let ((full-prompt - (if (stringp (car prompt-list)) - (cl-loop for text in prompt-list ; Simple format, list of strings - for role = t then (not role) - if text - collect (list :role (if role "user" "assistant") - :content `[(:type "text" :text ,text)])) - (let ((prompts)) - (dolist (entry prompt-list) ; Advanced format, list of lists - (pcase entry - (`(prompt . ,msg) - (push (list :role "user" - :content `[(:type "text" :text ,(or (car-safe msg) msg))]) - prompts)) - (`(response . ,msg) - (push (list :role "assistant" - :content `[(:type "text" :text ,(or (car-safe msg) msg))]) - prompts)) - (`(tool . ,call) - (unless (plist-get call :id) - (plist-put call :id (gptel--anthropic-format-tool-id nil))) - (push (list :role "assistant" - :content `[( :type "tool_use" :id ,(plist-get call :id) - :name ,(plist-get call :name) - :input ,(plist-get call :args))]) - prompts) - (push (gptel--parse-tool-results backend (list (cdr entry))) prompts)))) - (nreverse prompts))))) + (if (consp (car prompt-list)) + (let ((prompts)) + (dolist (entry prompt-list) ; Advanced format, list of lists + (pcase entry + (`(prompt . ,msg) + (push (list :role "user" + :content `[(:type "text" :text ,(or (car-safe msg) msg))]) + prompts)) + (`(response . ,msg) + (push (list :role "assistant" + :content `[(:type "text" :text ,(or (car-safe msg) msg))]) + prompts)) + (`(tool . ,call) + (unless (plist-get call :id) + (plist-put call :id (gptel--anthropic-format-tool-id nil))) + (push (list :role "assistant" + :content `[( :type "tool_use" :id ,(plist-get call :id) + :name ,(plist-get call :name) + :input ,(plist-get call :args))]) + prompts) + (push (gptel--parse-tool-results backend (list (cdr entry))) prompts)))) + (nreverse prompts)) + (cl-loop for text in prompt-list ; Simple format, list of strings + for role = t then (not role) + if text + collect (list :role (if role "user" "assistant") + :content `[(:type "text" :text ,text)]))))) ;; cache messages if required: add cache_control to the last message (when (and (or (eq gptel-cache t) (memq 'message gptel-cache)) (gptel--model-capable-p 'cache)) diff --git a/gptel-gemini.el b/gptel-gemini.el index abd0e307e0..6b4cdb7314 100644 --- a/gptel-gemini.el +++ b/gptel-gemini.el @@ -228,32 +228,32 @@ See generic implementation for full documentation." (plist-put data :contents (vconcat prompts (list new-prompt))))) (cl-defmethod gptel--parse-list ((backend gptel-gemini) prompt-list) - (if (stringp (car prompt-list)) - (cl-loop for text in prompt-list ; Simple format, list of strings - for role = t then (not role) - if text - if role - collect (list :role "user" :parts `[(:text ,text)]) into prompts - else collect (list :role "model" :parts `(:text ,text)) into prompts - finally return prompts) - (let ((full-prompt)) ; Advanced format, list of lists - (dolist (entry prompt-list) - (pcase entry - (`(prompt . ,msg) - (push (list :role "user" - :parts `[(:text ,(or (car-safe msg) msg))]) - full-prompt)) - (`(response . ,msg) - (push (list :role "model" - :parts `[(:text ,(or (car-safe msg) msg))]) - full-prompt)) - (`(tool . ,call) - (push (list :role "model" - :parts (vector `(:functionCall ( :name ,(plist-get call :name) - :args ,(plist-get call :args))))) - full-prompt) - (push (gptel--parse-tool-results backend (list (cdr entry))) full-prompt)))) - (nreverse full-prompt)))) + (if (consp (car prompt-list)) + (let ((full-prompt)) ; Advanced format, list of lists + (dolist (entry prompt-list) + (pcase entry + (`(prompt . ,msg) + (push (list :role "user" + :parts `[(:text ,(or (car-safe msg) msg))]) + full-prompt)) + (`(response . ,msg) + (push (list :role "model" + :parts `[(:text ,(or (car-safe msg) msg))]) + full-prompt)) + (`(tool . ,call) + (push (list :role "model" + :parts (vector `(:functionCall ( :name ,(plist-get call :name) + :args ,(plist-get call :args))))) + full-prompt) + (push (gptel--parse-tool-results backend (list (cdr entry))) full-prompt)))) + (nreverse full-prompt)) + (cl-loop for text in prompt-list ; Simple format, list of strings + for role = t then (not role) + if text + if role + collect (list :role "user" :parts `[(:text ,text)]) into prompts + else collect (list :role "model" :parts `(:text ,text)) into prompts + finally return prompts))) (cl-defmethod gptel--parse-buffer ((backend gptel-gemini) &optional max-entries) (let ((prompts) (prev-pt (point)) diff --git a/gptel-ollama.el b/gptel-ollama.el index 51d265d520..1253d27601 100644 --- a/gptel-ollama.el +++ b/gptel-ollama.el @@ -136,29 +136,29 @@ Store response metadata in state INFO." ;; handled by its defgeneric implementation (cl-defmethod gptel--parse-list ((backend gptel-ollama) prompt-list) - (if (stringp (car prompt-list)) - (cl-loop for text in prompt-list ; Simple format, list of strings - for role = t then (not role) - if text collect - (list :role (if role "user" "assistant") :content text)) - (let ((full-prompt)) ; Advanced format, list of lists - (dolist (entry prompt-list) - (pcase entry - (`(prompt . ,msg) - (push (list :role "user" :content (or (car-safe msg) msg)) - full-prompt)) - (`(response . ,msg) - (push (list :role "assistant" :content (or (car-safe msg) msg)) - full-prompt)) - (`(tool . ,call) - (push (list :role "assistant" - :content "" - :tool_calls `[(:function (:name ,(plist-get call :name) - :arguments ,(plist-get call :args)))]) - full-prompt) - (push (car (gptel--parse-tool-results backend (list (cdr entry)))) - full-prompt)))) - (nreverse full-prompt)))) + (if (consp (car prompt-list)) + (let ((full-prompt)) ; Advanced format, list of lists + (dolist (entry prompt-list) + (pcase entry + (`(prompt . ,msg) + (push (list :role "user" :content (or (car-safe msg) msg)) + full-prompt)) + (`(response . ,msg) + (push (list :role "assistant" :content (or (car-safe msg) msg)) + full-prompt)) + (`(tool . ,call) + (push (list :role "assistant" + :content "" + :tool_calls `[(:function (:name ,(plist-get call :name) + :arguments ,(plist-get call :args)))]) + full-prompt) + (push (car (gptel--parse-tool-results backend (list (cdr entry)))) + full-prompt)))) + (nreverse full-prompt)) + (cl-loop for text in prompt-list ; Simple format, list of strings + for role = t then (not role) + if text collect + (list :role (if role "user" "assistant") :content text)))) (cl-defmethod gptel--parse-buffer ((backend gptel-ollama) &optional max-entries) (let ((prompts) (prev-pt (point)) diff --git a/gptel-openai.el b/gptel-openai.el index d77444a2cd..5de95d709d 100644 --- a/gptel-openai.el +++ b/gptel-openai.el @@ -350,33 +350,33 @@ If the ID has the format used by a different backend, use as-is." ;; is handled by its defgeneric implementation (cl-defmethod gptel--parse-list ((backend gptel-openai) prompt-list) - (if (stringp (car prompt-list)) - (cl-loop for text in prompt-list ; Simple format, list of strings - for role = t then (not role) - if text collect - (list :role (if role "user" "assistant") :content text)) - (let ((full-prompt)) ; Advanced format, list of lists - (dolist (entry prompt-list) - (pcase entry - (`(prompt . ,msg) - (push (list :role "user" :content (or (car-safe msg) msg)) full-prompt)) - (`(response . ,msg) - (push (list :role "assistant" :content (or (car-safe msg) msg)) full-prompt)) - (`(tool . ,call) - (unless (plist-get call :id) - (plist-put call :id (gptel--openai-format-tool-id nil))) - (push - (list - :role "assistant" - :tool_calls - (vector - (list :type "function" - :id (plist-get call :id) - :function `( :name ,(plist-get call :name) - :arguments ,(gptel--json-encode (plist-get call :args)))))) - full-prompt) - (push (car (gptel--parse-tool-results backend (list (cdr entry)))) full-prompt)))) - (nreverse full-prompt)))) + (if (consp (car prompt-list)) + (let ((full-prompt)) ; Advanced format, list of lists + (dolist (entry prompt-list) + (pcase entry + (`(prompt . ,msg) + (push (list :role "user" :content (or (car-safe msg) msg)) full-prompt)) + (`(response . ,msg) + (push (list :role "assistant" :content (or (car-safe msg) msg)) full-prompt)) + (`(tool . ,call) + (unless (plist-get call :id) + (plist-put call :id (gptel--openai-format-tool-id nil))) + (push + (list + :role "assistant" + :tool_calls + (vector + (list :type "function" + :id (plist-get call :id) + :function `( :name ,(plist-get call :name) + :arguments ,(gptel--json-encode (plist-get call :args)))))) + full-prompt) + (push (car (gptel--parse-tool-results backend (list (cdr entry)))) full-prompt)))) + (nreverse full-prompt)) + (cl-loop for text in prompt-list ; Simple format, list of strings + for role = t then (not role) + if text collect + (list :role (if role "user" "assistant") :content text)))) (cl-defmethod gptel--parse-buffer ((backend gptel-openai) &optional max-entries) (let ((prompts) (prev-pt (point))