feat(platform): updated schema to allow featuring of specific creators (#9048)
updated schema to allow featuring of specific creators
This commit is contained in:
parent
e8dd0a297e
commit
aa883d8465
|
@ -153,6 +153,7 @@ async def test_add_agent_to_library(mocker):
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_user_agent = mocker.patch("prisma.models.UserAgent.prisma")
|
mock_user_agent = mocker.patch("prisma.models.UserAgent.prisma")
|
||||||
|
mock_user_agent.return_value.find_first = mocker.AsyncMock(return_value=None)
|
||||||
mock_user_agent.return_value.create = mocker.AsyncMock()
|
mock_user_agent.return_value.create = mocker.AsyncMock()
|
||||||
|
|
||||||
# Call function
|
# Call function
|
||||||
|
@ -162,6 +163,13 @@ async def test_add_agent_to_library(mocker):
|
||||||
mock_store_listing_version.return_value.find_unique.assert_called_once_with(
|
mock_store_listing_version.return_value.find_unique.assert_called_once_with(
|
||||||
where={"id": "version123"}, include={"Agent": True}
|
where={"id": "version123"}, include={"Agent": True}
|
||||||
)
|
)
|
||||||
|
mock_user_agent.return_value.find_first.assert_called_once_with(
|
||||||
|
where={
|
||||||
|
"userId": "test-user",
|
||||||
|
"agentId": "agent1",
|
||||||
|
"agentVersion": 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
mock_user_agent.return_value.create.assert_called_once_with(
|
mock_user_agent.return_value.create.assert_called_once_with(
|
||||||
data=prisma.types.UserAgentCreateInput(
|
data=prisma.types.UserAgentCreateInput(
|
||||||
userId="test-user", agentId="agent1", agentVersion=1, isCreatedByUser=False
|
userId="test-user", agentId="agent1", agentVersion=1, isCreatedByUser=False
|
||||||
|
|
|
@ -172,6 +172,9 @@ async def get_store_creators(
|
||||||
# Build where clause with sanitized inputs
|
# Build where clause with sanitized inputs
|
||||||
where = {}
|
where = {}
|
||||||
|
|
||||||
|
if featured:
|
||||||
|
where["isFeatured"] = featured
|
||||||
|
|
||||||
# Add search filter if provided, using parameterized queries
|
# Add search filter if provided, using parameterized queries
|
||||||
if search_query:
|
if search_query:
|
||||||
# Sanitize and validate search query by escaping special characters
|
# Sanitize and validate search query by escaping special characters
|
||||||
|
@ -247,6 +250,7 @@ async def get_store_creators(
|
||||||
num_agents=creator.num_agents,
|
num_agents=creator.num_agents,
|
||||||
agent_rating=creator.agent_rating,
|
agent_rating=creator.agent_rating,
|
||||||
agent_runs=creator.agent_runs,
|
agent_runs=creator.agent_runs,
|
||||||
|
is_featured=creator.is_featured,
|
||||||
)
|
)
|
||||||
for creator in creators
|
for creator in creators
|
||||||
]
|
]
|
||||||
|
|
|
@ -113,6 +113,7 @@ async def test_get_store_creator_details(mocker):
|
||||||
agent_rating=4.5,
|
agent_rating=4.5,
|
||||||
agent_runs=10,
|
agent_runs=10,
|
||||||
top_categories=["test"],
|
top_categories=["test"],
|
||||||
|
is_featured=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mock prisma call
|
# Mock prisma call
|
||||||
|
@ -197,6 +198,7 @@ async def test_update_profile(mocker):
|
||||||
description="Test description",
|
description="Test description",
|
||||||
links=["link1"],
|
links=["link1"],
|
||||||
avatarUrl="avatar.jpg",
|
avatarUrl="avatar.jpg",
|
||||||
|
isFeatured=False,
|
||||||
createdAt=datetime.now(),
|
createdAt=datetime.now(),
|
||||||
updatedAt=datetime.now(),
|
updatedAt=datetime.now(),
|
||||||
)
|
)
|
||||||
|
@ -215,6 +217,7 @@ async def test_update_profile(mocker):
|
||||||
description="Test description",
|
description="Test description",
|
||||||
links=["link1"],
|
links=["link1"],
|
||||||
avatar_url="avatar.jpg",
|
avatar_url="avatar.jpg",
|
||||||
|
is_featured=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Call function
|
# Call function
|
||||||
|
@ -239,6 +242,7 @@ async def test_get_user_profile(mocker):
|
||||||
description="Test description",
|
description="Test description",
|
||||||
links=["link1", "link2"],
|
links=["link1", "link2"],
|
||||||
avatarUrl="avatar.jpg",
|
avatarUrl="avatar.jpg",
|
||||||
|
isFeatured=False,
|
||||||
createdAt=datetime.now(),
|
createdAt=datetime.now(),
|
||||||
updatedAt=datetime.now(),
|
updatedAt=datetime.now(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -74,6 +74,7 @@ class Creator(pydantic.BaseModel):
|
||||||
num_agents: int
|
num_agents: int
|
||||||
agent_rating: float
|
agent_rating: float
|
||||||
agent_runs: int
|
agent_runs: int
|
||||||
|
is_featured: bool
|
||||||
|
|
||||||
|
|
||||||
class CreatorsResponse(pydantic.BaseModel):
|
class CreatorsResponse(pydantic.BaseModel):
|
||||||
|
@ -98,6 +99,7 @@ class Profile(pydantic.BaseModel):
|
||||||
description: str
|
description: str
|
||||||
links: list[str]
|
links: list[str]
|
||||||
avatar_url: str
|
avatar_url: str
|
||||||
|
is_featured: bool
|
||||||
|
|
||||||
|
|
||||||
class StoreSubmission(pydantic.BaseModel):
|
class StoreSubmission(pydantic.BaseModel):
|
||||||
|
|
|
@ -88,6 +88,7 @@ def test_creator():
|
||||||
description="Test description",
|
description="Test description",
|
||||||
avatar_url="avatar.jpg",
|
avatar_url="avatar.jpg",
|
||||||
num_agents=5,
|
num_agents=5,
|
||||||
|
is_featured=False,
|
||||||
)
|
)
|
||||||
assert creator.name == "Test Creator"
|
assert creator.name == "Test Creator"
|
||||||
assert creator.num_agents == 5
|
assert creator.num_agents == 5
|
||||||
|
@ -104,6 +105,7 @@ def test_creators_response():
|
||||||
description="Test description",
|
description="Test description",
|
||||||
avatar_url="avatar.jpg",
|
avatar_url="avatar.jpg",
|
||||||
num_agents=5,
|
num_agents=5,
|
||||||
|
is_featured=False,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
pagination=backend.server.v2.store.model.Pagination(
|
pagination=backend.server.v2.store.model.Pagination(
|
||||||
|
|
|
@ -402,6 +402,7 @@ def test_get_creators_pagination(mocker: pytest_mock.MockFixture):
|
||||||
num_agents=1,
|
num_agents=1,
|
||||||
agent_rating=4.5,
|
agent_rating=4.5,
|
||||||
agent_runs=100,
|
agent_runs=100,
|
||||||
|
is_featured=False,
|
||||||
)
|
)
|
||||||
for i in range(5)
|
for i in range(5)
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Profile" ADD COLUMN "isFeatured" BOOLEAN NOT NULL DEFAULT false;
|
|
@ -71,6 +71,7 @@ SELECT
|
||||||
p.description,
|
p.description,
|
||||||
ARRAY_AGG(DISTINCT c) FILTER (WHERE c IS NOT NULL) as top_categories,
|
ARRAY_AGG(DISTINCT c) FILTER (WHERE c IS NOT NULL) as top_categories,
|
||||||
p.links,
|
p.links,
|
||||||
|
p."isFeatured" as is_featured,
|
||||||
COALESCE(ast.num_agents, 0) as num_agents,
|
COALESCE(ast.num_agents, 0) as num_agents,
|
||||||
COALESCE(ast.agent_rating, 0.0) as agent_rating,
|
COALESCE(ast.agent_rating, 0.0) as agent_rating,
|
||||||
COALESCE(ast.agent_runs, 0) as agent_runs
|
COALESCE(ast.agent_runs, 0) as agent_runs
|
||||||
|
@ -84,7 +85,7 @@ LEFT JOIN LATERAL (
|
||||||
AND sl."isDeleted" = FALSE
|
AND sl."isDeleted" = FALSE
|
||||||
AND sl."isApproved" = TRUE
|
AND sl."isApproved" = TRUE
|
||||||
) cats ON true
|
) cats ON true
|
||||||
GROUP BY p.username, p.name, p."avatarUrl", p.description, p.links,
|
GROUP BY p.username, p.name, p."avatarUrl", p.description, p.links, p."isFeatured",
|
||||||
ast.num_agents, ast.agent_rating, ast.agent_runs;
|
ast.num_agents, ast.agent_rating, ast.agent_runs;
|
||||||
|
|
||||||
CREATE VIEW "StoreSubmission" AS
|
CREATE VIEW "StoreSubmission" AS
|
||||||
|
|
|
@ -423,6 +423,8 @@ model Profile {
|
||||||
|
|
||||||
avatarUrl String?
|
avatarUrl String?
|
||||||
|
|
||||||
|
isFeatured Boolean @default(false)
|
||||||
|
|
||||||
@@index([username])
|
@@index([username])
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
}
|
}
|
||||||
|
@ -439,6 +441,7 @@ view Creator {
|
||||||
num_agents Int
|
num_agents Int
|
||||||
agent_rating Float
|
agent_rating Float
|
||||||
agent_runs Int
|
agent_runs Int
|
||||||
|
is_featured Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
view StoreAgent {
|
view StoreAgent {
|
||||||
|
|
|
@ -1,628 +0,0 @@
|
||||||
// We need to migrate our database schema to support the domain as we understand it now
|
|
||||||
// To do so requires adding a bunch of new tables, but also modiftying old ones and how
|
|
||||||
// they relate to each other. This is a large change, so instead of doing in in one go,
|
|
||||||
// We have created the target schema, and will migrate to it incrementally.
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgresql"
|
|
||||||
url = env("DATABASE_URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-py"
|
|
||||||
recursive_type_depth = 5
|
|
||||||
interface = "asyncio"
|
|
||||||
}
|
|
||||||
|
|
||||||
// User model to mirror Auth provider users
|
|
||||||
model User {
|
|
||||||
id String @id @db.Uuid // This should match the Supabase user ID
|
|
||||||
email String @unique
|
|
||||||
name String?
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
metadata String @default("")
|
|
||||||
|
|
||||||
// Relations
|
|
||||||
Agents Agent[]
|
|
||||||
AgentExecutions AgentExecution[]
|
|
||||||
AgentExecutionSchedules AgentExecutionSchedule[]
|
|
||||||
AnalyticsDetails AnalyticsDetails[]
|
|
||||||
AnalyticsMetrics AnalyticsMetrics[]
|
|
||||||
UserBlockCredit UserBlockCredit[]
|
|
||||||
AgentPresets AgentPreset[]
|
|
||||||
UserAgents UserAgent[]
|
|
||||||
|
|
||||||
// User Group relations
|
|
||||||
UserGroupMemberships UserGroupMembership[]
|
|
||||||
Profile Profile[]
|
|
||||||
StoreListing StoreListing[]
|
|
||||||
StoreListingSubmission StoreListingSubmission[]
|
|
||||||
StoreListingReview StoreListingReview[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserGroup {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
name String
|
|
||||||
description String
|
|
||||||
groupIconUrl String?
|
|
||||||
|
|
||||||
UserGroupMemberships UserGroupMembership[]
|
|
||||||
|
|
||||||
Agents Agent[]
|
|
||||||
Profile Profile[]
|
|
||||||
StoreListing StoreListing[]
|
|
||||||
|
|
||||||
@@index([name])
|
|
||||||
}
|
|
||||||
|
|
||||||
enum UserGroupRole {
|
|
||||||
MEMBER
|
|
||||||
OWNER
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserGroupMembership {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
userGroupId String @db.Uuid
|
|
||||||
UserGroup UserGroup @relation(fields: [userGroupId], references: [id], onDelete: Cascade)
|
|
||||||
Role UserGroupRole @default(MEMBER)
|
|
||||||
|
|
||||||
@@unique([userId, userGroupId])
|
|
||||||
@@index([userId])
|
|
||||||
@@index([userGroupId])
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the Agent Graph/Flow (Multi Agent System).
|
|
||||||
model Agent {
|
|
||||||
id String @default(uuid()) @db.Uuid
|
|
||||||
version Int @default(1)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
name String?
|
|
||||||
description String?
|
|
||||||
|
|
||||||
// Link to User model
|
|
||||||
createdByUserId String? @db.Uuid
|
|
||||||
// Do not cascade delete the agent when the user is deleted
|
|
||||||
// This allows us to delete user data with deleting the agent which maybe in use by other users
|
|
||||||
CreatedByUser User? @relation(fields: [createdByUserId], references: [id], onDelete: SetNull)
|
|
||||||
|
|
||||||
groupId String? @db.Uuid
|
|
||||||
// Do not cascade delete the agent when the group is deleted
|
|
||||||
// This allows us to delete user group data with deleting the agent which maybe in use by other users
|
|
||||||
Group UserGroup? @relation(fields: [groupId], references: [id], onDelete: SetNull)
|
|
||||||
|
|
||||||
AgentNodes AgentNode[]
|
|
||||||
AgentExecution AgentExecution[]
|
|
||||||
|
|
||||||
// All sub-graphs are defined within this 1-level depth list (even if it's a nested graph).
|
|
||||||
SubAgents Agent[] @relation("SubAgents")
|
|
||||||
agentParentId String? @db.Uuid
|
|
||||||
agentParentVersion Int?
|
|
||||||
AgentParent Agent? @relation("SubAgents", fields: [agentParentId, agentParentVersion], references: [id, version])
|
|
||||||
|
|
||||||
AgentPresets AgentPreset[]
|
|
||||||
WebhookTrigger WebhookTrigger[]
|
|
||||||
AgentExecutionSchedule AgentExecutionSchedule[]
|
|
||||||
UserAgents UserAgent[]
|
|
||||||
UserBlockCredit UserBlockCredit[]
|
|
||||||
StoreListing StoreListing[]
|
|
||||||
StoreListingVersion StoreListingVersion[]
|
|
||||||
|
|
||||||
@@id(name: "agentVersionId", [id, version])
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//////////////// USER SPECIFIC DATA ////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// An AgentPrest is an Agent + User Configuration of that agent.
|
|
||||||
// For example, if someone has created a weather agent and they want to set it up to
|
|
||||||
// Inform them of extreme weather warnings in Texas, the agent with the configuration to set it to
|
|
||||||
// monitor texas, along with the cron setup or webhook tiggers, is an AgentPreset
|
|
||||||
model AgentPreset {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
name String
|
|
||||||
description String
|
|
||||||
|
|
||||||
// For agents that can be triggered by webhooks or cronjob
|
|
||||||
// This bool allows us to disable a configured agent without deleting it
|
|
||||||
isActive Boolean @default(true)
|
|
||||||
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
agentId String @db.Uuid
|
|
||||||
agentVersion Int
|
|
||||||
Agent Agent @relation(fields: [agentId, agentVersion], references: [id, version], onDelete: Cascade)
|
|
||||||
|
|
||||||
InputPresets AgentNodeExecutionInputOutput[] @relation("AgentPresetsInputData")
|
|
||||||
UserAgents UserAgent[]
|
|
||||||
WebhookTrigger WebhookTrigger[]
|
|
||||||
AgentExecutionSchedule AgentExecutionSchedule[]
|
|
||||||
AgentExecution AgentExecution[]
|
|
||||||
|
|
||||||
@@index([userId])
|
|
||||||
}
|
|
||||||
|
|
||||||
// For the library page
|
|
||||||
// It is a user controlled list of agents, that they will see in there library
|
|
||||||
model UserAgent {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
agentId String @db.Uuid
|
|
||||||
agentVersion Int
|
|
||||||
Agent Agent @relation(fields: [agentId, agentVersion], references: [id, version])
|
|
||||||
|
|
||||||
agentPresetId String? @db.Uuid
|
|
||||||
AgentPreset AgentPreset? @relation(fields: [agentPresetId], references: [id])
|
|
||||||
|
|
||||||
isFavorite Boolean @default(false)
|
|
||||||
isCreatedByUser Boolean @default(false)
|
|
||||||
isArchived Boolean @default(false)
|
|
||||||
isDeleted Boolean @default(false)
|
|
||||||
|
|
||||||
@@index([userId])
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//////// AGENT DEFINITION AND EXECUTION TABLES ////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
// This model describes a single node in the Agent Graph/Flow (Multi Agent System).
|
|
||||||
model AgentNode {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
|
|
||||||
agentBlockId String @db.Uuid
|
|
||||||
AgentBlock AgentBlock @relation(fields: [agentBlockId], references: [id], onUpdate: Cascade)
|
|
||||||
|
|
||||||
agentId String @db.Uuid
|
|
||||||
agentVersion Int @default(1)
|
|
||||||
Agent Agent @relation(fields: [agentId, agentVersion], references: [id, version], onDelete: Cascade)
|
|
||||||
|
|
||||||
// List of consumed input, that the parent node should provide.
|
|
||||||
Input AgentNodeLink[] @relation("AgentNodeSink")
|
|
||||||
|
|
||||||
// List of produced output, that the child node should be executed.
|
|
||||||
Output AgentNodeLink[] @relation("AgentNodeSource")
|
|
||||||
|
|
||||||
// JSON serialized dict[str, str] containing predefined input values.
|
|
||||||
constantInput Json @default("{}")
|
|
||||||
|
|
||||||
// JSON serialized dict[str, str] containing the node metadata.
|
|
||||||
metadata Json @default("{}")
|
|
||||||
|
|
||||||
ExecutionHistory AgentNodeExecution[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the link between two AgentNodes.
|
|
||||||
model AgentNodeLink {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
|
|
||||||
// Output of a node is connected to the source of the link.
|
|
||||||
agentNodeSourceId String @db.Uuid
|
|
||||||
AgentNodeSource AgentNode @relation("AgentNodeSource", fields: [agentNodeSourceId], references: [id], onDelete: Cascade)
|
|
||||||
sourceName String
|
|
||||||
|
|
||||||
// Input of a node is connected to the sink of the link.
|
|
||||||
agentNodeSinkId String @db.Uuid
|
|
||||||
AgentNodeSink AgentNode @relation("AgentNodeSink", fields: [agentNodeSinkId], references: [id], onDelete: Cascade)
|
|
||||||
sinkName String
|
|
||||||
|
|
||||||
// Default: the data coming from the source can only be consumed by the sink once, Static: input data will be reused.
|
|
||||||
isStatic Boolean @default(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes a component that will be executed by the AgentNode.
|
|
||||||
model AgentBlock {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
name String @unique
|
|
||||||
|
|
||||||
// We allow a block to have multiple types of input & output.
|
|
||||||
// Serialized object-typed `jsonschema` with top-level properties as input/output name.
|
|
||||||
inputSchema Json @default("{}")
|
|
||||||
outputSchema Json @default("{}")
|
|
||||||
|
|
||||||
// Prisma requires explicit back-references.
|
|
||||||
ReferencedByAgentNode AgentNode[]
|
|
||||||
UserBlockCredit UserBlockCredit[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the status of an AgentExecution or AgentNodeExecution.
|
|
||||||
enum AgentExecutionStatus {
|
|
||||||
INCOMPLETE
|
|
||||||
QUEUED
|
|
||||||
RUNNING
|
|
||||||
COMPLETED
|
|
||||||
FAILED
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum for execution trigger types
|
|
||||||
enum ExecutionTriggerType {
|
|
||||||
MANUAL
|
|
||||||
SCHEDULE
|
|
||||||
WEBHOOK
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the execution of an AgentGraph.
|
|
||||||
model AgentExecution {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
startedAt DateTime?
|
|
||||||
executionTriggerType ExecutionTriggerType @default(MANUAL)
|
|
||||||
|
|
||||||
executionStatus AgentExecutionStatus @default(COMPLETED)
|
|
||||||
|
|
||||||
agentId String @db.Uuid
|
|
||||||
agentVersion Int @default(1)
|
|
||||||
Agent Agent @relation(fields: [agentId, agentVersion], references: [id, version], onDelete: Cascade)
|
|
||||||
|
|
||||||
// we need to be able to associate an agent execution with an agent preset
|
|
||||||
agentPresetId String? @db.Uuid
|
|
||||||
AgentPreset AgentPreset? @relation(fields: [agentPresetId], references: [id])
|
|
||||||
|
|
||||||
AgentNodeExecutions AgentNodeExecution[]
|
|
||||||
|
|
||||||
// This is so we can track which user executed the agent.
|
|
||||||
executedByUserId String @db.Uuid
|
|
||||||
ExecutedByUser User @relation(fields: [executedByUserId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
stats Json @default("{}") // JSON serialized object
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the execution of an AgentNode.
|
|
||||||
model AgentNodeExecution {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
|
|
||||||
agentExecutionId String @db.Uuid
|
|
||||||
AgentExecution AgentExecution @relation(fields: [agentExecutionId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
agentNodeId String @db.Uuid
|
|
||||||
AgentNode AgentNode @relation(fields: [agentNodeId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
Input AgentNodeExecutionInputOutput[] @relation("AgentNodeExecutionInput")
|
|
||||||
Output AgentNodeExecutionInputOutput[] @relation("AgentNodeExecutionOutput")
|
|
||||||
|
|
||||||
executionStatus AgentExecutionStatus @default(COMPLETED)
|
|
||||||
// Final JSON serialized input data for the node execution.
|
|
||||||
executionData String?
|
|
||||||
addedTime DateTime @default(now())
|
|
||||||
queuedTime DateTime?
|
|
||||||
startedTime DateTime?
|
|
||||||
endedTime DateTime?
|
|
||||||
|
|
||||||
stats Json @default("{}") // JSON serialized object
|
|
||||||
UserBlockCredit UserBlockCredit[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the output of an AgentNodeExecution.
|
|
||||||
model AgentNodeExecutionInputOutput {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
|
|
||||||
name String
|
|
||||||
data String
|
|
||||||
time DateTime @default(now())
|
|
||||||
|
|
||||||
// Prisma requires explicit back-references.
|
|
||||||
referencedByInputExecId String? @db.Uuid
|
|
||||||
ReferencedByInputExec AgentNodeExecution? @relation("AgentNodeExecutionInput", fields: [referencedByInputExecId], references: [id], onDelete: Cascade)
|
|
||||||
referencedByOutputExecId String? @db.Uuid
|
|
||||||
ReferencedByOutputExec AgentNodeExecution? @relation("AgentNodeExecutionOutput", fields: [referencedByOutputExecId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
agentPresetId String? @db.Uuid
|
|
||||||
AgentPreset AgentPreset? @relation("AgentPresetsInputData", fields: [agentPresetId], references: [id])
|
|
||||||
|
|
||||||
// Input and Output pin names are unique for each AgentNodeExecution.
|
|
||||||
@@unique([referencedByInputExecId, referencedByOutputExecId, name])
|
|
||||||
}
|
|
||||||
|
|
||||||
// This model describes the recurring execution schedule of an Agent.
|
|
||||||
model AgentExecutionSchedule {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
agentPresetId String @db.Uuid
|
|
||||||
AgentPreset AgentPreset @relation(fields: [agentPresetId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
schedule String // cron expression
|
|
||||||
isEnabled Boolean @default(true)
|
|
||||||
|
|
||||||
// Allows triggers to be routed down different execution paths in an agent graph
|
|
||||||
triggerIdentifier String
|
|
||||||
|
|
||||||
// default and set the value on each update, lastUpdated field has no time zone.
|
|
||||||
lastUpdated DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
// Link to User model
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
Agent Agent? @relation(fields: [agentId, agentVersion], references: [id, version])
|
|
||||||
agentId String? @db.Uuid
|
|
||||||
agentVersion Int?
|
|
||||||
|
|
||||||
@@index([isEnabled])
|
|
||||||
}
|
|
||||||
|
|
||||||
enum HttpMethod {
|
|
||||||
GET
|
|
||||||
POST
|
|
||||||
PUT
|
|
||||||
DELETE
|
|
||||||
PATCH
|
|
||||||
}
|
|
||||||
|
|
||||||
model WebhookTrigger {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
agentPresetId String @db.Uuid
|
|
||||||
AgentPreset AgentPreset @relation(fields: [agentPresetId], references: [id])
|
|
||||||
|
|
||||||
method HttpMethod
|
|
||||||
urlSlug String
|
|
||||||
|
|
||||||
// Allows triggers to be routed down different execution paths in an agent graph
|
|
||||||
triggerIdentifier String
|
|
||||||
|
|
||||||
isActive Boolean @default(true)
|
|
||||||
lastReceivedDataAt DateTime?
|
|
||||||
isDeleted Boolean @default(false)
|
|
||||||
Agent Agent? @relation(fields: [agentId, agentVersion], references: [id, version])
|
|
||||||
agentId String? @db.Uuid
|
|
||||||
agentVersion Int?
|
|
||||||
|
|
||||||
@@index([agentPresetId])
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////// METRICS TRACKING TABLES ////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
model AnalyticsDetails {
|
|
||||||
// PK uses gen_random_uuid() to allow the db inserts to happen outside of prisma
|
|
||||||
// typical uuid() inserts are handled by prisma
|
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
// Link to User model
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
// Analytics Categorical data used for filtering (indexable w and w/o userId)
|
|
||||||
type String
|
|
||||||
|
|
||||||
// Analytic Specific Data. We should use a union type here, but prisma doesn't support it.
|
|
||||||
data Json @default("{}")
|
|
||||||
|
|
||||||
// Indexable field for any count based analytical measures like page order clicking, tutorial step completion, etc.
|
|
||||||
dataIndex String?
|
|
||||||
|
|
||||||
@@index([userId, type], name: "analyticsDetails")
|
|
||||||
@@index([type])
|
|
||||||
}
|
|
||||||
|
|
||||||
model AnalyticsMetrics {
|
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
// Analytics Categorical data used for filtering (indexable w and w/o userId)
|
|
||||||
analyticMetric String
|
|
||||||
// Any numeric data that should be counted upon, summed, or otherwise aggregated.
|
|
||||||
value Float
|
|
||||||
// Any string data that should be used to identify the metric as distinct.
|
|
||||||
// ex: '/build' vs '/market'
|
|
||||||
dataString String?
|
|
||||||
|
|
||||||
// Link to User model
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//////// ACCOUNTING AND CREDIT SYSTEM TABLES //////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
enum UserBlockCreditType {
|
|
||||||
TOP_UP
|
|
||||||
USAGE
|
|
||||||
}
|
|
||||||
|
|
||||||
model UserBlockCredit {
|
|
||||||
transactionKey String @default(uuid())
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
|
|
||||||
userId String @db.Uuid
|
|
||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
blockId String? @db.Uuid
|
|
||||||
Block AgentBlock? @relation(fields: [blockId], references: [id])
|
|
||||||
|
|
||||||
// We need to be able to associate a credit transaction with an agent
|
|
||||||
executedAgentId String? @db.Uuid
|
|
||||||
executedAgentVersion Int?
|
|
||||||
ExecutedAgent Agent? @relation(fields: [executedAgentId, executedAgentVersion], references: [id, version])
|
|
||||||
|
|
||||||
// We need to be able to associate a cost with a specific agent execution
|
|
||||||
agentNodeExecutionId String? @db.Uuid
|
|
||||||
AgentNodeExecution AgentNodeExecution? @relation(fields: [agentNodeExecutionId], references: [id])
|
|
||||||
|
|
||||||
amount Int
|
|
||||||
type UserBlockCreditType
|
|
||||||
|
|
||||||
isActive Boolean @default(true)
|
|
||||||
metadata Json @default("{}")
|
|
||||||
|
|
||||||
@@id(name: "creditTransactionIdentifier", [transactionKey, userId])
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////// Store TABLES ///////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
model Profile {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
// Only 1 of user or group can be set.
|
|
||||||
// The user this profile belongs to, if any.
|
|
||||||
userId String? @db.Uuid
|
|
||||||
User User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
// The group this profile belongs to, if any.
|
|
||||||
groupId String? @db.Uuid
|
|
||||||
Group UserGroup? @relation(fields: [groupId], references: [id])
|
|
||||||
|
|
||||||
username String @unique
|
|
||||||
description String
|
|
||||||
|
|
||||||
links String[]
|
|
||||||
|
|
||||||
avatarUrl String?
|
|
||||||
|
|
||||||
@@index([username])
|
|
||||||
}
|
|
||||||
|
|
||||||
model StoreListing {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
isDeleted Boolean @default(false)
|
|
||||||
// Not needed but makes lookups faster
|
|
||||||
isApproved Boolean @default(false)
|
|
||||||
|
|
||||||
// The agent link here is only so we can do lookup on agentId, for the listing the StoreListingVersion is used.
|
|
||||||
agentId String @db.Uuid
|
|
||||||
agentVersion Int
|
|
||||||
Agent Agent @relation(fields: [agentId, agentVersion], references: [id, version], onDelete: Cascade)
|
|
||||||
|
|
||||||
owningUserId String @db.Uuid
|
|
||||||
OwningUser User @relation(fields: [owningUserId], references: [id])
|
|
||||||
|
|
||||||
isGroupListing Boolean @default(false)
|
|
||||||
owningGroupId String? @db.Uuid
|
|
||||||
OwningGroup UserGroup? @relation(fields: [owningGroupId], references: [id])
|
|
||||||
|
|
||||||
StoreListingVersions StoreListingVersion[]
|
|
||||||
StoreListingSubmission StoreListingSubmission[]
|
|
||||||
|
|
||||||
@@index([isApproved])
|
|
||||||
@@index([agentId])
|
|
||||||
@@index([owningUserId])
|
|
||||||
@@index([owningGroupId])
|
|
||||||
}
|
|
||||||
|
|
||||||
model StoreListingVersion {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
version Int @default(1)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
// The agent and version to be listed on the store
|
|
||||||
agentId String @db.Uuid
|
|
||||||
agentVersion Int
|
|
||||||
Agent Agent @relation(fields: [agentId, agentVersion], references: [id, version])
|
|
||||||
|
|
||||||
// The detials for this version of the agent, this allows the author to update the details of the agent,
|
|
||||||
// But still allow using old versions of the agent with there original details.
|
|
||||||
// TODO: Create a database view that shows only the latest version of each store listing.
|
|
||||||
slug String
|
|
||||||
name String
|
|
||||||
videoUrl String?
|
|
||||||
imageUrls String[]
|
|
||||||
description String
|
|
||||||
categories String[]
|
|
||||||
|
|
||||||
isFeatured Boolean @default(false)
|
|
||||||
|
|
||||||
isDeleted Boolean @default(false)
|
|
||||||
// Old versions can be made unavailable by the author if desired
|
|
||||||
isAvailable Boolean @default(true)
|
|
||||||
// Not needed but makes lookups faster
|
|
||||||
isApproved Boolean @default(false)
|
|
||||||
StoreListing StoreListing? @relation(fields: [storeListingId], references: [id], onDelete: Cascade)
|
|
||||||
storeListingId String? @db.Uuid
|
|
||||||
StoreListingSubmission StoreListingSubmission[]
|
|
||||||
|
|
||||||
// Reviews are on a specific version, but then aggregated up to the listing.
|
|
||||||
// This allows us to provide a review filter to current version of the agent.
|
|
||||||
StoreListingReview StoreListingReview[]
|
|
||||||
|
|
||||||
@@unique([agentId, agentVersion])
|
|
||||||
@@index([agentId, agentVersion, isApproved])
|
|
||||||
}
|
|
||||||
|
|
||||||
model StoreListingReview {
|
|
||||||
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
storeListingVersionId String @db.Uuid
|
|
||||||
StoreListingVersion StoreListingVersion @relation(fields: [storeListingVersionId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
reviewByUserId String @db.Uuid
|
|
||||||
ReviewByUser User @relation(fields: [reviewByUserId], references: [id])
|
|
||||||
|
|
||||||
score Int
|
|
||||||
comments String?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SubmissionStatus {
|
|
||||||
DAFT
|
|
||||||
PENDING
|
|
||||||
APPROVED
|
|
||||||
REJECTED
|
|
||||||
}
|
|
||||||
|
|
||||||
model StoreListingSubmission {
|
|
||||||
id String @id @default(uuid()) @db.Uuid
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
|
||||||
|
|
||||||
storeListingId String @db.Uuid
|
|
||||||
StoreListing StoreListing @relation(fields: [storeListingId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
storeListingVersionId String @db.Uuid
|
|
||||||
StoreListingVersion StoreListingVersion @relation(fields: [storeListingVersionId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
reviewerId String @db.Uuid
|
|
||||||
Reviewer User @relation(fields: [reviewerId], references: [id])
|
|
||||||
|
|
||||||
Status SubmissionStatus @default(PENDING)
|
|
||||||
reviewComments String?
|
|
||||||
|
|
||||||
@@index([storeListingId])
|
|
||||||
@@index([Status])
|
|
||||||
}
|
|
Loading…
Reference in New Issue