|
12 | 12 |
|
13 | 13 | from oss.src.core.mounts.service import MountsService |
14 | 14 | from oss.src.core.mounts.types import ( |
| 15 | + MountArtifactIdInvalid, |
15 | 16 | MountDataInvalid, |
16 | 17 | MountFileNotFound, |
17 | 18 | MountImmutableField, |
|
24 | 25 | ) |
25 | 26 |
|
26 | 27 | from oss.src.apis.fastapi.mounts.models import ( |
| 28 | + AgentMountQueryRequest, |
27 | 29 | MountCreateRequest, |
28 | 30 | MountCredentialsResponse, |
29 | 31 | MountEditRequest, |
@@ -65,6 +67,11 @@ async def wrapper(*args, **kwargs): |
65 | 67 | status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, |
66 | 68 | detail=e.message, |
67 | 69 | ) from e |
| 70 | + except MountArtifactIdInvalid as e: |
| 71 | + raise HTTPException( |
| 72 | + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, |
| 73 | + detail=e.message, |
| 74 | + ) from e |
68 | 75 | except MountSlugConflict as e: |
69 | 76 | raise HTTPException( |
70 | 77 | status_code=status.HTTP_409_CONFLICT, |
@@ -130,6 +137,25 @@ def __init__( |
130 | 137 | response_model_exclude_none=True, |
131 | 138 | status_code=status.HTTP_200_OK, |
132 | 139 | ) |
| 140 | + # Fixed agent sub-paths must be registered before "/{mount_id}" so they win. |
| 141 | + self.router.add_api_route( |
| 142 | + "/agents/sign", |
| 143 | + self.sign_agent_mount_credentials, |
| 144 | + methods=["POST"], |
| 145 | + operation_id="sign_agent_mount_credentials", |
| 146 | + response_model=MountCredentialsResponse, |
| 147 | + response_model_exclude_none=True, |
| 148 | + status_code=status.HTTP_200_OK, |
| 149 | + ) |
| 150 | + self.router.add_api_route( |
| 151 | + "/agents/query", |
| 152 | + self.query_agent_mount, |
| 153 | + methods=["POST"], |
| 154 | + operation_id="query_agent_mount", |
| 155 | + response_model=MountsResponse, |
| 156 | + response_model_exclude_none=True, |
| 157 | + status_code=status.HTTP_200_OK, |
| 158 | + ) |
133 | 159 | self.router.add_api_route( |
134 | 160 | "/{mount_id}", |
135 | 161 | self.fetch_mount, |
@@ -284,6 +310,48 @@ async def query_mounts( |
284 | 310 |
|
285 | 311 | return MountsResponse(count=len(mounts), mounts=mounts) |
286 | 312 |
|
| 313 | + @intercept_exceptions() |
| 314 | + @handle_mount_exceptions() |
| 315 | + async def sign_agent_mount_credentials( |
| 316 | + self, |
| 317 | + request: Request, |
| 318 | + *, |
| 319 | + artifact_id: str = Query(...), |
| 320 | + name: str = Query(default="default"), |
| 321 | + ) -> MountCredentialsResponse: |
| 322 | + await self._check(request, Permission.RUN_SESSIONS) |
| 323 | + |
| 324 | + mount = await self.mounts_service.get_or_create_agent_mount( |
| 325 | + project_id=UUID(request.state.project_id), |
| 326 | + user_id=UUID(str(request.state.user_id)), |
| 327 | + artifact_id=artifact_id, |
| 328 | + name=name, |
| 329 | + ) |
| 330 | + credentials = await sign_mount_credentials( |
| 331 | + mounts_service=self.mounts_service, |
| 332 | + project_id=UUID(request.state.project_id), |
| 333 | + mount_id=mount.id, |
| 334 | + ) |
| 335 | + return MountCredentialsResponse(count=1, mount=mount, credentials=credentials) |
| 336 | + |
| 337 | + @intercept_exceptions() |
| 338 | + @handle_mount_exceptions() |
| 339 | + async def query_agent_mount( |
| 340 | + self, |
| 341 | + request: Request, |
| 342 | + *, |
| 343 | + body: AgentMountQueryRequest, |
| 344 | + ) -> MountsResponse: |
| 345 | + await self._check(request, Permission.VIEW_SESSIONS) |
| 346 | + |
| 347 | + mount = await self.mounts_service.fetch_agent_mount( |
| 348 | + project_id=UUID(request.state.project_id), |
| 349 | + artifact_id=body.artifact_id, |
| 350 | + name=body.name, |
| 351 | + ) |
| 352 | + mounts = [mount] if mount else [] |
| 353 | + return MountsResponse(count=len(mounts), mounts=mounts) |
| 354 | + |
287 | 355 | @intercept_exceptions() |
288 | 356 | async def fetch_mount( |
289 | 357 | self, |
|
0 commit comments