Skip to content

Commit aee07a4

Browse files
author
Kang Tu
committed
Move append-summary feature to ai-code--insert-prompt
1 parent 7c46971 commit aee07a4

3 files changed

Lines changed: 202 additions & 8 deletions

File tree

ai-code-change.el

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ Otherwise implement comments for the entire current file.
284284
Argument ARG is the prefix argument.
285285
Optional DEFAULT-ACTION skips the action prompt when non-nil."
286286
;; DONE: I want to implement the idea inside https://github.com/tninja/ai-code-interface.el/issues/316, it could to either code change or ask question, given user's input with completing-read selection. The difference of this org-mode section TODO, with the existing comment todo is, it won't replace the TODO section with implementation. It just use the section headline and content inside this section as part of prompt, and send to AI.
287+
;; DONE: for this command triggered from org-mode file buffer. We want to let user choose if they want to add the condense result summary as a section (org headline), at the end of current section under cursor. If user choose yes. The prompt should let AI know this and where to add (maybe let it know current file, headline / cursor position maybe), so that it can add result summary.
288+
;; DONE: This result summary looks good. Is it possible to move this feature to the function just before sending prompt to AI, so that it can be applied to other code change or question asking command as well? The key point is to let user choose if they want to have this summary added to the file, and where to add, so that the prompt can include this requirement and context.
287289
(interactive "P")
288290
(if (not buffer-file-name)
289291
(user-error "Error: buffer-file-name must be available")

ai-code-prompt-mode.el

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -415,13 +415,21 @@ that root, otherwise return the absolute path."
415415
(defun ai-code--insert-prompt (prompt-text)
416416
"Preprocess and insert PROMPT-TEXT into the AI prompt file.
417417
If PROMPT-TEXT is a command (starts with /), execute it directly instead."
418-
(let ((processed-prompt (if ai-code-prompt-preprocess-filepaths
419-
(ai-code--preprocess-prompt-text prompt-text)
420-
prompt-text)))
421-
(if (and (string-prefix-p "/" processed-prompt)
422-
(not (string-match-p " " processed-prompt)))
423-
(ai-code--execute-command processed-prompt)
424-
(ai-code--write-prompt-to-file-and-send processed-prompt))))
418+
(let* ((processed-prompt (if ai-code-prompt-preprocess-filepaths
419+
(ai-code--preprocess-prompt-text prompt-text)
420+
prompt-text))
421+
(append-summary-p (and (derived-mode-p 'org-mode)
422+
(org-at-heading-p)
423+
(y-or-n-p "Append result summary to current section? ")))
424+
(final-prompt (if append-summary-p
425+
(concat processed-prompt
426+
(format "\n\nAfter completing, append a concise result summary as a sub-heading at the end of the current section in file %s near line %d."
427+
buffer-file-name (line-number-at-pos)))
428+
processed-prompt)))
429+
(if (and (string-prefix-p "/" final-prompt)
430+
(not (string-match-p " " final-prompt)))
431+
(ai-code--execute-command final-prompt)
432+
(ai-code--write-prompt-to-file-and-send final-prompt))))
425433

426434
;; Define the AI Prompt Mode (derived from org-mode)
427435
;;;###autoload

test/test_ai-code-change.el

Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ is between the function definition and its body."
506506
(should (string-match-p "[Qq]uestion" captured-label))
507507
(should-not (string-match-p "implementation" captured-label))))))
508508

509-
(ert-deftest ai-code-test-ai-code-implement-todo-org-section-includes-heading-and-content ()
509+
(ert-deftest ai-code-test-implement-todo-org-section-includes-heading-and-content ()
510510
"Test Org TODO section is used as prompt context without requiring comment syntax."
511511
(with-temp-buffer
512512
(require 'org)
@@ -792,6 +792,190 @@ is between the function definition and its body."
792792

793793
(should (equal captured-default-action "Code change"))))))
794794

