feat(agents): add manual drag-and-drop sorting for agent and session lists#13460
feat(agents): add manual drag-and-drop sorting for agent and session lists#13460kangfenmao merged 11 commits intomainfrom
Conversation
Add sort_order column to agents table and implement drag-and-drop reordering in the agent sidebar panel, consistent with assistant list behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
EurFelux
left a comment
There was a problem hiding this comment.
Self-review: overall implementation looks good. Two minor suggestions:
- Transaction safety —
reorderAgentsshould use a DB transaction to prevent partial updates on failure - Error feedback — Reorder failure should show a toast to the user instead of silently reverting
- Use database.transaction() for atomic sort_order updates - Show error toast on reorder failure instead of silent revert - Add i18n keys for reorder error message Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
When sort_order values are equal (e.g., after migration when all existing agents have sort_order=0), use created_at DESC as a deterministic tie-breaker to maintain stable ordering. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
|
Note on migration from unified list order: Previously, when Agents and Assistants were mixed together, their display order was stored in As a result, after upgrading, existing agents will all start with |
There was a problem hiding this comment.
Re-reviewed the latest revision. The follow-up issues raised in review are now addressed: reorder writes are wrapped in a transaction, reorder failures surface an error toast instead of silently reverting, and sort_order ties now use created_at DESC as a deterministic secondary sort after migration. I don't see new blocking issues in the current revision. LGTM.
|
Sessions also need to be sorted. |
Mirror the agent sorting implementation for sessions, scoped per-agent. Add sort_order column to sessions table, reorder API endpoint, and swap DynamicVirtualList for DraggableVirtualList in the Sessions UI. Combine agent and session sort_order into a single migration (0003). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
There was a problem hiding this comment.
Re-reviewed the updated PR after the session-sorting expansion. The earlier review findings remain addressed, and the new session-side implementation follows the same persistence/error-handling pattern: transactional reorder writes, deterministic sort_order tie-breaking with created_at DESC, and user-visible failure feedback on optimistic rollback. I don't see a new blocking issue in the current revision. LGTM.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
EurFelux
left a comment
There was a problem hiding this comment.
Overall this is a well-designed feature with clean architecture — sort_order column + transactional reorder APIs + optimistic frontend updates is the right approach.
Main issue to fix:
AgentService.createAgent— the sort_order shift + insert needs to be wrapped in a transaction (likeSessionService.createSessionalready does), otherwise a failed insert leaves all sort_orders incremented with no rollback.
Minor suggestions:
- Swagger doc
orderBydefault doesn't reflect the conditionalascforsort_order agentId!non-null assertion could use an early return guard
Everything else looks good — DB migration, API design, frontend DnD integration, and optimistic caching are all solid. 👍
- Wrap createAgent shift+insert in transaction for atomicity - Replace agentId! non-null assertion with early return in reorderSessions - Update Swagger doc to note conditional orderBy default for sort_order Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
EurFelux
left a comment
There was a problem hiding this comment.
Review Summary
Well-structured PR! The implementation follows existing patterns nicely (DraggableList reuse, SWR optimistic updates, Drizzle transactions). The backend/frontend integration is clean and the route ordering to prevent "reorder" being captured as :agentId is a nice touch.
What looks great
- Transactions for both create (sort_order shift + insert) and reorder operations
- Optimistic SWR updates with proper rollback on error
- Secondary sort by
created_at DESCfor tie-breaking after migration - Scoped session sorting per agent
- Route placement comments explaining why
/reordermust precede/:id
Minor suggestions (non-blocking)
- Element-level type validation for
ordered_idsarray entries - Future optimization opportunity: batch UPDATE via
CASE/WHENinstead of N individual UPDATEs - Confirm
autoHideScrollbarremoval in Sessions is intentional - Confirm no-revalidation-on-success pattern is intentional for both hooks
Overall: clean implementation, no blockers found. 👍
Ensure each element in ordered_ids is a non-empty string, not just that the array itself is non-empty. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
EurFelux
left a comment
There was a problem hiding this comment.
Re-review after a30aad9
The new commit a30aad9 correctly addresses the element-type validation feedback — both reorderAgents and reorderSessions handlers now validate that each entry in ordered_ids is a non-empty string via .every((id: unknown) => typeof id === 'string' && id.length > 0).
All previously raised review threads are resolved. No new issues found.
Remaining non-blocking suggestions from earlier review (for future consideration):
- Batch UPDATE via
CASE/WHENfor reorder performance optimization - Confirm
autoHideScrollbarremoval in Sessions component is intentional - Consider adding server revalidation after successful reorder
LGTM overall 👍
|
with Tailwind - Extract agent list from AgentSidePanel into dedicated Agents component, mirroring the Sessions component structure - Replace styled-components StyledVirtualList with Tailwind classes in both Agents and Sessions components Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: icarus <[email protected]>
1d35a78 to
f106798
Compare
|
Fixed? |
Yes |
|
merge? |
|
Note This issue/comment/review was translated by Claude. I think it's OK now. Do we need to review it further? Original Content我觉得 OK 了,还要再看看吗 |




What this PR does
Before this PR:
Agents and sessions in the sidebar are listed in fixed order with no way to manually reorder them.
After this PR:
Both agents and sessions can be reordered via drag-and-drop. The order is persisted to the SQLite database via a new
sort_ordercolumn, and new items are automatically placed at the top of the list. Session sorting is scoped per-agent (each agent's sessions are independently sortable).Why we need it and why it was done in this way
The following tradeoffs were made:
sort_orderinteger column in SQLite (backend persistence) rather than Redux/localStorage, because agents/sessions data lives in the backend DB — consistent with the existing architecture.sort_order = 0and all existing items are shifted up by 1, matching the assistant list behavior where new items appear at the top.DraggableListcomponent for agents andDraggableVirtualListfor sessions (both using@hello-pangea/dnd) for consistency with existing drag-and-drop patterns.PUT /v1/agents/reorderandPUT /v1/agents/{agentId}/sessions/reorderendpoints rather than updating sort_order through individual PATCH calls, to ensure atomic reorder operations.The following alternatives were considered:
@dnd-kit/sortableinstead of@hello-pangea/dnd— rejected to maintain consistency with existing components.Breaking changes
None. The new
sort_ordercolumn defaults to0for all existing agents and sessions, so they will share the same sort order initially and fall back tocreated_at DESCas tie-breaker.Special notes for your reviewer
Database migration:
0003_slippery_wild_pack.sqladdssort_order INTEGER NOT NULL DEFAULT 0to bothagentsandsessionstablesidx_agents_sort_order,idx_sessions_sort_order) for query performancesort_order = 0by default; the first reorder operation will assign proper valuesAPI changes:
PUT /v1/agents/reorder— accepts{ ordered_ids: string[] }to reorder agentsPUT /v1/agents/{agentId}/sessions/reorder— accepts{ ordered_ids: string[] }to reorder sessions (scoped to agent)GET /v1/agents— default sort changed tosort_order ASC, created_at DESCGET /v1/agents/{agentId}/sessions— default sort changed tosort_order ASC, created_at DESCFrontend:
useAgentshook exposesreorderAgents()with optimistic SWR cache updateuseSessionshook exposesreorderSessions()with optimistic SWRInfinite cache update (preserves real total for pagination)AgentSidePanelusesDraggableListfor agent drag-and-dropSessionscomponent swapped fromDynamicVirtualListtoDraggableVirtualListfor session drag-and-dropAtomicity:
createSessionwraps sort_order shift + insert in a transactionreorderAgentsandreorderSessionsboth use transactionsChecklist
Release note