import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { ExecutionBlocker } from "@paperclipai/shared"; import { agentsApi } from "../api/agents"; import { activityApi } from "../api/activity"; import { queryKeys } from "../lib/queryKeys"; import { Button } from "./ui/button"; import { cn } from "../lib/utils"; import { Link } from "../lib/router"; export function ExecutionBlockerNotice({ companyId, issueId, blocker, onRetried, className }: { className?: string; companyId: string; issueId: string; blocker: ExecutionBlocker; onRetried: () => void; }) { const queryClient = useQueryClient(); const { data: runs, error: runsError } = useQuery({ queryKey: queryKeys.issues.runs(issueId), queryFn: () => activityApi.runsForIssue(issueId), }); const failedRun = runs?.find(run => run.runId === blocker.runId && ["failed", "timed_out"].includes(run.status)); const modelRejected = failedRun?.errorCode === "native_provider_model_rejected"; const requiresInspection = blocker.cause === "native_continuation_requires_reconciliation" || blocker.cause === "native_session_cleanup_quarantined"; const retry = useMutation({ mutationFn: () => agentsApi.retryFailedRun(blocker.agentId!, blocker.runId!, companyId), onSuccess: () => { onRetried(); for (const queryKey of [queryKeys.issues.detail(issueId), queryKeys.issues.runs(issueId), queryKeys.issues.liveRuns(issueId), queryKeys.issues.activeRun(issueId)]) { void queryClient.invalidateQueries({ queryKey }); } }, }); return (
{modelRejected ? "Model unavailable." : "Recovery needed."}{blocker.runError ? ` ${blocker.runError}` : ""}
{modelRejected &&Choose a supported model or clear the task's model override, then retry.
}{blocker.nextAction}
{Boolean(blocker.savedMessageCount) && ({blocker.savedMessageCount} saved {blocker.savedMessageCount === 1 ? "message is" : "messages are"} waiting for recovery.
)}{retry.error.message}
)} {runsError &&{runsError.message}
}