Prefer python exec for complex file writes
This commit is contained in:
@@ -217,20 +217,20 @@ def get_using_your_tools_section(enabled_tool_names: set[str]) -> str:
|
||||
items.append('编辑文件时,优先使用 edit_file,而不是 shell 文本替换。')
|
||||
if 'write_file' in enabled_tool_names:
|
||||
items.append(
|
||||
'创建或追加通用文本文件时,优先使用 write_file,而不是 heredoc 或 echo 重定向;默认写入当前 session 目录。'
|
||||
'write_file 只适合短文本、少量 Markdown、轻量配置或小型手写文件;默认写入当前 session 目录。'
|
||||
)
|
||||
items.append(
|
||||
'write_file 是通用保存文件工具。普通文本、Markdown、Python 脚本一律优先用 content_lines(一行一个字符串);content 只用于很短的简单文本,避免把多行内容或大量引号塞进单个 JSON 字符串。'
|
||||
'不要用 write_file 写长 Python 脚本、JSONL、CSV、大 JSON、生成数据集或包含大量引号/换行的内容;这些内容会让工具参数 JSON 很容易失效。'
|
||||
)
|
||||
items.append(
|
||||
'保存结构化数据时,不要自己拼 JSON/JSONL/CSV 字符串:JSON 用 json_content,JSONL 用 jsonl_records,CSV 用 csv_headers + csv_rows,让工具负责序列化和转义。'
|
||||
'如果必须用 write_file:普通文本/Markdown 用 content_lines;很小的 JSON 用 json_content;很少量 JSONL 用 jsonl_records;很小的 CSV 用 csv_headers + csv_rows;content 只用于一行短文本。'
|
||||
)
|
||||
items.append(
|
||||
'需要分批写入长文件时,使用 write_file 的 append=true 追加稳定文件;不要反复覆盖同一个中间产物。'
|
||||
'不要把 JSON/JSONL/CSV/脚本先拼成一个大字符串再塞进 write_file.content。'
|
||||
)
|
||||
if 'python_exec' in enabled_tool_names:
|
||||
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:
|
||||
items.append('搜索文件时,优先使用 glob_search,而不是 find 或 ls。')
|
||||
@@ -246,6 +246,9 @@ def get_using_your_tools_section(enabled_tool_names: set[str]) -> str:
|
||||
items.append(
|
||||
'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:
|
||||
items.append(
|
||||
'当 python_exec 因缺少 pandas、pyarrow、openpyxl 等 Python 包失败时,使用 python_package 在当前用户独立 venv 中安装缺失包,然后重试;不要安装到系统 Python 或项目 .venv。'
|
||||
|
||||
@@ -1614,11 +1614,11 @@ class LocalCodingAgent:
|
||||
f'工具:{name};位置:line {exc.lineno} column {exc.colno};'
|
||||
f'原因:{exc.msg};参数片段:{preview!r}。'
|
||||
'请回复“继续”,我会要求模型重新生成合法 JSON 参数;'
|
||||
'如果是 write_file 写普通文本/脚本/Markdown,应改用 content_lines;'
|
||||
'如果是保存 JSON/JSONL/CSV,应改用 json_content、jsonl_records 或 csv_rows;'
|
||||
'如果 write_file 仍不稳定,应改用 python_exec 作为通用写文件兜底;'
|
||||
'如果是 write_file 写短文本/Markdown,应改用 content_lines;'
|
||||
'如果是很小的 JSON/JSONL/CSV,可用 json_content、jsonl_records 或 csv_rows;'
|
||||
'如果是脚本、长文本、大 JSON、JSONL、CSV 或生成数据,应直接改用 python_exec 写文件;'
|
||||
'如果是生成/转换结构化数据,应优先调用对应 skill 脚本或 python_exec,'
|
||||
'不要把大段 JSON/CSV/draft 直接塞进工具参数;bash 仅作为最后兜底。'
|
||||
'不要把大段内容直接塞进工具参数;bash 仅作为最后兜底。'
|
||||
) from exc
|
||||
if not isinstance(arguments, dict):
|
||||
raise OpenAICompatError(
|
||||
|
||||
@@ -39,9 +39,10 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
|
||||
AgentTool(
|
||||
name='write_file',
|
||||
description=(
|
||||
'Write or append a UTF-8 text 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 '
|
||||
'so the tool serializes the file instead of forcing the model to escape large strings.'
|
||||
'Write or append a SMALL UTF-8 file inside the workspace. Creates parent directories when needed. '
|
||||
'Use this for short notes, lightweight markdown, and small config files. '
|
||||
'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={
|
||||
'type': 'object',
|
||||
@@ -50,11 +51,11 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
|
||||
'content_lines': {
|
||||
'type': 'array',
|
||||
'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': {
|
||||
'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': {
|
||||
'type': 'string',
|
||||
@@ -62,12 +63,12 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
|
||||
},
|
||||
'json_content': {
|
||||
'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': {
|
||||
'type': 'array',
|
||||
'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': {
|
||||
'type': 'array',
|
||||
|
||||
Reference in New Issue
Block a user