diff --git a/packages/server/src/server/agent/agent-manager.test.ts b/packages/server/src/server/agent/agent-manager.test.ts index 4ec647ab4a..72798e6f6f 100644 --- a/packages/server/src/server/agent/agent-manager.test.ts +++ b/packages/server/src/server/agent/agent-manager.test.ts @@ -12768,6 +12768,34 @@ test("commits startup notices once on create and after restored history", async } }); +test("commits distinct new startup rows even when notification text matches", async () => { + const notice = { type: "notification", level: "warning", message: "Runtime warning" } as const; + const initialTimeline = [ + { item: notice, timestamp: "2026-11-07T00:00:00.000Z" }, + { item: notice, timestamp: "2026-11-07T00:01:00.000Z" }, + ]; + const client = new (class extends TestAgentClient { + override async createSession(config: AgentSessionConfig) { + return new (class extends TestAgentSession { + readonly initialTimeline = initialTimeline; + })(config); + } + })(); + const manager = new AgentManager({ clients: { [client.provider]: client }, logger }); + const agent = await manager.createAgent( + { provider: client.provider, cwd: tmpdir() }, + undefined, + {}, + ); + try { + expect( + (await manager.getTimelineRows(agent.id)).map(({ item, timestamp }) => ({ item, timestamp })), + ).toEqual(initialTimeline); + } finally { + await manager.closeAgent(agent.id); + } +}); + test("failed startup history closes the session without registering an agent", async () => { let closed = false; class FailingHistorySession extends TestAgentSession { diff --git a/packages/server/src/server/agent/plugin-provider.test.ts b/packages/server/src/server/agent/plugin-provider.test.ts index a9cf3b0ed5..a6aa20271e 100644 --- a/packages/server/src/server/agent/plugin-provider.test.ts +++ b/packages/server/src/server/agent/plugin-provider.test.ts @@ -1724,6 +1724,72 @@ test("commits notices emitted during session open as the initial timeline with s ); }); +test("reopening a plugin agent does not append the same startup notice", async () => { + await withObservedProvider( + { + openChildren(sessionId, emit) { + emit({ + type: "session.notice", + sessionId, + notice: { + id: "full-access", + severity: "warning", + title: "Full access", + }, + }); + }, + }, + async (client) => { + const manager = new AgentManager({ + clients: { [client.provider]: client }, + logger: createTestLogger(), + }); + const agent = await manager.createAgent( + { provider: client.provider, cwd: tmpdir() }, + undefined, + {}, + ); + try { + for (let attempt = 0; attempt < 4; attempt++) await manager.reloadAgentSession(agent.id); + expect( + (await manager.getTimelineRows(agent.id)).filter( + (row) => row.item.type === "notification", + ), + ).toHaveLength(1); + } finally { + await manager.closeAgent(agent.id); + } + }, + ); +}); + +test("a resumed plugin session offers only new startup rows to the manager", async () => { + await withObservedProvider( + { + openChildren(sessionId, emit) { + emit({ + type: "session.notice", + sessionId, + notice: { id: "full-access", severity: "warning", title: "Full access" }, + }); + }, + }, + async (client) => { + const config = { provider: client.provider, cwd: tmpdir() }; + const original = await client.createSession(config); + const handle = original.describePersistence()!; + expect(original.initialTimeline).toHaveLength(1); + await original.close(); + const resumed = await client.resumeSession(handle, config); + try { + expect(resumed.initialTimeline).toEqual([]); + } finally { + await resumed.close(); + } + }, + ); +}); + describe("pending provider responses", () => { test.each(["session.open", "catalog", "session.configure", "session.prompt"])( "preserves the send error for %s",