added preset functionality

This commit is contained in:
SwiftyOS
2025-01-07 10:58:41 +01:00
parent 7e80401083
commit 69747cc891
7 changed files with 363 additions and 0 deletions

View File

@@ -56,3 +56,18 @@ class SetGraphActiveVersion(pydantic.BaseModel):
class UpdatePermissionsRequest(pydantic.BaseModel):
permissions: List[APIKeyPermission]
class Pagination(pydantic.BaseModel):
total_items: int = pydantic.Field(
description="Total number of items.", examples=[42]
)
total_pages: int = pydantic.Field(
description="Total number of pages.", examples=[97]
)
current_page: int = pydantic.Field(
description="Current_page page number.", examples=[1]
)
page_size: int = pydantic.Field(
description="Number of items per page.", examples=[25]
)

View File

@@ -1,3 +1,4 @@
import json
import logging
from typing import List
@@ -7,6 +8,7 @@ import prisma.types
import backend.data.graph
import backend.data.includes
import backend.server.model
import backend.server.v2.library.model
import backend.server.v2.store.exceptions
@@ -163,3 +165,122 @@ async def add_agent_to_library(store_listing_version_id: str, user_id: str) -> N
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to add agent to library"
) from e
##############################################
########### Presets DB Functions #############
##############################################
async def get_presets(
user_id: str, page: int, page_size: int
) -> backend.server.v2.library.model.LibraryAgentPresetResponse:
try:
presets = await prisma.models.AgentPreset.prisma().find_many(
where={"userId": user_id},
skip=page * page_size,
take=page_size,
)
total_items = await prisma.models.AgentPreset.prisma().count(
where={"userId": user_id},
)
total_pages = (total_items + page_size - 1) // page_size
presets = [
backend.server.v2.library.model.LibraryAgentPreset.from_db(preset)
for preset in presets
]
return backend.server.v2.library.model.LibraryAgentPresetResponse(
presets=presets,
pagination=backend.server.model.Pagination(
total_items=total_items,
total_pages=total_pages,
current_page=page,
page_size=page_size,
),
)
except prisma.errors.PrismaError as e:
logger.error(f"Database error getting presets: {str(e)}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch presets"
) from e
async def get_preset(
user_id: str, preset_id: str
) -> backend.server.v2.library.model.LibraryAgentPreset | None:
try:
preset = await prisma.models.AgentPreset.prisma().find_unique(
where={"id": preset_id, "userId": user_id}
)
if not preset:
return None
return backend.server.v2.library.model.LibraryAgentPreset.from_db(preset)
except prisma.errors.PrismaError as e:
logger.error(f"Database error getting preset: {str(e)}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch preset"
) from e
async def create_or_update_preset(
user_id: str,
preset: backend.server.v2.library.model.CreateLibraryAgentPresetRequest,
preset_id: str | None = None,
) -> backend.server.v2.library.model.LibraryAgentPreset:
try:
new_preset = await prisma.models.AgentPreset.prisma().upsert(
where={
"id": preset_id if preset_id else "",
},
data={
"create": prisma.types.AgentPresetCreateInput(
userId=user_id,
name=preset.name,
description=preset.description,
agentId=preset.agent_id,
agentVersion=preset.agent_version,
Agent=prisma.types.AgentGraphUpdateOneWithoutRelationsInput(
connect=prisma.types.AgentGraphWhereUniqueInput(
id=preset.agent_id,
version=preset.agent_version,
),
),
isActive=preset.is_active,
InputPresets={
"create": [
{"name": name, "data": json.dumps(data)}
for name, data in preset.inputs.items()
]
},
),
"update": prisma.types.AgentPresetUpdateInput(
name=preset.name,
description=preset.description,
isActive=preset.is_active,
),
},
)
return backend.server.v2.library.model.LibraryAgentPreset.from_db(new_preset)
except prisma.errors.PrismaError as e:
logger.error(f"Database error creating preset: {str(e)}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to create preset"
) from e
async def delete_preset(user_id: str, preset_id: str) -> None:
try:
await prisma.models.AgentPreset.prisma().update(
where={"id": preset_id, "userId": user_id},
data={"isDeleted": True},
)
except prisma.errors.PrismaError as e:
logger.error(f"Database error deleting preset: {str(e)}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to delete preset"
) from e

View File

@@ -1,7 +1,13 @@
import datetime
import json
import typing
import prisma.models
import pydantic
import backend.data.block
import backend.server.model
class LibraryAgent(pydantic.BaseModel):
id: str # Changed from agent_id to match GraphMeta
@@ -14,3 +20,49 @@ class LibraryAgent(pydantic.BaseModel):
# Made input_schema and output_schema match GraphMeta's type
input_schema: dict[str, typing.Any] # Should be BlockIOObjectSubSchema in frontend
output_schema: dict[str, typing.Any] # Should be BlockIOObjectSubSchema in frontend
class LibraryAgentPreset(pydantic.BaseModel):
id: str
updated_at: datetime.datetime
agent_id: str
agent_version: int
name: str
description: str
is_active: bool
inputs: dict[str, backend.data.block.BlockInput]
@staticmethod
def from_db(preset: prisma.models.AgentPreset):
input_data = {}
for data in preset.InputPresets or []:
input_data[data.name] = json.loads(data.data)
return LibraryAgentPreset(
id=preset.id,
updated_at=preset.updatedAt,
agent_id=preset.agentId,
agent_version=preset.agentVersion,
name=preset.name,
description=preset.description,
is_active=preset.isActive,
inputs=input_data,
)
class LibraryAgentPresetResponse(pydantic.BaseModel):
presets: list[LibraryAgentPreset]
pagination: backend.server.model.Pagination
class CreateLibraryAgentPresetRequest(pydantic.BaseModel):
name: str
description: str
inputs: dict[str, backend.data.block.BlockInput]
agent_id: str
agent_version: int
is_active: bool

