Skip to content

Commit 2144f4f

Browse files
committed
fix(acp): address Greptile review on session/load invariant tests
- Extract shared makeTestSession() factory to eliminate duplicated TestSession class definitions across all three tests (concern #1) - Pass handle through typed constructor option instead of casting private initialHandle field (concern #2) - Add missing type imports for AgentCapabilityFlags and AgentPersistenceHandle
1 parent 0aa23df commit 2144f4f

1 file changed

Lines changed: 42 additions & 102 deletions

File tree

packages/server/src/server/agent/providers/acp-agent.test.ts

Lines changed: 42 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
import { GenericACPAgentClient } from "./generic-acp-agent.js";
4444
import { transformPiModels } from "./pi/agent.js";
4545
import type { AgentStreamEvent } from "../agent-sdk-types.js";
46+
import type { AgentCapabilityFlags, AgentPersistenceHandle } from "../agent-sdk-types.js";
4647
import { createTestLogger } from "../../../test-utils/test-logger.js";
4748
import { asInternals } from "../../test-utils/class-mocks.js";
4849
import * as spawnUtils from "../../../utils/spawn.js";
@@ -2453,8 +2454,24 @@ describe("ACPAgentClient probe cleanup", () => {
24532454
});
24542455

24552456
describe("ACP session/load invariant — cwd and mcpServers always passed", () => {
2456-
test("loadSession is always called with sessionId, cwd, and mcpServers even when mcpServers is empty", async () => {
2457-
const loadSession = vi.fn().mockResolvedValue({
2457+
/**
2458+
* Shared factory: creates an ACPAgentSession subclass whose spawnProcess
2459+
* returns stubbed ACP internals so tests can inspect connection method calls
2460+
* without spawning real processes. Each call produces fresh vi.fn() stubs.
2461+
*/
2462+
function makeTestSession(args: {
2463+
capabilities?: AgentCapabilityFlags;
2464+
handle: AgentPersistenceHandle;
2465+
loadSession?: ReturnType<typeof vi.fn>;
2466+
unstableResumeSession?: ReturnType<typeof vi.fn>;
2467+
}) {
2468+
const loadSession = args.loadSession ?? vi.fn().mockResolvedValue({
2469+
sessionId: "session-1",
2470+
modes: null,
2471+
models: null,
2472+
configOptions: [],
2473+
});
2474+
const unstableResumeSession = args.unstableResumeSession ?? vi.fn().mockResolvedValue({
24582475
sessionId: "session-1",
24592476
modes: null,
24602477
models: null,
@@ -2468,17 +2485,16 @@ describe("ACP session/load invariant — cwd and mcpServers always passed", () =
24682485
connection: {
24692486
prompt: vi.fn(),
24702487
loadSession,
2471-
},
2472-
initialize: { agentCapabilities: { loadSession: true } },
2473-
} as unknown as SpawnedACPProcess;
2488+
unstable_resumeSession: unstableResumeSession,
2489+
} as unknown as ClientSideConnection,
2490+
initialize: { agentCapabilities: args.capabilities ?? {} },
2491+
} as SpawnedACPProcess;
24742492
}
24752493
}
24762494

2495+
// Pass handle through the typed constructor option (no private-field casts).
24772496
const session = new TestSession(
2478-
{
2479-
provider: "claude-acp",
2480-
cwd: "/tmp/paseo-acp-test",
2481-
},
2497+
{ provider: "claude-acp", cwd: "/tmp/paseo-acp-test" },
24822498
{
24832499
provider: "claude-acp",
24842500
logger: createTestLogger(),
@@ -2491,14 +2507,20 @@ describe("ACP session/load invariant — cwd and mcpServers always passed", () =
24912507
supportsMcpServers: true,
24922508
supportsReasoningStream: true,
24932509
supportsToolInvocations: true,
2510+
...args.capabilities,
24942511
},
2512+
handle: args.handle,
24952513
},
24962514
);
2497-
// Provide the persistence handle that initializeResumedSession requires
2498-
(session as unknown as { initialHandle: unknown }).initialHandle = {
2499-
sessionId: "session-1",
2500-
provider: "claude-acp",
2501-
};
2515+
2516+
return { session, loadSession, unstableResumeSession };
2517+
}
2518+
2519+
test("loadSession is always called with sessionId, cwd, and mcpServers even when mcpServers is empty", async () => {
2520+
const { session, loadSession } = makeTestSession({
2521+
capabilities: { loadSession: true, supportsMcpServers: true },
2522+
handle: { sessionId: "session-1", provider: "claude-acp" },
2523+
});
25022524

25032525
await session.initializeResumedSession();
25042526

@@ -2510,51 +2532,11 @@ describe("ACP session/load invariant — cwd and mcpServers always passed", () =
25102532
});
25112533

25122534
test("loadSession is always called with mcpServers even when supportsMcpServers is false", async () => {
2513-
const loadSession = vi.fn().mockResolvedValue({
2514-
sessionId: "session-1",
2515-
modes: null,
2516-
models: null,
2517-
configOptions: [],
2535+
const { session, loadSession } = makeTestSession({
2536+
capabilities: { loadSession: true, supportsMcpServers: false },
2537+
handle: { sessionId: "session-1", provider: "claude-acp" },
25182538
});
25192539

2520-
class TestSession extends ACPAgentSession {
2521-
protected override async spawnProcess(): Promise<SpawnedACPProcess> {
2522-
return {
2523-
child: createProbeChildStub(),
2524-
connection: {
2525-
prompt: vi.fn(),
2526-
loadSession,
2527-
},
2528-
initialize: { agentCapabilities: { loadSession: true } },
2529-
} as unknown as SpawnedACPProcess;
2530-
}
2531-
}
2532-
2533-
const session = new TestSession(
2534-
{
2535-
provider: "claude-acp",
2536-
cwd: "/tmp/paseo-acp-test",
2537-
},
2538-
{
2539-
provider: "claude-acp",
2540-
logger: createTestLogger(),
2541-
defaultCommand: ["claude", "--acp"],
2542-
defaultModes: [],
2543-
capabilities: {
2544-
supportsStreaming: true,
2545-
supportsSessionPersistence: true,
2546-
supportsDynamicModes: true,
2547-
supportsMcpServers: false,
2548-
supportsReasoningStream: true,
2549-
supportsToolInvocations: true,
2550-
},
2551-
},
2552-
);
2553-
(session as unknown as { initialHandle: unknown }).initialHandle = {
2554-
sessionId: "session-1",
2555-
provider: "claude-acp",
2556-
};
2557-
25582540
await session.initializeResumedSession();
25592541

25602542
// Even with supportsMcpServers=false, mcpServers: [] must still be passed
@@ -2566,53 +2548,11 @@ describe("ACP session/load invariant — cwd and mcpServers always passed", () =
25662548
});
25672549

25682550
test("unstable_resumeSession is always called with sessionId, cwd, and mcpServers", async () => {
2569-
const unstableResumeSession = vi.fn().mockResolvedValue({
2570-
sessionId: "session-1",
2571-
modes: null,
2572-
models: null,
2573-
configOptions: [],
2551+
const { session, unstableResumeSession } = makeTestSession({
2552+
capabilities: { sessionCapabilities: { resume: {} } },
2553+
handle: { sessionId: "session-1", provider: "claude-acp" },
25742554
});
25752555

2576-
class TestSession extends ACPAgentSession {
2577-
protected override async spawnProcess(): Promise<SpawnedACPProcess> {
2578-
return {
2579-
child: createProbeChildStub(),
2580-
connection: {
2581-
prompt: vi.fn(),
2582-
unstable_resumeSession: unstableResumeSession,
2583-
},
2584-
initialize: {
2585-
agentCapabilities: { sessionCapabilities: { resume: {} } },
2586-
},
2587-
} as unknown as SpawnedACPProcess;
2588-
}
2589-
}
2590-
2591-
const session = new TestSession(
2592-
{
2593-
provider: "claude-acp",
2594-
cwd: "/tmp/paseo-acp-test",
2595-
},
2596-
{
2597-
provider: "claude-acp",
2598-
logger: createTestLogger(),
2599-
defaultCommand: ["claude", "--acp"],
2600-
defaultModes: [],
2601-
capabilities: {
2602-
supportsStreaming: true,
2603-
supportsSessionPersistence: true,
2604-
supportsDynamicModes: true,
2605-
supportsMcpServers: true,
2606-
supportsReasoningStream: true,
2607-
supportsToolInvocations: true,
2608-
},
2609-
},
2610-
);
2611-
(session as unknown as { initialHandle: unknown }).initialHandle = {
2612-
sessionId: "session-1",
2613-
provider: "claude-acp",
2614-
};
2615-
26162556
await session.initializeResumedSession();
26172557

26182558
expect(unstableResumeSession).toHaveBeenCalledWith({

0 commit comments

Comments
 (0)