diff --git a/src/components/AgentChat.tsx b/src/components/AgentChat.tsx index 67388ed..5bfdaaf 100644 --- a/src/components/AgentChat.tsx +++ b/src/components/AgentChat.tsx @@ -107,7 +107,7 @@ export const AgentChat: React.FC = () => { } })()} - + {!state.pendingToolPermission && } diff --git a/src/components/ToolPermissionPrompt.tsx b/src/components/ToolPermissionPrompt.tsx index 87c1801..323d44d 100644 --- a/src/components/ToolPermissionPrompt.tsx +++ b/src/components/ToolPermissionPrompt.tsx @@ -19,19 +19,8 @@ export const ToolPermissionPrompt: React.FC = () => { const handleSubmit = (value: string) => { const response = value.trim() || "yes" - // Resolve ALL pending tool permission requests with the same response - // This handles the case where multiple tools are called in parallel - while ( - store.messageQueue.hasPendingRequests() && - store.pendingToolPermission - ) { - store.messageQueue.sendMessage(response) - - // Check if there are still more requests after sending - if (!store.messageQueue.hasPendingRequests()) { - break - } - } + // Send the permission response to the waiting canUseTool call + store.messageQueue.sendPermissionResponse(response) actions.setPendingToolPermission(undefined) actions.setInput("") diff --git a/src/utils/MessageQueue.ts b/src/utils/MessageQueue.ts index 9950269..a7338d3 100644 --- a/src/utils/MessageQueue.ts +++ b/src/utils/MessageQueue.ts @@ -2,6 +2,7 @@ import { EventEmitter } from "events" export class MessageQueue extends EventEmitter { private messageBuffer: string[] = [] + private permissionBuffer: string[] = [] constructor() { super() @@ -25,15 +26,39 @@ export class MessageQueue extends EventEmitter { } } + async waitForPermissionResponse(): Promise { + if (this.permissionBuffer.length > 0) { + return this.permissionBuffer.shift()! + } + + return new Promise((resolve) => { + this.once("permissionResponse", resolve) + }) + } + + sendPermissionResponse(value: string): void { + if (this.listenerCount("permissionResponse") > 0) { + this.emit("permissionResponse", value) + } else { + this.permissionBuffer.push(value) + } + } + clear(): void { this.removeAllListeners("message") + this.removeAllListeners("permissionResponse") this.messageBuffer = [] + this.permissionBuffer = [] } hasPendingRequests(): boolean { return this.listenerCount("message") > 0 } + hasPendingPermissionRequest(): boolean { + return this.listenerCount("permissionResponse") > 0 + } + subscribe(callback: (message: string) => void): () => void { this.on("message", callback) return () => { diff --git a/src/utils/__tests__/canUseTool.test.ts b/src/utils/__tests__/canUseTool.test.ts index 9f5f4b7..73a0c56 100644 --- a/src/utils/__tests__/canUseTool.test.ts +++ b/src/utils/__tests__/canUseTool.test.ts @@ -16,7 +16,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("yes") + queue.sendPermissionResponse("yes") const result = await promise expect(result.behavior).toBe("allow") @@ -37,7 +37,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("y") + queue.sendPermissionResponse("y") const result = await promise expect(result.behavior).toBe("allow") @@ -55,7 +55,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("allow") + queue.sendPermissionResponse("allow") const result = await promise expect(result.behavior).toBe("allow") @@ -73,7 +73,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("no") + queue.sendPermissionResponse("no") const result = await promise expect(result.behavior).toBe("deny") @@ -95,7 +95,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("n") + queue.sendPermissionResponse("n") const result = await promise expect(result.behavior).toBe("deny") @@ -113,7 +113,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("deny") + queue.sendPermissionResponse("deny") const result = await promise expect(result.behavior).toBe("deny") @@ -131,7 +131,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("YES") + queue.sendPermissionResponse("YES") const result = await promise expect(result.behavior).toBe("allow") @@ -149,7 +149,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage(" yes ") + queue.sendPermissionResponse(" yes ") const result = await promise expect(result.behavior).toBe("allow") @@ -167,7 +167,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("do something else") + queue.sendPermissionResponse("do something else") const result = await promise expect(result.behavior).toBe("deny") @@ -193,7 +193,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("yes") + queue.sendPermissionResponse("yes") await promise expect(callback).toHaveBeenCalledTimes(1) @@ -212,7 +212,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("yes") + queue.sendPermissionResponse("yes") const result = await promise expect(result.behavior).toBe("allow") @@ -250,7 +250,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("yes") + queue.sendPermissionResponse("yes") const result = await promise expect(result.behavior).toBe("allow") @@ -275,7 +275,7 @@ describe("createCanUseTool", () => { } ) - queue.sendMessage("no") + queue.sendPermissionResponse("no") await promise await new Promise((resolve) => setTimeout(resolve, 100)) diff --git a/src/utils/canUseTool.ts b/src/utils/canUseTool.ts index 0054d40..6e64461 100644 --- a/src/utils/canUseTool.ts +++ b/src/utils/canUseTool.ts @@ -25,7 +25,7 @@ export const createCanUseTool = (options: CanUseToolOptions) => { onToolPermissionRequest(toolName, input) } - const userResponse = await messageQueue.waitForMessage() + const userResponse = await messageQueue.waitForPermissionResponse() const response = userResponse.toLowerCase().trim() const CONFIRM = ["y", "yes", "allow"].includes(response)