feat: reuse single comment

This commit is contained in:
2026-07-21 00:54:46 +02:00
parent a9289e656c
commit 73045258fa
9 changed files with 170 additions and 56 deletions
+7
View File
@@ -105,6 +105,13 @@ class GiteaClient:
)
return int(response.json()["id"])
async def update_comment(self, owner: str, repo: str, comment_id: int, body: str) -> None:
await self._request(
"PATCH",
f"/repos/{owner}/{repo}/issues/comments/{comment_id}",
json={"body": body},
)
async def create_pull_request(
self,
owner: str,
+25 -17
View File
@@ -61,28 +61,28 @@ class Worker:
log.info("job started", extra=extra)
try:
if job.accepted_comment_id is None:
accepted_id = await self.gitea.create_comment(
job.accepted_comment_id = await self.gitea.create_comment(
job.repo_owner,
job.repo_name,
job.issue_number,
f"Agent job `{job.id}` queued (`{job.kind}`).",
f"Agent job `{job.id}` started (`{job.kind}`).",
)
await self.storage.set_job_comment(
job.id, "accepted_comment_id", accepted_id
job.id, "accepted_comment_id", job.accepted_comment_id
)
else:
await self.gitea.update_comment(
job.repo_owner,
job.repo_name,
job.accepted_comment_id,
f"Agent job `{job.id}` started (`{job.kind}`).",
)
comment_id = await self.gitea.create_comment(
job.repo_owner,
job.repo_name,
job.issue_number,
f"Agent job `{job.id}` started (`{job.kind}`).",
)
await self.storage.set_job_comment(job.id, "started_comment_id", comment_id)
await self.dispatcher.dispatch(job)
except JobRejected as exc:
await self._safe_update_job(
job, status=JobStatus.REJECTED, stage="rejected", error=str(exc)
)
await self._safe_comment(job, f"Agent job `{job.id}` was rejected: {exc}")
await self._safe_job_comment(job, f"Agent job `{job.id}` was rejected: {exc}")
log.info("job rejected", extra={**extra, "stage": "rejected"})
except Exception as exc:
failed_stage = await self._safe_job_stage(job)
@@ -90,7 +90,7 @@ class Worker:
job, status=JobStatus.FAILED, stage="failed", error=_safe_error(exc)
)
await self._safe_fail_workflow(job)
await self._safe_comment(
await self._safe_job_comment(
job,
f"Agent job `{job.id}` failed during `{failed_stage}`: {_safe_error(exc)}",
)
@@ -111,7 +111,7 @@ class Worker:
for job in jobs:
await self._abort_job_sessions(job)
await self._safe_fail_workflow(job)
await self._safe_comment(
await self._safe_job_comment(
job,
f"Agent job `{job.id}` failed because the service restarted during execution.",
)
@@ -136,11 +136,19 @@ class Worker:
for session_id, workspace in sessions:
await self.opencode.abort(session_id, workspace)
async def _safe_comment(self, job: Job, body: str) -> None:
async def _safe_job_comment(self, job: Job, body: str) -> None:
try:
await self.gitea.create_comment(
job.repo_owner, job.repo_name, job.issue_number, body
)
if job.accepted_comment_id is None:
job.accepted_comment_id = await self.gitea.create_comment(
job.repo_owner, job.repo_name, job.issue_number, body
)
await self.storage.set_job_comment(
job.id, "accepted_comment_id", job.accepted_comment_id
)
else:
await self.gitea.update_comment(
job.repo_owner, job.repo_name, job.accepted_comment_id, body
)
except Exception:
log.exception("could not publish job status", extra={"job_id": job.id})
+9 -1
View File
@@ -9,7 +9,7 @@ from agentci.adapters.gitea import GiteaClient
from agentci.adapters.opencode import OpenCodeClient
from agentci.adapters.storage import Storage
from agentci.config import Settings
from agentci.domain.models import ReviewReport
from agentci.domain.models import Job, ReviewReport
from agentci.prompts import PromptLibrary
from agentci.workflows.context import ContextBuilder
@@ -69,3 +69,11 @@ def report_for_prompt(report_json_value: str | None) -> str:
def agent_comment(kind: str, workflow_id: str, body: str) -> str:
return f"<!-- agentci:{kind} workflow={workflow_id} -->\n{body}"
async def update_job_comment(deps: Dependencies, job: Job, body: str) -> None:
if job.accepted_comment_id is None:
raise RuntimeError("Expected a persisted Gitea job comment ID")
await deps.gitea.update_comment(
job.repo_owner, job.repo_name, job.accepted_comment_id, body
)
+4 -9
View File
@@ -17,6 +17,7 @@ from agentci.workflows.common import (
agent_comment,
report_json,
review_markdown,
update_job_comment,
)
@@ -125,17 +126,11 @@ class ImplementWorkflow:
f"{job.repo_name}/pulls/{pull.number}"
)
body = f"Pull request created: {pull_url}\n\n{result_comment(result, sha=sha)}"
await self.deps.gitea.create_comment(
job.repo_owner,
job.repo_name,
job.issue_number,
agent_comment("implementation", workflow.id, body),
)
body = agent_comment("implementation", workflow.id, body)
remaining = review_markdown(report)
if remaining:
await self.deps.gitea.create_comment(
job.repo_owner, job.repo_name, pull.number, remaining
)
body = f"{body}\n\n{remaining}"
await update_job_comment(self.deps, job, body)
async def _reject_duplicate(self, job: Job) -> None:
workflows = await self.deps.storage.implementation_workflows(
+6 -14
View File
@@ -19,6 +19,7 @@ from agentci.workflows.common import (
report_json,
required_session,
review_markdown,
update_job_comment,
)
@@ -97,11 +98,8 @@ class PlanWorkflow:
schema_name="discussion.json",
result_type=DiscussionReply,
)
await self.deps.gitea.create_comment(
job.repo_owner,
job.repo_name,
job.issue_number,
agent_comment("discussion", workflow.id, reply.markdown),
await update_job_comment(
self.deps, job, agent_comment("discussion", workflow.id, reply.markdown)
)
async def iterate(self, job: Job) -> None:
@@ -213,17 +211,11 @@ class PlanWorkflow:
workflow.review_json = report_json(report)
workflow.status = WorkflowStatus.COMPLETED
await self.deps.storage.update_workflow(workflow)
await self.deps.gitea.create_comment(
job.repo_owner,
job.repo_name,
job.issue_number,
agent_comment("plan", workflow.id, artifact.plan_markdown),
)
body = agent_comment("plan", workflow.id, artifact.plan_markdown)
remaining = review_markdown(report)
if remaining:
await self.deps.gitea.create_comment(
job.repo_owner, job.repo_name, job.issue_number, remaining
)
body = f"{body}\n\n{remaining}"
await update_job_comment(self.deps, job, body)
async def _latest_plan(self, job: Job) -> Workflow:
workflow = await self.deps.storage.latest_workflow(
+8 -12
View File
@@ -10,6 +10,7 @@ from agentci.workflows.common import (
report_for_prompt,
report_json,
review_markdown,
update_job_comment,
)
@@ -88,17 +89,13 @@ class PullRequestWorkflow:
workflow.artifact = result.model_dump_json()
workflow.review_json = report_json(report)
await self.deps.storage.update_workflow(workflow)
await self.deps.gitea.create_comment(
job.repo_owner,
job.repo_name,
pull_number,
agent_comment("iteration", workflow.id, result_comment(result, sha=sha)),
body = agent_comment(
"iteration", workflow.id, result_comment(result, sha=sha)
)
remaining = review_markdown(report)
if remaining:
await self.deps.gitea.create_comment(
job.repo_owner, job.repo_name, pull_number, remaining
)
body = f"{body}\n\n{remaining}"
await update_job_comment(self.deps, job, body)
async def fix(self, job: Job) -> None:
pull_number = _pull_number(job)
@@ -145,10 +142,9 @@ class PullRequestWorkflow:
set_upstream=False,
commit_prefix="agent fix",
)
await self.deps.gitea.create_comment(
job.repo_owner,
job.repo_name,
pull_number,
await update_job_comment(
self.deps,
job,
agent_comment("fix", job.id, result_comment(result, sha=sha)),
)