Prefer python exec for complex file writes

This commit is contained in:
wuyang6
2026-05-13 16:35:17 +08:00
parent a9f229d222
commit 9984d35d1f
3 changed files with 20 additions and 16 deletions
+8 -5
View File
@@ -217,20 +217,20 @@ def get_using_your_tools_section(enabled_tool_names: set[str]) -> str:
items.append('编辑文件时,优先使用 edit_file,而不是 shell 文本替换。') items.append('编辑文件时,优先使用 edit_file,而不是 shell 文本替换。')
if 'write_file' in enabled_tool_names: if 'write_file' in enabled_tool_names:
items.append( items.append(
'创建或追加通用文本文件时,优先使用 write_file,而不是 heredoc 或 echo 重定向;默认写入当前 session 目录。' 'write_file 只适合短文本、少量 Markdown、轻量配置或小型手写文件;默认写入当前 session 目录。'
) )
items.append( items.append(
'write_file 是通用保存文件工具。普通文本、Markdown、Python 脚本一律优先用 content_lines(一行一个字符串);content 只用于很短的简单文本,避免把多行内容或大量引号塞进单个 JSON 字符串' '不要用 write_file 写长 Python 脚本、JSONL、CSV、大 JSON、生成数据集或包含大量引号/换行的内容;这些内容会让工具参数 JSON 很容易失效'
) )
items.append( items.append(
'保存结构化数据时,不要自己拼 JSON/JSONL/CSV 字符串:JSON 用 json_contentJSONL 用 jsonl_recordsCSV 用 csv_headers + csv_rows,让工具负责序列化和转义' '如果必须用 write_file:普通文本/Markdown 用 content_lines;很小的 JSON 用 json_content;很少量 JSONL 用 jsonl_records;很小的 CSV 用 csv_headers + csv_rowscontent 只用于一行短文本'
) )
items.append( items.append(
'需要分批写入长文件时,使用 write_file 的 append=true 追加稳定文件;不要反复覆盖同一个中间产物' '不要把 JSON/JSONL/CSV/脚本先拼成一个大字符串再塞进 write_file.content'
) )
if 'python_exec' in enabled_tool_names: if 'python_exec' in enabled_tool_names:
items.append( items.append(
'如果 write_file 因内容过长、引号/换行转义复杂或工具参数生成失败而无法稳定完成写入,下一轮应优先用 python_exec 写文件:把文本作为 stdin 或 Python 字符串/列表处理,并写入同一个 session 路径。' '写 Python 脚本、批量数据、JSONL、CSV、大 JSON、长 Markdown 或复杂多行文本时,优先用 python_exec 通过 pathlib/json/csv 写入文件;这是复杂写文件的默认可靠路径。'
) )
if 'glob_search' in enabled_tool_names: if 'glob_search' in enabled_tool_names:
items.append('搜索文件时,优先使用 glob_search,而不是 find 或 ls。') items.append('搜索文件时,优先使用 glob_search,而不是 find 或 ls。')
@@ -246,6 +246,9 @@ def get_using_your_tools_section(enabled_tool_names: set[str]) -> str:
items.append( items.append(
'python_exec 会注入 PYTHON_EXEC_SCRATCHPAD 环境变量,指向当前用户当前会话隔离的 scratchpad。一次性脚本、缓存和中间输出都应写入这里,交付产物写入 session/output。' 'python_exec 会注入 PYTHON_EXEC_SCRATCHPAD 环境变量,指向当前用户当前会话隔离的 scratchpad。一次性脚本、缓存和中间输出都应写入这里,交付产物写入 session/output。'
) )
items.append(
'需要可靠保存文件时,可以在 python_exec.code 中使用 pathlib.Path(...).write_text(...)、json.dump/json.dumps、csv.writer 或流式逐行写入;这比把大段内容塞进 write_file 参数更稳定。'
)
if 'python_package' in enabled_tool_names: if 'python_package' in enabled_tool_names:
items.append( items.append(
'当 python_exec 因缺少 pandas、pyarrow、openpyxl 等 Python 包失败时,使用 python_package 在当前用户独立 venv 中安装缺失包,然后重试;不要安装到系统 Python 或项目 .venv。' '当 python_exec 因缺少 pandas、pyarrow、openpyxl 等 Python 包失败时,使用 python_package 在当前用户独立 venv 中安装缺失包,然后重试;不要安装到系统 Python 或项目 .venv。'
+4 -4
View File
@@ -1614,11 +1614,11 @@ class LocalCodingAgent:
f'工具:{name};位置:line {exc.lineno} column {exc.colno}' f'工具:{name};位置:line {exc.lineno} column {exc.colno}'
f'原因:{exc.msg};参数片段:{preview!r}' f'原因:{exc.msg};参数片段:{preview!r}'
'请回复“继续”,我会要求模型重新生成合法 JSON 参数;' '请回复“继续”,我会要求模型重新生成合法 JSON 参数;'
'如果是 write_file 写普通文本/脚本/Markdown,应改用 content_lines' '如果是 write_file 写短文本/Markdown,应改用 content_lines'
'如果是保存 JSON/JSONL/CSV应改用 json_content、jsonl_records 或 csv_rows' '如果是很小的 JSON/JSONL/CSV用 json_content、jsonl_records 或 csv_rows'
'如果 write_file 仍不稳定,应改用 python_exec 作为通用写文件兜底' '如果是脚本、长文本、大 JSON、JSONL、CSV 或生成数据,应直接改用 python_exec 写文件;'
'如果是生成/转换结构化数据,应优先调用对应 skill 脚本或 python_exec' '如果是生成/转换结构化数据,应优先调用对应 skill 脚本或 python_exec'
'不要把大段 JSON/CSV/draft 直接塞进工具参数;bash 仅作为最后兜底。' '不要把大段内容直接塞进工具参数;bash 仅作为最后兜底。'
) from exc ) from exc
if not isinstance(arguments, dict): if not isinstance(arguments, dict):
raise OpenAICompatError( raise OpenAICompatError(
+8 -7
View File
@@ -39,9 +39,10 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
AgentTool( AgentTool(
name='write_file', name='write_file',
description=( description=(
'Write or append a UTF-8 text file inside the workspace. Creates parent directories when needed. ' 'Write or append a SMALL UTF-8 file inside the workspace. Creates parent directories when needed. '
'Use content_lines for text/scripts/markdown. Use json_content, jsonl_records, or csv_rows for structured data ' 'Use this for short notes, lightweight markdown, and small config files. '
'so the tool serializes the file instead of forcing the model to escape large strings.' 'For Python scripts, JSONL, large JSON/CSV, generated datasets, or quote-heavy/multi-line content, prefer python_exec '
'to write the file with pathlib/json/csv; do not pack large content into tool arguments.'
), ),
parameters={ parameters={
'type': 'object', 'type': 'object',
@@ -50,11 +51,11 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
'content_lines': { 'content_lines': {
'type': 'array', 'type': 'array',
'items': {'type': 'string'}, 'items': {'type': 'string'},
'description': 'Lines to join with "\\n"; use this for normal text, scripts, markdown, and any multi-line content.', 'description': 'Lines to join with "\\n"; use only for short text/markdown or small scripts. For long scripts use python_exec to create the file.',
}, },
'content': { 'content': {
'type': 'string', 'type': 'string',
'description': 'Short one-line/simple text only. For multi-line or quote-heavy content use content_lines or structured fields.', 'description': 'Short one-line/simple text only. Never use for multi-line scripts, JSON, JSONL, CSV, or quote-heavy content.',
}, },
'content_base64': { 'content_base64': {
'type': 'string', 'type': 'string',
@@ -62,12 +63,12 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
}, },
'json_content': { 'json_content': {
'type': 'object', 'type': 'object',
'description': 'JSON value to serialize with ensure_ascii=false and indent=2. Use for .json files instead of stringifying JSON manually.', 'description': 'Small JSON value to serialize with ensure_ascii=false and indent=2. For large JSON use python_exec streaming write.',
}, },
'jsonl_records': { 'jsonl_records': {
'type': 'array', 'type': 'array',
'items': {'type': 'object'}, 'items': {'type': 'object'},
'description': 'Objects to serialize as compact JSONL, one object per line. Use for .jsonl files.', 'description': 'Small list of objects to serialize as compact JSONL. For more than a few dozen records or generated datasets use python_exec.',
}, },
'csv_headers': { 'csv_headers': {
'type': 'array', 'type': 'array',