diff --git a/doc/prd/workbench.md b/doc/prd/workbench.md index ce26aace..cb334ebf 100644 --- a/doc/prd/workbench.md +++ b/doc/prd/workbench.md @@ -242,15 +242,16 @@ #### WB-SESSION-011 清空消息记录 -- 系统行为:一次 AI run 正常完成后,Composer 上方出现「清空消息记录」胶囊(与消息操作胶囊同壳,内含橡皮/擦除图标,不用火花或垃圾桶)。整颗主操作 hover 提示:`清空「{伙伴名}」的全部消息记录,无法恢复。`。点击后先弹出确认框(标题「清空消息记录?」,正文说明将删除该伙伴全部对话消息且无法恢复、伙伴本身保留;主按钮「清空」为危险态)。确认后物理删除该伙伴 `chat_session_message_log` 全部行及对应 `ai_run`;**不删除** `ai_file_change`、伙伴本身、Composer 草稿、右侧标签与浏览器标签。清空后主区消息列表为空。伙伴仍在运行时不允许清空。 +- 系统行为:当前伙伴存在消息记录、且不在 running / waiting_approval 时,Composer 上方显示「清空消息记录」胶囊(与消息操作胶囊同壳,内含橡皮/擦除图标,不用火花或垃圾桶)。整颗主操作 hover 提示:`清空「{伙伴名}」的全部消息记录,无法恢复。`。点击后先弹出确认框(标题「清空消息记录?」,正文说明将删除该伙伴全部对话消息且无法恢复、伙伴本身保留;主按钮「清空」为危险态)。确认后物理删除该伙伴 `chat_session_message_log` 全部行及对应 `ai_run`;**不删除** `ai_file_change`、伙伴本身、Composer 草稿、右侧标签与浏览器标签。清空后主区消息列表为空,胶囊随之消失。伙伴仍在运行或等待审批时不显示清空入口。 - 验收: - `WB-SESSION-011-AC1` 确认清空后该伙伴消息列表为空,不再保留旧气泡。 - `WB-SESSION-011-AC2` 清空后仍停留在同一伙伴;Composer 草稿与右侧标签保持不变。 - `WB-SESSION-011-AC3` 清空后下一次发送不再把旧对话作为模型上下文。 - - `WB-SESSION-011-AC4` 当前伙伴存在 running / waiting_approval 时,清空不可用。 + - `WB-SESSION-011-AC4` 当前伙伴存在 running / waiting_approval 时,清空入口不显示。 - `WB-SESSION-011-AC5` 胶囊文案为「清空消息记录」;hover tooltip 含伙伴名且说明无法恢复。 - `WB-SESSION-011-AC6` 点击胶囊先出现确认框;取消确认不删除任何消息。 - `WB-SESSION-011-AC7` 清空不删除该伙伴的 `ai_file_change` 文件回退记录。 + - `WB-SESSION-011-AC8` 伙伴有消息且空闲时显示清空入口;切换伙伴或重启后,只要仍有消息且空闲仍应显示。 #### WB-SESSION-012 编辑伙伴 @@ -293,9 +294,9 @@ - 验收: - `WB-COMPOSER-003-AC1` 智能模式发送后,主区先可见用户消息与 assistant 占位消息。 - `WB-COMPOSER-003-AC2` AI 运行成功启动后,assistant 过程流通过事件逐步追加更新,而不是一次性静态替换。 - - `WB-COMPOSER-003-AC3` assistant 在 Brain 思考阶段于过程流最下方展示“俺想想”并带有微光流动视觉反馈。当思考请求发起时在消息最下方展示;当收到输出、思考结束、出现“正在重试”过程组、已有可见流式 Thought / 最终回答、或 run 已结束(完成 / 失败 / 取消)时,必须隐藏“俺想想”。 + - `WB-COMPOSER-003-AC3` assistant 在 Brain 思考阶段于过程流最下方展示“让俺想想”并带有微光流动视觉反馈。运行未结束且尚无最终回答时预留同高占位,避免文案显隐导致消息区上挤抖动。当思考请求发起时展示文案;当收到输出、思考结束、出现“正在重试”过程组、已有可见流式 Thought / 最终回答、或 run 已结束(完成 / 失败 / 取消)时,必须隐藏“让俺想想”。 - `WB-COMPOSER-003-AC4` assistant turn 中 brain 最终输出始终位于过程流下方,并按 markdown 渲染;最终回答在内容分片到达后直接流式渲染,不展示独立收尾等待层;内部文件链接打开右侧文件预览,网页链接打开右侧内置浏览器;若当前伙伴已有浏览器 Tab 正停留在同一 URL,则激活该 Tab,不新开。 - - `WB-COMPOSER-003-AC5` 决策层(Thought)只展示面向用户的短摘要,不得展示模型原始长篇推理;决策层出现时,当前“俺想想”必须立即隐藏;已落地的 Thought 使用浅灰色(#787774)文本呈现思考状态;未超出单行时不展示折叠图标,超出单行时默认以单行省略号截断展示且不常驻图标,鼠标悬浮时显示展开图标,点击展开后常驻浅灰卡片背景并展示收起图标,展开内容受最大高度限制(超出纵向滚动),流式阶段平铺展开。 + - `WB-COMPOSER-003-AC5` 决策层(Thought)只展示面向用户的短摘要,不得展示模型原始长篇推理;决策层出现时,当前“让俺想想”必须立即隐藏;已落地的 Thought 使用浅灰色(#787774)文本呈现思考状态;未超出单行时不展示折叠图标,超出单行时默认以单行省略号截断展示且不常驻图标,鼠标悬浮时显示展开图标,点击展开后常驻浅灰卡片背景并展示收起图标,展开内容受最大高度限制(超出纵向滚动),流式阶段平铺展开。 - `WB-COMPOSER-003-AC6` 过程流使用用户可理解的文案,不直接暴露内部 tool 名或底层事件名;两次 Thought 之间的工具调用(含 `learn_skill`)合并为一个 Activity 面板,展开后按时间平铺自然语言说明;压缩与重试单独成行。Activity header 汇总规则见 `WB-COMPOSER-009-AC5`;等待审批时的 header 与审后工具行图标见 `WB-BLOCKER-001-AC6` / `WB-BLOCKER-001-AC7`。 - `WB-COMPOSER-003-AC7` AI 输出中切到 Settings 或触发界面重新挂载后,回到 Workbench 能通过伙伴消息记录投影恢复过程流、partial answer、最终回答或等待审批状态。 - `WB-COMPOSER-003-AC8` brain 在最终交付 markdown 中使用标准 Markdown 链接引用资料(名称 + 绝对路径或 https URL);最终交付生成后、回传界面前,后台**仅对本地文件**链接地址并行去重检查并写入交付 `linkAccess` sidecar(不改写正文)。可访问的本地文件链接保留文件预览交互;不可访问或无法识别的本地文件链接不得删除,必须使用强调色降低透明度的灰色弱化文本,悬浮提示「链接无法访问」,且不可点击。`http(s)` 网页链接不做可达性检查、不写入可达性 sidecar,交付前后均默认可点并打开内置浏览器。界面不把裸 URL / `www.…` 自动识别为链接,也不对其套用 `linkAccess` 弱化态;流式阶段尚无 sidecar 时本地文件链接可先保持可点,交付落库后按 sidecar 更新。界面渲染和用户点击时均不再次检查可访问性。渲染侧匹配 sidecar 前须对 href 做 percent-decoding / 路径规范化,避免中文等非 ASCII 路径因编码差异误判不可达。 @@ -352,7 +353,7 @@ #### WB-COMPOSER-009 消息流布局 -- 系统行为:workbench 消息区不展示用户与 assistant 头像;assistant 回复以左对齐内容流展示,过程流没有独立标题或左侧竖线,且与最终 brain 输出共用消息 rail;最终 markdown 输出直接位于内容流中;用户消息使用右对齐紧凑气泡。无消息时输入区位于主工作区中部;存在消息后输入区固定在主区底部,只允许消息区独立滚动,右侧面板展开或折叠不得改变输入区定位。过程流按真实时间展示决策层与过程层:思考层“俺想想”是 Brain 请求阶段的临时等待状态,位于过程区最下方展示,请求时出现、结束时隐藏;决策层(Thought)使用浅灰色文本,未超出单行时不显示折叠图标,超出单行时默认单行省略且鼠标 hover 显示展开图标,展开后常驻浅灰卡片背景并支持内部滚动;两次 Thought 之间的全部工具调用(含 `learn_skill`)合并为一个 Activity 面板(默认折叠,hover 显示展开箭头),header 与展开行规则见 `WB-COMPOSER-009-AC5` / `WB-COMPOSER-009-AC6`;压缩层、重试层和决策层累计保留,压缩与重试单独成行、不并入 Activity。 +- 系统行为:workbench 消息区不展示用户与 assistant 头像;assistant 回复以左对齐内容流展示,过程流没有独立标题或左侧竖线,且与最终 brain 输出共用消息 rail;最终 markdown 输出直接位于内容流中;用户消息使用右对齐紧凑气泡。无消息时输入区位于主工作区中部;存在消息后输入区固定在主区底部,只允许消息区独立滚动,右侧面板展开或折叠不得改变输入区定位。过程流按真实时间展示决策层与过程层:思考层“让俺想想”是 Brain 请求阶段的临时等待状态,位于过程区最下方展示,请求时出现、结束时隐藏;决策层(Thought)使用浅灰色文本,未超出单行时不显示折叠图标,超出单行时默认单行省略且鼠标 hover 显示展开图标,展开后常驻浅灰卡片背景并支持内部滚动;两次 Thought 之间的全部工具调用(含 `learn_skill`)合并为一个 Activity 面板(默认折叠,hover 显示展开箭头),header 与展开行规则见 `WB-COMPOSER-009-AC5` / `WB-COMPOSER-009-AC6`;压缩层、重试层和决策层累计保留,压缩与重试单独成行、不并入 Activity。 - 验收: - `WB-COMPOSER-009-AC1` 用户与 assistant 消息不展示头像或头像占位。 - `WB-COMPOSER-009-AC2` assistant 过程流和最终输出左边缘与底部 composer 内容 rail 对齐。 @@ -363,7 +364,7 @@ - `WB-COMPOSER-009-AC7` 文件名、query、命令、URL 和技能名不使用粗体或冒号强调,保持正常字重;可以通过文字颜色表达层级。 - `WB-COMPOSER-009-AC8` `learn_skill` 作为普通工具行展示,使用技能通用名称,例如 `docx 阅读器`、`docx 编辑器`、`资料查阅器`、`命令执行器`;运行中展示“正在学习 xx”,完成后展示“已学会 xx”,不再作为独立学习层。 - `WB-COMPOSER-009-AC9` Activity header、压缩层和重试层展示对应图标;浏览器各动作(打开网页使用地球图标、查看页面使用眼睛图标、操作页面使用指针图标、提取内容使用清单图标、截取页面使用相机图标、滚动页面使用上下箭头图标、列出标签使用窗口图标)、网页抓取使用下载图标、网页搜索使用放大镜图标、读取图片与生成图片使用照片相框图标(截取页面并读取图片的视觉成对动作统一使用照片图标,不退化为闪电)、知识库、文件、终端和学习使用独立语义图标;其他混合动作或混合工具时使用工作流闪电图标。展开后的每条工具句子不展示图标,也不渲染前置小圆点或“AI 思路”类图标。 - - `WB-COMPOSER-009-AC10` 决策层、Activity、压缩层、重试层按事件时间顺序累计展示;决策层采用浅灰色文本,未超出单行时不显示折叠图标,超出单行时单行截断省略,折叠状态展开图标在 hover 时显示且垂直居中于单行文本,展开时常驻浅灰卡片背景、折叠按钮居顶对齐第一行文本并在最大高度内纵向滚动,Activity 默认折叠;不存在独立学习层或最终收尾等待层;Brain 请求期间在消息流最下方展示“俺想想”。 + - `WB-COMPOSER-009-AC10` 决策层、Activity、压缩层、重试层按事件时间顺序累计展示;决策层采用浅灰色文本,未超出单行时不显示折叠图标,超出单行时单行截断省略,折叠状态展开图标在 hover 时显示且垂直居中于单行文本,展开时常驻浅灰卡片背景、折叠按钮居顶对齐第一行文本并在最大高度内纵向滚动,Activity 默认折叠;不存在独立学习层或最终收尾等待层;Brain 请求期间在消息流最下方展示“让俺想想”。 - `WB-COMPOSER-009-AC11` 无消息时输入区保持居中;存在消息后消息区为唯一纵向滚动容器,输入区固定在主区底部且不被消息内容向下推出窗口。 - `WB-COMPOSER-009-AC12` “正在 / 已检索知识库”只来自 AI 实际调用知识库工具;新建干净智能对话、仅切换伙伴时不得凭空出现该过程文案。 diff --git a/doc/test-plan/workbench-test.md b/doc/test-plan/workbench-test.md index 5569e37e..6d93739f 100644 --- a/doc/test-plan/workbench-test.md +++ b/doc/test-plan/workbench-test.md @@ -282,10 +282,10 @@ tests/case/workbench/ #### `context-clear-capsule` - 测试类型:`e2e` -- What:run 完成后出现「清空消息记录」胶囊;hover tooltip 含伙伴名与无法恢复说明;点击先确认,取消不删;确认后消息列表为空,仍停留在同一伙伴,草稿不变。 -- Why:用户需要可理解的「清空对话」动作:确认后消息列表为空,下次发送不再带旧上下文。 +- What:伙伴有消息且空闲时出现「清空消息记录」胶囊;hover tooltip 含伙伴名与无法恢复说明;点击先确认,取消不删;确认后消息列表为空,仍停留在同一伙伴,草稿不变。 +- Why:用户需要可理解的「清空对话」动作:确认后消息列表为空,下次发送不再带旧上下文;切换伙伴后只要仍有消息也应能清空。 - How:创建伙伴并完成一次真实 AI run;检查胶囊文案与 tooltip;点击胶囊后取消确认并断言消息仍在;再点胶囊并确认清空;断言消息为空、仍在同一伙伴、输入草稿不变。运行中不得出现清空入口。 -- Oracle:确认后列表为空对齐 `WB-SESSION-011-AC1`;不换伙伴 / 草稿对齐 `WB-SESSION-011-AC2`;下次发送无旧上下文对齐 `WB-SESSION-011-AC3`(由清空后 message log 为空保证);运行中不可用对齐 `WB-SESSION-011-AC4`(本 case Not,沿用既有运行态约束);文案与 tooltip 对齐 `WB-SESSION-011-AC5`;确认框取消/确认对齐 `WB-SESSION-011-AC6`。 +- Oracle:有消息且空闲时可见对齐 `WB-SESSION-011-AC8`;确认后列表为空对齐 `WB-SESSION-011-AC1`;不换伙伴 / 草稿对齐 `WB-SESSION-011-AC2`;下次发送无旧上下文对齐 `WB-SESSION-011-AC3`(由清空后 message log 为空保证);运行中不可用对齐 `WB-SESSION-011-AC4`;文案与 tooltip 对齐 `WB-SESSION-011-AC5`;确认框取消/确认对齐 `WB-SESSION-011-AC6`。 - Not:不验证 compaction;不在本 case 制造文件回退记录(`WB-SESSION-011-AC7` 由 unit `clear-partner-context-deletes-messages-and-runs-keeps-file-changes` 覆盖)。 ### 5.2 `run` @@ -296,7 +296,7 @@ tests/case/workbench/ - What:智能模式真实发送后,验证 Thought / Activity 过程层渲染与最终 markdown 收口(过程流主 case)。 - Why:重构后过程层是用户扫进度的主界面;需覆盖 Activity 折叠 header、展开平铺、学习/工具统一渲染,以及最终回答,而不是只断言“有过程块”。 - How:真实文件地址内准备带唯一事实的文件;先创建伙伴;用户通过 UI 发送自然语言总结请求;等待真实 AI run 完成;展开全部 Activity 面板并采集 header / body 文案。 -- Oracle:用户消息与 assistant 过程流逐步出现,对齐 `WB-COMPOSER-003-AC1`、`WB-COMPOSER-003-AC2`;用户与 assistant 消息不展示头像,用户消息右对齐气泡,assistant 过程流/最终输出与 composer 内容 rail 对齐,最终 markdown 无独立背景卡片,对齐 `WB-COMPOSER-009-AC1`、`WB-COMPOSER-009-AC2`、`WB-COMPOSER-009-AC3`、`WB-COMPOSER-009-AC4`。运行中过程流可见,且“正在重试”与“俺想想”不同时出现;“俺想想”在 Brain 请求期间于过程区最下方展示,run 完成 / 失败 / 取消或产出正文后过程区不得仍挂着“俺想想”,对齐 `WB-COMPOSER-003-AC3`。决策层(Thought)短摘要可见且不暴露原始长推理,以浅灰文本展示,未超出单行时不展示折叠图标,超出单行时单行省略,hover 时展示展开图标且垂直居中于单行文本,展开后常驻浅灰卡片背景、折叠按钮居顶对齐第一行并在内部滚动,对齐 `WB-COMPOSER-003-AC5`、`WB-COMPOSER-009-AC10`。若本轮确有可见工具调用:至少一块 Activity(`details` + summary + 展开行);summary 为工具独立维护的 header 短句汇总(可独立成句,不携带命令参数/路径/query,不得出现展开行半截连词如「查看页面并」),根据单一动作或混合工具精准呈现对应专属语义图标(浏览器打开/查看/操作/提取/截图/滚动/标签、网页抓取/搜索、图片读取/生成或工作流闪电图标;截取页面并读取图片的成对视觉动作统一呈现为照片图标,不退化为闪电;浏览器操作不产生审批卡片与展开行审核绿勾);展开行为带对象的工具原句且不含冒号强调;两次 Thought 之间的工具合并为 Activity,对齐 `WB-COMPOSER-003-AC6`、`WB-COMPOSER-009-AC5`、`WB-COMPOSER-009-AC6`、`WB-COMPOSER-014-AC5`、`WB-BLOCKER-001-AC8`。Header:按工具 UI 类型归并;同类多次为「短句 N 次」;归并后 ≤3 类用「并/但」拼接;>3 类 summary 为「已完成 n 项」。若事件含 `learn_skill`:展开行文案含“正在学习 / 已学会”,且不作为独立学习层;若含 docx 工具:展开行文案含“Word 文档”;对齐 `WB-COMPOSER-009-AC8`、`WB-COMPOSER-009-AC9`、`WB-COMPOSER-009-AC10`。文件名、query、命令、URL 和技能名不使用粗体或冒号强调,对齐 `WB-COMPOSER-009-AC7`。过程区不出现最终收尾等待文案(如“让俺收尾”),最终回答直接流式收口,对齐 `WB-COMPOSER-003-AC4`、`WB-COMPOSER-014-AC1`、`WB-COMPOSER-014-AC2`。证据引用与 terminal 状态规则仍由同域其他 case / AI suite 覆盖,本 case 保持 `WB-COMPOSER-003-AC8`、`WB-COMPOSER-003-AC9` 的过程流兼容边界(不因过程层重构破坏)。自动重试与截断提示、计划进度环等由相关运行态 case 覆盖并继续对齐 `WB-COMPOSER-014-AC3`、`WB-COMPOSER-014-AC4`。最终 markdown 围绕工作区事实(Alice/Bob)且不裸露 chain-of-thought,对齐 `WB-CORE-005`、`WB-CORE-006`。仅切换伙伴或新建干净对话时不得凭空出现“正在 / 已检索知识库”,对齐 `WB-COMPOSER-009-AC12`。 +- Oracle:用户消息与 assistant 过程流逐步出现,对齐 `WB-COMPOSER-003-AC1`、`WB-COMPOSER-003-AC2`;用户与 assistant 消息不展示头像,用户消息右对齐气泡,assistant 过程流/最终输出与 composer 内容 rail 对齐,最终 markdown 无独立背景卡片,对齐 `WB-COMPOSER-009-AC1`、`WB-COMPOSER-009-AC2`、`WB-COMPOSER-009-AC3`、`WB-COMPOSER-009-AC4`。运行中过程流可见,且“正在重试”与“让俺想想”不同时出现;“让俺想想”在 Brain 请求期间于过程区最下方展示,run 完成 / 失败 / 取消或产出正文后过程区不得仍挂着“让俺想想”,对齐 `WB-COMPOSER-003-AC3`。决策层(Thought)短摘要可见且不暴露原始长推理,以浅灰文本展示,未超出单行时不展示折叠图标,超出单行时单行省略,hover 时展示展开图标且垂直居中于单行文本,展开后常驻浅灰卡片背景、折叠按钮居顶对齐第一行并在内部滚动,对齐 `WB-COMPOSER-003-AC5`、`WB-COMPOSER-009-AC10`。若本轮确有可见工具调用:至少一块 Activity(`details` + summary + 展开行);summary 为工具独立维护的 header 短句汇总(可独立成句,不携带命令参数/路径/query,不得出现展开行半截连词如「查看页面并」),根据单一动作或混合工具精准呈现对应专属语义图标(浏览器打开/查看/操作/提取/截图/滚动/标签、网页抓取/搜索、图片读取/生成或工作流闪电图标;截取页面并读取图片的成对视觉动作统一呈现为照片图标,不退化为闪电;浏览器操作不产生审批卡片与展开行审核绿勾);展开行为带对象的工具原句且不含冒号强调;两次 Thought 之间的工具合并为 Activity,对齐 `WB-COMPOSER-003-AC6`、`WB-COMPOSER-009-AC5`、`WB-COMPOSER-009-AC6`、`WB-COMPOSER-014-AC5`、`WB-BLOCKER-001-AC8`。Header:按工具 UI 类型归并;同类多次为「短句 N 次」;归并后 ≤3 类用「并/但」拼接;>3 类 summary 为「已完成 n 项」。若事件含 `learn_skill`:展开行文案含“正在学习 / 已学会”,且不作为独立学习层;若含 docx 工具:展开行文案含“Word 文档”;对齐 `WB-COMPOSER-009-AC8`、`WB-COMPOSER-009-AC9`、`WB-COMPOSER-009-AC10`。文件名、query、命令、URL 和技能名不使用粗体或冒号强调,对齐 `WB-COMPOSER-009-AC7`。过程区不出现最终收尾等待文案(如“让俺收尾”),最终回答直接流式收口,对齐 `WB-COMPOSER-003-AC4`、`WB-COMPOSER-014-AC1`、`WB-COMPOSER-014-AC2`。证据引用与 terminal 状态规则仍由同域其他 case / AI suite 覆盖,本 case 保持 `WB-COMPOSER-003-AC8`、`WB-COMPOSER-003-AC9` 的过程流兼容边界(不因过程层重构破坏)。自动重试与截断提示、计划进度环等由相关运行态 case 覆盖并继续对齐 `WB-COMPOSER-014-AC3`、`WB-COMPOSER-014-AC4`。最终 markdown 围绕工作区事实(Alice/Bob)且不裸露 chain-of-thought,对齐 `WB-CORE-005`、`WB-CORE-006`。仅切换伙伴或新建干净对话时不得凭空出现“正在 / 已检索知识库”,对齐 `WB-COMPOSER-009-AC12`。 - Not:不对最终文案逐字断言;不把真实模型是否调用某工具误归因为 UI bug(工具相关断言均以本轮实际事件为条件)。 #### `terminal-background-service-flow` diff --git a/logo/README.md b/logo/README.md index b5b3d43f..a34504da 100644 --- a/logo/README.md +++ b/logo/README.md @@ -49,4 +49,4 @@ Windows 与 macOS 使用不同的安全留白比例。Windows ICO 包含 16、20 这版 logo 的核心是“憨厚可靠的工作伙伴”。 -黑色圆形是稳定底座,代表工具的可靠性。帽檐和思考点轻微跳出圆形,表达产品里“俺想想”的气质:不是冷冰冰地正在处理,而是像一个会帮用户琢磨办法的伙伴。 +黑色圆形是稳定底座,代表工具的可靠性。帽檐和思考点轻微跳出圆形,表达产品里“让俺想想”的气质:不是冷冰冰地正在处理,而是像一个会帮用户琢磨办法的伙伴。 diff --git a/src/main/services/ai/human/node/brainNode/index.ts b/src/main/services/ai/human/node/brainNode/index.ts index 4f5ab9bf..86f2f645 100644 --- a/src/main/services/ai/human/node/brainNode/index.ts +++ b/src/main/services/ai/human/node/brainNode/index.ts @@ -135,7 +135,7 @@ export const createBrainNode = (input: { const classifyStreamAsThought = (): void => { if (streamClassifiedAsThought) return streamClassifiedAsThought = true - // Process-layer "俺想想" closes as soon as brain produces visible output. + // Process-layer "让俺想想" closes as soon as brain produces visible output. // Log annotation thinking_completed stays until the round finishes (thought projection). completeThinking() input.ctx.sendEvent({ diff --git a/src/renderer/src/components/workbench/AssistantTurnCard.tsx b/src/renderer/src/components/workbench/AssistantTurnCard.tsx index 98c87f3d..9d05e273 100644 --- a/src/renderer/src/components/workbench/AssistantTurnCard.tsx +++ b/src/renderer/src/components/workbench/AssistantTurnCard.tsx @@ -557,6 +557,10 @@ const AssistantTurnCard: React.FC = ({ runFinished: Boolean(turn?.runFinished), hasFinalAnswer }) + /** 运行未结束且尚无最终回答时预留固定行高,避免「让俺想想」显隐把页面顶抖 */ + const reserveThinkingSlot = + showThinkingIndicator || + (!Boolean(turn?.runFinished) && !Boolean(turn?.waitingApproval) && !hasFinalAnswer) const processGroups = useMemo( () => (turn?.processGroups || []).filter((group) => group.kind !== 'thinking'), [turn?.processGroups] @@ -586,7 +590,7 @@ const AssistantTurnCard: React.FC = ({ return (
- {timeline.length > 0 || hasStreamingThought || showThinkingIndicator ? ( + {timeline.length > 0 || hasStreamingThought || reserveThinkingSlot ? (
= ({
) : null} - {showThinkingIndicator ? ( + {reserveThinkingSlot ? (
- - 俺想想 - + {showThinkingIndicator ? ( + + 让俺想想 + + ) : null}
) : null}
diff --git a/src/renderer/src/components/workbench/utils.ts b/src/renderer/src/components/workbench/utils.ts index 40c2ed1a..4d47d39e 100644 --- a/src/renderer/src/components/workbench/utils.ts +++ b/src/renderer/src/components/workbench/utils.ts @@ -425,7 +425,7 @@ const getDisplayGroupText = ( status: AssistantProcessStatus ): AssistantRichTextSegment[] => { if (display.kind === 'thinking') { - if (status === 'running') return sentence(text('俺想想')) + if (status === 'running') return sentence(text('让俺想想')) return [] } if (display.kind === 'retry') { @@ -639,7 +639,7 @@ export const createAssistantThinkingGroup = (messageId: string): AssistantProces skillKey: 'generic', iconKind: 'default', status: 'running', - runningText: sentence(text('俺想想')), + runningText: sentence(text('让俺想想')), completedText: [], failedText: [], partialFailedText: [], diff --git a/src/renderer/src/pages/ChatPage.tsx b/src/renderer/src/pages/ChatPage.tsx index 102cdc64..15424990 100644 --- a/src/renderer/src/pages/ChatPage.tsx +++ b/src/renderer/src/pages/ChatPage.tsx @@ -375,7 +375,7 @@ const reduceAssistantTurnByRunEvent = ( } if (event.type === 'run_warning') { - // 告警不停跑:仅结束「俺想想」,不把 turn 标 failed。 + // 告警不停跑:仅结束「让俺想想」,不把 turn 标 failed。 next = { ...next, isBrainThinking: false } } @@ -771,7 +771,6 @@ const ChatPage: React.FC = () => { const [createPartnerShape, setCreatePartnerShape] = useState('circle') const [createPartnerColor, setCreatePartnerColor] = useState('blue') const [createPartnerSubmitting, setCreatePartnerSubmitting] = useState(false) - const [clearContextVisible, setClearContextVisible] = useState(false) const [busyCancelTask, setBusyCancelTask] = useState(null) const [activeTimelineDayStart, setActiveTimelineDayStart] = useState(null) const [composerAiPreference, setComposerAiPreference] = useState('default') @@ -1282,6 +1281,14 @@ const ChatPage: React.FC = () => { () => [...currentMessages].reverse().find((item) => item.role === 'user')?.id || null, [currentMessages] ) + const clearContextVisible = useMemo( + () => + Boolean(currentPartnerId) && + currentMessages.length > 0 && + !aiRunId && + !pendingApprovalBatch, + [aiRunId, currentMessages.length, currentPartnerId, pendingApprovalBatch] + ) const userMessageTimeIds = useMemo( () => collectUserMessageTimeIds(currentMessages), [currentMessages] @@ -1878,7 +1885,6 @@ const ChatPage: React.FC = () => { const opened = await window.api.partnerOpen({ partnerId, limit: 50 }) if (partnerSwitchRequestRef.current !== requestId) return applyPartnerUiState(partnerId, opened.uiState || null) - setClearContextVisible(false) setActiveTimelineDayStart(null) pendingTimelineJumpDayRef.current = null const restoredActiveTab = opened.uiState?.panel.tabs.find( @@ -2776,7 +2782,6 @@ const ChatPage: React.FC = () => { setAssistantTurns({}) setAiRunId(null) setLoading(false) - setClearContextVisible(false) void window.api.workbenchUiStateSave({ activeViewKey: null }) } } @@ -3241,9 +3246,6 @@ const ChatPage: React.FC = () => { }) } void refreshContextUsage(eventPartnerId || currentPartnerIdRef.current) - if (eventPartnerId === currentPartnerIdRef.current) { - setClearContextVisible(true) - } } }) return () => { @@ -3394,7 +3396,6 @@ const ChatPage: React.FC = () => { setCancellingRun(false) setPendingApprovalBatch(null) setApprovalSubmitting(false) - setClearContextVisible(false) lastSubmittedInputRef.current = userQuery setPartners((items) => items.map((item) => @@ -3506,7 +3507,6 @@ const ChatPage: React.FC = () => { } setCurrentMessages([]) setHasMoreMessagesBefore(false) - setClearContextVisible(false) setActiveTimelineDayStart(null) void loadPartners() } catch (error) { diff --git a/src/shared/assistantThinkingWait.ts b/src/shared/assistantThinkingWait.ts index 44bc084a..8166ed17 100644 --- a/src/shared/assistantThinkingWait.ts +++ b/src/shared/assistantThinkingWait.ts @@ -22,7 +22,7 @@ export type AssistantThinkingIndicatorInput = { } /** - * “俺想想”展示判断规则: + * “让俺想想”展示判断规则: * - 请求时展示(isBrainThinking 为 true); * - 结束时隐藏(收到输出、出错、run 结束、等待审批或已产出最终交付时隐藏)。 */ diff --git a/tests/case/workbench/conversation/message/user-message-actions.e2e.test.ts b/tests/case/workbench/conversation/message/user-message-actions.e2e.test.ts index d80c5af5..0b578fa9 100644 --- a/tests/case/workbench/conversation/message/user-message-actions.e2e.test.ts +++ b/tests/case/workbench/conversation/message/user-message-actions.e2e.test.ts @@ -314,8 +314,8 @@ describe('workbench conversation e2e', () => { result.runningEditButtons === 0 && result.messageAttachmentTexts.some((text) => text.includes('message-note.md')) && result.messageAttachmentTexts.some((text) => text.includes('MD')) && - result.assistantProcessTextAfterSend.includes('俺想想') && - (result.assistantProcessTextAfterWait.includes('俺想想') || + result.assistantProcessTextAfterSend.includes('让俺想想') && + (result.assistantProcessTextAfterWait.includes('让俺想想') || result.assistantProcessTextAfterWait.includes('处理中')) && result.interruptedRunCancelled && result.attachmentsAboveBubble, diff --git a/tests/case/workbench/run/process/ai-process-stream-and-final-answer.e2e.test.ts b/tests/case/workbench/run/process/ai-process-stream-and-final-answer.e2e.test.ts index 71dc5ff9..c03aeaf3 100644 --- a/tests/case/workbench/run/process/ai-process-stream-and-final-answer.e2e.test.ts +++ b/tests/case/workbench/run/process/ai-process-stream-and-final-answer.e2e.test.ts @@ -136,10 +136,10 @@ const sampleThinkingWaitEarly = async ( ): Promise<{ sawThinkingWait: boolean; processTextDuringRun: string }> => { const deadline = Date.now() + timeoutMs let processTextDuringRun = ((await processLocator.textContent()) || '').trim() - let sawThinkingWait = /俺想想/u.test(processTextDuringRun) + let sawThinkingWait = /让俺想想/u.test(processTextDuringRun) while (Date.now() < deadline && !sawThinkingWait) { processTextDuringRun = ((await processLocator.textContent()) || '').trim() - if (/俺想想/u.test(processTextDuringRun)) { + if (/让俺想想/u.test(processTextDuringRun)) { sawThinkingWait = true break } @@ -149,7 +149,7 @@ const sampleThinkingWaitEarly = async ( } if (!sawThinkingWait) { processTextDuringRun = ((await processLocator.textContent()) || '').trim() - sawThinkingWait = /俺想想/u.test(processTextDuringRun) + sawThinkingWait = /让俺想想/u.test(processTextDuringRun) } return { sawThinkingWait, processTextDuringRun } } @@ -179,7 +179,7 @@ describe('workbench run e2e', () => { const earlySample = await sampleThinkingWaitEarly(page, processLocator) const retryAndThinkingCoexist = /正在重试/u.test(earlySample.processTextDuringRun) && - /俺想想/u.test(earlySample.processTextDuringRun) + /让俺想想/u.test(earlySample.processTextDuringRun) const evidence = await waitForWorkbenchAiRunCompletion( runtime, startedAtMs, @@ -195,7 +195,7 @@ describe('workbench run e2e', () => { sawThinkingWait: earlySample.sawThinkingWait, processTextDuringRun: earlySample.processTextDuringRun, retryAndThinkingCoexist, - thinkingStuckAfterComplete: /俺想想/u.test(processRender.processRootText), + thinkingStuckAfterComplete: /让俺想想/u.test(processRender.processRootText), processRender, visibleToolNames, finalAnswerText, @@ -260,7 +260,7 @@ describe('workbench run e2e', () => { { name: 'workbench-ai-process-activity-render-real', message: - '真实 AI run 应渲染 Thought/Activity 过程层(header 同类归并/并但/>3 类已完成 n 项、展开平铺、无收尾等待层、俺想想不卡在完成后),并产出围绕工作区事实的最终 markdown,对齐 WB-COMPOSER-003、WB-COMPOSER-009、WB-COMPOSER-014、WB-CORE-005、WB-CORE-006。', + '真实 AI run 应渲染 Thought/Activity 过程层(header 同类归并/并但/>3 类已完成 n 项、展开平铺、无收尾等待层、让俺想想不卡在完成后),并产出围绕工作区事实的最终 markdown,对齐 WB-COMPOSER-003、WB-COMPOSER-009、WB-COMPOSER-014、WB-CORE-005、WB-CORE-006。', data: result } )