Skip to content

Commit f58bfeb

Browse files
ericdalloeca-agent
andcommitted
Fix Anthropic empty/garbled chat titles on 3rd message retitle
The retitle feature passed the full chat history (including assistant messages) as user-messages to sync-prompt!. Anthropic's handler detected assistant messages without thinking blocks and converted all roles to user, producing a malformed conversation that yielded empty or nonsensical titles. Fix: pass chat history as past-messages (which bypasses the fix-non-thinking-assistant-messages transform) and keep only the current user message as user-messages. 🤖 Generated with [eca](https://eca.dev) Co-Authored-By: eca-agent <git@eca.dev>
1 parent b88567c commit f58bfeb

File tree

3 files changed

+27
-8
lines changed

3 files changed

+27
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Support `ask_user` tool allowing LLM to ask the user questions with optional selectable options. #338
66
- Remove redundant system message when background jobs finish or are killed.
77
- Remove timeout for `ask_user` tool so it waits indefinitely for user response.
8+
- Fix Anthropic chat titles being empty or garbled on 3rd message retitle by passing conversation history as past-messages.
89

910
## 0.126.0
1011

src/eca/features/chat.clj

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -574,18 +574,17 @@
574574
retitle?))]
575575
(assert-compatible-apis-between-models! db chat-id provider model config)
576576
(when generate-title?
577-
(let [title-messages (if retitle?
578-
(into (get-in db [:chats chat-id :messages] [])
579-
user-messages)
580-
user-messages)]
577+
(let [title-past-messages (when retitle?
578+
(get-in db [:chats chat-id :messages] []))]
581579
(future* config
582580
(when-let [{:keys [output-text]} (llm-api/sync-prompt!
583581
{:provider provider
584582
:model model
585583
:model-capabilities
586584
(assoc model-capabilities :reason? false :tools false :web-search false)
587585
:instructions (f.prompt/chat-title-prompt agent config)
588-
:user-messages title-messages
586+
:past-messages title-past-messages
587+
:user-messages user-messages
589588
:config config
590589
:provider-auth provider-auth
591590
:subagent? true})]

test/eca/features/chat_test.clj

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,23 @@
222222
(is (match? {:chat-id string? :status :prompting} resp))
223223
{:chat-id chat-id}))
224224

225+
(deftest sanitize-title-test
226+
(testing "strips markdown headers"
227+
(is (= "My Title" (#'f.chat/sanitize-title "## My Title")))
228+
(is (= "My Title" (#'f.chat/sanitize-title "### My Title"))))
229+
(testing "takes first non-blank line"
230+
(is (= "First Line" (#'f.chat/sanitize-title "\n\n First Line\nSecond Line"))))
231+
(testing "strips control characters"
232+
(is (= "clean text" (#'f.chat/sanitize-title "clean\u0000 \u001ftext"))))
233+
(testing "collapses whitespace"
234+
(is (= "hello world" (#'f.chat/sanitize-title "hello world"))))
235+
(testing "truncates to 40 chars"
236+
(is (= 40 (count (#'f.chat/sanitize-title (apply str (repeat 60 "a")))))))
237+
(testing "returns empty string for blank input"
238+
(is (= "" (#'f.chat/sanitize-title " \n \n "))))
239+
(testing "returns nil for nil input"
240+
(is (nil? (#'f.chat/sanitize-title nil)))))
241+
225242
(deftest title-generation-test
226243
(testing "generates title on first message and re-generates at third with full context"
227244
(h/reset-components!)
@@ -251,9 +268,11 @@
251268
(is (= 2 (count @sync-prompt-calls*))
252269
"Should call sync-prompt! again on third message")
253270
(is (= "Title 2" (get-in (h/db) [:chats chat-id :title])))
254-
(let [retitle-messages (:user-messages (second @sync-prompt-calls*))]
255-
(is (> (count retitle-messages) 1)
256-
"Third message title should include full conversation history"))
271+
(let [retitle-call (second @sync-prompt-calls*)]
272+
(is (= 1 (count (:user-messages retitle-call)))
273+
"Third message title should pass only current user message")
274+
(is (seq (:past-messages retitle-call))
275+
"Third message title should include chat history as past-messages"))
257276

258277
;; Message 4: should NOT re-generate title
259278
(h/reset-messenger!)

0 commit comments

Comments
 (0)