feat: make repository reads alias-aware
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a049a4-ee9f-78e1-9d66-2cb0f9bea3e3
This commit is contained in:
parent
639b9aed08
commit
2e2ae1e5d0
19 changed files with 982 additions and 94 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import re
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from fastapi import HTTPException
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
|
|
@ -11,7 +11,6 @@ from api.models.agent_message import AgentMessage
|
|||
from api.models.capability_catalog import CapabilityCatalog
|
||||
from api.models.capability_request import CapabilityRequest
|
||||
from api.models.domain import Domain
|
||||
from api.models.managed_repo import ManagedRepo
|
||||
from api.models.task import Task
|
||||
from api.services.suggestion_relevance import bump_matching_for_capability_request
|
||||
from api.schemas.capability_request import (
|
||||
|
|
@ -22,12 +21,15 @@ from api.schemas.capability_request import (
|
|||
CapabilityRequestRead,
|
||||
CapabilityRequestReroute,
|
||||
CapabilityRequestStatusPatch,
|
||||
CatalogCreate,
|
||||
CatalogPatch,
|
||||
CatalogRead,
|
||||
)
|
||||
from hub_core.routers.capabilities import (
|
||||
create_capability_catalog_router,
|
||||
create_capability_request_read_router,
|
||||
create_capability_request_write_router,
|
||||
)
|
||||
from api.services.repository_aliases import resolve_repository_slug
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -394,12 +396,102 @@ def _check_transition(current: str, target: str) -> None:
|
|||
)
|
||||
|
||||
|
||||
router = create_capability_catalog_router(
|
||||
get_session,
|
||||
domain_model=Domain,
|
||||
repo_model=ManagedRepo,
|
||||
catalog_model=CapabilityCatalog,
|
||||
router = APIRouter(tags=["capability-requests"])
|
||||
|
||||
|
||||
async def _catalog_domain(slug: str, session: AsyncSession) -> Domain:
|
||||
domain = (
|
||||
await session.execute(select(Domain).where(Domain.slug == slug))
|
||||
).scalar_one_or_none()
|
||||
if domain is None:
|
||||
raise HTTPException(status_code=404, detail=f"Domain '{slug}' not found")
|
||||
return domain
|
||||
|
||||
|
||||
@router.post(
|
||||
"/capability-catalog/",
|
||||
response_model=CatalogRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
async def create_catalog_entry(
|
||||
body: CatalogCreate,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> CapabilityCatalog:
|
||||
domain = await _catalog_domain(body.domain, session)
|
||||
repo_id = None
|
||||
if body.repo_slug:
|
||||
repo_id = (await resolve_repository_slug(session, body.repo_slug)).repo.id
|
||||
entry = CapabilityCatalog(
|
||||
domain_id=domain.id,
|
||||
repo_id=repo_id,
|
||||
capability_type=body.capability_type,
|
||||
title=body.title,
|
||||
description=body.description,
|
||||
keywords=body.keywords,
|
||||
)
|
||||
session.add(entry)
|
||||
try:
|
||||
await session.commit()
|
||||
except Exception:
|
||||
await session.rollback()
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail=(
|
||||
f"Catalog entry '{body.title}' for type '{body.capability_type}' "
|
||||
f"already exists in domain '{body.domain}'"
|
||||
),
|
||||
)
|
||||
await session.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
@router.get("/capability-catalog/", response_model=list[CatalogRead])
|
||||
async def list_catalog(
|
||||
domain: str | None = Query(None),
|
||||
capability_type: str | None = Query(None),
|
||||
status_filter: str | None = Query(None, alias="status"),
|
||||
repo_slug: str | None = Query(None),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> list[CapabilityCatalog]:
|
||||
query = select(CapabilityCatalog).order_by(CapabilityCatalog.created_at.desc())
|
||||
if domain:
|
||||
query = query.where(
|
||||
CapabilityCatalog.domain_id == (await _catalog_domain(domain, session)).id
|
||||
)
|
||||
if capability_type:
|
||||
query = query.where(CapabilityCatalog.capability_type == capability_type)
|
||||
if repo_slug:
|
||||
query = query.where(
|
||||
CapabilityCatalog.repo_id
|
||||
== (await resolve_repository_slug(session, repo_slug)).repo.id
|
||||
)
|
||||
if status_filter and status_filter != "all":
|
||||
query = query.where(CapabilityCatalog.status == status_filter)
|
||||
elif not status_filter:
|
||||
query = query.where(CapabilityCatalog.status == "active")
|
||||
return list((await session.execute(query)).scalars().all())
|
||||
|
||||
|
||||
@router.patch("/capability-catalog/{entry_id}", response_model=CatalogRead)
|
||||
async def patch_catalog_entry(
|
||||
entry_id: uuid.UUID,
|
||||
body: CatalogPatch,
|
||||
session: AsyncSession = Depends(get_session),
|
||||
) -> CapabilityCatalog:
|
||||
entry = await session.get(CapabilityCatalog, entry_id)
|
||||
if entry is None:
|
||||
raise HTTPException(status_code=404, detail=f"Catalog entry '{entry_id}' not found")
|
||||
if body.repo_slug is not None:
|
||||
entry.repo_id = (await resolve_repository_slug(session, body.repo_slug)).repo.id
|
||||
for field in ("description", "keywords", "status"):
|
||||
value = getattr(body, field)
|
||||
if value is not None:
|
||||
setattr(entry, field, value)
|
||||
await session.commit()
|
||||
await session.refresh(entry)
|
||||
return entry
|
||||
|
||||
|
||||
router.include_router(
|
||||
create_capability_request_read_router(
|
||||
get_session,
|
||||
|
|
@ -432,4 +524,4 @@ router.include_router(
|
|||
after_dispute=_notify_on_dispute,
|
||||
after_reroute=_notify_on_reroute,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue