generated from coulomb/repo-seed
Add retrieval agent briefs and interface cards
This commit is contained in:
@@ -62,6 +62,7 @@ def structural_checks(context: Any) -> dict[str, list[dict[str, Any]]]:
|
||||
_check_required_schemas(context.infospace_root, errors)
|
||||
_check_canon_paths(context.repo_root, context.infospace_root, errors)
|
||||
_check_artifact_index(context.repo_root, context.infospace_root, errors)
|
||||
_check_agent_assets(context.infospace_root, context.infospace.artifacts, errors)
|
||||
_check_optional_assets(context.infospace_root, warnings)
|
||||
|
||||
return {"errors": errors, "warnings": warnings}
|
||||
@@ -314,6 +315,97 @@ def _check_optional_assets(
|
||||
)
|
||||
|
||||
|
||||
def _check_agent_assets(
|
||||
infospace_root: Path,
|
||||
artifacts: list[Any],
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
required_files = (
|
||||
"agent/global-agent-brief.md",
|
||||
"agent/retrieval-index.md",
|
||||
"agent/retrieval-index.yaml",
|
||||
"agent/retrieval-index.json",
|
||||
"agent/templates/canon-interface-card.template.yaml",
|
||||
"agent/templates/consumer-brief.template.md",
|
||||
"agent/consumer-briefs/user-engine.md",
|
||||
"agent/consumer-briefs/railiance-fabric.md",
|
||||
"agent/consumer-briefs/repo-scoping.md",
|
||||
)
|
||||
for relative in required_files:
|
||||
if not (infospace_root / relative).is_file():
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_agent_asset",
|
||||
"path": str(Path("infospace") / relative),
|
||||
}
|
||||
)
|
||||
|
||||
retrieval_index = _read_yaml(infospace_root / "agent" / "retrieval-index.yaml", errors)
|
||||
artifact_ids = {artifact.id for artifact in artifacts}
|
||||
if isinstance(retrieval_index, dict):
|
||||
items = retrieval_index.get("items") or []
|
||||
if not isinstance(items, list):
|
||||
errors.append(
|
||||
{
|
||||
"code": "invalid_retrieval_index",
|
||||
"path": "infospace/agent/retrieval-index.yaml",
|
||||
"message": "Expected items list.",
|
||||
}
|
||||
)
|
||||
else:
|
||||
indexed_ids = {
|
||||
str(item.get("id"))
|
||||
for item in items
|
||||
if isinstance(item, dict) and item.get("id")
|
||||
}
|
||||
missing = sorted(artifact_ids - indexed_ids)
|
||||
for artifact_id in missing:
|
||||
errors.append(
|
||||
{
|
||||
"code": "artifact_missing_from_retrieval_index",
|
||||
"artifact_id": artifact_id,
|
||||
}
|
||||
)
|
||||
|
||||
required_brief_artifacts = [
|
||||
artifact
|
||||
for artifact in artifacts
|
||||
if artifact.kind in {"kernel", "model", "standard", "profile"}
|
||||
]
|
||||
for artifact in required_brief_artifacts:
|
||||
relative = Path("agent") / "briefs" / f"{_safe_id(artifact.id)}.md"
|
||||
brief_path = infospace_root / relative
|
||||
if not brief_path.is_file():
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_agent_brief",
|
||||
"artifact_id": artifact.id,
|
||||
"path": str(Path("infospace") / relative),
|
||||
}
|
||||
)
|
||||
continue
|
||||
frontmatter = _read_markdown_frontmatter(brief_path, errors)
|
||||
if frontmatter.get("artifact_id") != artifact.id:
|
||||
errors.append(
|
||||
{
|
||||
"code": "agent_brief_artifact_mismatch",
|
||||
"artifact_id": artifact.id,
|
||||
"path": str(Path("infospace") / relative),
|
||||
"value": frontmatter.get("artifact_id"),
|
||||
}
|
||||
)
|
||||
if frontmatter.get("source_path") != artifact.path:
|
||||
errors.append(
|
||||
{
|
||||
"code": "agent_brief_source_path_mismatch",
|
||||
"artifact_id": artifact.id,
|
||||
"path": str(Path("infospace") / relative),
|
||||
"value": frontmatter.get("source_path"),
|
||||
"expected": artifact.path,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _artifact_paths_by_path(
|
||||
infospace_root: Path,
|
||||
errors: list[dict[str, Any]],
|
||||
@@ -348,6 +440,33 @@ def _read_yaml(path: Path, errors: list[dict[str, Any]]) -> Any:
|
||||
return None
|
||||
|
||||
|
||||
def _read_markdown_frontmatter(path: Path, errors: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
except FileNotFoundError:
|
||||
errors.append({"code": "missing_markdown", "path": str(path)})
|
||||
return {}
|
||||
if not text.startswith("---\n"):
|
||||
errors.append({"code": "missing_markdown_frontmatter", "path": str(path)})
|
||||
return {}
|
||||
end = text.find("\n---\n", 4)
|
||||
if end == -1:
|
||||
errors.append({"code": "invalid_markdown_frontmatter", "path": str(path)})
|
||||
return {}
|
||||
try:
|
||||
data = yaml.safe_load(text[4:end]) or {}
|
||||
except yaml.YAMLError as exc:
|
||||
errors.append(
|
||||
{
|
||||
"code": "invalid_markdown_frontmatter_yaml",
|
||||
"path": str(path),
|
||||
"message": str(exc),
|
||||
}
|
||||
)
|
||||
return {}
|
||||
return data if isinstance(data, dict) else {}
|
||||
|
||||
|
||||
def _strip_infospace_prefix(path: str) -> str:
|
||||
prefix = "infospace/"
|
||||
return path[len(prefix) :] if path.startswith(prefix) else path
|
||||
@@ -358,3 +477,7 @@ def _has_substantive_files(directory: Path) -> bool:
|
||||
if path.is_file() and path.name != "README.md":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _safe_id(value: str) -> str:
|
||||
return value.replace("/", "-").replace("_", "-")
|
||||
|
||||
Reference in New Issue
Block a user