Skip to content

Commit acc209e

Browse files
committed
Support rollback messages in chat
1 parent 8dc1e82 commit acc209e

File tree

2 files changed

+53
-19
lines changed

2 files changed

+53
-19
lines changed

eca-chat.el

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ Must be a positive integer."
280280
"Face for the user sent messages in chat."
281281
:group 'eca)
282282

283+
(defface eca-chat-rollback-face
284+
'((t (:inherit eca-chat-user-messages-face
285+
:weight bold
286+
:underline t)))
287+
"Face for the rollback button."
288+
:group 'eca)
289+
283290
(defface eca-chat-system-messages-face
284291
'((t :inherit font-lock-builtin-face))
285292
"Face for the system messages in chat."
@@ -629,6 +636,15 @@ Must be a positive integer."
629636
:params (list :chatId eca-chat--id))
630637
(eca-chat--set-chat-loading session nil)))
631638

639+
(defun eca-chat--rollback (session content-id)
640+
"Rollback chat messages for SESSION to before CONTENT-ID."
641+
(unless eca-chat--chat-loading
642+
(when (y-or-n-p "Do you want to really rollback the chat to before this message?")
643+
(eca-api-request-sync session
644+
:method "chat/rollback"
645+
:params (list :chatId eca-chat--id
646+
:contentId content-id)))))
647+
632648
(defun eca-chat--set-chat-loading (session loading)
633649
"Set the SESSION chat to a loading state if LOADING is non nil.
634650
Otherwise to a not loading state."
@@ -1075,21 +1091,29 @@ space, tab, or newline."
10751091
(add-text-properties 0 (length first) properties first)
10761092
(concat first rest))))
10771093

