|
205 | 205 | (match-content chat-id "assistant" {:type "reasonText" :id (m/pred string?) :text "call tool eca__direc"}) |
206 | 206 | (match-content chat-id "assistant" {:type "reasonText" :id (m/pred string?) :text "tory_tree"}) |
207 | 207 | (match-content chat-id "assistant" {:type "reasonFinished" :id (m/pred string?) :totalTimeMs (m/pred number?)}) |
208 | | - ;; Text is buffered (8-char tail for <thought> detection), then flushed when tool calls start |
209 | | - (match-content chat-id "assistant" {:type "text" :text "I will li"}) |
210 | | - (match-content chat-id "assistant" {:type "text" :text "st files"}) |
211 | | - (match-content chat-id "assistant" {:type "toolCallPrepare" |
212 | | - :origin "native" |
213 | | - :id (m/pred string?) |
214 | | - :name "directory_tree" |
215 | | - :argumentsText "" |
216 | | - :summary "Listing file tree"}) |
217 | | - (match-content chat-id "assistant" {:type "toolCallPrepare" |
218 | | - :origin "native" |
219 | | - :id (m/pred string?) |
220 | | - :name "directory_tree" |
221 | | - :argumentsText "{\"pat" |
222 | | - :summary "Listing file tree"}) |
223 | | - (match-content chat-id "assistant" {:type "toolCallPrepare" |
224 | | - :origin "native" |
225 | | - :id (m/pred string?) |
226 | | - :name "directory_tree" |
227 | | - :argumentsText (str "h\":\"" (h/json-escape-path (h/project-path->canon-path "resources")) "\"}") |
228 | | - :summary "Listing file tree"}) |
229 | | - (match-content chat-id "system" {:type "usage"}) |
| 208 | + |
| 209 | + ;; The text chunks and toolCallPrepare messages may arrive in slightly different |
| 210 | + ;; order on different platforms due to streaming/buffering timing differences. |
| 211 | + ;; Consume them in a batch and verify all expected messages are present. |
| 212 | + ;; Expected: 2 text chunks + 3 toolCallPrepare + 1 usage = 6 messages |
| 213 | + (let [streaming-msgs (h/consume-contents 6) |
| 214 | + content-types (frequencies (map #(get-in % [:content :type]) streaming-msgs))] |
| 215 | + ;; Verify we got the expected message types |
| 216 | + (is (match? {"text" 2 |
| 217 | + "toolCallPrepare" 3 |
| 218 | + "usage" 1} |
| 219 | + content-types)) |
| 220 | + ;; Verify the text content is present (order may vary) |
| 221 | + (is (match? (m/in-any-order [{:content {:type "text" :text "I will li"}} |
| 222 | + {:content {:type "text" :text "st files"}}]) |
| 223 | + (filter #(= "text" (get-in % [:content :type])) streaming-msgs))) |
| 224 | + ;; Verify toolCallPrepare messages contain expected data |
| 225 | + (let [prepare-msgs (filter #(= "toolCallPrepare" (get-in % [:content :type])) streaming-msgs)] |
| 226 | + (is (match? (m/in-any-order [{:content {:argumentsText ""}} |
| 227 | + {:content {:argumentsText "{\"pat"}} |
| 228 | + {:content {:argumentsText (str "h\":\"" (h/json-escape-path (h/project-path->canon-path "resources")) "\"}")}}]) |
| 229 | + prepare-msgs)))) |
| 230 | + |
| 231 | + ;; The tool execution flow has a deterministic order |
230 | 232 | (match-content chat-id "assistant" {:type "toolCallRun" |
231 | 233 | :origin "native" |
232 | 234 | :id (m/pred string?) |
|
254 | 256 | " file2.md\n\n" |
255 | 257 | "0 directories, 2 files")}]}) |
256 | 258 | ;; Text chunks get re-split due to 8-char tail buffering for <thought> detection. |
257 | | - ;; Note: We use m/in-any-order for the final text/usage/progress events since their |
258 | | - ;; relative ordering can vary due to async processing and buffering. |
259 | 259 | (match-content chat-id "assistant" {:type "text" :text "The files"}) |
260 | 260 | (match-content chat-id "assistant" {:type "text" :text " I see:\nfile"}) |
261 | 261 | (match-content chat-id "assistant" {:type "text" :text "1\nfile2\n"}) |
|
0 commit comments