import hashlib from dataclasses import dataclass, field from typing import Optional from pydantic import BaseModel from contracts.ProjectContext import ProjectContext class IssueComment(BaseModel): id: str author: str body: str created_at: int is_agent: bool = False marker: dict[str, str] = field(default_factory=dict) @dataclass class IssueContext: issue_id: str title: str body: str acceptance_criteria: str | None = None comments: list[IssueComment] = field(default_factory=list) labels: list[str] = field(default_factory=list) repo: Optional[str] = None metadata: dict = field(default_factory=dict) images: list[str] = field(default_factory=list) project: ProjectContext | None = None def body_hash(self) -> str: h = hashlib.sha256() h.update(self.title.encode()) h.update(self.body.encode()) h.update((self.acceptance_criteria or "").encode()) return h.hexdigest()[:8] def to_prompt_text(self) -> str: parts = [f"# Issue {self.issue_id}: {self.title}", "", self.body] if self.project: parts.append("\n## Project info") parts.append(self.project.to_prompt_text()) meta_lines = [] for key in ("state", "url"): if self.metadata.get(key): meta_lines.append(f"- {key.capitalize()}: {self.metadata[key]}") if meta_lines: parts.append("\n## Issue Metadata") parts.extend(meta_lines) if self.comments: parts.append("\n## Discussion / Comments") for c in self.comments: parts.append(f"- @{c.author} ({c.created_at}): {c.body}") return "\n".join(parts)