From 1872d0b89a7e0439edc09b7d4cada79e83c5bb6f Mon Sep 17 00:00:00 2001 From: roberts Date: Mon, 30 Mar 2026 20:49:20 -0500 Subject: [PATCH] Add task IDs (T-1, T-2, ...) for tracking and debugging Every PrimaryTask and SubTask gets a unique auto-incrementing ID. All log messages now include the task ID: T-1 NEW: Following GavRocket (stack depth: 1) T-2 INTERRUPT: Fighting spider T-2 COMPLETE: Fighting spider T-1 RESUMED: Following GavRocket T-3 NEW: Checking inventory (stack depth: 2) T-1 PAUSED: Following GavRocket T-3 COMPLETE: Checking inventory T-1 RESUMED: Following GavRocket Makes it easy to track which task is which and debug the stack. Co-Authored-By: Claude Opus 4.6 (1M context) --- dougbot/core/brain.py | 3 ++- dougbot/core/task_queue.py | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) 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."""