Skip to content

Commit 46e0f6c

Browse files
majdyzclaude
andauthored
feat(platform): Add recommended run schedule for agent execution (#10827)
## Summary <img width="1000" alt="Screenshot 2025-09-02 at 9 46 49 PM" src="https://github.com/user-attachments/assets/d78100c7-7974-4d37-a788-757764d8b6b7" /> <img width="1000" alt="Screenshot 2025-09-02 at 9 20 24 PM" src="https://github.com/user-attachments/assets/cd092963-8e26-4198-b65a-4416b2307a50" /> <img width="1000" alt="Screenshot 2025-09-02 at 9 22 30 PM" src="https://github.com/user-attachments/assets/e16b3bdb-c48c-4dec-9281-b2a35b3e21d0" /> <img width="1000" alt="Screenshot 2025-09-02 at 9 20 38 PM" src="https://github.com/user-attachments/assets/11d74a39-f4b4-4fce-8d30-0e6a925f3a9b" /> • Added recommended schedule cron expression as an optional input throughout the platform • Implemented complete data flow from builder → store submission → agent library → run page • Fixed UI layout issues including button text overflow and ensured proper component reusability ## Changes ### Backend - Added `recommended_schedule_cron` field to `AgentGraph` schema and database migration - Updated API models (`LibraryAgent`, `MyAgent`, `StoreSubmissionRequest`) to include the new field - Enhanced store submission approval flow to persist recommended schedule to database ### Frontend - Added recommended schedule input to builder page (SaveControl component) with overflow-safe styling - Updated store submission modal (PublishAgentModal) with schedule configuration - Enhanced agent run page with schedule tip display and pre-filled schedule dialog - Refactored `CronSchedulerDialog` with discriminated union types for better reusability - Fixed layout issues including button text truncation and popover width constraints - Implemented robust cron expression parsing with 100% reversibility between UI and cron format 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude <[email protected]>
1 parent c03af5c commit 46e0f6c

File tree

32 files changed

+585
-82
lines changed

32 files changed

+585
-82
lines changed

autogpt_platform/backend/backend/data/graph.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class BaseGraph(BaseDbModel):
160160
is_active: bool = True
161161
name: str
162162
description: str
163+
recommended_schedule_cron: str | None = None
163164
nodes: list[Node] = []
164165
links: list[Link] = []
165166
forked_from_id: str | None = None
@@ -696,6 +697,7 @@ def from_db(
696697
is_active=graph.isActive,
697698
name=graph.name or "",
698699
description=graph.description or "",
700+
recommended_schedule_cron=graph.recommendedScheduleCron,
699701
nodes=[NodeModel.from_db(node, for_export) for node in graph.Nodes or []],
700702
links=list(
701703
{
@@ -1083,6 +1085,7 @@ async def __create_graph(tx, graph: Graph, user_id: str):
10831085
version=graph.version,
10841086
name=graph.name,
10851087
description=graph.description,
1088+
recommendedScheduleCron=graph.recommended_schedule_cron,
10861089
isActive=graph.is_active,
10871090
userId=user_id,
10881091
forkedFromId=graph.forked_from_id,

autogpt_platform/backend/backend/server/v2/library/model.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class LibraryAgent(pydantic.BaseModel):
6464
# Indicates if this agent is the latest version
6565
is_latest_version: bool
6666

67+
# Recommended schedule cron (from marketplace agents)
68+
recommended_schedule_cron: str | None = None
69+
6770
@staticmethod
6871
def from_db(
6972
agent: prisma.models.LibraryAgent,
@@ -130,6 +133,7 @@ def from_db(
130133
new_output=new_output,
131134
can_access_graph=can_access_graph,
132135
is_latest_version=is_latest_version,
136+
recommended_schedule_cron=agent.AgentGraph.recommendedScheduleCron,
133137
)
134138

135139

autogpt_platform/backend/backend/server/v2/library/routes_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ async def test_get_library_agents_success(
5050
credentials_input_schema={"type": "object", "properties": {}},
5151
has_external_trigger=False,
5252
status=library_model.LibraryAgentStatus.COMPLETED,
53+
recommended_schedule_cron=None,
5354
new_output=False,
5455
can_access_graph=True,
5556
is_latest_version=True,
@@ -69,6 +70,7 @@ async def test_get_library_agents_success(
6970
credentials_input_schema={"type": "object", "properties": {}},
7071
has_external_trigger=False,
7172
status=library_model.LibraryAgentStatus.COMPLETED,
73+
recommended_schedule_cron=None,
7274
new_output=False,
7375
can_access_graph=False,
7476
is_latest_version=True,

autogpt_platform/backend/backend/server/v2/store/db.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ async def get_store_agent_details(
183183
store_listing.hasApprovedVersion if store_listing else False
184184
)
185185

186+
if store_listing and store_listing.ActiveVersion:
187+
recommended_schedule_cron = (
188+
store_listing.ActiveVersion.recommendedScheduleCron
189+
)
190+
else:
191+
recommended_schedule_cron = None
192+
186193
logger.debug(f"Found agent details for {username}/{agent_name}")
187194
return backend.server.v2.store.model.StoreAgentDetails(
188195
store_listing_version_id=agent.storeListingVersionId,
@@ -201,6 +208,7 @@ async def get_store_agent_details(
201208
last_updated=agent.updated_at,
202209
active_version_id=active_version_id,
203210
has_approved_version=has_approved_version,
211+
recommended_schedule_cron=recommended_schedule_cron,
204212
)
205213
except backend.server.v2.store.exceptions.AgentNotFoundError:
206214
raise
@@ -562,6 +570,7 @@ async def create_store_submission(
562570
sub_heading: str = "",
563571
categories: list[str] = [],
564572
changes_summary: str | None = "Initial Submission",
573+
recommended_schedule_cron: str | None = None,
565574
) -> backend.server.v2.store.model.StoreSubmission:
566575
"""
567576
Create the first (and only) store listing and thus submission as a normal user
@@ -655,6 +664,7 @@ async def create_store_submission(
655664
submissionStatus=prisma.enums.SubmissionStatus.PENDING,
656665
submittedAt=datetime.now(tz=timezone.utc),
657666
changesSummary=changes_summary,
667+
recommendedScheduleCron=recommended_schedule_cron,
658668
)
659669
]
660670
},
@@ -710,6 +720,7 @@ async def edit_store_submission(
710720
sub_heading: str = "",
711721
categories: list[str] = [],
712722
changes_summary: str | None = "Update submission",
723+
recommended_schedule_cron: str | None = None,
713724
) -> backend.server.v2.store.model.StoreSubmission:
714725
"""
715726
Edit an existing store listing submission.
@@ -789,6 +800,7 @@ async def edit_store_submission(
789800
sub_heading=sub_heading,
790801
categories=categories,
791802
changes_summary=changes_summary,
803+
recommended_schedule_cron=recommended_schedule_cron,
792804
)
793805

794806
# For PENDING submissions, we can update the existing version
@@ -804,6 +816,7 @@ async def edit_store_submission(
804816
categories=categories,
805817
subHeading=sub_heading,
806818
changesSummary=changes_summary,
819+
recommendedScheduleCron=recommended_schedule_cron,
807820
),
808821
)
809822

@@ -866,6 +879,7 @@ async def create_store_version(
866879
sub_heading: str = "",
867880
categories: list[str] = [],
868881
changes_summary: str | None = "Initial submission",
882+
recommended_schedule_cron: str | None = None,
869883
) -> backend.server.v2.store.model.StoreSubmission:
870884
"""
871885
Create a new version for an existing store listing
@@ -935,6 +949,7 @@ async def create_store_version(
935949
submissionStatus=prisma.enums.SubmissionStatus.PENDING,
936950
submittedAt=datetime.now(),
937951
changesSummary=changes_summary,
952+
recommendedScheduleCron=recommended_schedule_cron,
938953
storeListingId=store_listing_id,
939954
)
940955
)
@@ -1150,6 +1165,7 @@ async def get_my_agents(
11501165
last_edited=graph.updatedAt or graph.createdAt,
11511166
description=graph.description or "",
11521167
agent_image=library_agent.imageUrl,
1168+
recommended_schedule_cron=graph.recommendedScheduleCron,
11531169
)
11541170
for library_agent in library_agents
11551171
if (graph := library_agent.AgentGraph)
@@ -1351,6 +1367,21 @@ async def review_store_submission(
13511367
]
13521368
)
13531369

1370+
# Update the AgentGraph with store listing data
1371+
await prisma.models.AgentGraph.prisma().update(
1372+
where={
1373+
"graphVersionId": {
1374+
"id": store_listing_version.agentGraphId,
1375+
"version": store_listing_version.agentGraphVersion,
1376+
}
1377+
},
1378+
data={
1379+
"name": store_listing_version.name,
1380+
"description": store_listing_version.description,
1381+
"recommendedScheduleCron": store_listing_version.recommendedScheduleCron,
1382+
},
1383+
)
1384+
13541385
await prisma.models.StoreListing.prisma(tx).update(
13551386
where={"id": store_listing_version.StoreListing.id},
13561387
data={

autogpt_platform/backend/backend/server/v2/store/db_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ async def test_get_store_agent_details(mocker):
9090
mock_store_listing = mocker.MagicMock()
9191
mock_store_listing.activeVersionId = "active-version-id"
9292
mock_store_listing.hasApprovedVersion = True
93+
mock_store_listing.ActiveVersion = mocker.MagicMock()
94+
mock_store_listing.ActiveVersion.recommendedScheduleCron = None
9395

9496
# Mock StoreAgent prisma call
9597
mock_store_agent = mocker.patch("prisma.models.StoreAgent.prisma")

autogpt_platform/backend/backend/server/v2/store/model.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class MyAgent(pydantic.BaseModel):
1414
agent_image: str | None = None
1515
description: str
1616
last_edited: datetime.datetime
17+
recommended_schedule_cron: str | None = None
1718

1819

1920
class MyAgentsResponse(pydantic.BaseModel):
@@ -53,6 +54,7 @@ class StoreAgentDetails(pydantic.BaseModel):
5354
rating: float
5455
versions: list[str]
5556
last_updated: datetime.datetime
57+
recommended_schedule_cron: str | None = None
5658

5759
active_version_id: str | None = None
5860
has_approved_version: bool = False
@@ -157,6 +159,7 @@ class StoreSubmissionRequest(pydantic.BaseModel):
157159
description: str = ""
158160
categories: list[str] = []
159161
changes_summary: str | None = None
162+
recommended_schedule_cron: str | None = None
160163

161164

162165
class StoreSubmissionEditRequest(pydantic.BaseModel):
@@ -167,6 +170,7 @@ class StoreSubmissionEditRequest(pydantic.BaseModel):
167170
description: str = ""
168171
categories: list[str] = []
169172
changes_summary: str | None = None
173+
recommended_schedule_cron: str | None = None
170174

171175

172176
class ProfileDetails(pydantic.BaseModel):

autogpt_platform/backend/backend/server/v2/store/routes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ async def create_submission(
535535
sub_heading=submission_request.sub_heading,
536536
categories=submission_request.categories,
537537
changes_summary=submission_request.changes_summary or "Initial Submission",
538+
recommended_schedule_cron=submission_request.recommended_schedule_cron,
538539
)
539540
except Exception:
540541
logger.exception("Exception occurred whilst creating store submission")
@@ -580,6 +581,7 @@ async def edit_submission(
580581
sub_heading=submission_request.sub_heading,
581582
categories=submission_request.categories,
582583
changes_summary=submission_request.changes_summary,
584+
recommended_schedule_cron=submission_request.recommended_schedule_cron,
583585
)
584586

585587

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-- AlterTable
2+
ALTER TABLE "StoreListingVersion" ADD COLUMN "recommendedScheduleCron" TEXT;
3+
ALTER TABLE "AgentGraph" ADD COLUMN "recommendedScheduleCron" TEXT;

autogpt_platform/backend/schema.prisma

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ model AgentGraph {
110110
111111
name String?
112112
description String?
113+
recommendedScheduleCron String?
113114
114115
isActive Boolean @default(true)
115116
@@ -785,6 +786,8 @@ model StoreListingVersion {
785786
reviewComments String? // Comments visible to creator
786787
reviewedAt DateTime?
787788
789+
recommendedScheduleCron String? // cron expression like "0 9 * * *"
790+
788791
// Reviews for this specific version
789792
Reviews StoreListingReview[]
790793

autogpt_platform/backend/snapshots/agt_details

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"1.1.0"
2323
],
2424
"last_updated": "2023-01-01T00:00:00",
25+
"recommended_schedule_cron": null,
2526
"active_version_id": null,
2627
"has_approved_version": false
2728
}

0 commit comments

Comments
 (0)