795+
(ert-deftest ai-code-test-implement-todo-org-no-append-summary-in-build ()
796+
"Test that `build-and-send-prompt' no longer asks about appending summary (moved to insert-prompt)."
797+
(with-temp-buffer
798+
(require 'org)
799+
(setq buffer-file-name "todo.org")
800+
(insert "* TODO Build feature\n")
801+
(insert "Details here.\n")
802+
(org-mode)
803+
(goto-char (point-min))
804+
805+
(let (y-or-n-called)
806+
(cl-letf (((symbol-function 'completing-read)
807+
(lambda (&rest _) "Code change"))
808+
((symbol-function 'y-or-n-p)
809+
(lambda (_prompt)
810+
(setq y-or-n-called t)
811+
nil))
812+
((symbol-function 'ai-code-read-string)
813+
(lambda (_label input) input))
814+
((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
815+
((symbol-function 'ai-code--get-context-files-string) (lambda () ""))
816+
((symbol-function 'ai-code--format-repo-context-info) (lambda () ""))
817+
((symbol-function 'which-function) (lambda () nil))
818+
((symbol-function 'region-active-p) (lambda () nil))
819+
((symbol-function 'ai-code--insert-prompt) (lambda (_p) nil)))
820+
821+
(ai-code--implement-todo--build-and-send-prompt nil)
822+
823+
(should-not y-or-n-called)))))
824+
825+
(ert-deftest ai-code-test-implement-todo-comment-no-append-summary-asked ()
826+
"Test that `y-or-n-p' is NOT asked on regular TODO comment path."
827+
(with-temp-buffer
828+
(setq buffer-file-name "test.el")
829+
(setq-local comment-start ";")
830+
(setq-local comment-end "")
831+
(insert ";; TODO: implement feature\n")
832+
(goto-char (point-min))
833+
834+
(let (y-or-n-called)
835+
(cl-letf (((symbol-function 'completing-read)
836+
(lambda (&rest _) "Code change"))
837+
((symbol-function 'y-or-n-p)
838+
(lambda (_prompt)
839+
(setq y-or-n-called t)
840+
nil))
841+
((symbol-function 'ai-code-read-string)
842+
(lambda (_label input) input))
843+
((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
844+
((symbol-function 'ai-code--get-context-files-string) (lambda () ""))
845+
((symbol-function 'ai-code--format-repo-context-info) (lambda () ""))
846+
((symbol-function 'ai-code--get-function-name-for-comment) (lambda () nil))
847+
((symbol-function 'which-function) (lambda () nil))
848+
((symbol-function 'region-active-p) (lambda () nil))
849+
((symbol-function 'ai-code--insert-prompt) (lambda (_p) nil)))
850+
851+
(ai-code--implement-todo--build-and-send-prompt nil)
852+
853+
(should-not y-or-n-called)))))
854+
855+
(ert-deftest ai-code-test-implement-todo-org-build-prompt-no-summary-text ()
856+
"Test that `build-and-send-prompt' prompt does NOT contain summary (moved to insert-prompt)."
857+
(with-temp-buffer
858+
(require 'org)
859+
(setq buffer-file-name "/tmp/project/todo.org")
860+
(insert "* TODO Build feature\n")
861+
(insert "Details here.\n")
862+
(org-mode)
863+
(goto-char (point-min))
864+
865+
(let (captured-prompt)
866+
(cl-letf (((symbol-function 'completing-read)
867+
(lambda (&rest _) "Code change"))
868+
((symbol-function 'ai-code-read-string)
869+
(lambda (_label input) input))
870+
((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
871+
((symbol-function 'ai-code--get-context-files-string) (lambda () ""))
872+
((symbol-function 'ai-code--format-repo-context-info) (lambda () ""))
873+
((symbol-function 'which-function) (lambda () nil))
874+
((symbol-function 'region-active-p) (lambda () nil))
875+
((symbol-function 'ai-code--insert-prompt)
876+
(lambda (p) (setq captured-prompt p))))
877+
878+
(ai-code--implement-todo--build-and-send-prompt nil)
879+
880+
(should (stringp captured-prompt))
881+
(should-not (string-match-p "summary" captured-prompt))))))
882+
883+
(ert-deftest ai-code-test-implement-todo-org-append-summary-no ()
884+
"Test that choosing no does NOT add summary instruction to prompt."
885+
(with-temp-buffer
886+
(require 'org)
887+
(setq buffer-file-name "/tmp/project/todo.org")
888+
(insert "* TODO Build feature\n")
889+
(insert "Details here.\n")
890+
(org-mode)
891+
(goto-char (point-min))
892+
893+
(let (captured-prompt)
894+
(cl-letf (((symbol-function 'completing-read)
895+
(lambda (&rest _) "Code change"))
896+
((symbol-function 'ai-code-read-string)
897+
(lambda (_label input) input))
898+
((symbol-function 'ai-code--get-clipboard-text) (lambda () nil))
899+
((symbol-function 'ai-code--get-context-files-string) (lambda () ""))
900+
((symbol-function 'ai-code--format-repo-context-info) (lambda () ""))
901+
((symbol-function 'which-function) (lambda () nil))
902+
((symbol-function 'region-active-p) (lambda () nil))
903+
((symbol-function 'ai-code--insert-prompt)
904+
(lambda (p) (setq captured-prompt p))))
905+
906+
(ai-code--implement-todo--build-and-send-prompt nil)
907+
908+
(should (stringp captured-prompt))
909+
(should-not (string-match-p "summary" captured-prompt))))))
910+
911+
(ert-deftest ai-code-test-insert-prompt-org-heading-append-summary-yes ()
912+
"Test that `ai-code--insert-prompt' appends summary instruction on org heading when user confirms."
913+
(with-temp-buffer
914+
(require 'org)
915+
(setq buffer-file-name "/tmp/project/plan.org")
916+
(insert "* TODO Build search feature\n")
917+
(insert "Design the API first.\n")
918+
(org-mode)
919+
(goto-char (point-min))
920+
921+
(let (captured-prompt
922+
(ai-code-prompt-preprocess-filepaths nil))
923+
(cl-letf (((symbol-function 'y-or-n-p) (lambda (_) t))
924+
((symbol-function 'ai-code--write-prompt-to-file-and-send)
925+
(lambda (prompt) (setq captured-prompt prompt))))
926+
927+
(ai-code--insert-prompt "Test prompt text")
928+
929+
(should (stringp captured-prompt))
930+
(should (string-match-p "Test prompt text" captured-prompt))
931+
(should (string-match-p "summary" captured-prompt))
932+
(should (string-match-p "plan\\.org" captured-prompt))))))
933+
934+
(ert-deftest ai-code-test-insert-prompt-org-heading-append-summary-no ()
935+
"Test that `ai-code--insert-prompt' does NOT append summary when user declines."
936+
(with-temp-buffer
937+
(require 'org)
938+
(setq buffer-file-name "/tmp/project/plan.org")
939+
(insert "* TODO Build search feature\n")
940+
(insert "Design the API first.\n")
941+
(org-mode)
942+
(goto-char (point-min))
943+
944+
(let (captured-prompt
945+
(ai-code-prompt-preprocess-filepaths nil))
946+
(cl-letf (((symbol-function 'y-or-n-p) (lambda (_) nil))
947+
((symbol-function 'ai-code--write-prompt-to-file-and-send)
948+
(lambda (prompt) (setq captured-prompt prompt))))
949+
950+
(ai-code--insert-prompt "Test prompt text")
951+
952+
(should (stringp captured-prompt))
953+
(should (string-match-p "Test prompt text" captured-prompt))
954+
(should-not (string-match-p "summary" captured-prompt))))))
955+
956+
(ert-deftest ai-code-test-insert-prompt-non-org-no-summary-asked ()
957+
"Test that `ai-code--insert-prompt' does NOT ask about summary in non-org buffer."
958+
(with-temp-buffer
959+
(setq buffer-file-name "/tmp/project/test.el")
960+
(setq-local comment-start ";")
961+
(insert ";; some code\n")
962+
(goto-char (point-min))
963+
964+
(let (y-or-n-called captured-prompt
965+
(ai-code-prompt-preprocess-filepaths nil))
966+
(cl-letf (((symbol-function 'y-or-n-p)
967+
(lambda (_)
968+
(setq y-or-n-called t)
969+
nil))
970+
((symbol-function 'ai-code--write-prompt-to-file-and-send)
971+
(lambda (prompt) (setq captured-prompt prompt))))
972+
973+
(ai-code--insert-prompt "Test prompt text")
974+
975+
(should-not y-or-n-called)
976+
(should (string-match-p "Test prompt text" captured-prompt))
977+
(should-not (string-match-p "summary" captured-prompt))))))
978+
795979
(provide 'test_ai-code-change)
796980

797981
;;; test_ai-code-change.el ends here

0 commit comments

Comments
 (0)