(messages: Message[])
| 20 | * a latent ws CJS/ESM resolution race in CI shard-2. |
| 21 | */ |
| 22 | export function groupMessagesByApiRound(messages: Message[]): Message[][] { |
| 23 | const groups: Message[][] = [] |
| 24 | let current: Message[] = [] |
| 25 | // message.id of the most recently seen assistant. This is the sole |
| 26 | // boundary gate: streaming chunks from the same API response share an |
| 27 | // id, so boundaries only fire at the start of a genuinely new round. |
| 28 | // normalizeMessages yields one AssistantMessage per content block, and |
| 29 | // StreamingToolExecutor interleaves tool_results between chunks live |
| 30 | // (yield order, not concat order — see query.ts:613). The id check |
| 31 | // correctly keeps `[tu_A(id=X), result_A, tu_B(id=X)]` in one group. |
| 32 | let lastAssistantId: string | undefined |
| 33 | |
| 34 | // In a well-formed conversation the API contract guarantees every |
| 35 | // tool_use is resolved before the next assistant turn, so lastAssistantId |
| 36 | // alone is a sufficient boundary gate. Tracking unresolved tool_use IDs |
| 37 | // would only do work when the conversation is malformed (dangling tool_use |
| 38 | // after resume-from-partial-batch or max_tokens truncation) — and in that |
| 39 | // case it pins the gate shut forever, merging all subsequent rounds into |
| 40 | // one group. We let those boundaries fire; the summarizer fork's own |
| 41 | // ensureToolResultPairing at claude.ts:1136 repairs the dangling tu at |
| 42 | // API time. |
| 43 | for (const msg of messages) { |
| 44 | if ( |
| 45 | msg.type === 'assistant' && |
| 46 | msg.message.id !== lastAssistantId && |
| 47 | current.length > 0 |
| 48 | ) { |
| 49 | groups.push(current) |
| 50 | current = [msg] |
| 51 | } else { |
| 52 | current.push(msg) |
| 53 | } |
| 54 | if (msg.type === 'assistant') { |
| 55 | lastAssistantId = msg.message.id |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | if (current.length > 0) { |
| 60 | groups.push(current) |
| 61 | } |
| 62 | return groups |
| 63 | } |
| 64 |
no test coverage detected