Skip to content

Commit c6b82a5

Browse files
committed
Merge remote-tracking branch 'origin/master' into rules_improvement_and_tool
# Conflicts: # CHANGELOG.md # src/eca/features/chat.clj
2 parents e53bd1e + 6fe08a4 commit c6b82a5

13 files changed

Lines changed: 262 additions & 118 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
## Unreleased
44

55
- Improve rules with frontmatter filters, condition variables, path-scoped loading, enforcement support, and clearer documentation. #222
6+
- `preToolCall` hooks now receive `approval: "ask"` for the native `ask_user` tool so notification hooks (e.g. matching `.approval == "ask"`) also fire when the chat is blocked waiting for a user answer, regardless of trust mode.
7+
8+
## 0.129.2
9+
610
- Add support for gpt-5.5 variants
11+
- Restore trust mode on chat resume: `chat/open` and the `/resume` slash command now emit `config/updated` with `selectTrust` reflecting the resumed chat's persisted trust toggle, so the client indicator stays in sync with the server's auto-approval behavior. #426
712

813
## 0.129.1
914

docs/config/hooks.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ To reject a tool call, either output `{"approval": "deny"}` or exit with code `2
102102
}
103103
```
104104

105+
The same hook also fires for the native `ask_user` tool: it always blocks
106+
waiting for a user answer (regardless of trust mode), so `preToolCall`
107+
receives `approval: "ask"` for it. This means a single `'.approval == "ask"'`
108+
hook covers both "tool call needs approval" and "assistant is waiting on a
109+
user question".
110+
105111
=== "Inject context on chat start"
106112

