Merge branch 'dev' into swiftyos/secrt-1706-improve-store-search

This commit is contained in:
Swifty
2025-10-16 15:10:01 +02:00
committed by GitHub
11 changed files with 61 additions and 95 deletions

View File

@@ -102,6 +102,7 @@ class LlmModel(str, Enum, metaclass=LlmModelMeta):
CLAUDE_4_OPUS = "claude-opus-4-20250514"
CLAUDE_4_SONNET = "claude-sonnet-4-20250514"
CLAUDE_4_5_SONNET = "claude-sonnet-4-5-20250929"
CLAUDE_4_5_HAIKU = "claude-haiku-4-5-20251001"
CLAUDE_3_7_SONNET = "claude-3-7-sonnet-20250219"
CLAUDE_3_5_SONNET = "claude-3-5-sonnet-latest"
CLAUDE_3_5_HAIKU = "claude-3-5-haiku-latest"
@@ -217,6 +218,9 @@ MODEL_METADATA = {
LlmModel.CLAUDE_4_5_SONNET: ModelMetadata(
"anthropic", 200000, 64000
), # claude-sonnet-4-5-20250929
LlmModel.CLAUDE_4_5_HAIKU: ModelMetadata(
"anthropic", 200000, 64000
), # claude-haiku-4-5-20251001
LlmModel.CLAUDE_3_7_SONNET: ModelMetadata(
"anthropic", 200000, 64000
), # claude-3-7-sonnet-20250219

View File

@@ -69,6 +69,7 @@ MODEL_COST: dict[LlmModel, int] = {
LlmModel.CLAUDE_4_1_OPUS: 21,
LlmModel.CLAUDE_4_OPUS: 21,
LlmModel.CLAUDE_4_SONNET: 5,
LlmModel.CLAUDE_4_5_HAIKU: 4,
LlmModel.CLAUDE_4_5_SONNET: 9,
LlmModel.CLAUDE_3_7_SONNET: 5,
LlmModel.CLAUDE_3_5_SONNET: 4,

View File

@@ -38,8 +38,8 @@ from prisma.types import (
from pydantic import BaseModel, ConfigDict, JsonValue, ValidationError
from pydantic.fields import Field
from backend.server.v2.store.exceptions import DatabaseError
from backend.util import type as type_utils
from backend.util.exceptions import DatabaseError
from backend.util.json import SafeJson
from backend.util.models import Pagination
from backend.util.retry import func_retry

View File

@@ -7,7 +7,7 @@ from prisma.enums import AgentExecutionStatus
from backend.data.execution import get_graph_executions
from backend.data.graph import get_graph_metadata
from backend.data.model import UserExecutionSummaryStats
from backend.server.v2.store.exceptions import DatabaseError
from backend.util.exceptions import DatabaseError
from backend.util.logging import TruncatedLogger
logger = TruncatedLogger(logging.getLogger(__name__), prefix="[SummaryData]")

View File

@@ -15,7 +15,7 @@ from prisma.types import (
# from backend.notifications.models import NotificationEvent
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator
from backend.server.v2.store.exceptions import DatabaseError
from backend.util.exceptions import DatabaseError
from backend.util.json import SafeJson
from backend.util.logging import TruncatedLogger

View File

@@ -16,8 +16,8 @@ from prisma.types import JsonFilter, UserCreateInput, UserUpdateInput
from backend.data.db import prisma
from backend.data.model import User, UserIntegrations, UserMetadata
from backend.data.notifications import NotificationPreference, NotificationPreferenceDTO
from backend.server.v2.store.exceptions import DatabaseError
from backend.util.encryption import JSONCryptor
from backend.util.exceptions import DatabaseError
from backend.util.json import SafeJson
from backend.util.settings import Settings

View File

@@ -20,7 +20,7 @@ from backend.data.includes import AGENT_PRESET_INCLUDE, library_agent_include
from backend.data.model import CredentialsMetaInput
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.exceptions import DatabaseError, NotFoundError
from backend.util.json import SafeJson
from backend.util.models import Pagination
from backend.util.settings import Config
@@ -61,11 +61,11 @@ async def list_library_agents(
if page < 1 or page_size < 1:
logger.warning(f"Invalid pagination: page={page}, page_size={page_size}")
raise store_exceptions.DatabaseError("Invalid pagination input")
raise DatabaseError("Invalid pagination input")
if search_term and len(search_term.strip()) > 100:
logger.warning(f"Search term too long: {repr(search_term)}")
raise store_exceptions.DatabaseError("Search term is too long")
raise DatabaseError("Search term is too long")
where_clause: prisma.types.LibraryAgentWhereInput = {
"userId": user_id,
@@ -143,7 +143,7 @@ async def list_library_agents(
except prisma.errors.PrismaError as e:
logger.error(f"Database error fetching library agents: {e}")
raise store_exceptions.DatabaseError("Failed to fetch library agents") from e
raise DatabaseError("Failed to fetch library agents") from e
async def list_favorite_library_agents(
@@ -172,7 +172,7 @@ async def list_favorite_library_agents(
if page < 1 or page_size < 1:
logger.warning(f"Invalid pagination: page={page}, page_size={page_size}")
raise store_exceptions.DatabaseError("Invalid pagination input")
raise DatabaseError("Invalid pagination input")
where_clause: prisma.types.LibraryAgentWhereInput = {
"userId": user_id,
@@ -229,9 +229,7 @@ async def list_favorite_library_agents(
except prisma.errors.PrismaError as e:
logger.error(f"Database error fetching favorite library agents: {e}")
raise store_exceptions.DatabaseError(
"Failed to fetch favorite library agents"
) from e
raise DatabaseError("Failed to fetch favorite library agents") from e
async def get_library_agent(id: str, user_id: str) -> library_model.LibraryAgent:
@@ -273,7 +271,7 @@ async def get_library_agent(id: str, user_id: str) -> library_model.LibraryAgent
except prisma.errors.PrismaError as e:
logger.error(f"Database error fetching library agent: {e}")
raise store_exceptions.DatabaseError("Failed to fetch library agent") from e
raise DatabaseError("Failed to fetch library agent") from e
async def get_library_agent_by_store_version_id(
@@ -338,7 +336,7 @@ async def get_library_agent_by_graph_id(
return library_model.LibraryAgent.from_db(agent, sub_graphs=sub_graphs)
except prisma.errors.PrismaError as e:
logger.error(f"Database error fetching library agent by graph ID: {e}")
raise store_exceptions.DatabaseError("Failed to fetch library agent") from e
raise DatabaseError("Failed to fetch library agent") from e
async def add_generated_agent_image(
@@ -479,9 +477,7 @@ async def update_agent_version_in_library(
)
except prisma.errors.PrismaError as e:
logger.error(f"Database error updating agent version in library: {e}")
raise store_exceptions.DatabaseError(
"Failed to update agent version in library"
) from e
raise DatabaseError("Failed to update agent version in library") from e
async def update_library_agent(
@@ -544,7 +540,7 @@ async def update_library_agent(
)
except prisma.errors.PrismaError as e:
logger.error(f"Database error updating library agent: {str(e)}")
raise store_exceptions.DatabaseError("Failed to update library agent") from e
raise DatabaseError("Failed to update library agent") from e
async def delete_library_agent(
@@ -572,7 +568,7 @@ async def delete_library_agent_by_graph_id(graph_id: str, user_id: str) -> None:
)
except prisma.errors.PrismaError as e:
logger.error(f"Database error deleting library agent: {e}")
raise store_exceptions.DatabaseError("Failed to delete library agent") from e
raise DatabaseError("Failed to delete library agent") from e
async def add_store_agent_to_library(
@@ -663,7 +659,7 @@ async def add_store_agent_to_library(
raise
except prisma.errors.PrismaError as e:
logger.error(f"Database error adding agent to library: {e}")
raise store_exceptions.DatabaseError("Failed to add agent to library") from e
raise DatabaseError("Failed to add agent to library") from e
##############################################
@@ -697,7 +693,7 @@ async def list_presets(
logger.warning(
"Invalid pagination input: page=%d, page_size=%d", page, page_size
)
raise store_exceptions.DatabaseError("Invalid pagination parameters")
raise DatabaseError("Invalid pagination parameters")
query_filter: prisma.types.AgentPresetWhereInput = {
"userId": user_id,
@@ -733,7 +729,7 @@ async def list_presets(
except prisma.errors.PrismaError as e:
logger.error(f"Database error getting presets: {e}")
raise store_exceptions.DatabaseError("Failed to fetch presets") from e
raise DatabaseError("Failed to fetch presets") from e
async def get_preset(
@@ -763,7 +759,7 @@ async def get_preset(
return library_model.LibraryAgentPreset.from_db(preset)
except prisma.errors.PrismaError as e:
logger.error(f"Database error getting preset: {e}")
raise store_exceptions.DatabaseError("Failed to fetch preset") from e
raise DatabaseError("Failed to fetch preset") from e
async def create_preset(
@@ -813,7 +809,7 @@ async def create_preset(
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
raise DatabaseError("Failed to create preset") from e
async def create_preset_from_graph_execution(
@@ -951,7 +947,7 @@ async def update_preset(
return library_model.LibraryAgentPreset.from_db(updated)
except prisma.errors.PrismaError as e:
logger.error(f"Database error updating preset: {e}")
raise store_exceptions.DatabaseError("Failed to update preset") from e
raise DatabaseError("Failed to update preset") from e
async def set_preset_webhook(
@@ -997,7 +993,7 @@ async def delete_preset(user_id: str, preset_id: str) -> None:
)
except prisma.errors.PrismaError as e:
logger.error(f"Database error deleting preset: {e}")
raise store_exceptions.DatabaseError("Failed to delete preset") from e
raise DatabaseError("Failed to delete preset") from e
async def fork_library_agent(
@@ -1025,7 +1021,7 @@ async def fork_library_agent(
# TODO: once we have open/closed sourced agents this needs to be enabled ~kcze
# + update library/agents/[id]/page.tsx agent actions
# if not original_agent.can_access_graph:
# raise store_exceptions.DatabaseError(
# raise DatabaseError(
# f"User {user_id} cannot access library agent graph {library_agent_id}"
# )
@@ -1039,4 +1035,4 @@ async def fork_library_agent(
return (await create_library_agent(new_graph, user_id))[0]
except prisma.errors.PrismaError as e:
logger.error(f"Database error cloning library agent: {e}")
raise store_exceptions.DatabaseError("Failed to fork library agent") from e
raise DatabaseError("Failed to fork library agent") from e

View File

@@ -8,7 +8,7 @@ from fastapi.responses import Response
import backend.server.v2.library.db as library_db
import backend.server.v2.library.model as library_model
import backend.server.v2.store.exceptions as store_exceptions
from backend.util.exceptions import NotFoundError
from backend.util.exceptions import DatabaseError, NotFoundError
logger = logging.getLogger(__name__)
@@ -221,7 +221,7 @@ async def add_marketplace_agent_to_library(
"to add to library"
)
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
except store_exceptions.DatabaseError as e:
except DatabaseError as e:
logger.error(f"Database error while adding agent to library: {e}", e)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
@@ -275,7 +275,7 @@ async def update_library_agent(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(e),
) from e
except store_exceptions.DatabaseError as e:
except DatabaseError as e:
logger.error(f"Database error while updating library agent: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,

View File

@@ -26,6 +26,7 @@ from backend.data.notifications import (
NotificationEventModel,
)
from backend.notifications.notifications import queue_notification_async
from backend.util.exceptions import DatabaseError
from backend.util.settings import Settings
logger = logging.getLogger(__name__)
@@ -249,9 +250,7 @@ async def get_store_agents(
)
except Exception as e:
logger.error(f"Error getting store agents: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch store agents"
) from e
raise DatabaseError("Failed to fetch store agents") from e
# TODO: commenting this out as we concerned about potential db load issues
# finally:
# if search_term:
@@ -362,9 +361,7 @@ async def get_store_agent_details(
raise
except Exception as e:
logger.error(f"Error getting store agent details: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch agent details"
) from e
raise DatabaseError("Failed to fetch agent details") from e
async def get_available_graph(store_listing_version_id: str) -> GraphMeta:
@@ -391,9 +388,7 @@ async def get_available_graph(store_listing_version_id: str) -> GraphMeta:
except Exception as e:
logger.error(f"Error getting agent: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch agent"
) from e
raise DatabaseError("Failed to fetch agent") from e
async def get_store_agent_by_version_id(
@@ -433,9 +428,7 @@ async def get_store_agent_by_version_id(
raise
except Exception as e:
logger.error(f"Error getting store agent details: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch agent details"
) from e
raise DatabaseError("Failed to fetch agent details") from e
async def get_store_creators(
@@ -461,9 +454,7 @@ async def get_store_creators(
# Sanitize and validate search query by escaping special characters
sanitized_query = search_query.strip()
if not sanitized_query or len(sanitized_query) > 100: # Reasonable length limit
raise backend.server.v2.store.exceptions.DatabaseError(
"Invalid search query"
)
raise DatabaseError("Invalid search query")
# Escape special SQL characters
sanitized_query = (
@@ -489,11 +480,9 @@ async def get_store_creators(
try:
# Validate pagination parameters
if not isinstance(page, int) or page < 1:
raise backend.server.v2.store.exceptions.DatabaseError(
"Invalid page number"
)
raise DatabaseError("Invalid page number")
if not isinstance(page_size, int) or page_size < 1 or page_size > 100:
raise backend.server.v2.store.exceptions.DatabaseError("Invalid page size")
raise DatabaseError("Invalid page size")
# Get total count for pagination using sanitized where clause
total = await prisma.models.Creator.prisma().count(
@@ -548,9 +537,7 @@ async def get_store_creators(
)
except Exception as e:
logger.error(f"Error getting store creators: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch store creators"
) from e
raise DatabaseError("Failed to fetch store creators") from e
async def get_store_creator_details(
@@ -585,9 +572,7 @@ async def get_store_creator_details(
raise
except Exception as e:
logger.error(f"Error getting store creator details: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch creator details"
) from e
raise DatabaseError("Failed to fetch creator details") from e
async def get_store_submissions(
@@ -862,7 +847,7 @@ async def create_store_submission(
) from exc
else:
# Reraise as a generic database error for other unique violations
raise backend.server.v2.store.exceptions.DatabaseError(
raise DatabaseError(
f"Unique constraint violated (not slug): {error_str}"
) from exc
except (
@@ -872,9 +857,7 @@ async def create_store_submission(
raise
except prisma.errors.PrismaError as e:
logger.error(f"Database error creating store submission: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to create store submission"
) from e
raise DatabaseError("Failed to create store submission") from e
async def edit_store_submission(
@@ -995,9 +978,7 @@ async def edit_store_submission(
)
if not updated_version:
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to update store listing version"
)
raise DatabaseError("Failed to update store listing version")
return backend.server.v2.store.model.StoreSubmission(
agent_id=current_version.agentGraphId,
agent_version=current_version.agentGraphVersion,
@@ -1033,9 +1014,7 @@ async def edit_store_submission(
raise
except prisma.errors.PrismaError as e:
logger.error(f"Database error editing store submission: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to edit store submission"
) from e
raise DatabaseError("Failed to edit store submission") from e
async def create_store_version(
@@ -1150,9 +1129,7 @@ async def create_store_version(
)
except prisma.errors.PrismaError as e:
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to create new store version"
) from e
raise DatabaseError("Failed to create new store version") from e
async def create_store_review(
@@ -1192,9 +1169,7 @@ async def create_store_review(
except prisma.errors.PrismaError as e:
logger.error(f"Database error creating store review: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to create store review"
) from e
raise DatabaseError("Failed to create store review") from e
async def get_user_profile(
@@ -1218,9 +1193,7 @@ async def get_user_profile(
)
except Exception as e:
logger.error(f"Error getting user profile: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to get user profile"
) from e
raise DatabaseError("Failed to get user profile") from e
async def update_profile(
@@ -1257,7 +1230,7 @@ async def update_profile(
logger.error(
f"Unauthorized update attempt for profile {existing_profile.id} by user {user_id}"
)
raise backend.server.v2.store.exceptions.DatabaseError(
raise DatabaseError(
f"Unauthorized update attempt for profile {existing_profile.id} by user {user_id}"
)
@@ -1282,9 +1255,7 @@ async def update_profile(
)
if updated_profile is None:
logger.error(f"Failed to update profile for user {user_id}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to update profile"
)
raise DatabaseError("Failed to update profile")
return backend.server.v2.store.model.CreatorDetails(
name=updated_profile.name,
@@ -1299,9 +1270,7 @@ async def update_profile(
except prisma.errors.PrismaError as e:
logger.error(f"Database error updating profile: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to update profile"
) from e
raise DatabaseError("Failed to update profile") from e
async def get_my_agents(
@@ -1369,9 +1338,7 @@ async def get_my_agents(
)
except Exception as e:
logger.error(f"Error getting my agents: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to fetch my agents"
) from e
raise DatabaseError("Failed to fetch my agents") from e
async def get_agent(store_listing_version_id: str) -> GraphModel:
@@ -1633,7 +1600,7 @@ async def review_store_submission(
)
if not submission:
raise backend.server.v2.store.exceptions.DatabaseError(
raise DatabaseError(
f"Failed to update store listing version {store_listing_version_id}"
)
@@ -1748,9 +1715,7 @@ async def review_store_submission(
except Exception as e:
logger.error(f"Could not create store submission review: {e}")
raise backend.server.v2.store.exceptions.DatabaseError(
"Failed to create store submission review"
) from e
raise DatabaseError("Failed to create store submission review") from e
async def get_admin_listings_with_versions(

View File

@@ -75,12 +75,6 @@ class ListingExistsError(StoreError):
pass
class DatabaseError(StoreError):
"""Raised when there is an error interacting with the database"""
pass
class ProfileNotFoundError(NotFoundError):
"""Raised when a profile is not found"""

View File

@@ -86,3 +86,9 @@ class GraphValidationError(ValueError):
for node_id, errors in self.node_errors.items()
]
)
class DatabaseError(Exception):
"""Raised when there is an error interacting with the database"""
pass