diff --git a/src/main/AryxAppService.ts b/src/main/AryxAppService.ts index d33d8e9..4822f0c 100644 --- a/src/main/AryxAppService.ts +++ b/src/main/AryxAppService.ts @@ -42,6 +42,7 @@ import { normalizeSessionApprovalSettings, pruneApprovalPolicyTools, pruneSessionApprovalSettings, + resolveApprovalToolKey, resolvePendingApproval, type ApprovalDecision, type PendingApprovalMessageRecord, @@ -124,7 +125,7 @@ type AppServiceEvents = { type PendingApprovalHandle = { sessionId: string; requestId: string; - resolve: (decision: ApprovalDecision) => void | Promise; + resolve: (decision: ApprovalDecision, alwaysApprove?: boolean) => void | Promise; }; type PendingUserInputHandle = { @@ -635,8 +636,8 @@ export class AryxAppService extends EventEmitter { await this.applyAgentActivity(workspace, session.id, requestId, event); }, async (event) => { - await this.handleApprovalRequested(workspace, session.id, requestId, event, (decision) => - this.sidecar.resolveApproval(event.approvalId, decision)); + await this.handleApprovalRequested(workspace, session.id, requestId, event, (decision, alwaysApprove) => + this.sidecar.resolveApproval(event.approvalId, decision, alwaysApprove)); }, async (event) => { await this.handleUserInputRequested(workspace, session.id, requestId, event, (answer, wasFreeform) => @@ -729,7 +730,7 @@ export class AryxAppService extends EventEmitter { this.setSessionPendingApprovalState(session, dequeuePendingApprovalState(session, approvalId)); session.updatedAt = resolvedAt; - const approvalKey = approval.toolName ?? approval.permissionKind; + const approvalKey = resolveApprovalToolKey(approval.toolName, approval.permissionKind); if (decision === 'approved' && alwaysApprove && approvalKey) { const existing = session.approvalSettings?.autoApprovedToolNames ?? []; if (!existing.includes(approvalKey)) { @@ -748,7 +749,7 @@ export class AryxAppService extends EventEmitter { this.pendingApprovalHandles.delete(approvalId); try { - await Promise.resolve(handle.resolve(decision)); + await Promise.resolve(handle.resolve(decision, alwaysApprove)); } catch (error) { const failedAt = nowIso(); this.rejectPendingApprovals( @@ -1396,7 +1397,7 @@ export class AryxAppService extends EventEmitter { sessionId: string, requestId: string, approval: ApprovalRequestedEvent | PendingApprovalRecord, - resolve: (decision: ApprovalDecision) => void | Promise, + resolve: (decision: ApprovalDecision, alwaysApprove?: boolean) => void | Promise, ): Promise { const session = this.requireSession(workspace, sessionId); const pendingApproval = diff --git a/src/main/sidecar/sidecarProcess.ts b/src/main/sidecar/sidecarProcess.ts index 9257c9a..be795b7 100644 --- a/src/main/sidecar/sidecarProcess.ts +++ b/src/main/sidecar/sidecarProcess.ts @@ -120,12 +120,13 @@ export class SidecarClient { }); } - async resolveApproval(approvalId: string, decision: ApprovalDecision): Promise { + async resolveApproval(approvalId: string, decision: ApprovalDecision, alwaysApprove?: boolean): Promise { return this.dispatch({ type: 'resolve-approval', requestId: `approval-${Date.now()}`, approvalId, decision, + alwaysApprove: alwaysApprove ?? false, }); } diff --git a/src/renderer/components/chat/ApprovalBanner.tsx b/src/renderer/components/chat/ApprovalBanner.tsx index 1fd9afe..8d16b14 100644 --- a/src/renderer/components/chat/ApprovalBanner.tsx +++ b/src/renderer/components/chat/ApprovalBanner.tsx @@ -3,7 +3,9 @@ import { Bot, Check, ChevronDown, Loader2, ShieldAlert, ShieldBan, ShieldCheck, import { MarkdownContent } from '@renderer/components/MarkdownContent'; import { permissionDetailSummary, PermissionDetailView } from '@renderer/components/chat/PermissionDetailView'; +import { resolveApprovalToolKey } from '@shared/domain/approval'; import type { ApprovalDecision, PendingApprovalRecord } from '@shared/domain/approval'; +import { resolveToolLabel } from '@shared/domain/tooling'; /* ── ApprovalBanner ────────────────────────────────────────── */ @@ -23,8 +25,9 @@ export function ApprovalBanner({ const kindLabel = approval.kind === 'final-response' ? 'Final response review' : 'Tool call approval'; const hasMessages = approval.messages && approval.messages.length > 0; const showPosition = position !== undefined && total !== undefined && total > 1; - const approvalToolKey = approval.toolName ?? approval.permissionKind; + const approvalToolKey = resolveApprovalToolKey(approval.toolName, approval.permissionKind); const canAlwaysApprove = approval.kind === 'tool-call' && !!approvalToolKey; + const approvalToolLabel = approvalToolKey ? resolveToolLabel(approvalToolKey) : undefined; return (
@@ -91,11 +94,11 @@ export function ApprovalBanner({ {canAlwaysApprove && (