diff --git a/tools.py b/tools.py index 5a769df..00ab4aa 100644 --- a/tools.py +++ b/tools.py @@ -16,6 +16,8 @@ def format_relative_time(timestamp: float) -> str: now = time.time() diff = now - timestamp seconds = int(diff) + if seconds < 0: + return "In the future" if seconds < 60: return "Just now" minutes = seconds // 60 @@ -27,11 +29,11 @@ def format_relative_time(timestamp: float) -> str: days = hours // 24 if days == 1: return "Yesterday" - if days < 7: + if days < 30: return f"{days}d ago" - weeks = days // 7 - if weeks < 4: - return f"{weeks}w ago" + months = days // 30 + if months < 12: + return f"{months}mo ago" dt = datetime.datetime.fromtimestamp(timestamp) return dt.strftime('%Y-%m-%d') @@ -166,7 +168,6 @@ async def list_thumbnails_handler(args: Dict[str, Any]): x = padding + col * (thumb_size + padding) y = padding + row * (thumb_size + label_height + padding) - # Continuous numbering across pages global_index = start_idx + i + 1 try: @@ -178,11 +179,17 @@ async def list_thumbnails_handler(args: Dict[str, Any]): canvas.paste(img, (x + off_x, y + off_y)) mod_time_rel = format_relative_time(info["mtime"]) - size_kb = info["size"] / 1024 - file_details.append(f"{global_index}. {filename} | {width}x{height} | {size_kb:.1f}KB | {mod_time_rel}") + file_details.append(f"{global_index}. {filename} | {width}x{height} | {mod_time_rel}") text = str(global_index) - draw.text((x + 2, y + thumb_size + 2), text, fill=(255, 255, 255), font=font) + if font: + bbox = draw.textbbox((0, 0), text, font=font) + text_w = bbox[2] - bbox[0] + else: + text_w = len(text) * 7 + + text_x = x + (thumb_size - text_w) // 2 + draw.text((text_x, y + thumb_size + 2), text, fill=(255, 255, 255), font=font) except Exception as e: logger.error(f"Failed to process {filename}: {e}") @@ -207,6 +214,7 @@ async def list_directory_details_handler(args: Dict[str, Any]): path = args.get("path") page = int(args.get("page", 1)) page_size = int(args.get("page_size", 64)) + sort_by = args.get("sort_by", "mtime") if not path: return {"text": "Error: Missing path argument"} @@ -234,7 +242,9 @@ async def list_directory_details_handler(args: Dict[str, Any]): "type": "dir", "name": entry, "info": f"{count} items", - "mtime": mtime_rel + "mtime": mtime_rel, + "mtime_raw": stats.st_mtime, + "size": stats.st_size }) else: size_kb = stats.st_size / 1024 @@ -242,16 +252,33 @@ async def list_directory_details_handler(args: Dict[str, Any]): "type": "file", "name": entry, "info": f"{size_kb:.1f}KB", - "mtime": mtime_rel + "mtime": mtime_rel, + "mtime_raw": stats.st_mtime, + "size": stats.st_size }) except Exception as e: logger.error(f"Could not stat {entry}: {e}") - all_items.sort(key=lambda x: (x["type"] == "file", x["name"].lower())) + if sort_by == "mtime": + all_items.sort(key=lambda x: (x["type"] == "file", -x["mtime_raw"])) + elif sort_by == "size": + all_items.sort(key=lambda x: (x["type"] == "file", -x["size"])) + else: + all_items.sort(key=lambda x: (x["type"] == "file", x["name"].lower())) total_items = len(all_items) - start_idx = (page - 1) * page_size - end_idx = start_idx + page_size + + if total_items <= 100: + start_idx = 0 + end_idx = total_items + effective_page = 1 + total_pages = 1 + else: + start_idx = (page - 1) * page_size + end_idx = start_idx + page_size + total_pages = (total_items + page_size - 1) // page_size + effective_page = page + paged_items = all_items[start_idx:end_idx] if not paged_items: @@ -264,8 +291,7 @@ async def list_directory_details_handler(args: Dict[str, Any]): else: output.append(f" {item['name']} | {item['info']} | {item['mtime']}") - total_pages = (total_items + page_size - 1) // page_size - header = f"Listing of {path}\nPage {page} of {total_pages} ({total_items} total items). Showing {start_idx+1}-{min(end_idx, total_items)}." + header = f"Listing of {path}\nPage {effective_page} of {total_pages} ({total_items} total items). Showing {start_idx+1}-{min(end_idx, total_items)}." return {"text": f"{header}\n\n" + "\n".join(output)} @@ -307,13 +333,14 @@ TOOL_REGISTRY = [ ), Tool( name="list_directory", - description="Lists the contents of a directory in a file browser format. Directories first, then files. Supports pagination.", + description="Lists the contents of a directory in a file browser format. Directories first, then files. Supports pagination and sorting.", schema={ "type": "object", "properties": { "path": {"type": "string", "description": "Path to the directory to list"}, "page": {"type": "integer", "description": "The page number to retrieve (1-indexed)", "default": 1}, "page_size": {"type": "integer", "description": "Number of items per page", "default": 64}, + "sort_by": {"type": "string", "description": "Sort order: 'mtime' (newest first, default), 'name' (alphabetical), or 'size' (largest first)", "default": "mtime"}, }, "required": ["path"], },