Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backend): Add Support for Managing Agent Presets with Pagination and Soft Delete #9211

Merged
merged 25 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4465994
Allow execution of store listings
Swiftyos Jan 3, 2025
6b9580b
Merge branch 'dev' into swiftyos/open-2276-add-ability-to-execute-sto…
Swiftyos Jan 3, 2025
6df94aa
updated comment to make the meaning of userId clearer
Swiftyos Jan 3, 2025
a7e0af0
Merge branch 'swiftyos/open-2276-add-ability-to-execute-store-agents-…
Swiftyos Jan 3, 2025
c6daeef
Merge branch 'dev' into swiftyos/open-2276-add-ability-to-execute-sto…
Swiftyos Jan 7, 2025
69747cc
added preset functionality
Swiftyos Jan 7, 2025
4f861e3
fixed merged error
Swiftyos Jan 7, 2025
797f9ed
fmt
Swiftyos Jan 7, 2025
9750b79
Merge branch 'dev' into swiftyos/open-2278-implement-agent-preset-fun…
Swiftyos Jan 7, 2025
c027080
Update autogpt_platform/backend/backend/server/model.py
Swiftyos Jan 7, 2025
46d573c
added error message to logs
Swiftyos Jan 7, 2025
bb8e562
Update autogpt_platform/backend/backend/data/graph.py
Swiftyos Jan 7, 2025
0c4888f
add from_db test
Swiftyos Jan 7, 2025
f051266
Merge branch 'dev' into swiftyos/open-2276-add-ability-to-execute-sto…
Swiftyos Jan 7, 2025
37e8b51
add isActive filter back in
Swiftyos Jan 8, 2025
5259875
add preset execution
Swiftyos Jan 8, 2025
783ca12
Merge branch 'swiftyos/open-2276-add-ability-to-execute-store-agents-…
Swiftyos Jan 8, 2025
37c5999
add library management functions
Swiftyos Jan 8, 2025
fa5f24e
add db functions
Swiftyos Jan 8, 2025
2a86f22
updated router
Swiftyos Jan 8, 2025
bc8043b
fix tests
Swiftyos Jan 8, 2025
1f82ceb
Merge branch 'dev' into swiftyos/open-2278-implement-agent-preset-fun…
Swiftyos Jan 10, 2025
6007def
Merge branch 'swiftyos/open-2277-implement-library-add-update-remove-…
Swiftyos Jan 10, 2025
4d20e41
testing preset functionality
Swiftyos Jan 10, 2025
d0c4a1f
Merge remote-tracking branch 'origin/dev' into swiftyos/open-2278-imp…
Swiftyos Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions autogpt_platform/backend/backend/server/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
)
121 changes: 121 additions & 0 deletions autogpt_platform/backend/backend/server/v2/library/db.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import logging
from typing import List

Expand All @@ -7,6 +8,7 @@

import backend.data.graph
import backend.data.includes
import backend.server.model
import backend.server.v2.library.model
import backend.server.v2.store.exceptions

Expand Down Expand Up @@ -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
52 changes: 52 additions & 0 deletions autogpt_platform/backend/backend/server/v2/library/model.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from datetime import datetime

import backend.data.block
import backend.server.model
import backend.server.v2.library.model


Expand Down Expand Up @@ -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"}
Loading
Loading