From a7a36bfc5b0f6c609a46525b2507e6582616f096 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Tue, 4 Aug 2026 16:24:32 +0800 Subject: [PATCH 1/3] Remove inferred chat confirmation state --- apps/aevatar-console-web/src/locales/en-US.ts | 5 -- apps/aevatar-console-web/src/locales/zh-CN.ts | 5 -- .../src/pages/chat/chatTypes.ts | 2 - .../src/pages/chat/index.test.tsx | 38 +++++---- .../src/pages/chat/index.tsx | 81 ++----------------- 5 files changed, 26 insertions(+), 105 deletions(-) diff --git a/apps/aevatar-console-web/src/locales/en-US.ts b/apps/aevatar-console-web/src/locales/en-US.ts index 7d63d62608..2bc1e9adfc 100644 --- a/apps/aevatar-console-web/src/locales/en-US.ts +++ b/apps/aevatar-console-web/src/locales/en-US.ts @@ -43,8 +43,6 @@ const enUSMessages = { 'pages.chat.index.chatStopped': 'Chat stopped.', 'pages.chat.index.composerPlaceholder': 'Describe the workflow you want, or ask about the current setup...', - 'pages.chat.index.confirmAndCreate': 'Confirm and create', - 'pages.chat.index.confirmPrompt': 'Confirm. Please create it now.', 'pages.chat.index.continuationContextMissing': 'The continuation may have been accepted, but its turn identity was not received. Reload this page before continuing.', 'pages.chat.index.cancel': 'Cancel', @@ -80,15 +78,12 @@ const enUSMessages = { 'pages.chat.index.resolvingScope': 'Resolving scope', 'pages.chat.index.retry': 'Retry', 'pages.chat.index.retryHistory': 'Retry chat history', - 'pages.chat.index.reviewPlan': 'Review the plan before creating resources.', 'pages.chat.index.scopeMismatch': 'Requested scope {requestedScopeId} does not match authenticated scope {authenticatedScopeId}. Open Chat from the active workspace or sign in again.', 'pages.chat.index.scopeValue': 'Scope {scopeId}', 'pages.chat.index.status.completed': 'Completed', - 'pages.chat.index.status.creating': 'Creating', 'pages.chat.index.status.draft': 'Draft', 'pages.chat.index.status.error': 'Error', - 'pages.chat.index.status.needsConfirmation': 'Needs confirmation', 'pages.chat.index.status.streaming': 'Streaming', 'pages.chat.index.status.studioReady': 'Studio ready', 'pages.chat.index.time.daysAgo': '{count}d ago', diff --git a/apps/aevatar-console-web/src/locales/zh-CN.ts b/apps/aevatar-console-web/src/locales/zh-CN.ts index ce32d183a9..433608bcf5 100644 --- a/apps/aevatar-console-web/src/locales/zh-CN.ts +++ b/apps/aevatar-console-web/src/locales/zh-CN.ts @@ -42,8 +42,6 @@ const zhCNMessages = { 'pages.gagents.index.platformBreadcrumb': '平台', 'pages.chat.index.chatStopped': 'Chat 已停止。', 'pages.chat.index.composerPlaceholder': '描述你想要的 workflow,或询问当前配置...', - 'pages.chat.index.confirmAndCreate': '确认并创建', - 'pages.chat.index.confirmPrompt': '确认,请现在创建。', 'pages.chat.index.continuationContextMissing': '续聊请求可能已经被接受,但未收到本轮身份。请重新加载此页面后再继续。', 'pages.chat.index.cancel': '取消', @@ -74,15 +72,12 @@ const zhCNMessages = { 'pages.chat.index.resolvingScope': '正在解析 scope', 'pages.chat.index.retry': '重试', 'pages.chat.index.retryHistory': '重新加载会话历史', - 'pages.chat.index.reviewPlan': '创建资源前请先确认计划。', 'pages.chat.index.scopeMismatch': '请求的 scope {requestedScopeId} 与当前认证 scope {authenticatedScopeId} 不一致。请从当前工作区重新打开 Chat,或重新登录。', 'pages.chat.index.scopeValue': 'Scope {scopeId}', 'pages.chat.index.status.completed': '已完成', - 'pages.chat.index.status.creating': '创建中', 'pages.chat.index.status.draft': '草稿', 'pages.chat.index.status.error': '错误', - 'pages.chat.index.status.needsConfirmation': '待确认', 'pages.chat.index.status.streaming': '生成中', 'pages.chat.index.status.studioReady': 'Studio 已就绪', 'pages.chat.index.time.daysAgo': '{count} 天前', diff --git a/apps/aevatar-console-web/src/pages/chat/chatTypes.ts b/apps/aevatar-console-web/src/pages/chat/chatTypes.ts index 396c939267..479d5873b0 100644 --- a/apps/aevatar-console-web/src/pages/chat/chatTypes.ts +++ b/apps/aevatar-console-web/src/pages/chat/chatTypes.ts @@ -56,8 +56,6 @@ export type ChatStudioTarget = { export type LocalChatStatus = | "draft" | "streaming" - | "needs_confirmation" - | "creating" | "completed_text" | "completed_with_studio_target" | "error"; diff --git a/apps/aevatar-console-web/src/pages/chat/index.test.tsx b/apps/aevatar-console-web/src/pages/chat/index.test.tsx index 764d818394..ef9a20adaa 100644 --- a/apps/aevatar-console-web/src/pages/chat/index.test.tsx +++ b/apps/aevatar-console-web/src/pages/chat/index.test.tsx @@ -1174,7 +1174,7 @@ describe("ChatPage server-backed history", () => { expect(screen.queryByRole("button", { name: "Retry" })).toBeNull(); }); - it("keeps every chat action disabled until reconciliation observes a positive Conversation watermark", async () => { + it("keeps Team selection in the composer until reconciliation observes a positive Conversation watermark", async () => { let resolveZeroDetail: ( detail: ReturnType ) => void = () => undefined; @@ -1195,11 +1195,13 @@ describe("ChatPage server-backed history", () => { ...serverConversation, id: "server-confirm", messageCount: 1, - title: "Confirmation plan", + title: "Weekly report Team selection", }; + const teamSelectionPrompt = + "请再确认具体使用哪个 Team(当前有两个 active Team)。\n确认后我会立即创建周报 workflow。"; const projectedMessages = [ { - content: "Please confirm this plan.", + content: teamSelectionPrompt, id: "turn-confirm:assistant", role: "assistant" as const, status: "complete" as const, @@ -1235,7 +1237,7 @@ describe("ChatPage server-backed history", () => { chatContextFrame("server-confirm", "turn-confirm", "scope-a", 7), { runFinished: { - result: { output: "Please confirm this plan." }, + result: { output: teamSelectionPrompt }, }, }, ]) @@ -1250,40 +1252,42 @@ describe("ChatPage server-backed history", () => { renderWithQueryClient(); await sendPrompt("Draft a workflow plan"); - const confirmButton = await screen.findByRole("button", { - name: "Confirm and create", - }); + expect( + await screen.findByText( + "请再确认具体使用哪个 Team(当前有两个 active Team)。" + ) + ).toBeInTheDocument(); + expect( + screen.getByText("确认后我会立即创建周报 workflow。") + ).toBeInTheDocument(); + expect( + screen.queryByRole("button", { name: "Confirm and create" }) + ).toBeNull(); + expect(screen.queryByText("Needs confirmation")).toBeNull(); await waitFor(() => expect(chatHistoryApi.loadConversation).toHaveBeenCalledTimes(1) ); - expect(confirmButton).toBeDisabled(); expect(screen.getByRole("textbox")).toBeDisabled(); act(() => resolveZeroDetail(conversationDetail(projectedMessages, 0))); await waitFor(() => expect(chatHistoryApi.loadConversation).toHaveBeenCalledTimes(2) ); - expect(confirmButton).toBeDisabled(); expect(screen.getByRole("textbox")).toBeDisabled(); act(() => resolveRegressedDetail(conversationDetail(projectedMessages, 6)) ); - await waitFor(() => - expect( - screen.getByRole("button", { name: "Confirm and create" }) - ).toBeEnabled() - ); - expect(screen.getByRole("textbox")).toBeEnabled(); + await waitFor(() => expect(screen.getByRole("textbox")).toBeEnabled()); - fireEvent.click(screen.getByRole("button", { name: "Confirm and create" })); + await sendPrompt("使用 Team team-weekly-report"); await waitFor(() => expect(chatRequestBodies()).toHaveLength(2)); expect(chatRequestBodies()[1]).toMatchObject({ conversation: { conversationId: "server-confirm", minimumStateVersion: 6, }, - prompt: "Confirm. Please create it now.", + prompt: "使用 Team team-weekly-report", }); }); diff --git a/apps/aevatar-console-web/src/pages/chat/index.tsx b/apps/aevatar-console-web/src/pages/chat/index.tsx index f49ad1a5d1..8c29b146c0 100644 --- a/apps/aevatar-console-web/src/pages/chat/index.tsx +++ b/apps/aevatar-console-web/src/pages/chat/index.tsx @@ -4,7 +4,6 @@ import { MessageOutlined, PlusOutlined, ReloadOutlined, - SendOutlined, } from "@ant-design/icons"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { @@ -466,10 +465,6 @@ function formatStatusLabel(status: LocalChatStatus): string { return t("pages.chat.index.status.draft", "Draft"); case "streaming": return t("pages.chat.index.status.streaming", "Streaming"); - case "needs_confirmation": - return t("pages.chat.index.status.needsConfirmation", "Needs confirmation"); - case "creating": - return t("pages.chat.index.status.creating", "Creating"); case "completed_with_studio_target": return t("pages.chat.index.status.studioReady", "Studio ready"); case "completed_text": @@ -483,13 +478,10 @@ function formatStatusLabel(status: LocalChatStatus): string { function resolveStatusTone( status: LocalChatStatus -): "default" | "processing" | "success" | "warning" | "error" { +): "default" | "processing" | "success" | "error" { switch (status) { case "streaming": - case "creating": return "processing"; - case "needs_confirmation": - return "warning"; case "completed_with_studio_target": case "completed_text": return "success"; @@ -500,21 +492,6 @@ function resolveStatusTone( } } -function shouldAskForConfirmation(content: string): boolean { - const normalized = content.toLowerCase(); - if (!normalized.trim()) { - return false; - } - - return ( - normalized.includes("confirm") || - normalized.includes("approval") || - normalized.includes("approve") || - normalized.includes("确认") || - normalized.includes("同意") - ); -} - function resolveStudioJump(target: ChatStudioTarget | undefined): StudioJump | null { if (!target) { return null; @@ -698,9 +675,7 @@ const ChatPage: React.FC = () => { const conversations = (conversationsQuery.data ?? []).filter( (conversation) => !scopedDeletedConversationIds.has(conversation.id) ); - const isStreaming = - activeConversation?.status === "streaming" || - activeConversation?.status === "creating"; + const isStreaming = activeConversation?.status === "streaming"; const studioJump = resolveStudioJump(activeConversation?.target); const visibleConversations = useMemo(() => { const activeConversationId = activeConversation?.conversationId; @@ -1227,8 +1202,6 @@ const ChatPage: React.FC = () => { conversation.title === t("pages.chat.index.newChat", "New chat") ? trimTitle(trimmedInput) : conversation.title; - const nextStatus: LocalChatStatus = - conversation.status === "needs_confirmation" ? "creating" : "streaming"; const createCommandId = conversation.conversationId ? undefined : !conversation.createRequestPrompt || @@ -1243,7 +1216,7 @@ const ChatPage: React.FC = () => { : trimmedInput, latestTurnId: undefined, messages: [...conversation.messages, userMessage, assistantMessage], - status: nextStatus, + status: "streaming", title, }; const rawFrames: unknown[] = []; @@ -1451,14 +1424,11 @@ const ChatPage: React.FC = () => { : "complete"; const finalTarget = artifacts.target || streamingConversation.target; const finalUsage = artifacts.usage || streamingConversation.usage; - const finalContent = accumulator.finalOutput || accumulator.assistantText; const finalStatus: LocalChatStatus = accumulator.errorText ? "error" : resolveStudioJump(finalTarget) ? "completed_with_studio_target" - : shouldAskForConfirmation(finalContent) - ? "needs_confirmation" - : "completed_text"; + : "completed_text"; const finalConversation: ConversationState = { ...streamingConversation, messages: streamingConversation.messages.map((message) => @@ -1664,17 +1634,6 @@ const ChatPage: React.FC = () => { void runChat(conversation, prompt); }, [activeConversation, prompt, runChat]); - const handleConfirmCreate = useCallback(() => { - if (!activeConversation) { - return; - } - - void runChat( - activeConversation, - t("pages.chat.index.confirmPrompt", "Confirm. Please create it now.") - ); - }, [activeConversation, runChat]); - const handleStop = useCallback(() => { abortControllerRef.current?.abort(); }, []); @@ -1871,8 +1830,7 @@ const ChatPage: React.FC = () => { "pages.chat.index.historySavePendingShort", "Saving history" ) - : conversation.liveStatus === "streaming" || - conversation.liveStatus === "creating" + : conversation.liveStatus === "streaming" ? formatStatusLabel(conversation.liveStatus) : formatTurnCount(conversation.messageCount)} @@ -2214,35 +2172,6 @@ const ChatPage: React.FC = () => { {activeConversation?.messages.map((message) => ( ))} - {activeConversation?.status === "needs_confirmation" ? ( -
- - - {t( - "pages.chat.index.reviewPlan", - "Review the plan before creating resources." - )} - - - -
- ) : null} )}
From 7dea1fa75bc2be76383c66f4630c30787ffed709 Mon Sep 17 00:00:00 2001 From: AbigailDeng Date: Tue, 4 Aug 2026 17:04:40 +0800 Subject: [PATCH 2/3] docs: archive superseded chat confirmation concept --- .../docs/prd/2026-07-01-chat-top-entry-mvp-prd.md | 10 +++++++++- .../2026-07-01-chat-top-entry-prototype.html | 10 ++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/aevatar-console-web/docs/prd/2026-07-01-chat-top-entry-mvp-prd.md b/apps/aevatar-console-web/docs/prd/2026-07-01-chat-top-entry-mvp-prd.md index fd2cbb047d..cf82803025 100644 --- a/apps/aevatar-console-web/docs/prd/2026-07-01-chat-top-entry-mvp-prd.md +++ b/apps/aevatar-console-web/docs/prd/2026-07-01-chat-top-entry-mvp-prd.md @@ -1,11 +1,19 @@ # Chat Top Entry MVP PRD Date: 2026-07-01 -Status: Simplified for product/design review +Status: Archived historical concept; not a current implementation contract Target surface: `apps/aevatar-console-web` Related prototype: `../prototypes/2026-07-01-chat-top-entry-prototype.html` Related PNG: `../prototypes/2026-07-01-chat-top-entry-prototype.png` +> **Superseded behavior:** The current Chat surface uses backend-backed history +> and typed runtime events. Assistant prose that asks the user to choose or +> confirm something remains a completed text turn, and the user continues +> through the composer. Do not infer `needs_confirmation` or `creating` from +> message text, and do not render a generic confirmation action from prose. +> Approval controls must come from an explicit typed approval or intervention +> event. The material below is retained only as the July 2026 design record. + ## Product Thesis `Chat` is the first top-level entry in Aevatar Console. The MVP has only two diff --git a/apps/aevatar-console-web/docs/prototypes/2026-07-01-chat-top-entry-prototype.html b/apps/aevatar-console-web/docs/prototypes/2026-07-01-chat-top-entry-prototype.html index 4caa52807a..82eac1c33d 100644 --- a/apps/aevatar-console-web/docs/prototypes/2026-07-01-chat-top-entry-prototype.html +++ b/apps/aevatar-console-web/docs/prototypes/2026-07-01-chat-top-entry-prototype.html @@ -3,7 +3,7 @@ - Aevatar Chat MVP Prototype + Archived Aevatar Chat MVP Prototype