Releases: Komeiji-Shiki/Gray-Code
Releases · Komeiji-Shiki/Gray-Code
Release list
v1.5.1
Added
- 子代理渠道策略:新增逐代理「与当前模型同步」(
syncWithCurrentModel)开关——勾选后该子代理忽略自身固定的渠道/模型,派发前统一改用当前会话渠道与模型(channelConfigId+channelModelId),与 General Worker 继承口径一致,渠道切换(备用 key/新供应商)时无需逐个修改子代理;无活动渠道时拒绝派发并返回明确错误;勾选后渠道/模型下拉禁用并显示激活提示;旧「强制使用当前渠道」全局开关已废弃,启动时自动一次性迁移为逐代理配置(幂等,显式false的代理保持固定渠道),新 UI 不再提供全局入口。 - fast-tavern 子项目:实现 build 模块(H1)——
buildPrompt/buildPromptFromSillyTavern重构(阶段视图/深度注入/worldbook 静态条目排序/视图过滤),替换插值转义(H7)与正则/数值边界加固;TS 与 Python 双实现同步更新。 - 启动预加载渠道设置:新增
frontend/src/services/channelConfigCache.ts预加载缓存模块——App.vue 启动时(开屏动画期间)fire-and-forget 触发preloadChannelConfigs()(幂等、在途请求复用、30s 超时、代际作废、逐条容错、resetChannelConfigsCache 测试隔离);ChannelSettings 挂载命中缓存直接采用、缓存为 null 时同挂载兜底重试,渠道设置页首开延迟被开屏动画隐藏。 - 通知系统-声音提示新增「子代理(SubAgent)提示音独立控制」:事件类型分区为「主代理 / 子代理」两组开关(警告、错误、任务完成、任务失败各四档,互不干扰,旧设置自动回退默认开启);后台子代理任务(taskEvent)、子代理工具状态(streamChunk)、SubAgent Monitor 的 run 完成/失败/重试事件均按子代理开关门控,Monitor 面板补齐窗口焦点推送与音频解锁 hooks,与主窗口同一套「失焦才播」规则。
- 聊天输入框新增高度调整手柄:可向上/向下拖动以扩展超长内容的编辑空间,支持方向键微调,双击或按 Home 恢复按内容自动伸缩;手动高度限制在当前 Webview 可视区域内,并保留内部滚动与光标跟随。
- 关闭开屏动画时新增主题自适应的「石墨蚀刻光场」启动占位:以宿主编辑器背景、侧栏、浮层与前景色变量生成银黑/雾白灰阶渐变,叠加宽幅棱面、椭圆折射层和极淡拉丝纹理;中心光环低频呼吸并轻微偏转,斜向交界的灰银反光周期性掠过,明确表示仍在加载,同时不复刻正式 Splash 的 Logo 演出;不含 logo、文字或传统转圈图标,
prefers-reduced-motion下恢复静态画面。扩展生成 Webview HTML 时同步读取开屏偏好,关闭态从首帧立即显示并持续至主界面初始化结束。
Changed
- plan/design/review 模式现可使用记忆指令(memory_wake/note/recall/compress/zoom/forget/config):三个内置模式的 toolPolicy allowlist 统一追加
MEMORY_TOOL_NAMES,且各自系统提示词模板补充{{$MEMORY}}区块(记忆开关关闭时该区块自动留空,与 code 模式行为一致);ask 模式保持纯问答只读定位,不授予记忆指令。前端「恢复默认模板」的 design/plan 模板同步补充{{$MEMORY}}占位符。 - 移除首次启动自动预置的默认 Gemini 渠道(此前扩展激活时无条件创建
gemini-pro渠道,含占位 API Key,易让用户误以为开箱即用)。现在首次打开显示「无渠道」空态,引导用户新建渠道并填写 API Key;设置页允许删除全部渠道(不再强制「至少保留一个」),删除当前聊天会话正在使用的渠道后自动切换到剩余渠道、删光则回到无渠道空态。 - 切换渠道类型时保留自定义 API URL 与 API Key(API Key 此前已保留;自定义端点如中转站/代理对多种类型通用,无需重写);若旧 URL 只是旧类型的默认端点(用户未自定义),则跟随新类型默认端点,避免残留旧默认值。模型列表、高级选项等类型特有字段仍重置为新类型默认值;相关确认框与提示文案同步更新。
- 移除「工具确认批注」功能:点击工具卡片的确认/拒绝按钮不再读取输入栏内容作为批注——此前输入栏有文字时点击「执行/确认」会把未发送的文字自动作为用户消息发出(插入聊天流、清空输入栏并随
toolConfirmation发送),且前端本地乐观插入的批注消息backendIndex与后端真实索引错位(被拒工具的 functionResponse 插在其前),删除该消息时命中MESSAGE_CHANGED。现在点击确认/拒绝只提交工具决策;用户在有待确认工具时发送消息改为「中断当前回合」语义:App.vue handleSend先cancelStreamAndRejectTools(拒绝待确认工具、本地与后端同步插入 functionResponse 占位、结束当前回合),再走正常sendMessage把文字作为新回合发出,不再有本地索引猜测。后端同步移除annotation/annotationMessageId契约字段。
v1.4.6-nightly.20260810
自动构建:2026-08-10 03:42 UTC
Commit: fc34ff0efa317e69d7e8a257f664ed8e7b2a486d
版本:v1.4.6-nightly.20260810
注意:nightly 为每日自动构建(预览版),仅供测试,不建议作为正式版本安装。
v1.4.6
[1.4.6] - 2026-08-08
Added
- 后台任务回执「完成即插入」(排队消息提前投递的 P2 增强):后台子代理 / 后台命令完成时,回执不再硬等模型回合完整结束——LLM 执行完当前动作(非终结 toolIteration,工具结果已全部落盘)且无排队消息可投时,动作边界立即投递回执(
backgroundTaskStore.flushReportsAfterAction,与排队消息提前投递同构:cancelStream({preserveSubAgents:true})替换当前回合 + 新chatStream,H1 写序保证旧流完全退出后才写入新消息);队列非空时排队消息优先,回执等下一动作边界或回合结束补发。安全护栏复用既有语义:跨会话跳过(只投递归属当前会话的任务)、投递窗口(cancelStream 往返)内会话切换 / 并发发送者抢先开新流时放弃投递并回滚 reported 等待补发、发送失败回滚 reported 不静默丢失、queueAfterActionDraining防动作边界重入。新增backgroundReportEarlyEmit.test.ts(16 用例:忙时替换回合投递回执、无任务/已回流/运行中不投递、跨会话跳过、投递窗口会话切换、并发发送者抢先、发送失败回滚、重入防护、队列空编排转投回执、排队消息优先、动作边界触发编排、flushReports 持锁跳过、sendMessage false 回滚、迟到调度直投、编排窗口会话切换、失败重试恢复链)。 - 新增「手动创建存档点」:检查点此前完全由 AI 工具执行时自动创建(受 enabled 开关与工具/消息类型配置过滤),用户没有主动存档入口——AI 做了一系列改动后想回档检查点 / 切分支时,无法先保存当前状态(用户自己手动改过的文件更是从未被存档保护)。现输入区底部工具栏新增存档按钮(codicon-save,BranchTreePanel 旁):后端
CheckpointManager.createCheckpoint支持forceCreate(跳过 enabled 开关与工具/消息类型过滤,无条件创建;仍尊重排除规则——自定义忽略 / 默认类别 / 文件大小上限等安全边界不变),新 webview 消息checkpoint.createManual把存档绑定到当前最后一条消息(恢复时「回档到该消息前」= 回到现在)并绑定当前分支活跃尾节点(BCP-02,分支切换 chat-and-workspace 切走再切回也能恢复,往返无损);前端createManualCheckpointaction + chatStore 接线 + 三语 i18n(按钮提示 / 创建成功 / 失败)。新增测试:CheckpointManager forceCreate 无条件创建(enabled=false 且未配置工具时普通调用仍跳过)+ 手动存档可恢复工作区文件(核心价值);checkpointActions 成功入列 / 后端拒绝 / 无会话短路 / IPC 异常兜底(4 用例)。 - 思考强度档位扩展:OpenAI / OpenAI Responses 渠道在 xhigh 之上新增 max、ultra 档位,Anthropic 渠道在 max 之上新增 ultra 档位;三渠道统一新增「自定义 (custom)」档位——选中后出现输入框,用户可手动输入任意 effort 值(如 max、ultra),请求发送时由 formatter 将 custom 解析为
effortCustom字段的值原样透传(空值回退为不发送);配置类型effort枚举同步扩展并新增effortCustom字段;三语 i18n 新增档位文案与输入框占位提示。 - 消息左下角统计新增首字延迟(TTFT)显示:后端
StreamAccumulator基于请求开始时间与首个流式块到达时间计算 TTFT(content.ttft,随消息 metadata 下发),前端每条模型消息的统计区展示「首字 x.x s」;Token 速率计算同步剥离首字等待窗口——速率分母从完整响应耗时改为「响应耗时 − TTFT」,只反映生成阶段吞吐,不再被首字等待拉低(旧数据无 ttft 字段时退化为原分母,历史展示不变);三语 i18n 新增文案。
Changed
- 完成 bug-hunt round 1 的前端与 Webview 稳定性收敛:消息处理器统一补齐入参校验、异常边界和请求路由清理;
HandlerContext.streamAbortControllers收敛为真实StreamAbortManager契约,移除旧 Map 鸭子类型分支;设置导出键提取为共享常量,子代理数值参数增加有界校验。 - 弹层组件(Modal / Drawer / ConfirmDialog)改用引用计数的 body 滚动锁,支持多弹层叠加,并补齐 dialog 语义、焦点陷阱、Esc 关闭和焦点恢复;会话历史与标签页增加键盘操作和 ARIA 状态。
- 界面语言选项按当前语言本地化显示并同步页面
lang属性;移除重复注册的废弃toggle_skills前端工具实现,历史消息继续由read_skill兼容渲染。 - 前端公共工具增强:
debounce.cancel、throttletrailing 调用、Date/Map/Set 空值判断、Firefox 兼容的延迟 Object URL 回收;流式平滑输出统一按 Unicode 字素计数,避免拆分 emoji 等组合字符。 - 总结保留预算
keepRecentTokens的百分比基数从「主对话模型上下文窗口」改为「本次总结规划范围内的活跃历史 token 总量」(上一次总结之后、未被isSummarized覆盖的消息):'50%'即「截断一半、保留另一半」,与模型窗口大小无关;内置默认值从'25%'调整为'50%'(截断一半);绝对 token 数配置(如30000)语义不变。修复单次对话总结后上下文几乎被压光的问题(如 369928 token 总结后只剩约 30000 预算 + 首条用户消息,而非历史的一半)。 - Release notes 生成策略调整(scripts/extract-release-notes.mjs):默认只携带当前版本的 CHANGELOG 小节;脚本通过
GITHUB_TOKEN查询 GitHub 最新已发布 release,检测到当前版本与最新 release 之间存在未发布小节(版本被跳过,如最新 release 为 1.4.4 时发布 1.4.6,中间 1.4.5 从未发布)时自动补带这些跳过版本的内容,避免用户错过未发布版本;查询失败 / 无 token 时回退为只带当前版本(不阻塞发布)。
Fixed
- 修复 Webview 消息路由与流式任务异常路径:阻塞 handler 返回但未响应、流式 handler 抛错、未知 clientId 回退等场景不再泄漏请求映射或错投其他面板;流式错误统一回传并清理状态。
- 修复分支与流控制竞态:分支切换在真正切图前再次检查活跃流,
StreamAbortManager.waitForIdle超时后正确释放退休链等待者;无 content 的终结性toolIteration也会调度排队消息,避免消息永久滞留。 - 修复异步界面操作的未处理异常:分支切换/删除/恢复、checkpoint 回档、渠道与模型切换、排队发送、历史页与用量页打开会话等失败时给出可见提示,已成功的主操作不再因派生元数据刷新失败而误报失败。
- 修复渠道与设置边界:Gemini 默认配置幂等初始化,新建渠道仍可仅传类型与名称并由后端补齐默认值;MCP env/headers 非法 JSON 不再静默丢弃,数字输入空值或非有限值不再保存为 0;设置导出默认路径与 reload 响应时序得到修正。
- 修复上下文与附件处理:上下文标签属性/正文正确转义和还原引号、尖括号与闭合标签;文本、图片和 base64 附件增加读取前大小限制;临时预览使用唯一文件名并定时清理;FileReader、canvas、视频缩略图和附件取消等异常路径补齐。
- 修复多项前端可用性问题:回复查看器仅在数据存在时渲染;删除会话改为确认后执行;内部删除/关闭按钮的键盘事件不再误触父级选择;多弹层、后台任务监听、diff 倒计时和文件跳转高亮资源在卸载时正确释放。
- 修复
update_plan接收 schema 外遗留字段的问题,运行时现在明确拒绝 continuation/source-artifact carry-over 参数;修复 checkpoint 配置失败响应缺少错误对象时的二次异常。 - 修复子代理执行任意工具必然报错「Cannot read properties of undefined (reading 'getToolRejectionReason')」:P1 安全加固(子代理危险工具确认门)把
toolNeedsConfirmation解构为独立函数后调用,该实例方法内部依赖this(真实实现调用this.getToolRejectionReason),解构调用丢失绑定直接 TypeError,子代理的确认门判定完全不可用。现改为经 service 实例bind调用(行为与主链路一致,确认门恢复生效),fail-closed 兜底保留(确认门缺失时仍拒绝执行)。新增回归测试subagentToolConfirmation.test.ts「确认门方法依赖 this(真实 ToolExecutionService 形态):不因解构丢失绑定而 TypeError」——用真实依赖 this 的类方法形态复现,断言拒绝原因正常回流且底层工具未执行。 - 修复总结截断起始点在长对话中难以定位:滚动条 marker 选择器从
.user-message扩展为.user-message, .summarize-divider,已总结 / 未总结分隔线在右侧滚动条上显示黄色 marker(区别于用户消息的蓝色 marker,点击可跳转),悬停 tooltip 显示专属前缀与「此线以下为发送给 AI 的活跃内容」说明(CustomScrollbarmarker 新增data-marker-color/data-marker-tooltip-prefix元素级覆盖,缺省回落全局 props);三语 i18n 新增文案。 - 修复手动总结单轮对话(历史中仅一个真实用户回合)必然失败报「对话历史在总结期间发生变化,本次总结的范围已失效」:单轮时总结范围规划走轮内截断(intra_round),切点必然位于轮首 user 消息之后,
insertIndex恒大于最后一条真实用户消息下标 →markAndInsertSummarizedAtomically一律判STALE_RANGE放弃落盘。现手动总结对「整个历史仅一条真实用户消息」放行(用户主动总结就是把这一轮的前半部分拿去总结,不存在「当前回合」需要保护);首条用户消息保护仍生效(锚点不标记、原样保留并持续发送,且总结模型输入始终包含首条用户消息);自动总结保持严格 STALE(回合内吞掉当前用户消息会毁掉回复上下文);越界(并发删除把历史缩短到区间之外)与多轮场景同样保持 STALE。新增summarizeManualSingleRound.test.ts(5 用例:单超大轮轮内截断成功、总结期间历史并发变长仍成功、并发缩短越界仍 STALE、多轮范围覆盖第二轮仍 STALE、多轮正常路径不回归)。 - 修复编辑用户消息保存后候选切换器(‹ 2/2 ›)不立即显示,关掉对话重新打开才恢复:编辑 / reroll 分支流的候选节点在流开始时就已落盘(
editCandidate/createRerollCandidate先于工具循环),但前端分支图刷新此前只挂在终结 chunk(complete / error / cancelled / awaitingConfirmation / 终结性 toolIteration)上——流未结束时 BranchSwitcherBar 永远不刷新(与已修复的「停在工具确认不显示」同类,覆盖流进行中的任何阶段)。现streamHandler在分支流第一个输出 chunk 到达时提前刷新一次分支图(此时候选必然已落盘,切换器立即显示;按 streamId 隔离只刷一次),终结时仍消费标记再刷新一次(更新模型候选内容 / 摘要,支持同一会话连续编辑 / 重 roll);会话隔离与既有终结刷新一致(标记属于发起会话,不跨会话刷新)。新增/更新测试:editBranchRefresh.test.ts 首输出提前刷新 + 终结再刷新、连续编辑再次触发(streamId 重置)、会话不匹配不提前刷新(3 用例);streamHandlerTerminalCleanup.test.ts 非终结 toolIteration 提前刷新但不消费标记(断言对齐新语义)。
Performance
- 工作区多路径解析改为并行处理;分支切换器滚动/缩放定位由 rAF 合并布局计算;工具消息预览改为精确监听增量长度,减少高频流式更新中的无效深度监听。
- 文件与 Usage 热路径增加资源上限:读取前按 10MB 文本 / 50MB 附件限制拒绝超大输入,base64 在解码前预判;Usage 缓存增加 TTL 清理与 32 条容量淘汰;Skills 配置仅在启用状态实际变化时写盘和刷新工具声明。
- Webview 工作区搜索与路径判断优化:工作区归属改用
getWorkspaceFolder精确匹配,目录搜索避免对明显无关路径做深层遍历;临时预览文件自动回收。
Security
- 子代理不再绕过危险工具确认(P1):主链路对
delete_file/execute_command等被用户配置为「需确认」的工具的确认门(toolNeedsConfirmation,与isToolAutoExec设置同源)此前只在主会话的两个循环控制器生效,子代理(subagent)独立工具循环直接调用共享执行器、绕过了确认门;现子代理执行工具前同样查询确认门——需要确认的工具直接拒绝并把明确原因(「Ask the main model to perform this action」)以 functionResponse 回给子模型,共享执行服务缺少确认门时 fail-closed 拒绝(不静默放行);自动执行(autoExec)与 diff 审阅类工具不受影响。新增subagentToolConfirmation.test.ts(拒绝含原因回流、放行、fail-closed 三用例)。 - 会话写锁挂起超时不再放行并发写(P1):
ConversationManager.withConversationWriteLock、分段历史写队列、元数据写链(storage.ts)与用量索引写队列(UsageIndexStore)此前在挂起超时后让队列链继续前进,超时后的底层文件操作仍在后台运行——新写入任务并发启动会互相覆盖/删除同一会话的段文件、索引与元数据(历史损坏);现队列链尾挂在底层任务(underlying)上:超时只让调用方 fail-fast,链不前进,后续写必须等旧任务真正结束;挂起超时同时改为从任务真正启动时开始计时(排队等待不计入,慢而健康的写入不再被误报)。新增writeChainHangTimeout.test.ts(链不前进 + fail-fast + 正常串行)并更新UsageIndexStore.test.ts挂起语义用例。 - 流式响应缓冲加入大小上限(P1):流式解析无法识别上游格式(非 SSE/JSON)时
parseStreamBuffer把整段缓冲保留为 remaining,代理与原生 fetch 两条分支的缓冲逐轮累积且无上限,异常上游持续吐垃圾数据会造成 Extension Host 内存耗尽;现仅在「解析无进展」时按 64MB 上限终止(PARSE_ERROR,不可重试),合法巨型单事件(多模态 base64 附件等)不受影响。新增streamSecurity.test.ts超限终止 + 合法巨型事件不误杀两用例。 - 检查点双文件提交配对一致性(P2):
files.json与manifest.json两次独立 rename 无法整体原子,崩溃发生在两次提交之间时磁盘会出现「新 files.json + 旧 manifest.json」的混合配对且读取侧无法识别;现每次提交生成随机filesRevision同时写入两个文件(读取校验配对、混合配对被拒绝),写新 files.json 前旧配对被暂存为files.json.prev(崩溃后读取路径自动恢复 manifest 对应的完整配对,不误报数据丢失);files.json.prev同步纳入目录遍历/大小统计/恢复路径的元数据跳过清单。新增 CheckpointManifestRepository ATOMIC-PAIR 测试(配对绑定、两崩溃窗口恢复、无备份孤儿拒绝、损坏 files.json 不裸抛、filesRevision 类型守卫)。 - 子代理无可用工具时不再向模型声明全部工具(P2):空工具集此前被转成
undefined,ChannelManager 把 undefined 当作「未指定覆盖」回退成渠道全量工具声明——模型反复调用不可用工具形成失败循环;现空数组原样透传,各 formatter 只在工具列表非空时注入声明。 - 流式请求补上渠道配置验证(P2):
generateStream此前跳过formatter.validateConfig(非流式路径有),无效 API Key / URL / 模型配置不提前拦截而表现为网络/鉴权/解析错误并空耗重试;现与非流式路径一致在发起请求前校验(VALIDATION_ERROR 提前失败)。 - 纯文本上游错误正文不再丢失(P2):
executeStreamRequest原生分支、proxyFetch.proxyStreamFetch无代理分支与非流式executeRequest此前先response.json()(消费响应体)失败后再读response.text()只能拿到空串——网关 502 HTML / 纯文本错误体丢失;现统一改为先读text()再尝试JSON.parse,真实错误正文进入错误信息。新增proxyFetchErrorBody.test.ts与streamSecurity.test.ts错误体用例。 - 多模态流不再被误判为空响应(P2):流式内容检测
streamChunkHasContent只认 text/functionCall,GeminiinlineData/fileData附件流在连接中断时被误判为空响应触发整条流重播(附件重复、重复计费);现与非流式isResponseContentEmpty同一口径纳入多模态字段;前端messageActions/toolActions/streamChunkHandlers的空消息清理判定同步补齐。新增streamSecurity.test.ts多模态用例。 - 子代理请求级上下文裁剪(P2):子代理未接主链路 ContextTrimService,history 只增不减,长任务直接撞模型上下文上限失败;现发送前按渠道
maxContextTokens(缺省 128000)× 0.8 做请求级裁剪——超预算时从最旧开始整轮丢弃(functionCall/functionResponse 配对整体移除不产生孤儿,首条任务消息与末尾两轮保留),仍超预算时对超大字符串截断并标记(结构与 provider JSON 兼容),估算含 1.5× 安全系数并与多模态 part 折算对齐;裁剪不修改 run 内原 history,lastSentHistory同步记录裁剪结果保证续跑前缀一致。新增subagentContextTrim.test.ts(零开销原引用、整轮丢弃保配对、首条/末尾保留、超大文本/工具结果截断且不改原史、预算折算)。
v1.4.5
[1.4.5] - 2026-08-07
Added
- 渠道设置支持更改已存在渠道的渠道类型:编辑表单中「渠道类型」由只读徽章改为可选下拉框(Gemini / OpenAI Compatible / OpenAI Responses / Anthropic 互转),切换前弹三语确认框提示(明示类型特有参数将重置);后端
updateConfig放开 type 字段——类型变更时以新类型默认配置为基底重建,仅保留跨类型通用字段(名称、API Key、超时、重试、自定义标头/Body、上下文管理、Token 计数等),类型特有字段(API URL、模型列表、当前模型、高级选项、useAuthorizationHeader 等)重置为新类型默认值,避免旧类型字段残留(如 Gemini thinkingConfig 残留到 Anthropic 配置)污染请求;createConfig/updateConfig新增运行时渠道类型校验(非法 type 直接拒绝,不再落入 default 分支产生无 url 的死配置);显式传入的更新字段优先级最高;设置导入覆盖路径同步获得类型变更能力;若变更的是当前激活渠道,前端同时清空会话级模型覆盖(selectedModelId),避免残留旧类型模型 ID 被当作显式模型发送。新增ConfigManager.updateConfig.test.ts回归测试(11 用例:类型可改且 ID/createdAt 不变、类型特有字段重置、通用字段保留、显式覆盖、互转默认值、普通更新不回归、同类型不触发重建、配置不存在报错、非法 type 拒绝(更新/创建)、openai 特有字段重置)。渠道类型运行时校验常量CHANNEL_TYPES与ChannelType类型定义同源(configs/base.ts),新增渠道类型时类型与守卫同步维护。 - GitHub Releases 自动更新:扩展启动后延迟 10s 检查
Komeiji-Shiki/Gray-Code最新 Release(距上次检查不足 24 小时跳过,时间戳存 globalState;设置页「立即检查」忽略节流),有新版本时前端弹窗展示 Release 说明,用户确认后自动下载 vsix 并调用workbench.extensions.installExtension安装、提示 reload 窗口生效;设置页「通用」新增「自动更新」区块(启用开关 + 立即检查 + 一键更新按钮——一键更新自动完成「检查 → 下载 vsix → 安装」,安装后提示重启窗口即可生效);请求复用渠道代理配置(createProxyFetch),版本检查超时 10s / 下载 120s,失败静默不打扰;新增checkForUpdates设置项(默认 true,可关闭,随 Settings Sync);三语 i18n + 设置搜索索引;新增 webview 消息getUpdateStatus/checkUpdateNow/installUpdate/updateNow/openUpdatePage与UpdateHandlers(updateNow为检查安装一条龙);后端新增UpdateChecker模块(版本比较 / 节流判断 / API 响应解析为纯函数,update状态机覆盖 disabled / idle / checking / upToDate / updateAvailable / error)及 33 个单元测试(含下载安装 mock、handler 安装/重启流程)。 - GitHub Actions 发布流程
.github/workflows/release.yml:推送v*tag 时自动npm ci+ 构建 +vsce package生成graycode-<tag>.vsix并发布到 GitHub Releases(自动生成 release notes),替代手动打包上传,为自动更新提供稳定 vsix 资产。 - 提示词预设(prompt entries)的 assistant 条目新增「伪造思考过程」(fakeThought):可额外配置一段伪造的 AI 思考内容,组装请求时以 thought part(thought: true)附加在临时 assistant 消息正文之前,模拟一轮带推理过程的回复;是否随请求回传由渠道「发送历史思考内容」(sendHistoryThoughts)开关决定——显式关闭时不回传(剥离 thought part、正文照发),与真实历史思考语义一致;过滤在发送侧执行(
applyPromptContextThoughtPolicy),不写入 turnDynamicContext 缓存(同一回合缓存可能被不同渠道复用)。 - 渠道设置「当前轮次回传配置」与「历史回合回传配置」合并为单一「思考回传配置」区块(内部按当前轮次/历史回合分组,控件与默认值不变),三语 i18n 同步(
common.thinkingBackfill,渠道级覆盖键迁移为thinkingBackfill.*)。
Changed
- 排队消息提前投递(P1):排队消息不再等待整个 LLM 回合完整结束才发出——前端在「非终结 toolIteration」边界(后端已把当前动作批次的工具结果
settleFunctionResponses/addContent全部落盘,动作彻底结束)自动取出下一条排队消息,按与「立即发送」相同的方式替换当前回合(cancelStream({preserveSubAgents: true})+ 新chatStream);后端 H1 写序保证(webview 层awaitOldStreamCompletion+ 后端waitForOldStreamExit)确保旧流完全退出后才写入新用户消息,插入点之前的完整历史保持原样、不丢序;每执行完一个动作投递一条,剩余排队消息在回合结束时照常投递;发送失败自动放回队首,不静默丢失;跨会话消息跳过逻辑与processQueue一致;终结性 toolIteration(审批门闸/工具取消)与 awaitingConfirmation 阶段不触发,保持原等待语义。新增queuedMessageEarlyEmit.test.ts(12 用例:streamHandler hook 接线 5 + 投递行为 7,含重入保护、跨会话跳过、失败回队首、投递窗口会话切换与并发发送者防护)。processQueue与processQueueAfterAction的「取当前会话下一条消息」逻辑提取为公共函数takeNextForConversation(跨会话跳过语义单一实现)。
Fixed
- 修复编辑消息、删除消息或重试截断历史后误报
VALIDATION_ERROR: Invalid tool history: orphan_function_call:共享 transcript 删除逻辑现在会识别“functionResponse 被本次删除、对应 functionCall 仍保留”的配对断裂,并在同一次仓储变更中把调用标记为 rejected(不再伪造“用户拒绝执行此工具”响应);deleteMessagesInRange、deleteToMessage/truncateFrom与单条逻辑删除统一继承。settleFunctionResponses同步加固:迟到真实结果仅写回当前历史仍存在的调用,落盘后清除 rejected;调用所属旧分支已被截断时丢弃迟到响应,避免反向制造orphan_function_response。新增orphanFunctionCallRepair.test.ts覆盖编辑分支复现、截断/区间/单条删除、并行调用与结算时序。 - 修复后台任务回执(
[Background task completed])加载旧对话时显示为普通用户消息:StreamRequestHandler.handleChatStream解构前端chatStream请求时漏透传source字段,后端落盘时request.source为 undefined,回执消息的source='background_task'从未写入历史——当前会话靠前端内存正常显示,重新加载对话后渲染成完整正文的用户消息(占地超大且无折叠卡片);现补上source透传(新数据落盘即带标记),并在getMessagesPaged/getMessages返回路径对历史遗留的「缺 source 且以[Background task completed]前缀开头的用户消息」做展示层归一化补source='background_task'(只补内存不写盘,避免重写历史文件);新增ensureBackgroundTaskSourceForDisplay单元测试(缺 source 补标记 / 已有 source 不覆盖 / 普通消息与 functionResponse 不误判 / 无 parts 安全跳过)。 - 渠道设置「启用此配置」开关移至表单顶部:此前该开关位于配置表单最底部,用户进入设置时下意识以为没有启用功能;现置于 API URL 之前(配置选择器/新建按钮正下方),一眼可见,
data-search-anchor="channel-enabled"搜索锚点保留。 - 修复
memory_config只读调用在工作区记忆目录尚未初始化时误报「workspace URI could not be resolved」:此前纯读走createIfMissing=false,工作区目录不存在时返回 null,被笼统报成 URI 解析失败;现区分「URI 不可解析」与「工作区记忆目录未初始化」两种失败——前者才报解析错误,后者纯读时回退显示全局配置并标注workspaceNotInitialized(保持无磁盘副作用,不创建目录),带更新参数时仍正常创建目录并写工作区独立配置;memory_zoom只读调用同样区分两种失败,工作区未初始化时改报明确的Workspace memory is not initialized for this workspace;新增memoryConfigTool.test.ts回归测试(6 用例:无工作区读全局、工作区独立配置隔离、未初始化纯读回退标注且无副作用、未初始化带更新参数建目录、URI 不可解析报错、全局未初始化报错)。 - 修复 VSCode 窗口聚焦时仍播放任务完成/错误提示音:音效控制器
handleSoundEvent此前只在文档隐藏(窗口最小化/切走)时聚合不播,窗口聚焦时无论焦点在哪都直接播放;现由扩展侧监听vscode.window.onDidChangeWindowState把窗口焦点状态(windowFocusChanged命令)推送到前端,音效按窗口焦点分级——VSCode 窗口聚焦(用户看得见界面、事件结果已可见)不播,窗口失焦(切到其他应用)时照常播放提醒;文档隐藏期间聚合的事件在恢复可见时仍补播一次。新增soundEventController.test.ts(7 用例:默认聚焦不播、聚焦不播、失焦播放、失焦后聚焦不播、隐藏聚合后恢复补播、visibilitychange 集成、事件过期丢弃)。 - 修复流式输出自动滚动吸底的拉回与丢吸底问题:① 正文主滚动容器(CustomScrollbar sticky-bottom)此前
wasAtBottom在 scroll 事件的 rAF 回调里才更新,滞后一帧——流式期间 MutationObserver 驱动的贴底写入读到陈旧状态,把刚向上滚动的用户拉回底部(「使劲滚才能滚上去」);现 scroll 事件同步更新吸底状态,用户滚动意图立即生效。② 贴底写入后立即用实时 scrollHeight 复验,大段输出/md 异步解析会让 scrollHeight 在写入后继续增长,误判「用户滚离」→ 永久丢吸底;现程序贴底写入记录目标 scrollTop(programmaticScrollTop),其触发的 scroll 事件按写入值比对识别为程序行为、保持吸底状态,吸底状态只由用户滚动改变。③ 思维链中展开(MessageRenderBlock)shouldStickBottom按scrollHeight - scrollTop - clientHeight复验,用户滚回底部后内容大段增长(scrollTop 未变、scrollHeight 变大)同样误判丢吸底;现改用 scrollTop 变化检测——scrollTop 未变 = 用户没动,内容增长不改变吸底意图。④ promote 后的 nextTick 贴底校正增加当前位置复验,用户刚滚离(scroll 事件滞后)不再被拉回。新增CustomScrollbarSticky.test.ts(3 用例:底部增长贴底、滚离不打扰、写入后增长不丢吸底)与 MessageRenderBlock 中展开增长不丢吸底回归测试。 - 修复高 tps/高刷新率下流式输出「使劲滚才能滚上去」与代码块渲染后丢吸底:① 高 tps 下内容增长会抵消滚动距离(滚 100px 内容长 80px),且 scroll 事件异步派发滞后于 rAF 贴底写入——用户滚动后同一帧的贴底写入先把 scrollTop 拉回、随后派发的 scroll 事件又被
programmaticScrollTop比对误判为程序行为,用户每帧都被拉回底部;现监听wheel/触摸板输入事件(输入处理阶段同步派发、早于 scroll 事件与 rAF,程序写入 scrollTop 不会触发)标记 250ms 冷静期,期间不执行贴底跟随,让用户滚动真正生效;滚动条拖动(handleThumbMouseDown)同样标记冷静期;中展开(MessageRenderBlock)同步加@wheel冷静期短路,重新进入中展开时重置。② 代码块 fence 闭合后遇空行触发渐进 markdown promote,程序贴底写入(CharFlowscrollToEnd/ promote 后 nextTick 校正)改变了 scrollTop 但未同步记录,紧随其后的代码块异步渲染(hljs 高亮)让 scrollHeight 骤增——中展开的 scrollTop 变化检测把程序写入误判为「用户滚动」→ 位置复验按涨量判定「不在底部」→ 丢吸底;现shouldStickBottom返回贴底前用微任务读回写入后的实际 scrollTop(浏览器对 scrollTop 赋值有钳制,读回最准),promote 校正写入后同步记录,程序写入不再触发变化检测误判。新增测试:CustomScrollbarSticky 冷静期 2 用例(wheel 后不拉回、冷静期过后恢复贴底)、MessageRenderBlock wheel 抵消滚动距离 1 用例 + 贴底写入后代码块异步渲染高度骤增不丢吸底 1 用例。 - 修复设置页「保存提示词」误报保存失败(实际已保存):webview 消息处理走串行队列(
messageHandlingQueue),countSystemPromptTokens(token 计数调用渠道 API)、tokenizer.getResource(首次下载词表,分钟级)、exportPromptModes/settings.export/settings.import/storagePath.selectFolder(showSaveDialog/showOpenDialog 模态对话框,打开期间 handler 一直 await)、storagePath.getStats(大目录统计)等慢 handler 会长期占住队列——期间用户点保存,savePromptMode排队超过前端 180s 超时被误报「保存失败」,而队列轮到时后端实际保存成功;现将上述类型移入NON_BLOCKING_MESSAGE_TYPES(fire-and-forget,handler 内部 sendResponse 仍正常路由回发起方),并同步加入前端UNBOUNDED_REQUEST_TYPES超时豁免(对话框/下载/导入本身不再超时误报);前端saveConfig保存成功后的 token 计数改为不阻塞保存成功反馈(void countTokens())。新增messageRouterNonBlockingBehavior.test.ts(慢 handler 不阻塞后续消息 + 普通 handler 阻塞对照组)与promptSaveChain.test.ts(Vue reactive Proxy 数据保存链路回归:序列化、postMessage、响应路由全链路)。 - 修复设置保存「每次报失败但数据实际已写入」的根因:
VSCodeSettingsStorage的SYNCABLE_KEYS含checkForUpdates,但 package.json 的contributes.configuration未声明graycode.checkForUpdates——VS Code 对未注册配置键调用config.update直接 reject;保存时Promise.all并发写全部变更键,已注册键(如 toolsConfig)先成功落盘、未注册键(checkForUpdates,默认值 true 且从未写入过、快照恒为空)抛错,整体 save 失败——前端报「保存失败」但提示词已写入 settings.json(重启后仍在),且每次保存必然触发。现补上graycode.checkForUpdates声明(type: boolean, default: true);新增vscodeSettingsStorageRegisteredKeys.test.ts防回归——断言ALL_CONFIG_KEYS每个键都已注册(ALL_CONFIG_KEYS改为导出)。 - 修复编辑首条(根)用户消息后会话「无论如何都不发消息」:编辑根节点时前端自动降级 keep(原地保存),但
editAndRetry仍进入流式等待状态(设置isStreaming/isWaitingForResponse)且依赖后端 complete 事件复位——keep 模式后端不重新生成,一旦 complete 丢失(视图重建/IPC 抖动/后端异常)状态永久残留,sendMessage会把后续所有新消息拦截成deliverInterruptMessage(投递到无人消费的 inbox),表现为停止/重试/重新保存全部失效。现 keep 模式不进入流式等待状态(不设isStreaming/isWaitingForResponse/streamingMessageId,activeStreamId保留用于 error chunk 路由),replayBranchStreamAfterError的 keep 重放同步处理;后端 keep 分支 complete 改为不带 content(此前携带主历史最后一条消息,可能是 user 角色——前端残留占位时会把 user 内容替换进 assistant 消息,ChatStreamCompleteData.content改为可选,与前端resetTerminalStreamState的「无 content 终结 chunk」协议一致);编辑对话框对首条消息显示提示并禁用「保存」(branch)按钮(仅保留「原地保存」),消除「保存后应重新生成」的误解。新增/更新测试:keep 模式不进入流式等待状态断言、complete 无 content 路径回归。 - 修复代码块渲染后无法复制(复制按钮被净化移除):
sanitizeHtml的危险元素黑名单包含button,会把 Markdown fence 渲染器生成的代码块工具栏复制/换行按钮一并移除——默认渲染路径(AI 消息正文)下代码块只有标题栏没有复制按钮,用户无法直接复制代码(测试此前只在 artifactSafe 路径断言按钮存在,default 路径被净化后一直缺失)。现 sanitize 对 class 受控的工具栏按钮(code-tool-btn,仅 fence 渲染器产出)放行,其余button照旧移除,on*/style 等危险属性剥离逻辑不受影响;复制执行同时加固——navigator.clipboard不可用(VSCode Webview 非 secure context)或写入被拒时回退 textarea +document.execCommand('copy'),失败给按钮短暂红色反馈(不再静默 console.error)。新增测试:default 路径复制按钮保留 + data-code 可解码、copyToClipboard 兜底链(clipboard 缺失/抛错/双失败/选区恢复,5 用例)。 - 修复首条(根)用户消息无法「保存并重新发送」:此前根节点无父节点可挂编辑候选(BranchGraph 单根模型),编辑对话框「保存」按钮被禁用、store 层 branch 自动降级为 keep(只改文本不重新生成)、后端
resolveEditTargetNode直接拒绝根节点 branch 模式——用户编辑首条消息后无法让 AI 按新问题重新作答。现整条链路支持根节点编辑重生成(TREE-03-R):后端 branch 模式对根节点放行,执行「原地改写根节点文本 + 截断其后主历史(旧消息已归档进分支图 sidecar)+ 新建模型候选重新生成」,旧回答保留为可切换候选(与 reroll 同语义),isFirstMessage动态判断(根节点编辑后刷新系统提示词);前端editAndRetry/restoreAndEdit不再对根节点降级 keep,branch 模式原样透传(截断窗口 + 流式占位 + 分支图刷新标记),「原地保存(keep)」仍由编辑对话框显式选择;编辑对话框「保存」按钮对首条消息恢复可用(title 提示保存将重新生成后续回复),三语 i18n 更新。新增/更新测试:resolveEditTargetNode 根节点 branch 放行(图/线性模式)、根节点编辑重生成编排(改写 + 截断 + 候选 + finishReroll 回填 + 旧回答切回)、前端根节点 branch 流式流程。 - 修复「伪造思考过程」(fakeThought)内容重启后丢失:前端
PromptSettings.vue的normalizePromptEntries重建条目对象时只保留 id/name/type/enabled/role/content/order,fakeThought字段在加载(loadModeConfig)...
v1.4.3
Added
- 新增长期使用时间统计(
backend/modules/activity):ActivityTracker 以「60 秒心跳 + 用户活动事件」采集 IDE 活跃时间(监听编辑/光标/滚动/切换编辑器/终端/窗口聚焦,连续 5 分钟无活动或失焦即暂停,过滤挂机),采样按天落盘至<dataPath>/activity/YYYY-MM-DD.json(串行队列防并发覆盖,原子写入防损坏);统计层提供每日使用时长与活跃会话、24 小时作息热力、当前连续工作时长(间隔 ≤15 分钟视为同一会话,跨天拼接不腰斩)。 - AI 工作期间同样记为活跃:模型流式生成(
StreamChunkProcessorchunk 打点)、工具执行(ToolExecutionService.runSingleToolCallbegin/end 引用计数)、子代理生成(SubAgentExecutor流式循环打点)与后台任务事件(TaskManager事件兜底)都会刷新活跃状态——主人在看 AI 输出时长时间不操作编辑器不会被误判为离开,AI 工作中窗口失焦(后台跑任务)也不暂停统计。 - 新增 AI 工具
get_activity_stats:AI 可查询用户每日使用时长、最近作息(可选 24h 热力)与连续工作时长,返回本地时间字符串;数据仅含时间戳不含用户内容。 - 用量统计页新增「使用时间」区块(
UsageTimeSection.vue):今日已用/当前连续工作/近 7 天合计总览卡片 + 每日使用时长条形图 + 近 7 天 × 24 小时作息热力网格(悬停查看详情);新消息处理器activity.getStats(30 秒结果缓存,force 绕过)。 StoragePathManager存储目录列表新增activity(随迁移/清理/统计联动);工具分类新增「使用时间」(codicon-watch)并补齐三语 i18n。- 消息操作按钮布局修整(用户消息编辑/复制/分支/删除四按钮):编辑与重试按钮补齐悬停 tooltip(此前缺失,与复制/分支/删除不一致);
MessageActions与BranchSwitcherBarcompact 模式补flex-shrink: 0,窄侧边栏下按钮组不再被压缩变形导致高低不一;候选切换器间距改用 margin 均衡(padding 0 2px→margin 0 2px);IconButton补box-sizing: border-box;新增MessageActions.test.ts渲染测试(按钮组合与 tooltip 断言,4 用例)。 - 修复编辑消息对话框(EditDialog)底部按钮换行:
.dialog-footer的flex-wrap: wrap在窗口略窄时会把最后一个「保存」按钮单独挤到第二行(取消/回档到用户消息前/原地保存在第一行);现改为强制单行(nowrap),长文案按钮(回档/原地保存)文字走单行省略(btn-label包 span +max-width截断),「保存」主按钮flex-shrink: 0恒在同行最右。 - 使用时间统计支持长期历史浏览(
backend/modules/activity):查询范围扩展365d/all(ActivityStore.loadAllDays全量读取),新增按月聚合aggregateMonthly(月总分钟/活跃天数/会话数,includeMonthly控制);AI 工具get_activity_stats同步扩展 range 枚举与includeMonthly参数;用量页「使用时间」区块新增范围切换(近 7 天 / 30 天 / 90 天 / 1 年 / 全部)——7/30 天显示每日条形图,90 天及以上显示月度条形图(点击月份展开该月每日明细,数据来自已拉取的 daily 无需二次请求),总览卡片「范围内合计」随范围联动,作息热力保持最近 7 天。 - 设置面板新增「用量统计」页签(
SettingsPanel.vue+settingsStore):内嵌使用时间区块(UsageTimeSection)与 Token 用量摘要卡片(总 Token/输入/输出/思考/缓存写入/缓存命中/对话数/回复数,范围筛选 全部/今天/近 7 天/近 30 天),底部「查看完整统计」按钮接通原showUsage()整页入口(此前该入口在 UI 中无任何调用方);三语 i18n 同步(components.settings.tabs.usage/sections.usage)。
Changed
- 使用时间统计区块(
UsageTimeSection)默认范围从近 30 天改为近 7 天(activeRange初始值'30d'→'7d',范围切换仍保留 7/30/90 天/1 年/全部)。 - 欢迎页「欢迎使用 GrayCode」图标从 codicon 对话气泡改为开屏动画同款的手绘 Gray logo:内联 SVG 静态完稿态(灰阶色块 + 细描边线稿,颜色变量与 Splash.vue 同源,亮/暗主题自适应)。
- 修复欢迎页 Gray logo 图标右侧头发色块缺失:复制 Splash 色块层时遗漏第二个
fill-hairpath(M 587.0 408.0...),后半头发只有线稿描边、色块透明;现补齐与 Splash.vue 一致的 7 个色块 path(body×2 / hair×2 / face×1 / cap×2)。
Fixed
- 清除纯
tsc --noEmit下.vue相关类型噪音(vue-tsc 标准检查本就全绿):①vite-env.d.ts的*.vueshim 从DefineComponent<object, object, unknown>宽松为Record<string, any>版本——纯 tsc 无法解析.vue内部结构,原 shim 导致测试中mount/setProps的字面量 props 触发 excess property check(TS2353,MessageItemStreaming / MessageRenderBlock / Splash / MarkdownRenderer 共 10 处);② 新增MessageItem.vue.d.ts旁路声明补齐普通<script>块具名导出(backgroundTaskViewModeByMessageId/BACKGROUND_TASK_VIEW_MODE_CAP/pruneBackgroundTaskViewModes/BackgroundTaskViewMode)——全局 shim 只有默认导出,测试文件具名导入报 TS2614 共 3 处;vue-tsc 优先解析真实.vue文件,行为与类型均不受影响。 - 设置页工具列表
get_activity_stats工具补齐三语 i18n(此前缺失词条,显示名回退为英文 "Get Activity Stats"、描述回退后端英文原文):toolDisplayNames/toolDescriptions新增词条(zh-CN 显示名「获取活动统计」、en "Get Activity Stats"、ja「アクティビティ統計を取得」),toolLocalization.test.ts同步补断言。 - 修复自动总结在工具循环内触发后模型「失忆」(一次工具调用后历史与用户输入从请求中整体消失):
SummarizeService自动总结从「只插入不删除」改为物理替换(同一写锁事务内删除被总结区间[historyStartIndex, insertIndex)并插入总结,replaceSummarizedRangeAtomically),存储与请求组装口径一致,token 估算随历史缩短自然回落、不再每轮反复触发;写入前基于最新历史重新校验范围(STALE_RANGE,总结永不越过当前回合用户消息,杜绝并发写入下连用户输入一起吞掉);总结文本过短(< 50 字符)视为低质量拒绝替换(LOW_QUALITY_SUMMARY);ToolIterationLoopService流式 autoSummary chunk 透传removedCount,非流式循环补 abort 检查。 - 前端
handleAutoSummary同步「物理替换」语义:收到removedCount > 0时删除本地窗口中被替换区间、幸存消息backendIndex平移、插入总结(去重优先用后端消息 id);StreamChunkProcessor转发removedCount字段。 - 修复自动总结后模型丢失原始任务指令:物理替换被总结区间时删除起点不越过第一条真实用户消息(用户首条消息承载任务目标,总结文本永远不如原话清楚,必须原样保留);请求组装时若首条用户消息早于最后总结,把它原样拼到请求历史最前(不能只依赖 Preserved user inputs 档案——首次总结后档案读不到已被删除的首条消息);实际删除数回填
summarizedMessageCount与返回协议(insertIndex为替换完成后总结新下标)。 - 修复底部 TPS 统计在代码编辑/写入时虚高:
record透传chunk.createdAt真实到达时间(后台标签页回放/隐藏 webview 积压的整段数据按原时间入窗并被窗口立即修剪,不再产生天量尖峰);tpsMeter突发摊薄(单事件 > 250 token 按最近 1s 均匀铺开、总量守恒)与速率硬上限(1200 tok/s);工具调用 JSON 参数与思考 token 均计入生成速度(都是模型输出),计数改为模型专属 tokenizer(见下条)。 - TPS 统计接入模型专属 tokenizer + 自校准叠加:文本/思考/工具参数统一按真实编码计数——DeepSeek 模型用官方
deepseek_v3_tokenizer转换词表(与官方 Python 基准 12 类样本逐位一致,含中文/代码/JSON/emoji),其余模型用 cl100k(OpenAI 系近精确,其他模型由校准因子修正);词表不打包进 vsix,由扩展端TokenizerResourceManager运行时联网下载到数据目录tokenizers/(cl100k 来自 OpenAI encodings CDN、DeepSeek 来自官方 api-docs zip,下载/解压/转换后本地缓存,启动复用不再联网;首次需要时触发),前端经tokenizer.getResource消息通道获取并用js-tiktoken/lite(9KB BPE 引擎)加载,下载失败/离线时回退字符类别加权估算(ASCII/CJK/其他分系数);每轮流结束用最终 usage(2.5 挡 usage 异常,localStorage 持久化),同一模型系统性偏差收敛到candidatesTokenCount,含思考,与估算口径一致)对比本轮估算,按模型 EMA 学习校准因子(离群剔除 0.435%;超长文本分批计数规避 tokenizer 合并缓存非线性退化;vsix 体积不增反降(移除 gpt-tokenizer 双词表与内置 DeepSeek 词表)。 - 修复子代理设置面板 MCP 工具名显示为「Mcp Mcp 1785407697930 5wldv41 Search」:
getToolDisplayName增加 MCP 分支(decodeMcpToolName解码后只对原始工具名做 Title Case),SubAgentsSettings保留serverName并以徽标展示(与自动执行页一致),原始编码名降级为悬浮提示;useCheckpointConfig重复实现改为复用toolLocalization,AutoExecSettings的split('__')改用 codec。 - 修复 checkpoint 增量快照静默过期:
CheckpointSnapshotBuilderstat 复用哈希的mtimeNs分支补size校验(FAT32/SMB/容器挂载卷上同一时间刻度内重写且字节数不变时不再错误复用旧哈希)。 - 修复 MCP stdio 客户端内存无界增长:
StdioClientbuffer 设 16MB 硬上限(超限终止连接),单条消息 > 4MB 拒绝发送(背压保护)。 - 修复
McpManager.handleServerNotification竞态:per-server 刷新链串行化,写入 capabilities 前重查代际(disconnect/重连不再用旧 client 空列表覆盖新缓存),rejection 兜底。 - 修复工具并行只读组无 abort-race(组内工具永不结束时停止按钮失效):
ToolExecutionService并行组套用 abort 竞速 + 2s 收尾窗口,超时按取消结算。 - 修复
fileWriteLockManager25ms 轮询空转:release 时 generation 通知等待者 + 50ms 兜底轮询。 - 修复会话删除后
mailboxDrainEpochs条目残留(deleteConversation接线清理);ToolIterationLoopService两个会话级 Map 加容量上限;MemoryManager.cover()二分迭代 60→32 次(提前退出);CheckpointManager持久化前过滤复制失败的 changes 条目;repeatedCallGuard大字符串改采样哈希;ToolRegistry.getFilteredDeclarations别名归一化;SettingsCore.reset深拷贝默认配置;taskManager.cleanup真正清扫终态任务。 - 修复前端流式期间 CustomScrollbar 每帧强制布局:
characterData变更不再触发 marker 重扫(仅结构变更触发,500ms 节流 + 尾沿补偿),贴底跟随行为不变。 - 修复
chatStore.initialize()监听器非幂等(HMR/重挂载重复订阅导致流式消息被处理 N 次):重复调用先注销旧监听再注册。 - 修复终端输出无上限(长驻终端 O(n²) 拼接 + 整段重渲染):
terminalStore输出截断保留最近 200KB。 - 修复
MessageRouterNON_BLOCKING 分支 handler 未回复时requestClients条目泄漏;SubAgentMonitorrun 终态清理renderMessageCacheByRun;MarkdownRendererimageCache 增加 32MB 字节预算(单图 > 1MB 不缓存);smoothStreamManager反查索引 O(1);agentStopNotificationController日志收敛为 debug;MessageList删除 scrollTop 死代码。 - 后台命令不再吃满 CPU:
execute_command后台(background)启动的 shell 进程降为低优先级(Windows:BelowNormal优先级类,spawn 后 PowerShell 设置,子进程树创建时继承——cmd/powershell 后续启动的 node/jest 等同样让路;POSIX: nice +5),跑测试/长任务时让出 CPU 给前台交互、空闲时仍全速;前台命令保持 normal 不拖慢同步等待。注:Node spawn 的priority选项在 Windows 上实测不生效,故采用 spawn 后外部设置(尽力而为,失败静默)。 - 渠道默认改为流式输出:新渠道
options.stream默认true(实时可见输出、支持流式工具边执行);设置界面流式开关显示与后端默认一致(?? true);显式保存过options.stream的已有渠道不受影响(显式值优先)。 - 渠道自动重试覆盖空响应与流截断:HTTP 成功但模型返回空内容(无文本/思考/工具调用/附件,非流式解析后检测)或流式从未产出内容(未收到 done 标记)→
EMPTY_RESPONSE_ERROR自动重试(此前静默当成功);已产出内容但流未收到 done 标记(上游/代理中途掐断连接,for-await 静默结束)→ 显式抛「流式输出被截断」错误不再假装成功(已产出内容不自动重试:重播会与已显示内容重复、流式早启动的工具副作用无法撤回,错误透传前端可手动重试);generateStream/generateNonStream的 ChannelError 均原样透传不再误包 PARSE_ERROR。
v1.4.2
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.execFileargv 数组传递(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改用索引投影(lastSentHistoryProjectionv1,可匹配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_MS1400→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_MS1700→2300、minDisplayMs默认 1700→2300;光标闪烁改steps(1, end)惯用写法;splash 根加role="status";prefers-reduced-motion 分支同步(色块直接可见、线稿静态细描边);测试常量与两拍退场断言同步。 - 移植 fork 的全仓性能优化(保留插件形态,不涉及桌面版 electron 层):
getMetadataLight接入会话元数...
v1.4.1
[1.4.1] - 2026-08-05
Changed
- 分支树面板改造成双模式“分支历史”:默认“分支导航”会折叠连续线性消息,只保留根节点、分支点、候选入口、命名/删除节点与当前尾部;“完整消息”显示所有节点,但普通父子消息沿用同一纵向轨道,只有真正的兄弟候选才横向展开,不再随对话长度形成一路向右的阶梯。面板同时增加节点计数、角色标签、精简时间、悬停操作按钮和窄窗口适配,保留候选切换、工作区恢复确认、软删除、恢复与重命名能力,三语文案同步。
- 子代理完整 transcript 从 conversation
.meta.json迁移到conversations/<conversationId>/subagents/<runId>.json独立原子文件;元数据仅保留状态、计数、修订号和transcriptRef,不再重复内嵌contents与lastSentHistory(包括图片 Base64)。旧内嵌记录首次加载时自动迁移并清除大字段,Monitor 历史与续跑 provider 前缀保持完整。
Added
- 树状分支重 roll 前端主流程接线(此前仅后端完成):消息「重试」与「回档并重试」从破坏性删除(deleteMessage + retryStream)切换为
chat.rerollStream(旧回答保留进分支图 sidecar,新候选生成后可经 BranchSwitcherBar 的「‹ 2/2 ›」切换回);reroll 流结束(complete/error/cancelled)后自动刷新分支图;重试确认框三语文案同步为「保留当前回答、生成新版本」语义;chat.rerollStream加入无超时请求白名单与 VSCodeRequest 类型联合 - 编辑用户消息前端主流程接入
chat.editBranchStream(此前仅后端完成):消息「编辑」与「回档并编辑」从破坏性editAndRetryStream(覆盖原消息)切换为分支编辑——后端创建编辑候选(新 user 节点)并截断主历史,原消息及其子树保留进分支图 sidecar(决策 7:旧分支保留,失败可切回);本地窗口改写目标消息 + 截断 + 流式占位,置位分支图刷新标记(流结束后 BranchSwitcherBar 显示候选切换器);流启动失败时重载最后一页 + 检查点恢复前后端一致;chat.editBranchStream加入无超时请求白名单与 VSCodeRequest 类型联合;附件仅更新本地窗口(编辑分支接口无附件字段) - 子代理设置页工具白名单/黑名单列表工具名称与悬停描述接入三语 i18n:新增公共模块
frontend/src/utils/toolLocalization.ts(工具显示名/描述本地化,缺失时机械转换/回退原文),工具设置页与子代理设置页共用同一套toolDisplayNames/toolDescriptions条目,MCP 外部工具自动回退英文原名 - 删除消息同步软删分支图子树(后端):
deleteToMessage(删除到某条消息)与单条删除在硬删除主历史后同步更新分支图——被删消息对应节点及其后续整棵子树(含非活跃候选)标记为已删除(保留可恢复语义、不物理清理 sidecar,过期清理仍走保留期机制),活跃尾自动回退到最后保留消息对应节点,指向被删节点的活跃指针一并清空;无分支图(线性对话)或无分支服务注册时保持原有删除行为不变,图同步失败仅告警不阻断硬删除(主历史为唯一真源) - 编辑用户消息新增「保持当前分支」模式(
chat.editBranchStream请求新增mode字段,默认'branch'行为不变):mode='keep'为真·原地保存——只改写活跃路径上目标用户消息的文本,后续消息、检查点与分支全部保留,不截断、不软删、不创建候选、不重新生成;后端ensureBranchGraph建图(无图时建线性基线)后updateMessage改写主历史 +updateActiveNodeParts同步图节点内容,流直接完成(complete 仅通知前端复位状态);前端编辑对话框新增「原地保存(保持当前分支)」按钮(三语文案),编辑链路(EditDialog → MessageItem → MessageList → App → editAndRetry → webview)透传mode,分支流错误重放上下文同步携带mode;editAndRetry/restoreAndEdit本地同样只改目标消息(不截断窗口、不创建占位),发送时本地 user 消息补近似parentId(首条为 null)供根节点判断
Fixed
- 修复流停止等待竞态:
waitForIdle()现在同时等待当前控制器和已退休旧流的 finally;cancel()不再让既有等待者永久挂起,也不会在旧流仍处于工具结算窗口时假报空闲;cancelAll()在视图/扩展销毁时统一释放全部退休链。 - 修复删除会话与运行任务/元数据写入竞态:删除前先中止并等待主流退出,退出该会话全部前台与后台子代理,等待 executor 注销及 transcript/索引持久化排空,再删除检查点和会话;会话物理删除同时进入元数据共享写链,进行中的巨大
.meta.json写不能在删除后通过晚到 rename 复活幽灵文件。 - 修复「原地保存(保持当前分支)」误删整个分支:keep 模式原实现为「改写 + 截断其后内容 + 软删图子树 + 重新生成」,用户点击后目标消息之后的全部消息与分支候选被移除。现改为真·原地保存语义(只改目标消息文本,后续消息 / 检查点 / 分支全部保留,不重新生成),后端去掉
deleteCheckpointsFromIndex/deleteMessagesInRange/syncGraphAfterHistoryDelete与工具循环(keep 模式流直接完成),前端不截断窗口、不创建占位、不置分支图刷新标记;错误条重放(replayBranchStreamAfterError)对 keep 上下文同样不截断、不创建占位;根节点编辑降级 keep 时走同一语义 - 修复编辑第一条消息(根节点)报
INVALID_BRANCH_RELATION: cannot edit the root node:BranchGraph 为单根模型,根节点没有父节点可挂编辑候选(TREE-03 遗留「根节点编辑暂拒」)。现在编辑根节点时前端自动降级为「原地保存」语义(keep 模式——只改写根消息,后续内容保留,与编辑对话框「保持当前分支」按钮一致):resolveEditTargetNode新增mode参数、keep 模式放行根节点(图模式与线性模式都支持),editAndRetry/restoreAndEdit检测目标消息parentId == null时自动以mode='keep'发起chat.editBranchStream(错误条重放上下文同步携带 keep 模式);contentToMessage/contentToMessageEnhanced透传content.parentId(Message 类型新增parentId字段),前端据此识别根节点 - 修复编辑用户消息报
NODE_NOT_FOUND: node not found: <id>(新对话首条消息即必现):前端发送用户消息时窗口消息 id 用generateId()生成,但chatStream请求只传文本、不传 id,后端落库时由ensureNodeId另行生成randomUUID()——窗口 id 与主历史/分支图 Content.id 永远不一致,编辑/重试按 id 定位必失败(assistant 消息经流式contentToPersistedMessage有 id 对齐机制,user 消息没有)。现在chatStream请求新增messageId字段(ChatRequestData.messageId),前端sendMessage携带窗口 user 消息 id,后端addMessage原样落库(省略时仍由后端生成,兼容旧客户端);工具确认批注同款修复(annotationMessageId经toolConfirmation→handleToolConfirmation→addContent透传)。已打开会话中的历史遗留不一致消息,重新加载历史(切走再切回)后窗口 id 与后端对齐 - 修复候选切换器(BranchSwitcherBar)挂载位置:切换器改为跟随「当前活跃的候选消息」(用户重 roll / 编辑过的消息本身),而非候选组的父节点——此前
user:1 → ai:2 → ai:3重试 3 后切换器显示在 2 上(候选组挂在父节点 2 下),现在显示在 3'(3 的位置)上;新增buildCandidateGroupForNode(按消息节点推导所属候选组,仅活跃成员返回),BranchSwitcherBarprop 从parentNodeId改为nodeId - 上下文裁剪 fallback 切点回合内稳定(保留 provider 前缀缓存):
getHistoryWithGranularFallback支持stableStartIndex——自动总结失败后同一真实用户回合的多次工具迭代(含工具确认后的续跑)复用第一次确定的裁剪起点,工具结果增长不再每轮把absoluteStartIndex向后推(此前每轮 retainedHistory 开头漂移,缓存只能命中 history 之前的固定系统/工具段);仅当完整性校验失败或估算超过硬上限(maxContextTokens 的 95%)才重新规划;新回合/总结成功后自动清点重新评估,clearTrimState同步清理 - 上下文总结请求不再携带图片/文件载荷:
cleanMessagesForSummarize把用户消息中的inlineData/fileData替换为[Image: …]/[File: …]文本占位符(总结模型无需加载图片字节,省输入 token,也避免不支持多模态的总结渠道报错) - reroll/编辑分支流前端修复:
_pendingBranchRefreshAfterStream标记改为按会话隔离(记录发起流的会话 ID):会话切换后其他会话的终结 chunk 不再误消费并误刷分支图;切回原会话后由该会话的终结 chunk(或后台缓冲 flush)正确消费retryFromMessagereroll 流启动失败且会话已切换时不再重载原会话历史(避免污染当前会话窗口与检查点,与 editAndRetry 同款身份校验)- 内容型
toolIteration因「需用户确认 / 审批门闸 / 工具被取消」终结流时同样消费分支图刷新标记(此前标记残留,可能被后续无关终结事件消费) restoreAndEdit补 R3-#13 同款按 id 重定位(await 恢复期间数组变化不再错改错删),恢复失败错误写入加会话归属校验restoreAndRetry/restoreAndEdit的chat.rerollStream/chat.editBranchStream载荷补齐promptModeId(与 messageActions 入口一致)- i18n 新增
hasMessage()静默 key 存在性检查;工具本地化(toolLocalization)缺失条目不再触发[i18n] Missing translationconsole.warn 刷屏 - reroll/编辑分支流失败时错误条可重试(方案 B):后端在流式失败时把底层
ChannelError.type(API_ERROR/NETWORK_ERROR/TIMEOUT_ERROR/PARSE_ERROR等)透传到错误 chunk({ code, type?, message }),前端isRetryableError对REROLL_ERROR/EDIT_BRANCH_ERROR改为按底层 type 判定可重试——携带可重试 type 时错误条显示「重试」;无 type(如REROLL_FINISH_SYNC_FAILED等 reroll 特有错误)或 type 不可重试(CONFIG_ERROR/VALIDATION_ERROR/CANCELLED_ERROR)时不显示;ErrorInfo类型补可选type字段,retryAfterError入口守卫改用isRetryableError保持与错误条判定一致 - 主聊天发起的 diff 预览同样跟随主聊天所在列:
vscode.diff的viewColumn参数在部分布局/版本下不生效(仍在当前活动编辑器组打开,焦点在 Monitor 面板时 diff 会落到 Monitor 列),现在主聊天上下文同样下发diffViewColumn(与 Monitor 路由同语义,主聊天在侧边栏时回退主区域第一列),且openDiffView打开后用vscode.moveActiveEditor把 diff tab 校正到目标列(目标列即当前列时移动幂等)
- 修复后台子 Agent 完成回执插入尚未结束的主模型调用,并导致上下文从约 35 万 token 骤降至约 2 万 token(用户实测):
- 根因一是前端收到
completechunk 后会先清除isStreaming/isWaitingForResponse,但后端流此时可能尚未执行StreamRequestHandler.finally;后台任务回流仅依据前端状态判断空闲,随即创建同会话新流,触发StreamAbortManager.create()中止并替换仍在收尾的旧流。现在新增后端chat.awaitConversationIdle与StreamAbortManager.waitForIdle(),回执发送前以运行控制器为生命周期唯一事实来源,等待旧流真正退出;等待期间若切换会话或启动新流则重新判定,不再依靠延时或前端瞬时状态猜测 - 根因二是后台回执经普通
chatStream落盘时被标记为真实 user 消息,裁剪器将其识别为新回合;当前一个工具回合本身约 35 万 token 时,回合完整性约束会迫使裁剪器丢弃整个旧回合,只保留约 2 万 token 的回执回合。现在source: 'background_task'从前端请求贯通到后端历史,回执以isUserInput: false保存;合法裁剪起点、回合识别、当前回合定位、思考范围与 token 累加统一复用isRealUserMessage(),后台回执视为原任务的异步延续,旧历史中缺少isUserInput的真实用户消息仍兼容;source在渠道 formatter 发请求前剥离,历史重载时透传回前端以保持后台任务卡片样式 - 补充后端运行生命周期、回合边界、旧历史兼容和前端来源透传回归测试;根 TypeScript 检查、前端生产构建及目标测试通过
REROLL_ERROR/EDIT_BRANCH_ERROR错误条重试改为重放原分支流(方案 B 一致性收口):此前错误条「重试」会回退到retryStream直接追加生成——流式失败后主历史已有半截候选、请求级失败后旧回答仍留在主历史,追加生成分别造成「半截候选 + 新回答」重复与「旧回答 + 新回答」重复,并让分支图与主历史失配(后续删除/编辑报索引越界)。现在retryFromMessage/editAndRetry/restoreAndRetry/restoreAndEdit在发起分支流时记录原请求快照(目标节点、编辑文本、配置、模型覆盖与 Prompt 模式),流失败时随错误对象保存;错误条重试按错误码重放chat.rerollStream/chat.editBranchStream——流式失败(REROLL_ERROR/EDIT_BRANCH_ERROR)复用失败候选(省略旧节点 ID,由后端按当前活跃路径选择,前端仅回滚半截展示、绝不调用deleteMessage),请求级失败(RETRY_ERROR/EDIT_RETRY_ERROR)按原目标节点重建本地窗口后重放;重放上下文随标签页快照保存/恢复(切标签页后仍可重试),成功/取消/关闭错误时清理;普通流错误(STREAM_ERROR/API_ERROR等)重试行为不变
- 根因一是前端收到
- 修复
agent.sendMessage工具名含点号导致 OpenAI 兼容 API 拒绝请求(400Invalid 'tools[N].function.name': string does not match pattern '^[a-zA-Z0-9_-]+$'):工具更名为agent_send_message(与全局 snake_case 命名一致),并在声明中注册agent.sendMessage为别名,旧对话历史中的调用仍可经 ToolRegistry 别名解析执行 - 子代理设置页工具白名单/黑名单列表不再把工具完整描述直接渲染在名字下方(几十个工具的长英文描述把设置页撑得极大),改为仅显示工具名,描述收敛为鼠标悬停的 title 提示
- 批量代码审查修复:
- 工具系统:validateToolArgs 对非对象参数加守卫(畸形模型输出不再 TypeError 崩溃整个工具批次);insert_code 空内容不再产生多余空行;jsonFormatter 字符串值内出现字面
<<<END_TOOL_CALL>>>标记不再提前截断块(状态机感知字符串开关与转义) - 对话历史:rejectToolCalls 对无 parts 消息加防御;getCustomMetadata 在 meta.json 损坏时降级返回 undefined 而非抛错;删除会话后迟到的 setTitle/updateSummary 不再重建幽灵 meta.json(loadMetadataForWrite 校验历史存在性)
- 文件与搜索:generate_image 参数缺失路径不再残留 running 任务;网络错误不再误报为用户取消;remove_background mask 缩放改 fit:'fill' 消除裁切错位;find_files maxResults 语义修正(+1 探测避免 truncated 误报);search_in_files replace 模式匹配收集加 20000 上限与 truncated 标志、多根工作区 path 解析失败不再静默回退、正则源超 500 字符拒绝(ReDoS 防护)
- 子代理与文档工具:agent_send_message 消息加 16000 字符与 inbox 50 条上限;子代理排队取消路径收敛到 finalizeRun 终态出口;update_progress latestConclusion 归一化;record_progress_milestone 里程碑 id 撞车自动递增重试;create_progress 区分 ENOENT 与其它读错误;create_design 不再静默覆盖已存在设计文档;toggle_skills 未找到技能改 data.warnings 语义
- 记忆与设置:truncateLog 长度读取移入锁内(并发 note 不再被误截断);compress 仅在 treePut 成功时上报 done;wake 缺失摘要提示指向实际缺失块;SkillsManager.refresh 同步清理已删除技能;代理设置不再默认启用;设置文件损坏抛错而非静默归零;savePromptMode 校验 mode.id 非空
- webview:MessageRouter 流式请求 clientId 映射改为流结束时统一清理(Monitor 发起的流出错不再错投主聊天或永久挂起);cancelStream 缺 data 不再泄漏映射条目;diff 预览内容缓存加 50 条上限;getExtensionVersion 收敛到公共模块;UsageHandlers dispose 清空统计缓存;删除 FileHandlers 死代码变量
- 前端:流式终结 chunk 缺 content 时流状态仍无条件复位(不再卡在"等待响应");视频/图片缩略图加载加整体超时与 onerror 兜底;声音去重集合与 todo 状态集合加容量上限;待确认工具拦截路径不再静默丢弃附件;后台会话流式缓冲加 2000 chunk 上限
- 构建与测试:.vscodeignore 补充 .env/.env./.pem/*.key 防密钥入包;jest 全局 testTimeout 20000;移除空 jest.setup 引用;messageRouterNonBlocking 测试改为断言生产常量(不再是无效测试);tsconfig 移除 tsc 直出遗留死配置;npm scripts 收敛;fast-tavern 恢复被删除的 build 模块(buildPrompt/buildPromptFromSillyTavern,npm build 与 pytest 恢复通过)、vectorSearch 类型收敛为同步并修正 Python 端异常静默、Python 正则/世界书浮点语义对齐 TS(NaN/Inf 守卫、不再 int 截断)、递归上限对齐 Math.trunc+clamp
- 工具系统:validateToolArgs 对非对象参数加守卫(畸形模型输出不再 TypeError 崩溃整个工具批次);insert_code 空内容不再产生多余空行;jsonFormatter 字符串值内出现字面
- 第二轮高风险并发/性能修复:
- 流式取消竞态(ToolIterationLoopService + ChatFlowService):取消时先以 3s 有界窗口等早启动工具落定再结算(真实结果不再丢失为 cancelled 占位);主工具循环 gen.next() 与 handleToolConfirmation 两个确认循环补 abort-race + 2s 收尾窗口(不再永久挂起);流式取消分支补 resolveAndPersistPostToolStopState(审批门不再残留误拦截)——配套 5 个时序测试
- 代理模式取消:executeStreamRequest 代理分支循环结束后显式检测 externalSignal.aborted 抛 CANCE...
v1.3.2
Changed
- 存档点创建/恢复主流程切换到新架构:创建改用
CheckpointSnapshotBuilder(多根工作区扫描、强制排除存档目录自身、流式哈希 + 有界并发、stat 复用),恢复改用CheckpointRestoreEngine(增量链文件索引 O(1) 查询、scoped 路径安全解析、失败清单区分 missing_in_chain / hash_mismatch / copy_failed / delete_failed);新存档记录工作区身份(workspaceRoots/workspaceFingerprint),恢复前校验当前工作区,跨项目恢复被明确拒绝;新存档备份目录改用 scoped 布局(cp_xxx/ws_xxx/relative),多根工作区同名文件不再互相覆盖;旧格式存档(相对路径键 + 旧布局)单根恢复保持兼容,多根下明确拒绝而非静默错恢复;存档创建/恢复进入工作区级互斥锁(等待进行中的写工具退出并阻止新写入),恢复失败路径转相对路径展示 - 用量统计性能再优化:统计读取元数据改为轻量路径(只读
{id}.meta.json,不再走getMetadata的历史完整性检查——此前每次统计都会为每个对话额外加载一次历史,索引优化的收益被抵消大半);新增对话目录监听(fs.watchrecursive)+ 内存明细缓存——任何历史/元数据/索引文件写入都会把对应对话标记为 dirty,统计只重读 dirty 对话并回填缓存,其余对话直接重放内存明细(零 stat、零读文件),日常统计从几千次跨进程文件调用降到毫秒级;统计自身重建索引写入{id}.usage.json会触发一次自伤标记,下一轮重读小索引文件后自然恢复,不会无限循环;扩展 dispose 时释放监听,非文件存储(测试/内存适配器)自动退化全量扫描;新增缓存命中跳过读取 / dirty 重读回填 / 已删对话清理 / 缓存时间筛选与 watcher 文件名解析测试 - 提示词设置页排版重排(PR #5):动态上下文保留策略区块从全局固定位置移入对应的模板模式内——预设条目模式下显示在条目编辑区下方,传统模板模式下内联显示在动态模板文本框下方,选项归属不再让人困惑;新增「可用变量参考」可收缩面板(默认收起,静态变量组 / 动态变量组分组展示,chevron 展开收起),长变量列表不再永久占据设置页空间
- 提示词模式栏新增保存按钮(绿色保存图标,保存中切换为 loading 动画),与底部原保存按钮并存;导入 / 导出按钮从 codicon 通用图标改为成对的自定义 SVG 图标(方向相反的导出/导入箭头),视觉上明确为一对操作
- 提示词页保存 / 导出 / 导入反馈统一为浮窗 toast(成功 / 失败着色,2.5 秒自动消失,Transition 动画),移除底部行内文本提示(saveMessage)
- 存档点文件哈希改为流式读取(
CheckpointManager.getFileHash/computeFileHashes),不再把大文件整体readFile进内存,哈希结果不变 - 默认启用存档的写工具列表补齐(CP-13):新增
insert_code、delete_code、search_in_files(replace 模式)、图像处理(remove_background/crop_image/resize_image/rotate_image)与文档类(create_plan/update_plan/create_design/update_design/create_progress/update_progress/record_progress_milestone/create_review/record_review_milestone/finalize_review/reopen_review)默认在执行前/后创建存档;search_in_files纯 search 模式(非 replace)不再创建全工作区存档 - 恢复检查点前主动取消该对话的流式请求与关联的活跃 SubAgent(CP-04/CP-12),防止恢复后迟到 chunk 污染历史、SubAgent 继续写文件与恢复结果冲突
- 存档排除功能上线(EX-01~EX-12):
CheckpointIgnoreResolver升级为四层排除模型——强制排除(.git/node_modules/ 扩展存储根绝对路径,!不可否定)→ 默认排除类别(8 类,设置页可分别开关,可被!重新纳入)→ 嵌套.gitignore(anchored + 否定 + 目录作用域)→ 用户自定义模式(独立最终求值阶段,最后生效);shouldIgnore返回{ignored, reason, rule, source},快照构建输出完整excluded清单(含命中规则文本)与排除统计;单文件大小上限默认 50 MiB(0 = 不限制),超限文件记录reason: 'size'不静默消失;存档记录与 manifest 保存排除规则快照ignoreSnapshot与excludedCount/excludedBytes,恢复时对比快照规则与当前规则输出excludedNote(含rulesChanged),且恢复过滤严格按当前规则(不因旧规则宽而覆盖当前明确忽略的文件) - 存档排除设置与预览(EX-08/EX-09):
CheckpointConfig.exclusion(enabledProfiles 全开 / maxFileSizeBytes 50MiB / customPatterns,兼容旧customIgnorePatterns合并);设置页新增默认类别开关、大小上限输入、自定义模式编辑器与「预览排除结果」按钮(按类别聚合展示、samples 上限 50、命中 reason/rule/source、被排除目录有界遍历 2000 项且complete=false标记);新增checkpoint.previewExclusions/checkpoint.getExclusionProfileshandler;配置校验拒绝空模式、绝对路径(盘符/UNC)、纯!、..越界、换行注入、未知类别 id 与非有限数值 - 排除语义细节:win32 下强制排除绝对路径比较统一小写归一(防
C:\Projvsc:\proj大小写漏排);「重新纳入目录类别下文件需同时否定目录本身(如!data/ + !data/keep.txt)」在设置页给出提示;自定义模式不再被嵌套.gitignore覆盖(见 Fixed)
Fixed
- 存档恢复边界显式化:只删除目标快照
fileHashes中记录过的路径(#29 语义),快照后新建、快照时被忽略/未备份(复制失败、大小超限、不可读)的文件恢复时不会被静默删除;恢复/创建期间与写工具互斥,避免快照与文件写入竞态 - 修复批量删除增量链断链(CP-05):旧实现只检查「被保留检查点直接引用」一层,链 A→B→C 删除 {A,B} 时 A 被删而 B 保留,B 恢复时断链;现在从所有保留节点向前遍历完整祖先链,被直接或间接依赖的祖先全部强制保留并返回 rejectedIds
- 存档删除/合并操作接入工作区级互斥锁(CP-03):删除、按索引删除、批量删除与创建/恢复互斥;
CheckpointOperationLock支持同 owner 相同工作区集合的可重入(引用计数),create 锁内清理旧存档(cleanupOldCheckpoints → deleteCheckpoint)不再嵌套等待自己而死锁 - 修复回档并重试 / 回档并删除时后端删除失败仍继续执行(CP-11):前端
deleteMessage返回失败或抛错时中止后续重试/流程并展示明确错误,不再出现「前端已截断而后端历史残留」的静默不一致;后端各删除路径的磁盘删除失败不再完全静默,记录 warn 便于排查(元数据已正确移除,残留目录为孤儿目录不影响正确性) - 恢复结果新增未备份文件提示(CP-08/CP-10):
restoreCheckpoint返回unbackedPaths(快照时大小超限/不可读/复制失败的文件,恢复时受保护不会被删除),前端恢复确认后展示失败/部分失败/未备份文件清单;设置页批量删除展示被依赖保留与删除失败的数量 - 新增恢复预览确认流程(CP-09):所有恢复入口(普通恢复 / 回档并重试 / 回档并删除 / 回档并编辑)先调用
checkpoint.previewRestore计算恢复计划(将恢复/删除/跳过数量 + 待删除文件清单),确认框展示清单后才执行真正恢复;待删除文件区分「快照记录过」(#29 白名单)与「快照后新建」(默认保留,用户确认后一并删除,实现「撤销工具新建文件」语义);RestoreEngine提取纯计算函数computeRestorePlan,预览清单与实际执行的删除严格一致;restoreCheckpoint新增deleteUntrackedFiles选项,未确认时保持原有保护语义不删除任何快照后新建文件 - 恢复确认流程安全加固:
restoreAndRetry/restoreAndDelete/restoreAndEdit的「删除快照后新建文件」改为调用方(确认框)显式传参确认,默认 false——绕过确认框的调用不会静默删除文件;回档三连中deleteMessage失败时不再只提示,而是重新加载历史拉回前端窗口与后端一致;恢复确认框取消时清理暂存的预览动作状态;预览期间恢复按钮显示 loading 并禁用 - 存档维护改进:
pruneMissingBackupCheckpointRecords顺带清理孤儿备份目录(磁盘存在但无任何记录引用,如删除失败/崩溃残留,仅处理cp_*格式目录);设置页存档详情展示「N 个文件未备份」(悬停显示路径清单,去除工作区作用域前缀);CheckpointOperationLock可重入放宽为「请求集合是已持有集合的子集即放行」,嵌套调用更不易死锁 - 深度审查修复:快照强制排除范围从存档目录扩大为整个扩展存储根(自定义数据目录位于工作区内时,memory/conversations 等扩展数据不再进入存档);恢复时「删除多余空目录」纳入
deleteUntrackedFiles确认控制(快照后新建的空目录默认保留,#29 语义,预览清单一并展示);legacy 存档预览返回legacy标记,前端展示「恢复以备份内容为准」避免误判「无变更」;恢复确认框打开期间恢复按钮禁用,防止重复点击覆盖确认内容 - 修复增量链恢复索引错误:增量节点磁盘上只保存
changes里的文件,但恢复索引此前把该节点完整fileHashes都指向其目录,导致未变化文件恢复时报missing_in_chain;现在按changes限定节点备份边界,未变化文件从更早节点(base)恢复 - 修复存档路径安全缺口:备份源目录(
backupDir)来自存档元数据,损坏数据可含../绝对路径,现在恢复时校验备份源必须位于存档根目录内(越界视为链上缺失);恢复目标路径全程做符号链接/junction 检查(resolveSafePathInsideRoot),链接不能绕过工作区边界 - 修复旧版存档(无
fileHashes)恢复安全隐患:多根工作区下明确拒绝(旧记录无工作区身份,无法确定文件归属);单根恢复以备份目录实际内容为目标、绝不删除当前工作区任何文件(旧记录没有“快照时可见”清单),替代此前“删除备份里没有的所有文件”的危险行为 - 修复同一对话切换工作区后增量链错乱:新存档识别到工作区指纹不一致时从新的完整备份开始(断开旧链),不再跨工作区串接增量
- 部分恢复失败时返回
error摘要(前 5 条路径+原因,超出计数),前端restoreCheckpoint类型同步补充failures字段 - 修复流式报错后重试残留半截回答:流式过程中后端报错时,后端不会持久化半截 assistant 消息,但前端窗口会保留有内容的半截消息,点击错误通知上的「重试」(
retryAfterError)之前不会清理,导致重试后窗口/历史出现半截回答残留,且与后端历史错位;现在handleError会记录失败半截消息 ID,retryAfterError重试前回滚(删除窗口消息 + 清理检查点 + 防御性同步删除后端),错误条「关闭」按钮与发送新消息也会一并清理失败残留,工具响应后的「继续对话」语义不受影响(不删除正常历史);新增回归测试 12 用例(frontendstreamErrorRetry.test.ts) - 修复动态上下文策略选项的误导性括号标注:单份模式选项原先带有「(当前策略)」(zh-CN)或「(当前行为)」(en/ja)注释,而该选项与保留模式是并列可切换的,标注「当前」会让用户在切换后看到错误的归属语义;现在移除括号注释,三语统一为中性文案「单份动态上下文 / Single dynamic context / 単一の動的コンテキスト」
- 修复动态上下文策略警告文案硬编码英文:设置页选中保留模式时提示「preserve 会把旧回合的动态快照固定插回原位…」,而选项在 UI 上显示的是中文「保留旧动态上下文原位」,用户无法把二者对应;现在句首直接使用选项的中文名称,不再出现英文标识
- 修复空提示词保存后回退默认模板(PR #5):
resolvedMode?.template || promptConfig?.template(PromptManager.ts)与mode?.template || ...(SettingsManager.getSystemPromptTemplate)的空字符串回退导致 legacy 模式显式保存的空模板在运行时被全局模板覆盖,用户无法真正清空模板;两处改为??(nullish coalescing),空字符串原样保留;前端loadModeConfig同步用typeof === 'string'判断而非||兜底,空模板不再被 DEFAULT_TEMPLATE 顶替,新增回归测试锁定该行为 - 修复提示词导出流程不可控(PR #5):前端 Blob 下载在 webview 环境保存位置与文件名不受用户控制,改为通过新增的
exportPromptModeswebview handler 调用vscode.window.showSaveDialog让用户选择保存位置,确认后才写文件;取消保存对话框时不写文件并返回{ success: false, cancelled: true },成功后才报告成功;导出成功 / 取消 / 失败均有明确反馈,不再出现「已导出但不知道存到哪」 - 修复恢复路径未接入四层排除模型(审查 H-1):恢复时的目标状态过滤与当前工作区状态收集此前只走
.gitignore+ 旧customIgnorePatterns两层,恢复可能把文件写回当前明确排除的路径(dist/、data/、超过大小上限的文件)或删除当前应排除的文件;现在createIgnoreResolver统一构造完整四层规则(强制排除含扩展存储根、默认类别、嵌套.gitignore、新旧自定义模式合并),filterRestoreTargetScoped/collectCurrentWorkspaceState与快照构建同一口径,恢复不再触碰当前明确排除的路径 - 修复空增量节点恢复必失败(审查 H1):增量链索引构建时
changes为空数组的节点(工具执行但无文件变化的 before/after 存档)被当作完整节点,其全部哈希被指到自己的空备份目录并覆盖更早节点,恢复任何漂移文件都报missing_in_chain;现在区分「未提供 changes(完整节点)」与「空数组(空增量节点,不索引任何文件)」,空增量后的恢复由更早节点提供文件 - 修复跨格式合并断链(审查 M6):容量清理把 legacy 布局(
cp_xxx/relative)被清理节点并入新格式后继时,文件被原样复制到后继根目录且不写进 manifest,恢复时missing_in_chain;现在按后继 scoped 布局重写路径(ws_xxx/前缀)再复制,并把合并文件的 scoped 键并入后继 manifest.files(hash 取自被删节点),legacy→新格式过渡期清理不再破坏可恢复性 - 修复存档取消竞态与锁等待裸异常(审查 M4/M5):取消发生在等待文件写锁期间时,锁管理器抛普通 Error 从
runExclusive漏出并冒泡到工具循环中断整轮执行;现在 create/restore/deleteAll/deleteBatch 外层捕获锁取消错误转为取消结果;取消发生在复制完成、元数据落盘之前时检查点仍会被保存且进度被done覆盖——现在写 manifest 与写会话元数据前检查throwIfAborted,进度终态改为signal.aborted ? 'cancelled' : 'done' - 修复排除规则对比漏类别开关(审查 M3/M-4):
rulesChanged只比较大小上限与自定义模式,设置页仅开关默认类别(如关闭 logs)时恢复说明误报「规则未变化」;现在同时比较键排序后的enabledProfiles与规则版本号 - 修复自定义排除模式被嵌套
.gitignore双向覆盖(审查 M-1):自定义模式与默认类别原先注入根作用域 matcher,嵌套.gitignore可否定自定义层的!规则或反过来;现在自定义模式从作用域链拆出,作为所有作用域求值之后的独立最终阶段(强制排除仍不可覆盖),「设置页规则最后生效」与计划语义一致 - 修复排除预览
complete谎报(审查 M-6):主扫描遇到不可读目录时静默跳过且complete仍为 true;现在不可读目录产出unreadable排除条目并置complete=false计入统计 - 修复恢复说明与未备份提示回归:
rulesChanged与excludedNote补全后恢复说明准确;存档摘要(CheckpointSummary)化后设置页「N 个文件未备份」提示丢失——摘要补齐unbackedPaths相关字段,前端悬停提示恢复 - 修复 append-only 崩溃恢复后计数永久不一致(审查 H1):尾段 rename 成功但 index 写失败/崩溃时残留行会在下次追加被并入段计数,
index.totalMessages与各段 count 永久相差、全量读与分页读口径不一;现在尾段读取后先按 index 提交点截断(slice(0, count))再拼接新内容,at-most-once 语义下重试不重复,崩溃残留不会泄漏 - 修复元数据文件损坏导致列表 UNKNOWN_ERROR(真实故障):
saveMetadata原为非原子writeFile,写入中途崩溃/断电即截断{id}.meta.json(如 24MB 大文件),读取时parse_error抛到前端阻塞对话列表;现在元数据写入改为临时文件 + rename 原子替换(index 式提交点),getMetadata遇parse_error时把损坏文件改名备份为.corrupt-*(只保留一份)并从历史时间戳重建 fallback 元数据返回,不再向上抛错(存档记录列表随损坏文件丢失属降级代价,磁盘cp_*备份目录不受影响且不会被自动清理) - 修复完整性检查两类误判(审查 M1):legacy 单文件历史只
exists不解析导致损坏 JSON 报ok——现在至少做一次JSON.parse探测;segmented 分支 index 完好但段文件缺失时误报ok——现在对每个段stat存在性(不解析内容,保持 HIS-11 只读结构目标),任一缺失即readable=false - 修复段缓存元素引用污染(审查 M2):
loadSegmentedHistory的slice只复制数组、元素与缓存共享引用,ContextTrimService对tokenCountByChannel的原地赋值会污染缓存;现在加载路径返回前对元素浅拷贝,缓存只读边界落实;缓存键纳入段文件 mtime(revision::m{mtime}),外部进程改写段内容后命中前stat比对自动失效(审查 M5) - 修复用量与元数据一致性:
updateSummary不再无条件写前端传来的messageCount——超过历史实际条数时按index.totalMessages钳制,前端 IPC 失败时不同步本地计数(审查 M3);append 遇「index 存在但尾段缺失/损坏」时不再永久失败,回退全量重写自愈(审查 M4) - 修复前端历史窗口与缓存问题:backfill 把 IPC 失败误当「已到历史开头」置
windowStartIndex=0导致更早消息无法上拉——现在错误与空页区分,错误时放弃合并保留原窗口(审查 L2);loadMoreConversations游标按实际返回数量前进,批量结果缺失时不再跳过未加载对话(审查 L3);消息中间位置同长度替换(迟到 cancelled chunk 清理)会命中陈旧可见缓存——replaceMessageAt非尾部替换时清缓存(审查 L1);addBatch直通 append 可能绕过 functionResponse 去重安全网——契约注释明确仅限纯追加 user/model 并对 functionResponse 显式拒绝(审查 L4) - 修复子agent 续跑丢失 provider 缓存(用户反馈):子agent 每次执行分配新 runId 作为请求
conversationId,DeepSeek/Anthropic 的user_id按它哈希,continueFromRunId续跑时新 runId 落入新缓存域、前缀缓存必 miss;现在续跑时conversationId直接沿用旧 run 的 runId(request.continueFromRunId || runId),user_id哈希输入与旧 run 完全一致、缓存域天然相同——模型调用工具只需传 `continueFromRunI...
v1.3.1-1
Fixed
- 修复存储路径迁移目录套娃(无限递归):
copyDirectory复制时若目标位于源目录内部会无限递归自我复制(mkdir 目标后 readdir 源会看到刚创建的子目录,一次误选子路径可产生数千层嵌套),现检测到目标在源内部时跳过;路径重叠判断改用realpath,junction/符号链接无法绕过防套娃 - 修复存储路径迁移数据安全:源/目标互相包含时先复制到临时目录中转,避免清理旧目录时删除新数据;复制失败终止迁移并回滚,源数据与配置保持不变;失败时恢复原
customDataPath/状态,不再错误切回默认路径;路径验证改用随机临时目录,不再覆盖用户.limcode-test文件 - 修复前端误读
config.customPath(后端字段为customDataPath)导致重置按钮永远禁用;应用/重置按钮增加明确提示(空路径、已是默认路径时不再静默无反应) - 修复设置页描述单行截断:工具名与描述改用 i18n(47 个工具全覆盖),描述样式改自动换行(pre-wrap),不再截断
- 修复动态上下文策略选项的误导性括号标注:单份模式选项原先带有「(当前策略)」(zh-CN)或「(当前行为)」(en/ja)注释,而该选项与保留模式是并列可切换的,标注「当前」会让用户在切换后看到错误的归属语义;现在移除括号注释,三语统一为中性文案「单份动态上下文 / Single dynamic context / 単一の動的コンテキスト」
- 修复动态上下文策略警告文案硬编码英文:设置页选中保留模式时提示「preserve 会把旧回合的动态快照固定插回原位…」,而选项在 UI 上显示的是中文「保留旧动态上下文原位」,用户无法把二者对应;现在句首直接使用选项的中文名称,不再出现英文标识
Changed
- 工具调用格式选项移除「(推荐)」标记:JSON 边界标记不再标注为推荐项(原生 Function Calling 已是主流选择),渠道设置下拉与提示文案的中/英/日三语同步调整
- 设置页 i18n 补全:工具设置/自动执行/存档点/子代理/模型管理的分类分组全量三语翻译(记忆/审查/进度/技能/设计/通知/代理等 16 类),消除重复「其他」分组;Prompt 设置补
modules.MEMORY(记忆系统)三语;记忆设置 Raw Memory Entries 等硬编码英文改走 i18n - 存储路径设置 UI 改版:合并「当前存储路径/自定义路径」为单一输入框,新增 📁 文件夹选择按钮(
storagePath.selectFolder),删除冗余的迁移数据按钮;validatePath放宽——允许选择默认路径/子路径/普通非空目录(如桌面),仅拒绝已包含扩展数据子目录(conversations/checkpoints 等)的目标,防止数据混合 - 渠道设置新建配置:改为模态遮罩弹窗(点击遮罩取消),配置名称为空时红框+提示
- 更新扩展与活动栏图标:市场图标由 1024px 角色插画(1.4MB)替换为 256px 三色剪影版(73KB,深蓝圆角方底,小尺寸辨识度更好);活动栏/侧边栏图标由 VS Code 默认地球替换为角色剪影,并进一步改为纯轮廓线稿(fill=none + stroke=currentColor 随主题着色,Douglas-Peucker 路径简化 716→161 点,24px 下无锯齿)
- 用量统计性能再优化:统计读取元数据改为轻量路径(只读
{id}.meta.json,不再走getMetadata的历史完整性检查——此前每次统计都会为每个对话额外加载一次历史,索引优化的收益被抵消大半);新增对话目录监听(fs.watchrecursive)+ 内存明细缓存——任何历史/元数据/索引文件写入都会把对应对话标记为 dirty,统计只重读 dirty 对话并回填缓存,其余对话直接重放内存明细(零 stat、零读文件),日常统计从几千次跨进程文件调用降到毫秒级;统计自身重建索引写入{id}.usage.json会触发一次自伤标记,下一轮重读小索引文件后自然恢复,不会无限循环;扩展 dispose 时释放监听,非文件存储(测试/内存适配器)自动退化全量扫描;新增缓存命中跳过读取 / dirty 重读回填 / 已删对话清理 / 缓存时间筛选与 watcher 文件名解析测试
Added
- 新增
StoragePathManager单元测试(6 项):覆盖迁移中转、失败回滚、realpath 重叠判断、路径验证临时目录等安全加固行为
v1.3.1
Fixed
- 修复 README 与实际工程能力不一致:更新 npm 构建、Node.js 版本、工具参数、模板变量、设置导出边界、测试命令和项目目录说明
- 修复 npm 工作流残留 pnpm 调用与根锁文件过期:
vscode:prepublish、前端构建和开发脚本统一通过 npm 执行,重新生成与 GrayCode 1.3.0 当前依赖一致的package-lock.json - 修复 SubAgent 对话延续入口不可达:
subagents工具正式暴露并在前台、后台、General Worker 与自定义代理路径中透传continueFromRunId - 修复 Sub-Agent 可获得永久记忆工具:所有子代理统一排除 7 个 memory 工具,工具清单描述和执行期允许列表使用同一隔离规则
- 再次修复输入框 Ctrl+Z 撤销忽略粘贴内容:此前文字粘贴在
paste回调中preventDefault后通过execCommand('insertHTML')模拟插入,虽然单独执行命令可进入撤销栈,但没有保留 Chromium 原生insertFromPaste事务,实际 webview 中仍可能跳过粘贴内容;现在仅在本次粘贴默认动作期间把编辑器临时切换为contenteditable="plaintext-only",由 Chromium 原生完成纯文本粘贴并记录撤销项,事件结束后恢复普通编辑模式,不影响 Shift+Enter 自定义换行与上下文徽章;文件粘贴仍按附件处理,新增组件级回归测试覆盖文字与文件两条分支 - 修复用量索引文件被识别为假对话:
FileUsageIndexStore把索引写到{conversationId}.usage.json(与历史文件同级),而listConversations只排除了.meta.json,导致每个对话的.usage.json都被识别成假对话 ID(形如xxx.usage)显示在历史列表,点入报 "Metadata file is missing";现在文件识别同样排除.usage.json,只返回真实对话 ID(legacy{id}.json与 segmented{id}/目录),新增回归测试锁定该行为 - 修复 XML 工具调用解析安全(F-01):
fast-xml-parser升级到 5.10.1 后为解析器增加processEntities: false与maxNestedTags: 100,工具协议不再接受 DOCTYPE 自定义实体与超深嵌套输入;协议层额外过滤__proto__/constructor/prototype危险键名防原型污染,新增安全输入回归测试(数字字符串保持、实体不展开、深嵌套安全失败、危险键名拒绝) - 修复批量工具部分成功时 LLM 只看得到顶层错误(F-02):
serializeToolResultForLLM()错误分支不再丢弃data,data.results混合数组逐项格式化(避免 JSON 二次转义)、data.message与批量统计(successCount/failCount/totalCount)一并输出,data.output与取消标记保持原有格式;新增共享 formatter 回归测试覆盖 10 项场景 - 修复 XML 工具指南示例过时(F-03):
read_file的paths与write_file的files旧示例改为真实 schema(单文件path/ 批量files: [{ path, startLine?, endLine? }]/ 顶层path+content),XML/JSON 测试夹具同步更新为真实参数形状 - 修复
SubAgentRegistry.isEnabled()把未注册代理误判为启用(F-05):未注册代理现在返回 false - 修复注册的自定义 Sub-Agent executor 从未被调用(F-08):Registry 查询不再隐式创建并缓存默认 executor,正式工具调用路径优先使用显式注册的 executor;executor 请求新增
conversationId/conversationStore/promptModeSnapshot动态上下文并在每次调用透传 - 修复 Sub-Agent 跨对话接续泄漏(F-06):
continueFromRunId只允许接续当前主对话所属的 run,归属不一致时拒绝且错误信息不泄漏旧对话 ID 或内容 - 修复重载/内存淘汰后已持久化 run 无法接续(F-09):接续时内存快照未命中会只加载当前对话的持久化记录,恢复后仍执行归属与终态校验
- 修复全部配置代理禁用时
subagents工具被整体隐藏(F-10):ChannelManager/ToolDeclarationResolver统一使用「配置代理计数 > 0 或 General Worker 启用」的hasAvailableSubAgent()判断 - 修复 Windows 通知依赖链(F-07):移除已停更且有生产审计告警的
node-notifier,通知适配器改为 VS Code 原生showInformationMessage(操作按钮打开聊天、不阻塞工具调用),esbuild 不再复制原生包,npm audit --omit=dev归零 - 修复
.vscode/launch.json的Extension Tests指向不存在的测试入口:替换为可运行的 Jest 调试配置
Added
- 永久记忆设置新增默认开启的总开关;关闭后不再向系统提示词注入
{{$MEMORY}}内容,也不会向 AI 暴露 7 个 memory 工具,已有记忆、运行参数和自定义提示词保持不变并可继续在设置页管理,重新开启后恢复使用 read_file新增单次批量读取:保留path/startLine/endLine单文件调用,新增files: [{ path, startLine?, endLine? }],每个文本文件可独立指定行范围,结果按输入顺序汇总并保留部分失败详情;前端工具摘要与结果面板同步支持批量参数- 用量统计新增缓存维度:此前 Anthropic 的缓存写入(cache_creation_input_tokens)与缓存命中(cache_read_input_tokens)在 formatter 被合并成 cachedContentTokenCount 后明细即丢失,聚合器也从未读取该字段,统计里完全没有缓存信息;现在 usageMetadata 拆分保存 cacheCreationTokenCount / cacheReadTokenCount(Anthropic 分别映射写入与命中,OpenAI cached_tokens / Gemini cachedContentTokenCount 映射命中),流式累加器同步合并;aggregateUsageStats 总览 / 按对话 / 按模型 / 按天各维度新增缓存写入与缓存命中两个桶——缓存是 promptTokenCount 的细分(prompt 已含缓存部分),不重复计入 totalTokens;用量统计页总览卡片与明细行新增「缓存写入 / 缓存命中」展示(有值才显示),i18n 三语补齐,新增聚合与 formatter 断言测试
- 用量统计兼容旧数据缓存记录:旧版本只存缓存合并值(cachedContentTokenCount)无法拆分写入/命中,升级前的对话统计时近似全部记为缓存命中(OpenAI/Gemini 语义下该值本就是命中,Anthropic 实际以命中为主,偏差最小),避免旧对话的缓存贡献在统计中消失
- 用量统计性能优化:聚合由串行逐个读取改为限流并发(12 路);新增轻量读取接口 getMessagesRaw 绕过显示规范化与逐条深拷贝,只读统计所需的原始消息;handler 层新增进程内 5 分钟 TTL 结果缓存,短时间内重复打开统计页直接命中缓存,手动刷新(force)强制重算
- 用量统计性能优化新增消息级增量索引:全量扫描历史文件的开销随对话数增长(每次统计都要解析全部历史 JSON),现在消息落盘时同步维护每对话的用量索引({conversationId}.usage.json,只存消息级 token 明细,不存消息内容),统计时按历史文件与索引文件的 mtime 判定新鲜度——索引最新则直接聚合索引(完全不读历史文件),缺失/过期/损坏则回退读取历史并重建写回(一次性成本);任何历史写路径(编辑/删除/回滚/清空/导入/分支)都会更新历史 mtime 从而自动触发索引重建,无需逐一追踪写入口;删除对话时索引同步清理;索引写失败静默降级,不影响对话保存与统计正确性;新增索引构建/命中/重建/损坏回退/写失败降级测试
- 新增本轮安全与行为修复的回归测试:
toolResponseFormatter.test.ts(部分成功序列化)、subagentRegistry.test.ts(isEnabled 与 executor 语义)、subagentExecutorContinuation.test.ts(跨对话拒绝与持久化恢复)、windowsToastAdapter.test.ts(VS Code 原生通知适配器) - 优化了插件大小