From fd5e9a865739db7dfc8cf2ebfb7762bd732b1461 Mon Sep 17 00:00:00 2001 From: Gagancreates Date: Tue, 19 May 2026 04:16:55 +0530 Subject: [PATCH] feat: show agent and add swap-and-retry on acpx permission card --- apps/x/apps/renderer/src/App.tsx | 18 ++++++++++ .../ai-elements/permission-request.tsx | 36 ++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx index a06d6e4f..f61cc01d 100644 --- a/apps/x/apps/renderer/src/App.tsx +++ b/apps/x/apps/renderer/src/App.tsx @@ -5738,6 +5738,24 @@ function App() { onApproveSession={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'session')} onApproveAlways={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'always')} onDeny={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny')} + onSwitchAgent={async (newAgent) => { + const runIdForSwitch = tab.runId + await handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny') + window.dispatchEvent(new CustomEvent('code-mode-detected', { + detail: { runId: runIdForSwitch, agent: newAgent }, + })) + if (runIdForSwitch) { + try { + await window.ipc.invoke('runs:createMessage', { + runId: runIdForSwitch, + message: `Use ${newAgent === 'claude' ? 'Claude Code' : 'Codex'} instead — rerun the same task with the same prompt, just swap the agent binary to \`${newAgent}\`.`, + codeMode: newAgent, + }) + } catch (err) { + console.error('Failed to send swap-agent follow-up', err) + } + } + }} isProcessing={isActive && isProcessing} response={response} /> diff --git a/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx b/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx index c0369a9a..0a69bdea 100644 --- a/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx +++ b/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx @@ -9,7 +9,7 @@ import { DropdownMenuItem, } from "@/components/ui/dropdown-menu"; import { cn } from "@/lib/utils"; -import { AlertTriangleIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, XCircleIcon, XIcon } from "lucide-react"; +import { AlertTriangleIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, RefreshCwIcon, Terminal, XCircleIcon, XIcon } from "lucide-react"; import type { ComponentProps } from "react"; import { ToolCallPart } from "@x/shared/dist/message.js"; import { ToolPermissionMetadata } from "@x/shared/dist/runs.js"; @@ -21,6 +21,7 @@ export type PermissionRequestProps = ComponentProps<"div"> & { onApproveSession?: () => void; onApproveAlways?: () => void; onDeny?: () => void; + onSwitchAgent?: (newAgent: 'claude' | 'codex') => void; isProcessing?: boolean; response?: 'approve' | 'deny' | null; permission?: z.infer; @@ -41,6 +42,7 @@ export const PermissionRequest = ({ onApproveSession, onApproveAlways, onDeny, + onSwitchAgent, isProcessing = false, response = null, permission, @@ -54,6 +56,17 @@ export const PermissionRequest = ({ : null; const filePermission = permission?.kind === "file" ? permission : null; + // Detect acpx coding-agent invocations so we can show the agent identity and + // offer a one-click swap-and-retry. + const acpxAgent: 'claude' | 'codex' | null = (() => { + if (!command) return null; + const match = command.match(/\bacpx\b[\s\S]*?\b(claude|codex)\b\s+exec\b/); + return match ? (match[1] as 'claude' | 'codex') : null; + })(); + const otherAgent: 'claude' | 'codex' | null = acpxAgent === 'claude' ? 'codex' : acpxAgent === 'codex' ? 'claude' : null; + const agentDisplay = acpxAgent === 'claude' ? 'Claude Code' : acpxAgent === 'codex' ? 'Codex' : null; + const otherDisplay = otherAgent === 'claude' ? 'Claude Code' : otherAgent === 'codex' ? 'Codex' : null; + const isResponded = response !== null; const isApproved = response === 'approve'; @@ -89,6 +102,15 @@ export const PermissionRequest = ({

{isResponded ? "Requested:" : "The agent wants to execute:"} {toolCall.toolName} + {agentDisplay && ( + + + {agentDisplay} + + )}

{isResponded && ( @@ -201,6 +223,18 @@ export const PermissionRequest = ({ )} + {otherAgent && otherDisplay && onSwitchAgent && ( + + )}