generated from coulomb/repo-seed
usecase e2e tests
This commit is contained in:
@@ -4,6 +4,7 @@ from dataclasses import asdict
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException, Query
|
||||
from fastapi.responses import PlainTextResponse
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
@@ -27,6 +28,8 @@ from repo_registry.web_api.schemas import (
|
||||
CandidateGraphResponse,
|
||||
CandidateLeafRelink,
|
||||
CandidateRejection,
|
||||
CapabilityGapRequest,
|
||||
CapabilityGapResponse,
|
||||
CapabilityCreate,
|
||||
CapabilitySummaryResponse,
|
||||
CapabilityUpdate,
|
||||
@@ -38,6 +41,7 @@ from repo_registry.web_api.schemas import (
|
||||
IdResponse,
|
||||
ObservedFactResponse,
|
||||
RepositoryAbilityMapResponse,
|
||||
RepositoryComparisonResponse,
|
||||
RepositoryCreate,
|
||||
RepositoryResponse,
|
||||
RepositoryUpdate,
|
||||
@@ -91,6 +95,7 @@ OPENAPI_TAGS = [
|
||||
{"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."},
|
||||
{"name": "discovery", "description": "Comparison, gap analysis, and export helpers."},
|
||||
]
|
||||
|
||||
app = FastAPI(
|
||||
@@ -951,6 +956,62 @@ def get_ability_map(
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get(
|
||||
"/repos/{repository_id}/export",
|
||||
tags=["discovery"],
|
||||
response_class=PlainTextResponse,
|
||||
responses={
|
||||
200: {
|
||||
"content": {"application/x-yaml": {}},
|
||||
"description": "YAML registry export suitable for repo-abilities.yaml.",
|
||||
}
|
||||
},
|
||||
)
|
||||
def export_repository_registry_entry(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> PlainTextResponse:
|
||||
try:
|
||||
content = service.export_registry_entry(repository_id)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
return PlainTextResponse(content, media_type="application/x-yaml")
|
||||
|
||||
|
||||
@app.get(
|
||||
"/repository-comparisons",
|
||||
tags=["discovery"],
|
||||
response_model=RepositoryComparisonResponse,
|
||||
)
|
||||
def compare_repositories(
|
||||
repository_ids: list[int] = Query(
|
||||
...,
|
||||
description="Repository ids to compare by approved abilities and capabilities.",
|
||||
min_length=2,
|
||||
),
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return service.compare_repositories(repository_ids)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post(
|
||||
"/capability-gaps",
|
||||
tags=["discovery"],
|
||||
response_model=CapabilityGapResponse,
|
||||
)
|
||||
def detect_capability_gaps(
|
||||
payload: CapabilityGapRequest,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return service.detect_capability_gaps(**payload.model_dump())
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get("/search", tags=["search"], response_model=list[SearchResultResponse])
|
||||
def search(
|
||||
q: str = Query(
|
||||
|
||||
@@ -664,3 +664,85 @@ class CapabilitySummaryResponse(BaseModel):
|
||||
description: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
|
||||
|
||||
class CapabilityGapRequest(BaseModel):
|
||||
desired_ability: str
|
||||
desired_capabilities: list[str]
|
||||
repository_ids: list[int] | None = None
|
||||
|
||||
model_config = {
|
||||
"json_schema_extra": {
|
||||
"examples": [
|
||||
{
|
||||
"desired_ability": "Business Email Routing",
|
||||
"desired_capabilities": [
|
||||
"Classify Incoming Email",
|
||||
"Route Email to Team",
|
||||
],
|
||||
"repository_ids": [1, 2],
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ComparedCapabilityResponse(BaseModel):
|
||||
name: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
evidence_count: int
|
||||
|
||||
|
||||
class ComparedAbilityRepositoryResponse(BaseModel):
|
||||
repository_id: int
|
||||
repository_name: str
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
capabilities: list[ComparedCapabilityResponse]
|
||||
|
||||
|
||||
class ComparedAbilityResponse(BaseModel):
|
||||
name: str
|
||||
repositories: list[ComparedAbilityRepositoryResponse]
|
||||
|
||||
|
||||
class UniqueCapabilityResponse(BaseModel):
|
||||
repository_id: int
|
||||
repository_name: str
|
||||
ability_name: str
|
||||
capability_name: str
|
||||
|
||||
|
||||
class RepositoryComparisonResponse(BaseModel):
|
||||
repositories: list[RepositoryResponse]
|
||||
abilities: list[ComparedAbilityResponse]
|
||||
unique_capabilities: list[UniqueCapabilityResponse]
|
||||
|
||||
|
||||
class CapabilityGapMatchResponse(BaseModel):
|
||||
capability: str
|
||||
repositories: list[str]
|
||||
|
||||
|
||||
class WeakCapabilityEvidenceResponse(BaseModel):
|
||||
capability: str
|
||||
repository_id: int
|
||||
repository_name: str
|
||||
evidence_count: int
|
||||
strongest_evidence: str | None = None
|
||||
confidence: float
|
||||
confidence_label: str
|
||||
|
||||
|
||||
class DuplicateCapabilityResponse(BaseModel):
|
||||
capability: str
|
||||
repositories: list[str]
|
||||
|
||||
|
||||
class CapabilityGapResponse(BaseModel):
|
||||
desired_ability: str
|
||||
matched_capabilities: list[CapabilityGapMatchResponse]
|
||||
missing_capabilities: list[str]
|
||||
weakly_evidenced_capabilities: list[WeakCapabilityEvidenceResponse]
|
||||
duplicate_capabilities: list[DuplicateCapabilityResponse]
|
||||
|
||||
Reference in New Issue
Block a user