Skip to content

Commit 19d959c

Browse files
committed
Add summary for eca commands via summary field on tool calls.
1 parent e3e4754 commit 19d959c

File tree

6 files changed

+91
-20
lines changed

6 files changed

+91
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- Improve `eca_shell_command` to handle better error outputs.
6+
- Add summary for eca commands via `summary` field on tool calls.
67

78
## 0.21.1
89

docs/protocol.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,12 @@ interface ToolCallPrepareContent {
563563
*/
564564
manualApproval: boolean;
565565

566+
/**
567+
* Summary text to present about this tool call,
568+
* ex: 'Reading file "foo"...'.
569+
*/
570+
summary?: string;
571+
566572
/**
567573
* Extra details about this call.
568574
* Clients may use this to present different UX for this tool call.
@@ -597,6 +603,12 @@ interface ToolCallRunContent {
597603
* Whether this call requires manual approval from the user.
598604
*/
599605
manualApproval: boolean;
606+
607+
/**
608+
* Summary text to present about this tool call,
609+
* ex: 'Reading file "foo"...'.
610+
*/
611+
summary?: string;
600612

601613
/**
602614
* Extra details about this call.
@@ -648,6 +660,12 @@ interface ToolCalledContent {
648660
content: string;
649661
}];
650662

663+
/**
664+
* Summary text to present about this tool call,
665+
* ex: 'Reading file "foo"...'.
666+
*/
667+
summary?: string;
668+
651669
/**
652670
* Extra details about this call.
653671
* Clients may use this to present different UX for this tool call.
@@ -680,6 +698,12 @@ interface ToolCallRejected {
680698
*/
681699
reason: 'user';
682700

701+
/**
702+
* Summary text to present about this tool call,
703+
* ex: 'Reading file "foo"...'.
704+
*/
705+
summary?: string;
706+
683707
/**
684708
* Extra details about this call.
685709
* Clients may use this to present different UX for this tool call.

src/eca/features/chat.clj

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,19 @@
163163
(assert-chat-not-stopped! chat-ctx)
164164
(swap! tool-call-by-id* update-in [id :args] str arguments-text)
165165
(send-content! chat-ctx :assistant
166-
{:type :toolCallPrepare
167-
:name name
168-
:origin (tool-name->origin name all-tools)
169-
:arguments-text (get-in @tool-call-by-id* [id :args])
170-
:id id
171-
:manual-approval manual-approval?}))
166+
(assoc-some
167+
{:type :toolCallPrepare
168+
:name name
169+
:origin (tool-name->origin name all-tools)
170+
:arguments-text (get-in @tool-call-by-id* [id :args])
171+
:id id
172+
:manual-approval manual-approval?}
173+
:summary (f.tools/tool-call-summary all-tools name nil))))
172174
:on-tool-called (fn [{:keys [id name arguments] :as tool-call}]
173175
(assert-chat-not-stopped! chat-ctx)
174176
(let [approved?* (promise)
175-
details (f.tools/get-tool-call-details name arguments)]
177+
details (f.tools/get-tool-call-details name arguments)
178+
summary (f.tools/tool-call-summary all-tools name arguments)]
176179
(send-content! chat-ctx :assistant
177180
(assoc-some
178181
{:type :toolCallRun
@@ -181,7 +184,8 @@
181184
:arguments arguments
182185
:id id
183186
:manual-approval manual-approval?}
184-
:details details))
187+
:details details
188+
:summary summary))
185189
(swap! db* assoc-in [:chats chat-id :tool-calls id :approved?*] approved?*)
186190
(when-not (string/blank? @received-msgs*)
187191
(add-to-history! {:role "assistant" :content @received-msgs*})
@@ -206,7 +210,8 @@
206210
:error (:error result)
207211
:id id
208212
:outputs (:contents result)}
209-
:details details)))
213+
:details details
214+
:summary summary)))
210215
(do
211216
(add-to-history! {:role "tool_call" :content tool-call})
212217
(add-to-history! {:role "tool_call_output" :content (assoc tool-call :output {:error true
@@ -220,7 +225,8 @@
220225
:arguments arguments
221226
:reason :user
222227
:id id}
223-
:details details))))
228+
:details details
229+
:summary summary))))
224230
(swap! tool-call-by-id* dissoc id)
225231
(send-content! chat-ctx :system {:type :progress :state :running :text "Generating"})
226232
{:new-messages (get-in @db* [:chats chat-id :messages])}))

src/eca/features/tools.clj

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@
3333
f.tools.shell/definitions))))
3434

3535
(defn ^:private native-tools [db config]
36-
(mapv #(select-keys % [:name :description :parameters])
37-
(vals (native-definitions db config))))
36+
(vals (native-definitions db config)))
3837

3938
(defn all-tools
4039
"Returns all available tools, including both native ECA tools
@@ -70,7 +69,9 @@
7069
(messenger/tool-server-updated messenger {:type :native
7170
:name "ECA"
7271
:status "running"
73-
:tools (mapv with-tool-status (native-tools @db* config))})
72+
:tools (->> (native-tools @db* config)
73+
(mapv #(select-keys % [:name :description :parameters]))
74+
(mapv with-tool-status))})
7475
(f.mcp/initialize-servers-async!
7576
{:on-server-updated (fn [server]
7677
(messenger/tool-server-updated messenger (-> server
@@ -104,6 +105,16 @@
104105
(messenger/tool-server-updated messenger (-> server
105106
(assoc :type :mcp)
106107
(update :tools #(mapv with-tool-status %)))))})))
108+
109+
(defn tool-call-summary [all-tools name args]
110+
(when-let [summary-fn (:summary-fn (first (filter #(= name (:name %))
111+
all-tools)))]
112+
(try
113+
(summary-fn args)
114+
(catch Exception e
115+
(logger/error (format "Error in tool call summary fn %s: %s" name (.getMessage e)))
116+
nil))))
117+
107118
(defn get-tool-call-details [name arguments]
108119
(case name
109120
"eca_write_file" (let [path (get arguments "path")

src/eca/features/tools/filesystem.clj

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
(string/join "\n")))]
4848
(tools.util/single-text-content content))))
4949

50+
(defn ^:private read-file-summary [args]
51+
(if-let [path (get args "path")]
52+
(str "Reading file " (fs/file-name (fs/file path)))
53+
"Reading file"))
54+
5055
(defn ^:private write-file [arguments {:keys [db]}]
5156
(or (tools.util/invalid-arguments arguments [["path" (partial allowed-path? db) (str "Access denied - path $path outside allowed directories: " (tools.util/workspace-roots-strs db))]])
5257
(let [path (get arguments "path")
@@ -55,6 +60,11 @@
5560
(spit path content)
5661
(tools.util/single-text-content (format "Successfully wrote to %s" path)))))
5762

63+
(defn ^:private write-file-summary [args]
64+
(if-let [path (get args "path")]
65+
(str "Creating file " (fs/file-name (fs/file path)))
66+
"Creating file"))
67+
5868
(defn ^:private run-ripgrep [path pattern include]
5969
(let [cmd (cond-> ["rg" "--files-with-matches" "--no-heading"]
6070
include (concat ["--glob" include])
@@ -147,6 +157,11 @@
147157
(tools.util/single-text-content (string/join "\n" paths))
148158
(tools.util/single-text-content "No files found for given pattern" :error)))))
149159

160+
(defn grep-summary [args]
161+
(if-let [pattern (get args "pattern")]
162+
(format "Searching for '%s'" pattern)
163+
"Searching for files"))
164+
150165
(defn file-change-full-content [path original-content new-content all?]
151166
(let [original-full-content (slurp path)
152167
new-full-content (if all?
@@ -193,7 +208,8 @@
193208
"limit" {:type "integer"
194209
:description "Maxium number of entries to show (default: 100)"}}
195210
:required ["path"]}
196-
:handler #'directory-tree}
211+
:handler #'directory-tree
212+
:summary-fn (constantly "Listing file tree")}
197213
"eca_read_file"
198214
{:description (str "Read the contents of a file from the file system. "
199215
"Use this tool when you need to examine "
@@ -209,7 +225,8 @@
209225
"limit" {:type "integer"
210226
:description (str "Maximum lines to read (default: " read-file-max-lines ")")}}
211227
:required ["path"]}
212-
:handler #'read-file}
228+
:handler #'read-file
229+
:summary-fn #'read-file-summary}
213230
"eca_write_file"
214231
{:description (str "Create a new file or completely overwrite an existing file with new content. "
215232
"This tool will automatically create any necessary parent directories if they don't exist. "
@@ -223,7 +240,8 @@
223240
"content" {:type "string"
224241
:description "The complete content to write to the file"}}
225242
:required ["path" "content"]}
226-
:handler #'write-file}
243+
:handler #'write-file
244+
:summary-fn #'write-file-summary}
227245
"eca_edit_file"
228246
{:description (str "Replace a specific string or content block in a file with new content. "
229247
"Finds the exact original content and replaces it with new content. "
@@ -240,7 +258,8 @@
240258
"all_occurrences" {:type "boolean"
241259
:description "Whether to replace all occurences of the file or just the first one (default)"}}
242260
:required ["path" "original_content" "new_content"]}
243-
:handler #'edit-file}
261+
:handler #'edit-file
262+
:summary-fn (constantly "Editting file")}
244263
"eca_move_file"
245264
{:description (str "Move or rename files and directories. Can move files between directories "
246265
"and rename them in a single operation. If the destination exists, the "
@@ -253,7 +272,8 @@
253272
"destination" {:type "string"
254273
:description "The new absolute file path to move to."}}
255274
:required ["source" "destination"]}
256-
:handler #'move-file}
275+
:handler #'move-file
276+
:summary-fn (constantly "Moving file")}
257277
"eca_grep"
258278
{:description (str "Fast content search tool that works with any codebase size. "
259279
"Finds the paths to files that have matching contents using regular expressions. "
@@ -271,4 +291,5 @@
271291
"max_results" {:type "integer"
272292
:description "Maximum number of results to return (default: 1000)"}}
273293
:required ["path" "pattern"]}
274-
:handler #'grep}})
294+
:handler #'grep
295+
:summary-fn #'grep-summary}})

src/eca/features/tools/shell.clj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@
5151
[{:type :text
5252
:text (str "Stdout:\n" out)}])))})))))
5353

54+
(defn shell-command-summary [args]
55+
(if-let [command (get args "command")]
56+
(if (> (count command) 20)
57+
(format "Running '%s...'" (subs command 0 20))
58+
(format "Running '%s'" command))
59+
"Running shell command"))
60+
5461
(def definitions
5562
{"eca_shell_command"
5663
{:description (multi-str "Execute an arbitrary shell command and return the output.
@@ -178,4 +185,5 @@ Important:
178185
"working_directory" {:type "string"
179186
:description "The directory to run the command in. Default to the first workspace root."}}
180187
:required ["command"]}
181-
:handler #'shell-command}})
188+
:handler #'shell-command
189+
:summary-fn #'shell-command-summary}})

0 commit comments

Comments
 (0)