from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import text from sqlalchemy.orm import Session from core_domain import ServiceHealth from app.application.services import SkillApplicationService from app.db.session import get_db from app.domain.repositories import ( SkillDefinitionRepository, SkillInstallationRepository, SkillRunRepository, SkillVersionRepository, ) from app.schemas.skill import ( SkillCreateRequest, SkillInstallRequest, SkillInstallationResponse, SkillInstallationStatusUpdateRequest, SkillResponse, SkillRunCreateRequest, SkillRunExecuteRequest, SkillRunResponse, SkillStatusUpdateRequest, SkillVersionCreateRequest, SkillVersionResponse, ) router = APIRouter() def get_skill_application_service(db: Session = Depends(get_db)) -> SkillApplicationService: return SkillApplicationService( skill_repository=SkillDefinitionRepository(db), skill_version_repository=SkillVersionRepository(db), installation_repository=SkillInstallationRepository(db), skill_run_repository=SkillRunRepository(db), ) @router.get("/health", response_model=ServiceHealth) def health_check(db: Session = Depends(get_db)) -> ServiceHealth: db.execute(text("SELECT 1")) return ServiceHealth(service="skill-service", status="ok", database="ok") @router.post("", response_model=SkillResponse) def create_skill( payload: SkillCreateRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillResponse: return SkillResponse.from_entity(service.create_skill(payload)) @router.get("", response_model=list[SkillResponse]) def list_skills( tenant_id: str = Query(...), service: SkillApplicationService = Depends(get_skill_application_service), ) -> list[SkillResponse]: return [SkillResponse.from_entity(item) for item in service.list_skills(tenant_id=tenant_id)] @router.patch("/{skill_id}/status", response_model=SkillResponse) def update_skill_status( skill_id: str, payload: SkillStatusUpdateRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillResponse: entity = service.update_skill_status(skill_id=skill_id, payload=payload) if entity is None: raise HTTPException(status_code=404, detail=f"skill not found: {skill_id}") return SkillResponse.from_entity(entity) @router.post("/versions", response_model=SkillVersionResponse) def create_skill_version( payload: SkillVersionCreateRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillVersionResponse: try: return SkillVersionResponse.from_entity(service.create_skill_version(payload)) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc @router.get("/versions", response_model=list[SkillVersionResponse]) def list_skill_versions( tenant_id: str = Query(...), skill_id: str = Query(...), service: SkillApplicationService = Depends(get_skill_application_service), ) -> list[SkillVersionResponse]: return [ SkillVersionResponse.from_entity(item) for item in service.list_skill_versions(tenant_id=tenant_id, skill_id=skill_id) ] @router.post("/installations", response_model=SkillInstallationResponse) def install_skill( payload: SkillInstallRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillInstallationResponse: try: return SkillInstallationResponse.from_entity(service.install_skill(payload)) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc @router.get("/installations", response_model=list[SkillInstallationResponse]) def list_installations( tenant_id: str = Query(...), install_scope: str | None = Query(default=None), scope_id: str | None = Query(default=None), service: SkillApplicationService = Depends(get_skill_application_service), ) -> list[SkillInstallationResponse]: return [ SkillInstallationResponse.from_entity(item) for item in service.list_installations( tenant_id=tenant_id, install_scope=install_scope, scope_id=scope_id, ) ] @router.patch("/installations/{installation_id}/status", response_model=SkillInstallationResponse) def update_installation_status( installation_id: str, payload: SkillInstallationStatusUpdateRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillInstallationResponse: entity = service.update_installation_status(installation_id=installation_id, payload=payload) if entity is None: raise HTTPException(status_code=404, detail=f"skill installation not found: {installation_id}") return SkillInstallationResponse.from_entity(entity) @router.post("/runs", response_model=SkillRunResponse) def create_skill_run( payload: SkillRunCreateRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillRunResponse: try: return SkillRunResponse.from_entity(service.create_skill_run(payload)) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc @router.post("/runs/{skill_run_id}/execute", response_model=SkillRunResponse) def execute_skill_run( skill_run_id: str, payload: SkillRunExecuteRequest, service: SkillApplicationService = Depends(get_skill_application_service), ) -> SkillRunResponse: entity = service.execute_skill_run(skill_run_id=skill_run_id, payload=payload) if entity is None: raise HTTPException(status_code=404, detail=f"skill_run not found: {skill_run_id}") return SkillRunResponse.from_entity(entity)