2026-09-20 20:56:36 +03:00
|
|
|
import hashlib
|
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
|
from typing import Optional
|
|
|
|
|
|
2026-09-25 22:14:07 +03:00
|
|
|
from pydantic import BaseModel, Field
|
2026-09-22 23:21:59 +03:00
|
|
|
|
2026-09-20 20:56:36 +03:00
|
|
|
from contracts.ProjectContext import ProjectContext
|
|
|
|
|
|
|
|
|
|
|
2026-09-25 19:44:48 +03:00
|
|
|
class IssueComment(BaseModel):
|
|
|
|
|
id: str
|
|
|
|
|
author: str
|
|
|
|
|
body: str
|
|
|
|
|
created_at: int
|
|
|
|
|
is_agent: bool = False
|
2026-09-25 22:14:07 +03:00
|
|
|
marker: dict[str, str] = Field(default_factory=dict)
|
2026-09-25 19:44:48 +03:00
|
|
|
|
|
|
|
|
|
2026-09-20 20:56:36 +03:00
|
|
|
@dataclass
|
|
|
|
|
class IssueContext:
|
|
|
|
|
issue_id: str
|
|
|
|
|
title: str
|
|
|
|
|
body: str
|
2026-09-22 23:21:59 +03:00
|
|
|
acceptance_criteria: str | None = None
|
|
|
|
|
comments: list[IssueComment] = field(default_factory=list)
|
2026-09-20 20:56:36 +03:00
|
|
|
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:
|
2026-09-22 23:21:59 +03:00
|
|
|
parts.append(f"- @{c.author} ({c.created_at}): {c.body}")
|
2026-09-20 20:56:36 +03:00
|
|
|
|
|
|
|
|
return "\n".join(parts)
|