""" Write JSON Tool - 用于直接安全写入结构化 JSON 数据,避免大模型生成超长转义文本导致的截断和报错 """ import json from pathlib import Path from typing import Optional, Dict, Any from agent.tools import tool, ToolResult, ToolContext @tool(description="专门且唯一安全的 JSON 数据文件写入工具。传入 Python Dict/Object,自动为你生成格式化和转义无误的 JSON 文件。严禁使用普通的 write_file 写 JSON。参数 file_path 是文件绝对路径字符串,json_data 是要写入的原生 JSON 对象(直接传 dict,无需提前序列化)", hidden_params=["context"], groups=["core"]) async def write_json( file_path: str = "", json_data: dict = None, context: Optional[ToolContext] = None ) -> ToolResult: # 参数防空保护 - 给出明确错误而非空报错 if not file_path: return ToolResult( title="参数错误", output="请提供 file_path 参数:file_path 必须是一个有效的绝对文件路径字符串,例如 '/path/to/output.json'", error="Missing required argument: file_path" ) if json_data is None: return ToolResult( title="参数错误", output="请提供 json_data 参数:json_data 必须是一个原生的 Python dict 对象,请将要写入的 JSON 结构直接作为对象传入,无需序列化为字符串", error="Missing required argument: json_data" ) """ 专门安全地写入结构化 JSON 数据到文件。 Args: file_path: 要写入的绝对或相对文件路径。 json_data: 要写入的数据对象 (object/dict)。 context: 工具上下文 Returns: ToolResult: 写入操作结果 """ path = Path(file_path) if not path.is_absolute(): path = Path.cwd() / path if path.exists() and path.is_dir(): return ToolResult( title="路径错误", output=f"路径是目录,不是文件: {file_path}", error="Path is a directory" ) path.parent.mkdir(parents=True, exist_ok=True) # 自动检测并修正类型:如果模型传进来的是 JSON 字符串,先反序列化再写入 # 这解决了模型把 dict 当成 JSON 字符串传入导致的双重序列化问题 if isinstance(json_data, str): try: json_data = json.loads(json_data) except json.JSONDecodeError as e: return ToolResult( title="JSON 解析失败", output=f"json_data 参数作为 JSON 字符串解析失败,错误在这附近:{e}\n\n" f"[系统强制警告] 你的 JSON 生成存在语法错误(很可能是 description 中的未转义双引号、换行符,或者缺少逗号)。\n" f"⚠️ 严禁使用 write_file 回退硬写!用 write_file 强行写入坏 JSON 会导致整个流水线后续崩溃死锁!\n" f"你必须立即检查并修复字符串内的转义问题,然后重新调用 write_json!", error=str(e) ) try: # 落盘前自动将 JSON 数据中的外站图片 URL 替换为自有 CDN 链接 try: from agent.tools.builtin.file.image_cdn import replace_image_urls_in_obj json_data = await replace_image_urls_in_obj(json_data) except Exception as cdn_err: import logging logging.getLogger(__name__).warning("[write_json] CDN mirror step failed, writing original: %s", cdn_err) with open(path, 'w', encoding='utf-8') as f: json.dump(json_data, f, ensure_ascii=False, indent=2) json_str = json.dumps(json_data, ensure_ascii=False, indent=2) lines = len(json_str.split('\n')) return ToolResult( title=path.name, output=f"JSON 数据已安全且完美地格式化写入: {path.name}", metadata={ "lines": lines, "existed": path.exists() }, long_term_memory=f"安全覆盖写入了结构化 JSON 文件 {path.name}" ) except Exception as e: return ToolResult( title="JSON 写入失败", output=f"无法写入 JSON 到文件: {str(e)}", error=str(e) )