task_contract.py 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. """Shared immutable Task contract reference used by progress and candidates."""
  2. from __future__ import annotations
  3. from typing import Literal
  4. from pydantic import BaseModel, ConfigDict, Field, model_validator
  5. class TaskContractRef(BaseModel):
  6. model_config = ConfigDict(
  7. extra="forbid",
  8. frozen=True,
  9. str_strip_whitespace=True,
  10. )
  11. kind: Literal["root_task_anchor", "task_brief"]
  12. root_task_anchor_hash: str | None = Field(
  13. default=None,
  14. pattern=r"^[0-9a-f]{64}$",
  15. )
  16. task_brief_version: int | None = Field(default=None, ge=1)
  17. task_brief_hash: str | None = Field(default=None, pattern=r"^[0-9a-f]{64}$")
  18. @model_validator(mode="after")
  19. def validate_kind_fields(self) -> "TaskContractRef":
  20. if self.kind == "root_task_anchor":
  21. if not self.root_task_anchor_hash:
  22. raise ValueError("root_task_anchor requires root_task_anchor_hash")
  23. if self.task_brief_version is not None or self.task_brief_hash is not None:
  24. raise ValueError("root_task_anchor does not accept TaskBrief fields")
  25. else:
  26. if self.task_brief_version is None or not self.task_brief_hash:
  27. raise ValueError("task_brief requires version and hash")
  28. if self.root_task_anchor_hash is not None:
  29. raise ValueError("task_brief does not accept root_task_anchor_hash")
  30. return self