read_file.py
1 # Copyright (c) 2024-2026 Tencent Zhuque Lab. All rights reserved. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # 15 # Requirement: Any integration or derivative work must explicitly attribute 16 # Tencent Zhuque Lab (https://github.com/Tencent/AI-Infra-Guard) in its 17 # documentation or user interface, as detailed in the NOTICE file. 18 19 import os 20 from typing import Any 21 22 from tools.registry import register_tool 23 from utils.loging import logger 24 from utils.tool_context import ToolContext 25 26 27 def _is_path_allowed(file_path: str, context: ToolContext | None) -> bool: 28 if not context or not context.folder: 29 return False 30 31 allowed_root = os.path.realpath(context.folder) 32 target_path = os.path.realpath(file_path) 33 34 try: 35 return os.path.commonpath([allowed_root, target_path]) == allowed_root 36 except ValueError: 37 return False 38 39 40 @register_tool 41 def read_file(file_path: str, context: ToolContext = None) -> dict[str, Any]: 42 """读取文件内容 43 44 Args: 45 file_path: 文件路径 46 47 Returns: 48 包含成功状态和文件内容的字典 49 """ 50 try: 51 if not _is_path_allowed(file_path, context): 52 return { 53 "success": False, 54 "message": f"Path is not allowed: {file_path}, you can only access the given directory", 55 } 56 if not os.path.exists(file_path): 57 return { 58 "success": False, 59 "message": f"File not found: {file_path}", 60 } 61 62 if not os.path.isfile(file_path): 63 return { 64 "success": False, 65 "message": f"Path is not a file: {file_path}", 66 } 67 68 with open(file_path, encoding="utf-8") as f: 69 content = f.read() 70 71 logger.info(f"Read file: {file_path} ({len(content)} chars)") 72 73 return {"data": content} 74 75 except UnicodeDecodeError: 76 return { 77 "success": False, 78 "message": f"Failed to decode file {file_path}. File may be binary.", 79 } 80 except PermissionError: 81 return { 82 "success": False, 83 "message": f"Permission denied: {file_path}", 84 } 85 except Exception as e: 86 logger.error(f"Error reading file {file_path}: {e}") 87 return { 88 "success": False, 89 "message": f"Error reading file: {str(e)}", 90 }