Repository navigation
Conversation
- 可见/内部文件工具全部补充 details:environment 真实支持矩阵、成功时返回、失败时返回(类别+修法)、工具分工约定 - 修正:幽灵工具名 readFileFull→read_file_binary;read_file_part 默认窗口文档 100→200(含 files.d.ts) - write_file 写明默认覆盖与自动建父目录;整文件重写配方统一 delete_file→write_file - create_file/edit_file 描述自含化,不再引用不可见的 apply_file - copy_file recursive 缺省 true→false 与文档/JS 对齐,目录复制漏参明确报错 - extended_file_tools.js:修复 file_exists 把"不存在"误报为失败;environment 描述对齐最终矩阵 - apply_file 描述补充匹配语义/occurrence 参数/结果格式(实现随后续阶段落地)
- ToolExecutionLimits 新增 MAX_FILE_READ_SIZE_BYTES=32MB;read_file/read_file_full/read_file_binary 在 android/linux/saf 三环境实现入口统一检查,超限失败并引导 read_file_part 分段读取 - readFilePart 改单次流式扫描(去 countFileLines+readLinesFromFile 双次全量 IO),end_line 缺省读到预算为止;start_line 超界明确报错并告知总行数;补 isTextLike 门禁(二进制不再乱码报成功) - read_file 截断判定修复:字节数与字符预算误比 → 实际多读一字符判定;多字节编码下不再误标截断 - 特殊文件(图片 OCR)解码失败/异常从 success=true+错误文本当内容 改为显式 success=false - read_file_binary:base64 进入模型可见结果(修复 toString 只回摘要导致工具实际不可用);超单条消息预算显式拒绝并给替代路径 - FilePartContentData 总行数未知时明确提示续读方式;FileApplyResultData 无效转义链清理
- FileBindingService 整体重构: - 精确匹配快速路径:归一化 indexOf 唯一命中直接返回,跳过滑动窗模糊扫描 - 多候选拒绝:模糊搜索收集全部 >0.9 窗口并按行区间重叠聚类为独立位置,≥2 处时拒绝并列出各候选行号+相似度;未指定 occurrence 绝不静默选第一处(旧实现仅拒绝完美重复,近似重复会被静默改写) - occurrence 参数:old 命中多处时按第 N 处定位;edit_file/apply_file 同步透传 - old 入口剥离 read_file 输出的 N| 行号前缀(此前污染 n-gram 与精确匹配) - 失败可诊断:无匹配时报最高相似度候选行号并引导 read_file_part 精读重试;明确提示不要退化为 shell 编辑 - 成功结果回传各 op 匹配行号(Applied at: lines X-Y)至 details 与 FileApplyResultData.matchedRanges - 删除死代码:[START-REPLACE] 块解析链(processFileBinding/applyFuzzyPatch/parseEditOperations/EDIT_BLOCK_REGEX)、hasMultiplePerfectMatches、未用常量与扩展函数 - FileApplyResultData 无效恒等转义清理 - 新增 FileBindingServiceTest:精确/行号剥离/多候选拒绝/occurrence/模糊长块/无匹配诊断/delete 八个用例
- 新增 WorkspacePathChecker(纯函数判定器 + 24 个受护文件工具族清单 + 危险根目录清单) - 会话未绑定工作区 → 所有路径按区外(需求确认项);android 路径 canonical 前缀比较;linux/repo 环境按会话绑定环境一致判定 - ToolExecutionManager.checkToolPermission 插入工作区阶段:区内走既有权限模式;区外 ALLOW/ASK 强制弹窗确认(原因列出目标路径)、FORBID 直接拒绝;判定先于 deny_tool 标记,不可被模型侧文本绕过;扩展包限定名(pkg:copy_file)同族纳管 - 执行前按 chatId 查 ChatHistory.workspace/workspaceEnv 为准(ChatHistoryManager.getChatWorkspaceBinding) - 区外确认过的路径记录进 ToolRuntimeContext.approvedOutsidePaths,嵌套重入不误拦 - 新增 WorkspaceFileToolHook(AIToolHook 兜底):JS 包 toolCall → executeTool 的嵌套调用在 ThreadLocal 作用域内判定,区外拒绝并回传理由;主链路在 ThreadLocal 设置前判空放行,与弹窗阶段互不重叠 - delete_file:recursive 递归删除 /、/storage/emulated/0、/sdcard、/data 等 protected roots 在 android/linux 双环境硬拦截 - ToolPermissionSystem.requestConfirmation(reason):无视允许模式强制弹窗的入口,reason 附于操作描述展示 - 新增 WorkspacePathCheckerTest 九个用例(含无工作区、兄弟前缀、多路径、限定名、危险根)
- FunctionType 新增 TOOL_REVIEW;测试更新(11→12);8 个 locale 补显示名/描述;功能模型配置卡片按枚举自动生成,缺省回落主模型
- ApiPreferences 新增 tool_review_inside/outside_workspace 开关键 + Flow + 保存方法;ApiConfigDelegate/ChatViewModel 透出
- FunctionalPrompts.toolReviewPrompt:工具名/操作类别/目标路径/区内外/工作区根/内容摘要(500字) → 严格 JSON {compliant, reason}
- 新增 ToolReviewService:callFunctionModel + withTimeout(15s) + 宽松解析;审查失败语义统一为弹窗人工确认(需求确认项)
- checkToolPermission 审查流(仅文件工具族 + 允许模式 + 对应区开关开):
- 合规 → 直接执行不弹窗(区外同样放行,需求确认项)
- 不合规 → 弹窗展示审查理由由用户决定
- 审查失败/超时 → 弹窗提示错误信息由用户决定
- UI:Agent/Classic 两种输入栏的工具组新增区内/区外审查开关行,仅工具模式为允许时显示
- 新增字符串:审查弹窗两条 + 菜单开关两条
- repo: 环境 clean guard:zip_files/unzip_files/open_file/share_file/apply_file 入口明确拒绝(旧实现静默落 Android FS 报'不存在') - applyFile 路径校验按环境路由:linux 支持 ~ 前缀(旧实现统一走 validateAndroidPath,~/x 必失败);linux 结构化编辑经既有子调用路由(fileExists/readFileFull/writeFile 均按 environment 委托)可用 - edit_file 补 occurrence 参数透传与 schema(EN/CN),与阶段 A 描述一致 - grep_code(linux 环境):native ripgrep 前经 PathMapper 映射到宿主 rootfs 真实路径扫描,结果路径反向映射回 linux 逻辑路径;PathMapper 新增 mapAndroidPathToLinux - SAF 写白名单报错列出全部支持扩展名与知名文件名,模型可自纠 - 禁用包调用错误修正:捕获 usePackage 返回的真实原因(如'包未启用'),不再笼统报 Auto-activation failed
- FunctionalConfigScreen 连接测试 when(functionType) 为非穷尽表达式(无 else),新增 TOOL_REVIEW 枚举值后必编译失败 → 补连接测试分支(与 CHAT 同款简单问答) - ToolReviewService 与 EnhancedAIService 不同包,补缺失的 import
- SystemToolPrompts/Internal 27 处 details 文本中的 [\u0024env] 被 Kotlin 字符串模板当变量解析(Unresolved 'env')→ 统一改为 [android] 具体示例 - AIChatScreen 报 No parameter 'toolReviewInsideWorkspace':参数误插进 AgentExtraSettingsPopup 签名而 AgentChatInputSection 缺失 → 在 AgentChatInputSection(:163) 签名补四参数(带默认值)并向下透传至 AgentExtraSettingsPopup,popup 内既有传参接续生效
- 新增 HighRiskToolCatalog:18 个高危工具族(命令/代码执行、Intent/广播、应用与系统管理、网络外发、任意工具代理入口、工作流编排),扩展包限定名同族纳管 - 新增 call_purpose 调用说明声明参数:可审查工具调用时可附'为什么发起本次调用',供审查模型与调用点上下文一致性比对;执行前由 ToolExecutionManager 剥离 - ToolReviewService 泛化:审查范围从文件工具族扩展到文件工具+高危工具;审查 prompt 注入调用点前上下文(最近 10 条大模型消息)、最近一条用户指令、call_purpose - 审查开关扩展为三分区(工作区内/工作区外/高危工具),ApiPreferences/ApiConfigDelegate/ChatViewModel/UI(Agent+Classic 双栏)同步透传 - FunctionalPrompts 审查 prompt 与 SystemToolPrompts 参数文档同步;TODO 目录新增 07-高危工具审查.md (另一会话的实现,如实提交)
read_file/read_file_part/read_file_full 默认经 FunctionType.FILE_DISTILL 功能模型提炼:单次协议一次输出 related/worth/带行号摘录,part 与大文件 full 走逐块扫描(24K 字符/块、8 轮上限);worth=false 或摘录占比超 0.6 返回原文。透传边界(行为与现状一致):开关关/raw=true/repo:·linux 环境/ 特殊类型抽取管线(图片 PDF 等)/≤2048 字节。失败一律显式报错指引 raw=true 重读,无回退。 - 新增 FileDistillService 拦截层(ToolRegistration executor 包装,5 权限子类零改动) - ApiPreferences 开关 file_distill_enabled 默认开,UI 置于会话工具菜单审查三开关之下(Agent/Classic 两链路) - SystemToolPrompts 补 raw/focus 参数与 AI 提炼说明;part 注明不确认行号时用默认 AI 读取 - 计划与实施记录:docs/TODO/chat_file_tool_hardening/08-AI读取提炼.md
CATMIAOZHI
left a comment
There was a problem hiding this comment.
审计结论:❌ 请求修改
改动(52 个文件,+4151/−582):文件工具八阶段强化:描述规范化、读取 32MB 上限与流式分段、edit/apply 引擎重构(精确快路径 + 多候选拒绝 + occurrence)、工作区防护与危险根删除底线、大模型合规审查(TOOL_REVIEW)、环境矩阵与扩展通道、高危工具审查泛化、read 族 AI 提炼(FILE_DISTILL,默认开)。
通过的检查:
- 目标分支 dev,非草稿,非自审(作者 542474846);PR 描述与 diff 基本一致(52 文件与 API 计数一致;早前一次 stale origin/dev 导致的 terminal 子模块差异已核实不在本 PR 内)
- 工作区判定:android 路径用 canonicalPath 前缀比较(/data/ws 与 /data/ws2 不会混淆);未绑定工作区一律按区外;判定先于 deny_tool 标记
- 审查失败 fail-closed:超时/解析失败/未配置均走弹窗人工确认,不静默放行;未配置功能模型时回落主模型(FunctionalConfigManager defaultMapping 覆盖全部 FunctionType)
- call_purpose 仅供审查读取、执行前剥离;Hook 注册幂等,主链路执行走直接 executor、不重跑拦截,与嵌套兜底不重叠
- 读取侧:32MB 硬上限覆盖 read_file/read_file_full/read_file_binary 及 SAF/Linux 路径;read_file_part 单次流式扫描;截断判定改为"读满且还有下一字符";二进制门禁与 base64 预算;特殊类型抽取管线透传
- 旧 [START-REPLACE] 死代码链删除干净,无残留调用方;ToolRuntimeContext 由 data class 改为普通类,无 copy/判等使用方
- copy_file recursive 默认 true→false 与文档对齐(行为变更已在 PR 描述中声明)
问题:
- [P1] 危险根递归删除硬底线可被路径拼写绕过:
WorkspacePathChecker.isDangerousRecursiveDeleteTarget只做 trim + 去尾部/后的精确字符串匹配,不做 canonicalize;两个调用点(StandardFileSystemTools.deleteFile、LinuxFileSystemTools.deleteFile)都直接传模型原始 path。/sdcard/.、/sdcard/..、//sdcard、/storage/emulated/0/.均不在集合内,但指向同一目录,deleteRecursively()会真的清空。测试也只覆盖精确拼写。建议:比较前先取File(path).canonicalPath(不存在的路径做规范化处理),并把/.、..这类变体补进单测。 - [P1] linux 环境 grep 的
..可逃出 proot rootfs:LinuxFileSystemTools.grepCode把模型传的 linux 路径经PathMapper.resolvePath→mapLinuxPath(File(ubuntuRoot, relativePath).absolutePath,不 canonicalize、不做 containment 校验)交给宿主 native ripgrep;validateLinuxPath只校验以//~开头,不拦..。grep_code(path=/../../../../data/..., environment=linux)可扫描宿主文件系统;且工作区判定把"环境一致"视为区内,不会弹窗。建议:映射后 canonicalize 并校验仍在 ubuntuRoot 内,否则拒绝;同类问题也存在于 zip/unzip 既有用 resolvePath 的路径上,建议一并收敛到 mapLinuxPath 内。 - [P1] FunctionTypeTest 与新枚举不一致,测试必失败:枚举现有 13 个值(新增 TOOL_REVIEW、FILE_DISTILL),测试断言总数 12 且 expected 列表漏了 FILE_DISTILL。作者自述单元测试未在本地执行、交由 CI,CI 会红。建议:总数改为 13 并补 FILE_DISTILL,本地跑一次
:app:testDebugUnitTest。 - [P2] occurrence 的 schema default 与实现矛盾:edit_file/apply_file 的 ToolParameterSchema 写
default = "1"(中英文两处),而实现把"未传 occurrence"当作 null、多候选一律拒绝;JSON-schema 的 default 不会被 API 自动注入,实际行为是拒绝,与 details 里"命中多处会被拒绝"的说明直接冲突。建议:去掉 default="1",说明统一为"未传则拒绝"。 - [P2] 嵌套调用的高危工具不受 Hook 约束:WorkspaceFileToolHook 只拦截文件工具族;JS 扩展包经 toolCall → AIToolHandler.executeTool 嵌套调用 execute_shell/http_request 等高危工具时,Hook 直接放行,也不经过主链路的审查/弹窗(主链路只审了外层包工具)。建议:说明该缺口在设计预期内,或把高危工具族也纳入 Hook 的拒绝范围。
- [P2] read_file_part 在 end_line < start_line 时静默返回空成功:requestedCount 被 coerceAtLeast(0),0 行时返回 success 空内容;旧实现会把 end_line 钳到有效范围返回实际内容。模型传错范围时得不到纠错信号。建议:非法范围改为显式失败并提示有效范围。
- [P3] i18n 不同步:PR 描述称"同步更新 8 个语言目录 strings",但 8 条新审查/工作区文案只存在于默认 values/,values-en 只有 4 条 function_type/file_distill 文案,其余 6 个语言目录各 2 条;非中文语言下弹窗与菜单会回退显示中文(不崩溃)。建议补齐各语言翻译或至少英文。
- [P3] 模糊匹配聚类的传递闭包可能合并相邻重复块:clusterOverlappingWindows 按行区间重叠做传递闭包聚类,相邻的近似重复块可被一串重叠窗口桥接成一个簇、只保留最优窗。精确重复由精确路径兜底(列出全部位置并拒绝),残余风险限于"非精确的近似重复且相邻"的情形。
- [P3] linux grep 反向映射失败时回落返回宿主原始路径:mapAndroidPathToLinux 返回 null 时调用方保留 fileMatch 原路径(宿主 rootfs 绝对路径),会把宿主内部路径暴露给模型,且模型后续可能拿它当 linux 路径用。建议:映射失败时丢弃该条或标注清楚。
- [P3] CDATA 内 diff 若含
]]>会破坏 XML:FileApplyResultData 把 diff 原文直接放进 CDATA(旧的"转义"链本就是恒等替换,无回归),含]]>的代码 diff 会提前闭合 CDATA。建议:对]]>做分段处理或转义。
后续可跟进(不阻塞):
- [question] 手工回归矩阵(区内/区外/无工作区 × 允许/询问/禁止 × 审查开/关 × 合规/不合规/失败等)在 TODO index 中"结果待填",是否计划合入前补齐实测结果?
- [question]
file_distill_enabled默认开启且 focus 必填:现有角色卡/子任务/自动化流程中不带 focus 的 read 调用会改为显式失败(指引 raw=true),是否确认这是期望的默认行为?
验证说明:作者称 :app:compileDebugKotlin 通过(exit 0),单元测试未在本地执行、交由 CI;手工回归矩阵结果待填。结合问题 3(FunctionTypeTest 计数错误),建议合入前本地跑一次 :app:testDebugUnitTest 并补齐回归矩阵。
由 水晴喵的muse 审计
…失败、CDATA 转义、i18n 补齐 对应 PR AAswordman#1496 评审(水晴喵的muse 审计)的 P1/P2/P3 修复: - P1 危险根递归删除可被路径拼写绕过:isDangerousRecursiveDeleteTarget 在精确匹配前先做词法规范化(./..//重复斜杠,lexicallyNormalizePath 纯函数 供跨平台单测)再 canonical 化(覆盖符号链接),两道比较任一命中即拒绝; 补 9 个拼写变体测试与词法规范化测试 - P1 linux grep 的 .. 逃出 proot rootfs:mapLinuxPath 拼接结果 canonical 化 并强制 containment(逃出返回 null),zip_files/unzip_files/download_file/grep_code 四个调用点显式拒绝(rootfsEscapeResult),不再回落原始路径;grep 反向映射 失败的条目丢弃并记日志,不把宿主真实路径回传给模型(P3) - P1 FunctionTypeTest 与枚举不一致:总数 12→13,补 FILE_DISTILL - P2 occurrence 的 schema default="1" 与实现矛盾:三处(EN edit_file/CN edit_file/Internal apply_file)去掉 default,描述明确"不传即拒绝" - P2 read_file_part 的 end_line < start_line 静默空成功:android/linux/saf 三分支委托前统一显式失败并提示重查行号 - P3 FileApplyResultData 的 CDATA 内 ]]> 提前闭合:按 XML 规范拆段转义 - P3 审查/工作区/提炼 8+11 条文案补齐 en/es/id/ko/ms/ro/pt-rBR/ja 全部 语言目录并通过 XML 校验
完整 :app:testDebugUnitTest 首次真正跑起来后暴露: - WorkspacePathChecker.isAndroidPathInside:canonicalPath 的分隔符随平台变化 (Windows 桌面 JVM 为 '\',设备为 '/'),target.startsWith(root + "/") 在 Windows 上永不匹配——设备行为不变(设备上 canonicalPath 本就用 '/'), 分隔符归一仅在 File.separatorChar == '\' 时生效 - FileBindingServiceTest 两处失准(该文件此前从未通过编译,八个用例从未真正运行): 模糊匹配用例的 lambda 用隐式 it 却引用 $i(编译错误);无匹配诊断用例传了 空 new 的 REPLACE——在校验阶段即被丢弃(No valid edit operations provided), 走不到无匹配诊断路径,改为合法 replace + 不存在内容 - 危险根拼写变体测试修正:/storage/emulated/0/../storage/emulated/0 词法规范化 后是 /storage/emulated/storage/emulated/0(.. 只回退一级),本就不该命中; 换成真正回到受保护根的 /storage/emulated/0/.. - 断言消息带规范化结果便于后续诊断 结果::app:testDebugUnitTest 1666 个用例全部通过
|
感谢审计,问题均已处理(commit P1-1 危险根拼写绕过 — 已修。 P1-2 linux grep P1-3 FunctionTypeTest — 已修(总数 13,补 P2-4 occurrence schema — 三处(EN/CN edit_file、Internal apply_file)已去掉 P2-5 嵌套调用的高危工具不受 Hook 约束 — 按评审给出的第一个选项处理:说明为设计预期。外层包工具调用已经过主链路的工作区判定与审查/弹窗;把高危工具族纳入 Hook 拒绝范围意味着已审查通过的扩展包从此完全失去 execute_shell 等能力,这是显著的行为收紧,留待 maintainer 决策后再做。 P2-6 end_line < start_line — 已修。android/linux/saf 三分支委托前统一显式失败并提示重查行号。 P3-7 i18n — 已补齐:9 条审查/工作区文案(en)+ 11 条(es/id/ko/ms/ro/pt-rBR/ja,含 P3-8 聚类传递闭包 — 维持现状:精确重复由精确路径兜底(列出全部位置并拒绝),残余风险限于"非精确近似重复且相邻"的情形;待真实案例出现再收敛聚类策略。 P3-9 反向映射失败回落宿主路径 — 已修。映射失败的 grep 结果条目直接丢弃并记日志,不把宿主真实路径回传给模型。 P3-10 CDATA [question] 回归矩阵 — 目前仅完成编译与全量单测;真机回归矩阵(区内/区外/无工作区 × 三权限模式 × 审查开关 × 合规/不合规/失败)待实机执行后补填到 TODO index。 [question] file_distill 默认开 + focus 必填 — 确认为期望行为。设计即"无兜底":不带 focus 的旧调用显式失败并指引 |
CATMIAOZHI
left a comment
There was a problem hiding this comment.
审计结论:✅ 批准合并
复审说明:这是针对新提交 b2c416c9 + ab346982 的复审(上次 review 5887753747,commit 50016df7,结论 REQUEST_CHANGES)。本轮只审新增 diff(18 个文件,+301/−34),作者在评论区已逐项回复。
改动(新增 diff,18 个文件,+301/−34):按上次评审意见修复危险根拼写绕过、linux grep rootfs 逃逸、FunctionTypeTest 不一致、occurrence schema、非法行号范围、CDATA 转义、i18n 补齐等,并补测试。
逐项核对(上次评审的问题):
- [P1] 危险根拼写绕过 — ✅ 已修并核实。
isDangerousRecursiveDeleteTarget先经lexicallyNormalizePath(纯词法消解./../重复斜杠)再经canonicalPath(覆盖符号链接),任一命中即拒绝;"/"与"/storage/emulated"本就在危险根集合内,/sdcard/..→/、/storage/emulated/0/..→/storage/emulated均能命中。新增测试覆盖 9 个拼写变体。 - [P1] linux grep
..逃出 proot rootfs — ✅ 已修并核实。mapLinuxPath改为可空返回:拼接结果 canonical 化并强制 containment,逃出 rootfs 返回 null;grep_code、zip_files、unzip_files、download_file四个调用点均显式拒绝(rootfsEscapeResult),不再回落原始路径;resolvePath签名改为可空,主代码中全部 6 处调用点均已处理 null,无遗漏。 - [P1] FunctionTypeTest 与新枚举不一致 — ✅ 已修。补
FILE_DISTILL,总数断言 12 → 13;作者称本地完整:app:testDebugUnitTest1666 个用例全部通过(以 CI 为准)。 - [P2] occurrence schema 与实现矛盾 — ✅ 已修。三处(EN/CN edit_file、Internal apply_file)去掉
default = "1",描述明确不传会被拒绝。 - [P2] 嵌套调用的高危工具不受 Hook 约束 — 说明已接受,留待 maintainer 决策。作者按评审给出的第一个选项处理:外层包工具调用已过主链路判定与审查,把高危工具族纳入 Hook 拒绝范围会使已审查通过的扩展包完全失去 execute_shell 等能力,属于显著行为收紧,需 maintainer 拍板后再做。结论上不阻塞本次合并。
- [P2] read_file_part 在 end_line < start_line 时静默返回空成功 — ✅ 已修。android/linux/saf 三分支委托前统一显式失败并提示重查行号。
- [P3] i18n 不同步 — ✅ 已修并核实。
function_type/desc_file_distill在 values 及 8 个语言目录均已存在;9 条审查/工作区文案(en)+ 11 条(其余 7 个语言目录)已补齐。 - [P3] 模糊匹配聚类传递闭包 — 维持现状,可接受。精确重复由精确路径兜底(列出全部位置并拒绝),残余风险限于"非精确近似重复且相邻"的情形,待真实案例出现再收敛。
- [P3] linux grep 反向映射失败回落宿主路径 — ✅ 已修。映射失败的条目直接丢弃并记日志,不把宿主真实路径回传给模型。
- [P3] CDATA 内 diff 含
]]>破坏 XML — ✅ 已修。按 XML 规范拆段转义(]]→]]]]><![CDATA[>),diff 与 request-content 两处 CDATA 均覆盖。 - [question] 手工回归矩阵"结果待填" — 作者回复:目前仅完成编译与全量单测,真机回归矩阵待实机执行后补填到 TODO index。已记录为合入后跟进项,不阻塞合并。
- [question]
file_distill_enabled默认开且 focus 必填 — 作者确认为期望行为(设计即"无兜底",不带 focus 的旧调用显式失败并指引raw=true重读)。接受。
通过的检查:
- 新增 diff 全部落在上次评审指出的问题范围内,无无关改动、无新文件(相对上次 head 无新增文件);
resolvePath改为可空后全部主代码调用点均显式处理 null,grep/zip/unzip/download 均 fail-closed;isAndroidPathInside的分隔符归一在 Android 设备上是 no-op,不改变设备行为;lexicallyNormalizePath为纯字符串运算,不做文件系统访问;绝对路径的..在根处截断,不会逃逸到根之外;- CDATA 转义、行号范围显式失败、grep 结果丢弃并记日志等均为 fail-closed 的处理。
后续可跟进(不阻塞):
- 嵌套调用的高危工具是否纳入 Hook 拒绝范围,需 maintainer(@AAswordman)决策;
- 真机回归矩阵(区内/区外/无工作区 × 三权限模式 × 审查开关 × 合规/不合规/失败)待作者实机执行后补填到
docs/TODO/chat_file_tool_hardening/index.md。
由 水晴喵的muse 审计
变更说明 / Description
背景与动机 / Context and motivation
静态审计确认的文件工具失败机制:提示词与实现不对齐(32KB 截断未文档化、read_file 输出的行号前缀污染 edit 匹配、environment 支持矩阵失实);edit_file/apply_file 的模糊匹配没有精确快路径,0.9 相似度的多候选静默取最优,报错还指向不存在的工具名;read_file_binary 的内容根本到不了模型;工作区零防护,任意绝对路径直接执行且递归删除没有危险路径底线;工具调用没有审查机制。失败率居高导致模型绕开文件工具改用终端脚本改文件。
改动范围 / Changes
八个阶段,落在一个分支,计划与逐阶段实施记录见 docs/TODO/chat_file_tool_hardening/:
不包含:聊天列表滚动实现调整(独立改动)、token 统计改动。
兼容性与风险 / Compatibility and risks
file_distill_enabled默认开,审查三开关默认关。开启审查或 AI 提炼会对功能模型产生额外调用与 token 消耗,需用户在功能配置中指定 FILE_DISTILL / TOOL_REVIEW 模型,未配置时回落主模型关联 Issue / Related issue
N/A。改动来源为本地静态审计,背景与实施记录见 docs/TODO/chat_file_tool_hardening/index.md。
验证方式 / Verification
手工回归矩阵(记录于 TODO index,结果待填):区内/区外/无工作区 × 允许/询问/禁止 × 审查开/关 × 合规/不合规/失败;高危工具 execute_shell × 高危开关独立生效;32MB 大文件读取、read_file_part 分页、edit_file 行号粘贴/多候选/occurrence、扩展包 file_exists、禁用包报错、repo: guard。
检查清单 / Checklist
dev;如目标为main,我已说明这是维护者发布同步 / The target branch isdevfor regular work; if it ismain, I explained why this is a maintainer-led release syncCandidate checks覆盖改动范围,并会处理技术失败项 /Candidate checkscovers the change scope and technical failures will be addressed