107113
```javascript title="~/.config/eca/config.json"

docs/protocol.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,9 +1824,11 @@ in the UI. The server replays the chat by emitting `chat/cleared` (messages),
18241824
the persisted messages. When the persisted chat has a stored model the server
18251825
additionally emits a `config/updated` notification to realign the client's
18261826
selected model (and available variants) with the resumed chat, so the next
1827-
prompt keeps using the chat's original provider/model. Typically used after
1828-
`chat/list` when the user selects a chat that has not been opened in the current
1829-
client session.
1827+
prompt keeps using the chat's original provider/model. The same notification
1828+
also carries `selectTrust` reflecting the resumed chat's trust toggle, so the
1829+
client indicator stays in sync with the auto-approval behavior the server will
1830+
apply. Typically used after `chat/list` when the user selects a chat that has
1831+
not been opened in the current client session.
18301832

18311833
_Request:_
18321834

@@ -2300,6 +2302,17 @@ interface ConfigUpdatedParams {
23002302
*/
23012303
selectVariant?: string | null;
23022304

2305+
/**
2306+
* The trust toggle state for the active chat. When present clients
2307+
* should forcefully update the chat trust indicator (and any
2308+
* derived UI like a shield/flame icon) to match this value.
2309+
*
2310+
* Server returns this on chat resume (`chat/open`, `/resume`) so the
2311+
* client's indicator matches the auto-approval behavior the server
2312+
* will apply for subsequent tool calls in the resumed chat.
2313+
*/
2314+
selectTrust?: boolean;
2315+
23032316
/**
23042317
* Message to show when starting a new chat.
23052318
*/

resources/ECA_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.129.1
1+
0.129.2

src/eca/config.clj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,19 @@
682682
messenger
683683
db*))))
684684

685+
(defn notify-selected-trust-changed!
686+
"Server-initiated equivalent of a client-side trust toggle: aligns the
687+
client-side trust indicator with the chat's persisted `:trust` value.
688+
Emits via `notify-fields-changed-only!`, so it is a no-op when nothing
689+
changed. Used by chat resume flows (`chat/open`, `/resume`) so the icon
690+
the client shows matches the auto-approval behavior the server is about
691+
to apply (#426)."
692+
[trust db* messenger]
693+
(notify-fields-changed-only!
694+
{:chat {:select-trust (boolean trust)}}
695+
messenger
696+
db*))
697+
685698
(def ^:private config-schema-url "https://eca.dev/config.json")
686699

687700
(defn ^:private flatten-to-paths

src/eca/features/chat.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,4 +1480,5 @@
14801480
(send-chat-contents! messages chat-ctx)
14811481
(lifecycle/send-content! chat-ctx :system (assoc-some {:type :metadata} :title title))
14821482
(config/notify-selected-model-changed! (:model chat) db* messenger config)
1483+
(config/notify-selected-trust-changed! (:trust chat) db* messenger)
14831484
{:found? true :chat-id chat-id :title title}))))

src/eca/features/chat/tool_calls.clj

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,16 @@
546546
trusted? (= :trust/allow approval)
547547
effective-approval (if trusted? :allow approval)
548548

549+
;; ask_user always blocks waiting for the user regardless of trust/auto-allow.
550+
;; Surface that as :ask to preToolCall hooks so notification hooks
551+
;; (e.g. matching .approval == "ask") also fire when the chat is blocked on
552+
;; a user question. Only override when allowed; explicit deny is preserved.
553+
hook-approval (if (and (= "eca" server-name)
554+
(= "ask_user" name)
555+
(= :allow effective-approval))
556+
:ask
557+
effective-approval)
558+
549559
;; 2. Run hooks to collect modifications and approval overrides
550560
hook-state* (atom {:hook-results []
551561
:approval-override nil
@@ -560,7 +570,7 @@
560570
{:tool-name name
561571
:server server-name
562572
:tool-input arguments
563-
:approval effective-approval})
573+
:approval hook-approval})
564574
{:on-before-action on-before-hook-action
565575
:on-after-action (fn [result]
566576
(on-after-hook-action result)

src/eca/features/commands.clj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@
516516
;; Align the client's selected model with the resumed chat
517517
;; so the LLM call keeps using the chat's original model. #417
518518
(config/notify-selected-model-changed! (:model chat) db* messenger config)
519+
;; Align the client's trust indicator with the resumed
520+
;; chat's persisted :trust so the icon matches the
521+
;; auto-approval behavior the server will apply. #426
522+
(config/notify-selected-trust-changed! (:trust chat) db* messenger)
519523
{:type :chat-messages
520524
:clear-before? true
521525
:chats {chat-id {:title (:title chat)

src/eca/features/completion.clj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
(->> (assoc lines line-idx updated-line)
3030
(string/join "\n"))))
3131

32-
33-
3432
(defn complete [{:keys [doc-text doc-version position]} db* config messenger metrics]
3533
(let [full-model (get-in config [:completion :model])
3634
[provider model] (shared/full-model->provider+model full-model)

src/eca/features/tools/agent.clj

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,23 +91,6 @@
9191
sort
9292
vec))
9393

94-
(defn ^:private available-variant-names
95-
"Returns a sorted union of all variant names across all available models."
96-
[config db]
97-
(let [model-keys (keys (:models db))]
98-
(when (seq model-keys)
99-
(let [all-variants (->> model-keys
100-
(mapcat (fn [^String full-model]
101-
(let [idx (.indexOf full-model "/")]
102-
(when (pos? idx)
103-
(let [provider (subs full-model 0 idx)
104-
model (subs full-model (inc idx))
105-
user-variants (get-in config [:providers provider :models model :variants])]
106-
(config/selectable-variant-names (config/effective-model-variants config provider model user-variants)))))))
107-
(into (sorted-set)))]
108-
(when (seq all-variants)
109-
(vec all-variants))))))
110-
11194
(defn ^:private model-variant-names
11295
"Returns sorted variant names for a specific full model string (e.g. \"anthropic/claude-sonnet-4-6\")."
11396
[config ^String full-model]
@@ -270,7 +253,7 @@
270253
(str base-description agents-section)))
271254

272255
(defn definitions
273-
[config db]
256+
[config _db]
274257
{"spawn_agent"
275258
{:description (build-description config)
276259
:parameters {:type "object"

0 commit comments

Comments
 (0)