diff --git a/src/agents/tools/sessions.test.ts b/src/agents/tools/sessions.test.ts index dda5dae5140..2a777c98719 100644 --- a/src/agents/tools/sessions.test.ts +++ b/src/agents/tools/sessions.test.ts @@ -56,6 +56,29 @@ type SessionsListResult = Awaited< ReturnType["execute"]> >; +function requireRecord(value: unknown, label: string): Record { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error(`expected ${label}`); + } + return value as Record; +} + +function requireDetails(result: { details?: unknown }, label = "result details") { + return requireRecord(result.details, label); +} + +function requireSessions(details: Record) { + const sessions = details.sessions; + if (!Array.isArray(sessions)) { + throw new Error("expected details.sessions"); + } + return sessions.map((session, index) => requireRecord(session, `session ${index}`)); +} + +function requireGatewayRequest(index = 0) { + return requireRecord(callGatewayMock.mock.calls[index]?.[0], `gateway request ${index}`); +} + beforeAll(async () => { ({ createSessionsListTool } = await import("./sessions-list-tool.js")); ({ createSessionsSendTool } = await import("./sessions-send-tool.js")); @@ -167,7 +190,7 @@ function expectWorkerTranscriptPath( params: { containsPath: string; sessionId: string }, ) { const session = getFirstListedSession(result); - expect(session).toMatchObject({ key: "agent:worker:main" }); + expect(session?.key).toBe("agent:worker:main"); const transcriptPath = session?.transcriptPath ?? ""; expect(path.normalize(transcriptPath)).toContain(path.normalize(params.containsPath)); expect(transcriptPath).toMatch(new RegExp(`${params.sessionId}\\.jsonl$`)); @@ -328,8 +351,7 @@ describe("resolveAnnounceTarget", () => { threadId: "99", }); expect(callGatewayMock).toHaveBeenCalledTimes(1); - const first = callGatewayMock.mock.calls[0]?.[0] as { method?: string } | undefined; - expect(first).toMatchObject({ method: "sessions.list" }); + expect(requireGatewayRequest().method).toBe("sessions.list"); }); it("falls back to origin provider and accountId from sessions.list when legacy route fields are absent", async () => { @@ -435,10 +457,9 @@ describe("sessions_list gating", () => { it("filters out other agents when tools.agentToAgent.enabled is false", async () => { const tool = createMainSessionsListTool(); const result = await tool.execute("call1", {}); - expect(result.details).toMatchObject({ - count: 1, - sessions: [{ key: MAIN_AGENT_SESSION_KEY }], - }); + const details = requireDetails(result); + expect(details.count).toBe(1); + expect(requireSessions(details)[0]?.key).toBe(MAIN_AGENT_SESSION_KEY); }); it("keeps requester-owned cross-agent rows with tree visibility without a spawned lookup", async () => { @@ -462,10 +483,11 @@ describe("sessions_list gating", () => { const result = await createMainSessionsListTool().execute("call1", {}); - expect(result.details).toMatchObject({ - count: 1, - sessions: [{ key: "agent:codex:acp:child-1", spawnedBy: MAIN_AGENT_SESSION_KEY }], - }); + const details = requireDetails(result); + expect(details.count).toBe(1); + const session = requireSessions(details)[0]; + expect(session?.key).toBe("agent:codex:acp:child-1"); + expect(session?.spawnedBy).toBe(MAIN_AGENT_SESSION_KEY); expect(callGatewayMock).toHaveBeenCalledTimes(1); }); @@ -490,10 +512,11 @@ describe("sessions_list gating", () => { const result = await createMainSessionsListTool().execute("call1", {}); - expect(result.details).toMatchObject({ - count: 1, - sessions: [{ key: "agent:codex:acp:child-1", parentSessionKey: MAIN_AGENT_SESSION_KEY }], - }); + const details = requireDetails(result); + expect(details.count).toBe(1); + const session = requireSessions(details)[0]; + expect(session?.key).toBe("agent:codex:acp:child-1"); + expect(session?.parentSessionKey).toBe(MAIN_AGENT_SESSION_KEY); expect(callGatewayMock).toHaveBeenCalledTimes(1); }); @@ -653,9 +676,10 @@ describe("sessions_list channel derivation", () => { }); const result = await executeMainSessionsList(); - expect(result.details).toMatchObject({ - sessions: [{ key: "agent:main:discord:group:ops", channel: "discord" }], - }); + const details = requireDetails(result); + const session = requireSessions(details)[0]; + expect(session?.key).toBe("agent:main:discord:group:ops"); + expect(session?.channel).toBe("discord"); }); }); @@ -672,10 +696,9 @@ describe("sessions_send gating", () => { timeoutSeconds: 5, }); - expect(result.details).toMatchObject({ - status: "error", - error: "Either sessionKey or label is required", - }); + const details = requireDetails(result); + expect(details.status).toBe("error"); + expect(details.error).toBe("Either sessionKey or label is required"); expect(callGatewayMock).not.toHaveBeenCalled(); }); @@ -689,14 +712,13 @@ describe("sessions_send gating", () => { timeoutSeconds: 5, }); - expect(result.details).toMatchObject({ - status: "error", - }); + const details = requireDetails(result); + expect(details.status).toBe("error"); expect((result.details as { error?: string } | undefined)?.error ?? "").toContain( "No session found with label", ); expect(callGatewayMock).toHaveBeenCalledTimes(1); - expect(callGatewayMock.mock.calls[0]?.[0]).toMatchObject({ method: "sessions.resolve" }); + expect(requireGatewayRequest().method).toBe("sessions.resolve"); }); it("blocks cross-agent sends when tools.agentToAgent.enabled is false", async () => { @@ -709,8 +731,8 @@ describe("sessions_send gating", () => { }); expect(callGatewayMock).toHaveBeenCalledTimes(1); - expect(callGatewayMock.mock.calls[0]?.[0]).toMatchObject({ method: "sessions.list" }); - expect(result.details).toMatchObject({ status: "forbidden" }); + expect(requireGatewayRequest().method).toBe("sessions.list"); + expect(requireDetails(result).status).toBe("forbidden"); }); it("rejects direct thread session targets before dispatching an agent run", async () => { @@ -730,10 +752,9 @@ describe("sessions_send gating", () => { timeoutSeconds: 0, }); - expect(result.details).toMatchObject({ - status: "error", - sessionKey: threadSessionKey, - }); + const details = requireDetails(result); + expect(details.status).toBe("error"); + expect(details.sessionKey).toBe(threadSessionKey); expect((result.details as { error?: string } | undefined)?.error ?? "").toContain( "cannot target a thread session", ); @@ -758,15 +779,14 @@ describe("sessions_send gating", () => { timeoutSeconds: 0, }); - expect(result.details).toMatchObject({ - status: "error", - sessionKey: threadSessionKey, - }); + const details = requireDetails(result); + expect(details.status).toBe("error"); + expect(details.sessionKey).toBe(threadSessionKey); expect((result.details as { error?: string } | undefined)?.error ?? "").toContain( "cannot target a thread session", ); expect(callGatewayMock).toHaveBeenCalledTimes(1); - expect(callGatewayMock.mock.calls[0]?.[0]).toMatchObject({ method: "sessions.resolve" }); + expect(requireGatewayRequest().method).toBe("sessions.resolve"); }); it("does not reuse a stale assistant reply when no new reply appears", async () => { @@ -806,10 +826,9 @@ describe("sessions_send gating", () => { }); expect(historyCalls).toBe(2); - expect(result.details).toMatchObject({ - status: "ok", - reply: undefined, - sessionKey: MAIN_AGENT_SESSION_KEY, - }); + const details = requireDetails(result); + expect(details.status).toBe("ok"); + expect(details.reply).toBeUndefined(); + expect(details.sessionKey).toBe(MAIN_AGENT_SESSION_KEY); }); });