From 13629c60cb4cb61a5f2e1382f27aba395e614ba8 Mon Sep 17 00:00:00 2001 From: AIGameCreator App Date: Thu, 16 Jul 2026 16:29:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5=E6=AD=A3=E5=BC=8F=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=80=BB=E6=8E=A7=E5=AF=B9=E8=AF=9D=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 登录后项目开发页接入 project-supervisor active Session 与 same-run steer 为全新项目自动创建 Supervisor Session 并隔离 legacy 项目对话写入 展示总控运行状态、确认问答与专业 Agent 只读协作状态 补充桌面窄屏样式、界面回归测试和 V1.28 文档 --- apps/ai-game-creator-shell/src/App.tsx | 839 ++++++++++++------ apps/ai-game-creator-shell/src/styles.css | 167 ++++ .../tests/appSurface.test.ts | 367 ++++++-- .../shared-memory/decision-log.md | 4 +- ...案】AI游戏创作Agent Runtime V1.1-2026-07-12.md | 11 +- ...案】AI游戏创作智能体App实施计划-2026-06-24.md | 40 +- 6 files changed, 1057 insertions(+), 371 deletions(-) diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index e5f605ba1..c038dcdb5 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -26,11 +26,11 @@ import { Home, Image, LogOut, - MessageSquare, Pause, Pencil, Play, Plus, + Send, Settings, Sparkles, Target, @@ -163,6 +163,7 @@ type LauncherImportedAttachment = { type LauncherProjectContext = { projectPath: string; projectName: string; + manifest: GameCreationAppManifest; mode: HomeAgentMode | null; initialPrompt: string; attachments: LauncherImportedAttachment[]; @@ -1319,6 +1320,21 @@ function mergeProjectSupervisorResponseStream( return next; } +function conversationContainsProjectSupervisorResponseStream( + messages: LocalConversationMessageRecord[], + stream: AgentRuntimeResponseStream | null | undefined, +) { + return Boolean( + stream?.accumulatedText.trim() && + messages.some( + (message) => + message.role === 'assistant' && + message.content === stream.accumulatedText && + message.updatedAt >= stream.startedAt, + ), + ); +} + function agentRuntimeWaitingOnFromPhase(phase: string) { switch (phase) { case 'planning': @@ -1474,6 +1490,123 @@ function matchingAgentRuntimeForSteer( ); } +function projectSupervisorActiveSessionIdFromList( + sessionList: AgentConversationSessionListResult, +) { + if ( + !sessionList || + sessionList.agentId !== PROJECT_SUPERVISOR_AGENT_ID || + !Array.isArray(sessionList.sessions) + ) { + throw new Error('项目总控 Agent 会话列表返回格式无效'); + } + const activeSession = sessionList.activeSessionId + ? sessionList.sessions.find( + (session) => + session.sessionId === sessionList.activeSessionId && + session.archivedAt === null, + ) + : null; + return ( + activeSession?.sessionId || + sessionList.sessions.find((session) => session.archivedAt === null) + ?.sessionId || + null + ); +} + +async function readProjectSupervisorActiveSessionId( + invoke: TauriInvoke, + projectPath: string, +) { + try { + const sessionList = await invoke( + 'list_game_creator_agent_sessions', + { + projectPath, + agentId: PROJECT_SUPERVISOR_AGENT_ID, + }, + ); + return projectSupervisorActiveSessionIdFromList(sessionList); + } catch (error) { + if (isMissingAgentSessionCommandError(error)) { + return null; + } + throw error; + } +} + +async function ensureProjectSupervisorActiveSessionId( + invoke: TauriInvoke, + projectPath: string, +) { + const existingSessionId = await readProjectSupervisorActiveSessionId( + invoke, + projectPath, + ); + if (existingSessionId) { + return existingSessionId; + } + const sessionList = await invoke( + 'create_game_creator_agent_session', + { + projectPath, + agentId: PROJECT_SUPERVISOR_AGENT_ID, + title: '项目总控', + }, + ); + const sessionId = projectSupervisorActiveSessionIdFromList(sessionList); + if (!sessionId) { + throw new Error('项目总控 Agent active Session 创建失败'); + } + return sessionId; +} + +async function submitProjectSupervisorRuntimeTask({ + invoke, + projectPath, + sessionId, + prompt, + runtime, +}: { + invoke: TauriInvoke; + projectPath: string; + sessionId: string; + prompt: string; + runtime: AgentRuntimeState | null; +}) { + const steerRuntime = matchingAgentRuntimeForSteer( + [runtime], + PROJECT_SUPERVISOR_AGENT_ID, + sessionId, + ); + if (steerRuntime) { + const steer = await invoke( + 'steer_game_creator_agent_runtime_task', + { + projectPath, + agentId: PROJECT_SUPERVISOR_AGENT_ID, + sessionId, + runId: steerRuntime.runId, + steerId: createAgentChatRunId('project-supervisor-steer'), + instruction: prompt, + }, + ); + return { mode: 'steer' as const, runtimeResult: steer.runtime }; + } + const runtimeResult = await invoke( + 'start_game_creator_agent_runtime_task', + { + projectPath, + agentId: PROJECT_SUPERVISOR_AGENT_ID, + sessionId, + task: prompt, + runId: createAgentChatRunId('project-supervisor-task'), + }, + ); + return { mode: 'start' as const, runtimeResult }; +} + function agentRuntimeSteerStatus(result: AgentRuntimeSteerResult) { const runId = result.runtime.state.runId; if (result.providerInterrupted) { @@ -2812,6 +2945,95 @@ function formatProjectSupervisorCompactProgress( ].join(' · '); } +function ProjectSupervisorRuntimePanel({ + runtime, + error, + runtimeByAgentId, + controlBusy, + onToolAction, + onUserInput, +}: { + runtime: AgentRuntimeState | null; + error: string; + runtimeByAgentId: Record; + controlBusy: boolean; + onToolAction: (decision: 'confirm' | 'reject') => void | Promise; + onUserInput: ( + request: AgentRuntimeUserInputRequest, + responseId: string, + answers: Record, + ) => void | Promise; +}) { + const status = projectSupervisorRuntimeStatusLabel(runtime, error); + if (!status) { + return null; + } + const statusDetail = error || runtime?.error || ''; + const compactProgress = runtime + ? formatProjectSupervisorCompactProgress( + runtime, + projectSupervisorCollaboratingAgentCount(runtime, runtimeByAgentId), + ) + : ''; + const pendingToolAction = runtime?.pendingToolAction ?? null; + const userInputRequest = runtime?.userInputRequest ?? null; + const needsUserInput = agentRuntimeNeedsUserInput(runtime); + + return ( +
+
+ {`项目总控 Agent · ${status}`} +
+ {statusDetail ? {statusDetail} : null} + {compactProgress ? ( + {compactProgress} + ) : null} + {userInputRequest ? ( + + ) : needsUserInput ? ( +

+ 待回答问题未能读取,请稍后重试。 +

+ ) : null} + {pendingToolAction ? ( +
+ + {pendingToolAction.tool} + {pendingToolAction.inputSummary ? ( + {pendingToolAction.inputSummary} + ) : null} + + + +
+ ) : null} +
+ ); +} + function isTransientProjectOpenMessage( message: ChatMessage, projectPath: string, @@ -3685,26 +3907,6 @@ function buildHomeConversationContent( return lines.join('\n'); } -function buildHomeConversationReceipt( - importedAttachments: LauncherImportedAttachment[], -) { - const lines = ['已创建项目草稿,本轮仅进入项目开发占位,不启动生成。']; - if (importedAttachments.length > 0) { - lines.push(''); - lines.push('附件导入结果:'); - for (const attachment of importedAttachments) { - lines.push( - `- ${attachment.fileName}: ${ - attachment.status === 'imported' - ? attachment.localPath || '已导入' - : attachment.error || '导入失败' - }`, - ); - } - } - return lines.join('\n'); -} - export function AuthenticatedClient({ children, }: { @@ -5855,35 +6057,6 @@ export function WorkspaceLauncher({ return imported; } - async function appendHomeConversation( - invoke: TauriInvoke, - nextProjectPath: string, - mode: HomeAgentMode, - prompt: string, - attachments: HomeAttachmentDraft[], - importedAttachments: LauncherImportedAttachment[], - ) { - const userContent = buildHomeConversationContent(mode, prompt, attachments); - await invoke('append_local_conversation_message', { - projectPath: nextProjectPath, - agentId: null, - message: { - role: 'user', - content: userContent, - agentId: null, - }, - }); - await invoke('append_local_conversation_message', { - projectPath: nextProjectPath, - agentId: null, - message: { - role: 'assistant', - content: buildHomeConversationReceipt(importedAttachments), - agentId: null, - }, - }); - } - async function createHomeProjectFromDirectory( nextProjectPath: string, mode: HomeAgentMode, @@ -5934,18 +6107,24 @@ export function WorkspaceLauncher({ attachments, ); try { - await appendHomeConversation( + const sessionId = await ensureProjectSupervisorActiveSessionId( invoke, result.projectPath, - mode, - prompt, - attachments, - importedAttachments, ); - setStatus('已创建项目并记录首条需求'); + if (!sessionId) { + throw new Error('项目总控 Agent active Session 不可用'); + } + await submitProjectSupervisorRuntimeTask({ + invoke, + projectPath: result.projectPath, + sessionId, + prompt: buildHomeConversationContent(mode, prompt, attachments), + runtime: null, + }); + setStatus('已创建项目并交给项目总控 Agent'); } catch (error) { - setStatus( - `已创建项目;首条需求保存失败:${ + throw new Error( + `项目已创建;首条需求投递失败:${ error instanceof Error ? error.message : String(error) }`, ); @@ -5954,6 +6133,7 @@ export function WorkspaceLauncher({ projectPath: result.projectPath, projectName: result.manifest.name || projectNameFromPath(result.projectPath), + manifest: result.manifest, mode, initialPrompt: prompt.trim() || @@ -6016,6 +6196,7 @@ export function WorkspaceLauncher({ projectPath: result.projectPath, projectName: result.manifest.name || projectNameFromPath(result.projectPath), + manifest: result.manifest, mode: null, initialPrompt: '', attachments: [], @@ -6060,12 +6241,22 @@ export function WorkspaceLauncher({ setStatus('这不是已初始化的 AI 游戏项目,请使用新建项目。'); return; } + let projectManifest = seedManifest; + try { + projectManifest = await invoke( + 'get_local_game_manifest', + { projectPath: trimmedProjectPath }, + ); + } catch { + // The Supervisor surface can still restore conversation/runtime state. + } setStatus('已打开项目'); enterProjectDevelopment({ projectPath: trimmedProjectPath, projectName: directoryStatus.projectName || projectNameFromPath(trimmedProjectPath), + manifest: projectManifest, mode: null, initialPrompt: '', attachments: [], @@ -9507,6 +9698,15 @@ export function WorkspaceLauncher({

{currentProjectContext?.projectName ?? '项目开发'}

{currentProjectContext?.projectPath ?? '尚未选择项目'}

+ {currentProjectContext?.recentRunStatus ? ( + + {`run: ${currentProjectContext.recentRunStatus}${ + currentProjectContext.recentRunStopReason + ? ` · ${currentProjectContext.recentRunStopReason}` + : '' + }`} + + ) : null}
-
-
- 创建模式 - - {currentProjectContext?.mode - ? homeAgentModeLabels[currentProjectContext.mode] - : '打开已有项目'} - - - {currentProjectContext - ? formatLocalDateTime(currentProjectContext.createdAt) - : '未知时间'} - -
-
- 首条需求 - - {currentProjectContext?.initialPrompt || '暂无首页需求'} - -
-
- 最近 Run - - {currentProjectContext?.recentRunStatus ?? '暂无'} - - {currentProjectContext?.recentRunStopReason ? ( - {currentProjectContext.recentRunStopReason} - ) : null} -
-
-
-
-
-
+ {currentProjectContext ? ( + + ) : null}
+ projectSupervisorOnly ? false : isDeveloperMode(), + ); + const [initialProjectPath] = useState( + () => initialProjectPathOverride || readInitialProjectPath(), + ); const [projectPath, setProjectPath] = useState( initialProjectPath || defaultProjectPath, ); - const [localProject, setLocalProject] = - useState(null); + const [localProject, setLocalProject] = useState( + () => + projectSupervisorOnly && initialProjectPath + ? { + projectPath: initialProjectPath, + manifestPath: `${initialProjectPath.replace(/[\\/]+$/, '')}/.agent/manifest.json`, + manifest: initialProjectManifest ?? seedManifest, + } + : null, + ); const localProjectPathRef = useRef(null); localProjectPathRef.current = localProject?.projectPath ?? null; - const [manifest, setManifest] = - useState(seedManifest); - const [projectStatus, setProjectStatus] = useState('未初始化'); + const [manifest, setManifest] = useState( + initialProjectManifest ?? seedManifest, + ); + const [projectStatus, setProjectStatus] = useState( + projectSupervisorOnly && initialProjectPath ? '已初始化' : '未初始化', + ); const [preview, setPreview] = useState(null); const [previewStatus, setPreviewStatus] = useState('未启动'); const [chatInput, setChatInput] = useState(''); @@ -17154,7 +17347,11 @@ export function App() { const [runtimeConfigOpen, setRuntimeConfigOpen] = useState(false); const [llmConfigStatus, setLlmConfigStatus] = useState(null); - const [workspaceStatus, setWorkspaceStatus] = useState('请选择工作区'); + const [workspaceStatus, setWorkspaceStatus] = useState( + projectSupervisorOnly && initialProjectPath + ? `已打开:${initialProjectPath}` + : '请选择工作区', + ); const [selectedAgent, setSelectedAgent] = useState( null, ); @@ -17204,8 +17401,14 @@ export function App() { const [projectLogStatus, setProjectLogStatus] = useState('未读取'); const [projectLogContent, setProjectLogContent] = useState(''); const [conversationWriteVersion, setConversationWriteVersion] = useState(0); - const savedConversationCountRef = useRef(0); - const savedConversationProjectPathRef = useRef(null); + const savedConversationCountRef = useRef( + projectSupervisorOnly && initialProjectPath + ? createDefaultChatMessages().length + : 0, + ); + const savedConversationProjectPathRef = useRef( + projectSupervisorOnly && initialProjectPath ? initialProjectPath : null, + ); const projectConversationWriteConfirmedRef = useRef(null); const projectConversationWriteCancelledRef = useRef<{ projectPath: string; @@ -17245,6 +17448,13 @@ export function App() { const initialProjectOpenedRef = useRef(false); const pendingUiConfirmationActionRef = useRef<(() => void) | null>(null); + function requestRuntimeConfigOpen() { + if (projectSupervisorOnly) { + return; + } + setRuntimeConfigOpen(true); + } + function updateProjectSupervisorRuntime( runtime: AgentRuntimeState | null, previous = projectSupervisorRuntimeRef.current, @@ -17260,11 +17470,25 @@ export function App() { incoming: AgentRuntimeResponseStream | null | undefined, runtime: AgentRuntimeState, ) { - const nextStream = mergeProjectSupervisorResponseStream( + let nextStream = mergeProjectSupervisorResponseStream( projectSupervisorResponseStreamRef.current, incoming, runtime, ); + const candidateStream = nextStream; + if ( + candidateStream && + latestMessagesRef.current.some( + (message) => + message.runtimeOwned && + message.role === 'assistant' && + message.text === candidateStream.accumulatedText && + typeof message.updatedAt === 'number' && + message.updatedAt >= candidateStream.startedAt, + ) + ) { + nextStream = null; + } projectSupervisorResponseStreamRef.current = nextStream; setProjectSupervisorResponseStream(nextStream); } @@ -17341,10 +17565,30 @@ export function App() { return; } initialProjectOpenedRef.current = true; + if (projectSupervisorOnly) { + if (!isAbsoluteProjectPath(initialProjectPath)) { + setWorkspaceStatus('请提供工作区绝对路径'); + return; + } + if (projectPathHasControlCharacter(initialProjectPath)) { + setWorkspaceStatus('工作区路径不能包含控制字符'); + return; + } + localProjectPathRef.current = initialProjectPath; + void loadProjectConversation(initialProjectPath).finally(() => { + if (localProjectPathRef.current === initialProjectPath) { + void refreshAgentRunTrace(initialProjectPath); + } + }); + return; + } void openWorkspace(initialProjectPath, false); - }, [initialProjectPath]); + }, [initialProjectPath, projectSupervisorOnly]); useEffect(() => { + if (projectSupervisorOnly) { + return; + } const listen = window.__TAURI__?.event?.listen; if (!listen) { return; @@ -17381,7 +17625,7 @@ export function App() { disposed = true; cleanup?.(); }; - }, []); + }, [projectSupervisorOnly]); useEffect(() => { const listen = window.__TAURI__?.event?.listen; @@ -17546,7 +17790,7 @@ export function App() { const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } setProjectSupervisorRuntimeError(message); } @@ -17588,6 +17832,17 @@ export function App() { if (pendingMessages.length === 0) { return; } + if ( + projectSupervisorOnly && + pendingMessages.every( + (message) => + message.runtimeOwned || + isTransientProjectOpenMessage(message, nextProjectPath), + ) + ) { + savedConversationCountRef.current = messages.length; + return; + } if (conversationWriteInFlightRef.current) { return; } @@ -17707,6 +17962,7 @@ export function App() { messages, conversationWriteVersion, pendingUiConfirmation, + projectSupervisorOnly, ]); function appendLocalPermissionLog( @@ -18304,15 +18560,17 @@ export function App() { { projectPath: nextProjectPath }, ); projectSupervisorRuntimeResumeProjectPathRef.current = nextProjectPath; + agentRuntimeResumeProjectPathRef.current = nextProjectPath; return ''; } catch (error) { if (isMissingAgentRuntimeResumeCommandError(error)) { projectSupervisorRuntimeResumeProjectPathRef.current = nextProjectPath; + agentRuntimeResumeProjectPathRef.current = nextProjectPath; return ''; } const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } const runtimeError = `项目总控 Agent 恢复失败:${message}`; setProjectSupervisorRuntimeError(runtimeError); @@ -18324,29 +18582,7 @@ export function App() { invoke: TauriInvoke, nextProjectPath: string, ) { - try { - const sessionList = await invoke( - 'list_game_creator_agent_sessions', - { - projectPath: nextProjectPath, - agentId: PROJECT_SUPERVISOR_AGENT_ID, - }, - ); - if (!sessionList || !Array.isArray(sessionList.sessions)) { - throw new Error('项目总控 Agent 会话列表返回格式无效'); - } - return ( - sessionList.activeSessionId || - sessionList.sessions.find((session) => session.archivedAt === null) - ?.sessionId || - null - ); - } catch (error) { - if (isMissingAgentSessionCommandError(error)) { - return null; - } - throw error; - } + return readProjectSupervisorActiveSessionId(invoke, nextProjectPath); } async function refreshProjectSupervisorConversation( @@ -18381,12 +18617,9 @@ export function App() { ); const transientResponse = projectSupervisorResponseStreamRef.current; if ( - transientResponse && - supervisorConversation.messages.some( - (message) => - message.role === 'assistant' && - message.content === transientResponse.accumulatedText && - message.updatedAt >= transientResponse.startedAt, + conversationContainsProjectSupervisorResponseStream( + supervisorConversation.messages, + transientResponse, ) ) { projectSupervisorResponseStreamRef.current = null; @@ -18483,6 +18716,18 @@ export function App() { ) { return; } + const conversationMessages = mergeProjectSupervisorConversation( + projectConversation.messages, + supervisorConversation?.messages ?? [], + ); + if ( + conversationContainsProjectSupervisorResponseStream( + supervisorConversation?.messages ?? [], + runtimeResponseStream, + ) + ) { + runtimeResponseStream = null; + } projectSupervisorSessionIdRef.current = sessionId; setProjectSupervisorSessionId(sessionId); updateProjectSupervisorRuntime(runtime); @@ -18493,10 +18738,6 @@ export function App() { setProjectSupervisorResponseStream(null); } setProjectSupervisorRuntimeError(runtimeError || resumeError); - const conversationMessages = mergeProjectSupervisorConversation( - projectConversation.messages, - supervisorConversation?.messages ?? [], - ); setMessages((current) => { const hasOnlyDefaultGreeting = current.length === 1 && @@ -18538,7 +18779,7 @@ export function App() { } const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } setProjectSupervisorRuntimeError(message); setWorkspaceStatus((workspaceStatus) => @@ -22071,7 +22312,7 @@ export function App() { if (currentSessionId) { return currentSessionId; } - const sessionId = await readProjectSupervisorActiveSession( + const sessionId = await ensureProjectSupervisorActiveSessionId( invoke, nextProjectPath, ); @@ -22114,45 +22355,18 @@ export function App() { if (!sessionId || localProjectPathRef.current !== nextProjectPath) { return; } - const steerRuntime = matchingAgentRuntimeForSteer( - [projectSupervisorRuntimeRef.current], - PROJECT_SUPERVISOR_AGENT_ID, + const submission = await submitProjectSupervisorRuntimeTask({ + invoke, + projectPath: nextProjectPath, sessionId, - ); - let runtimeResult: AgentRuntimeResult; - if (steerRuntime) { - const steer = await invoke( - 'steer_game_creator_agent_runtime_task', - { - projectPath: nextProjectPath, - agentId: PROJECT_SUPERVISOR_AGENT_ID, - sessionId, - runId: steerRuntime.runId, - steerId: createAgentChatRunId('project-supervisor-steer'), - instruction: prompt, - }, - ); - runtimeResult = steer.runtime; - setCommandLog((current) => [ - ...current, - 'agent.runtime.steer project-supervisor', - ]); - } else { - runtimeResult = await invoke( - 'start_game_creator_agent_runtime_task', - { - projectPath: nextProjectPath, - agentId: PROJECT_SUPERVISOR_AGENT_ID, - sessionId, - task: prompt, - runId: createAgentChatRunId('project-supervisor-task'), - }, - ); - setCommandLog((current) => [ - ...current, - 'agent.runtime.start project-supervisor', - ]); - } + prompt, + runtime: projectSupervisorRuntimeRef.current, + }); + const runtimeResult = submission.runtimeResult; + setCommandLog((current) => [ + ...current, + `agent.runtime.${submission.mode} project-supervisor`, + ]); const runtime = agentRuntimeStateFromResult( runtimeResult, projectSupervisorRuntimeRef.current, @@ -22207,7 +22421,7 @@ export function App() { } const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } setProjectSupervisorRuntimeError(message); setMessages((current) => [ @@ -22290,7 +22504,7 @@ export function App() { } const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } setProjectSupervisorRuntimeError(message); } finally { @@ -22391,7 +22605,7 @@ export function App() { } const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } setProjectSupervisorRuntimeError(`回答提交失败:${message}`); } finally { @@ -22503,7 +22717,7 @@ export function App() { void refreshAgentRunTrace(nextProjectPath); const message = error instanceof Error ? error.message : String(error); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } setMessages((current) => [ ...current, @@ -25716,7 +25930,7 @@ export function App() { const message = error instanceof Error ? error.message : String(error); setAssetStatus(message); if (isRuntimeConfigMissingError(message)) { - setRuntimeConfigOpen(true); + requestRuntimeConfigOpen(); } if (announceToChat) { setMessages((current) => [ @@ -26604,25 +26818,6 @@ export function App() { ); const projectSupervisorTransientReply = projectSupervisorResponseStream?.accumulatedText.trim() ?? ''; - const projectSupervisorStatus = projectSupervisorRuntimeStatusLabel( - projectSupervisorRuntime, - projectSupervisorRuntimeError, - ); - const projectSupervisorStatusDetail = - projectSupervisorRuntimeError || projectSupervisorRuntime?.error || ''; - const projectSupervisorCompactProgress = projectSupervisorRuntime - ? formatProjectSupervisorCompactProgress( - projectSupervisorRuntime, - projectSupervisorCollaboratingAgentCount( - projectSupervisorRuntime, - agentRuntimeById, - ), - ) - : ''; - const projectSupervisorPendingToolAction = - projectSupervisorRuntime?.pendingToolAction ?? null; - const projectSupervisorUserInputRequest = - projectSupervisorRuntime?.userInputRequest ?? null; const projectSupervisorNeedsUserInput = agentRuntimeNeedsUserInput( projectSupervisorRuntime, ); @@ -26700,6 +26895,157 @@ export function App() { } }, [agentStatusCards, selectedAgent]); + function handleProjectSupervisorOnlySubmit( + event: FormEvent, + ) { + event.preventDefault(); + const prompt = chatInput.trim(); + if (agentRuntimeNeedsUserInput(projectSupervisorRuntimeRef.current)) { + setProjectSupervisorRuntimeError('请先回答项目总控 Agent 当前的澄清问题'); + return; + } + if (!prompt || chatAgentBusy) { + return; + } + setChatInput(''); + setMessages((current) => [ + ...current, + { role: 'user', text: prompt, runtimeOwned: true }, + ]); + void executeChatAgentReply(prompt); + } + + const visibleProfessionalAgentCards = agentStatusCards.filter( + (agent) => + agent.id !== PROJECT_SUPERVISOR_AGENT_ID && + (agent.runtimeStatus !== null || agent.hasRecentEvidence), + ); + + if (projectSupervisorOnly) { + return ( + <> +
+
+
+ {hiddenConversationCount > 0 ? ( + + ) : null} + {visibleMessages.map((message, index) => ( +

+ {message.text} +

+ ))} + {projectSupervisorTransientReply ? ( +

+ {projectSupervisorTransientReply} +

+ ) : null} +
+ + {pendingUiConfirmation ? ( +
+ + {pendingUiConfirmation.commandId} + {pendingUiConfirmation.detail} + + + +
+ ) : null} +
+