mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
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:
@@ -2763,6 +2763,13 @@ class CodexMcpAgentSession implements AgentSession {
|
||||
async setMode(modeId: string): Promise<void> {
|
||||
this.currentMode = modeId;
|
||||
this.config.modeId = modeId;
|
||||
// Update cached runtime info to reflect mode change
|
||||
if (this.cachedRuntimeInfo) {
|
||||
this.cachedRuntimeInfo = {
|
||||
...this.cachedRuntimeInfo,
|
||||
modeId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
// - The sandbox config IS passed correctly to Claude SDK
|
||||
// - Claude executes tool calls without requesting permission
|
||||
|
||||
3
plan.md
3
plan.md
@@ -1100,7 +1100,7 @@ Build a new Codex MCP provider side‑by‑side with the existing Codex SDK prov
|
||||
- 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).
|
||||
|
||||
- [ ] **Test**: Add daemon E2E test for `setAgentMode()`.
|
||||
- [x] **Test**: Add daemon E2E test for `setAgentMode()`.
|
||||
|
||||
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
|
||||
- Mode switch persists across messages
|
||||
- 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()`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user