View File

@@ -1,3 +1,7 @@
from datetime import datetime
import backend.data.block
import backend.server.model
import backend.server.v2.library.model
@@ -41,3 +45,84 @@ def test_library_agent_with_user_created():
assert agent.isCreatedByUser is True
assert agent.input_schema == {"type": "object", "properties": {}}
assert agent.output_schema == {"type": "object", "properties": {}}
def test_library_agent_preset():
preset = backend.server.v2.library.model.LibraryAgentPreset(
id="preset-123",
name="Test Preset",
description="Test preset description",
agent_id="test-agent-123",
agent_version=1,
is_active=True,
inputs={
"input1": backend.data.block.BlockInput(
name="input1",
data={"type": "string", "value": "test value"},
)
},
updated_at=datetime.now(),
)
assert preset.id == "preset-123"
assert preset.name == "Test Preset"
assert preset.description == "Test preset description"
assert preset.agent_id == "test-agent-123"
assert preset.agent_version == 1
assert preset.is_active is True
assert preset.inputs == {"input1": "test value"}
def test_library_agent_preset_response():
preset = backend.server.v2.library.model.LibraryAgentPreset(
id="preset-123",
name="Test Preset",
description="Test preset description",
agent_id="test-agent-123",
agent_version=1,
is_active=True,
inputs={
"input1": backend.data.block.BlockInput(
name="input1",
data={"type": "string", "value": "test value"},
)
},
updated_at=datetime.now(),
)
pagination = backend.server.model.Pagination(
total_items=1, total_pages=1, current_page=1, page_size=10
)
response = backend.server.v2.library.model.LibraryAgentPresetResponse(
presets=[preset], pagination=pagination
)
assert len(response.presets) == 1
assert response.presets[0].id == "preset-123"
assert response.pagination.total_items == 1
assert response.pagination.total_pages == 1
assert response.pagination.current_page == 1
assert response.pagination.page_size == 10
def test_create_library_agent_preset_request():
request = backend.server.v2.library.model.CreateLibraryAgentPresetRequest(
name="New Preset",
description="New preset description",
agent_id="agent-123",
agent_version=1,
is_active=True,
inputs={
"input1": backend.data.block.BlockInput(
name="input1",
data={"type": "string", "value": "test value"},
)
},
)
assert request.name == "New Preset"
assert request.description == "New preset description"
assert request.agent_id == "agent-123"
assert request.agent_version == 1
assert request.is_active is True
assert request.inputs == {"input1": "test value"}

View File

@@ -121,3 +121,89 @@ async def add_agent_to_library(
raise fastapi.HTTPException(
status_code=500, detail="Failed to add agent to library"
)
@router.get("/presets")
async def get_presets(
user_id: typing.Annotated[
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
],
page: int = 1,
page_size: int = 10,
) -> backend.server.v2.library.model.LibraryAgentPresetResponse:
try:
presets = await backend.server.v2.library.db.get_presets(
user_id, page, page_size
)
return presets
except Exception:
logger.exception("Exception occurred whilst getting presets")
raise fastapi.HTTPException(status_code=500, detail="Failed to get presets")
@router.get("/presets/{preset_id}")
async def get_preset(
preset_id: str,
user_id: typing.Annotated[
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
],
) -> backend.server.v2.library.model.LibraryAgentPreset:
try:
preset = await backend.server.v2.library.db.get_preset(user_id, preset_id)
if not preset:
raise fastapi.HTTPException(
status_code=404,
detail=f"Preset {preset_id} not found",
)
return preset
except Exception:
logger.exception("Exception occurred whilst getting preset")
raise fastapi.HTTPException(status_code=500, detail="Failed to get preset")
@router.post("/presets")
async def create_preset(
preset: backend.server.v2.library.model.CreateLibraryAgentPresetRequest,
user_id: typing.Annotated[
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
],
) -> backend.server.v2.library.model.LibraryAgentPreset:
try:
return await backend.server.v2.library.db.create_or_update_preset(
user_id, preset
)
except Exception:
logger.exception("Exception occurred whilst creating preset")
raise fastapi.HTTPException(status_code=500, detail="Failed to create preset")
@router.put("/presets/{preset_id}")
async def update_preset(
preset_id: str,
preset: backend.server.v2.library.model.CreateLibraryAgentPresetRequest,
user_id: typing.Annotated[
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
],
) -> backend.server.v2.library.model.LibraryAgentPreset:
try:
return await backend.server.v2.library.db.create_or_update_preset(
user_id, preset, preset_id
)
except Exception:
logger.exception("Exception occurred whilst updating preset")
raise fastapi.HTTPException(status_code=500, detail="Failed to update preset")
@router.delete("/presets/{preset_id}")
async def delete_preset(
preset_id: str,
user_id: typing.Annotated[
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
],
):
try:
await backend.server.v2.library.db.delete_preset(user_id, preset_id)
return fastapi.Response(status_code=204)
except Exception:
logger.exception("Exception occurred whilst deleting preset")
raise fastapi.HTTPException(status_code=500, detail="Failed to delete preset")

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "AgentPreset" ADD COLUMN "isDeleted" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -106,6 +106,8 @@ model AgentPreset {
UserAgents UserAgent[]
AgentExecution AgentGraphExecution[]
isDeleted Boolean @default(false)
@@index([userId])
}