/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
'use client'
import {
type ComponentProps,
createContext,
type ReactNode,
useContext,
} from 'react'
import type { ToolUIPart } from 'ai'
import { cn } from '@/lib/utils'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
// Workaround for missing types in 'ai' package
type ExtendedToolState =
| ToolUIPart['state']
| 'approval-requested'
| 'approval-responded'
| 'output-denied'
type ExtendedToolApproval = { approved: boolean }
type ConfirmationContextValue = {
approval: ExtendedToolApproval | undefined
state: ExtendedToolState
}
const ConfirmationContext = createContext(null)
const useConfirmation = () => {
const context = useContext(ConfirmationContext)
if (!context) {
throw new Error('Confirmation components must be used within Confirmation')
}
return context
}
export type ConfirmationProps = ComponentProps & {
approval?: ExtendedToolApproval
state: ExtendedToolState
}
export const Confirmation = ({
className,
approval,
state,
...props
}: ConfirmationProps) => {
if (!approval || state === 'input-streaming' || state === 'input-available') {
return null
}
return (
)
}
export type ConfirmationTitleProps = ComponentProps
export const ConfirmationTitle = ({
className,
...props
}: ConfirmationTitleProps) => (
)
export type ConfirmationRequestProps = {
children?: ReactNode
}
export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => {
const { state } = useConfirmation()
// Only show when approval is requested
if (state !== 'approval-requested') {
return null
}
return children
}
export type ConfirmationAcceptedProps = {
children?: ReactNode
}
export const ConfirmationAccepted = ({
children,
}: ConfirmationAcceptedProps) => {
const { approval, state } = useConfirmation()
// Only show when approved and in response states
if (
!approval?.approved ||
(state !== 'approval-responded' &&
state !== 'output-denied' &&
state !== 'output-available')
) {
return null
}
return children
}
export type ConfirmationRejectedProps = {
children?: ReactNode
}
export const ConfirmationRejected = ({
children,
}: ConfirmationRejectedProps) => {
const { approval, state } = useConfirmation()
// Only show when rejected and in response states
if (
approval?.approved !== false ||
(state !== 'approval-responded' &&
state !== 'output-denied' &&
state !== 'output-available')
) {
return null
}
return children
}
export type ConfirmationActionsProps = ComponentProps<'div'>
export const ConfirmationActions = ({
className,
...props
}: ConfirmationActionsProps) => {
const { state } = useConfirmation()
// Only show when approval is requested
if (state !== 'approval-requested') {
return null
}
return (
)
}
export type ConfirmationActionProps = ComponentProps
export const ConfirmationAction = (props: ConfirmationActionProps) => (
)