(calls: ToolCall[])
| 57 | } |
| 58 | |
| 59 | export function groupMutatingForParallel(calls: ToolCall[]): ToolCall[][] { |
| 60 | if (calls.length <= 1) return calls.map(c => [c]); |
| 61 | |
| 62 | const batches: ToolCall[][] = []; |
| 63 | let currentBatch: ToolCall[] = []; |
| 64 | let currentPaths: string[] = []; |
| 65 | |
| 66 | for (const tc of calls) { |
| 67 | const name = tc.function.name; |
| 68 | // Globals and broad always solo |
| 69 | if (GLOBAL_TOOLS.has(name) || BROAD_TOOLS.has(name)) { |
| 70 | if (currentBatch.length > 0) { |
| 71 | batches.push(currentBatch); |
| 72 | currentBatch = []; |
| 73 | currentPaths = []; |
| 74 | } |
| 75 | batches.push([tc]); |
| 76 | continue; |
| 77 | } |
| 78 | let args: any; |
| 79 | try { args = tc.function.arguments ? JSON.parse(tc.function.arguments) : {}; } catch { args = null; } |
| 80 | const paths = extractPaths(args); |
| 81 | if (!paths) { |
| 82 | // Unknown path → conservatively solo |
| 83 | if (currentBatch.length > 0) { |
| 84 | batches.push(currentBatch); |
| 85 | currentBatch = []; |
| 86 | currentPaths = []; |
| 87 | } |
| 88 | batches.push([tc]); |
| 89 | continue; |
| 90 | } |
| 91 | if (pathsConflict(currentPaths, paths)) { |
| 92 | // Flush current batch, start a new one |
| 93 | batches.push(currentBatch); |
| 94 | currentBatch = [tc]; |
| 95 | currentPaths = paths.slice(); |
| 96 | } else { |
| 97 | currentBatch.push(tc); |
| 98 | currentPaths.push(...paths); |
| 99 | } |
| 100 | } |
| 101 | if (currentBatch.length > 0) batches.push(currentBatch); |
| 102 | return batches; |
| 103 | } |
no test coverage detected