From fca04b85aaf341d0f9216ef2241b4a09189c55b5 Mon Sep 17 00:00:00 2001 From: Dmitry Paramonov Date: Wed, 31 Jul 2024 14:17:28 +0300 Subject: [PATCH] feat: Create new and update existing routes --- .../agents_api/routers/agents/create_agent.py | 27 +-- .../routers/agents/create_agent_tools.py | 35 ++++ .../routers/agents/create_or_update_agent.py | 33 ++++ .../routers/agents/delete_agent_tools.py | 28 +++ .../routers/agents/list_agent_tools.py | 31 ++++ .../routers/agents/patch_agent_tools.py | 32 ++++ .../routers/agents/update_agent_tools.py | 32 ++++ .../agents_api/routers/tasks/routers.py | 164 ++++++++++++++---- 8 files changed, 334 insertions(+), 48 deletions(-) create mode 100644 agents-api/agents_api/routers/agents/create_agent_tools.py create mode 100644 agents-api/agents_api/routers/agents/create_or_update_agent.py create mode 100644 agents-api/agents_api/routers/agents/delete_agent_tools.py create mode 100644 agents-api/agents_api/routers/agents/list_agent_tools.py create mode 100644 agents-api/agents_api/routers/agents/patch_agent_tools.py create mode 100644 agents-api/agents_api/routers/agents/update_agent_tools.py diff --git a/agents-api/agents_api/routers/agents/create_agent.py b/agents-api/agents_api/routers/agents/create_agent.py index 12029adb8..d1b04e1f4 100644 --- a/agents-api/agents_api/routers/agents/create_agent.py +++ b/agents-api/agents_api/routers/agents/create_agent.py @@ -5,7 +5,10 @@ from pydantic import UUID4 from starlette.status import HTTP_201_CREATED -from ...autogen.openapi_model import CreateAgentRequest, ResourceCreatedResponse +from ...autogen.openapi_model import ( + CreateAgentRequest, + ResourceCreatedResponse, +) from ...dependencies.developer_id import get_developer_id from ...models.agent.create_agent import create_agent as create_agent_query from .router import router @@ -18,17 +21,17 @@ async def create_agent( ) -> ResourceCreatedResponse: new_agent_id = uuid4() - resp = create_agent_query( - developer_id=x_developer_id, - agent_id=new_agent_id, - name=request.name, - about=request.about, - instructions=request.instructions or [], - model=request.model, - default_settings=request.default_settings or {}, - metadata=request.metadata or {}, + _, resp = next( + create_agent_query( + developer_id=x_developer_id, + agent_id=new_agent_id, + name=request.name, + about=request.about, + instructions=request.instructions or [], + model=request.model, + default_settings=request.default_settings or {}, + metadata=request.metadata or {}, + ).iterrows() ) - resp.iterrows() - return ResourceCreatedResponse(id=new_agent_id, created_at=resp["created_at"]) diff --git a/agents-api/agents_api/routers/agents/create_agent_tools.py b/agents-api/agents_api/routers/agents/create_agent_tools.py new file mode 100644 index 000000000..50667e05c --- /dev/null +++ b/agents-api/agents_api/routers/agents/create_agent_tools.py @@ -0,0 +1,35 @@ +from typing import Annotated +from uuid import UUID, uuid4 + +from fastapi import Depends +from pydantic import UUID4 +from starlette.status import HTTP_201_CREATED + +from ...autogen.openapi_model import ( + CreateAgentRequest, + CreateOrUpdateAgentRequest, + CreateToolRequest, + ResourceCreatedResponse, +) +from ...dependencies.developer_id import get_developer_id +from ...models.tools.create_tools import create_tools as create_tools_query +from .router import router + + +@router.post("/agents/{agent_id}/tools", status_code=HTTP_201_CREATED, tags=["agents"]) +async def create_agent_tools( + agent_id: UUID, + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + data: list[CreateToolRequest], + ignore_existing: bool = False, +) -> ResourceCreatedResponse: + _, resp = next( + create_tools_query( + developer_id=x_developer_id, + agent_id=agent_id, + data=data, + ignore_existing=ignore_existing, + ).iterrows() + ) + + return ResourceCreatedResponse(id=resp["tool_id"], created_at=resp["created_at"]) diff --git a/agents-api/agents_api/routers/agents/create_or_update_agent.py b/agents-api/agents_api/routers/agents/create_or_update_agent.py new file mode 100644 index 000000000..bcd53f800 --- /dev/null +++ b/agents-api/agents_api/routers/agents/create_or_update_agent.py @@ -0,0 +1,33 @@ +from typing import Annotated +from uuid import UUID + +from fastapi import Depends +from pydantic import UUID4 +from starlette.status import HTTP_201_CREATED + +from ...autogen.openapi_model import ( + CreateOrUpdateAgentRequest, + ResourceCreatedResponse, +) +from ...dependencies.developer_id import get_developer_id +from ...models.agent.create_or_update_agent import ( + create_or_update_agent as create_or_update_agent_query, +) +from .router import router + + +@router.post("/agents/{agent_id}", status_code=HTTP_201_CREATED, tags=["agents"]) +async def create_or_update_agent( + agent_id: UUID, + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + data: CreateOrUpdateAgentRequest, +) -> ResourceCreatedResponse: + _, resp = next( + create_or_update_agent_query( + developer_id=x_developer_id, + agent_id=agent_id, + data=data, + ).iterrows() + ) + + return ResourceCreatedResponse(id=agent_id, created_at=resp["created_at"]) diff --git a/agents-api/agents_api/routers/agents/delete_agent_tools.py b/agents-api/agents_api/routers/agents/delete_agent_tools.py new file mode 100644 index 000000000..b1177b094 --- /dev/null +++ b/agents-api/agents_api/routers/agents/delete_agent_tools.py @@ -0,0 +1,28 @@ +from typing import Annotated +from uuid import UUID + +from fastapi import Depends +from pydantic import UUID4 + +from ...autogen.openapi_model import ResourceDeletedResponse +from ...common.utils.datetime import utcnow +from ...dependencies.developer_id import get_developer_id +from ...models.tools.delete_tools import delete_tool as delete_tool_query +from .router import router + + +@router.delete("/agents/{agent_id}/tools/{tool_id}", tags=["agents"]) +async def delete_agent_tools( + agent_id: UUID, + tool_id: UUID, + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], +) -> ResourceDeletedResponse: + _, resp = next( + delete_tool_query( + developer_id=x_developer_id, + agent_id=agent_id, + tool_id=tool_id, + ).iterrows() + ) + + return ResourceDeletedResponse(id=resp["tool_id"], deleted_at=utcnow()) diff --git a/agents-api/agents_api/routers/agents/list_agent_tools.py b/agents-api/agents_api/routers/agents/list_agent_tools.py new file mode 100644 index 000000000..d4068d8a2 --- /dev/null +++ b/agents-api/agents_api/routers/agents/list_agent_tools.py @@ -0,0 +1,31 @@ +from typing import Annotated, Literal +from uuid import UUID + +from fastapi import Depends +from pydantic import UUID4 + +from ...dependencies.developer_id import get_developer_id +from ...models.tools.list_tools import list_tools as list_tools_query +from .router import router + + +@router.get("/agents/{agent_id}/tools", tags=["agents"]) +async def list_agent_tools( + agent_id: UUID, + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + limit: int = 100, + offset: int = 0, + sort_by: Literal["created_at", "updated_at"] = "created_at", + direction: Literal["asc", "desc"] = "desc", +) -> list[tuple[str, dict]]: + return [ + row + for _, row in list_tools_query( + developer_id=x_developer_id, + agent_id=agent_id, + limit=limit, + offset=offset, + sort_by=sort_by, + direction=direction, + ).iterrows() + ] diff --git a/agents-api/agents_api/routers/agents/patch_agent_tools.py b/agents-api/agents_api/routers/agents/patch_agent_tools.py new file mode 100644 index 000000000..ab8e0c206 --- /dev/null +++ b/agents-api/agents_api/routers/agents/patch_agent_tools.py @@ -0,0 +1,32 @@ +from typing import Annotated +from uuid import UUID + +from fastapi import Depends +from pydantic import UUID4 + +from ...autogen.openapi_model import ( + PatchToolRequest, + ResourceUpdatedResponse, +) +from ...dependencies.developer_id import get_developer_id +from ...models.tools.patch_tool import patch_tool as patch_tool_query +from .router import router + + +@router.patch("/agents/{agent_id}/tools/{tool_id}", tags=["agents"]) +async def patch_agent_tools( + agent_id: UUID, + tool_id: UUID, + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + patch_tool: PatchToolRequest, +) -> ResourceUpdatedResponse: + _, resp = next( + patch_tool_query( + developer_id=x_developer_id, + agent_id=agent_id, + tool_id=tool_id, + patch_tool=patch_tool, + ).iterrows() + ) + + return ResourceUpdatedResponse(id=resp["tool_id"], updated_at=resp["updated_at"]) diff --git a/agents-api/agents_api/routers/agents/update_agent_tools.py b/agents-api/agents_api/routers/agents/update_agent_tools.py new file mode 100644 index 000000000..ac51afd16 --- /dev/null +++ b/agents-api/agents_api/routers/agents/update_agent_tools.py @@ -0,0 +1,32 @@ +from typing import Annotated +from uuid import UUID + +from fastapi import Depends +from pydantic import UUID4 + +from ...autogen.openapi_model import ( + ResourceUpdatedResponse, + UpdateToolRequest, +) +from ...dependencies.developer_id import get_developer_id +from ...models.tools.update_tool import update_tool as update_tool_query +from .router import router + + +@router.put("/agents/{agent_id}/tools/{tool_id}", tags=["agents"]) +async def update_agent_tools( + agent_id: UUID, + tool_id: UUID, + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + data: UpdateToolRequest, +) -> ResourceUpdatedResponse: + _, resp = next( + update_tool_query( + developer_id=x_developer_id, + agent_id=agent_id, + tool_id=tool_id, + data=data, + ).iterrows() + ) + + return ResourceUpdatedResponse(id=resp["tool_id"], updated_at=resp["updated_at"]) diff --git a/agents-api/agents_api/routers/tasks/routers.py b/agents-api/agents_api/routers/tasks/routers.py index 84583721d..737ddf0c0 100644 --- a/agents-api/agents_api/routers/tasks/routers.py +++ b/agents-api/agents_api/routers/tasks/routers.py @@ -1,5 +1,5 @@ import logging -from typing import Annotated +from typing import Annotated, Literal from uuid import uuid4 import pandas as pd @@ -15,7 +15,7 @@ CreateTaskRequest, Execution, ResourceCreatedResponse, - ResourceUpdatedResponse, + # ResourceUpdatedResponse, Task, Transition, UpdateExecutionRequest, @@ -30,21 +30,26 @@ from agents_api.models.execution.get_execution import ( get_execution as get_execution_query, ) -from agents_api.models.execution.get_execution_transition import ( - get_execution_transition as get_execution_transition_query, -) + +# from agents_api.models.execution.get_execution_transition import ( +# get_execution_transition as get_execution_transition_query, +# ) from agents_api.models.execution.list_execution_transitions import ( list_execution_transitions as list_execution_transitions_query, ) +from agents_api.models.execution.list_executions import ( + list_executions as list_executions_query, +) from agents_api.models.execution.list_executions import ( list_executions as list_task_executions_query, ) from agents_api.models.execution.update_execution import ( - update_execution as update_execution_status_query, -) -from agents_api.models.execution.update_execution_transition import ( - update_execution_transition_query, + update_execution as update_execution_query, ) + +# from agents_api.models.execution.update_execution_transition import ( +# update_execution_transition_query, +# ) from agents_api.models.task.create_task import create_task as create_task_query from agents_api.models.task.get_task import get_task as get_task_query from agents_api.models.task.list_tasks import list_tasks as list_tasks_query @@ -74,9 +79,16 @@ async def list_tasks( x_developer_id: Annotated[UUID4, Depends(get_developer_id)], limit: int = 100, offset: int = 0, + sort_by: Literal["created_at", "updated_at"] = "created_at", + direction: Literal["asc", "desc"] = "desc", ) -> TaskList: query_results = list_tasks_query( - agent_id=agent_id, developer_id=x_developer_id, limit=limit, offset=offset + agent_id=agent_id, + developer_id=x_developer_id, + limit=limit, + offset=offset, + sort_by=sort_by, + direction=direction, ) items = [] @@ -219,7 +231,7 @@ async def create_task_execution( except Exception as e: logger.exception(e) - update_execution_status_query( + update_execution_query( developer_id=x_developer_id, task_id=task_id, execution_id=execution_id, @@ -251,12 +263,12 @@ async def list_task_executions( ) -@router.get("/tasks/{task_id}/executions/{execution_id}", tags=["tasks"]) +@router.get("/executions/{execution_id}", tags=["executions"]) async def get_execution(task_id: UUID4, execution_id: UUID4) -> Execution: try: res = [ row.to_dict() - for _, row in get_execution_query(task_id, execution_id).iterrows() + for _, row in get_execution_query(execution_id=execution_id).iterrows() ][0] return Execution(**res) except (IndexError, KeyError): @@ -266,51 +278,131 @@ async def get_execution(task_id: UUID4, execution_id: UUID4) -> Execution: ) -@router.get("/executions/{execution_id}/transitions/{transition_id}", tags=["tasks"]) -async def get_execution_transition( +# TODO: write PATCH query +@router.patch("/tasks/{task_id}/executions/{execution_id}", tags=["tasks"]) +async def patch_execution( + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + task_id: UUID4, execution_id: UUID4, - transition_id: UUID4, -) -> Transition: + data: UpdateExecutionRequest, +) -> Execution: try: res = [ row.to_dict() - for _, row in get_execution_transition_query( - execution_id, transition_id + for _, row in update_execution_query( + developer_id=x_developer_id, + task_id=task_id, + execution_id=execution_id, + data=data, ).iterrows() ][0] - return Transition(**res) + return Execution(**res) except (IndexError, KeyError): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Transition not found", + detail="Execution not found", ) -# TODO: Later; for resuming waiting transitions -# TODO: Ask for a task token to resume a waiting transition -@router.put("/executions/{execution_id}/transitions/{transition_id}", tags=["tasks"]) -async def update_execution_transition( +@router.put("/tasks/{task_id}/executions/{execution_id}", tags=["tasks"]) +async def put_execution( + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + task_id: UUID4, execution_id: UUID4, - transition_id: UUID4, - request: Transition, -) -> ResourceUpdatedResponse: + data: UpdateExecutionRequest, +) -> Execution: try: - resp = update_execution_transition_query( - execution_id, transition_id, **request.model_dump() + res = [ + row.to_dict() + for _, row in update_execution_query( + developer_id=x_developer_id, + task_id=task_id, + execution_id=execution_id, + data=data, + ).iterrows() + ][0] + return Execution(**res) + except (IndexError, KeyError): + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Execution not found", ) - return ResourceUpdatedResponse( - id=resp["transition_id"][0], - updated_at=resp["updated_at"][0][0], - ) + +@router.get("/tasks/{task_id}/executions", tags=["tasks"]) +async def list_execution( + x_developer_id: Annotated[UUID4, Depends(get_developer_id)], + task_id: UUID4, + limit: int = 100, + offset: int = 0, + sort_by: Literal["created_at", "updated_at"] = "created_at", + direction: Literal["asc", "desc"] = "desc", +) -> list[Execution]: + try: + res = [ + Execution(**row.to_dict()) + for _, row in list_executions_query( + developer_id=x_developer_id, + task_id=task_id, + limit=limit, + offset=offset, + sort_by=sort_by, + direction=direction, + ).iterrows() + ] + return res except (IndexError, KeyError): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Transition not found", + detail="Execution not found", ) -@router.get("/executions/{execution_id}/transitions", tags=["tasks"]) +# @router.get("/executions/{execution_id}/transitions/{transition_id}", tags=["tasks"]) +# async def get_execution_transition( +# execution_id: UUID4, +# transition_id: UUID4, +# ) -> Transition: +# try: +# res = [ +# row.to_dict() +# for _, row in get_execution_transition_query( +# execution_id, transition_id +# ).iterrows() +# ][0] +# return Transition(**res) +# except (IndexError, KeyError): +# raise HTTPException( +# status_code=status.HTTP_404_NOT_FOUND, +# detail="Transition not found", +# ) + + +# TODO: Later; for resuming waiting transitions +# TODO: Ask for a task token to resume a waiting transition +# @router.put("/executions/{execution_id}/transitions/{transition_id}", tags=["tasks"]) +# async def update_execution_transition( +# execution_id: UUID4, +# transition_id: UUID4, +# request: Transition, +# ) -> ResourceUpdatedResponse: +# try: +# resp = update_execution_transition_query( +# execution_id, transition_id, **request.model_dump() +# ) + +# return ResourceUpdatedResponse( +# id=resp["transition_id"][0], +# updated_at=resp["updated_at"][0][0], +# ) +# except (IndexError, KeyError): +# raise HTTPException( +# status_code=status.HTTP_404_NOT_FOUND, +# detail="Transition not found", +# ) + + +@router.get("/executions/{execution_id}/transitions", tags=["executions"]) async def list_execution_transitions( execution_id: UUID4, limit: int = 100,