1078-
(defun eca-chat--add-expandable-content (id label content)
1094+
(defun eca-chat--add-expandable-content (id label content &optional icon-face)
10791095
"Add LABEL to the chat current position for ID as a interactive text.
10801096
When expanded, shows CONTENT.
10811097
Applies LABEL-FACE to label and CONTENT-FACE to content."
10821098
(save-excursion
10831099
(let* ((context-start (eca-chat--prompt-area-start-point))
1084-
(start-point (1- context-start)))
1100+
(start-point (1- context-start))
1101+
(open-icon (if icon-face
1102+
(propertize eca-chat-expandable-block-open-symbol 'font-lock-face icon-face)
1103+
eca-chat-expandable-block-open-symbol))
1104+
(close-icon (if icon-face
1105+
(propertize eca-chat-expandable-block-close-symbol 'font-lock-face icon-face)
1106+
eca-chat-expandable-block-close-symbol)))
10851107
(goto-char start-point)
10861108
(unless (bolp) (eca-chat--insert "\n"))
10871109
(let ((ov-label (make-overlay (point) (point) (current-buffer))))
10881110
(overlay-put ov-label 'eca-chat--expandable-content-id id)
1111+
(overlay-put ov-label 'eca-chat--expandable-content-open-icon open-icon)
1112+
(overlay-put ov-label 'eca-chat--expandable-content-close-icon close-icon)
10891113
(overlay-put ov-label 'eca-chat--expandable-content-toggle nil)
10901114
(eca-chat--insert (propertize (eca-chat--propertize-only-first-word label
10911115
'line-prefix (unless (string-empty-p content)
1092-
eca-chat-expandable-block-open-symbol))
1116+
open-icon))
10931117
'keymap (let ((km (make-sparse-keymap)))
10941118
(define-key km (kbd "<mouse-1>") (lambda () (eca-chat--expandable-content-toggle id)))
10951119
(define-key km (kbd "<tab>") (lambda () (eca-chat--expandable-content-toggle id)))
@@ -1121,8 +1145,8 @@ Applies LABEL-FACE to label and CONTENT-FACE to content."
11211145
(eca-chat--insert (propertize (eca-chat--propertize-only-first-word label
11221146
'line-prefix (unless (string-empty-p new-content)
11231147
(if open?
1124-
eca-chat-expandable-block-close-symbol
1125-
eca-chat-expandable-block-open-symbol)))
1148+
(overlay-get ov-label 'eca-chat--expandable-content-close-icon)
1149+
(overlay-get ov-label 'eca-chat--expandable-content-open-icon))))
11261150
'help-echo "mouse-1 / RET / tab: expand/collapse"))
11271151
(when open?
11281152
(if append-content?
@@ -1153,13 +1177,13 @@ If FORCE? decide to CLOSE? or not."
11531177
(progn
11541178
(put-text-property (point) (line-end-position)
11551179
'line-prefix (unless empty-content?
1156-
eca-chat-expandable-block-open-symbol))
1180+
(overlay-get ov-label 'eca-chat--expandable-content-open-icon)))
11571181
(goto-char (1+ (line-end-position)))
11581182
(delete-region (overlay-start ov-content) (overlay-end ov-content))
11591183
(overlay-put ov-label 'eca-chat--expandable-content-toggle nil))
11601184
(progn
11611185
(put-text-property (point) (line-end-position)
1162-
'line-prefix eca-chat-expandable-block-close-symbol)
1186+
'line-prefix (overlay-get ov-label 'eca-chat--expandable-content-close-icon))
11631187
(goto-char (overlay-start ov-content))
11641188
(eca-chat--insert content "\n")
11651189
(overlay-put ov-label 'eca-chat--expandable-content-toggle t))))
@@ -1854,6 +1878,7 @@ Append STATUS, TOOL-CALL-NEXT-LINE-SPACING and ROOTS"
18541878
(let* ((chat-id (plist-get params :chatId))
18551879
(role (plist-get params :role))
18561880
(content (plist-get params :content))
1881+
(content-id (plist-get content :contentId))
18571882
(roots (eca--session-workspace-folders session))
18581883
(tool-call-next-line-spacing (make-string (1+ (length eca-chat-expandable-block-open-symbol)) ?\s))
18591884
(chat-buffer (eca-chat--get-chat-buffer session chat-id)))
@@ -1865,15 +1890,14 @@ Append STATUS, TOOL-CALL-NEXT-LINE-SPACING and ROOTS"
18651890
(when-let* ((text (plist-get content :text)))
18661891
(pcase role
18671892
("user"
1868-
(eca-chat--add-text-content
1869-
(concat
1870-
(unless eca-chat--empty "\n")
1871-
(propertize text
1872-
'font-lock-face 'eca-chat-user-messages-face
1873-
'line-prefix (propertize eca-chat-prompt-prefix
1874-
'font-lock-face 'eca-chat-user-messages-face)
1875-
'line-spacing 10))
1876-
'eca-chat--user-message-id eca-chat--last-request-id)
1893+
(eca-chat--add-expandable-content
1894+
content-id
1895+
(propertize (string-trim-right text) 'font-lock-face 'eca-chat-user-messages-face)
1896+
(eca-buttonize
1897+
eca-chat-mode-map
1898+
(propertize "Rollback chat to before this message" 'font-lock-face 'eca-chat-rollback-face)
1899+
(lambda () (eca-chat--rollback session content-id)))
1900+
'eca-chat-user-messages-face)
18771901
(eca-chat--mark-header)
18781902
(font-lock-ensure))
18791903
("system"
@@ -1895,7 +1919,7 @@ Append STATUS, TOOL-CALL-NEXT-LINE-SPACING and ROOTS"
18951919
("reasonStarted"
18961920
(let ((id (plist-get content :id))
18971921
(label (propertize "Thinking..." 'font-lock-face 'eca-chat-reason-label-face)))
1898-
(eca-chat--add-expandable-content id label "")
1922+
(eca-chat--add-expandable-content id label "" 'eca-chat-reason-label-face)
18991923
(setq-local eca-chat--empty nil)))
19001924
("reasonText"
19011925
(let ((id (plist-get content :id))
@@ -1913,7 +1937,7 @@ Append STATUS, TOOL-CALL-NEXT-LINE-SPACING and ROOTS"
19131937
(let* ((id (plist-get content :id))
19141938
(name (plist-get content :name))
19151939
(label (propertize (format "Running hook '%s'..." name) 'font-lock-face 'eca-chat-hook-label-face)))
1916-
(eca-chat--add-expandable-content id label "")))
1940+
(eca-chat--add-expandable-content id label "" 'eca-chat-hook-label-face)))
19171941
("hookActionFinished"
19181942
(let* ((id (plist-get content :id))
19191943
(name (plist-get content :name))
@@ -1958,7 +1982,8 @@ Append STATUS, TOOL-CALL-NEXT-LINE-SPACING and ROOTS"
19581982
(eca-chat--content-table
19591983
`(("Tool" . ,name)
19601984
("Server" . ,server)
1961-
("Arguments" . ,new-content)))))))))
1985+
("Arguments" . ,new-content)))
1986+
'eca-chat-mcp-tool-call-label-face))))))
19621987
("toolCallRun"
19631988
(let* ((id (plist-get content :id))
19641989
(args (plist-get content :arguments))
@@ -2086,6 +2111,14 @@ Append STATUS, TOOL-CALL-NEXT-LINE-SPACING and ROOTS"
20862111
(setq-local eca-chat--session-cost (plist-get content :sessionCost)))
20872112
(_ nil)))))
20882113

2114+
(defun eca-chat-cleared (session params)
2115+
"Clear chat for SESSION and PARAMS requested by server."
2116+
(-let* ((chat-id (plist-get params :chatId))
2117+
(messages? (plist-get params :messages))
2118+
(chat-buffer (eca-chat--get-chat-buffer session chat-id)))
2119+
(eca-chat--with-current-buffer chat-buffer
2120+
(when messages?
2121+
(eca-chat--clear)))))
20892122

20902123
(defun eca-chat-config-updated (session chat-config)
20912124
"Update chat based on the CHAT-CONFIG for SESSION."

eca.el

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
(pcase method
9090
("config/updated" (eca-config-updated session params))
9191
("chat/contentReceived" (eca-chat-content-received session params))
92+
("chat/cleared" (eca-chat-cleared session params))
9293
("rewrite/contentReceived" (eca-rewrite-content-received session params))
9394
("tool/serverUpdated" (eca--tool-server-updated session params))
9495
("$/showMessage" (eca--handle-show-message params))

0 commit comments

Comments
 (0)