import { useState } from 'react'; import { useSessionActions, useSessionSelector } from '../../context/SessionContext.jsx'; import { useSettingsNamespace } from '../../settings/index.js'; import CardFrame from '../CardFrame/index.jsx'; function formatUpdatedAt(value) { const timestamp = Number(value); if (!Number.isFinite(timestamp) || timestamp <= 0) return null; const date = new Date(timestamp); if (Number.isNaN(date.getTime())) return null; return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit', second: '2-digit' }); } function OverseerMemoryPopup({ memory, onClose }) { const summary = typeof memory?.summary === 'string' && memory.summary.trim() ? memory.summary : 'Memory unavailable.'; const updatedAt = formatUpdatedAt(memory?.updatedAt); return (
event.stopPropagation()}> Close } bodyClassName="p-0.5 text-xs" > {/* The memory is rendered as the server's existing plain-text summary so this popup stays consistent with the overseer/admin debug display. */}
{summary}
); } function OverseerPreferencePanelBody() { const { identifySession } = useSessionActions(); const vote = useSessionSelector((state) => state.session?.overseerVote || null); const overseerMemory = useSessionSelector((state) => state.overseerMemory || null); const { value: profile } = useSettingsNamespace('profile', { nickname: '' }); const { value: identity } = useSettingsNamespace('identity', { cookieUserId: '' }); const { value, save } = useSettingsNamespace('overseerPreference', { enabled: false }); const [memoryOpen, setMemoryOpen] = useState(false); const enabled = Boolean(value?.enabled); const running = Boolean(vote?.running); const onToggle = async (event) => { const next = Boolean(event?.target?.checked); await save((current) => ({ ...(current || {}), enabled: next })); await identifySession({ cookieUserId: String(identity?.cookieUserId || '').trim(), nickname: String(profile?.nickname || '').trim(), overseerEnabled: next, }); }; const actions = ( ); return ( <> Enable a local LLM in chat
Yes!: {Number(vote?.yesCount || 0)}, No...: {Number(vote?.noCount || 0)}
{running ? 'Running!' : 'Stopped by vote.'}
{memoryOpen ? setMemoryOpen(false)} /> : null} ); } export default function OverseerPreferencePanel() { const visible = useSessionSelector((state) => { const vote = state.session?.overseerVote; // The server owns whether voting has any effect. The panel appears only // when the autonomous vote-gated scheduler is active; direct-address mode // is intentionally hidden because users invoke it by starting a chat // message with the configured overseer name instead of voting it on. return Boolean(vote?.votingEnabled); }); if (!visible) { return null; } return ; }