From cab26484389adfec2026960012f6483a487a2f88 Mon Sep 17 00:00:00 2001 From: Eric Zawadski Date: Wed, 8 Jan 2025 13:29:04 -0800 Subject: [PATCH] feat(backend): added verbose title and description to path and query params in agents router --- src/backend/routers/agent.py | 223 +++++++++---------------- src/backend/schemas/params/__init__.py | 0 src/backend/schemas/params/agent.py | 19 +++ src/backend/schemas/params/shared.py | 25 +++ 4 files changed, 119 insertions(+), 148 deletions(-) create mode 100644 src/backend/schemas/params/__init__.py create mode 100644 src/backend/schemas/params/agent.py create mode 100644 src/backend/schemas/params/shared.py diff --git a/src/backend/routers/agent.py b/src/backend/routers/agent.py index 0c63f3dc16..4c6db8481f 100644 --- a/src/backend/routers/agent.py +++ b/src/backend/routers/agent.py @@ -1,7 +1,7 @@ import asyncio -from typing import Optional +from typing import Annotated, Optional -from fastapi import APIRouter, Depends, HTTPException +from fastapi import APIRouter, Depends, HTTPException, Query from fastapi import File as RequestFile from fastapi import UploadFile as FastAPIUploadFile @@ -41,6 +41,12 @@ FileMetadata, UploadAgentFileResponse, ) +from backend.schemas.params.agent import ( + agent_id_path, + agent_tool_metadata_id_path, + file_id_path, +) +from backend.schemas.params.shared import PaginationQueryParams from backend.services.agent import ( raise_db_error, validate_agent_exists, @@ -72,19 +78,13 @@ ], ) async def create_agent( - session: DBSessionDep, agent: CreateAgentRequest, + session: DBSessionDep, ctx: Context = Depends(get_context), ) -> AgentPublic: """ Create an agent. - Args: - session (DBSessionDep): Database session. - agent (CreateAgentRequest): Agent data. - ctx (Context): Context object. - Returns: - AgentPublic: Created agent with no user ID or organization ID. Raises: HTTPException: If the agent creation fails. """ @@ -129,22 +129,21 @@ async def create_agent( @router.get("", response_model=list[AgentPublic]) async def list_agents( *, - offset: int = 0, - limit: int = 100, + page_params: Annotated[PaginationQueryParams, Depends()], + visibility: Annotated[AgentVisibility, Query( + title="Visibility", + description="Agent visibility", + )] = AgentVisibility.ALL, + organization_id: Annotated[Optional[str], Query( + title="Organization ID", + description="Organization ID of the agent", + )] = None, session: DBSessionDep, - visibility: AgentVisibility = AgentVisibility.ALL, - organization_id: Optional[str] = None, ctx: Context = Depends(get_context), ) -> list[AgentPublic]: """ List all agents. - Args: - offset (int): Offset to start the list. - limit (int): Limit of agents to be listed. - session (DBSessionDep): Database session. - ctx (Context): Context object. - Returns: list[AgentPublic]: List of agents with no user ID or organization ID. """ @@ -159,8 +158,8 @@ async def list_agents( agents = agent_crud.get_agents( session, user_id=user_id, - offset=offset, - limit=limit, + offset=page_params.offset, + limit=page_params.limit, visibility=visibility, organization_id=organization_id, ) @@ -174,16 +173,12 @@ async def list_agents( @router.get("/{agent_id}", response_model=AgentPublic) async def get_agent_by_id( - agent_id: str, session: DBSessionDep, ctx: Context = Depends(get_context) + agent_id: Annotated[str, agent_id_path], + session: DBSessionDep, + ctx: Context = Depends(get_context) ) -> AgentPublic: """ - Args: - agent_id (str): Agent ID. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - Agent: Agent. + Return an agent by ID. Raises: HTTPException: If the agent with the given ID is not found. @@ -213,16 +208,12 @@ async def get_agent_by_id( @router.get("/{agent_id}/deployments", response_model=list[DeploymentSchema]) async def get_agent_deployment( - agent_id: str, session: DBSessionDep, ctx: Context = Depends(get_context) + agent_id: Annotated[str, agent_id_path], + session: DBSessionDep, + ctx: Context = Depends(get_context) ) -> DeploymentSchema: """ - Args: - agent_id (str): Agent ID. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - Agent: Agent. + Get the deployment for an agent Raises: HTTPException: If the agent with the given ID is not found. @@ -245,23 +236,14 @@ async def get_agent_deployment( ], ) async def update_agent( - agent_id: str, - new_agent: UpdateAgentRequest, - session: DBSessionDep, - ctx: Context = Depends(get_context), + agent_id: Annotated[str, agent_id_path], + new_agent: UpdateAgentRequest, + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> AgentPublic: """ Update an agent by ID. - Args: - agent_id (str): Agent ID. - new_agent (UpdateAgentRequest): New agent data. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - AgentPublic: Updated agent with no user ID or organization ID. - Raises: HTTPException: If the agent with the given ID is not found. """ @@ -281,7 +263,7 @@ async def update_agent( try: db_deployment, db_model = get_deployment_model_from_agent(new_agent, session) - new_agent_db = UpdateAgentDB(**new_agent.dict()) + new_agent_db = UpdateAgentDB(**new_agent.model_dump()) if db_deployment and db_model: new_agent_db.model_id = db_model.id new_agent_db.deployment_id = db_deployment.id @@ -302,21 +284,13 @@ async def update_agent( @router.delete("/{agent_id}", response_model=DeleteAgent) async def delete_agent( - agent_id: str, - session: DBSessionDep, - ctx: Context = Depends(get_context), + agent_id: Annotated[str, agent_id_path], + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> DeleteAgent: """ Delete an agent by ID. - Args: - agent_id (str): Agent ID. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - DeleteAgent: Empty response. - Raises: HTTPException: If the agent with the given ID is not found. """ @@ -336,10 +310,10 @@ async def delete_agent( async def handle_tool_metadata_update( - agent: Agent, - new_agent: Agent, - session: DBSessionDep, - ctx: Context = Depends(get_context), + agent: Agent, + new_agent: Agent, + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> Agent: """Update or create tool metadata for an agent. @@ -377,10 +351,10 @@ async def handle_tool_metadata_update( async def update_or_create_tool_metadata( - agent: Agent, - new_tool_metadata: AgentToolMetadata, - session: DBSessionDep, - ctx: Context = Depends(get_context), + agent: Agent, + new_tool_metadata: AgentToolMetadata, + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> None: """Update or create tool metadata for an agent. @@ -395,30 +369,24 @@ async def update_or_create_tool_metadata( existing_tools_names = [metadata.tool_name for metadata in agent.tools_metadata] if new_tool_metadata.tool_name in existing_tools_names or new_tool_metadata.id: await update_agent_tool_metadata( - agent.id, new_tool_metadata.id, session, new_tool_metadata, ctx + agent.id, new_tool_metadata.id, new_tool_metadata, session, ctx ) else: create_metadata_req = CreateAgentToolMetadataRequest( **new_tool_metadata.model_dump(exclude_none=True) ) - create_agent_tool_metadata(session, agent.id, create_metadata_req, ctx) + create_agent_tool_metadata(agent.id, create_metadata_req, session, ctx) @router.get("/{agent_id}/tool-metadata", response_model=list[AgentToolMetadataPublic]) async def list_agent_tool_metadata( - agent_id: str, session: DBSessionDep, ctx: Context = Depends(get_context) + agent_id: Annotated[str, agent_id_path], + session: DBSessionDep, + ctx: Context = Depends(get_context) ) -> list[AgentToolMetadataPublic]: """ List all agent tool metadata by agent ID. - Args: - agent_id (str): Agent ID. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - list[AgentToolMetadataPublic]: List of agent tool metadata with no user ID or organization ID. - Raises: HTTPException: If the agent tool metadata retrieval fails. """ @@ -438,23 +406,14 @@ async def list_agent_tool_metadata( response_model=AgentToolMetadataPublic, ) def create_agent_tool_metadata( - session: DBSessionDep, - agent_id: str, - agent_tool_metadata: CreateAgentToolMetadataRequest, - ctx: Context = Depends(get_context), + agent_id: Annotated[str, agent_id_path], + agent_tool_metadata: CreateAgentToolMetadataRequest, + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> AgentToolMetadataPublic: """ Create an agent tool metadata. - Args: - session (DBSessionDep): Database session. - agent_id (str): Agent ID. - agent_tool_metadata (CreateAgentToolMetadataRequest): Agent tool metadata data. - ctx (Context): Context object. - - Returns: - AgentToolMetadataPublic: Created agent tool metadata. - Raises: HTTPException: If the agent tool metadata creation fails. """ @@ -487,25 +446,15 @@ def create_agent_tool_metadata( @router.put("/{agent_id}/tool-metadata/{agent_tool_metadata_id}") async def update_agent_tool_metadata( - agent_id: str, - agent_tool_metadata_id: str, - session: DBSessionDep, - new_agent_tool_metadata: UpdateAgentToolMetadataRequest, - ctx: Context = Depends(get_context), + agent_id: Annotated[str, agent_id_path], + agent_tool_metadata_id: Annotated[str, agent_tool_metadata_id_path], + new_agent_tool_metadata: UpdateAgentToolMetadataRequest, + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> AgentToolMetadata: """ Update an agent tool metadata by ID. - Args: - agent_id (str): Agent ID. - agent_tool_metadata_id (str): Agent tool metadata ID. - session (DBSessionDep): Database session. - new_agent_tool_metadata (UpdateAgentToolMetadataRequest): New agent tool metadata data. - ctx (Context): Context object. - - Returns: - AgentToolMetadata: Updated agent tool metadata. - Raises: HTTPException: If the agent tool metadata with the given ID is not found. HTTPException: If the agent tool metadata update fails. @@ -531,23 +480,14 @@ async def update_agent_tool_metadata( @router.delete("/{agent_id}/tool-metadata/{agent_tool_metadata_id}") async def delete_agent_tool_metadata( - agent_id: str, - agent_tool_metadata_id: str, - session: DBSessionDep, - ctx: Context = Depends(get_context), + agent_id: Annotated[str, agent_id_path], + agent_tool_metadata_id: Annotated[str, agent_tool_metadata_id_path], + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> DeleteAgentToolMetadata: """ Delete an agent tool metadata by ID. - Args: - agent_id (str): Agent ID. - agent_tool_metadata_id (str): Agent tool metadata ID. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - DeleteAgentToolMetadata: Empty response. - Raises: HTTPException: If the agent tool metadata with the given ID is not found. HTTPException: If the agent tool metadata deletion fails. @@ -573,10 +513,14 @@ async def delete_agent_tool_metadata( @router.post("/batch_upload_file", response_model=list[UploadAgentFileResponse]) async def batch_upload_file( - session: DBSessionDep, - files: list[FastAPIUploadFile] = RequestFile(...), - ctx: Context = Depends(get_context), + *, + files: list[FastAPIUploadFile] = RequestFile(...), + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> UploadAgentFileResponse: + """ + Upload a batch of files + """ user_id = ctx.get_user_id() uploaded_files = [] @@ -597,23 +541,14 @@ async def batch_upload_file( @router.get("/{agent_id}/files/{file_id}", response_model=FileMetadata) async def get_agent_file( - agent_id: str, - file_id: str, + agent_id: Annotated[str, agent_id_path], + file_id: Annotated[str, file_id_path], session: DBSessionDep, ctx: Context = Depends(get_context), ) -> FileMetadata: """ Get an agent file by ID. - Args: - agent_id (str): Agent ID. - file_id (str): File ID. - session (DBSessionDep): Database session. - ctx (Context): Context object. - - Returns: - FileMetadata: File with the given ID. - Raises: HTTPException: If the agent or file with the given ID is not found, or if the file does not belong to the agent. """ @@ -645,22 +580,14 @@ async def get_agent_file( @router.delete("/{agent_id}/files/{file_id}") async def delete_agent_file( - agent_id: str, - file_id: str, - session: DBSessionDep, - ctx: Context = Depends(get_context), + agent_id: Annotated[str, agent_id_path], + file_id: Annotated[str, file_id_path], + session: DBSessionDep, + ctx: Context = Depends(get_context), ) -> DeleteAgentFileResponse: """ Delete an agent file by ID. - Args: - agent_id (str): Agent ID. - file_id (str): File ID. - session (DBSessionDep): Database session. - - Returns: - DeleteFile: Empty response. - Raises: HTTPException: If the agent with the given ID is not found. """ diff --git a/src/backend/schemas/params/__init__.py b/src/backend/schemas/params/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/backend/schemas/params/agent.py b/src/backend/schemas/params/agent.py new file mode 100644 index 0000000000..287a61f577 --- /dev/null +++ b/src/backend/schemas/params/agent.py @@ -0,0 +1,19 @@ +""" +Query and Path Parameters for Agents +""" +from fastapi import Path + +agent_id_path = Path( + title="Agent ID", + description="Agent ID for agent in question", +) + +agent_tool_metadata_id_path = Path( + title="Agent Tool Metadata ID", + description="Agent Tool Metadata ID for tool metadata in question", +) + +file_id_path = Path( + title="File ID", + description="File ID for file in question", +) diff --git a/src/backend/schemas/params/shared.py b/src/backend/schemas/params/shared.py new file mode 100644 index 0000000000..aef0d5e879 --- /dev/null +++ b/src/backend/schemas/params/shared.py @@ -0,0 +1,25 @@ +""" +Shared Query and Path Parameters for Routers +""" +from typing import Annotated + +from fastapi import Query + + +class PaginationQueryParams: + """ + Common pagination query parameters + """ + def __init__( + self, + offset: Annotated[int, Query( + title="Pagination Offset", + description="Offset for where request should start returning records from", + )] = 0, + limit: Annotated[int, Query( + title="Pagination Limit", + description="Maximum number of records to return per request", + )] = 100, + ) -> None: + self.offset = offset + self.limit = limit