对齐策划入口测试到新设计 Agent
Project CI / Repository checks (pull_request) Failing after 6m22s
Project CI / Frontend tests (pull_request) Failing after 6m48s
Project CI / Native shell tests (pull_request) Failing after 9m54s
Project CI / Backend tests (pull_request) Failing after 16m19s

新建策划入口走设计会话命令,已有 V2 会话仍走原链路
补审批与澄清卡界面用例
This commit is contained in:
2026-09-10 09:09:37 +00:00
parent aaa52c2b34
commit cb79c4a9c6
5 changed files with 151 additions and 10 deletions
@@ -2,7 +2,6 @@ use super::*;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};
use uuid::Uuid;
use serde_json::Value;
@@ -301,6 +300,7 @@ pub(crate) fn reject_design_phase(
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn phase_artifact_check_includes_previous_phases() {
@@ -1,6 +1,7 @@
/** @vitest-environment jsdom */
import { registerAgentRuntimeCommandTests } from './appSurface/agent-runtime.suite';
import { registerAuthTests } from './appSurface/auth.suite';
import { registerDesignAgentSurfaceTests } from './appSurface/design-agent.suite';
import {
registerDeveloperAgentWindowTests,
registerDeveloperToolsTests,
@@ -56,4 +57,5 @@ describe('AI 游戏创作 App 界面边界', () => {
registerAgentRuntimeCommandTests();
registerCanvasAssetTests();
registerPlanGddApprovalTests();
registerDesignAgentSurfaceTests();
});
@@ -0,0 +1,70 @@
import {
App,
createProjectSupervisorRuntimeHarness,
expect,
fireEvent,
it,
React,
render,
screen,
waitFor,
} from './harness';
function designApprovalView() {
return {
session: {
sessionId: 'design-session-1',
projectId: 'local-project-draft',
currentPhase: 'concept',
approvedPhases: [],
pendingApproval: {
requestId: 'approval-1',
phase: 'concept',
submittedAt: 1,
},
pendingClarification: null,
turnIndex: 2,
lastError: null,
},
messages: [{ id: 'a1', role: 'assistant', text: '概念稿已写好。' }],
running: false,
canRetry: false,
};
}
export function registerDesignAgentSurfaceTests() {
it('hydrates an existing design session and decides approval through design commands', async () => {
const harness = createProjectSupervisorRuntimeHarness({
designAgentView: designApprovalView(),
});
window.__TAURI__ = {
core: { invoke: harness.invoke },
event: { listen: harness.listen },
};
window.history.pushState({}, '', '/');
render(
React.createElement(App, {
initialProjectPath: harness.projectPath,
orchestrationMode: 'single-supervisor',
planningStartMode: true,
projectSupervisorOnly: true,
}),
);
await screen.findByLabelText('批准');
expect(
harness.invoke.mock.calls.some(
([command]) => command === 'hydrate_design_agent_session',
),
).toBe(true);
expect(screen.getByLabelText('项目需求')).toHaveProperty('disabled', true);
fireEvent.click(screen.getByRole('button', { name: '批准' }));
await waitFor(() => {
expect(
harness.invoke.mock.calls.some(
([command]) => command === 'decide_design_phase',
),
).toBe(true);
});
});
}
@@ -462,6 +462,9 @@ function createProjectSupervisorRuntimeHarness({
expectedRunProfile = 'autonomous-game-build',
planningV2Result = null,
planningV2StartResult = null,
designAgentView = null,
designAgentContinueView = null,
designWorkspaceFiles = [],
}: {
projectPath?: string;
sessionId?: string;
@@ -475,6 +478,9 @@ function createProjectSupervisorRuntimeHarness({
expectedRunProfile?: 'standard' | 'autonomous-game-build';
planningV2Result?: Record<string, unknown> | null;
planningV2StartResult?: Record<string, unknown> | null;
designAgentView?: Record<string, unknown> | null;
designAgentContinueView?: Record<string, unknown> | null;
designWorkspaceFiles?: Array<Record<string, unknown>>;
} = {}) {
const manifest = createGameCreationAppManifest(
'local-project-draft',
@@ -522,6 +528,9 @@ function createProjectSupervisorRuntimeHarness({
// 默认不配置策划状态:hydrate 与接入本 harness 之前一样抛出,既有用例行为不变。
let currentPlanningV2Result = planningV2Result;
let currentPlanningV2StartResult = planningV2StartResult;
let currentDesignAgentView = designAgentView;
const currentDesignContinueView = designAgentContinueView;
const currentDesignWorkspaceFiles = [...designWorkspaceFiles];
let planningV2DecisionError: string | null = null;
const planningV2DecisionCalls: Array<Record<string, unknown>> = [];
let runtimeUpdateHandler:
@@ -841,6 +850,29 @@ function createProjectSupervisorRuntimeHarness({
});
return runtimeResult();
}
if (command === 'hydrate_design_agent_session') {
return currentDesignAgentView;
}
if (command === 'continue_design_agent_session') {
const next = currentDesignContinueView ?? currentDesignAgentView;
if (!next) {
throw new Error('DESIGN_AGENT_VIEW_NOT_CONFIGURED');
}
currentDesignAgentView = next;
return next;
}
if (command === 'decide_design_phase') {
if (!currentDesignAgentView) {
throw new Error('DESIGN_AGENT_VIEW_NOT_CONFIGURED');
}
return currentDesignAgentView;
}
if (command === 'list_design_workspace') {
return currentDesignWorkspaceFiles;
}
if (command === 'read_design_workspace_file') {
return '';
}
if (command === 'hydrate_planning_session_v2') {
return currentPlanningV2Result;
}
@@ -745,9 +745,39 @@ export function registerPlanGddApprovalTests() {
});
});
it('starts a new V2 planning session and renders its question card', async () => {
it('starts a new planning entry through the design agent', async () => {
const harness = createProjectSupervisorRuntimeHarness({
planningV2StartResult: planningV2QuestionResult(),
designAgentContinueView: {
session: {
sessionId: 'design-session-1',
projectId: 'local-project-draft',
currentPhase: 'concept',
approvedPhases: [],
pendingApproval: null,
pendingClarification: {
requestId: 'clarify-1',
question: '玩家在一局中主要反复做什么?',
options: ['持续闪避', '站桩输出'],
createdAt: 1,
},
turnIndex: 1,
lastError: null,
},
messages: [
{
id: 'u1',
role: 'user',
text: '做一个2D弹幕射击游戏',
},
{
id: 'a1',
role: 'assistant',
text: '先确认核心循环。',
},
],
running: false,
canRetry: false,
},
});
window.__TAURI__ = {
core: { invoke: harness.invoke },
@@ -764,21 +794,28 @@ export function registerPlanGddApprovalTests() {
}),
);
await screen.findByLabelText('Needs input');
await screen.findByText('玩家在一局中主要反复做什么?');
expect(
harness.invoke.mock.calls.some(
([command]) => command === 'hydrate_design_agent_session',
),
).toBe(true);
expect(
harness.invoke.mock.calls.some(
([command]) => command === 'start_planning_session_v2',
),
).toBe(true);
expect(screen.getByText('玩家在一局中主要反复做什么?')).not.toBeNull();
).toBe(false);
expect(screen.queryByText(/agent\.delegate/)).toBeNull();
fireEvent.click(screen.getByRole('button', { name: /持续闪避/ }));
fireEvent.click(screen.getByRole('button', { name: '提交回答' }));
fireEvent.click(screen.getByRole('button', { name: '持续闪避' }));
await waitFor(() => {
expect(harness.invoke).toHaveBeenCalledWith(
'continue_planning_session_v2',
'continue_design_agent_session',
expect.objectContaining({
input: { text: '持续闪避', questionId: 'core_loop' },
input: expect.objectContaining({
type: 'clarification',
requestId: 'clarify-1',
optionIndex: 0,
}),
}),
);
});