diff --git a/packages/server/src/server/agent/agent-projections.ts b/packages/server/src/server/agent/agent-projections.ts index 69f38ebde..c5a724377 100644 --- a/packages/server/src/server/agent/agent-projections.ts +++ b/packages/server/src/server/agent/agent-projections.ts @@ -17,12 +17,14 @@ export type { ManagedAgent }; type ProjectionOptions = { title?: string | null; + createdAt?: string; }; export function toStoredAgentRecord( agent: ManagedAgent, options?: ProjectionOptions ): StoredAgentRecord { + const createdAt = options?.createdAt ?? agent.createdAt.toISOString(); const config = buildSerializableConfig(agent.config); const persistence = sanitizePersistenceHandle(agent.persistence); @@ -30,7 +32,7 @@ export function toStoredAgentRecord( id: agent.id, provider: agent.provider, cwd: agent.cwd, - createdAt: agent.createdAt.toISOString(), + createdAt, updatedAt: agent.updatedAt.toISOString(), lastActivityAt: agent.updatedAt.toISOString(), lastUserMessageAt: agent.lastUserMessageAt diff --git a/packages/server/src/server/agent/agent-registry.test.ts b/packages/server/src/server/agent/agent-registry.test.ts index a94d8a55b..0604e32af 100644 --- a/packages/server/src/server/agent/agent-registry.test.ts +++ b/packages/server/src/server/agent/agent-registry.test.ts @@ -126,6 +126,30 @@ describe("AgentRegistry", () => { expect(persisted.config?.extra?.claude).toMatchObject({ maxThinkingTokens: 1024 }); }); + test("applySnapshot preserves original createdAt timestamp", async () => { + const agentId = "agent-created-at"; + const firstTimestamp = new Date("2025-01-01T00:00:00.000Z"); + await registry.applySnapshot( + createManagedAgent({ id: agentId, createdAt: firstTimestamp }) + ); + + const initialRecord = await registry.get(agentId); + expect(initialRecord?.createdAt).toBe(firstTimestamp.toISOString()); + + await registry.applySnapshot( + createManagedAgent({ + id: agentId, + createdAt: new Date("2025-02-01T00:00:00.000Z"), + updatedAt: new Date("2025-02-01T00:00:00.000Z"), + lifecycle: "running", + }) + ); + + const updatedRecord = await registry.get(agentId); + expect(updatedRecord?.createdAt).toBe(firstTimestamp.toISOString()); + expect(updatedRecord?.lastStatus).toBe("running"); + }); + test("stores titles independently of snapshots", async () => { await registry.applySnapshot( createManagedAgent({ diff --git a/packages/server/src/server/agent/agent-registry.ts b/packages/server/src/server/agent/agent-registry.ts index bcba509ea..cd84ce04b 100644 --- a/packages/server/src/server/agent/agent-registry.ts +++ b/packages/server/src/server/agent/agent-registry.ts @@ -109,6 +109,7 @@ export class AgentRegistry { const existing = this.cache.get(agent.id); const record = toStoredAgentRecord(agent, { title: existing?.title ?? null, + createdAt: existing?.createdAt, }); this.cache.set(agent.id, record); await this.flush();