Releases
v1.4.2
Compare
Sorry, something went wrong.
No results found
Fixed
修复流式平滑输出折叠思考预览变空/出现省略号(透明占位字符与换行占位“挤空”预览):折叠预览是单行滚动容器(nowrap + followEnd 滚到最右),此前只禁用了淡入(noFade 经 reducedMotion 参数“碰巧生效”),但换行符在 nowrap 下渲染成占位空格、text-overflow: ellipsis 在滚动失效时把后续内容全部变成“...”,高 tps 长思考时预览区仍会被挤成空白。现在 CharFlow 构造改为显式 options:noFade 正式实现(直接文本追加);新增 squashLineBreaks(换行折叠为零宽空格 \u200B,append/restore 两条路径都处理)与 tailWindow(折叠预览只保留最近 64 字符,长思考内容有界);折叠预览 CSS 改 text-overflow: clip(流式期间不再出现省略号);展开态保留逐字淡入。
思考块展开态接入渐进分段 markdown 渲染(思维链分段渲染):MessageRenderBlock 展开态注册显示层时启用 onPromote,已定型完整段落(空行分隔 + 代码围栏配对)即时由 MarkdownRenderer 渲染格式(列表/代码块不再等整段结束),未完成尾巴继续在 CharFlow 逐字淡入;registerSmoothDisplay 注册后立即尝试提升已定型段落(重建/展开后不用等下一个字符才出格式),折叠态(单行预览不适合分段格式)保持纯文本流并用 restoreFull 显示完整累计文本。
TPS 条移除空闲期随机模拟假数据并修复归零/统计口径:TpsBar 删除「流不活跃时伪造 ~12 tok/s 波动」的模拟逻辑(含 is-sim 视觉弱化),流结束/空闲时直接绘制 tpsMeter 真实 EMA 衰减曲线——柱子自然变矮滚出屏幕、不再被瞬间清空,归零后保持 0.0 tok/s 与空画布直到下一轮真实流;tpsMeter 新增归零阈值 SETTLE_EPS(无事件时 EMA 衰减到 0.05 tok/s 以下精确归零,浮点衰减不再悬停在不可见小值);工具调用输出计入 TPS:streamChunkHandlers 在 functionCall 增量到达时按函数名 + 参数 JSON 长度粗估 record(此前仅文本 delta 计入,工具参数流式输出期间曲线错误回落)。
删除消息范围或单条消息前等待主流真正退出:deleteMessage / deleteSingleMessage 先经 abortAndWaitForCompletion(或 cancel + waitForIdle)等待流退出再执行删除,避免停止后的迟到写入覆盖删除结果。
修复扩展宿主重启后子代理 Monitor 永久显示 running/queued:加载历史 run 记录时把上一宿主遗留的非终态记录纠正为 interrupted(当前进程仍活跃的 run 不受影响,按快照存在性区分)。
修复 shell 可用性检测的命令拼接注入面:checkShellAvailability 的 wsl / where / which 检测从 cp.exec 字符串拼接改为 cp.execFile argv 数组传递(customPath 属用户可控配置,不再拼进 shell 命令)。
Webview CSP 加固:ChatViewProvider 与 SubAgentMonitorPanel 的内联脚本从 'unsafe-inline' 改为 nonce 机制(每面板随机 nonce,脚本标签显式携带),不再依赖内联执行豁免。
前端正则高亮 ReDoS 护栏:新增 regexGuard(源长度 500 上限 + 危险分组量词检测 + 构造失败回退),history_search 高亮不再因畸形正则阻塞 Webview 渲染线程(与后端搜索护栏同一限制)。
修复手动总结请求丢失当前对话模型:summarizeContext 处理器此前只转发 conversationId / configId / abortSignal,前端载荷中的 modelOverride 在 webview 层被丢弃,频道配置 model 为空时总结请求仍发送空模型名(HTTP 404: No available providers at the moment)。处理器现原样透传 modelOverride,与后端 SummarizeService 的模型透传修复(含独立总结渠道隔离与默认模型回落)闭环;新增处理器层透传回归测试。
修复总结请求不携带当前对话实际选中的模型:频道配置 model 为空、用户在界面临时选择模型时,手动总结(SummarizeService.handleSummarizeContext 读取请求 modelOverride)与流式/非流式自动总结(ToolIterationLoopService 两处调用透传当前回合 modelOverride)此前均向 OpenAI 兼容接口发送空模型名(HTTP 404: No available providers at the moment);使用独立总结渠道时主动隔离主对话模型,未显式指定总结模型则回落到独立渠道自身默认模型,不再错误继承主对话的 modelOverride。
修复手动总结假成功:上下文管理关闭时发送路径直接从索引 0 读取历史,忽略已存在的手动 summary 边界(总结消息只插入历史而不物理删除旧消息),界面显示总结成功、下一次请求却仍携带全部旧上下文。现 ContextTrimService 在策略禁用时也查找并应用最后一条总结边界作为发送历史起点(decision.action = manual_summary_applied)。
修复编辑分支 / reroll 流停在「工具待确认」(awaitingConfirmation 终结)后 BranchSwitcherBar 不显示新候选:streamHandler 的 awaitingConfirmation 分支此前遗漏 finishBranchStreamTracking(complete/error/cancelled/toolIteration 终结均有,唯此遗漏),_pendingBranchRefreshAfterStream 标记残留导致分支图不刷新——用户点「保存」后不切对话看不到「‹ 2/2 ›」切换器,切换对话触发 loadBranchGraph 后才恢复。现 awaitingConfirmation 终结同样消费标记并刷新分支图(后端编辑候选在流开始时已落盘,刷新安全且即时);新增 editBranchRefresh.test.ts 覆盖 complete / cancelled / toolIteration 审批门闸 / awaitingConfirmation 四种终结路径
上下文阈值恢复为自动总结软触发条件,不再作为主 Agent 请求硬上限:ContextTrimService 预算体系重构——fallback 拒绝边界只取当前模型明确声明的 contextWindow(ContextBudgetExceededError / CONTEXT_OVERFLOW 仅在最小合法请求仍超窗时抛出),模型元数据缺失时最多 best-effort 裁剪,渠道 maxContextTokens 与默认值不再伪装成硬边界;contextThreshold 只触发自动总结与优先压缩目标,关闭上下文管理时也不因总结阈值/显示上限阻止主请求(新增显式总开关与旧版双开关回归测试)
跳过固定 prompt 占比过大时的低收益自动总结:系统提示词 + 动态上下文(fixedPromptTokens)计入预算——固定 prompt 已超软阈值且新增历史很少时跳过总结(decision.action = auto_summarize_skipped_low_savings)并继续主请求;真实窗口已超限时仍进入请求级 fallback(hard_fallback_needed),位于软阈值与硬窗口之间时原样继续;ToolIterationLoopService 流式/非流式路径把 fixedPromptTokens 透传给 getHistoryWithGranularFallback,fallback 预算细化为软预算(threshold 与模型窗口 95% 取小、扣除 provider 预留)、完整窗口 envelope 与硬边界三层
修复总结预算口径:手动总结不再受自动总结输入比例(默认 50%)提前拒绝,仅在接近总结模型真实窗口(95%)时预检失败返回 CONTEXT_OVERFLOW;自动/手动总结按 actualModelId 解析模型 contextWindow(独立总结渠道用总结模型、否则用当前对话模型),预算计入内置总结提示词、用户总结提示词与 provider 预留(resolveSummaryInputBudget);resolveSummarizeRange 保留预算支持 mainModelOverride,按主对话实际模型窗口解析而非渠道显示上限
修复 SubAgent transcript 大对象重复保存与持久化生命周期:终态 lastSentHistory 改用索引投影(lastSentHistoryProjection v1,可匹配 contents 的消息只存 contentIndex、无法匹配的内嵌原文,还原时只保留 provider 消费的 role/parts),大型工具结果/图片不再在 transcript 内保存两份,运行中仍保存完整数组;独立 transcript 按需惰性加载(transcriptLoaded,Monitor 聚焦/续跑/改消息时才读正文,恢复会话只读轻量 metadata);工具返回前 flushRun 等待终态 transcript 与元数据落盘(有限重试,扩展重载不再把已完成 run 误判为 interrupted);continueFromRunId 续跑前检测 transcriptLoaded === false 并先加载完整 transcript(保住 provider 前缀缓存命中所需的 lastSentHistory)
修复停止/删除生命周期边界:单会话停止只取消该会话的未决 diff(cancelAllPending(conversationId)),仅 cancelAllStreams 仍执行全局清理(此前停止 A 会话会取消 B 会话等待确认的 diff);检查点备份/索引位于扩展 globalStorage,deleteCheckpoint / deleteCheckpointsFromIndex / deleteAllCheckpoints / 批量删除在无工作区时改用稳定虚拟锁键继续删除(此前静默失败);对话删除时检查点清理失败返回显式错误(DELETE_CONVERSATION_CHECKPOINT_CLEANUP_FAILED)且不再继续删除会话
上下文溢出错误消息本地化与投影性能优化:SummarizeService 的 CONTEXT_OVERFLOW 与 ContextBudgetExceededError 对外消息改走 i18n(zh-CN/en/ja),ChatHandler.formatError 统一按 code 透出并携带估算参数(流式/非流式同一出口);终态 lastSentHistory 索引投影改为「粗桶 + 惰性精确索引」两级匹配(大型 parts 不再全量 stringify 作 Map key),flushRun 落盘重试次数提取为 MAX_FLUSH_RETRY_ATTEMPTS 常量
修复流式输出中长代码块无法滚动:MarkdownRenderer 通过 v-html 渲染,内容每次更新都会整体重建 DOM,代码块内部滚动容器(pre.code-block-wrapper,max-height: 400px + overflow-y: auto)因此被销毁重建、scrollTop 归零——流式期间长代码块一旦出现滚动条就无法滚动(滚动位置被重置、滚动条滚不动)。现流式期间(is-streaming)在根节点挂 is-streaming 类,CSS 据此放开 pre 的 max-height(自然展开,用户跟随输出阅读),流式结束后移除类、恢复 max-height 限制与内部滚动;思考块(thought)内的 MarkdownRenderer 同步透传 is-streaming(此前缺失),使思考过程里的长代码块同样生效。新增 MarkdownRenderer.test.ts(is-streaming 类切换、代码块结构完整性、流式内容追加渲染)与 MessageRenderBlock.test.ts(思考块 is-streaming 透传)。
修复流式平滑输出生命周期清理不全(SmoothStreamer 与 smoothTexts 条目泄漏):handleError 与终结性 toolIteration 此前先置空 streamingMessageId 再清理导致清理 no-op;complete/cancelled 的占位 id → 持久化 id 迁移后按新 id 清理残留旧条目;cancelStream/cancelStreamAndRejectTools/deleteMessage/deleteSingleMessage/clearMessages/resetConversationState/closeTab/switchTab 等本地重置路径(closeTab 时后端 cancelled 被后台缓冲丢弃、前端收不到终结)全部补上清理;占位 id 迁移时同步迁移 manager 条目键;disposeAllSmoothStreams 挂到 webview 卸载兜底。
修复流式平滑「替换最后一个文本/思考块」在新段落前导空白时错位(上一段已完成内容被平滑文本覆盖 → 消失→重现闪烁):纯空白 delta 不再进入平滑层(与 flushText 的 trim 语义对齐);显示层 smoothTexts 值改为携带 partKey,RenderBlock 增加 partKey 标识,MessageItem 只替换 partKey 匹配的块、找不到匹配块(快照重建的合并块)时回退真实文本。
修复流式平滑档位实时切换跳变:off→on 时新建 streamer 以当前 part 已累计真实文本为显示基线(不再整段消失重打);on→off 时立即 flush + dispose + 删除显示文本,切回真实内容。
修复流式结束/中断时超长代码块高度塌缩导致阅读位置丢失:MarkdownRenderer 流式期间记录实际高度超过限制的代码块,is-streaming 类解除时对这些块保留展开态(keep-expanded,max-height: none),用户点击换行按钮或滚动离开该块后恢复正常高度限制;流式类采用「滞后副本」过渡,杜绝先塌缩再弹回的闪烁。
修复 TPS 条在 Agent 工具执行/思考停顿(>2s 无 token)时误显示随机模拟数据并来回切换:TpsBar 引入「流活跃」信号(chatStore.isStreaming || isWaitingForResponse)——流活跃期间只显示真实(衰减)曲线、禁止启动模拟;模拟阶段加视觉区分(透明度降低)。修复 tpsMeter.record 无容量上限(webview 隐藏/后台流停表期间 events 无界增长):记录上限 1000 条、超出丢最旧。
修复设置持久化丢失(自动执行/工具策略/预设条目开关重启回滚):VSCodeSettingsStorage 保存快照此前直接保存活对象引用,保存成功后对同一对象的原地变更(toolAutoExec[tool] = x、toolsConfig[key] = v 等嵌套写入)会被 deepEqual 的 a === b 引用短路误判为「无变化」而跳过写盘,表现为自动执行开关/工具策略/预设条目开关重启后回滚。现快照改存深拷贝(deepCloneValue,structuredClone + JSON 往返回退),与活对象解耦;saveToolsConfigEntry / setToolAutoExec / setToolEnabled 同步改为整体替换对象(与既有 setToolsEnabled 约定一致);新增原地变更 + 重启读回归测试。
用量统计页展示读取失败被跳过的对话明细:aggregateUsageStats 统计被跳过对话时收集 skippedConversationDetails(标题尽力读取,meta 读取失败/无标题时回退 conversationId),用量页在跳过提示下新增明细列表(标题单行省略截断,悬停显示 conversationId 完整值)。
修复流式平滑尾巴与渐进 markdown 衔接处字号跳变:思考块展开态下 CharFlow 流式尾巴此前继承全局 --vscode-font-size(大字号、正常色、直体),与已提升段落的 md 渲染(--lim-md-font-size: 12px 灰斜体小字)前后相接时字号/颜色/字重同时跳变。现 .thought-flow-content 与 .tail-stream 显式对齐同容器 MarkdownRenderer 的 --lim-md-* 字体规格(思考块 12px/1.5 灰斜体,正文 13px/1.6 正常色),流式尾巴与已定型段落视觉连续;正文 tail-stream 同步固定规格,用户调大 VSCode 字号后正文也不会再出现跳变。
Changed
系统提示词设置页保存按钮加大加宽:模式选择栏右上角保存按钮从 24×24 纯图标改为带「保存配置」文字、最小宽度 88px 的实底主色按钮(图标 + 文字 + hover 变色),与旁边的小图标操作按钮区分开,不再不显眼。
开屏动画改为可选:外观设置新增「开屏动画」开关(ui.appearance.splashEnabled,默认开启),关闭后启动不再渲染 Splash 直接进入主界面;启动时随外观设置全局加载,保存/重置与其余外观项一致(后端 generalTypes 同步补字段类型与默认值)。
措辞统一:Splash 相关代码注释、i18n 文案与 CHANGELOG 中「灰码少女」的称呼统一改为「Gray logo」(图形线稿取自 resources/icon.svg)。
TPS 实时可视化条改为可选:外观设置新增「TPS 实时可视化条」开关(ui.appearance.tpsBarEnabled,默认开启),关闭后输入区底部不再渲染曲线(tpsMeter 随之停表,重新开启后从当前流重新统计);启动时随外观设置全局加载,保存/重置与其余外观项一致。
流式输出期间已完成段落即时渲染 markdown(渐进式提升):CharFlow 新增 settledText/promote——已定型文本到达安全段落边界(以空行 \n\n 结尾、且行首代码围栏 ```/~~~ 配对,未闭合代码块整块保留到围栏闭合)时,把该前缀从字符流水线剥离并交给 MessageItem 新增的渐进 `MarkdownRenderer` 即时渲染,未完成尾巴继续逐字淡入;长回答不再等到输出结束才出现格式。段落切换/终结时渐进内容随显示层释放(稳定块完整接管,无重复显示);档位切换与组件重建(切标签页)时 promote 边界(`promotedText`)随 entry 继承/重放,CharFlow 只恢复未提升尾巴,显示连续不跳变。
初次载入「开始动画」升级为完整叙事(Splash.vue):蓝图点阵背景 + 晕影聚焦;笔尖光点沿描线路径执笔画出 Gray logo(SMIL animateMotion + mpath 直接引用线稿 path,先帽后身,与描线 stroke-dashoffset 同曲线同节奏);完稿瞬间线条定影提亮、此后呼吸待机;标题改为「Gray 粗 / Code 细」+ 蓝色终端光标 ▍ 闪烁 + 副标题「AI CODING ASSISTANT」;原横线脉冲替换为 3-bit 格雷码等待线(000→001→011→010→110→111→101→100 循环,每步恰好只变一位,ready 后归一为蓝色实线);淡出升级为 blur+scale 消散,.chat-view 加 0.3s 淡入承接;DRAW_TOTAL_MS 1400→1700、minDisplayMs 默认 1100→1700,描线/定影/格雷码时间轴严格对齐;prefers-reduced-motion 分支同步更新(SMIL 光点直接隐藏);测试常量同步。
开始动画「草稿→上色」叙事升级 + 格雷码线可见性修复(Splash.vue):SVG 改双层结构——色块层(body 按 M…Z 拆块:身体/头发/脸镂空/帽檐/帽身,后画的覆盖重叠区)在描线完成后 1.6s 起 ink-in 错峰渗入(身体 1.6s / 帽子 1.75s),线稿同刻退位为细描边(line-retire 动画,delay 自元素插入起算,与 settled 类时机解耦);灰阶色块用 color-mix 从 currentColor 派生,亮/暗主题自适应;定影闪光挪到 2.0s 当「定稿章」。格雷码等待线修复「开场即全灭 + 归一不可见」:起跳提前到 1.15s、周期 2.4s→2s、相位旋转到 001 起始、对比度 0.15/0.9→0.12/1、容器与副标题同款 fade-up 入场;ready 退场改两拍——先归一(merging 类,0.42s:蓝线合并 + 光标定格实心 + 一次性 line-flash 闪光)再淡出(0.45s),归一不再被淡出淹没;DRAW_TOTAL_MS 1700→2300、minDisplayMs 默认 1700→2300;光标闪烁改 steps(1, end) 惯用写法;splash 根加 role="status";prefers-reduced-motion 分支同步(色块直接可见、线稿静态细描边);测试常量与两拍退场断言同步。
移植 fork 的全仓性能优化(保留插件形态,不涉及桌面版 electron 层):
getMetadataLight 接入会话元数据 LRU 缓存(256 条):对话列表分页(每页 30 条)、用量统计与检查点查询的逐对话读取从「每次 fs 读 + JSON parse」降为纯内存命中;所有写路径统一失效/回填——saveMetadata 落盘点收敛为 persistMetadata(写后回填缓存),saveHistory/appendHistory/历史迁移/分支全量重写等刷新 updatedAt 的路径失效缓存,删除会话同步失效(含负缓存);读侧返回深拷贝防调用方污染
usedTokens 两趟循环(正序找最新总结估算 + 逆序找最后一条助手 usage)合并为单趟逆序扫描:流式期间每个 chunk 都会使该 computed 失效,数组访问量减半;语义等价(新增 6 例回归测试覆盖 usage/总结估算 timestamp 优先级)
占位消息定位 Map 索引化:isLateTerminalChunkWithoutStreamId 与 handleError 的 O(n) find 改为 getMessageIndexById(与其它热路径一致)
handleStreamChunkBatch 诊断日志不再 slice + filter 分配临时数组,改为循环计数(终结 batch 每次都会走到)
Diff 工具卡顿优化(前端行级差分与渲染热路径,覆盖 apply_diff / write_file / search_in_files 面板与 VirtualDiffLines):
lineDiff 新增带缓存的 computeLineDiffCached:按内容 + 起始行 + 编辑预算键控、上限 32 条的 FIFO 缓存。流式结果更新 / 组件重渲染期间同一 hunk 直接复用上一次结果对象,不再重复 Myers 计算;同一结果对象引用同时让下游虚拟列表的 props 保持稳定,不再整树重渲染
Myers 快速失败:新旧核心区域无公共行且 n+m 超出编辑距离预算时直接输出退化结果(语义与预算耗尽时完全一致),大文件整体重写场景从跑满 768 层迭代降为一次行 ID 集合探测
Myers trace 改为按层动态分配(第 d 层仅覆盖 [-d, d] 对角线,offset 随层递增),总内存约为原来的 1/2,长距离 diff 的分配压力显著下降
apply_diff / write_file / search_in_files 的行级差分改为增量式:只对新加载/变更的文件或块计算并缓存结果(此前任一文件加载完成都会触发全部文件全量重算);展示行从「模板内每次渲染 slice」改为「按展开状态缓存的稳定引用」,父组件重渲染不再生成新数组导致 VirtualDiffLines 反复整体重渲染
search_in_files / write_file 批量 diff 内容加载改为并行(此前逐个 await 串行等待,N 个文件需 N 次往返);search_in_files 匹配列表按文件预分组,模板内不再对全量结果重复 filter
VirtualDiffLines 滚动事件按 rAF 节流:连续滚动时每帧至多同步一次视口,不再高频触发窗口行计算与重渲染
ToolMessage 对 diff.statusChanged 相同载荷去重:后端重复广播同一 pending diff 状态(定时器刷新 / 多面板路由)时跳过全部响应式更新,不再让所有消息组件无谓重渲染
存档点排除配置的默认类别行布局修正:「N 条规则」计数与「编辑」按钮组合为右侧操作列整体右对齐(计数紧贴按钮左侧),不再因各勾选框标签宽度不同而在行间漂移居中;补上此前缺失的编辑按钮 hover/禁用样式。
子代理工具白名单/黑名单改为按分类分组展示:新增公共工具分类模块 frontend/src/utils/toolCategory.ts(工具设置页与子代理设置页共用同一套分类名/图标映射),子代理面板工具列表从「内置工具 / MCP 工具」两个平铺大列表改为按后端 category 分组的分类卡片(文件、搜索、终端、媒体等,MCP 独立成组,缺省分类归入「其他」);每个工具项显示本地化名称 + 等宽工具 ID + 描述,MCP 分类文案接入三语 i18n;工具设置页同步改用公共分类模块(展示行为不变)。
分支树面板「完整消息」升级为「完整消息图」(高级模式):由目录树缩进改为轨道式泳道布局——每条消息一行,轨道列数由同时存在的候选分支决定(候选分支走完即释放轨道、后续新候选复用,不再随消息数量无限向右扩展);分叉以水平连接线表达,活跃路径轨道线高亮;默认折叠连续线性段,新增「展开完整消息」开关可查看全部节点;「分支导航」缩略版保持不变,三语文案同步。
总结 Token 统计改为「主上下文压缩量」口径:新增 SummaryTokenStats(被替换历史估算 token、新摘要 token、估算节省量、总结前主上下文 token 与总结后估算值),总结消息落库与前端展示均使用新口径(历史 → 摘要 + 节省量),旧记录明确标注为「总结模型请求输入 → 输出」(beforeTokenCount / afterTokenCount 标记 deprecated);会话用量指示器在总结后优先使用新估算值,下一次真实主回复后自动恢复实际用量(timestamp 判断新旧)。
被裁剪历史的逐字用户输入保险档案上限从 160k 字符降至 64k(约 40k → 16k token),省略标记文本计入预算,避免保险副本吃掉默认上下文保留预算、使总结后上下文几乎不下降。
存储路径加固:conversationId / snapshotId / diffId 统一白名单校验(^[A-Za-z0-9_-]+$,新增 assertSafeStorageId / assertSafeDiffId),覆盖 FileSystemStorageAdapter、UsageIndexStore、DiffStorageManager 与 integrityCheck,从根源拒绝 ..、路径分隔符、盘符与 URI 编码绕过。
根项目与前端锁文件同步(npm audit 均为 0 vulnerabilities,根项目声明 engines.node >=20)。
子代理续跑(continueFromRunId)改为「同一条 run 接着跑」:runId 复用旧 run(Monitor 记录唯一、transcript 一条线连续,不再出现第二条不同身份的记录),身份强制沿用旧 run 的 agent(系统提示/工具集不变,本次调用传入的 agentName 被忽略,旧 agent 已被删除时拒绝续跑),provider 前缀缓存命中条件不变(仍以 lastSentHistory 为请求前缀、conversationId 沿用旧 runId);续跑经 run_resumed 事件标记,前端工具卡 pending 阶段直接沿用 continueFromRunId 关联 Monitor。
apply_diff 字符串处理性能优化:匹配次数统计从 split(search)(大文件 + 短 search 时生成整个分割数组,且无上限)改为 indexOf 循环计数(内存 O(1),新增 100k 上限保护);起始行定位改用单次扫描的 getCharOffsetForLine(消除全量 split('\n') 行数组 + substring 拷贝);匹配行号反算改用 getLineNumberAtIndex(消除 substring + split);normalizeLineEndings 与 diffManager 的 splitLines 双正则合并为 \r\n? 单次扫描。新增 applyDiffToContent 真实实现单测覆盖以上行为。
流式平滑输出:新增 frontend/src/utils/smoothStream.ts(SmoothStreamer 自适应速率蓄水池——chunk 进池后按「每秒放字数 = clamp(积压÷前瞻窗口, 下限, 上限)」匀速放字,积压多自动加速、供应商卡顿时打字渐缓而非冻结)与 frontend/src/stores/chat/smoothStreamManager.ts(每条流式消息一个实例,Map<messageId, SmoothStreamer>,多标签页/subagent 并发流互不干扰,段落切换 thought↔正文/新 part 时先放完上一段积压再重置);真实内容(message.parts/content)照旧在 delta 到达时立即累加,另设显示层 store.smoothTexts(messageId → 当前正在流出段落的平滑文本),MessageItem 流式期间用平滑文本替换最后一个 text/thought 块渲染、终结/中止(complete/cancelled/error/toolIteration/awaitingConfirmation)时先 flush() 放完积压再销毁并切回真实 content,不丢尾巴;commit 按 ~32ms 批量合并 markdown 重渲染;rAF 隐藏时 dt 钳 100ms + 速率自适应 + panic 快进三层兜底;TPS 图与 token 统计仍吃真实 chunk 不经显示层;外观设置新增「流式平滑输出」档位(off=直通 / smooth=灵敏 220ms / balanced=标准 320ms / silky=丝滑 450ms),三语文案同步。
平滑流式与 TPS 审查修复:平滑档位经 state.smoothMode 传递(chatStore watch 设置同步,流式处理不再内联读全局 store);SmoothStreamer.push 按长度预判 panic 先快进再字素分割(超长 chunk 不再先全量分割浪费内存);commit 回调 set 前比较旧值(减少无效响应式通知);移除生产未使用的 end()/ended 分支;非流式消息不再写入平滑层;lineDiff 快速失败条件短路重排(预算不足时不再做公共行扫描)、editDistanceLimit 上限钳制 4096(防 trace O(limit²))、computeLineDiffCached 返回对象文档化为只读共享契约;ToolMessage 去重键改为定长长度前缀编码(与 JSON 语义等价、消除字段分隔符碰撞);MarkdownRenderer 流式 CSS 改 overflow: visible(消除无效的 overflow-y: visible 计算值);三个 diff 面板清理缓存时同步修剪展开状态集合;clearLineDiffCache 接入 MessageList 卸载。TPS 条新增「流活跃」状态机(见 Fixed)、模拟曲线以最近真实速率为基线、稳态均值校准到 ~12 tok/s、主题色每次绘制实时读取、窄面板(≤520px)隐藏 canvas 只留数值、视图隐藏时暂停模拟定时器、tooltip 走三语 i18n。
流式平滑渲染重构(CharFlow 字符流水线,取代「32ms 批量 commit + 180ms 限频 markdown 全量渲染」,解决高 tps 下消息越长越卡的 O(n²) 渲染问题):
新增 frontend/src/utils/charFlow.ts——活动尾块(当前正在流出的 text/thought 段落)由 CharFlow 全权托管:SmoothStreamer 每帧按速率放出字素,批内每个字符以 animation-delay 亚帧错峰淡入(CSS 动画按 vsync 采样,「提交频率与观感解耦」——180Hz 屏接近真·逐字流水,高 tps 下为连绵字符流),播完动画的 chip 每帧回收进单个 settled 文本节点(存活 span ≈ cps×fadeMs 有界),flush/panic 直通定型,支持 prefers-reduced-motion;DOM 全部手动操作,高频路径完全不经过 Vue 响应式链
SmoothStreamer commit 回调改为 (字素数组, 帧时长, instant):删除 commitIntervalMs 批量合并与 pendingCommit(每帧 drain 直接提交),panic 快进/flush 以 instant 直通(跳过淡入);maxCps/lookahead 语义不变
smoothStreamManager 新增显示目标注册表:MessageItem 挂载活动尾块 host 时 registerSmoothDisplay 注册 CharFlow(组件重建/切标签页回来从累计文本 restore 定型),段落切换(thought↔正文/新 part)先 flush 旧段落再注销显示目标(旧段落由 renderBlocks 接管为稳定块);smoothTexts 快照降级为低频(~120ms 节流 + 内容去重 + 段落切换/终结强制),仅用于组件判定与重建恢复
MessageItem/renderBlocks:流式期间最后一个 text 段落(partKey 匹配 + 单 part 块)从渲染块摘出交给 CharFlow;活动 thought 段落保留思维卡片外壳,在折叠预览或展开内容内挂载 CharFlow,流式期间不再反复全量解析 Markdown,折叠态自动跟随最新字符;已完成段落恢复 Markdown 渲染
修复 CharFlow 重构后正文重复:活动尾块 host 插入模板后曾拆断原 v-if/v-else-if 链,导致 parts 渲染与 message.content 兜底同时出现;现将 content 兜底显式限制为“无渲染块且无活动尾块”。摘块行为严格服从 tailInfo,工具调用成为尾部时保留上一段正文;权威 contentSnapshot 会终结旧显示基线。显示目标注册改为同宿主幂等、按宿主安全注销,首个 delta 入队前发布空基线,并补齐 toolsExecuting 与持久化 id 迁移后的终结清理
滚动层无需改动(CustomScrollbar sticky-bottom 已有 rAF 合帧 + 贴底判断)
Added
新增回归测试:getMetadataLight 元数据缓存(写路径回填免读盘 / 深拷贝防污染 / 负缓存 / append 与删除后失效重读,5 例)、usedTokens 单趟逆序语义等价(6 例)。
新增回归测试:行级差分快速失败(无公共行且超预算直接退化 / 预算内不退化且输出与预算耗尽一致)、动态 trace 分配下的预算内精确匹配与回退、computeLineDiffCached 缓存命中(同值复用同一结果对象)/ 键区分(起始行、编辑预算)/ 内容变化重新计算(lineDiff 套件扩展到 14 例)。
新增回归测试:删除生命周期(deleteLifecycle)、总结 Token 统计(summarizeTokenStats)、存储路径安全(storagePathSafety)、被裁剪用户输入预算(preservedUserInputsBudget)、子代理 run 事件总线(subagentRunEventBus)、前端正则护栏(regexGuard)、轨道式完整消息图布局(branchTreeLayout.buildTrackGraphRows:线性单轨道、候选轨道分配与释放复用、分叉线单元、折叠/展开行为)、工具分类分组(toolCategory:分组/归一化/分类名与图标映射)、总结模型透传(summarizeModelOverride:手动总结当前模型 / 独立模型优先 / 独立渠道无模型时不继承主对话模型)、自动总结当前模型透传(nonStreamAutoSummarizeTurn)、上下文管理关闭时手动总结边界(contextTrimBackgroundReceipt)、summarizeContext 处理器模型透传(summarizeContextModelOverride)。
前端启动「开始动画」:新增 frontend/src/components/Splash.vue——Gray logo 线稿(取自 resources/icon.svg)按「帽子先落笔 → 身体/发丝 → 标题字距收拢浮现 → 横线脉冲等待 ready」节奏以 stroke-dashoffset 描线动画呈现,最短展示约 1100ms、ready 后约 0.45s 淡出并通知父组件,支持 prefers-reduced-motion;App.vue 原 loading-container 加载界面替换为 Splash(ready 沿用 languageLoaded,主界面以 v-show 在下方就位避免 pop-in),并清理原 .loading-container 死样式(.spin 旋转动画保留,供自动总结/重试等其它组件使用)。
TPS 实时可视化条:新增 frontend/src/components/input/TpsBar.vue 与前端采样器 frontend/src/utils/tpsMeter.ts(模块级单例)——TPS 条位于聊天 Webview 面板最底部一行(InputArea.bottom-toolbar)、总结上下文按钮左侧,flex 布局为「左侧 TPS 标签 + 中间 240×24 canvas 柱状图 + 右侧实时数值」;流式 chunk 到达时 streamChunkHandlers 按文本长度粗估 token 数调用 tpsMeter.record,采样器 200ms 采样、1s 滑动窗口求瞬时速率、EMA(α≈0.3) 平滑、定长 ring 随采样滚动,柱高按窗口内峰值归一化、颜色跟随 --vscode-charts-blue 主题变量;无真实流(开始动画/空闲等待)时 TPS 条自行随机模拟波动(常态低流量 + 偶发突发 + 均值回归),收到真实流数据后自动切换为真实曲线,让启动与空闲阶段的图表保持活性。
新增测试:SmoothStreamer 单测(flush 同步输出不丢尾巴 / switchPart 段落切换先放上一段 / panic 快进 / dispose 不输出 / 档位 lookahead 有序)与 smoothStreamManager 单测(每消息独立实例 / partKey 切换 flush / 消息间隔离 / 模式变化重建实例);lineDiff 缓存套件扩展(预算 0 与负数退化语义、32 条 FIFO 淘汰、clearLineDiffCache 强制重算);前端全量 403 例通过。
新增修复回归测试:SmoothStreamer tick 路径(fake timers + mock rAF:速率累积 / commitIntervalMs 批量 / dt 钳 100ms / panic 快进 / 积压放完尾巴强制提交)与 manager 基线/模式切换(5+ 例);tpsMeter(fake timers:窗口累计 / 1s 修剪 / EMA 递推 / ring 上限 / live 2s 边界 / events 容量上限 / 退订停表 / 停表状态清理,8 例)与 Splash 状态机(ready 最短展示 / drawDone 门控 / done 单次 / 定时器清理 / reduced-motion 同步完成 / aria,8 例);lineDiff 边界(n+m === limit 不快速失败 / 只读契约守卫 / 预算钳制生效,+3 例);MarkdownRenderer CSS 规则静态断言(流式 max-height: none + overflow: visible / keep-expanded / 规则顺序)。前端全量 439 例通过。
CharFlow 重构配套测试:新增 charFlow 单测(批内错峰 delay / step 钳制 / collapse 回收 / finish 定型 / idle / restore 替换 / instant 直通 / reduced-motion 探测 / followEnd / dispose 清空,12 例);SmoothStreamer 单测重写为 commit 新签名(flush 直通不丢尾巴 / panic instant 快进 / 高帧率 180Hz 模拟逐帧输出 / dt 钳制 / 积压放完停止调度,11 例);smoothStreamManager 扩展(显示目标幂等注册/安全注销/恢复、首帧快照、快照节流与内容去重、段落切换、migrate 键同步迁移、finish 定型保留内容,14 例);新增 MessageItem 正文互斥、工具尾部可见性、thought CharFlow 与 contentSnapshot 基线重置回归测试。前端全量 466 例通过。
You can’t perform that action at this time.