Skip to content

Commit ed7d421

Browse files
committed
fix tool grouping and ordering
1 parent c9a0400 commit ed7d421

1 file changed

Lines changed: 35 additions & 14 deletions

File tree

frontend/app/aipanel/aitooluse.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import { memo, useEffect, useRef, useState } from "react";
77
import { WaveUIMessagePart } from "./aitypes";
88
import { WaveAIModel } from "./waveai-model";
99

10+
function getEffectiveApprovalStatus(baseApproval: string, isStreaming: boolean): string {
11+
return !isStreaming && baseApproval === "needs-approval" ? "timeout" : baseApproval;
12+
}
13+
1014
interface AIToolApprovalButtonsProps {
1115
count: number;
1216
onApprove: () => void;
@@ -73,10 +77,10 @@ interface AIToolUseBatchProps {
7377
const AIToolUseBatch = memo(({ parts, isStreaming }: AIToolUseBatchProps) => {
7478
const [userApprovalOverride, setUserApprovalOverride] = useState<string | null>(null);
7579

80+
// All parts in a batch have the same approval status (enforced by grouping logic in AIToolUseGroup)
7681
const firstTool = parts[0].data;
7782
const baseApproval = userApprovalOverride || firstTool.approval;
78-
const effectiveApproval = !isStreaming && baseApproval === "needs-approval" ? "timeout" : baseApproval;
79-
const allNeedApproval = parts.every((p) => (userApprovalOverride || p.data.approval) === "needs-approval");
83+
const effectiveApproval = getEffectiveApprovalStatus(baseApproval, isStreaming);
8084

8185
useEffect(() => {
8286
if (!isStreaming || effectiveApproval !== "needs-approval") return;
@@ -113,7 +117,7 @@ const AIToolUseBatch = memo(({ parts, isStreaming }: AIToolUseBatchProps) => {
113117
<AIToolUseBatchItem key={idx} part={part} effectiveApproval={effectiveApproval} />
114118
))}
115119
</div>
116-
{allNeedApproval && effectiveApproval === "needs-approval" && (
120+
{effectiveApproval === "needs-approval" && (
117121
<AIToolApprovalButtons count={parts.length} onApprove={handleApprove} onDeny={handleDeny} />
118122
)}
119123
</div>
@@ -139,7 +143,7 @@ const AIToolUse = memo(({ part, isStreaming }: AIToolUseProps) => {
139143
toolData.status === "completed" ? "text-success" : toolData.status === "error" ? "text-error" : "text-gray-400";
140144

141145
const baseApproval = userApprovalOverride || toolData.approval;
142-
const effectiveApproval = !isStreaming && baseApproval === "needs-approval" ? "timeout" : baseApproval;
146+
const effectiveApproval = getEffectiveApprovalStatus(baseApproval, isStreaming);
143147

144148
const isFileWriteTool = toolData.toolname === "write_text_file" || toolData.toolname === "edit_text_file";
145149

@@ -258,23 +262,40 @@ export const AIToolUseGroup = memo(({ parts, isStreaming }: AIToolUseGroupProps)
258262
return toolName === "read_text_file" || toolName === "read_dir";
259263
};
260264

261-
const groupedItems: ToolGroupItem[] = [];
262-
let currentBatch: Array<WaveUIMessagePart & { type: "data-tooluse" }> = [];
265+
const needsApproval = (part: WaveUIMessagePart & { type: "data-tooluse" }) => {
266+
return getEffectiveApprovalStatus(part.data?.approval, isStreaming) === "needs-approval";
267+
};
268+
269+
const readFileNeedsApproval: Array<WaveUIMessagePart & { type: "data-tooluse" }> = [];
270+
const readFileOther: Array<WaveUIMessagePart & { type: "data-tooluse" }> = [];
263271

264272
for (const part of parts) {
265273
if (isFileOp(part)) {
266-
currentBatch.push(part);
267-
} else {
268-
if (currentBatch.length > 0) {
269-
groupedItems.push({ type: "batch", parts: currentBatch });
270-
currentBatch = [];
274+
if (needsApproval(part)) {
275+
readFileNeedsApproval.push(part);
276+
} else {
277+
readFileOther.push(part);
271278
}
272-
groupedItems.push({ type: "single", part });
273279
}
274280
}
275281

276-
if (currentBatch.length > 0) {
277-
groupedItems.push({ type: "batch", parts: currentBatch });
282+
const groupedItems: ToolGroupItem[] = [];
283+
let addedApprovalBatch = false;
284+
let addedOtherBatch = false;
285+
286+
for (const part of parts) {
287+
const isFileOpPart = isFileOp(part);
288+
const partNeedsApproval = needsApproval(part);
289+
290+
if (isFileOpPart && partNeedsApproval && !addedApprovalBatch) {
291+
groupedItems.push({ type: "batch", parts: readFileNeedsApproval });
292+
addedApprovalBatch = true;
293+
} else if (isFileOpPart && !partNeedsApproval && !addedOtherBatch) {
294+
groupedItems.push({ type: "batch", parts: readFileOther });
295+
addedOtherBatch = true;
296+
} else if (!isFileOpPart) {
297+
groupedItems.push({ type: "single", part });
298+
}
278299
}
279300

280301
return (

0 commit comments

Comments
 (0)