diff --git a/packages/server/src/server/agent/agent-manager.test.ts b/packages/server/src/server/agent/agent-manager.test.ts index b139b3a4b7..645b3aaa20 100644 --- a/packages/server/src/server/agent/agent-manager.test.ts +++ b/packages/server/src/server/agent/agent-manager.test.ts @@ -5597,6 +5597,37 @@ test("setLabels merges and persists labels", async () => { }); }); +test("reopening a closed agent keeps metadata saved while the loader was reading its record", async () => { + const workdir = mkdtempSync(join(tmpdir(), "agent-manager-metadata-reopen-")); + const storage = new AgentStorage(join(workdir, "agents"), logger); + const manager = new AgentManager({ + clients: { codex: new TestAgentClient() }, + registry: storage, + logger, + }); + const created = await manager.createAgent( + { provider: "codex", cwd: workdir, title: "Metadata reopen" }, + undefined, + { workspaceId: undefined, metadata: { first: 1 } }, + ); + const agentId = created.id; + await manager.closeAgent(agentId); + + // The loader reads the record, then a setMetadata is queued before its resume runs. + const readByLoader = await storage.get(agentId); + const saved = manager.setMetadata(agentId, { second: 2 }); + const reopened = manager.resumeAgentFromPersistence( + { provider: "codex", sessionId: "session-metadata", metadata: { cwd: workdir } }, + { cwd: workdir }, + agentId, + { metadata: readByLoader?.metadata }, + ); + + expect(await saved).toEqual({ first: 1, second: 2 }); + expect((await reopened).metadata).toEqual({ first: 1, second: 2 }); + expect((await storage.get(agentId))?.metadata).toEqual({ first: 1, second: 2 }); +}); + test("detachAgent removes relationship lifecycle labels from a live agent and emits state", async () => { const workdir = mkdtempSync(join(tmpdir(), "agent-manager-detach-live-")); const storagePath = join(workdir, "agents"); diff --git a/packages/server/src/server/agent/agent-manager.ts b/packages/server/src/server/agent/agent-manager.ts index a3a046cf1d..98a6f00914 100644 --- a/packages/server/src/server/agent/agent-manager.ts +++ b/packages/server/src/server/agent/agent-manager.ts @@ -1597,6 +1597,9 @@ export class AgentManager { return this.registerSession(session, storedConfig, resolvedAgentId, { launchedOptions, ...options, + // The caller read its metadata before this turn in the lane; a setMetadata queued ahead of + // it has saved a newer record, the one the open hooks saw. + ...(record ? { metadata: record.metadata } : {}), launchEnv, persistence: handle, restoring: true,