Spaces:
Running
Running
File size: 4,093 Bytes
d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 d4017c8 11bf9b7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | import React, { useState, useCallback, useEffect } from 'react';
import { X } from 'lucide-react';
/**
* Modal for adding (or editing) the in-the-loop human participant.
*
* The user enters a name and a freeform self-description (experience,
* personality, etc.). On Approve the parent saves immediately and
* generates the structured credential summary in the background.
*/
export default function HumanParticipantModal({
isOpen,
initial,
onClose,
onSave,
onRemove,
}) {
const [name, setName] = useState('');
const [profileText, setProfileText] = useState('');
useEffect(() => {
if (!isOpen) return;
setName(initial?.name || 'Pat');
setProfileText(initial?.profile_text || '');
}, [isOpen, initial]);
const handleApprove = useCallback(() => {
if (!name.trim()) return;
if (!profileText.trim()) return;
const pid = initial?.participant_id || `human_${Date.now()}`;
onSave({
participant_id: pid,
name: name.trim(),
profile_text: profileText.trim(),
});
}, [name, profileText, initial, onSave]);
if (!isOpen) return null;
return (
<div className="ccai-credentials-overlay">
<div className="ccai-credentials-card ccai-human-modal-card">
<div className="ccai-credentials-header">
<div>
<h2>Add a Human Participant</h2>
<div className="ccai-credentials-subtitle">
Give yourself (or another human) a seat at the table.
The orchestrator will pause for your input when it's
your turn.
</div>
</div>
<div className="ccai-tab-spacer" />
<button className="modal-close" onClick={onClose}>×</button>
</div>
<div className="ccai-human-modal-body">
<label className="ccai-human-field">
<span className="ccai-human-field-label">Name</span>
<input
type="text"
className="ccai-human-input"
value={name}
onChange={e => setName(e.target.value)}
placeholder="e.g. Pat, Dr. Lopez, …"
/>
</label>
<label className="ccai-human-field">
<span className="ccai-human-field-label">
Experience, personality, …
</span>
<textarea
className="ccai-human-summary"
value={profileText}
onChange={e => setProfileText(e.target.value)}
rows={8}
spellCheck
placeholder={
'Describe your background, how you tend to argue, '
+ 'and anything the group should know about your perspective…'
}
/>
<div className="ccai-human-summary-help">
The orchestrator will turn this into a credential summary
for the group — the same way it assesses each LLM
participant's persona prompt.
</div>
</label>
</div>
<div className="ccai-human-modal-footer">
<div>
{onRemove && initial?.participant_id && (
<button
type="button"
className="btn-sm btn-outline ccai-human-remove"
onClick={onRemove}
title="Remove the human participant from this session"
>
<X size={14} style={{ marginRight: 4 }} />
Remove human
</button>
)}
</div>
<div className="ccai-human-modal-footer-right">
<button
type="button"
className="btn-sm btn-outline"
onClick={onClose}
>
Cancel
</button>
<button
type="button"
className="btn btn-primary btn-sm"
onClick={handleApprove}
disabled={!name.trim() || !profileText.trim()}
>
Approve
</button>
</div>
</div>
</div>
</div>
);
}
|