Skip to content

Commit a8cb509

Browse files
committed
Fix messages history
1 parent 7e19f8a commit a8cb509

File tree

9 files changed

+85
-94
lines changed

9 files changed

+85
-94
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
- Support stop chat prompts via `chat/promptStop` notification.
6+
- Fix anthropic messages history.
67

78
## 0.2.0
89

src/eca/features/chat.clj

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
[eca.llm-api :as llm-api]
1111
[eca.logger :as logger]
1212
[eca.messenger :as messenger]
13-
[eca.shared :as shared]))
13+
[eca.shared :as shared]
14+
[cheshire.core :as json]))
1415

1516
(set! *warn-on-reflection* true)
1617

@@ -172,7 +173,7 @@
172173
:request-id request-id
173174
:role :system
174175
:content {:type :text
175-
:text (str "API limit reached. Tokens: " (:tokens msg))}})
176+
:text (str "API limit reached. Tokens: " (json/generate-string (:tokens msg)))}})
176177
(finish-chat-prompt! chat-id :idle messenger db*))
177178
:finish (do
178179
(add-to-history! {:role "assistant" :content @received-msgs*})
@@ -217,7 +218,8 @@
217218
:arguments arguments
218219
:id id
219220
:outputs (:contents result)}})
220-
result))
221+
{:result result
222+
:past-messages (get-in @db* [:chats chat-id :messages] [])}))
221223
:on-reason (fn [{:keys [status]}]
222224
(assert-chat-not-stopped! chat-id db* messenger)
223225
(let [msg (case status

src/eca/features/tools/filesystem.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
(let [pattern (get arguments "pattern")
5959
pattern (if (string/includes? pattern "*")
6060
pattern
61-
(format "**/*%s*/**" pattern))
61+
(format "**%s**" pattern))
6262
paths (reduce
6363
(fn [paths {:keys [uri]}]
6464
(concat paths (fs/glob (shared/uri->filename uri)
@@ -254,7 +254,7 @@
254254
:description "The absolute path to start searching files from there."}
255255
"pattern" {:type "string"
256256
:description (str "Glob pattern following java FileSystem#getPathMatcher matching files or directory names."
257-
"Use '**/*' to match search in multiple levels like '**/*.txt'")}}
257+
"Use '**' to match search in multiple levels like '**.txt'")}}
258258
:required ["path" "pattern"]}
259259
:handler #'search-files}
260260
"grep"

src/eca/llm_providers/anthropic.clj

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -59,38 +59,38 @@
5959
(fn [e]
6060
(on-error {:exception e})))))
6161

62-
(defn ^:private ->messages-with-history [past-messages user-prompt]
63-
(conj (mapv (fn [{:keys [role content] :as msg}]
64-
(case role
65-
"tool_call" {:role "assistant"
66-
:content [{:type "tool_use"
67-
:id (:id content)
68-
:name (:name content)
69-
:input (or (:arguments content) {})}]}
62+
(defn ^:private past-messages->messages [past-messages]
63+
(mapv (fn [{:keys [role content] :as msg}]
64+
(case role
65+
"tool_call" {:role "assistant"
66+
:content [{:type "tool_use"
67+
:id (:id content)
68+
:name (:name content)
69+
:input (or (:arguments content) {})}]}
7070

71-
"tool_call_output"
72-
{:role "user"
73-
:content [{:type "tool_result"
74-
:tool_use_id (:id content)
75-
:content (llm-util/stringfy-tool-result content)}]}
76-
msg))
77-
past-messages)
78-
;; TODO add cache_control to last non thinking message
79-
{:role "user" :content [{:type :text
80-
:text user-prompt}]}))
71+
"tool_call_output"
72+
{:role "user"
73+
:content [{:type "tool_result"
74+
:tool_use_id (:id content)
75+
:content (llm-util/stringfy-tool-result content)}]}
76+
msg))
77+
past-messages))
8178

