diff --git a/client/src/pages/SeatsPage.tsx b/client/src/pages/SeatsPage.tsx index 80c3023..add5dea 100644 --- a/client/src/pages/SeatsPage.tsx +++ b/client/src/pages/SeatsPage.tsx @@ -64,6 +64,21 @@ interface Agent { skillKeys: string[] mcpServerIds: string[] docs: string[] + persona?: string | null +} + +interface AgentProfileLite { + id: string + profileKey: string + name: string + monogram?: string | null + recommendedAutonomy: string + skillKeys: string[] +} + +interface AgentProfileDetail { + profile: AgentProfileLite + body: string } const AUTONOMY = [ @@ -86,6 +101,7 @@ export function SeatsPage() { const [mcp, setMcp] = useState({ name: '', endpoint: '', headerName: 'Authorization', headerValue: '' }) const [newSeat, setNewSeat] = useState('') const [selectedSeat, setSelectedSeat] = useState(null) + const [profiles, setProfiles] = useState([]) const [agent, setAgent] = useState({ name: '', monogram: '', @@ -94,6 +110,7 @@ export function SeatsPage() { skillKeys: [] as string[], mcpServerIds: [] as string[], docs: '', + persona: '', }) const run = useCallback(async (action: () => Promise) => { @@ -128,6 +145,11 @@ export function SeatsPage() { const byKey = new Map() for (const s of lib) if (!byKey.has(s.skillKey)) byKey.set(s.skillKey, s) setSkills([...byKey.values()]) + // Agent profiles (AGENTS.md): one selectable entry per key (the resolvable winner is first). + const profileList = await api.get(`/api/orgboard/agent-profiles?organizationId=${organizationId}`) + const byProfileKey = new Map() + for (const p of profileList) if (!byProfileKey.has(p.profileKey)) byProfileKey.set(p.profileKey, p) + setProfiles([...byProfileKey.values()]) await loadConfigs() await loadMcpServers() }) @@ -217,11 +239,31 @@ export function SeatsPage() { skillKeys: existing.skillKeys, mcpServerIds: existing.mcpServerIds ?? [], docs: existing.docs.join(', '), + persona: existing.persona ?? '', } - : { name: '', monogram: '', autonomy: 'Gated', apiConfigId: configs[0]?.id ?? '', skillKeys: [], mcpServerIds: [], docs: '' }, + : { name: '', monogram: '', autonomy: 'Gated', apiConfigId: configs[0]?.id ?? '', skillKeys: [], mcpServerIds: [], docs: '', persona: '' }, ) }) + // Apply an AGENTS.md profile to the seat: prefill identity, autonomy, skills, and the persona + // (operating guide). The user can still tweak everything before saving. + const applyProfile = (key: string) => + run(async () => { + const versions = await api.get(`/api/orgboard/agent-profiles/${key}?organizationId=${organizationId}`) + const chosen = versions[0] + if (!chosen) return + const known = new Set(skills.map((s) => s.skillKey)) + setAgent((a) => ({ + ...a, + name: chosen.profile.name, + monogram: chosen.profile.monogram ?? '', + autonomy: chosen.profile.recommendedAutonomy, + skillKeys: chosen.profile.skillKeys.filter((k) => known.has(k)), + persona: chosen.body, + })) + toast.success(`Applied “${chosen.profile.name}”. Review and save.`) + }) + const saveAgent = () => run(async () => { if (!selectedSeat) return @@ -233,6 +275,7 @@ export function SeatsPage() { skillKeys: agent.skillKeys, mcpServerIds: agent.mcpServerIds, docs: agent.docs ? agent.docs.split(',').map((d) => d.trim()).filter(Boolean) : [], + persona: agent.persona.trim() || null, }) if (teamId) await loadSeats(teamId) toast.success(`${agent.name || 'Agent'} configured — seat is now AI.`) @@ -416,6 +459,19 @@ export function SeatsPage() { {selected && ( + {profiles.length > 0 && ( + + + + )} +
setAgent({ ...agent, name: e.target.value })} className="w-40" placeholder="Aria" /> @@ -494,6 +550,17 @@ export function SeatsPage() { setAgent({ ...agent, docs: e.target.value })} placeholder="product-docs, house-style" /> +
+ +