Skip to content

Commit 0068e4e

Browse files
ericdalloeca
andcommitted
Fix message->decision parsing and add tests
Ensure commands are tokenized with support for quoted arguments and detect MCP prompts by parsing the first token with a single split. Adds message->decision-test to verify existing behavior and quoted-args handling. 🤖 Generated with [eca](https://eca.dev) Co-Authored-By: eca <[email protected]>
1 parent f4a0442 commit 0068e4e

File tree

2 files changed

+63
-28
lines changed

2 files changed

+63
-28
lines changed

src/eca/features/chat.clj

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -76,27 +76,29 @@
7676
:message-cost (shared/tokens->cost input-tokens input-cache-creation-tokens input-cache-read-tokens output-tokens full-model db)
7777
:session-cost (shared/tokens->cost total-input-tokens total-input-cache-creation-tokens total-input-cache-read-tokens total-output-tokens full-model db)))))
7878

79-
(defn ^:private message->decision [message]
80-
(let [slash? (string/starts-with? message "/")
81-
mcp-prompt? (string/includes? (first (string/split message #" ")) ":")]
82-
(cond
83-
(and slash? mcp-prompt?)
84-
(let [command (subs message 1)
85-
parts (string/split command #" ")
86-
[server] (string/split command #":")]
87-
{:type :mcp-prompt
88-
:server server
89-
:prompt (second (string/split (first parts) #":"))
90-
:args (vec (rest parts))})
79+
(defn ^:private tokenize-args [^String s]
80+
(if (string/blank? s)
81+
[]
82+
(->> (re-seq #"\s*\"([^\"]*)\"|\s*([^\s]+)" s)
83+
(map (fn [[_ quoted unquoted]] (or quoted unquoted)))
84+
(vec))))
9185

92-
slash?
86+
(defn ^:private message->decision [message]
87+
(let [slash? (string/starts-with? message "/")]
88+
(if slash?
9389
(let [command (subs message 1)
94-
parts (string/split command #" ")]
95-
{:type :eca-command
96-
:command (first parts)
97-
:args (vec (rest parts))})
98-
99-
:else
90+
tokens (let [toks (tokenize-args command)] (if (seq toks) toks [""]))
91+
first-token (first tokens)
92+
args (vec (rest tokens))]
93+
(if (and first-token (string/includes? first-token ":"))
94+
(let [[server prompt] (string/split first-token #":" 2)]
95+
{:type :mcp-prompt
96+
:server server
97+
:prompt prompt
98+
:args args})
99+
{:type :eca-command
100+
:command first-token
101+
:args args}))
100102
{:type :prompt-message
101103
:message message})))
102104

@@ -230,15 +232,15 @@
230232
:origin origin)})
231233
(send-content! chat-ctx :assistant
232234
(assoc-some
233-
{:type :toolCalled
234-
:origin origin
235-
:name name
236-
:arguments arguments
237-
:error (:error result)
238-
:id id
239-
:outputs (:contents result)}
240-
:details details
241-
:summary summary))))
235+
{:type :toolCalled
236+
:origin origin
237+
:name name
238+
:arguments arguments
239+
:error (:error result)
240+
:id id
241+
:outputs (:contents result)}
242+
:details details
243+
:summary summary))))
242244
(do
243245
(add-to-history! {:role "tool_call" :content tool-call})
244246
(add-to-history! {:role "tool_call_output"

test/eca/features/chat_test.clj

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,36 @@
267267
(is (match?
268268
@invoked?
269269
[[{:role :user :content "test"}] test-chat-ctx]))))))
270+
271+
(deftest message->decision-test
272+
(testing "plain prompt message"
273+
(is (= {:type :prompt-message
274+
:message "Hello world"}
275+
(#'f.chat/message->decision "Hello world"))))
276+
(testing "ECA command without args"
277+
(is (= {:type :eca-command
278+
:command "help"
279+
:args []}
280+
(#'f.chat/message->decision "/help"))))
281+
(testing "ECA command with args"
282+
(is (= {:type :eca-command
283+
:command "search"
284+
:args ["foo" "bar"]}
285+
(#'f.chat/message->decision "/search foo bar"))))
286+
(testing "ECA command with args with spaces in quotes"
287+
(is (= {:type :eca-command
288+
:command "search"
289+
:args ["foo bar" "baz" "qux bla blow"]}
290+
(#'f.chat/message->decision "/search \"foo bar\" baz \"qux bla blow\""))))
291+
(testing "MCP prompt without args"
292+
(is (= {:type :mcp-prompt
293+
:server "server"
294+
:prompt "prompt"
295+
:args []}
296+
(#'f.chat/message->decision "/server:prompt"))))
297+
(testing "MCP prompt with args"
298+
(is (= {:type :mcp-prompt
299+
:server "server"
300+
:prompt "prompt"
301+
:args ["arg1" "arg2"]}
302+
(#'f.chat/message->decision "/server:prompt arg1 arg2")))))

0 commit comments

Comments
 (0)