[Haik]: ckpt, auto spawn sub agent feature done and toggleable via settings

This commit is contained in:
haikdc
2026-03-20 12:25:49 -07:00
parent 6dcfb19b17
commit 03c1cb1c91
4 changed files with 116 additions and 1 deletions
+1
View File
@@ -23,4 +23,5 @@ class AppSettings(BaseModel):
browser_homepage: str = "https://www.google.com"
auto_select_mode_on_new_agent: bool = False
expand_new_chats_in_dashboard: bool = False
auto_reveal_sub_agents: bool = True
dev_mode: bool = False
@@ -34,7 +34,9 @@ import {
removeBrowserCard,
pasteBrowserCard,
placeCard,
removeCard,
setGlowingAgentCard,
clearGlowingAgentCard,
DEFAULT_CARD_W,
DEFAULT_CARD_H,
EXPANDED_CARD_MIN_H,
@@ -97,6 +99,7 @@ const DashboardInner: React.FC = () => {
const newAgentShortcut = useAppSelector((state) => state.settings.data.new_agent_shortcut);
const browserHomepage = useAppSelector((state) => state.settings.data.browser_homepage);
const expandNewChats = useAppSelector((state) => state.settings.data.expand_new_chats_in_dashboard);
const autoRevealSubAgents = useAppSelector((state) => state.settings.data.auto_reveal_sub_agents);
const outputs = useAppSelector((state) => state.outputs.items);
const glowingAgentCards = useAppSelector((state) => state.dashboardLayout.glowingAgentCards);
const sessionList = Object.values(sessions);
@@ -357,6 +360,100 @@ const DashboardInner: React.FC = () => {
dispatch(reconcileSessions({ sessionIds: dashboardSessionIds, expandedSessionIds }));
}, [sessions, layoutInitialized, dispatch, dashboardId, expandedSessionIds]);
// ---- Auto-reveal / collapse / unreveal sub-agent cards ----
const autoRevealedRef = useRef(new Set<string>());
const prevSubStatusRef = useRef<Record<string, string>>({});
const prevParentStatusRef = useRef<Record<string, string>>({});
useEffect(() => {
if (!layoutInitialized || !autoRevealSubAgents) return;
const subSessions = Object.values(sessions).filter(
(s) => (s.mode === 'sub-agent' || s.mode === 'invoked-agent') && s.parent_session_id,
);
// 1) Auto-reveal newly spawned sub-agents (skip already-terminal ones on load)
for (const sub of subSessions) {
if (autoRevealedRef.current.has(sub.id)) continue;
if (cards[sub.id]) {
autoRevealedRef.current.add(sub.id);
continue;
}
const parentCard = cards[sub.parent_session_id!];
if (!parentCard) continue;
const isTerminal = sub.status === 'completed' || sub.status === 'error' || sub.status === 'stopped';
const parentSession = sessions[sub.parent_session_id!];
const parentTerminal = parentSession &&
(parentSession.status === 'completed' || parentSession.status === 'error' || parentSession.status === 'stopped');
if (isTerminal && parentTerminal) {
autoRevealedRef.current.add(sub.id);
continue;
}
autoRevealedRef.current.add(sub.id);
const targetX = parentCard.x + parentCard.width + GRID_GAP * 12;
let targetY = parentCard.y;
const columnCards = Object.values(cards).filter(
(c) => Math.abs(c.x - targetX) < 50 && c.session_id !== sub.id,
);
if (columnCards.length > 0) {
const lowestBottom = Math.max(
...columnCards.map((c) => c.y + Math.max(EXPANDED_CARD_MIN_H, c.height)),
);
targetY = lowestBottom + GRID_GAP;
}
dispatch(placeCard({ sessionId: sub.id, x: targetX, y: targetY, width: DEFAULT_CARD_W, height: DEFAULT_CARD_H }));
dispatch(expandSession(sub.id));
const label = sub.mode === 'sub-agent' ? 'Create Agent' : 'Invoke Agent';
dispatch(setGlowingAgentCard({ sessionId: sub.id, sourceId: sub.parent_session_id!, label }));
if (sub.status === 'completed' || sub.status === 'error' || sub.status === 'stopped') {
const subId = sub.id;
setTimeout(() => dispatch(collapseSession(subId)), 2000);
}
}
// 2) Auto-collapse sub-agents when they complete
const TERMINAL = new Set(['completed', 'error', 'stopped']);
for (const sub of subSessions) {
const prev = prevSubStatusRef.current[sub.id];
if (prev !== sub.status && TERMINAL.has(sub.status) && cards[sub.id]) {
dispatch(collapseSession(sub.id));
}
}
const newSubStatuses: Record<string, string> = {};
for (const sub of subSessions) { newSubStatuses[sub.id] = sub.status; }
prevSubStatusRef.current = newSubStatuses;
// 3) Unreveal all sub-agent cards when parent finishes output
const parentIds = new Set(subSessions.map((s) => s.parent_session_id!));
for (const pid of parentIds) {
const parent = sessions[pid];
if (!parent) continue;
const prev = prevParentStatusRef.current[pid];
if (prev !== parent.status && TERMINAL.has(parent.status)) {
const children = subSessions.filter((s) => s.parent_session_id === pid);
for (const child of children) {
if (!cards[child.id]) continue;
dispatch(collapseSession(child.id));
dispatch(removeCard(child.id));
setTimeout(() => {
dispatch(clearGlowingAgentCard(child.id));
}, 500);
}
}
}
const newParentStatuses: Record<string, string> = {};
for (const pid of parentIds) {
const parent = sessions[pid];
if (parent) newParentStatuses[pid] = parent.status;
}
prevParentStatusRef.current = newParentStatuses;
}, [sessions, cards, layoutInitialized, autoRevealSubAgents, dispatch]);
const skipInitialSave = useRef(true);
const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const pendingSaveRef = useRef<Parameters<typeof saveLayout>[0] | null>(null);
+16 -1
View File
@@ -569,7 +569,7 @@ const Settings: React.FC = () => {
/>
</Box>
<Box sx={inlineRowLastSx}>
<Box sx={inlineRowSx}>
<Box sx={{ mr: 3 }}>
<Typography sx={labelSx}>Default agent spawn state in dashboard</Typography>
<Typography sx={descSx}>When enabled, new agents spawn expanded instead of collapsed.</Typography>
@@ -584,6 +584,21 @@ const Settings: React.FC = () => {
/>
</Box>
<Box sx={inlineRowLastSx}>
<Box sx={{ mr: 3 }}>
<Typography sx={labelSx}>Auto-reveal sub-agents on dashboard</Typography>
<Typography sx={descSx}>Automatically show sub-agent cards (from CreateAgent / InvokeAgent) tethered to their parent on the dashboard.</Typography>
</Box>
<Switch
checked={form.auto_reveal_sub_agents}
onChange={(e) => setForm({ ...form, auto_reveal_sub_agents: e.target.checked })}
sx={{
'& .MuiSwitch-switchBase.Mui-checked': { color: c.accent.primary },
'& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { bgcolor: c.accent.primary },
}}
/>
</Box>
{/* ── Browser ── */}
<Typography sx={{ ...sectionSx, mt: 3 }}>Browser</Typography>
@@ -24,6 +24,7 @@ export interface AppSettings {
browser_homepage: string;
auto_select_mode_on_new_agent: boolean;
expand_new_chats_in_dashboard: boolean;
auto_reveal_sub_agents: boolean;
dev_mode: boolean;
}
@@ -55,6 +56,7 @@ const initialState: SettingsState = {
browser_homepage: 'https://www.google.com',
auto_select_mode_on_new_agent: false,
expand_new_chats_in_dashboard: false,
auto_reveal_sub_agents: true,
dev_mode: false,
},
loading: false,