# Reads a locally-downloaded attachment (spreadsheet or plain text/code file) and # returns its content as text the executor agent can reason over. # pandas: the standard library for reading tabular data (Excel/CSV) into a # DataFrame -- a table-like object we then render back out as plain text. from pathlib import Path import pandas as pd from llama_index.core.tools import FunctionTool MAX_FILE_CHARS = 8000 # keep tool output small enough to fit comfortably in the executor's context SPREADSHEET_EXTENSIONS = {".xlsx", ".xls", ".csv"} # Reads every sheet of a spreadsheet file and renders each as a plain-text table. def _read_spreadsheet(path: Path) -> str: if path.suffix == ".csv": sheets = {"": pd.read_csv(path)} else: sheets = pd.read_excel(path, sheet_name=None) # sheet_name=None -> dict of {sheet_name: DataFrame} blocks = [] for sheet_name, df in sheets.items(): header = f"Sheet '{sheet_name}':" if sheet_name else "Data:" blocks.append(f"{header}\n{df.to_string(index=False)}") return "\n\n".join(blocks) # Reads a text/code file as UTF-8, truncated to a safe length. def _read_text(path: Path) -> str: return path.read_text(encoding="utf-8", errors="replace") def read_attached_file(file_path: str) -> str: """Read a locally attached file (spreadsheet, code, or plain text) and return its content as text.""" path = Path(file_path) if not path.exists(): return f"File not found: '{file_path}'." try: content = _read_spreadsheet(path) if path.suffix.lower() in SPREADSHEET_EXTENSIONS else _read_text(path) except Exception as e: return f"Could not read '{file_path}': {type(e).__name__}: {e}" return content[:MAX_FILE_CHARS] read_attached_file_tool = FunctionTool.from_defaults( fn=read_attached_file, name="read_attached_file", description=( "Read the content of a locally attached file by its path -- spreadsheets (.xlsx/.xls/.csv) are " "rendered as tables, everything else (.py/.txt/.json/etc.) is read as plain text. " "Always use this when the question references an attached file that isn't an image or audio." ), )