test(app): stabilize plan approval and script e2e

This commit is contained in:
Mohamed Boudra
2026-05-01 13:02:50 +07:00
parent 111935f4eb
commit ed70827f39
4 changed files with 98 additions and 13 deletions
+4 -6
View File
@@ -28,14 +28,12 @@ test.describe("Codex plan approval", () => {
}
const agent = await client.createAgent({
provider: "codex",
provider: "mock",
cwd: repo.path,
title: "Codex plan approval e2e",
model: "gpt-5.4-mini",
thinkingOptionId: "low",
featureValues: { plan_mode: true, fast_mode: true },
initialPrompt:
"Create a concise plan to add a README note. Present the plan only and wait for approval.",
modeId: "load-test",
model: "ten-second-stream",
initialPrompt: "Emit synthetic plan approval.",
});
const agentUrl = `${buildHostWorkspaceRoute(
+1
View File
@@ -585,6 +585,7 @@ function startDaemon(args: DaemonSpawnArgs): ChildProcess {
PASEO_CORS_ORIGINS: `http://localhost:${args.metroPort}`,
PASEO_DICTATION_ENABLED: openAiUsable ? "1" : "0",
PASEO_VOICE_MODE_ENABLED: openAiUsable ? "1" : "0",
PASEO_NODE_ENV: "development",
...(openAiUsable
? {
PASEO_DICTATION_STT_PROVIDER: "openai",
@@ -279,7 +279,7 @@ test.describe("Workspace setup streaming", () => {
await page.getByTestId("workspace-scripts-button").click();
await expect(page.getByTestId("workspace-scripts-menu")).toBeVisible({ timeout: 10_000 });
await page.getByTestId("workspace-scripts-start-web").click();
await page.keyboard.press("Escape");
await page.getByTestId("workspace-scripts-menu-backdrop").click();
const terminalTab = page.locator('[data-testid^="workspace-tab-terminal_"]').first();
await expect(terminalTab).toBeVisible({ timeout: 30_000 });
@@ -99,6 +99,10 @@ interface AgentStreamStressRequest {
coalesced: boolean;
}
function shouldEmitPlanApprovalPrompt(prompt: AgentPromptInput): boolean {
return /emit\s+(?:a\s+)?synthetic\s+plan\s+approval/i.test(promptToText(prompt));
}
function resolveModelProfile(modelId: string | null | undefined): {
modelId: string;
durationMs: number;
@@ -288,6 +292,7 @@ export class MockLoadTestAgentSession implements AgentSession {
private readonly history: AgentStreamEvent[] = [];
private readonly logger?: Logger;
private activeTurn: ActiveTurn | null = null;
private pendingPermissions = new Map<string, AgentPermissionRequest>();
private modeId: string | null;
private modelId: string | null;
@@ -336,7 +341,9 @@ export class MockLoadTestAgentSession implements AgentSession {
const largePayload = parseLargeAgentStreamPayloadPrompt(prompt);
const stress = parseAgentStreamStressPrompt(prompt);
if (largePayload) {
if (shouldEmitPlanApprovalPrompt(prompt)) {
this.schedulePlanApprovalTurn(turn);
} else if (largePayload) {
this.scheduleLargePayloadTurn(turn, largePayload);
} else if (stress) {
this.scheduleStressTurn(turn, stress);
@@ -381,13 +388,29 @@ export class MockLoadTestAgentSession implements AgentSession {
}
getPendingPermissions(): AgentPermissionRequest[] {
return [];
return Array.from(this.pendingPermissions.values());
}
async respondToPermission(
_requestId: string,
_response: AgentPermissionResponse,
requestId: string,
response: AgentPermissionResponse,
): Promise<AgentPermissionResult | void> {
if (!this.pendingPermissions.delete(requestId)) {
return undefined;
}
const turn = this.activeTurn;
this.emit({
type: "permission_resolved",
provider: this.provider,
requestId,
resolution: response,
...(turn ? { turnId: turn.turnId } : {}),
});
if (turn) {
this.finishTurnWithText(turn, "Synthetic plan approval resolved");
}
return undefined;
}
@@ -457,6 +480,65 @@ export class MockLoadTestAgentSession implements AgentSession {
turn.timer.unref?.();
}
private schedulePlanApprovalTurn(turn: ActiveTurn): void {
turn.timer = setTimeout(() => {
this.emitPlanApprovalTurn(turn);
}, 0);
turn.timer.unref?.();
}
private emitPlanApprovalTurn(turn: ActiveTurn): void {
if (this.activeTurn !== turn) {
return;
}
this.clearTurnTimer(turn);
this.emit({
type: "turn_started",
provider: this.provider,
turnId: turn.turnId,
});
const request: AgentPermissionRequest = {
id: `mock-plan-${turn.turnId}`,
provider: this.provider,
name: "MockPlanApproval",
kind: "plan",
title: "Plan",
description: "Review the proposed plan before implementation starts.",
input: {
plan: "1. Add the README note.\n2. Keep the change scoped.\n3. Verify the diff.",
},
actions: [
{
id: "implement",
label: "Implement",
behavior: "allow",
variant: "primary",
intent: "implement",
},
{
id: "dismiss",
label: "Dismiss",
behavior: "deny",
variant: "secondary",
intent: "dismiss",
},
],
metadata: {
source: "mock_plan_approval",
},
};
this.pendingPermissions.set(request.id, request);
this.emit({
type: "permission_requested",
provider: this.provider,
request,
turnId: turn.turnId,
});
}
private emitStressTurn(turn: ActiveTurn, stress: AgentStreamStressRequest): void {
if (this.activeTurn !== turn) {
return;
@@ -695,11 +777,15 @@ export class MockLoadTestAgentSession implements AgentSession {
}
private finishTurn(turn: ActiveTurn): void {
this.activeTurn = null;
this.emitTimeline(turn.turnId, {
type: "assistant_message",
text: "## Synthetic load test complete\n\nThe mock provider finished its foreground turn.\n",
});
this.finishTurnWithText(turn, "Synthetic load test complete");
}
private finishTurnWithText(turn: ActiveTurn, finalText: string): void {
this.activeTurn = null;
const usage = {
inputTokens: turn.iteration * 32,
outputTokens: turn.iteration * 128,
@@ -714,7 +800,7 @@ export class MockLoadTestAgentSession implements AgentSession {
});
turn.resolve({
sessionId: this.id,
finalText: "Synthetic load test complete",
finalText,
usage,
timeline: [],
canceled: false,