mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
feat: optimize editing tools
This commit is contained in:
@@ -305,8 +305,8 @@ def _build_memory_section(memory_manager: Any, tools: Optional[List[Any]], langu
|
|||||||
"",
|
"",
|
||||||
"在回答关于以前的工作、决定、日期、人物、偏好或待办事项的任何问题之前:",
|
"在回答关于以前的工作、决定、日期、人物、偏好或待办事项的任何问题之前:",
|
||||||
"",
|
"",
|
||||||
"1. 不确定信息位置 → 先用 `memory_search` 通过关键词和语义检索相关内容",
|
"1. 不确定记忆文件位置 → 先用 `memory_search` 通过关键词和语义检索相关内容",
|
||||||
"2. 已知文件和大致位置 → 直接用 `memory_get` 读取相应的行",
|
"2. 已知文件位置 → 直接用 `memory_get` 读取相应的行",
|
||||||
"3. search 无结果 → 尝试用 `memory_get` 读取最近两天的记忆文件",
|
"3. search 无结果 → 尝试用 `memory_get` 读取最近两天的记忆文件",
|
||||||
"",
|
"",
|
||||||
"**记忆文件结构**:",
|
"**记忆文件结构**:",
|
||||||
@@ -317,10 +317,10 @@ def _build_memory_section(memory_manager: Any, tools: Optional[List[Any]], langu
|
|||||||
"- 自然使用记忆,就像你本来就知道; 不用刻意提起或列举记忆,除非用户提起相关内容",
|
"- 自然使用记忆,就像你本来就知道; 不用刻意提起或列举记忆,除非用户提起相关内容",
|
||||||
"",
|
"",
|
||||||
"**写入记忆的正确方式**:",
|
"**写入记忆的正确方式**:",
|
||||||
"- 追加到现有文件末尾 → 用 `read` 读取文件最后几行(offset=-10),然后用 `edit` 追加",
|
"- 追加到现有文件末尾 → 用 `edit` 工具,oldText 留空",
|
||||||
" 例: read(path=memory/2026-02-01.md, offset=-10) → 看到最后内容 → edit(oldText=最后几行完整文本, newText=最后几行+新内容)",
|
" 例: edit(path=memory/2026-02-01.md, oldText=\"\", newText=\"\\n## 新内容\\n...\")",
|
||||||
|
"- 修改文件中的某段文字 → 用 `edit` 工具,oldText 填写要替换的文本",
|
||||||
"- 创建新文件 → 用 `write`",
|
"- 创建新文件 → 用 `write`",
|
||||||
"- ⚠️ 不要用 `memory_get` 读取后再 `edit`,因为会截断长文本",
|
|
||||||
"",
|
"",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Edit(BaseTool):
|
|||||||
"""Tool for precise file editing"""
|
"""Tool for precise file editing"""
|
||||||
|
|
||||||
name: str = "edit"
|
name: str = "edit"
|
||||||
description: str = "Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits."
|
description: str = "Edit a file by replacing exact text, or append to end if oldText is empty. For append: use empty oldText. For replace: oldText must match exactly (including whitespace)."
|
||||||
|
|
||||||
params: dict = {
|
params: dict = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -33,7 +33,7 @@ class Edit(BaseTool):
|
|||||||
},
|
},
|
||||||
"oldText": {
|
"oldText": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Exact text to find and replace (must match exactly, cannot be empty). To append to end of file, include the last few lines as oldText."
|
"description": "Text to find and replace. Use empty string to append to end of file. For replacement: must match exactly including whitespace."
|
||||||
},
|
},
|
||||||
"newText": {
|
"newText": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -89,34 +89,45 @@ class Edit(BaseTool):
|
|||||||
normalized_old_text = normalize_to_lf(old_text)
|
normalized_old_text = normalize_to_lf(old_text)
|
||||||
normalized_new_text = normalize_to_lf(new_text)
|
normalized_new_text = normalize_to_lf(new_text)
|
||||||
|
|
||||||
# Use fuzzy matching to find old text (try exact match first, then fuzzy match)
|
# Special case: empty oldText means append to end of file
|
||||||
match_result = fuzzy_find_text(normalized_content, normalized_old_text)
|
if not old_text or not old_text.strip():
|
||||||
|
# Append mode: add newText to the end
|
||||||
if not match_result.found:
|
# Add newline before newText if file doesn't end with one
|
||||||
return ToolResult.fail(
|
if normalized_content and not normalized_content.endswith('\n'):
|
||||||
f"Error: Could not find the exact text in {path}. "
|
new_content = normalized_content + '\n' + normalized_new_text
|
||||||
"The old text must match exactly including all whitespace and newlines."
|
else:
|
||||||
|
new_content = normalized_content + normalized_new_text
|
||||||
|
base_content = normalized_content # For verification
|
||||||
|
else:
|
||||||
|
# Normal edit mode: find and replace
|
||||||
|
# Use fuzzy matching to find old text (try exact match first, then fuzzy match)
|
||||||
|
match_result = fuzzy_find_text(normalized_content, normalized_old_text)
|
||||||
|
|
||||||
|
if not match_result.found:
|
||||||
|
return ToolResult.fail(
|
||||||
|
f"Error: Could not find the exact text in {path}. "
|
||||||
|
"The old text must match exactly including all whitespace and newlines."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Calculate occurrence count (use fuzzy normalized content for consistency)
|
||||||
|
fuzzy_content = normalize_for_fuzzy_match(normalized_content)
|
||||||
|
fuzzy_old_text = normalize_for_fuzzy_match(normalized_old_text)
|
||||||
|
occurrences = fuzzy_content.count(fuzzy_old_text)
|
||||||
|
|
||||||
|
if occurrences > 1:
|
||||||
|
return ToolResult.fail(
|
||||||
|
f"Error: Found {occurrences} occurrences of the text in {path}. "
|
||||||
|
"The text must be unique. Please provide more context to make it unique."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute replacement (use matched text position)
|
||||||
|
base_content = match_result.content_for_replacement
|
||||||
|
new_content = (
|
||||||
|
base_content[:match_result.index] +
|
||||||
|
normalized_new_text +
|
||||||
|
base_content[match_result.index + match_result.match_length:]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate occurrence count (use fuzzy normalized content for consistency)
|
|
||||||
fuzzy_content = normalize_for_fuzzy_match(normalized_content)
|
|
||||||
fuzzy_old_text = normalize_for_fuzzy_match(normalized_old_text)
|
|
||||||
occurrences = fuzzy_content.count(fuzzy_old_text)
|
|
||||||
|
|
||||||
if occurrences > 1:
|
|
||||||
return ToolResult.fail(
|
|
||||||
f"Error: Found {occurrences} occurrences of the text in {path}. "
|
|
||||||
"The text must be unique. Please provide more context to make it unique."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Execute replacement (use matched text position)
|
|
||||||
base_content = match_result.content_for_replacement
|
|
||||||
new_content = (
|
|
||||||
base_content[:match_result.index] +
|
|
||||||
normalized_new_text +
|
|
||||||
base_content[match_result.index + match_result.match_length:]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Verify replacement actually changed content
|
# Verify replacement actually changed content
|
||||||
if base_content == new_content:
|
if base_content == new_content:
|
||||||
return ToolResult.fail(
|
return ToolResult.fail(
|
||||||
|
|||||||
Reference in New Issue
Block a user