chore: land multi-daemon rollout

This commit is contained in:
Mohamed Boudra
2025-11-26 08:47:49 +00:00
parent 4ab79b1a50
commit 59967aad87
18 changed files with 758 additions and 259 deletions
@@ -1,33 +1,67 @@
import { useMemo } from "react";
import { useEffect, useMemo, useRef } from "react";
import { SessionProvider } from "@/contexts/session-context";
import { useDaemonRegistry, type DaemonProfile } from "@/contexts/daemon-registry-context";
import { useDaemonConnections } from "@/contexts/daemon-connections-context";
export function MultiDaemonSessionHost() {
const { daemons } = useDaemonRegistry();
const { activeDaemonId } = useDaemonConnections();
const { activeDaemonId, sessionAccessorRoles } = useDaemonConnections();
const autoConnectStatesRef = useRef<Map<string, boolean>>(new Map());
const primaryDaemonIds = useMemo(() => {
const ids = new Set<string>();
sessionAccessorRoles.forEach((roles, daemonId) => {
if (roles.has("primary")) {
ids.add(daemonId);
}
});
return ids;
}, [sessionAccessorRoles]);
useEffect(() => {
const trackedStates = autoConnectStatesRef.current;
const activeIds = new Set<string>();
for (const daemon of daemons) {
activeIds.add(daemon.id);
const previousAutoConnect = trackedStates.get(daemon.id);
if (daemon.autoConnect === false && previousAutoConnect !== false) {
console.info("[DaemonConnection]", {
event: "auto_connect_skip",
daemonId: daemon.id,
label: daemon.label,
reason: "autoConnect disabled",
timestamp: new Date().toISOString(),
});
}
trackedStates.set(daemon.id, daemon.autoConnect);
}
for (const daemonId of Array.from(trackedStates.keys())) {
if (!activeIds.has(daemonId)) {
trackedStates.delete(daemonId);
}
}
}, [daemons]);
const backgroundDaemons = useMemo<DaemonProfile[]>(() => {
const shouldConnect = new Map<string, DaemonProfile>();
for (const daemon of daemons) {
if (daemon.autoConnect) {
shouldConnect.set(daemon.id, daemon);
if (!daemon.autoConnect) {
continue;
}
}
if (activeDaemonId) {
const activeDaemon = daemons.find((daemon) => daemon.id === activeDaemonId);
if (activeDaemon) {
shouldConnect.set(activeDaemon.id, activeDaemon);
if (daemon.id === activeDaemonId) {
continue;
}
// The active daemon already wraps the UI tree via ProvidersWrapper,
// so we skip rendering it here to avoid duplicate websocket connections.
shouldConnect.delete(activeDaemonId);
if (primaryDaemonIds.has(daemon.id)) {
continue;
}
shouldConnect.set(daemon.id, daemon);
}
return Array.from(shouldConnect.values());
}, [daemons, activeDaemonId]);
}, [daemons, activeDaemonId, primaryDaemonIds]);
if (backgroundDaemons.length === 0) {
return null;
@@ -36,7 +70,12 @@ export function MultiDaemonSessionHost() {
return (
<>
{backgroundDaemons.map((daemon) => (
<SessionProvider key={daemon.id} serverUrl={daemon.wsUrl} serverId={daemon.id}>
<SessionProvider
key={daemon.id}
serverUrl={daemon.wsUrl}
serverId={daemon.id}
role="background"
>
{null}
</SessionProvider>
))}