diff --git a/dougbot/core/brain.py b/dougbot/core/brain.py index cec0c0b..07bfb15 100644 --- a/dougbot/core/brain.py +++ b/dougbot/core/brain.py @@ -416,7 +416,8 @@ class DougBrain(QObject): if subtask.description: current = self._tasks.current_task priority_name = current.priority.name if current else "?" - log.info(f"[{priority_name}] {subtask.description}") + tid = current.task_id if current else 0 + log.info(f"T-{tid} [{priority_name}] {subtask.description}") self._action_sent_time = time.time() diff --git a/dougbot/core/task_queue.py b/dougbot/core/task_queue.py index 4aacf94..a27e267 100644 --- a/dougbot/core/task_queue.py +++ b/dougbot/core/task_queue.py @@ -15,11 +15,15 @@ import time from dataclasses import dataclass, field from enum import IntEnum from typing import Any, Optional +import itertools from dougbot.utils.logging import get_logger log = get_logger("core.tasks") +# Global task ID counter +_task_counter = itertools.count(1) + class Priority(IntEnum): """Task priority levels. Higher = more urgent.""" @@ -51,6 +55,7 @@ class SubTask: status: TaskStatus = TaskStatus.PENDING timeout: float = 30.0 started_at: float = 0.0 + task_id: int = field(default_factory=lambda: next(_task_counter)) @property def is_expired(self) -> bool: @@ -67,6 +72,7 @@ class PrimaryTask: """ name: str priority: Priority + task_id: int = field(default_factory=lambda: next(_task_counter)) description: str = "" source: str = "self" # "player" or "self" source_player: str = "" # Who gave the command @@ -141,7 +147,7 @@ class PrimaryTask: def __str__(self): st = self.current_subtask() step_info = f" → {st.description}" if st else "" - return f"[{self.priority.name}] {self.description}{step_info}" + return f"T-{self.task_id} [{self.priority.name}] {self.description}{step_info}" class TaskStack: @@ -204,7 +210,7 @@ class TaskStack: # Pause the current top task if self._stack and self._stack[-1].status == TaskStatus.ACTIVE: self._stack[-1].status = TaskStatus.PAUSED - log.info(f"Pausing: {self._stack[-1].description}") + log.info(f"T-{self._stack[-1].task_id} PAUSED: {self._stack[-1].description}") # Push new task task.status = TaskStatus.ACTIVE @@ -215,7 +221,7 @@ class TaskStack: while len(self._stack) > self.MAX_DEPTH: self._stack.pop(0) - log.info(f"New task: {task.description} (stack depth: {len(self._stack)})") + log.info(f"T-{task.task_id} NEW: {task.description} (stack depth: {len(self._stack)})") return True def interrupt(self, task: PrimaryTask): @@ -226,7 +232,7 @@ class TaskStack: self._interruption = task task.status = TaskStatus.ACTIVE task.started_at = time.time() - log.info(f"Interrupt: {task.description}") + log.info(f"T-{task.task_id} INTERRUPT: {task.description}") def complete_interruption(self): """Clear the current interruption, resume stack.""" @@ -258,12 +264,12 @@ class TaskStack: self._completed_names.append(top.name) if len(self._completed_names) > 20: self._completed_names.pop(0) - log.info(f"Task complete: {top.description}") + log.info(f"T-{top.task_id} COMPLETE: {top.description}") # Resume the task below if any if self._stack: self._stack[-1].status = TaskStatus.ACTIVE - log.info(f"Resuming: {self._stack[-1].description}") + log.info(f"T-{self._stack[-1].task_id} RESUMED: {self._stack[-1].description}") def fail_current(self): """Fail current subtask but don't kill the primary task.""" @@ -296,10 +302,10 @@ class TaskStack: if self._stack: removed = self._stack.pop() - log.info(f"Task cancelled: {removed.description}") + log.info(f"T-{removed.task_id} CANCELLED: {removed.description}") if self._stack: self._stack[-1].status = TaskStatus.ACTIVE - log.info(f"Resuming: {self._stack[-1].description}") + log.info(f"T-{self._stack[-1].task_id} RESUMED: {self._stack[-1].description}") def cancel_all(self): """Clear everything."""