from core_domain import ServiceHealth from core_shared.secrets import SecretCipher from fastapi import APIRouter, Depends, HTTPException, Query, Request from sqlalchemy import text from sqlalchemy.orm import Session from app.application.services import ToolApplicationService from app.bootstrap.settings import ToolServiceSettings from app.db.session import get_db from app.domain.repositories import ( ToolBindingRepository, ToolCredentialRepository, ToolDefinitionRepository, ToolVersionRepository, ) from app.schemas.tool import ( ToolBindingCreateRequest, ToolBindingDetailResponse, ToolBindingResponse, ToolCreateRequest, ToolCredentialCreateRequest, ToolCredentialResponse, ToolCredentialRevealResponse, ToolResponse, ToolVersionCreateRequest, ToolVersionResponse, ) router = APIRouter() def get_tool_application_service( request: Request, db: Session = Depends(get_db)) -> ToolApplicationService: settings: ToolServiceSettings = request.app.state.settings return ToolApplicationService( tool_definition_repository=ToolDefinitionRepository(db), tool_version_repository=ToolVersionRepository(db), tool_binding_repository=ToolBindingRepository(db), tool_credential_repository=ToolCredentialRepository(db), secret_cipher=SecretCipher(key=settings.credential_encryption_key)) @router.get("/health", response_model=ServiceHealth) def health_check(db: Session = Depends(get_db)) -> ServiceHealth: db.execute(text("SELECT 1")) return ServiceHealth(service="tool-service", status="ok", database="ok") @router.post("", response_model=ToolResponse) def create_tool_definition( payload: ToolCreateRequest, service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolResponse: entity = service.create_tool_definition(payload) return ToolResponse.from_entity(entity) @router.get("", response_model=list[ToolResponse]) def list_tool_definitions( service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolResponse]: return [ToolResponse.from_entity(item) for item in service.list_tool_definitions()] @router.post("/versions", response_model=ToolVersionResponse) def create_tool_version( payload: ToolVersionCreateRequest, service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolVersionResponse: entity = service.create_tool_version(payload) return ToolVersionResponse.from_entity(entity) @router.get("/versions", response_model=list[ToolVersionResponse]) def list_tool_versions( tool_id: str = Query(...), service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolVersionResponse]: return [ ToolVersionResponse.from_entity(item) for item in service.list_tool_versions(tool_id=tool_id) ] @router.post("/bindings", response_model=ToolBindingResponse) def create_tool_binding( payload: ToolBindingCreateRequest, service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolBindingResponse: try: entity = service.create_tool_binding(payload) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc return ToolBindingResponse.from_entity(entity) @router.get("/bindings", response_model=list[ToolBindingResponse]) def list_tool_bindings( app_id: str | None = Query(default=None), service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolBindingResponse]: return [ ToolBindingResponse.from_entity(item) for item in service.list_tool_bindings(app_id=app_id) ] @router.get("/bindings/{binding_id}", response_model=ToolBindingDetailResponse) def get_tool_binding_detail( binding_id: str, service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolBindingDetailResponse: result = service.get_tool_binding_detail(binding_id=binding_id) if result is None: raise HTTPException(status_code=404, detail=f"tool_binding not found: {binding_id}") binding, tool_version, tool_definition = result return ToolBindingDetailResponse( binding=ToolBindingResponse.from_entity(binding), tool_version=ToolVersionResponse.from_entity(tool_version), tool_definition=ToolResponse.from_entity(tool_definition)) @router.post("/credentials", response_model=ToolCredentialResponse) def create_tool_credential( payload: ToolCredentialCreateRequest, service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolCredentialResponse: entity = service.create_tool_credential(payload) return ToolCredentialResponse.from_entity(entity) @router.get("/credentials", response_model=list[ToolCredentialResponse]) def list_tool_credentials( service: ToolApplicationService = Depends(get_tool_application_service)) -> list[ToolCredentialResponse]: return [ ToolCredentialResponse.from_entity(item) for item in service.list_tool_credentials() ] @router.post("/credentials/{credential_id}/reveal", response_model=ToolCredentialRevealResponse) def reveal_tool_credential( credential_id: str, service: ToolApplicationService = Depends(get_tool_application_service)) -> ToolCredentialRevealResponse: result = service.reveal_tool_credential( credential_id=credential_id) if result is None: raise HTTPException(status_code=404, detail=f"tool credential not found: {credential_id}") credential, secret_json = result return ToolCredentialRevealResponse( credential=ToolCredentialResponse.from_entity(credential), secret_json=secret_json)