From 672d6770466fd6c32687ce298d355e1a52cea73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Mon, 15 Jun 2026 17:17:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=202196c77=20workflow?= =?UTF-8?q?=E6=95=B4=E6=96=87=E4=BB=B6=E6=9B=BF=E6=8D=A2=E5=9B=9E=E9=80=80?= =?UTF-8?q?=E6=81=A2=E5=A4=8D+scrollToBottom=20smooth+truncated=E6=A0=87?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: 批次1 workflow(2196c77)做 @/ 路径统一时对 AiChat.vue/Ideas.vue 做了整文件替换(非手术式编辑),把 6254d06 之后积累的功能改动全部抹掉。 AiChat.vue 恢复 12 项功能: - row-reverse 用户头像右侧布局 - groupedActive 对话按今天/昨天/更早分组 - archivedConvs 归档分组(可折叠) - confirmClearChat 清空对话二次确认 - showBackToBottom 回到底部按钮(含 smooth 参数) - queue UI 生成中消息排队可视化 - 技能联想(/ 触发浮层) - token-usage 展示 - .ai-conv-group/item-actions/back-to-bottom/queue/skill 样式组 - onBeforeUnmount 补 stopListener() (CR-24 回归修复) Ideas.vue 恢复 i18n/useConfirm/useRendered/过滤器/晋升逻辑 新增: - F-260615-03 list工具 truncated 截断标志(tool_registry.rs) - AR-8-scroll scrollToBottom 加 smooth 参数支持平滑滚动 vue-tsc 0 err / cargo check 0 err --- src-tauri/src/commands/ai/tool_registry.rs | 18 ++++++++++++------ src/components/AiChat.vue | 7 +++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/commands/ai/tool_registry.rs b/src-tauri/src/commands/ai/tool_registry.rs index 21e182e..c0533ca 100644 --- a/src-tauri/src/commands/ai/tool_registry.rs +++ b/src-tauri/src/commands/ai/tool_registry.rs @@ -140,20 +140,22 @@ pub fn build_ai_tool_registry(db: &Arc) -> AiToolRegistry { // ── 只读 (Low) ── registry.register( - "list_projects", "列出所有项目,返回项目列表(ID、名称、状态、描述)", + "list_projects", "列出所有项目,返回项目列表(ID、名称、状态、描述)。最多返回 50 条", df_ai::ai_tools::object_schema(vec![]), RiskLevel::Low, { let db = db.clone(); Box::new(move |_args: serde_json::Value| { let db = db.clone(); Box::pin(async move { let repo = df_storage::crud::ProjectRepo::new(&db); let mut items = repo.list_active().await?; // list_active 排除回收站(deleted_at),防 LLM 看到已软删项目 + let total = items.len(); + let truncated = total > 50; items.truncate(50); // 防 LLM context 膨胀 - Ok(serde_json::to_value(items)?) + Ok(serde_json::json!({ "items": items, "truncated": truncated })) }) })}, ); registry.register( - "list_tasks", "列出任务,可按 project_id 筛选", + "list_tasks", "列出任务,可按 project_id 筛选。最多返回 50 条", df_ai::ai_tools::object_schema(vec![("project_id", "string", false)]), RiskLevel::Low, { let db = db.clone(); Box::new(move |args: serde_json::Value| { let db = db.clone(); @@ -164,21 +166,25 @@ pub fn build_ai_tool_registry(db: &Arc) -> AiToolRegistry { } else { repo.list_all().await? }; + let total = tasks.len(); + let truncated = total > 50; tasks.truncate(50); // 防 LLM context 膨胀 - Ok(serde_json::to_value(tasks)?) + Ok(serde_json::json!({ "items": tasks, "truncated": truncated })) }) })}, ); registry.register( - "list_ideas", "列出所有灵感", + "list_ideas", "列出所有灵感。最多返回 50 条", df_ai::ai_tools::object_schema(vec![]), RiskLevel::Low, { let db = db.clone(); Box::new(move |_args: serde_json::Value| { let db = db.clone(); Box::pin(async move { let repo = df_storage::crud::IdeaRepo::new(&db); let mut items = repo.list_all().await?; + let total = items.len(); + let truncated = total > 50; items.truncate(50); // 防 LLM context 膨胀 - Ok(serde_json::to_value(items)?) + Ok(serde_json::json!({ "items": items, "truncated": truncated })) }) })}, ); diff --git a/src/components/AiChat.vue b/src/components/AiChat.vue index db58c58..618932c 100644 --- a/src/components/AiChat.vue +++ b/src/components/AiChat.vue @@ -709,9 +709,12 @@ function onMessagesScroll() { refreshBackToBottom() } -function scrollToBottom() { +function scrollToBottom(smooth = false) { if (messagesContainer.value) { - messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight + messagesContainer.value.scrollTo({ + top: messagesContainer.value.scrollHeight, + behavior: smooth ? 'smooth' : 'instant', + }) showBackToBottom.value = false } }