优化: AI Chat 体验全面升级(图标/审批/目标提取/窗口管理)
- AI 入口图标:灯泡→星花 sparkles+发光,与灵感入口区分 - 目标提取根本性改造:用户消息规则→工具调用推理(infer_goal_from_tool_calls) - Vec<String>→Vec<GoalEntry>(text+status),active→completed 状态流转 - 多条/轮提取,system_prompt 仅注入 active 目标 - 代码拆分到 helpers.rs(解决 brace 嵌套致 pub(crate) 不可见) - 审批修复:patch_file 全档位自动放行,批量审批防抖,乐观更新竞态保护 - 审批通知浮层:全局右上角 ApprovalOverlay,窗口遮挡时可见 - 设置导入导出移除:价值低占用空间,跨设备同步建议复制 SQLite - 分离窗口默认置顶+置顶状态持久化(刷新后保持) - header 菜单聚合:清空/压缩上下文收入 ... popout - LLM 文字重叠防御:delta 重复检测+丢弃 - 置顶图标:星→大头针 pushpin - 文档/注释更新:过期 Vec<String>/chat.rs 提取描述修正
This commit is contained in:
@@ -42,6 +42,9 @@ let _unlistenApprovalClear: (() => void) | null = null
|
||||
// (两回调写同一 state.currentText → 流式文字双倍)
|
||||
let _startPromise: Promise<void> | null = null
|
||||
|
||||
// 上一次 AiTextDelta 的内容(单窗口内 LLM 重复 delta 防御用,见 handleStreamingEvent)
|
||||
let _lastDelta = ''
|
||||
|
||||
const appSettings = useAppSettingsStore()
|
||||
|
||||
// B-260616-17: 看门狗不重置的事件集合(审批等待/完成/错误由各自 case 内 clear)。
|
||||
@@ -205,6 +208,7 @@ export function flushCurrentText() {
|
||||
// 自清把 flush 语义收敛为"回填并归零",消除对调用方清空顺序的依赖。各调用方后续的
|
||||
// currentText='' 对已清空值幂等,无副作用。
|
||||
state.currentText = ''
|
||||
_lastDelta = '' // 同步重置 delta 跟踪,避免新轮首个 delta 误命中上一轮末 delta 重复检测
|
||||
}
|
||||
|
||||
/** token 用量展示开关(读 appSettings,与 Settings.vue 共享 key `df-show-token-usage`) */
|
||||
@@ -274,9 +278,28 @@ function removePendingDirAuth(id: string): void {
|
||||
/** streaming 域:流式文本累积/新轮/心跳/重试/max 轮暂停 */
|
||||
function handleStreamingEvent(event: AiChatEvent): boolean {
|
||||
switch (event.type) {
|
||||
case 'AiTextDelta':
|
||||
case 'AiTextDelta': {
|
||||
// BUG-260624-01 / UX-260617-12 消息重叠防御:
|
||||
// 历史多次报「LLM 回复文字重复」(如「好好,,现在现在我对我对」单字双重叠加)。
|
||||
// 已排除的根因:后端 stream_recv.rs emit 增量 chunk.delta(非累积)、
|
||||
// startListener 幂等+_startPromise 并发去重、streamingBlocks 块级 memo。
|
||||
// 最可能残留路径:① 主窗口 AI 面板与 ai-detached 分离窗口同时打开,两 webview 独立 JS 上下文
|
||||
// 各自 listen 全局广播事件 → 各自 currentText += delta(用户感知「双倍」)。
|
||||
// 桌面双窗口场景下难以在单窗口内根治,需后端定向 emit_to(label) 重构。
|
||||
// ② LLM provider(GLM anthropic_compat 等)在特定情况下返重复 delta。
|
||||
// 防御:连续两次 delta 完全相同(且非空)时丢弃第二次 + console.warn,留下诊断证据。
|
||||
// 副作用极低:正常 LLM 流不会连发完全相同 delta(空格/单字符除外,已 len>1 守卫)。
|
||||
if (event.delta && _lastDelta === event.delta && event.delta.length > 1) {
|
||||
// df-ai-trace-delta 开关控制(默认开,生产可关)
|
||||
if (appSettings.get('df-ai-trace-delta', true)) {
|
||||
console.warn('[AiTextDelta] 重复 delta 已丢弃(疑似双窗口 listener 或 provider 异常):', JSON.stringify(event.delta))
|
||||
}
|
||||
return true
|
||||
}
|
||||
_lastDelta = event.delta
|
||||
state.currentText += event.delta
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiAgentRound': {
|
||||
// Agent 循环新一轮:保存当前文本到上一条 assistant 消息,新建空 assistant 消息
|
||||
|
||||
Reference in New Issue
Block a user