|
262 | 262 | "Should NOT call sync-prompt! on second message") |
263 | 263 | (is (= "Title 1" (get-in (h/db) [:chats chat-id :title]))) |
264 | 264 |
|
| 265 | + ;; Inject noisy entries into history before the retitle fires, to |
| 266 | + ;; exercise the role/content cleanup applied to :past-messages. |
| 267 | + (swap! (h/db*) update-in [:chats chat-id :messages] |
| 268 | + (fnil into []) |
| 269 | + [{:role "reason" :content "internal thoughts"} |
| 270 | + {:role "tool_call" :content {:name "read_file"}} |
| 271 | + {:role "tool_call_output" :content "file contents"} |
| 272 | + {:role "flag" :content {:text "ui-only"}}]) |
| 273 | + |
265 | 274 | ;; Message 3: should re-generate title with full conversation context |
266 | 275 | (h/reset-messenger!) |
267 | 276 | (prompt-with-title! {:message "And add tests" :chat-id chat-id} {:sync-prompt-mock sync-mock}) |
268 | 277 | (is (= 2 (count @sync-prompt-calls*)) |
269 | 278 | "Should call sync-prompt! again on third message") |
270 | 279 | (is (= "Title 2" (get-in (h/db) [:chats chat-id :title]))) |
271 | | - (let [retitle-call (second @sync-prompt-calls*)] |
| 280 | + (let [retitle-call (second @sync-prompt-calls*) |
| 281 | + past-roles (into #{} (map :role) (:past-messages retitle-call))] |
272 | 282 | (is (= 1 (count (:user-messages retitle-call))) |
273 | 283 | "Third message title should pass only current user message") |
274 | 284 | (is (seq (:past-messages retitle-call)) |
275 | | - "Third message title should include chat history as past-messages")) |
| 285 | + "Third message title should include chat history as past-messages") |
| 286 | + (is (= #{"user" "assistant"} past-roles) |
| 287 | + "Past messages should be cleaned of tool_call, tool_call_output, reason and flag entries")) |
276 | 288 |
|
277 | 289 | ;; Message 4: should NOT re-generate title |
278 | 290 | (h/reset-messenger!) |
279 | 291 | (prompt-with-title! {:message "One more thing" :chat-id chat-id} {:sync-prompt-mock sync-mock}) |
280 | 292 | (is (= 2 (count @sync-prompt-calls*)) |
281 | 293 | "Should NOT call sync-prompt! after third message")))) |
282 | 294 |
|
| 295 | + (testing "retitle respects the last compact marker, dropping pre-compaction history" |
| 296 | + (h/reset-components!) |
| 297 | + (let [sync-prompt-calls* (atom []) |
| 298 | + call-count* (atom 0) |
| 299 | + sync-mock (fn [params] |
| 300 | + (swap! sync-prompt-calls* conj params) |
| 301 | + {:output-text (str "Title " (swap! call-count* inc))})] |
| 302 | + (let [{:keys [chat-id]} (prompt-with-title! {:message "Help me debug"} {:sync-prompt-mock sync-mock})] |
| 303 | + (h/reset-messenger!) |
| 304 | + (prompt-with-title! {:message "Also refactor" :chat-id chat-id} {:sync-prompt-mock sync-mock}) |
| 305 | + |
| 306 | + ;; Insert a compact_marker so earlier history is treated as pre-compaction |
| 307 | + ;; and must not reach the title LLM. |
| 308 | + (swap! (h/db*) update-in [:chats chat-id :messages] |
| 309 | + (fnil conj []) {:role "compact_marker" :content {:auto? false}}) |
| 310 | + |
| 311 | + (h/reset-messenger!) |
| 312 | + (prompt-with-title! {:message "And add tests" :chat-id chat-id} {:sync-prompt-mock sync-mock}) |
| 313 | + (let [retitle-call (second @sync-prompt-calls*)] |
| 314 | + (is (empty? (:past-messages retitle-call)) |
| 315 | + "Past messages before the compact marker should be dropped from title context"))))) |
| 316 | + |
283 | 317 | (testing "manual rename suppresses automatic re-titling" |
284 | 318 | (h/reset-components!) |
285 | 319 | (let [sync-prompt-calls* (atom []) |
|
0 commit comments