diff --git a/app/server/modules/agents/agents-manager.ts b/app/server/modules/agents/agents-manager.ts index 962a4e03..690ef7e1 100644 --- a/app/server/modules/agents/agents-manager.ts +++ b/app/server/modules/agents/agents-manager.ts @@ -3,6 +3,7 @@ import type { BackupRunPayload, VolumeCommand, VolumeCommandResult } from "@zero import { Effect } from "effect"; import { config } from "../../core/config"; import { createAgentManagerRuntime, type AgentManagerEvent } from "./controller/server"; +import { LOCAL_AGENT_ID } from "./constants"; import { spawnLocalAgentProcess, stopLocalAgentProcess } from "./local/process"; import type { BackupExecutionProgress, BackupExecutionResult } from "./helpers/runtime-state"; import { createAgentRuntimeState } from "./helpers/runtime-state"; @@ -286,7 +287,16 @@ export const agentManager = { }; export const startLocalAgent = async () => { - await spawnLocalAgentProcess(getAgentRuntimeState()); + const runtime = getAgentRuntimeState(); + await spawnLocalAgentProcess(runtime); + + if (!runtime.agentManager) { + return; + } + + if (!(await runtime.agentManager.waitForAgentReady(LOCAL_AGENT_ID))) { + throw new Error("Local agent did not become ready before startup"); + } }; // fallow-ignore-next-line unused-export diff --git a/app/server/modules/agents/controller/server.ts b/app/server/modules/agents/controller/server.ts index 995ba237..f1c55e3b 100644 --- a/app/server/modules/agents/controller/server.ts +++ b/app/server/modules/agents/controller/server.ts @@ -46,6 +46,7 @@ class StopAgentManagerServerError extends Data.TaggedError("StopAgentManagerServ export function createAgentManagerRuntime(onEvent: (event: AgentManagerEvent) => void) { let sessions = new Map(); let runtimeScope: Scope.CloseableScope | null = null; + const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const closeSession = (sessionHandle: ControllerAgentSessionHandle) => Effect.gen(function* () { @@ -79,6 +80,11 @@ export function createAgentManagerRuntime(onEvent: (event: AgentManagerEvent) => const getSessionHandle = (agentId: string) => sessions.get(agentId); const getSession = (agentId: string) => getSessionHandle(agentId)?.session; + const isAgentReady = (agentId: string) => { + const session = getSession(agentId); + return !!session && Effect.runSync(session.isReady()); + }; + const handleSessionEvent = (params: { agentId: string; agentName: string; sessionId: string }) => { const { agentId, agentName } = params; @@ -290,6 +296,19 @@ export function createAgentManagerRuntime(onEvent: (event: AgentManagerEvent) => return { start, + waitForAgentReady: async (agentId: string, timeoutMs = 10_000) => { + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + if (isAgentReady(agentId)) { + return true; + } + + await sleep(50); + } + + return isAgentReady(agentId); + }, sendBackup: (agentId: string, payload: BackupRunPayload) => Effect.gen(function* () { const session = getSession(agentId);