/ src / core / tasks.py
tasks.py
  1  """
  2  Task management for Ag3ntum.
  3  
  4  Handles reading tasks from files and CLI, and managing task state.
  5  """
  6  import logging
  7  from pathlib import Path
  8  from typing import Optional
  9  
 10  from .exceptions import TaskError
 11  
 12  logger = logging.getLogger(__name__)
 13  
 14  
 15  class TaskManager:
 16      """
 17      Manages task loading and processing.
 18  
 19      Tasks can be loaded from:
 20      - A custom file path via --task-file
 21      - Directly from a string via --task
 22      """
 23  
 24      def __init__(self, working_dir: Optional[Path] = None) -> None:
 25          """
 26          Initialize the task manager.
 27  
 28          Args:
 29              working_dir: Working directory for task files.
 30          """
 31          self._working_dir = working_dir or Path.cwd()
 32  
 33      def load_from_file(self, file_path: str) -> str:
 34          """
 35          Load task from a file.
 36  
 37          Args:
 38              file_path: Path to task file (absolute or relative to working dir).
 39  
 40          Returns:
 41              The task content as a string.
 42  
 43          Raises:
 44              TaskError: If the file cannot be read.
 45          """
 46          task_path = Path(file_path)
 47          if not task_path.is_absolute():
 48              task_path = self._working_dir / task_path
 49  
 50          if not task_path.exists():
 51              raise TaskError(f"Task file not found: {task_path}")
 52  
 53          try:
 54              content = task_path.read_text().strip()
 55              if not content:
 56                  raise TaskError(f"Task file is empty: {task_path}")
 57  
 58              logger.info(f"Loaded task from {task_path}")
 59              return content
 60          except IOError as e:
 61              raise TaskError(f"Failed to read task file {task_path}: {e}") from e
 62  
 63      def load_from_string(self, task: str) -> str:
 64          """
 65          Load task from a string.
 66  
 67          Args:
 68              task: The task content as a string.
 69  
 70          Returns:
 71              The task content (validated).
 72  
 73          Raises:
 74              TaskError: If the task is empty.
 75          """
 76          content = task.strip()
 77          if not content:
 78              raise TaskError("Task cannot be empty")
 79  
 80          return content
 81  
 82      def load(
 83          self,
 84          task: Optional[str] = None,
 85          file_path: Optional[str] = None
 86      ) -> str:
 87          """
 88          Load task from string or file.
 89  
 90          Priority:
 91          1. If task string is provided, use it
 92          2. If file_path is provided, load from that file
 93          3. Otherwise, look for input/task.md in working directory
 94  
 95          Args:
 96              task: Task content as a string.
 97              file_path: Path to task file.
 98  
 99          Returns:
100              The task content.
101  
102          Raises:
103              TaskError: If no task can be loaded.
104          """
105          if task:
106              return self.load_from_string(task)
107  
108          # Use provided file_path or default to input/task.md
109          default_path = "input/task.md"
110          return self.load_from_file(file_path or default_path)
111  
112  
113  def load_task(
114      task: Optional[str] = None,
115      file_path: Optional[str] = None,
116      working_dir: Optional[Path] = None
117  ) -> str:
118      """
119      Convenience function to load a task.
120  
121      Args:
122          task: Task content as a string.
123          file_path: Path to task file.
124          working_dir: Working directory for task files.
125  
126      Returns:
127          The task content.
128      """
129      manager = TaskManager(working_dir)
130      return manager.load(task, file_path)