models.py 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. from __future__ import annotations
  2. from dataclasses import dataclass, field
  3. from datetime import datetime, timezone
  4. from typing import Any, Literal
  5. TaskStatus = Literal["pending", "running", "completed", "failed", "cancelled"]
  6. RunMode = Literal["sync", "async"]
  7. TERMINAL_STATUSES = frozenset({"completed", "failed", "stopped"})
  8. def _utc_now() -> datetime:
  9. return datetime.now(timezone.utc)
  10. @dataclass
  11. class TaskRecord:
  12. """Executor 内存中的单条任务快照。"""
  13. task_id: str
  14. trace_id: str
  15. task_description: str
  16. mode: RunMode
  17. metadata: dict[str, Any] = field(default_factory=dict)
  18. status: TaskStatus = "pending"
  19. created_at: datetime = field(default_factory=_utc_now)
  20. updated_at: datetime = field(default_factory=_utc_now)
  21. error_message: str | None = None
  22. trace_terminal_status: str | None = None
  23. def to_dict(self) -> dict[str, Any]:
  24. return {
  25. "task_id": self.task_id,
  26. "trace_id": self.trace_id,
  27. "task_description": self.task_description,
  28. "mode": self.mode,
  29. "metadata": dict(self.metadata),
  30. "status": self.status,
  31. "created_at": self.created_at.isoformat(),
  32. "updated_at": self.updated_at.isoformat(),
  33. "error_message": self.error_message,
  34. "trace_terminal_status": self.trace_terminal_status,
  35. }
  36. def touch(self, **kwargs: Any) -> None:
  37. for k, v in kwargs.items():
  38. if hasattr(self, k):
  39. setattr(self, k, v)
  40. self.updated_at = _utc_now()