diff --git a/desktop/src/components/ConsentActions.tsx b/desktop/src/components/ConsentActions.tsx index e955c3c45..0e7a08f8e 100644 --- a/desktop/src/components/ConsentActions.tsx +++ b/desktop/src/components/ConsentActions.tsx @@ -38,11 +38,15 @@ export function ConsentActions({ scopes, requestedProjectId, onResolved, + source = "auth_requests", + canonicalId, }: { requestId: string; scopes: string[]; requestedProjectId?: string; onResolved?: () => void; + source?: string; + canonicalId?: string; }) { const needsProject = scopes.some((s) => PROJECT_SCOPES.has(s)); const [busy, setBusy] = useState(false); @@ -133,9 +137,15 @@ export function ConsentActions({ setBusy(false); return; } - const url = approved - ? `/api/agents/auth-requests/${encodeURIComponent(requestId)}/approve` - : `/api/agents/auth-requests/${encodeURIComponent(requestId)}/deny`; + if (source === "agent_scope_requests" && !canonicalId) { + setError("Missing agent identifier; cannot process this scope request."); + setBusy(false); + return; + } + const baseUrl = source === "agent_scope_requests" + ? `/api/agents/registry/${encodeURIComponent(canonicalId!)}/scope-requests/${encodeURIComponent(requestId)}` + : `/api/agents/auth-requests/${encodeURIComponent(requestId)}`; + const url = `${baseUrl}/${approved ? "approve" : "deny"}`; let body: string | undefined; if (approved) { const payload: { granted_scopes: string[]; project_id?: string } = { granted_scopes: scopes }; @@ -276,12 +286,13 @@ export function ConsentActions({ * is missing. */ export function consentPayload( data: Record | undefined, -): { requestId: string; scopes: string[]; projectId?: string } | null { +): { requestId: string; scopes: string[]; projectId?: string; canonicalId?: string } | null { if (!data) return null; const requestId = data.request_id; if (typeof requestId !== "string") return null; const raw = data.requested_scopes; const scopes = Array.isArray(raw) ? raw.filter((s): s is string => typeof s === "string") : []; const projectId = typeof data.project_id === "string" ? data.project_id : undefined; - return { requestId, scopes, projectId }; + const canonicalId = typeof data.canonical_id === "string" ? data.canonical_id : undefined; + return { requestId, scopes, projectId, canonicalId }; } diff --git a/desktop/src/components/NotificationCentre.tsx b/desktop/src/components/NotificationCentre.tsx index 309c41efa..aef268cb2 100644 --- a/desktop/src/components/NotificationCentre.tsx +++ b/desktop/src/components/NotificationCentre.tsx @@ -39,7 +39,7 @@ function NotificationItem({ }) { // Agent access-requests carry inline Allow/Deny actions. These nested buttons // live outside the clickable row to keep the markup valid. - const consent = n.source === "auth_requests" ? consentPayload(n.data) : null; + const consent = (n.source === "auth_requests" || n.source === "agent_scope_requests") ? consentPayload(n.data) : null; return (
diff --git a/desktop/src/components/NotificationToast.tsx b/desktop/src/components/NotificationToast.tsx index 61982e302..0fdced5c5 100644 --- a/desktop/src/components/NotificationToast.tsx +++ b/desktop/src/components/NotificationToast.tsx @@ -270,7 +270,7 @@ function ToastItem({ notif, onExpire }: { notif: Notification; onExpire: () => v const archiveRead = useNotificationStore((s) => s.archiveRead); const Icon = LEVEL_ICONS[notif.level]; const isAgentPaused = notif.source === "agent.paused"; - const consent = notif.source === "auth_requests" ? consentPayload(notif.data) : null; + const consent = (notif.source === "auth_requests" || notif.source === "agent_scope_requests") ? consentPayload(notif.data) : null; // Stable boolean for the effect dependency — using the `consent` object // would recreate the timer on every render because consentPayload() returns // a new object reference each time. @@ -307,6 +307,8 @@ function ToastItem({ notif, onExpire }: { notif: Notification; onExpire: () => v requestId={consent.requestId} scopes={consent.scopes} requestedProjectId={consent.projectId} + source={notif.source} + canonicalId={consent.canonicalId} onResolved={() => archiveRead(notif.id)} /> )}