Skip to content

Commit 4ef7a8c

Browse files
committed
fix(chat): keep nearby batching boundaries in sync
1 parent bbc9723 commit 4ef7a8c

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
@@ -1270,17 +1270,12 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
12701270

12711271
// Messages that can be safely skipped over when batching tool asks.
12721272
// These are low-information or invisible messages that don't affect semantics:
1273-
// - api_req_started / api_req_finished (API request metadata rows)
1273+
// - api_req_started (API request metadata row)
12741274
// - empty text rows (partial streaming with no visible content)
12751275
// - reasoning rows (hidden from user by default)
12761276
const isIgnorableBetweenTargets = (msg: ClineMessage): boolean => {
12771277
if (msg.type !== "say") return false
1278-
return (
1279-
msg.say === "api_req_started" ||
1280-
msg.say === "api_req_finished" ||
1281-
(msg.say === "text" && !msg.text?.trim()) ||
1282-
msg.say === "reasoning"
1283-
)
1278+
return msg.say === "api_req_started" || (msg.say === "text" && !msg.text?.trim()) || msg.say === "reasoning"
12841279
}
12851280

12861281
// Semantic boundaries that stop batching. When we hit one of these,
@@ -1305,8 +1300,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13051300
}
13061301

13071302
// Consolidate tool asks into batches, allowing ignorable messages between targets.
1308-
// Unlike batchConsecutive which only merges truly adjacent items, batchNearby
1309-
// skips over api_req_started/finished, empty text rows, and reasoning rows that
1303+
// batchNearby skips over api_req_started, empty text rows, and reasoning rows that
13101304
// models like qwen insert between tool calls during streaming.
13111305
const readFileBatched = batchNearby(filtered, {
13121306
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)