Skip to content

Commit e2505ae

Browse files
committed
Avoid inserting out of turn notifications #345
This change is based on PR #346 (by @timvisher-dd)
1 parent f6023c6 commit e2505ae

1 file changed

Lines changed: 98 additions & 75 deletions

File tree

agent-shell.el

Lines changed: 98 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,60 +1136,72 @@ COMMAND, when present, may be a shell command string or an argv vector."
11361136
(let ((update (map-elt (map-elt notification 'params) 'update)))
11371137
(cond
11381138
((equal (map-elt update 'sessionUpdate) "tool_call")
1139-
(agent-shell--save-tool-call
1140-
state
1141-
(map-elt update 'toolCallId)
1142-
(append (list (cons :title (cond
1143-
((and (string= (map-elt update 'title) "Skill")
1144-
(map-nested-elt update '(rawInput command)))
1145-
(format "Skill: %s"
1146-
(agent-shell--tool-call-command-to-string
1147-
(map-nested-elt update '(rawInput command)))))
1148-
(t
1149-
(map-elt update 'title))))
1150-
(cons :status (map-elt update 'status))
1151-
(cons :kind (map-elt update 'kind))
1152-
(cons :command (agent-shell--tool-call-command-to-string
1153-
(map-nested-elt update '(rawInput command))))
1154-
(cons :description (map-nested-elt update '(rawInput description)))
1155-
(cons :content (map-elt update 'content))
1156-
(cons :raw-input (map-elt update 'rawInput)))
1157-
(when-let ((diff (agent-shell--make-diff-info :tool-call update)))
1158-
(list (cons :diff diff)))))
1159-
(agent-shell--emit-event
1160-
:event 'tool-call-update
1161-
:data (list (cons :tool-call-id (map-elt update 'toolCallId))
1162-
(cons :tool-call (map-nested-elt state (list :tool-calls (map-elt update 'toolCallId))))))
1163-
(let ((tool-call-labels (agent-shell-make-tool-call-label
1164-
state (map-elt update 'toolCallId))))
1165-
(agent-shell--update-fragment
1166-
:state state
1167-
:block-id (map-elt update 'toolCallId)
1168-
:label-left (map-elt tool-call-labels :status)
1169-
:label-right (map-elt tool-call-labels :title)
1170-
:expanded agent-shell-tool-use-expand-by-default)
1171-
;; Display plan as markdown block if present
1172-
(when-let ((plan (map-nested-elt update '(rawInput plan))))
1139+
;; Notification is out of context (session/prompt finished).
1140+
;; Cannot derive where to display, so show in minibuffer.
1141+
(if (not (shell-maker-busy))
1142+
(message "%s %s (stale, consider reporting to ACP agent)"
1143+
(agent-shell--make-status-kind-label
1144+
:status (map-elt update 'status)
1145+
:kind (map-elt update 'kind))
1146+
(propertize (or (map-elt update 'title) "")
1147+
'face font-lock-doc-markup-face))
1148+
(agent-shell--save-tool-call
1149+
state
1150+
(map-elt update 'toolCallId)
1151+
(append (list (cons :title (cond
1152+
((and (string= (map-elt update 'title) "Skill")
1153+
(map-nested-elt update '(rawInput command)))
1154+
(format "Skill: %s"
1155+
(agent-shell--tool-call-command-to-string
1156+
(map-nested-elt update '(rawInput command)))))
1157+
(t
1158+
(map-elt update 'title))))
1159+
(cons :status (map-elt update 'status))
1160+
(cons :kind (map-elt update 'kind))
1161+
(cons :command (agent-shell--tool-call-command-to-string
1162+
(map-nested-elt update '(rawInput command))))
1163+
(cons :description (map-nested-elt update '(rawInput description)))
1164+
(cons :content (map-elt update 'content))
1165+
(cons :raw-input (map-elt update 'rawInput)))
1166+
(when-let ((diff (agent-shell--make-diff-info :tool-call update)))
1167+
(list (cons :diff diff)))))
1168+
(agent-shell--emit-event
1169+
:event 'tool-call-update
1170+
:data (list (cons :tool-call-id (map-elt update 'toolCallId))
1171+
(cons :tool-call (map-nested-elt state (list :tool-calls (map-elt update 'toolCallId))))))
1172+
(let ((tool-call-labels (agent-shell-make-tool-call-label
1173+
state (map-elt update 'toolCallId))))
11731174
(agent-shell--update-fragment
11741175
:state state
1175-
:block-id (concat (map-elt update 'toolCallId) "-plan")
1176-
:label-left (propertize "Proposed plan" 'font-lock-face 'font-lock-doc-markup-face)
1177-
:body plan
1178-
:expanded t)))
1179-
(map-put! state :last-entry-type "tool_call"))
1176+
:block-id (map-elt update 'toolCallId)
1177+
:label-left (map-elt tool-call-labels :status)
1178+
:label-right (map-elt tool-call-labels :title)
1179+
:expanded agent-shell-tool-use-expand-by-default)
1180+
;; Display plan as markdown block if present
1181+
(when (map-nested-elt update '(rawInput plan))
1182+
(agent-shell--update-fragment
1183+
:state state
1184+
:block-id (concat (map-elt update 'toolCallId) "-plan")
1185+
:label-left (propertize "Proposed plan" 'font-lock-face 'font-lock-doc-markup-face)
1186+
:body (map-nested-elt update '(rawInput plan))
1187+
:expanded t)))
1188+
(map-put! state :last-entry-type "tool_call")))
11801189
((equal (map-elt update 'sessionUpdate) "agent_thought_chunk")
1181-
(let-alist update
1182-
;; (message "agent_thought_chunk: last-type=%s, will-append=%s"
1183-
;; (map-elt state :last-entry-type)
1184-
;; (equal (map-elt state :last-entry-type) "agent_thought_chunk"))
1190+
;; Notification is out of context (session/prompt finished).
1191+
;; Cannot derive where to display, so show in minibuffer.
1192+
(if (not (shell-maker-busy))
1193+
(message "%s %s (stale, consider reporting to ACP agent): %s"
1194+
agent-shell-thought-process-icon
1195+
(propertize "Thought process" 'face font-lock-doc-markup-face)
1196+
(truncate-string-to-width (map-nested-elt update '(content text)) 100))
11851197
(unless (equal (map-elt state :last-entry-type)
11861198
"agent_thought_chunk")
11871199
(map-put! state :chunked-group-count (1+ (map-elt state :chunked-group-count)))
11881200
(agent-shell--append-transcript
11891201
:text (format "## Agent's Thoughts (%s)\n\n" (format-time-string "%F %T"))
11901202
:file-path agent-shell--transcript-file))
11911203
(agent-shell--append-transcript
1192-
:text .content.text
1204+
:text (map-nested-elt update '(content text))
11931205
:file-path agent-shell--transcript-file)
11941206
(agent-shell--update-fragment
11951207
:state state
@@ -1199,31 +1211,35 @@ COMMAND, when present, may be a shell command string or an argv vector."
11991211
agent-shell-thought-process-icon
12001212
" "
12011213
(propertize "Thought process" 'font-lock-face font-lock-doc-markup-face))
1202-
:body .content.text
1214+
:body (map-nested-elt update '(content text))
12031215
:append (equal (map-elt state :last-entry-type)
12041216
"agent_thought_chunk")
1205-
:expanded agent-shell-thought-process-expand-by-default))
1206-
(map-put! state :last-entry-type "agent_thought_chunk"))
1217+
:expanded agent-shell-thought-process-expand-by-default)
1218+
(map-put! state :last-entry-type "agent_thought_chunk")))
12071219
((equal (map-elt update 'sessionUpdate) "agent_message_chunk")
1208-
(unless (equal (map-elt state :last-entry-type) "agent_message_chunk")
1209-
(map-put! state :chunked-group-count (1+ (map-elt state :chunked-group-count)))
1210-
(agent-shell--append-transcript
1211-
:text (format "\n## Agent (%s)\n\n" (format-time-string "%F %T"))
1212-
:file-path agent-shell--transcript-file))
1213-
(let-alist update
1220+
;; Notification is out of context (session/prompt finished).
1221+
;; Cannot derive where to display, so show in minibuffer.
1222+
(if (not (shell-maker-busy))
1223+
(message "Agent message (stale, consider reporting to ACP agent): %s"
1224+
(truncate-string-to-width (map-nested-elt update '(content text)) 100))
1225+
(unless (equal (map-elt state :last-entry-type) "agent_message_chunk")
1226+
(map-put! state :chunked-group-count (1+ (map-elt state :chunked-group-count)))
1227+
(agent-shell--append-transcript
1228+
:text (format "\n## Agent (%s)\n\n" (format-time-string "%F %T"))
1229+
:file-path agent-shell--transcript-file))
12141230
(agent-shell--append-transcript
1215-
:text .content.text
1231+
:text (map-nested-elt update '(content text))
12161232
:file-path agent-shell--transcript-file)
12171233
(agent-shell--update-fragment
12181234
:state state
12191235
:block-id (format "%s-agent_message_chunk"
12201236
(map-elt state :chunked-group-count))
1221-
:body .content.text
1237+
:body (map-nested-elt update '(content text))
12221238
:create-new (not (equal (map-elt state :last-entry-type)
12231239
"agent_message_chunk"))
12241240
:append t
1225-
:navigation 'never))
1226-
(map-put! state :last-entry-type "agent_message_chunk"))
1241+
:navigation 'never)
1242+
(map-put! state :last-entry-type "agent_message_chunk")))
12271243
((equal (map-elt update 'sessionUpdate) "user_message_chunk")
12281244
(let ((new-prompt-p (not (equal (map-elt state :last-entry-type)
12291245
"user_message_chunk"))))
@@ -1262,11 +1278,19 @@ COMMAND, when present, may be a shell command string or an argv vector."
12621278
:expanded t))
12631279
(map-put! state :last-entry-type "plan"))
12641280
((equal (map-elt update 'sessionUpdate) "tool_call_update")
1265-
(let-alist update
1281+
;; Notification is out of context (session/prompt finished).
1282+
;; Cannot derive where to display, so show in minibuffer.
1283+
(if (not (shell-maker-busy))
1284+
(message "%s %s (stale, consider reporting to ACP agent)"
1285+
(agent-shell--make-status-kind-label
1286+
:status (map-elt update 'status)
1287+
:kind (map-elt update 'kind))
1288+
(propertize (or (map-elt update 'title) "")
1289+
'face font-lock-doc-markup-face))
12661290
;; Update stored tool call data with new status and content
12671291
(agent-shell--save-tool-call
12681292
state
1269-
.toolCallId
1293+
(map-elt update 'toolCallId)
12701294
(append (list (cons :status (map-elt update 'status))
12711295
(cons :content (map-elt update 'content)))
12721296
;; The initial tool_call notification often has a
@@ -1291,17 +1315,16 @@ COMMAND, when present, may be a shell command string or an argv vector."
12911315
(list (cons :diff diff)))))
12921316
(agent-shell--emit-event
12931317
:event 'tool-call-update
1294-
:data (list (cons :tool-call-id .toolCallId)
1295-
(cons :tool-call (map-nested-elt state (list :tool-calls .toolCallId)))))
1296-
(let* ((diff (map-nested-elt state `(:tool-calls ,.toolCallId :diff)))
1318+
:data (list (cons :tool-call-id (map-elt update 'toolCallId))
1319+
(cons :tool-call (map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId))))))
1320+
(let* ((diff (map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId) :diff)))
12971321
(output (concat
12981322
"\n\n"
12991323
;; TODO: Consider if there are other
13001324
;; types of content to display.
13011325
(mapconcat (lambda (item)
1302-
(let-alist item
1303-
.content.text))
1304-
.content
1326+
(map-nested-elt item '(content text)))
1327+
(map-elt update 'content)
13051328
"\n\n")
13061329
"\n\n"))
13071330
(diff-text (agent-shell--format-diff-as-text diff))
@@ -1318,12 +1341,12 @@ COMMAND, when present, may be a shell command string or an argv vector."
13181341
(agent-shell--append-transcript
13191342
:text (agent-shell--make-transcript-tool-call-entry
13201343
:status (map-elt update 'status)
1321-
:title (map-nested-elt state `(:tool-calls ,.toolCallId :title))
1322-
:kind (map-nested-elt state `(:tool-calls ,.toolCallId :kind))
1323-
:description (map-nested-elt state `(:tool-calls ,.toolCallId :description))
1324-
:command (map-nested-elt state `(:tool-calls ,.toolCallId :command))
1344+
:title (map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId) :title))
1345+
:kind (map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId) :kind))
1346+
:description (map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId) :description))
1347+
:command (map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId) :command))
13251348
:parameters (agent-shell--extract-tool-parameters
1326-
(map-nested-elt state `(:tool-calls ,.toolCallId :raw-input)))
1349+
(map-nested-elt state `(:tool-calls ,(map-elt update 'toolCallId) :raw-input)))
13271350
:output body-text)
13281351
:file-path agent-shell--transcript-file))
13291352
;; Hide permission after sending response.
@@ -1334,17 +1357,17 @@ COMMAND, when present, may be a shell command string or an argv vector."
13341357
(not (equal (map-elt update 'status) "pending")))
13351358
;; block-id must be the same as the one used as
13361359
;; agent-shell--update-fragment param by "session/request_permission".
1337-
(agent-shell--delete-fragment :state state :block-id (format "permission-%s" .toolCallId)))
1360+
(agent-shell--delete-fragment :state state :block-id (format "permission-%s" (map-elt update 'toolCallId))))
13381361
(let ((tool-call-labels (agent-shell-make-tool-call-label
1339-
state .toolCallId)))
1362+
state (map-elt update 'toolCallId))))
13401363
(agent-shell--update-fragment
13411364
:state state
1342-
:block-id .toolCallId
1365+
:block-id (map-elt update 'toolCallId)
13431366
:label-left (map-elt tool-call-labels :status)
13441367
:label-right (map-elt tool-call-labels :title)
13451368
:body (string-trim body-text)
1346-
:expanded agent-shell-tool-use-expand-by-default))))
1347-
(map-put! state :last-entry-type "tool_call_update"))
1369+
:expanded agent-shell-tool-use-expand-by-default)))
1370+
(map-put! state :last-entry-type "tool_call_update")))
13481371
((equal (map-elt update 'sessionUpdate) "available_commands_update")
13491372
(let-alist update
13501373
(map-put! state :available-commands (map-elt update 'availableCommands))

0 commit comments

Comments
 (0)