From 443a89aef818d82a8b1812920f9d00f6abfe2901 Mon Sep 17 00:00:00 2001 From: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Date: Sat, 27 Jun 2026 17:41:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(app-shell):=20make=20AI-build=20"=E5=BC=80?= =?UTF-8?q?=E5=A7=8B=E6=90=AD=E5=BB=BA"=20send=20a=20gate-matching=20appro?= =?UTF-8?q?val?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The proposed-plan card's confirm button ("开始搭建") sent the Chinese message "就按这个方案搭建吧。", which the cloud confirm gate's APPROVAL_RE (service-ai-studio confirm-gate.ts) does NOT recognize as approval — it anchors Chinese approval on 确认 / 直接搭建. So clicking sent a message the agent re-proposed on instead of building, and the button looked inert (typing a "确认…" reply worked, which is the tell). Align both zh approve messages with the gate (确认-anchored): planApproveMessage "就按这个方案搭建吧。" → "确认,开始搭建。" planApproveDefaultsMessage "就按你的合理假设直接搭建,…" → "确认搭建,未决问题按你的合理假设和默认处理。" across the two hosts that wire them (i18n zh locale used by AiChatPage, and ConsoleFloatingChatbot's inline zh locale). English already matched ("build it as proposed" / "build it with your best"). Adds an i18n test that pins both messages to the gate's 确认 anchor so a future reword can't silently re-break the button. Co-Authored-By: Claude Opus 4.8 --- .../src/layout/ConsoleFloatingChatbot.tsx | 8 ++++++-- packages/i18n/src/__tests__/i18n.test.ts | 19 +++++++++++++++++-- packages/i18n/src/locales/zh.ts | 9 +++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/packages/app-shell/src/layout/ConsoleFloatingChatbot.tsx b/packages/app-shell/src/layout/ConsoleFloatingChatbot.tsx index 760ef35b0..72c698740 100644 --- a/packages/app-shell/src/layout/ConsoleFloatingChatbot.tsx +++ b/packages/app-shell/src/layout/ConsoleFloatingChatbot.tsx @@ -141,8 +141,12 @@ function buildChatLocale( planApprove: '开始搭建', planAdjust: '调整方案', planBuilt: '已搭建', - planApproveMessage: '就按这个方案搭建吧。', - planApproveDefaultsMessage: '就按你的合理假设直接搭建,未决问题用默认即可。', + // These messages the button SENDS must match the cloud confirm gate's + // APPROVAL_RE (service-ai-studio confirm-gate.ts) or the agent re-proposes + // and "开始搭建" looks inert — the gate anchors Chinese approval on 确认 / + // 直接搭建, so a bare "…搭建吧" does NOT match. Keep these 确认-anchored. + planApproveMessage: '确认,开始搭建。', + planApproveDefaultsMessage: '确认搭建,未决问题按你的合理假设和默认处理。', planAnswer: (question: string, option: string) => `关于「${question}」,我选择「${option}」。`, publishOk: '已发布,对象已生效。', publishFailed: '发布失败', diff --git a/packages/i18n/src/__tests__/i18n.test.ts b/packages/i18n/src/__tests__/i18n.test.ts index bde52a420..00cb38f9f 100644 --- a/packages/i18n/src/__tests__/i18n.test.ts +++ b/packages/i18n/src/__tests__/i18n.test.ts @@ -93,11 +93,26 @@ describe('@object-ui/i18n', () => { expect(i18n.t('console.ai.planApproveHint')).toBe('回复以确认或调整该方案。'); expect(i18n.t('console.ai.planApprove')).toBe('开始搭建'); expect(i18n.t('console.ai.planAdjust')).toBe('调整方案'); - expect(i18n.t('console.ai.planApproveMessage')).toBe('就按这个方案搭建吧。'); - expect(i18n.t('console.ai.planApproveDefaultsMessage')).toBe('就按你的合理假设直接搭建,未决问题用默认即可。'); + expect(i18n.t('console.ai.planApproveMessage')).toBe('确认,开始搭建。'); + expect(i18n.t('console.ai.planApproveDefaultsMessage')).toBe('确认搭建,未决问题按你的合理假设和默认处理。'); expect(i18n.t('console.ai.nextSteps')).toBe('下一步'); }); + // Regression guard: the "开始搭建" button SENDS these two messages, and the + // cloud confirm gate (service-ai-studio confirm-gate.ts APPROVAL_RE) only + // treats Chinese text as approval when it is 确认-anchored (e.g. "确认搭建"). + // A bare "…搭建吧" silently fails the gate → the agent re-proposes and the + // button looks inert. Keep both messages matching the gate's 确认 anchor. + it('AI plan-approve messages stay anchored on the confirm gate keyword (确认)', () => { + const i18n = createI18n({ defaultLanguage: 'zh', detectBrowserLanguage: false }); + // Mirror of the cloud APPROVAL_RE Chinese clause (confirm-gate.ts). Kept + // narrow on purpose: a plain build REQUEST ("帮我搭建一个 CRM") must NOT match. + const gate = /确认[,,、]?\s*(开始|可以|并|要)?\s*(搭建|创建|生成|构建|修改|应用)|直接搭建/; + expect(i18n.t('console.ai.planApproveMessage')).toMatch(gate); + expect(i18n.t('console.ai.planApproveDefaultsMessage')).toMatch(gate); + expect('帮我搭建一个 CRM').not.toMatch(gate); + }); + it('translates common keys in Japanese', () => { const i18n = createI18n({ defaultLanguage: 'ja', detectBrowserLanguage: false }); expect(i18n.t('common.save')).toBe('保存'); diff --git a/packages/i18n/src/locales/zh.ts b/packages/i18n/src/locales/zh.ts index cc245d7c4..a59faf191 100644 --- a/packages/i18n/src/locales/zh.ts +++ b/packages/i18n/src/locales/zh.ts @@ -1172,8 +1172,13 @@ const zh = { planApproveHint: '回复以确认或调整该方案。', planApprove: '开始搭建', planAdjust: '调整方案', - planApproveMessage: '就按这个方案搭建吧。', - planApproveDefaultsMessage: '就按你的合理假设直接搭建,未决问题用默认即可。', + // The two messages the "开始搭建" button SENDS (not the label above) must + // match the cloud confirm gate's APPROVAL_RE (service-ai-studio + // confirm-gate.ts), or the agent re-proposes instead of building and the + // button looks inert. The gate anchors Chinese approval on 确认 (or + // 直接搭建) — a bare "…搭建吧" does NOT match. Keep these 确认-anchored. + planApproveMessage: '确认,开始搭建。', + planApproveDefaultsMessage: '确认搭建,未决问题按你的合理假设和默认处理。', planAnswerMessage: '关于「{{question}}」,我选择「{{option}}」。', justNow: '刚刚', minutesAgo: '{{count}} 分钟前',