blob: 03d64e5725e34e6437c300d34f0bfe894835c1e8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
;;; write_text_file.el --- Write text files for gptel -*- lexical-binding: t; -*-
;; Copyright (C) 2025
;; Author: gptel-tool-writer
;; Keywords: convenience, tools
;; Package-Requires: ((emacs "27.1") (gptel "0.9.0"))
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;; Commentary:
;; This file provides a gptel tool for writing text files to the filesystem.
;; The tool includes safety features like backup creation, size limits,
;; and restriction to the user's home directory.
;;; Code:
(require 'gptel)
(with-eval-after-load 'gptel
(gptel-make-tool
:name "write_text_file"
:function (lambda (path content &optional overwrite)
(let* ((full-path (expand-file-name path "~"))
(content (or content ""))
(content-size (length content))
(size-limit (* 1024 1024 1024))) ; 1 GB
;; Check if path is within home directory
(unless (string-prefix-p (expand-file-name "~") full-path)
(error "Path must be within home directory"))
;; Check size limit
(when (> content-size size-limit)
(unless (y-or-n-p (format "File is %s. Write anyway? "
(file-size-human-readable content-size)))
(error "File write cancelled: size exceeds 1GB limit")))
;; Check write permission on parent directory
(let ((parent-dir (file-name-directory full-path)))
(when parent-dir
;; Create parent directories if needed
(unless (file-exists-p parent-dir)
(condition-case err
(make-directory parent-dir t)
(error (error "Cannot create directory %s: %s"
parent-dir (error-message-string err)))))
;; Check write permission
(unless (file-writable-p parent-dir)
(error "No write permission for directory %s" parent-dir))))
;; Handle existing file
(when (file-exists-p full-path)
(if overwrite
;; Create backup with timestamp
(let* ((backup-name
(format "%s-%s.bak"
full-path
(format-time-string "%Y-%m-%d-%H%M%S"))))
(copy-file full-path backup-name t)
(message "Backed up existing file to %s" backup-name))
(error "File %s already exists. Set overwrite to true to replace it" full-path)))
;; Write the file atomically
(with-temp-file full-path
(insert content))
(format "Successfully wrote %d bytes to %s"
content-size full-path)))
:description "Write text content to a file within the user's home directory. Creates parent directories if needed. Backs up existing files with timestamp when overwriting."
:args (list '(:name "path"
:type string
:description "File path relative to home directory, e.g., 'documents/myfile.txt' or '~/documents/myfile.txt'")
'(:name "content"
:type string
:description "The text content to write to the file")
'(:name "overwrite"
:type boolean
:description "If true, backup and overwrite existing file. If false or omitted, error if file exists"
:optional t))
:category "filesystem"
:confirm t
:include t)
;; Automatically add to gptel-tools on load
(add-to-list 'gptel-tools (gptel-get-tool '("filesystem" "write_text_file"))))
(provide 'write_text_file)
;;; write_text_file.el ends here
|