// Primus IQ — Chat screen components // HITL approval card: the agent proposed a report plan (template + outline); // the user picks/edits and approves, edits, or rejects before generation starts. const ReportPlanCard = ({ plan, onDecide }) => { const args = plan.args || {}; const [templates, setTemplates] = React.useState([]); const [template, setTemplate] = React.useState(args.template_id || 'primus_research'); React.useEffect(() => { PrimusAPI.listReportTemplates() .then(r => setTemplates((r && r.templates) || [])) .catch(() => setTemplates([ { id: 'primus_research', name: 'Primus Research' }, { id: 'default', name: 'Default Report' }, ])); }, []); // If the proposed template_id isn't a real bundle, snap to primus_research once templates load. React.useEffect(() => { if (templates.length && !templates.some(t => t.id === template)) { setTemplate(templates.some(t => t.id === 'primus_research') ? 'primus_research' : templates[0].id); } }, [templates]); const [outlineText, setOutlineText] = React.useState((args.outline || []).join('\n')); const buildOutline = () => outlineText.split('\n').map(s => s.trim()).filter(Boolean); const approve = () => { const outline = buildOutline(); const changed = template !== args.template_id || outline.join('|') !== (args.outline || []).join('|'); if (changed) { // Edit: replace the tool-call args entirely (must include all fields). // Spread the original args first so agent-set fields the card doesn't show // (e.g. review_mode) are preserved, then override the two the user edits. onDecide({ type: 'edit', edited_action: { name: plan.action, args: { ...args, template_id: template, outline }, }, }); } else { onDecide({ type: 'approve' }); } }; return (
📄 Report plan — your approval needed
{args.title && (
{args.title}
)}