import React, { useCallback, useMemo, useState } from 'react' import type { ChatMessageMeta, CheckpointReplyMetadata } from '../types/chat' import { MarkdownBody } from './MarkdownBody' interface DeliveryFeedbackPanelProps { meta: ChatMessageMeta onReply: (text: string, metadata?: CheckpointReplyMetadata) => void responded: boolean } function firstLine(text: string): string { return text.split('\n').map((line) => line.trim()).find(Boolean) ?? text } function checkpointStatusLabel(status: string): string { switch (status) { case 'ignored': return 'Ignored' case 'timeout': case 'timed_out': case 'expired': return 'Expired' case 'stale': case 'invalid': return 'Inactive' case 'superseded': return 'Superseded' case 'cancelled': case 'canceled': return 'Cancelled' case 'resolved': return 'Resolved' default: return 'Responded' } } export const DeliveryFeedbackPanel = React.memo(function DeliveryFeedbackPanel({ meta, onReply, responded, }: DeliveryFeedbackPanelProps) { const isResponded = responded const [feedback, setFeedback] = useState('') const [submittingAction, setSubmittingAction] = useState(null) const checkpointStatus = String(meta.checkpoint_status ?? '').trim().toLowerCase() const resolvedLabel = checkpointStatusLabel(checkpointStatus) const prompt = String(meta.prompt ?? meta.summary ?? '').trim() const baseTitle = String(meta.work_item_projection_title ?? firstLine(prompt) ?? 'Human Review').trim() || 'Human Review' const title = `${baseTitle} (for self-evolution)` const summary = String(meta.summary ?? '').trim() const activeSubagents = useMemo( () => (meta.active_subagents ?? []).filter((item) => !!item && typeof item === 'object'), [meta.active_subagents], ) const permissionRequests = useMemo( () => (meta.permission_requests ?? []).filter((item) => !!item && typeof item === 'object'), [meta.permission_requests], ) const worktreePath = String(meta.worktree_path ?? '').trim() const hasRuntimeState = activeSubagents.length > 0 || permissionRequests.length > 0 || !!worktreePath const actionsDisabled = isResponded || submittingAction !== null const buildReplyMetadata = useCallback((kind: NonNullable, text = ''): CheckpointReplyMetadata => { const checkpointId = String(meta.checkpoint_id ?? '').trim() if (!checkpointId) { throw new Error('Delivery self-evolution reply requires checkpoint_id metadata.') } const metadata: CheckpointReplyMetadata = { response_to_checkpoint_id: checkpointId, response_to_checkpoint_type: 'company_delivery_feedback', checkpoint_reply_kind: kind, } if (kind === 'approve' || kind === 'feedback') { metadata.self_evolution_trigger = true metadata.human_feedback_text = text } return metadata }, [meta.checkpoint_id]) const handleApprove = useCallback(() => { if (actionsDisabled) return const metadata = buildReplyMetadata('approve') setSubmittingAction('approve') onReply('I fully agree with this delivery.', metadata) }, [actionsDisabled, buildReplyMetadata, onReply]) const handleFeedback = useCallback(() => { const text = feedback.trim() if (actionsDisabled || !text) return const metadata = buildReplyMetadata('feedback', text) setSubmittingAction('feedback') onReply(text, metadata) setFeedback('') }, [actionsDisabled, buildReplyMetadata, feedback, onReply]) const handleIgnore = useCallback(() => { if (actionsDisabled) return const metadata = buildReplyMetadata('ignore') setSubmittingAction('ignore') onReply('Ignore this self-evolution review.', metadata) }, [actionsDisabled, buildReplyMetadata, onReply]) return (
{title}
{String(meta.feedback_scope ?? 'final').replace(/_/g, ' ')} {isResponded && {resolvedLabel}}
{summary && summary !== title && (
Summary
)} {prompt && (
Review Request
)} {hasRuntimeState && (
Runtime State
{worktreePath &&
Worktree: {worktreePath}
} {activeSubagents.length > 0 &&
Active subagents: {activeSubagents.length}
} {permissionRequests.length > 0 &&
Pending permission records: {permissionRequests.length}
}
)} {!isResponded && (