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}} 分钟前',