You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(api): let an app move from a folder back to the top level - #8077
An app moved into a folder cannot be moved back out. The /m Move dialog lists only folders, and /w has no top-level choice either. The API also had no way to clear a folder. edit_workflow dumps the edit with exclude_none=True, so a folder_id: null in the body was dropped and the app stayed in its folder.
Changes
API:
edit_workflow keeps a folder_id that the caller sent, including null. A null moves the item to the top level. An edit without folder_id leaves the folder as it is.
edit_application and edit_evaluator build a WorkflowEdit from a full dump of their own edit model. With the change above, that dump would send folder_id: null on every rename. They now pass folder_id on only when their caller sent it.
/m:
The Move dialog starts with an "All prompts" row (the word the breadcrumb uses). For a prompt inside a folder, it sends {"workflow": {"id": "<id>", "folder_id": null}}.
Folders still cannot move to the top level, because the folders API keeps the parent on a null parent_id. The row is greyed out for a folder.
Shared package (@agenta/entities): isValidMoveTarget accepts a null destination for a prompt in a folder, and moveWorkflowToFolder accepts a null folder id. Only /m calls them, and the /w type check passes.
Callers checked
Before this change, folder_id: null in an edit body did nothing. After it, a null clears the folder. I checked every caller that could send one:
API services. The simple edits (/simple/workflows, /simple/applications, /simple/evaluators) and the skills import build their edit without folder_id, so it is not sent. The PUT /applications/{id} and PUT /evaluators/{id} routes now pass folder_id on only when the request body has it.
/w frontend. updateAppName and the shared updateWorkflow send no folder_id. updateAppFolder sends one, but the /w prompts page calls it only with a folder id and refuses an empty destination. No /w code calls the application or evaluator edit routes.
/m and the shared packages. moveWorkflowToFolder is the only caller that sends folder_id, and it sends null only from the new "All prompts" choice.
Python SDK. The managers call the /simple/... routes, which have no folder_id. The agent rename_agent op calls PUT /workflows/{id}, but its input schema allows only name and description. The generated client folder is empty, so it makes no calls.
No caller sends back a full object it read, so none clears a folder by accident.
Tests
API unit tests in api/oss/tests/pytest/unit/workflows/test_edit_workflow_folder.py parse the JSON body the way the router does. They check that a null folder_id moves the item to the top level, that a folder_id moves it into that folder, and that a rename without folder_id keeps the folder for a workflow, an application and an evaluator. The null test fails on the old service code. The workflows, applications and evaluators unit suites pass (860 tests) through run-tests.py.
/m: the prompts screen test runs the real package code with only fetch mocked and asserts the exact PUT /workflows/{id} body. Dialog and package tests cover the new row and the move rules.
/m and /w type checks pass. ruff format and ruff check are clean.
What to QA
In /m Prompts (developer view prompts), move an app into a folder. Then open Move again and pick All prompts. The app shows at the top level, also after a reload.
In /w, rename an app that sits in a folder. It stays in the folder.
Rename an evaluator in /w. It keeps its folder, if it has one.
An app moved into a folder could not be moved back out. The workflow edit
dropped a null folder_id (exclude_none), so there was no way to clear it.
edit_workflow now keeps a folder_id the caller sent, including null.
edit_application and edit_evaluator pass folder_id on only when their caller
sent it, so a rename never moves an app or an evaluator.
/m: the Move dialog gets an All prompts row that sends folder_id null.
No actionable comments were generated in the recent review.
Summary
Summary by CodeRabbit
New Features
Prompts can now be moved from a folder to the top-level “All prompts” location by selecting it as the destination.
Bug Fixes
Moving workflows, applications, and evaluators to the top level now correctly clears their folder assignment.
Edits that omit a folder destination leave the current folder unchanged; explicitly choosing the top level clears it.
Prompts already at the top level cannot be moved to the same location.
The prompt move flow now supports moving a prompt from a folder to the top level. The dialog passes a null folder ID, and the edit services preserve explicitly supplied null values.
isValidMoveTarget allows a prompt in a folder to move to the top level. moveWorkflowToFolder accepts and forwards a null folder ID. Tests cover destination eligibility and the null request value.
Dialog selection and move request web/mobile/src/features/prompts/dialogs/MoveToFolderDialog.tsx, web/mobile/src/features/prompts/usePromptFolderActions.ts, web/mobile/tests/unit/promptDialogs.render.test.tsx, web/mobile/tests/unit/promptsScreen.render.test.tsx
The dialog displays the top-level destination and passes null when it is selected. The action sends the destination to target validation. Tests cover selecting the root and sending a request with folder_id: null.
Application, evaluator, and workflow edit services preserve folder_id when callers explicitly set it to null. Tests check null, non-null, and omitted folder IDs.
sequenceDiagram
participant User
participant MoveToFolderDialog
participant usePromptFolderActions
participant moveWorkflowToFolder
participant WorkflowsService
User->>MoveToFolderDialog: Select top-level destination and confirm
MoveToFolderDialog->>usePromptFolderActions: Pass null destination
usePromptFolderActions->>moveWorkflowToFolder: Move prompt to top level
moveWorkflowToFolder->>WorkflowsService: Send edit with folder_id null
Loading
Merge Risk: Low · up to 1d7a7
The move-to-top-level behavior is implemented correctly; only a narrow regression-test gap remains for application and evaluator wrappers.
Pre-merge checks: 4 · 1
Failed checks: 1 warning
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 0.00% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 4 passed
Check name
Status
Explanation
Title check
The title clearly and concisely describes the main change: allowing an application to move from a folder to the top level.
Description check
The description directly explains the API, dialog, validation, tests, and QA changes for moving prompts to the top level.
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage
Explanation
Docstring coverage is 0.00% which is insufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 3 functions across 11 files.
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
Finishing Touches
Generate docstrings
Commit to this branch
Create a new PR
Generate unit tests (beta)
Commit to this branch
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Reviewing files that changed from the base of the PR and between daf88ee and 1d7a73c.
Files selected for processing: 3
api/oss/src/core/applications/service.py
api/oss/src/core/evaluators/service.py
api/oss/src/core/workflows/service.py
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
Review loop result for head daf88eea32 (base d6ef7781e5), one round on the full diff.
Lens
Final rating
Correctness (Codex)
Low, no findings
Naming (Codex)
Low, no findings
Correctness checked that an explicit folder_id: null reaches the database write and clears the folder, and that edits without folder_id (including application and evaluator edits) keep the folder. Naming checked that folderId maps to folder_id in the request, the DTO and the stored artifact, and that the dialog reuses the existing "All prompts" label.
Fixed: nothing to fix. Left on purpose: folders still cannot move to the top level, because the folders API keeps the parent on a null parent_id.
Cover explicit folder_id=None through both wrapper services.
The application and evaluator tests cover only an omitted folder_id. They do not protect the explicit-null forwarding path. Add one test for each wrapper that asserts folder_id remains present and has value None.
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
Dependent tests finished. Post /preview for manual review. Environment absence verified; retained storage requires separate provider accounting.
Post /preview as a new comment to request a one-hour preview. Repeating it while active does not extend the hour.
Preview data is disposable. Expiry is enforced by the next successful cleanup sweep, not an exact timer.
Environment deletion stops its compute. Provider-retained storage and permanent services may still be billed.
🤖 The AI agent says: Live QA passed on head 1d7a73c (release/v0.128.5 merged in, no conflicts).
Setup: one fresh OSS dev stack built from release/v0.128.5 with #8075, #8076, #8077 and #8086 merged in, developer views playground,prompts,variants,endpoints,observability-app-filter on, a new account, Chromium at 1440 px and 390 px. The API ran this batch's code.
/m: I moved qa-completion into qa-folder and reloaded. It is in the folder. I renamed it inside the folder and reloaded. It stays in the folder. I moved it to "All prompts" and reloaded. It is back at the top level, and the folder is empty.
API: PUT /workflows/{id} with folder_id: null moves the app to the top level.
/w: Prompts > Move between qa-folder and qa-folder-2, both ways, still works after a reload. The request sends the new folder_id.
Not from this PR: in /w, the Move dialog logs "Maximum call stack size exceeded" (a focus loop) when you open it inside a folder. The move still works. The dialog is /w code that this PR does not change.
Checks on this head: API unit tests (10,118 pass, 145 skipped because no Postgres is available, 0 fail), ruff format and ruff check (clean), /m types, /w types, pnpm run lint in web/mobile (0 errors), the PR's mobile and entities tests, and speed:check all pass. Needed CI is green. Only the web test jobs fail, and they do not gate.
The screen recording (MP4) is saved with the QA evidence. I could not attach it here because the browser upload was not available in this session.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
API change. Not for v0.128.5; next release.
Context
An app moved into a folder cannot be moved back out. The /m Move dialog lists only folders, and /w has no top-level choice either. The API also had no way to clear a folder.
edit_workflowdumps the edit withexclude_none=True, so afolder_id: nullin the body was dropped and the app stayed in its folder.Changes
API:
edit_workflowkeeps afolder_idthat the caller sent, including null. A null moves the item to the top level. An edit withoutfolder_idleaves the folder as it is.edit_applicationandedit_evaluatorbuild aWorkflowEditfrom a full dump of their own edit model. With the change above, that dump would sendfolder_id: nullon every rename. They now passfolder_idon only when their caller sent it./m:
{"workflow": {"id": "<id>", "folder_id": null}}.parent_id. The row is greyed out for a folder.Shared package (
@agenta/entities):isValidMoveTargetaccepts a null destination for a prompt in a folder, andmoveWorkflowToFolderaccepts a null folder id. Only /m calls them, and the /w type check passes.Callers checked
Before this change,
folder_id: nullin an edit body did nothing. After it, a null clears the folder. I checked every caller that could send one:/simple/workflows,/simple/applications,/simple/evaluators) and the skills import build their edit withoutfolder_id, so it is not sent. ThePUT /applications/{id}andPUT /evaluators/{id}routes now passfolder_idon only when the request body has it.updateAppNameand the sharedupdateWorkflowsend nofolder_id.updateAppFoldersends one, but the /w prompts page calls it only with a folder id and refuses an empty destination. No /w code calls the application or evaluator edit routes.moveWorkflowToFolderis the only caller that sendsfolder_id, and it sends null only from the new "All prompts" choice./simple/...routes, which have nofolder_id. The agentrename_agentop callsPUT /workflows/{id}, but its input schema allows onlynameanddescription. The generated client folder is empty, so it makes no calls.No caller sends back a full object it read, so none clears a folder by accident.
Tests
api/oss/tests/pytest/unit/workflows/test_edit_workflow_folder.pyparse the JSON body the way the router does. They check that a nullfolder_idmoves the item to the top level, that afolder_idmoves it into that folder, and that a rename withoutfolder_idkeeps the folder for a workflow, an application and an evaluator. The null test fails on the old service code. The workflows, applications and evaluators unit suites pass (860 tests) throughrun-tests.py.fetchmocked and asserts the exactPUT /workflows/{id}body. Dialog and package tests cover the new row and the move rules.ruff formatandruff checkare clean.What to QA
prompts), move an app into a folder. Then open Move again and pick All prompts. The app shows at the top level, also after a reload.