diff --git a/README.md b/README.md index 5ae6cd711..4e566c532 100644 --- a/README.md +++ b/README.md @@ -682,6 +682,9 @@ Unsent Web UI composer drafts survive page reloads and switching between convers The Web UI composer also supports browser-based voice dictation when the browser exposes the Web Speech API. The microphone button transcribes speech into the local draft only; DeerFlow receives only the transcribed text, while audio handling is delegated to the browser or operating system speech-recognition service according to that environment's policy. Users can review or edit the text before sending. +The Web UI displays a localized AI-generated-content disclaimer below the composer in both standard and custom-agent conversations, reminding users to verify important +information. + Interrupted first-turn runs still persist a fallback conversation title, so stopping a streaming response does not leave the thread as "Untitled" after refresh. Streaming Markdown responses animate only newly arrived words; text that is already visible is not faded out and replayed when the next chunk extends the same block. diff --git a/frontend/src/components/workspace/input-box.tsx b/frontend/src/components/workspace/input-box.tsx index f8dec2bd9..4f8f438b1 100644 --- a/frontend/src/components/workspace/input-box.tsx +++ b/frontend/src/components/workspace/input-box.tsx @@ -2689,6 +2689,15 @@ export function InputBox({ )} +

+ {t.inputBox.disclaimer} +

+ diff --git a/frontend/src/core/i18n/locales/en-US.ts b/frontend/src/core/i18n/locales/en-US.ts index b18c5ac5f..c9fa25538 100644 --- a/frontend/src/core/i18n/locales/en-US.ts +++ b/frontend/src/core/i18n/locales/en-US.ts @@ -116,6 +116,7 @@ export const enUS: Translations = { // Input Box inputBox: { placeholder: "How can I assist you today?", + disclaimer: "Deerflow is AI and can make mistakes", createSkillPrompt: "We're going to build a new skill step by step with `skill-creator`. To start, what do you want this skill to do?", addAttachments: "Add attachments", diff --git a/frontend/src/core/i18n/locales/types.ts b/frontend/src/core/i18n/locales/types.ts index 8e0248a65..0931cd54e 100644 --- a/frontend/src/core/i18n/locales/types.ts +++ b/frontend/src/core/i18n/locales/types.ts @@ -99,6 +99,7 @@ export interface Translations { // Input Box inputBox: { placeholder: string; + disclaimer: string; createSkillPrompt: string; addAttachments: string; inputPolish: string; diff --git a/frontend/src/core/i18n/locales/zh-CN.ts b/frontend/src/core/i18n/locales/zh-CN.ts index 3f20c1062..16f653aef 100644 --- a/frontend/src/core/i18n/locales/zh-CN.ts +++ b/frontend/src/core/i18n/locales/zh-CN.ts @@ -115,6 +115,7 @@ export const zhCN: Translations = { // Input Box inputBox: { placeholder: "今天我能为你做些什么?", + disclaimer: "内容由AI生成,重要信息请务必核查", createSkillPrompt: "我们一起用 skill-creator 技能来创建一个技能吧。先问问我希望这个技能能做什么。", addAttachments: "添加附件", diff --git a/frontend/tests/e2e/agent-chat.spec.ts b/frontend/tests/e2e/agent-chat.spec.ts index 7d44d7518..07351ce91 100644 --- a/frontend/tests/e2e/agent-chat.spec.ts +++ b/frontend/tests/e2e/agent-chat.spec.ts @@ -31,7 +31,9 @@ test.describe("Agent chat", () => { }); }); - test("agent chat page loads with input box", async ({ page }) => { + test("agent chat page loads with input box and AI disclaimer", async ({ + page, + }) => { mockLangGraphAPI(page, { agents: MOCK_AGENTS }); await page.goto("/workspace/agents/test-agent/chats/new"); @@ -39,6 +41,9 @@ test.describe("Agent chat", () => { // The prompt input textarea should be visible const textarea = page.getByPlaceholder(/how can i assist you/i); await expect(textarea).toBeVisible({ timeout: 15_000 }); + await expect( + page.getByText("Deerflow is AI and can make mistakes", { exact: true }), + ).toBeVisible(); }); test("keeps new-chat drafts isolated between agents", async ({ page }) => { diff --git a/frontend/tests/e2e/chat.spec.ts b/frontend/tests/e2e/chat.spec.ts index cde58cb11..f27366b83 100644 --- a/frontend/tests/e2e/chat.spec.ts +++ b/frontend/tests/e2e/chat.spec.ts @@ -34,6 +34,18 @@ test.describe("Chat workspace", () => { await expect(page.getByRole("button", { name: /load more/i })).toBeHidden(); }); + test("shows the localized AI disclaimer", async ({ page }) => { + await page.goto("/workspace/chats/new"); + await page.evaluate(() => { + document.cookie = "locale=zh-CN; path=/; SameSite=Lax"; + }); + await page.reload(); + + await expect( + page.getByText("内容由AI生成,重要信息请务必核查", { exact: true }), + ).toBeVisible({ timeout: 15_000 }); + }); + test("can type a message in the input box", async ({ page }) => { await page.goto("/workspace/chats/new"); diff --git a/frontend/tests/unit/core/i18n/translations.test.ts b/frontend/tests/unit/core/i18n/translations.test.ts new file mode 100644 index 000000000..7757d87eb --- /dev/null +++ b/frontend/tests/unit/core/i18n/translations.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from "@rstest/core"; + +import { translations } from "@/core/i18n/translations"; + +describe("AI disclaimer translations", () => { + it("provides the requested overseas and domestic copy", () => { + expect(translations["en-US"].inputBox.disclaimer).toBe( + "Deerflow is AI and can make mistakes", + ); + expect(translations["zh-CN"].inputBox.disclaimer).toBe( + "内容由AI生成,重要信息请务必核查", + ); + }); +});