mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
feat(backend): Agent Presets backend improvements (#9786)
- Part of #9307 - ❗ Blocks #9541 ### Changes 🏗️ Backend: - Fix+improve `GET /library/presets` (`list_presets`) endpoint - Fix pagination - Add `graph_id` filter parameter - Allow partial preset updates: `PUT /presets/{preset_id}` -> `PATCH /presets/{preset_id}` - Allow creating preset from graph execution through `POST /presets` - Clean up models & DB functions - Split `upsert_preset` into `create_preset` + `update_preset` - Add `LibraryAgentPresetUpdatable` - Replace `CreateLibraryAgentPresetRequest` with `LibraryAgentPresetCreatable` - Use `LibraryAgentPresetCreatable` as base class for `LibraryAgentPreset` - Remove redundant `set_is_deleted_for_library_agent(..)` - Improve log statements - Improve DB statements (e.g. by using unique keys where possible) Frontend: - Add timestamp parsing logic to library agent preset endpoints - Brand `LibraryAgentPreset.id` + references ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] CI green - Since these changes don't affect existing front-end functionality, no additional testing is needed.
This commit is contained in:
committed by
GitHub
parent
2647417e9f
commit
781f138c09
@@ -211,7 +211,7 @@ class AgentServer(backend.util.service.AppProcess):
|
||||
|
||||
@staticmethod
|
||||
async def test_get_presets(user_id: str, page: int = 1, page_size: int = 10):
|
||||
return await backend.server.v2.library.routes.presets.get_presets(
|
||||
return await backend.server.v2.library.routes.presets.list_presets(
|
||||
user_id=user_id, page=page, page_size=page_size
|
||||
)
|
||||
|
||||
@@ -223,7 +223,7 @@ class AgentServer(backend.util.service.AppProcess):
|
||||
|
||||
@staticmethod
|
||||
async def test_create_preset(
|
||||
preset: backend.server.v2.library.model.CreateLibraryAgentPresetRequest,
|
||||
preset: backend.server.v2.library.model.LibraryAgentPresetCreatable,
|
||||
user_id: str,
|
||||
):
|
||||
return await backend.server.v2.library.routes.presets.create_preset(
|
||||
@@ -233,7 +233,7 @@ class AgentServer(backend.util.service.AppProcess):
|
||||
@staticmethod
|
||||
async def test_update_preset(
|
||||
preset_id: str,
|
||||
preset: backend.server.v2.library.model.CreateLibraryAgentPresetRequest,
|
||||
preset: backend.server.v2.library.model.LibraryAgentPresetUpdatable,
|
||||
user_id: str,
|
||||
):
|
||||
return await backend.server.v2.library.routes.presets.update_preset(
|
||||
|
||||
@@ -16,9 +16,11 @@ import backend.server.v2.store.media as store_media
|
||||
from backend.data import db
|
||||
from backend.data import graph as graph_db
|
||||
from backend.data.db import locked_transaction
|
||||
from backend.data.execution import get_graph_execution
|
||||
from backend.data.includes import library_agent_include
|
||||
from backend.integrations.creds_manager import IntegrationCredentialsManager
|
||||
from backend.integrations.webhooks.graph_lifecycle_hooks import on_graph_activate
|
||||
from backend.util.exceptions import NotFoundError
|
||||
from backend.util.settings import Config
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -145,7 +147,7 @@ async def get_library_agent(id: str, user_id: str) -> library_model.LibraryAgent
|
||||
Get a specific agent from the user's library.
|
||||
|
||||
Args:
|
||||
library_agent_id: ID of the library agent to retrieve.
|
||||
id: ID of the library agent to retrieve.
|
||||
user_id: ID of the authenticated user.
|
||||
|
||||
Returns:
|
||||
@@ -275,7 +277,7 @@ async def create_library_agent(
|
||||
isCreatedByUser=(user_id == graph.user_id),
|
||||
useGraphIsActiveVersion=True,
|
||||
User={"connect": {"id": user_id}},
|
||||
# Creator={"connect": {"id": agent.userId}},
|
||||
# Creator={"connect": {"id": graph.user_id}},
|
||||
AgentGraph={
|
||||
"connect": {
|
||||
"graphVersionId": {"id": graph.id, "version": graph.version}
|
||||
@@ -438,11 +440,13 @@ async def add_store_agent_to_library(
|
||||
|
||||
# Check if user already has this agent
|
||||
existing_library_agent = (
|
||||
await prisma.models.LibraryAgent.prisma().find_first(
|
||||
await prisma.models.LibraryAgent.prisma().find_unique(
|
||||
where={
|
||||
"userId": user_id,
|
||||
"agentGraphId": graph.id,
|
||||
"agentGraphVersion": graph.version,
|
||||
"userId_agentGraphId_agentGraphVersion": {
|
||||
"userId": user_id,
|
||||
"agentGraphId": graph.id,
|
||||
"agentGraphVersion": graph.version,
|
||||
}
|
||||
},
|
||||
include={"AgentGraph": True},
|
||||
)
|
||||
@@ -450,13 +454,13 @@ async def add_store_agent_to_library(
|
||||
if existing_library_agent:
|
||||
if existing_library_agent.isDeleted:
|
||||
# Even if agent exists it needs to be marked as not deleted
|
||||
await set_is_deleted_for_library_agent(
|
||||
user_id, graph.id, graph.version, False
|
||||
await update_library_agent(
|
||||
existing_library_agent.id, user_id, is_deleted=False
|
||||
)
|
||||
else:
|
||||
logger.debug(
|
||||
f"User #{user_id} already has graph #{graph.id} "
|
||||
"in their library"
|
||||
f"v{graph.version} in their library"
|
||||
)
|
||||
return library_model.LibraryAgent.from_db(existing_library_agent)
|
||||
|
||||
@@ -464,8 +468,11 @@ async def add_store_agent_to_library(
|
||||
added_agent = await prisma.models.LibraryAgent.prisma().create(
|
||||
data=prisma.types.LibraryAgentCreateInput(
|
||||
userId=user_id,
|
||||
agentGraphId=graph.id,
|
||||
agentGraphVersion=graph.version,
|
||||
AgentGraph={
|
||||
"connect": {
|
||||
"graphVersionId": {"id": graph.id, "version": graph.version}
|
||||
}
|
||||
},
|
||||
isCreatedByUser=False,
|
||||
),
|
||||
include=library_agent_include(user_id),
|
||||
@@ -485,60 +492,22 @@ async def add_store_agent_to_library(
|
||||
raise store_exceptions.DatabaseError("Failed to add agent to library") from e
|
||||
|
||||
|
||||
async def set_is_deleted_for_library_agent(
|
||||
user_id: str, agent_id: str, agent_version: int, is_deleted: bool
|
||||
) -> None:
|
||||
"""
|
||||
Changes the isDeleted flag for a library agent.
|
||||
|
||||
Args:
|
||||
user_id: The user's library from which the agent is being removed.
|
||||
agent_id: The ID of the agent to remove.
|
||||
agent_version: The version of the agent to remove.
|
||||
is_deleted: Whether the agent is being marked as deleted.
|
||||
|
||||
Raises:
|
||||
DatabaseError: If there's an issue updating the Library
|
||||
"""
|
||||
logger.debug(
|
||||
f"Setting isDeleted={is_deleted} for agent {agent_id} v{agent_version} "
|
||||
f"in library for user {user_id}"
|
||||
)
|
||||
try:
|
||||
logger.warning(
|
||||
f"Setting isDeleted={is_deleted} for agent {agent_id} v{agent_version} in library for user {user_id}"
|
||||
)
|
||||
count = await prisma.models.LibraryAgent.prisma().update_many(
|
||||
where={
|
||||
"userId": user_id,
|
||||
"agentGraphId": agent_id,
|
||||
"agentGraphVersion": agent_version,
|
||||
},
|
||||
data={"isDeleted": is_deleted},
|
||||
)
|
||||
logger.warning(f"Updated {count} isDeleted library agents")
|
||||
except prisma.errors.PrismaError as e:
|
||||
logger.error(f"Database error setting agent isDeleted: {e}")
|
||||
raise store_exceptions.DatabaseError(
|
||||
"Failed to set agent isDeleted in library"
|
||||
) from e
|
||||
|
||||
|
||||
##############################################
|
||||
########### Presets DB Functions #############
|
||||
##############################################
|
||||
|
||||
|
||||
async def get_presets(
|
||||
user_id: str, page: int, page_size: int
|
||||
async def list_presets(
|
||||
user_id: str, page: int, page_size: int, graph_id: Optional[str] = None
|
||||
) -> library_model.LibraryAgentPresetResponse:
|
||||
"""
|
||||
Retrieves a paginated list of AgentPresets for the specified user.
|
||||
|
||||
Args:
|
||||
user_id: The user ID whose presets are being retrieved.
|
||||
page: The current page index (0-based or 1-based, clarify in your domain).
|
||||
page: The current page index (1-based).
|
||||
page_size: Number of items to retrieve per page.
|
||||
graph_id: Agent Graph ID to filter by.
|
||||
|
||||
Returns:
|
||||
A LibraryAgentPresetResponse containing a list of presets and pagination info.
|
||||
@@ -550,21 +519,24 @@ async def get_presets(
|
||||
f"Fetching presets for user #{user_id}, page={page}, page_size={page_size}"
|
||||
)
|
||||
|
||||
if page < 0 or page_size < 1:
|
||||
if page < 1 or page_size < 1:
|
||||
logger.warning(
|
||||
"Invalid pagination input: page=%d, page_size=%d", page, page_size
|
||||
)
|
||||
raise store_exceptions.DatabaseError("Invalid pagination parameters")
|
||||
|
||||
query_filter: prisma.types.AgentPresetWhereInput = {"userId": user_id}
|
||||
if graph_id:
|
||||
query_filter["agentGraphId"] = graph_id
|
||||
|
||||
try:
|
||||
presets_records = await prisma.models.AgentPreset.prisma().find_many(
|
||||
where={"userId": user_id},
|
||||
skip=page * page_size,
|
||||
where=query_filter,
|
||||
skip=(page - 1) * page_size,
|
||||
take=page_size,
|
||||
include={"InputPresets": True},
|
||||
)
|
||||
total_items = await prisma.models.AgentPreset.prisma().count(
|
||||
where={"userId": user_id}
|
||||
)
|
||||
total_items = await prisma.models.AgentPreset.prisma().count(where=query_filter)
|
||||
total_pages = (total_items + page_size - 1) // page_size
|
||||
|
||||
presets = [
|
||||
@@ -617,69 +589,142 @@ async def get_preset(
|
||||
raise store_exceptions.DatabaseError("Failed to fetch preset") from e
|
||||
|
||||
|
||||
async def upsert_preset(
|
||||
async def create_preset(
|
||||
user_id: str,
|
||||
preset: library_model.CreateLibraryAgentPresetRequest,
|
||||
preset_id: Optional[str] = None,
|
||||
preset: library_model.LibraryAgentPresetCreatable,
|
||||
) -> library_model.LibraryAgentPreset:
|
||||
"""
|
||||
Creates or updates an AgentPreset for a user.
|
||||
Creates a new AgentPreset for a user.
|
||||
|
||||
Args:
|
||||
user_id: The ID of the user creating/updating the preset.
|
||||
preset: The preset data used for creation or update.
|
||||
preset_id: An optional preset ID to update; if None, a new preset is created.
|
||||
user_id: The ID of the user creating the preset.
|
||||
preset: The preset data used for creation.
|
||||
|
||||
Returns:
|
||||
The newly created or updated LibraryAgentPreset.
|
||||
The newly created LibraryAgentPreset.
|
||||
|
||||
Raises:
|
||||
DatabaseError: If there's a database error in creating or updating the preset.
|
||||
DatabaseError: If there's a database error in creating the preset.
|
||||
"""
|
||||
logger.debug(
|
||||
f"Creating preset ({repr(preset.name)}) for user #{user_id}",
|
||||
)
|
||||
try:
|
||||
new_preset = await prisma.models.AgentPreset.prisma().create(
|
||||
data=prisma.types.AgentPresetCreateInput(
|
||||
userId=user_id,
|
||||
name=preset.name,
|
||||
description=preset.description,
|
||||
agentGraphId=preset.graph_id,
|
||||
agentGraphVersion=preset.graph_version,
|
||||
isActive=preset.is_active,
|
||||
InputPresets={
|
||||
"create": [
|
||||
prisma.types.AgentNodeExecutionInputOutputCreateWithoutRelationsInput( # noqa
|
||||
name=name, data=prisma.fields.Json(data)
|
||||
)
|
||||
for name, data in preset.inputs.items()
|
||||
]
|
||||
},
|
||||
),
|
||||
include={"InputPresets": True},
|
||||
)
|
||||
return library_model.LibraryAgentPreset.from_db(new_preset)
|
||||
except prisma.errors.PrismaError as e:
|
||||
logger.error(f"Database error creating preset: {e}")
|
||||
raise store_exceptions.DatabaseError("Failed to create preset") from e
|
||||
|
||||
|
||||
async def create_preset_from_graph_execution(
|
||||
user_id: str,
|
||||
create_request: library_model.LibraryAgentPresetCreatableFromGraphExecution,
|
||||
) -> library_model.LibraryAgentPreset:
|
||||
"""
|
||||
Creates a new AgentPreset from an AgentGraphExecution.
|
||||
|
||||
Params:
|
||||
user_id: The ID of the user creating the preset.
|
||||
create_request: The data used for creation.
|
||||
|
||||
Returns:
|
||||
The newly created LibraryAgentPreset.
|
||||
|
||||
Raises:
|
||||
DatabaseError: If there's a database error in creating the preset.
|
||||
"""
|
||||
graph_exec_id = create_request.graph_execution_id
|
||||
graph_execution = await get_graph_execution(user_id, graph_exec_id)
|
||||
if not graph_execution:
|
||||
raise NotFoundError(f"Graph execution #{graph_exec_id} not found")
|
||||
|
||||
logger.debug(
|
||||
f"Creating preset for user #{user_id} from graph execution #{graph_exec_id}",
|
||||
)
|
||||
return await create_preset(
|
||||
user_id=user_id,
|
||||
preset=library_model.LibraryAgentPresetCreatable(
|
||||
inputs=graph_execution.inputs,
|
||||
graph_id=graph_execution.graph_id,
|
||||
graph_version=graph_execution.graph_version,
|
||||
name=create_request.name,
|
||||
description=create_request.description,
|
||||
is_active=create_request.is_active,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def update_preset(
|
||||
user_id: str,
|
||||
preset_id: str,
|
||||
preset: library_model.LibraryAgentPresetUpdatable,
|
||||
) -> library_model.LibraryAgentPreset:
|
||||
"""
|
||||
Updates an existing AgentPreset for a user.
|
||||
|
||||
Args:
|
||||
user_id: The ID of the user updating the preset.
|
||||
preset_id: The ID of the preset to update.
|
||||
preset: The preset data used for the update.
|
||||
|
||||
Returns:
|
||||
The updated LibraryAgentPreset.
|
||||
|
||||
Raises:
|
||||
DatabaseError: If there's a database error in updating the preset.
|
||||
ValueError: If attempting to update a non-existent preset.
|
||||
"""
|
||||
logger.debug(
|
||||
f"Upserting preset #{preset_id} ({repr(preset.name)}) for user #{user_id}",
|
||||
f"Updating preset #{preset_id} ({repr(preset.name)}) for user #{user_id}",
|
||||
)
|
||||
try:
|
||||
inputs = [
|
||||
prisma.types.AgentNodeExecutionInputOutputCreateWithoutRelationsInput(
|
||||
name=name, data=prisma.fields.Json(data)
|
||||
)
|
||||
for name, data in preset.inputs.items()
|
||||
]
|
||||
if preset_id:
|
||||
# Update existing preset
|
||||
updated = await prisma.models.AgentPreset.prisma().update(
|
||||
where={"id": preset_id},
|
||||
data={
|
||||
"name": preset.name,
|
||||
"description": preset.description,
|
||||
"isActive": preset.is_active,
|
||||
"InputPresets": {"create": inputs},
|
||||
},
|
||||
include={"InputPresets": True},
|
||||
)
|
||||
if not updated:
|
||||
raise ValueError(f"AgentPreset #{preset_id} not found")
|
||||
return library_model.LibraryAgentPreset.from_db(updated)
|
||||
else:
|
||||
# Create new preset
|
||||
new_preset = await prisma.models.AgentPreset.prisma().create(
|
||||
data=prisma.types.AgentPresetCreateInput(
|
||||
userId=user_id,
|
||||
name=preset.name,
|
||||
description=preset.description,
|
||||
agentGraphId=preset.graph_id,
|
||||
agentGraphVersion=preset.graph_version,
|
||||
isActive=preset.is_active,
|
||||
InputPresets={"create": inputs},
|
||||
),
|
||||
include={"InputPresets": True},
|
||||
)
|
||||
return library_model.LibraryAgentPreset.from_db(new_preset)
|
||||
update_data: prisma.types.AgentPresetUpdateInput = {}
|
||||
if preset.name:
|
||||
update_data["name"] = preset.name
|
||||
if preset.description:
|
||||
update_data["description"] = preset.description
|
||||
if preset.inputs:
|
||||
update_data["InputPresets"] = {
|
||||
"create": [
|
||||
prisma.types.AgentNodeExecutionInputOutputCreateWithoutRelationsInput( # noqa
|
||||
name=name, data=prisma.fields.Json(data)
|
||||
)
|
||||
for name, data in preset.inputs.items()
|
||||
]
|
||||
}
|
||||
if preset.is_active:
|
||||
update_data["isActive"] = preset.is_active
|
||||
|
||||
updated = await prisma.models.AgentPreset.prisma().update(
|
||||
where={"id": preset_id},
|
||||
data=update_data,
|
||||
include={"InputPresets": True},
|
||||
)
|
||||
if not updated:
|
||||
raise ValueError(f"AgentPreset #{preset_id} not found")
|
||||
return library_model.LibraryAgentPreset.from_db(updated)
|
||||
except prisma.errors.PrismaError as e:
|
||||
logger.error(f"Database error upserting preset: {e}")
|
||||
raise store_exceptions.DatabaseError("Failed to create preset") from e
|
||||
logger.error(f"Database error updating preset: {e}")
|
||||
raise store_exceptions.DatabaseError("Failed to update preset") from e
|
||||
|
||||
|
||||
async def delete_preset(user_id: str, preset_id: str) -> None:
|
||||
|
||||
@@ -168,27 +168,62 @@ class LibraryAgentResponse(pydantic.BaseModel):
|
||||
pagination: server_model.Pagination
|
||||
|
||||
|
||||
class LibraryAgentPreset(pydantic.BaseModel):
|
||||
class LibraryAgentPresetCreatable(pydantic.BaseModel):
|
||||
"""
|
||||
Request model used when creating a new preset for a library agent.
|
||||
"""
|
||||
|
||||
graph_id: str
|
||||
graph_version: int
|
||||
|
||||
inputs: block_model.BlockInput
|
||||
|
||||
name: str
|
||||
description: str
|
||||
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class LibraryAgentPresetCreatableFromGraphExecution(pydantic.BaseModel):
|
||||
"""
|
||||
Request model used when creating a new preset for a library agent.
|
||||
"""
|
||||
|
||||
graph_execution_id: str
|
||||
|
||||
name: str
|
||||
description: str
|
||||
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class LibraryAgentPresetUpdatable(pydantic.BaseModel):
|
||||
"""
|
||||
Request model used when updating a preset for a library agent.
|
||||
"""
|
||||
|
||||
inputs: Optional[block_model.BlockInput] = None
|
||||
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
|
||||
class LibraryAgentPreset(LibraryAgentPresetCreatable):
|
||||
"""Represents a preset configuration for a library agent."""
|
||||
|
||||
id: str
|
||||
updated_at: datetime.datetime
|
||||
|
||||
graph_id: str
|
||||
graph_version: int
|
||||
|
||||
name: str
|
||||
description: str
|
||||
|
||||
is_active: bool
|
||||
|
||||
inputs: block_model.BlockInput
|
||||
|
||||
@classmethod
|
||||
def from_db(cls, preset: prisma.models.AgentPreset) -> "LibraryAgentPreset":
|
||||
if preset.InputPresets is None:
|
||||
raise ValueError("Input values must be included in object")
|
||||
|
||||
input_data: block_model.BlockInput = {}
|
||||
|
||||
for preset_input in preset.InputPresets or []:
|
||||
for preset_input in preset.InputPresets:
|
||||
input_data[preset_input.name] = preset_input.data
|
||||
|
||||
return cls(
|
||||
@@ -210,19 +245,6 @@ class LibraryAgentPresetResponse(pydantic.BaseModel):
|
||||
pagination: server_model.Pagination
|
||||
|
||||
|
||||
class CreateLibraryAgentPresetRequest(pydantic.BaseModel):
|
||||
"""
|
||||
Request model used when creating a new preset for a library agent.
|
||||
"""
|
||||
|
||||
name: str
|
||||
description: str
|
||||
inputs: block_model.BlockInput
|
||||
graph_id: str
|
||||
graph_version: int
|
||||
is_active: bool
|
||||
|
||||
|
||||
class LibraryAgentFilter(str, Enum):
|
||||
"""Possible filters for searching library agents."""
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import logging
|
||||
from typing import Annotated, Any
|
||||
from typing import Annotated, Any, Optional
|
||||
|
||||
import autogpt_libs.auth as autogpt_auth_lib
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException, status
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
|
||||
|
||||
import backend.server.v2.library.db as db
|
||||
import backend.server.v2.library.model as models
|
||||
from backend.executor.utils import add_graph_execution_async
|
||||
from backend.util.exceptions import NotFoundError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -18,10 +19,13 @@ router = APIRouter()
|
||||
summary="List presets",
|
||||
description="Retrieve a paginated list of presets for the current user.",
|
||||
)
|
||||
async def get_presets(
|
||||
async def list_presets(
|
||||
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
page: int = Query(default=1, ge=1),
|
||||
page_size: int = Query(default=10, ge=1),
|
||||
graph_id: Optional[str] = Query(
|
||||
description="Allows to filter presets by a specific agent graph"
|
||||
),
|
||||
) -> models.LibraryAgentPresetResponse:
|
||||
"""
|
||||
Retrieve a paginated list of presets for the current user.
|
||||
@@ -30,12 +34,18 @@ async def get_presets(
|
||||
user_id (str): ID of the authenticated user.
|
||||
page (int): Page number for pagination.
|
||||
page_size (int): Number of items per page.
|
||||
graph_id: Allows to filter presets by a specific agent graph.
|
||||
|
||||
Returns:
|
||||
models.LibraryAgentPresetResponse: A response containing the list of presets.
|
||||
"""
|
||||
try:
|
||||
return await db.get_presets(user_id, page, page_size)
|
||||
return await db.list_presets(
|
||||
user_id=user_id,
|
||||
graph_id=graph_id,
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception occurred while getting presets: {e}")
|
||||
raise HTTPException(
|
||||
@@ -88,14 +98,17 @@ async def get_preset(
|
||||
description="Create a new preset for the current user.",
|
||||
)
|
||||
async def create_preset(
|
||||
preset: models.CreateLibraryAgentPresetRequest,
|
||||
preset: (
|
||||
models.LibraryAgentPresetCreatable
|
||||
| models.LibraryAgentPresetCreatableFromGraphExecution
|
||||
),
|
||||
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
|
||||
) -> models.LibraryAgentPreset:
|
||||
"""
|
||||
Create a new library agent preset. Automatically corrects node_input format if needed.
|
||||
|
||||
Args:
|
||||
preset (models.CreateLibraryAgentPresetRequest): The preset data to create.
|
||||
preset (models.LibraryAgentPresetCreatable): The preset data to create.
|
||||
user_id (str): ID of the authenticated user.
|
||||
|
||||
Returns:
|
||||
@@ -105,7 +118,12 @@ async def create_preset(
|
||||
HTTPException: If an error occurs while creating the preset.
|
||||
"""
|
||||
try:
|
||||
return await db.upsert_preset(user_id, preset)
|
||||
if isinstance(preset, models.LibraryAgentPresetCreatable):
|
||||
return await db.create_preset(user_id, preset)
|
||||
else:
|
||||
return await db.create_preset_from_graph_execution(user_id, preset)
|
||||
except NotFoundError as e:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception occurred while creating preset: {e}")
|
||||
raise HTTPException(
|
||||
@@ -114,22 +132,22 @@ async def create_preset(
|
||||
)
|
||||
|
||||
|
||||
@router.put(
|
||||
@router.patch(
|
||||
"/presets/{preset_id}",
|
||||
summary="Update an existing preset",
|
||||
description="Update an existing preset by its ID.",
|
||||
)
|
||||
async def update_preset(
|
||||
preset_id: str,
|
||||
preset: models.CreateLibraryAgentPresetRequest,
|
||||
preset: models.LibraryAgentPresetUpdatable,
|
||||
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
|
||||
) -> models.LibraryAgentPreset:
|
||||
"""
|
||||
Update an existing library agent preset. If the preset doesn't exist, it may be created.
|
||||
Update an existing library agent preset.
|
||||
|
||||
Args:
|
||||
preset_id (str): ID of the preset to update.
|
||||
preset (models.CreateLibraryAgentPresetRequest): The preset data to update.
|
||||
preset (models.LibraryAgentPresetUpdatable): The preset data to update.
|
||||
user_id (str): ID of the authenticated user.
|
||||
|
||||
Returns:
|
||||
@@ -139,7 +157,9 @@ async def update_preset(
|
||||
HTTPException: If an error occurs while updating the preset.
|
||||
"""
|
||||
try:
|
||||
return await db.upsert_preset(user_id, preset, preset_id)
|
||||
return await db.update_preset(
|
||||
user_id=user_id, preset_id=preset_id, preset=preset
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(f"Exception occurred whilst updating preset: {e}")
|
||||
raise HTTPException(
|
||||
|
||||
@@ -357,7 +357,7 @@ async def test_execute_preset(server: SpinTestServer):
|
||||
test_graph = await create_graph(server, test_graph, test_user)
|
||||
|
||||
# Create preset with initial values
|
||||
preset = backend.server.v2.library.model.CreateLibraryAgentPresetRequest(
|
||||
preset = backend.server.v2.library.model.LibraryAgentPresetCreatable(
|
||||
name="Test Preset With Clash",
|
||||
description="Test preset with clashing input values",
|
||||
graph_id=test_graph.id,
|
||||
@@ -446,7 +446,7 @@ async def test_execute_preset_with_clash(server: SpinTestServer):
|
||||
test_graph = await create_graph(server, test_graph, test_user)
|
||||
|
||||
# Create preset with initial values
|
||||
preset = backend.server.v2.library.model.CreateLibraryAgentPresetRequest(
|
||||
preset = backend.server.v2.library.model.LibraryAgentPresetCreatable(
|
||||
name="Test Preset With Clash",
|
||||
description="Test preset with clashing input values",
|
||||
graph_id=test_graph.id,
|
||||
|
||||
@@ -8,7 +8,7 @@ export default function LibraryAgentCard({
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
graph_id: agent_id,
|
||||
graph_id,
|
||||
can_access_graph,
|
||||
creator_image_url,
|
||||
image_url,
|
||||
@@ -86,7 +86,7 @@ export default function LibraryAgentCard({
|
||||
|
||||
{can_access_graph && (
|
||||
<Link
|
||||
href={`/build?flowID=${agent_id}`}
|
||||
href={`/build?flowID=${graph_id}`}
|
||||
className="text-lg font-semibold text-neutral-800 hover:underline dark:text-neutral-200"
|
||||
>
|
||||
Open in builder
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
GraphExecutionMeta,
|
||||
LibraryAgent,
|
||||
NodeExecutionResult,
|
||||
SpecialBlockID,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
import { GraphExecutionMeta, LibraryAgent } from "@/lib/autogpt-server-api";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import Link from "next/link";
|
||||
import { Button, buttonVariants } from "@/components/ui/button";
|
||||
|
||||
@@ -10,7 +10,6 @@ import type {
|
||||
APIKeyPermission,
|
||||
Block,
|
||||
CreateAPIKeyResponse,
|
||||
CreateLibraryAgentPresetRequest,
|
||||
CreatorDetails,
|
||||
CreatorsResponse,
|
||||
Credentials,
|
||||
@@ -29,7 +28,11 @@ import type {
|
||||
LibraryAgent,
|
||||
LibraryAgentID,
|
||||
LibraryAgentPreset,
|
||||
LibraryAgentPresetCreatable,
|
||||
LibraryAgentPresetCreatableFromGraphExecution,
|
||||
LibraryAgentPresetID,
|
||||
LibraryAgentPresetResponse,
|
||||
LibraryAgentPresetUpdatable,
|
||||
LibraryAgentResponse,
|
||||
LibraryAgentSortEnum,
|
||||
MyAgentsResponse,
|
||||
@@ -642,42 +645,63 @@ export default class BackendAPI {
|
||||
return this._request("POST", `/library/agents/${libraryAgentId}/fork`);
|
||||
}
|
||||
|
||||
listLibraryAgentPresets(params?: {
|
||||
async listLibraryAgentPresets(params?: {
|
||||
graph_id?: GraphID;
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
}): Promise<LibraryAgentPresetResponse> {
|
||||
return this._get("/library/presets", params);
|
||||
const response: LibraryAgentPresetResponse = await this._get(
|
||||
"/library/presets",
|
||||
params,
|
||||
);
|
||||
return {
|
||||
...response,
|
||||
presets: response.presets.map(parseLibraryAgentPresetTimestamp),
|
||||
};
|
||||
}
|
||||
|
||||
getLibraryAgentPreset(presetId: string): Promise<LibraryAgentPreset> {
|
||||
return this._get(`/library/presets/${presetId}`);
|
||||
}
|
||||
|
||||
createLibraryAgentPreset(
|
||||
preset: CreateLibraryAgentPresetRequest,
|
||||
async getLibraryAgentPreset(
|
||||
presetID: LibraryAgentPresetID,
|
||||
): Promise<LibraryAgentPreset> {
|
||||
return this._request("POST", "/library/presets", preset);
|
||||
const preset = await this._get(`/library/presets/${presetID}`);
|
||||
return parseLibraryAgentPresetTimestamp(preset);
|
||||
}
|
||||
|
||||
updateLibraryAgentPreset(
|
||||
presetId: string,
|
||||
preset: CreateLibraryAgentPresetRequest,
|
||||
async createLibraryAgentPreset(
|
||||
params:
|
||||
| LibraryAgentPresetCreatable
|
||||
| LibraryAgentPresetCreatableFromGraphExecution,
|
||||
): Promise<LibraryAgentPreset> {
|
||||
return this._request("PUT", `/library/presets/${presetId}`, preset);
|
||||
const new_preset = await this._request("POST", "/library/presets", params);
|
||||
return parseLibraryAgentPresetTimestamp(new_preset);
|
||||
}
|
||||
|
||||
async deleteLibraryAgentPreset(presetId: string): Promise<void> {
|
||||
await this._request("DELETE", `/library/presets/${presetId}`);
|
||||
async updateLibraryAgentPreset(
|
||||
presetID: LibraryAgentPresetID,
|
||||
partial_preset: LibraryAgentPresetUpdatable,
|
||||
): Promise<LibraryAgentPreset> {
|
||||
const updated_preset = await this._request(
|
||||
"PATCH",
|
||||
`/library/presets/${presetID}`,
|
||||
partial_preset,
|
||||
);
|
||||
return parseLibraryAgentPresetTimestamp(updated_preset);
|
||||
}
|
||||
|
||||
async deleteLibraryAgentPreset(
|
||||
presetID: LibraryAgentPresetID,
|
||||
): Promise<void> {
|
||||
await this._request("DELETE", `/library/presets/${presetID}`);
|
||||
}
|
||||
|
||||
executeLibraryAgentPreset(
|
||||
presetId: string,
|
||||
graphId: GraphID,
|
||||
presetID: LibraryAgentPresetID,
|
||||
graphID: GraphID,
|
||||
graphVersion: number,
|
||||
nodeInput: { [key: string]: any },
|
||||
): Promise<{ id: string }> {
|
||||
return this._request("POST", `/library/presets/${presetId}/execute`, {
|
||||
graph_id: graphId,
|
||||
): Promise<{ id: GraphExecutionID }> {
|
||||
return this._request("POST", `/library/presets/${presetID}/execute`, {
|
||||
graph_id: graphID,
|
||||
graph_version: graphVersion,
|
||||
node_input: nodeInput,
|
||||
});
|
||||
@@ -1133,6 +1157,10 @@ function parseScheduleTimestamp(result: any): Schedule {
|
||||
return _parseObjectTimestamps<Schedule>(result, ["next_run_time"]);
|
||||
}
|
||||
|
||||
function parseLibraryAgentPresetTimestamp(result: any): LibraryAgentPreset {
|
||||
return _parseObjectTimestamps<LibraryAgentPreset>(result, ["updated_at"]);
|
||||
}
|
||||
|
||||
function _parseObjectTimestamps<T>(obj: any, keys: (keyof T)[]): T {
|
||||
const result = { ...obj };
|
||||
keys.forEach(
|
||||
|
||||
@@ -276,7 +276,7 @@ export type GraphExecutionMeta = {
|
||||
user_id: UserID;
|
||||
graph_id: GraphID;
|
||||
graph_version: number;
|
||||
preset_id?: string;
|
||||
preset_id?: LibraryAgentPresetID;
|
||||
status: "QUEUED" | "RUNNING" | "COMPLETED" | "TERMINATED" | "FAILED";
|
||||
started_at: Date;
|
||||
ended_at: Date;
|
||||
@@ -414,7 +414,7 @@ export enum AgentStatus {
|
||||
ERROR = "ERROR",
|
||||
}
|
||||
|
||||
export interface LibraryAgentResponse {
|
||||
export type LibraryAgentResponse = {
|
||||
agents: LibraryAgent[];
|
||||
pagination: {
|
||||
current_page: number;
|
||||
@@ -422,36 +422,47 @@ export interface LibraryAgentResponse {
|
||||
total_items: number;
|
||||
total_pages: number;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export interface LibraryAgentPreset {
|
||||
id: string;
|
||||
export type LibraryAgentPreset = {
|
||||
id: LibraryAgentPresetID;
|
||||
updated_at: Date;
|
||||
graph_id: GraphID;
|
||||
graph_version: number;
|
||||
inputs: { [key: string]: any };
|
||||
name: string;
|
||||
description: string;
|
||||
is_active: boolean;
|
||||
inputs: { [key: string]: any };
|
||||
}
|
||||
};
|
||||
|
||||
export interface LibraryAgentPresetResponse {
|
||||
export type LibraryAgentPresetID = Brand<string, "LibraryAgentPresetID">;
|
||||
|
||||
export type LibraryAgentPresetResponse = {
|
||||
presets: LibraryAgentPreset[];
|
||||
pagination: {
|
||||
total: number;
|
||||
page: number;
|
||||
size: number;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export interface CreateLibraryAgentPresetRequest {
|
||||
name: string;
|
||||
description: string;
|
||||
inputs: { [key: string]: any };
|
||||
graph_id: GraphID;
|
||||
graph_version: number;
|
||||
is_active: boolean;
|
||||
}
|
||||
export type LibraryAgentPresetCreatable = Omit<
|
||||
LibraryAgentPreset,
|
||||
"id" | "updated_at" | "is_active"
|
||||
> & {
|
||||
is_active?: boolean;
|
||||
};
|
||||
|
||||
export type LibraryAgentPresetCreatableFromGraphExecution = Omit<
|
||||
LibraryAgentPresetCreatable,
|
||||
"graph_id" | "graph_version" | "inputs"
|
||||
> & {
|
||||
graph_execution_id: GraphExecutionID;
|
||||
};
|
||||
|
||||
export type LibraryAgentPresetUpdatable = Partial<
|
||||
Omit<LibraryAgentPresetCreatable, "graph_id" | "graph_version">
|
||||
>;
|
||||
|
||||
export enum LibraryAgentSortEnum {
|
||||
CREATED_AT = "createdAt",
|
||||
|
||||
Reference in New Issue
Block a user