Skip to content

Commit 6c0ee2d

Browse files
committed
Improve stop prompt
1 parent 3eaf2e7 commit 6c0ee2d

5 files changed

Lines changed: 36 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
- Fix remote server on Windows stealing TLS traffic from Tailscale/WireGuard when using the same port, by binding to specific interfaces instead of `0.0.0.0` when tunnel adapters are detected.
66
- Fix plugin-defined hooks not firing for `chatStart` and `sessionStart` due to plugins resolving after hooks fired. #374
77
- Fix workspace cache resume when worktrees are dynamically added mid-session by using the initial workspace set for the cache key. #372
8-
- Fix exception when stopping while a subagent chat run.
8+
- Lots of improvements to stop prompt behavior:
9+
- Fix exception when stopping while a subagent chat run.
10+
- Fix duplicate "Prompt stopped" message when stopping with a running subagent.
11+
- Fix delayed newline appearing after stopping a prompt by suppressing belated status notifications.
12+
- Reduce stream watchdog poll interval for faster stop responsiveness.
913

1014
## 0.117.0
1115

src/eca/features/chat.clj

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@
465465
(logger/info logger-tag "Superseding active prompt" {:chat-id chat-id
466466
:status (get-in @db* [:chats chat-id :status])}))
467467
(swap! db* assoc-in [:chats chat-id :status] :running)
468+
(swap! db* update-in [:chats chat-id] dissoc :prompt-finished?)
468469
(swap! db* assoc-in [:chats chat-id :updated-at] (System/currentTimeMillis))
469470
(messenger/chat-status-changed messenger {:chat-id chat-id :status :running})
470471
(swap! db* assoc-in [:chats chat-id :prompt-id] prompt-id)
@@ -772,7 +773,10 @@
772773
(when (and (= prompt-id (get-in @db* [:chats chat-id :prompt-id]))
773774
(contains? #{:stopping :running} (get-in @db* [:chats chat-id :status])))
774775
(swap! db* assoc-in [:chats chat-id :status] :idle)
775-
(messenger/chat-status-changed (:messenger chat-ctx) {:chat-id chat-id :status :idle})
776+
;; Only notify client if finish-chat-prompt! hasn't already run,
777+
;; otherwise the belated statusChanged causes duplicate finished handling.
778+
(when-not (get-in @db* [:chats chat-id :prompt-finished?])
779+
(messenger/chat-status-changed (:messenger chat-ctx) {:chat-id chat-id :status :idle}))
776780
(db/update-workspaces-cache! @db* metrics))))))))))
777781

778782
(defn ^:private send-mcp-prompt!
@@ -1021,25 +1025,28 @@
10211025
:commands commands}))
10221026

10231027
(defn prompt-stop
1024-
[{:keys [chat-id]} db* messenger metrics]
1025-
(when (identical? :running (get-in @db* [:chats chat-id :status]))
1026-
;; Set :stopping immediately to prevent race with stream callbacks
1027-
;; that check status via assert-chat-not-stopped! or cancelled?
1028-
(swap! db* assoc-in [:chats chat-id :status] :stopping)
1029-
(let [chat-ctx {:chat-id chat-id
1030-
:db* db*
1031-
:metrics metrics
1032-
:messenger messenger
1033-
:parent-chat-id (get-in @db* [:chats chat-id :parent-chat-id])}]
1034-
(lifecycle/send-content! chat-ctx :system {:type :text
1035-
:text "\nPrompt stopped"})
1028+
([params db* messenger metrics]
1029+
(prompt-stop params db* messenger metrics {}))
1030+
([{:keys [chat-id]} db* messenger metrics {:keys [silent?]}]
1031+
(when (identical? :running (get-in @db* [:chats chat-id :status]))
1032+
;; Set :stopping immediately to prevent race with stream callbacks
1033+
;; that check status via assert-chat-not-stopped! or cancelled?
1034+
(swap! db* assoc-in [:chats chat-id :status] :stopping)
1035+
(let [chat-ctx {:chat-id chat-id
1036+
:db* db*
1037+
:metrics metrics
1038+
:messenger messenger
1039+
:parent-chat-id (get-in @db* [:chats chat-id :parent-chat-id])}]
1040+
(when-not silent?
1041+
(lifecycle/send-content! chat-ctx :system {:type :text
1042+
:text "\nPrompt stopped"}))
10361043

1037-
;; Handle each active tool call
1038-
(doseq [[tool-call-id _] (tc/get-active-tool-calls @db* chat-id)]
1039-
(tc/transition-tool-call! db* chat-ctx tool-call-id :stop-requested
1040-
{:reason {:code :user-prompt-stop
1041-
:text "Tool call rejected because of user prompt stop"}}))
1042-
(lifecycle/finish-chat-prompt! :stopping (dissoc chat-ctx :on-finished-side-effect)))))
1044+
;; Handle each active tool call
1045+
(doseq [[tool-call-id _] (tc/get-active-tool-calls @db* chat-id)]
1046+
(tc/transition-tool-call! db* chat-ctx tool-call-id :stop-requested
1047+
{:reason {:code :user-prompt-stop
1048+
:text "Tool call rejected because of user prompt stop"}}))
1049+
(lifecycle/finish-chat-prompt! :stopping (dissoc chat-ctx :on-finished-side-effect))))))
10431050

10441051
(defn delete-chat
10451052
[{:keys [chat-id]} db* messenger config metrics]

src/eca/features/chat/lifecycle.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@
8888
{:type :progress
8989
:state :finished})
9090
(when-not (get-in @db* [:chats chat-id :created-at])
91-
(swap! db* assoc-in [:chats chat-id :created-at] (System/currentTimeMillis))))
91+
(swap! db* assoc-in [:chats chat-id :created-at] (System/currentTimeMillis)))
92+
(swap! db* assoc-in [:chats chat-id :prompt-finished?] true))
9293
(when (and on-finished-side-effect
9394
(not (identical? :stopping (get-in @db* [:chats chat-id :status]))))
9495
(on-finished-side-effect))

src/eca/features/tools/agent.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@
7575
:max-steps max-steps}}}))
7676

7777
(defn ^:private stop-subagent-chat!
78-
"Stop a running subagent chat."
78+
"Stop a running subagent chat silently (parent already shows 'Prompt stopped')."
7979
[db* messenger metrics subagent-chat-id agent-name]
8080
(let [prompt-stop (requiring-resolve 'eca.features.chat/prompt-stop)]
8181
(try
82-
(prompt-stop {:chat-id subagent-chat-id} db* messenger metrics)
82+
(prompt-stop {:chat-id subagent-chat-id} db* messenger metrics {:silent? true})
8383
(catch Exception e
8484
(logger/warn logger-tag (format "Error stopping subagent '%s': %s" agent-name (.getMessage e)))))))
8585

src/eca/llm_util.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
(logger/debug tag (format "[%s] %s %s" rid (or event "") data)))
8989

9090
(def ^:private default-stream-idle-timeout-ms 120000)
91-
(def ^:private default-stream-check-interval-ms 2000)
91+
(def ^:private default-stream-check-interval-ms 500)
9292

9393
(defn start-stream-watchdog!
9494
"Starts a daemon thread that monitors a streaming connection.

0 commit comments

Comments
 (0)