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) <noreply@anthropic.com>
This commit is contained in:
roberts 2026-03-30 20:49:20 -05:00
parent 7363e8589f
commit 1872d0b89a
2 changed files with 16 additions and 9 deletions

View file

@ -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()

View file

@ -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."""