feat(tools): edit_file old_string 不足3行升级为硬拒绝

- 单条/多组替换路径统一:old_string 少于3行直接报错拒绝执行,不再仅提示后放行
- 移除 replace_all 批量替换场景的单行豁免,工具描述同步改为硬性表述
- i18n 文案更新(中英):replace_short_old_notice -> replace_old_text_too_short,清理失效的 many_short_notice

Co-authored-by: Astrion powered by Kimi-K3 <astrion-agent@users.noreply.github.com>
This commit is contained in:
JOJO 2026-09-10 19:14:36 +08:00
parent a997c04cda
commit f78fd7442c
3 changed files with 17 additions and 19 deletions

View File

@ -247,7 +247,7 @@ class ToolsDefinitionFileToolsMixin:
"properties": { "properties": {
"old_string": { "old_string": {
"type": "string", "type": "string",
"description": "要替换的文本(需与文件内容精确匹配,保留缩进;建议提供至少3行提升定位稳定性。需要批量替换的场景可以单行或不足一行)" "description": "要替换的文本(需与文件内容精确匹配,保留缩进;必须提供至少3行内容包含目标行及其前后上下文不足3行将被拒绝执行)"
}, },
"new_string": { "new_string": {
"type": "string", "type": "string",

View File

@ -73,7 +73,12 @@ class ReplaceMixin:
"error": tr("file_manager.replace_new_text_too_long"), "error": tr("file_manager.replace_new_text_too_long"),
"suggestion": "请将大内容分成多个小的替换操作" "suggestion": "请将大内容分成多个小的替换操作"
} }
short_old_text_notice = bool(old_text and len(old_text.splitlines()) < 3) if old_text and len(old_text.splitlines()) < 3:
return {
"success": False,
"error": tr("file_manager.replace_old_text_too_short"),
"suggestion": "请在 old_string 中包含目标行及其前后上下文至少3行后重试"
}
# 检查是否包含要替换的内容 # 检查是否包含要替换的内容
if old_text and old_text not in content: if old_text and old_text not in content:
@ -111,11 +116,6 @@ class ReplaceMixin:
lines=line_text, lines=line_text,
count=count, count=count,
)) ))
if short_old_text_notice:
message_parts.insert(
0,
tr("file_manager.replace_short_old_notice")
)
if message_parts: if message_parts:
result["message"] = "".join(message_parts) result["message"] = "".join(message_parts)
print(f"{OUTPUT_FORMATS['file']} 替换了 {count} 处内容") print(f"{OUTPUT_FORMATS['file']} 替换了 {count} 处内容")
@ -144,7 +144,6 @@ class ReplaceMixin:
failed_details: List[Dict[str, Any]] = [] failed_details: List[Dict[str, Any]] = []
total_replacements = 0 total_replacements = 0
total_found_matches = 0 total_found_matches = 0
short_old_text_indices: List[int] = []
for zero_based_index, item in enumerate(replacements): for zero_based_index, item in enumerate(replacements):
index = zero_based_index + 1 index = zero_based_index + 1
@ -230,7 +229,13 @@ class ReplaceMixin:
break break
if len(old_text.splitlines()) < 3: if len(old_text.splitlines()) < 3:
short_old_text_indices.append(index) detail.update({
"status": "error",
"reason": "old_string 少于3行请包含目标行及其前后上下文至少3行后重试"
})
failed_details.append(detail.copy())
details.append(detail)
break
matched_lines = self._find_match_line_numbers(current_content, old_text) matched_lines = self._find_match_line_numbers(current_content, old_text)
found_count = len(matched_lines) found_count = len(matched_lines)
@ -300,9 +305,6 @@ class ReplaceMixin:
groups=len(replacements), groups=len(replacements),
replacements=total_replacements, replacements=total_replacements,
)] )]
if short_old_text_indices:
indices_text = ",".join(str(item) for item in short_old_text_indices)
message_parts.append(tr("file_manager.replace_many_short_notice", indices=indices_text))
write_result["message"] = "".join(message_parts) write_result["message"] = "".join(message_parts)
print(f"{OUTPUT_FORMATS['file']} 批量替换了 {total_replacements} 处内容") print(f"{OUTPUT_FORMATS['file']} 批量替换了 {total_replacements} 处内容")
return write_result return write_result

View File

@ -258,16 +258,12 @@ MESSAGES = {
"zh-CN": "发现{found}处,于{lines}行共替换{count}", "zh-CN": "发现{found}处,于{lines}行共替换{count}",
"en-US": "Found {found} matches; replaced {count} at lines {lines}", "en-US": "Found {found} matches; replaced {count} at lines {lines}",
}, },
"file_manager.replace_short_old_notice": { "file_manager.replace_old_text_too_short": {
"zh-CN": "提示old_string 少于3行已继续执行需要批量替换的场景可以单行或不足一行", "zh-CN": "old_string 少于3行为确保精确匹配请提供至少3行内容包含目标行及其前后上下文",
"en-US": "Note: old_string is shorter than 3 lines; execution continued. For batch replacement, use single-line or shorter strings", "en-US": "old_string has fewer than 3 lines: to ensure precise matching, provide at least 3 lines including the target line and its surrounding context",
}, },
"file_manager.replace_many_summary": { "file_manager.replace_many_summary": {
"zh-CN": "{groups} 组替换,替换 {replacements}", "zh-CN": "{groups} 组替换,替换 {replacements}",
"en-US": "{groups} groups processed; {replacements} replacements made", "en-US": "{groups} groups processed; {replacements} replacements made",
}, },
"file_manager.replace_many_short_notice": {
"zh-CN": "提示:第 {indices} 组 old_string 少于3行已继续执行",
"en-US": "Note: old_string in groups {indices} is shorter than 3 lines; execution continued",
},
} }