generated from coulomb/repo-seed
confidence labels
This commit is contained in:
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from fastapi import Depends, FastAPI, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
@@ -324,7 +324,26 @@ class CandidateEvidenceMerge(BaseModel):
|
||||
}
|
||||
|
||||
|
||||
app = FastAPI(title="Repository Ability Registry", version="0.1.0")
|
||||
API_DESCRIPTION = (
|
||||
"Register repositories, analyze their observable implementation facts, "
|
||||
"curate reviewable ability graphs, and search approved repository abilities."
|
||||
)
|
||||
|
||||
OPENAPI_TAGS = [
|
||||
{"name": "health", "description": "Service health checks."},
|
||||
{"name": "repositories", "description": "Repository registration and metadata."},
|
||||
{"name": "analysis", "description": "Repository scans and extracted review inputs."},
|
||||
{"name": "review", "description": "Candidate graph approval and correction workflow."},
|
||||
{"name": "registry", "description": "Approved ability maps and manual registry CRUD."},
|
||||
{"name": "search", "description": "Agent-facing discovery endpoints."},
|
||||
]
|
||||
|
||||
app = FastAPI(
|
||||
title="Repository Ability Registry",
|
||||
version="0.1.0",
|
||||
description=API_DESCRIPTION,
|
||||
openapi_tags=OPENAPI_TAGS,
|
||||
)
|
||||
|
||||
|
||||
from repo_registry.web_ui.views import router as ui_router
|
||||
@@ -332,12 +351,12 @@ from repo_registry.web_ui.views import router as ui_router
|
||||
app.include_router(ui_router)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
@app.get("/health", tags=["health"])
|
||||
def health() -> dict[str, str]:
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.post("/repos", status_code=201)
|
||||
@app.post("/repos", status_code=201, tags=["repositories"])
|
||||
def create_repository(
|
||||
payload: RepositoryCreate,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -349,14 +368,14 @@ def create_repository(
|
||||
return asdict(repository)
|
||||
|
||||
|
||||
@app.get("/repos")
|
||||
@app.get("/repos", tags=["repositories"])
|
||||
def list_repositories(
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
return [asdict(repository) for repository in service.list_repositories()]
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}")
|
||||
@app.get("/repos/{repository_id}", tags=["repositories"])
|
||||
def get_repository(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -367,7 +386,7 @@ def get_repository(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}")
|
||||
@app.patch("/repos/{repository_id}", tags=["repositories"])
|
||||
def update_repository(
|
||||
repository_id: int,
|
||||
payload: RepositoryUpdate,
|
||||
@@ -384,7 +403,7 @@ def update_repository(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}", status_code=204)
|
||||
@app.delete("/repos/{repository_id}", status_code=204, tags=["repositories"])
|
||||
def delete_repository(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -395,7 +414,7 @@ def delete_repository(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/analysis-runs", status_code=201)
|
||||
@app.post("/repos/{repository_id}/analysis-runs", status_code=201, tags=["analysis"])
|
||||
def create_analysis_run(
|
||||
repository_id: int,
|
||||
payload: AnalysisRunCreate,
|
||||
@@ -411,7 +430,7 @@ def create_analysis_run(
|
||||
return asdict(summary)
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs")
|
||||
@app.get("/repos/{repository_id}/analysis-runs", tags=["analysis"])
|
||||
def list_analysis_runs(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -422,7 +441,7 @@ def list_analysis_runs(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}")
|
||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}", tags=["analysis"])
|
||||
def get_analysis_run(
|
||||
repository_id: int,
|
||||
analysis_run_id: int,
|
||||
@@ -434,7 +453,7 @@ def get_analysis_run(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/review-decisions")
|
||||
@app.get("/repos/{repository_id}/review-decisions", tags=["review"])
|
||||
def list_repository_review_decisions(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -448,7 +467,10 @@ def list_repository_review_decisions(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}/review-decisions")
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/review-decisions",
|
||||
tags=["review"],
|
||||
)
|
||||
def list_analysis_run_review_decisions(
|
||||
repository_id: int,
|
||||
analysis_run_id: int,
|
||||
@@ -466,7 +488,7 @@ def list_analysis_run_review_decisions(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/observed-facts")
|
||||
@app.get("/repos/{repository_id}/observed-facts", tags=["analysis"])
|
||||
def list_observed_facts(
|
||||
repository_id: int,
|
||||
analysis_run_id: int | None = None,
|
||||
@@ -481,7 +503,7 @@ def list_observed_facts(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/content-chunks")
|
||||
@app.get("/repos/{repository_id}/content-chunks", tags=["analysis"])
|
||||
def list_content_chunks(
|
||||
repository_id: int,
|
||||
analysis_run_id: int | None = None,
|
||||
@@ -496,7 +518,10 @@ def list_content_chunks(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}/content-chunks")
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/content-chunks",
|
||||
tags=["analysis"],
|
||||
)
|
||||
def list_analysis_run_content_chunks(
|
||||
repository_id: int,
|
||||
analysis_run_id: int,
|
||||
@@ -511,7 +536,10 @@ def list_analysis_run_content_chunks(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph")
|
||||
@app.get(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph",
|
||||
tags=["review"],
|
||||
)
|
||||
def get_candidate_graph(
|
||||
repository_id: int,
|
||||
analysis_run_id: int,
|
||||
@@ -523,7 +551,10 @@ def get_candidate_graph(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph/approve")
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph/approve",
|
||||
tags=["review"],
|
||||
)
|
||||
def approve_candidate_graph(
|
||||
repository_id: int,
|
||||
analysis_run_id: int,
|
||||
@@ -544,7 +575,8 @@ def approve_candidate_graph(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-abilities/{candidate_ability_id}/reject"
|
||||
"/candidate-abilities/{candidate_ability_id}/reject",
|
||||
tags=["review"],
|
||||
)
|
||||
def reject_candidate_ability(
|
||||
repository_id: int,
|
||||
@@ -568,7 +600,8 @@ def reject_candidate_ability(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}/reject"
|
||||
"/candidate-capabilities/{candidate_capability_id}/reject",
|
||||
tags=["review"],
|
||||
)
|
||||
def reject_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -592,7 +625,8 @@ def reject_candidate_capability(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-features/{candidate_feature_id}/reject"
|
||||
"/candidate-features/{candidate_feature_id}/reject",
|
||||
tags=["review"],
|
||||
)
|
||||
def reject_candidate_feature(
|
||||
repository_id: int,
|
||||
@@ -616,7 +650,8 @@ def reject_candidate_feature(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-evidence/{candidate_evidence_id}/reject"
|
||||
"/candidate-evidence/{candidate_evidence_id}/reject",
|
||||
tags=["review"],
|
||||
)
|
||||
def reject_candidate_evidence(
|
||||
repository_id: int,
|
||||
@@ -640,7 +675,8 @@ def reject_candidate_evidence(
|
||||
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-abilities/{candidate_ability_id}"
|
||||
"/candidate-abilities/{candidate_ability_id}",
|
||||
tags=["review"],
|
||||
)
|
||||
def edit_candidate_ability(
|
||||
repository_id: int,
|
||||
@@ -664,7 +700,8 @@ def edit_candidate_ability(
|
||||
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}",
|
||||
tags=["review"],
|
||||
)
|
||||
def edit_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -688,7 +725,8 @@ def edit_candidate_capability(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{candidate_capability_id}/relink"
|
||||
"/candidate-capabilities/{candidate_capability_id}/relink",
|
||||
tags=["review"],
|
||||
)
|
||||
def relink_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -712,7 +750,8 @@ def relink_candidate_capability(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-features/{candidate_feature_id}/relink"
|
||||
"/candidate-features/{candidate_feature_id}/relink",
|
||||
tags=["review"],
|
||||
)
|
||||
def relink_candidate_feature(
|
||||
repository_id: int,
|
||||
@@ -736,7 +775,8 @@ def relink_candidate_feature(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-evidence/{candidate_evidence_id}/relink"
|
||||
"/candidate-evidence/{candidate_evidence_id}/relink",
|
||||
tags=["review"],
|
||||
)
|
||||
def relink_candidate_evidence(
|
||||
repository_id: int,
|
||||
@@ -760,7 +800,8 @@ def relink_candidate_evidence(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-abilities/{source_ability_id}/merge"
|
||||
"/candidate-abilities/{source_ability_id}/merge",
|
||||
tags=["review"],
|
||||
)
|
||||
def merge_candidate_ability(
|
||||
repository_id: int,
|
||||
@@ -784,7 +825,8 @@ def merge_candidate_ability(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-capabilities/{source_capability_id}/merge"
|
||||
"/candidate-capabilities/{source_capability_id}/merge",
|
||||
tags=["review"],
|
||||
)
|
||||
def merge_candidate_capability(
|
||||
repository_id: int,
|
||||
@@ -808,7 +850,8 @@ def merge_candidate_capability(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-features/{source_feature_id}/merge"
|
||||
"/candidate-features/{source_feature_id}/merge",
|
||||
tags=["review"],
|
||||
)
|
||||
def merge_candidate_feature(
|
||||
repository_id: int,
|
||||
@@ -832,7 +875,8 @@ def merge_candidate_feature(
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||
"/candidate-evidence/{source_evidence_id}/merge"
|
||||
"/candidate-evidence/{source_evidence_id}/merge",
|
||||
tags=["review"],
|
||||
)
|
||||
def merge_candidate_evidence(
|
||||
repository_id: int,
|
||||
@@ -854,7 +898,7 @@ def merge_candidate_evidence(
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/abilities", status_code=201)
|
||||
@app.post("/repos/{repository_id}/abilities", status_code=201, tags=["registry"])
|
||||
def create_ability(
|
||||
repository_id: int,
|
||||
payload: AbilityCreate,
|
||||
@@ -867,7 +911,7 @@ def create_ability(
|
||||
return {"id": ability_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/abilities/{ability_id}")
|
||||
@app.patch("/repos/{repository_id}/abilities/{ability_id}", tags=["registry"])
|
||||
def update_ability(
|
||||
repository_id: int,
|
||||
ability_id: int,
|
||||
@@ -886,7 +930,7 @@ def update_ability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/abilities/{ability_id}")
|
||||
@app.delete("/repos/{repository_id}/abilities/{ability_id}", tags=["registry"])
|
||||
def delete_ability(
|
||||
repository_id: int,
|
||||
ability_id: int,
|
||||
@@ -898,7 +942,7 @@ def delete_ability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/capabilities", status_code=201)
|
||||
@app.post("/repos/{repository_id}/capabilities", status_code=201, tags=["registry"])
|
||||
def create_capability(
|
||||
repository_id: int,
|
||||
payload: CapabilityCreate,
|
||||
@@ -911,7 +955,7 @@ def create_capability(
|
||||
return {"id": capability_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/capabilities/{capability_id}")
|
||||
@app.patch("/repos/{repository_id}/capabilities/{capability_id}", tags=["registry"])
|
||||
def update_capability(
|
||||
repository_id: int,
|
||||
capability_id: int,
|
||||
@@ -930,7 +974,7 @@ def update_capability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/capabilities/{capability_id}")
|
||||
@app.delete("/repos/{repository_id}/capabilities/{capability_id}", tags=["registry"])
|
||||
def delete_capability(
|
||||
repository_id: int,
|
||||
capability_id: int,
|
||||
@@ -942,7 +986,7 @@ def delete_capability(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/features", status_code=201)
|
||||
@app.post("/repos/{repository_id}/features", status_code=201, tags=["registry"])
|
||||
def create_feature(
|
||||
repository_id: int,
|
||||
payload: FeatureCreate,
|
||||
@@ -955,7 +999,7 @@ def create_feature(
|
||||
return {"id": feature_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/features/{feature_id}")
|
||||
@app.patch("/repos/{repository_id}/features/{feature_id}", tags=["registry"])
|
||||
def update_feature(
|
||||
repository_id: int,
|
||||
feature_id: int,
|
||||
@@ -974,7 +1018,7 @@ def update_feature(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/features/{feature_id}")
|
||||
@app.delete("/repos/{repository_id}/features/{feature_id}", tags=["registry"])
|
||||
def delete_feature(
|
||||
repository_id: int,
|
||||
feature_id: int,
|
||||
@@ -986,7 +1030,7 @@ def delete_feature(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post("/repos/{repository_id}/evidence", status_code=201)
|
||||
@app.post("/repos/{repository_id}/evidence", status_code=201, tags=["registry"])
|
||||
def create_evidence(
|
||||
repository_id: int,
|
||||
payload: EvidenceCreate,
|
||||
@@ -999,7 +1043,7 @@ def create_evidence(
|
||||
return {"id": evidence_id}
|
||||
|
||||
|
||||
@app.patch("/repos/{repository_id}/evidence/{evidence_id}")
|
||||
@app.patch("/repos/{repository_id}/evidence/{evidence_id}", tags=["registry"])
|
||||
def update_evidence(
|
||||
repository_id: int,
|
||||
evidence_id: int,
|
||||
@@ -1018,7 +1062,7 @@ def update_evidence(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete("/repos/{repository_id}/evidence/{evidence_id}")
|
||||
@app.delete("/repos/{repository_id}/evidence/{evidence_id}", tags=["registry"])
|
||||
def delete_evidence(
|
||||
repository_id: int,
|
||||
evidence_id: int,
|
||||
@@ -1030,7 +1074,7 @@ def delete_evidence(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/repos/{repository_id}/ability-map")
|
||||
@app.get("/repos/{repository_id}/ability-map", tags=["registry"])
|
||||
def get_ability_map(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
@@ -1041,14 +1085,33 @@ def get_ability_map(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/search")
|
||||
@app.get("/search", tags=["search"])
|
||||
def search(
|
||||
q: str,
|
||||
status: str | None = None,
|
||||
language: str | None = None,
|
||||
framework: str | None = None,
|
||||
ability: str | None = None,
|
||||
capability: str | None = None,
|
||||
q: str = Query(
|
||||
...,
|
||||
description="Natural-language or keyword query over approved registry entries.",
|
||||
examples=["classify email", "FastAPI health endpoint"],
|
||||
),
|
||||
status: str | None = Query(
|
||||
default=None,
|
||||
description="Filter repositories by registry status, such as indexed.",
|
||||
),
|
||||
language: str | None = Query(
|
||||
default=None,
|
||||
description="Filter by observed programming language.",
|
||||
),
|
||||
framework: str | None = Query(
|
||||
default=None,
|
||||
description="Filter by observed framework hint.",
|
||||
),
|
||||
ability: str | None = Query(
|
||||
default=None,
|
||||
description="Filter to results under an approved ability name.",
|
||||
),
|
||||
capability: str | None = Query(
|
||||
default=None,
|
||||
description="Filter to results under an approved capability name.",
|
||||
),
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
return [
|
||||
@@ -1064,14 +1127,14 @@ def search(
|
||||
]
|
||||
|
||||
|
||||
@app.get("/abilities")
|
||||
@app.get("/abilities", tags=["search"])
|
||||
def list_abilities(
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
return [asdict(ability) for ability in service.list_abilities()]
|
||||
|
||||
|
||||
@app.get("/capabilities")
|
||||
@app.get("/capabilities", tags=["search"])
|
||||
def list_capabilities(
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
|
||||
Reference in New Issue
Block a user