diff --git a/agent-shell.el b/agent-shell.el index 9ee2920d..48b56946 100644 --- a/agent-shell.el +++ b/agent-shell.el @@ -47,6 +47,7 @@ (require 'dired) (require 'diff) (require 'json) +(require 'mailcap) (require 'map) (unless (require 'markdown-overlays nil 'noerror) (error "Please update 'shell-maker' to v0.91.2 or newer")) @@ -5268,13 +5269,13 @@ Returns list of alists with :start, :end, and :path for each mention." (mimeType . ,(map-elt file :mime-type)) (uri . ,(concat "file://" resolved-path))) content-blocks)) - ;; Text file, small enough, text file capabilities granted and embeddedContext supported + ;; Small enough, text file capabilities granted and embeddedContext supported ;; Use ContentBlock::Resource ((and agent-shell-text-file-capabilities supports-embedded-context (map-elt file :size) (< (map-elt file :size) agent-shell-embed-file-size-limit)) (push `((type . "resource") (resource . ((uri . ,(concat "file://" resolved-path)) - (text . ,(map-elt file :content)) + (,(if (map-elt file :base64-p) 'blob 'text) . ,(map-elt file :content)) (mimeType . ,(map-elt file :mime-type))))) content-blocks)) ;; File too large, no text file capabilities granted or embeddedContext not supported @@ -5311,30 +5312,32 @@ Returns an alist with: :size - file size in bytes :extension - file extension (lowercase) :mime-type - MIME type based on extension - :base64-p - t if content is base64-encoded (binary image), nil otherwise + :base64-p - t if content is base64-encoded (binary file), nil otherwise :content - file content (omitted when SHALLOW is non-nil)" (let* ((ext (downcase (or (file-name-extension file-path) ""))) - (mime-type (or (agent-shell--image-type-to-mime file-path) - "text/plain")) - ;; Only treat supported binary image formats as binary - ;; SVG is XML/text and should not be base64-encoded - ;; API only supports: image/png, image/jpeg, image/gif, image/webp - (is-binary (member mime-type '("image/png" "image/jpeg" "image/gif" "image/webp"))) (file-size (file-attribute-size (file-attributes file-path))) - (content (unless shallow - (with-temp-buffer - (if is-binary - (progn - (insert-file-contents-literally file-path) - (base64-encode-string (buffer-string) t)) - (insert-file-contents file-path) - (buffer-string)))))) - (append (list (cons :size file-size) - (cons :extension ext) - (cons :mime-type mime-type) - (cons :base64-p is-binary)) - (unless shallow - (list (cons :content content)))))) + (mime-type (mailcap-extension-to-mime ext)) + (content-fields + (unless shallow + (let ((raw-content (with-temp-buffer + (set-buffer-multibyte nil) + (insert-file-contents-literally file-path) + (buffer-string))) + ;; Same heuristic that git uses + (is-binary (string-search "\0" raw-content)) + (content (if is-binary + (base64-encode-string raw-content) + (decode-coding-string raw-content 'undecided t)))) + ;; Set a better default MIME type for unknown extensions + ;; based on the content + (unless mime-type + (setq mime-type (if is-binary "application/octet-stream" "text/plain"))) + `((:base64-p . ,is-binary) + (:content . ,content)))))) + `((:size . ,file-size) + (:extension . ,ext) + (:mime-type . ,(or mime-type "text/plain")) + ,@content-fields))) (cl-defun agent-shell--load-image (&key file-path (max-width 200)) "Load image from FILE-PATH and return the image object.