Task 010 implement research manifest flow

This commit is contained in:
2026-05-21 21:56:44 +03:00
parent 5b27d1a3ca
commit 7d4a79acb5
23 changed files with 1063 additions and 26 deletions
@@ -20,6 +20,8 @@ from src.domain.contracts import (
PlanSummary,
PublishingRules,
PublishingStatus,
ResearchArtifactManifestSummary,
ResearchArtifactSummary,
ArticleWorkflowStatus,
WorkflowEventSummary,
Role,
@@ -46,6 +48,7 @@ class BackendRepository:
self.articles = ArticlesRepository(self)
self.boundary_questions = BoundaryQuestionsRepository(self)
self.article_plans = ArticlePlansRepository(self)
self.research_manifests = ResearchManifestsRepository(self)
self.agent_jobs = AgentJobsRepository(self)
self.script_config_versions = ScriptConfigVersionsRepository(self)
self.script_config_version_events = ScriptConfigVersionAuditEventsRepository(self)
@@ -1005,6 +1008,121 @@ class ArticlePlansRepository:
"""
class ResearchManifestsRepository:
def __init__(self, repository: BackendRepository) -> None:
self._repository = repository
def create(
self,
*,
article_id: UUID,
agent_job_id: UUID,
s3_prefix: str,
artifacts: list[JsonObject],
created_at: datetime,
) -> ResearchArtifactManifestSummary:
manifest_id = uuid4()
placeholder = self._repository.placeholder()
json_cast = self._repository.json_cast()
source_urls = [artifact["source_url"] for artifact in artifacts]
object_keys = [artifact["object_key"] for artifact in artifacts]
content_hashes = [artifact["content_hash"] for artifact in artifacts]
artifact_types = [artifact["artifact_type"] for artifact in artifacts]
metadata_references = [
artifact.get("metadata", {}).get("metadata_object_key")
for artifact in artifacts
]
with self._repository.connection() as connection:
connection.execute(
f"""
INSERT INTO research_run_manifests (
id,
article_id,
agent_job_id,
s3_prefix,
source_urls,
object_keys,
content_hashes,
artifact_types,
metadata_references,
artifacts,
created_at
)
VALUES (
{placeholder},
{placeholder},
{placeholder},
{placeholder},
{placeholder}{json_cast},
{placeholder}{json_cast},
{placeholder}{json_cast},
{placeholder}{json_cast},
{placeholder}{json_cast},
{placeholder}{json_cast},
{placeholder}
)
""",
(
str(manifest_id),
str(article_id),
str(agent_job_id),
s3_prefix,
_json_value(source_urls),
_json_value(object_keys),
_json_value(content_hashes),
_json_value(artifact_types),
_json_value(metadata_references),
_json_value(artifacts),
_datetime_value(created_at),
),
)
return self.get(manifest_id)
def list_for_article(self, article_id: UUID) -> list[ResearchArtifactManifestSummary]:
placeholder = self._repository.placeholder()
with self._repository.connection() as connection:
rows = connection.execute(
f"""
SELECT
id,
article_id,
agent_job_id,
s3_prefix,
artifacts,
created_at
FROM research_run_manifests
WHERE article_id = {placeholder}
ORDER BY created_at
""",
(str(article_id),),
).fetchall()
return [_research_manifest_from_row(row) for row in rows]
def get(self, manifest_id: UUID) -> ResearchArtifactManifestSummary:
placeholder = self._repository.placeholder()
with self._repository.connection() as connection:
row = connection.execute(
f"""
SELECT
id,
article_id,
agent_job_id,
s3_prefix,
artifacts,
created_at
FROM research_run_manifests
WHERE id = {placeholder}
""",
(str(manifest_id),),
).fetchone()
if row is None:
raise LookupError(f"Research manifest not found: {manifest_id}")
return _research_manifest_from_row(row)
class AgentJobsRepository:
def __init__(self, repository: BackendRepository) -> None:
self._repository = repository
@@ -1715,6 +1833,20 @@ def _plan_summary_from_row(
)
def _research_manifest_from_row(row: Any) -> ResearchArtifactManifestSummary:
return ResearchArtifactManifestSummary(
id=_row_value(row, "id"),
article_id=_row_value(row, "article_id"),
agent_job_id=_row_value(row, "agent_job_id"),
s3_prefix=_row_value(row, "s3_prefix"),
artifacts=[
ResearchArtifactSummary(**artifact)
for artifact in _json_from_row(row, "artifacts")
],
created_at=_row_value(row, "created_at"),
)
def _agent_job_summary_from_row(row: Any) -> AgentJobSummary:
return AgentJobSummary(
id=_row_value(row, "id"),