Skip to content

Commit 26b3351

Browse files
committed
fix(chat): keep nearby batching boundaries in sync
1 parent f4bb173 commit 26b3351

5 files changed

Lines changed: 34 additions & 170 deletions

File tree

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,17 +1281,12 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12811281

12821282
// Messages that can be safely skipped over when batching tool asks.
12831283
// These are low-information or invisible messages that don't affect semantics:
1284-
// - api_req_started / api_req_finished (API request metadata rows)
1284+
// - api_req_started (API request metadata row)
12851285
// - empty text rows (partial streaming with no visible content)
12861286
// - reasoning rows (hidden from user by default)
12871287
const isIgnorableBetweenTargets = (msg: ClineMessage): boolean => {
12881288
if (msg.type !== "say") return false
1289-
return (
1290-
msg.say === "api_req_started" ||
1291-
msg.say === "api_req_finished" ||
1292-
(msg.say === "text" && !msg.text?.trim()) ||
1293-
msg.say === "reasoning"
1294-
)
1289+
return msg.say === "api_req_started" || (msg.say === "text" && !msg.text?.trim()) || msg.say === "reasoning"
12951290
}
12961291

12971292
// Semantic boundaries that stop batching. When we hit one of these,
@@ -1316,8 +1311,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13161311
}
13171312

13181313
// Consolidate tool asks into batches, allowing ignorable messages between targets.
1319-
// Unlike batchConsecutive which only merges truly adjacent items, batchNearby
1320-
// skips over api_req_started/finished, empty text rows, and reasoning rows that
1314+
// batchNearby skips over api_req_started, empty text rows, and reasoning rows that
13211315
// models like qwen insert between tool calls during streaming.
13221316
const readFileBatched = batchNearby(filtered, {
13231317
isTarget: isReadFileAsk,

webview-ui/src/utils/__tests__/batchConsecutive.spec.ts

Lines changed: 0 additions & 116 deletions
This file was deleted.

webview-ui/src/utils/__tests__/batchNearby.spec.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ const isBoundary = (m: TestItem): boolean => {
3939
m.say === "completion_result" ||
4040
m.say === "checkpoint_saved" ||
4141
m.say === "error" ||
42-
m.say === "condense_context"
42+
m.say === "condense_context" ||
43+
m.say === "codebase_search_result"
4344
)
4445
}
4546

@@ -246,8 +247,32 @@ describe("batchNearby", () => {
246247
expect(result[1].text).toBe("done")
247248
})
248249

249-
test("non-ignorable non-target message stops batching", () => {
250-
const messages = [msg("match-1", "ask"), msg("command_output", "say", "command_output"), msg("match-2", "ask")]
250+
test("non-ignorable non-target message stops batching and restores pending ignorable messages", () => {
251+
const messages = [
252+
msg("match-1", "ask"),
253+
msg("", "say", "api_req_started"),
254+
msg("command_output", "say", "command_output"),
255+
msg("match-2", "ask"),
256+
]
257+
const result = batchNearby(messages, {
258+
isTarget: isMatch,
259+
isIgnorableBetweenTargets,
260+
isBoundary,
261+
synthesize: synthesizeBatch,
262+
})
263+
expect(result).toHaveLength(4)
264+
expect(result[0].text).toBe("match-1")
265+
expect(result[1].say).toBe("api_req_started")
266+
expect(result[2].text).toBe("command_output")
267+
expect(result[3].text).toBe("match-2")
268+
})
269+
270+
test("codebase_search_result stops batching", () => {
271+
const messages = [
272+
msg("match-1", "ask"),
273+
msg("search result", "say", "codebase_search_result"),
274+
msg("match-2", "ask"),
275+
]
251276
const result = batchNearby(messages, {
252277
isTarget: isMatch,
253278
isIgnorableBetweenTargets,
@@ -256,7 +281,7 @@ describe("batchNearby", () => {
256281
})
257282
expect(result).toHaveLength(3)
258283
expect(result[0].text).toBe("match-1")
259-
expect(result[1].text).toBe("command_output")
284+
expect(result[1].say).toBe("codebase_search_result")
260285
expect(result[2].text).toBe("match-2")
261286
})
262287

webview-ui/src/utils/batchConsecutive.ts

Lines changed: 0 additions & 38 deletions
This file was deleted.

webview-ui/src/utils/batchNearby.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
/**
22
* Batch tool asks that are near each other, allowing ignorable messages in between.
33
*
4-
* Unlike `batchConsecutive` which only merges truly adjacent items, this function
5-
* merges items of the same type even when separated by low-information or invisible
6-
* messages (e.g., api_req_started/finished, empty text rows, partial streaming).
4+
* This function merges items of the same type even when separated by low-information
5+
* or invisible messages (e.g., api_req_started, empty text rows, partial streaming).
76
*
87
* It stops merging when it hits a "semantic boundary": user feedback, visible assistant
98
* text, completion result, different tool group, checkpoint, error, etc.

0 commit comments

Comments
 (0)