Add daemon E2E test for setAgentMode()
- Added E2E test that verifies mode switching (auto → read-only → full-access) - Test verifies mode persists across messages - Fixed bug: setMode() now updates cachedRuntimeInfo so getRuntimeInfo() returns correct modeId after mode change 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
5ce0a742e7
commit
18cc63fa39
@@ -2763,6 +2763,13 @@ class CodexMcpAgentSession implements AgentSession {
|
|||||||
async setMode(modeId: string): Promise<void> {
|
async setMode(modeId: string): Promise<void> {
|
||||||
this.currentMode = modeId;
|
this.currentMode = modeId;
|
||||||
this.config.modeId = modeId;
|
this.config.modeId = modeId;
|
||||||
|
// Update cached runtime info to reflect mode change
|
||||||
|
if (this.cachedRuntimeInfo) {
|
||||||
|
this.cachedRuntimeInfo = {
|
||||||
|
...this.cachedRuntimeInfo,
|
||||||
|
modeId,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPendingPermissions(): AgentPermissionRequest[] {
|
getPendingPermissions(): AgentPermissionRequest[] {
|
||||||
|
|||||||
@@ -708,6 +708,118 @@ describe("daemon E2E", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("setAgentMode", () => {
|
||||||
|
test(
|
||||||
|
"switches agent mode and persists across messages",
|
||||||
|
async () => {
|
||||||
|
const cwd = tmpCwd();
|
||||||
|
|
||||||
|
// Create a Codex agent with default mode ("auto")
|
||||||
|
const agent = await ctx.client.createAgent({
|
||||||
|
provider: "codex",
|
||||||
|
cwd,
|
||||||
|
title: "Mode Switch Test Agent",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(agent.id).toBeTruthy();
|
||||||
|
expect(agent.status).toBe("idle");
|
||||||
|
|
||||||
|
// Verify initial mode is "auto" (the default)
|
||||||
|
expect(agent.currentModeId).toBe("auto");
|
||||||
|
|
||||||
|
// Clear message queue before mode switch
|
||||||
|
ctx.client.clearMessageQueue();
|
||||||
|
const startPosition = ctx.client.getMessageQueue().length;
|
||||||
|
|
||||||
|
// Switch to "read-only" mode
|
||||||
|
await ctx.client.setAgentMode(agent.id, "read-only");
|
||||||
|
|
||||||
|
// Wait for agent_state update reflecting the new mode
|
||||||
|
const stateAfterModeSwitch = await new Promise<AgentSnapshotPayload>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
reject(new Error("Timeout waiting for mode change in agent_state"));
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
const checkForModeChange = (): void => {
|
||||||
|
const queue = ctx.client.getMessageQueue();
|
||||||
|
for (let i = startPosition; i < queue.length; i++) {
|
||||||
|
const msg = queue[i];
|
||||||
|
if (
|
||||||
|
msg.type === "agent_state" &&
|
||||||
|
msg.payload.id === agent.id &&
|
||||||
|
msg.payload.currentModeId === "read-only"
|
||||||
|
) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
clearInterval(interval);
|
||||||
|
resolve(msg.payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const interval = setInterval(checkForModeChange, 50);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify mode changed to "read-only"
|
||||||
|
expect(stateAfterModeSwitch.currentModeId).toBe("read-only");
|
||||||
|
|
||||||
|
// Now verify the mode persists: send a message and check the mode is still "read-only"
|
||||||
|
ctx.client.clearMessageQueue();
|
||||||
|
await ctx.client.sendMessage(agent.id, "Say 'hello' and nothing else");
|
||||||
|
|
||||||
|
const finalState = await ctx.client.waitForAgentIdle(agent.id, 120000);
|
||||||
|
|
||||||
|
// Mode should still be "read-only" after the message
|
||||||
|
expect(finalState.currentModeId).toBe("read-only");
|
||||||
|
|
||||||
|
// Also verify runtimeInfo has the updated modeId
|
||||||
|
expect(finalState.runtimeInfo?.modeId).toBe("read-only");
|
||||||
|
|
||||||
|
// Switch to another mode: "full-access"
|
||||||
|
ctx.client.clearMessageQueue();
|
||||||
|
const position2 = ctx.client.getMessageQueue().length;
|
||||||
|
|
||||||
|
await ctx.client.setAgentMode(agent.id, "full-access");
|
||||||
|
|
||||||
|
// Wait for agent_state update
|
||||||
|
const stateAfterFullAccess = await new Promise<AgentSnapshotPayload>(
|
||||||
|
(resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
reject(new Error("Timeout waiting for full-access mode change"));
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
const checkForModeChange = (): void => {
|
||||||
|
const queue = ctx.client.getMessageQueue();
|
||||||
|
for (let i = position2; i < queue.length; i++) {
|
||||||
|
const msg = queue[i];
|
||||||
|
if (
|
||||||
|
msg.type === "agent_state" &&
|
||||||
|
msg.payload.id === agent.id &&
|
||||||
|
msg.payload.currentModeId === "full-access"
|
||||||
|
) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
clearInterval(interval);
|
||||||
|
resolve(msg.payload);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const interval = setInterval(checkForModeChange, 50);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(stateAfterFullAccess.currentModeId).toBe("full-access");
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
rmSync(cwd, { recursive: true, force: true });
|
||||||
|
},
|
||||||
|
180000 // 3 minute timeout
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Claude permission tests are skipped due to SDK behavior:
|
// Claude permission tests are skipped due to SDK behavior:
|
||||||
// - The sandbox config IS passed correctly to Claude SDK
|
// - The sandbox config IS passed correctly to Claude SDK
|
||||||
// - Claude executes tool calls without requesting permission
|
// - Claude executes tool calls without requesting permission
|
||||||
|
|||||||
@@ -1100,7 +1100,7 @@ Build a new Codex MCP provider side‑by‑side with the existing Codex SDK prov
|
|||||||
- DaemonClient `cancelAgent()` method verified working
|
- DaemonClient `cancelAgent()` method verified working
|
||||||
- **Done (2025-12-25 17:44)**: WHAT: Added E2E test in `packages/server/src/server/daemon.e2e.test.ts:573-708` that creates a Codex agent, sends "Run: sleep 30" to trigger a long-running operation, waits for "running" status, calls `cancelAgent(agentId)`, verifies the agent stops within 2 seconds, and checks for no zombie "sleep 30" processes. RESULT: Test passes - agent cancel request is received, turn_failed is emitted, and agent becomes idle/error within milliseconds (test completed in 291ms). EVIDENCE: `npm run test --workspace=@paseo/server -- daemon.e2e.test.ts -t "cancelAgent"` (1 passed, 9 skipped in 846ms).
|
- **Done (2025-12-25 17:44)**: WHAT: Added E2E test in `packages/server/src/server/daemon.e2e.test.ts:573-708` that creates a Codex agent, sends "Run: sleep 30" to trigger a long-running operation, waits for "running" status, calls `cancelAgent(agentId)`, verifies the agent stops within 2 seconds, and checks for no zombie "sleep 30" processes. RESULT: Test passes - agent cancel request is received, turn_failed is emitted, and agent becomes idle/error within milliseconds (test completed in 291ms). EVIDENCE: `npm run test --workspace=@paseo/server -- daemon.e2e.test.ts -t "cancelAgent"` (1 passed, 9 skipped in 846ms).
|
||||||
|
|
||||||
- [ ] **Test**: Add daemon E2E test for `setAgentMode()`.
|
- [x] **Test**: Add daemon E2E test for `setAgentMode()`.
|
||||||
|
|
||||||
Switch agent mode and verify it takes effect.
|
Switch agent mode and verify it takes effect.
|
||||||
|
|
||||||
@@ -1115,6 +1115,7 @@ Build a new Codex MCP provider side‑by‑side with the existing Codex SDK prov
|
|||||||
- Test passes
|
- Test passes
|
||||||
- Mode switch persists across messages
|
- Mode switch persists across messages
|
||||||
- DaemonClient `setAgentMode()` method verified working
|
- DaemonClient `setAgentMode()` method verified working
|
||||||
|
- **Done (2025-12-25 17:48)**: WHAT: Added E2E test in `packages/server/src/server/daemon.e2e.test.ts:711-821` that creates Codex agent, verifies initial mode is "auto", switches to "read-only", verifies mode persists after sending a message, and switches to "full-access". FIXED BUG: `packages/server/src/server/agent/providers/codex-mcp-agent.ts:2763-2773` - `setMode()` was not updating `cachedRuntimeInfo`, so `getRuntimeInfo()` returned stale `modeId`. Fix: update `cachedRuntimeInfo.modeId` when mode changes. RESULT: Test passes - mode switch reflects in both `currentModeId` and `runtimeInfo.modeId`, persists across messages. EVIDENCE: `npm run test --workspace=@paseo/server -- daemon.e2e.test.ts -t "setAgentMode"` (1 passed, 10 skipped in 4154ms).
|
||||||
|
|
||||||
- [ ] **Test**: Add daemon E2E test for `listAgents()`.
|
- [ ] **Test**: Add daemon E2E test for `listAgents()`.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user