8279
(defn ^:private add-cache-to-last-message [messages]
80+
;; TODO add cache_control to last non thinking message
8381
(shared/update-last
8482
(vec messages)
8583
#(assoc-in % [:content 0 :cache_control] {:type "ephemeral"})))
8684

8785
(defn completion!
8886
[{:keys [model user-prompt temperature context max-tokens
8987
api-key past-messages tools web-search]
90-
:or {max-tokens 1024
88+
:or {max-tokens 4096
9189
temperature 1.0}}
9290
{:keys [on-message-received on-error on-prepare-tool-call on-tool-called]}]
93-
(let [messages (->messages-with-history past-messages user-prompt)
91+
(let [messages (conj (past-messages->messages past-messages)
92+
{:role "user" :content [{:type :text
93+
:text user-prompt}]})
9494
body {:model model
9595
:messages (add-cache-to-last-message messages)
9696
:max_tokens max-tokens
@@ -131,10 +131,10 @@
131131
(when (= "tool_use" (:type content-block))
132132
(let [function-name (:name content-block)
133133
function-args (:input-json content-block)
134-
response (on-tool-called {:id (:id content-block)
135-
:name function-name
136-
:arguments (json/parse-string function-args)})
137-
messages (-> (concat messages
134+
{:keys [result past-messages]} (on-tool-called {:id (:id content-block)
135+
:name function-name
136+
:arguments (json/parse-string function-args)})
137+
messages (-> (concat (past-messages->messages past-messages)
138138
[{:role "assistant"
139139
:content [(dissoc content-block :input-json)]}]
140140
(mapv
@@ -143,7 +143,7 @@
143143
:content [{:type "tool_result"
144144
:tool_use_id (:id content-block)
145145
:content content}]})
146-
(:contents response)))
146+
(:contents result)))
147147
add-cache-to-last-message)]
148148
(base-request!
149149
{:rid (llm-util/gen-rid)

src/eca/llm_providers/ollama.clj

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
:function (select-keys tool [:name :description :parameters])})
6565
tools))
6666

67-
(defn ^:private ->messages-with-history [context past-messages user-prompt]
67+
(defn ^:private past-messages->messages [past-messages context]
6868
(concat
6969
[{:role "system" :content context}]
7070
(mapv (fn [{:keys [role content] :as msg}]
@@ -73,12 +73,13 @@
7373
:function content}]}
7474
"tool_call_output" {:role "tool" :content (llm-util/stringfy-tool-result content)}
7575
msg))
76-
past-messages)
77-
[{:role "user" :content user-prompt}]))
76+
past-messages)))
7877

7978
(defn completion! [{:keys [model user-prompt context host port past-messages tools]}
8079
{:keys [on-message-received on-error on-prepare-tool-call on-tool-called]}]
81-
(let [messages (->messages-with-history context past-messages user-prompt)
80+
(let [messages (concat
81+
(past-messages->messages past-messages context)
82+
[{:role "user" :content user-prompt}])
8283
body {:model model
8384
:messages messages
8485
:think false
@@ -100,18 +101,18 @@
100101

101102
done_reason
102103
(if-let [tool-call (get @tool-calls* rid)]
103-
(let [response (on-tool-called tool-call)]
104+
(let [{:keys [result past-messages]} (on-tool-called tool-call)]
104105
(swap! tool-calls* dissoc rid)
105106
(base-completion-request!
106107
{:rid (llm-util/gen-rid)
107108
:url url
108-
:body (assoc body :messages (concat messages
109+
:body (assoc body :messages (concat (past-messages->messages past-messages context)
109110
[message]
110111
(mapv
111112
(fn [{:keys [_type content]}]
112113
{:role "tool"
113114
:content content})
114-
(:contents response))))
115+
(:contents result))))
115116
:on-error on-error
116117
:on-response handle-response}))
117118
(on-message-received {:type :finish

src/eca/llm_providers/openai.clj

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,25 @@
4747
(fn [e]
4848
(on-error {:exception e})))))
4949

50-
(defn ^:private ->input-with-history [past-messages user-prompt]
51-
(conj (mapv (fn [{:keys [role content] :as msg}]
52-
(case role
53-
"tool_call" {:type "function_call"
54-
:name (:name content)
55-
:call_id (:id content)
56-
:arguments (json/generate-string (:arguments content))}
57-
"tool_call_output"
58-
{:type "function_call_output"
59-
:call_id (:id content)
60-
:output (llm-util/stringfy-tool-result content)}
61-
msg))
62-
past-messages)
63-
{:role "user" :content user-prompt}))
50+
(defn ^:private past-messages->input [past-messages]
51+
(mapv (fn [{:keys [role content] :as msg}]
52+
(case role
53+
"tool_call" {:type "function_call"
54+
:name (:name content)
55+
:call_id (:id content)
56+
:arguments (json/generate-string (:arguments content))}
57+
"tool_call_output"
58+
{:type "function_call_output"
59+
:call_id (:id content)
60+
:output (llm-util/stringfy-tool-result content)}
61+
msg))
62+
past-messages))
6463

6564
(defn completion! [{:keys [model user-prompt context temperature api-key past-messages tools web-search]
6665
:or {temperature 1.0}}
6766
{:keys [on-message-received on-error on-prepare-tool-call on-tool-called on-reason]}]
68-
(let [input (->input-with-history past-messages user-prompt)
67+
(let [input (conj (past-messages->input past-messages)
68+
{:role "user" :content user-prompt})
6969
tools (cond-> tools
7070
web-search (conj {:type "web_search_preview"}))
7171
body {:model model
@@ -93,12 +93,12 @@
9393
(case (:type (:item data))
9494
"function_call" (let [function-name (-> data :item :name)
9595
function-args (-> data :item :arguments)
96-
response (on-tool-called {:id (-> data :item :call_id)
97-
:name function-name
98-
:arguments (json/parse-string function-args)})]
96+
{:keys [result past-messages]} (on-tool-called {:id (-> data :item :call_id)
97+
:name function-name
98+
:arguments (json/parse-string function-args)})]
9999
(base-completion-request!
100100
{:rid (llm-util/gen-rid)
101-
:body (assoc body :input (concat input
101+
:body (assoc body :input (concat (past-messages->input past-messages)
102102
[{:type "function_call"
103103
:call_id (-> data :item :call_id)
104104
:name function-name
@@ -109,7 +109,7 @@
109109
{:type "function_call_output"
110110
:call_id (-> data :item :call_id)
111111
:output content})
112-
(:contents response))))
112+
(:contents result))))
113113
:api-key api-key
114114
:on-error on-error
115115
:on-response handle-response})

test/eca/llm_providers/anthropic_test.clj

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,15 @@
77
(deftest ->messages-with-history-test
88
(testing "no previous history"
99
(is (match?
10-
[{:role "user" :content [{:type :text :text "Hey"}]}]
11-
(#'llm-providers.anthropic/->messages-with-history [] "Hey"))))
10+
[]
11+
(#'llm-providers.anthropic/past-messages->messages []))))
1212
(testing "With basic text history"
1313
(is (match?
1414
[{:role "user" :content "Count with me: 1"}
15-
{:role "assistant" :content "2"}
16-
{:role "user" :content [{:type :text :text "3"}]}]
17-
(#'llm-providers.anthropic/->messages-with-history
15+
{:role "assistant" :content "2"}]
16+
(#'llm-providers.anthropic/past-messages->messages
1817
[{:role "user" :content "Count with me: 1"}
19-
{:role "assistant" :content "2"}]
20-
"3"))))
18+
{:role "assistant" :content "2"}]))))
2119
(testing "With tool_call history"
2220
(is (match?
2321
[{:role "user" :content "List the files you are allowed"}
@@ -29,9 +27,8 @@
2927
{:role "user" :content [{:type "tool_result"
3028
:tool_use_id "call-1"
3129
:content "Allowed directories: /foo/bar\n"}]}
32-
{:role "assistant" :content "I see /foo/bar"}
33-
{:role "user" :content [{:type :text :text "Thanks"}]}]
34-
(#'llm-providers.anthropic/->messages-with-history
30+
{:role "assistant" :content "I see /foo/bar"}]
31+
(#'llm-providers.anthropic/past-messages->messages
3532
[{:role "user" :content "List the files you are allowed"}
3633
{:role "assistant" :content "Ok!"}
3734
{:role "tool_call" :content {:id "call-1" :name "list_allowed_directories" :arguments {}}}
@@ -41,8 +38,7 @@
4138
:output {:contents [{:type :text
4239
:error false
4340
:content "Allowed directories: /foo/bar"}]}}}
44-
{:role "assistant" :content "I see /foo/bar"}]
45-
"Thanks")))))
41+
{:role "assistant" :content "I see /foo/bar"}])))))
4642

4743
(deftest add-cache-to-last-message-test
4844
(is (match?

test/eca/llm_providers/ollama_test.clj

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,17 @@
77
(deftest ->messages-with-history-test
88
(testing "no previous history"
99
(is (match?
10-
[{:role "system" :content "You are ECA"}
11-
{:role "user" :content "Hey"}]
12-
(#'llm-providers.ollama/->messages-with-history "You are ECA" [] "Hey"))))
10+
[{:role "system" :content "You are ECA"}]
11+
(#'llm-providers.ollama/past-messages->messages [] "You are ECA"))))
1312
(testing "With basic text history"
1413
(is (match?
1514
[{:role "system" :content "You are ECA"}
1615
{:role "user" :content "Count with me: 1"}
17-
{:role "assistant" :content "2"}
18-
{:role "user" :content "3"}]
19-
(#'llm-providers.ollama/->messages-with-history
20-
"You are ECA"
16+
{:role "assistant" :content "2"}]
17+
(#'llm-providers.ollama/past-messages->messages
2118
[{:role "user" :content "Count with me: 1"}
2219
{:role "assistant" :content "2"}]
23-
"3"))))
20+
"You are ECA"))))
2421
(testing "With tool_call history"
2522
(is (match?
2623
[{:role "system" :content "You are ECA"}
@@ -30,10 +27,8 @@
3027
:function {:name "list_allowed_directories"
3128
:arguments {}}}]}
3229
{:role "tool" :content "Allowed directories: /foo/bar\n"}
33-
{:role "assistant" :content "I see /foo/bar"}
34-
{:role "user" :content "Thanks"}]
35-
(#'llm-providers.ollama/->messages-with-history
36-
"You are ECA"
30+
{:role "assistant" :content "I see /foo/bar"}]
31+
(#'llm-providers.ollama/past-messages->messages
3732
[{:role "user" :content "List the files you are allowed"}
3833
{:role "assistant" :content "Ok!"}
3934
{:role "tool_call" :content {:id "call-1" :name "list_allowed_directories" :arguments {}}}
@@ -44,4 +39,4 @@
4439
:error false
4540
:content "Allowed directories: /foo/bar"}]}}}
4641
{:role "assistant" :content "I see /foo/bar"}]
47-
"Thanks")))))
42+
"You are ECA")))))

0 commit comments

Comments
 (0)