feat: separate Agent into independent module with dedicated page and route#13420
feat: separate Agent into independent module with dedicated page and route#13420
Conversation
…route (#13329) - Add `/agents` route, sidebar icon, launchpad entry, and i18n labels - Create AgentPage, AgentChat, AgentNavbar, AgentSidePanel components - Support left sidebar and right-side Sessions panel (topicPosition setting) - Rename Unified* components/hooks to Assistant* (agents removed from home) - Remove `activeTopicOrSession` from Redux runtime store (route-based detection) - Simplify HomePage/Chat.tsx by removing agent-related branches - Auto-select first agent when navigating to agent page - Add Redux migration v201 for sidebar icons Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: icarus <eurfelux@gmail.com>
|
Do you have a screenshot? Please take a look @EurFelux |
…d AddButton to components - Move agent-only components (AgentSessionInputbar, AgentSessionMessages, AgentContent, AgentItem, SessionItem, Sessions, SelectAgentBaseModelButton, OpenExternalAppButton, SessionWorkspaceMeta) to pages/agents/components/ - Move shared AddButton to renderer/src/components/ - Delete dead SessionsTab (no longer imported after agent separation) - Update all import paths to reflect new locations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: icarus <eurfelux@gmail.com>
|
Note This issue/comment/review was translated by Claude. Mostly ready for review. The loading states for API Server not started/agents loading/sessions loading haven't been fine-tuned yet. Original Content大体上 ready for review. API Server 未启动/agents 拉取中/sessions 拉取中的状态还没调好 |
- Move apiServer.enabled check to AgentPage top level as early return, preventing child components (Sessions, AgentSidePanel) from making API calls when server is disabled - Add loading indicator (Spin) during initialization instead of flashing incorrect alerts - Distinguish session map undefined (not initialized) vs null (no sessions) in useAgentSessionInitializer to prevent premature "create session" alert - Use apiServerRunning check in AgentChat to cover the gap before SWR starts fetching (key is null when server not yet running) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: icarus <eurfelux@gmail.com>
Combine the read-only hook (hooks/agents/useActiveAgent) and the
setter hook (home/Tabs/hooks/useActiveAgent) into a single hook
that returns both { agent, error, isLoading, setActiveAgentId }.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: icarus <eurfelux@gmail.com>
|
Note This issue/comment/review was translated by Claude. The lifecycle status display issue has been properly handled. Original Content生命周期状态显示问题已妥善处理 |
DeJeune
left a comment
There was a problem hiding this comment.
Review Summary
Excellent refactoring work — separating Agents into their own page/route is a well-motivated architectural improvement. The migration is clean, activeTopicOrSession removal is complete, and the new component hierarchy mirrors the home page structure nicely.
Issues Found
Bug (1):
- Migration 202 has a copy-paste error in the success log message (
'migrate 201 success'→ should be'migrate 202 success')
Significant (2):
AgentChat.tsx: The content rendering block (activeAgentId && activeSessionId) doesn't guard againstisInitializing, meaning if Redux already has both IDs set from a previous session, the spinner and chat content could render simultaneously. Adding!isInitializing &&to that condition would make it consistent with the other branches.AgentPage.tsx: The auto-select effect'ssetActiveAgentIddependency is unstable becauseuseAgentSessionInitializerincludesactiveSessionIdMapin itsuseCallbackdeps. This causes unnecessary callback re-creations on every session map change. A ref-based approach for the map check would stabilize the reference.
Minor/Nit (2):
AgentChat.tsx:useSettings()called twice — can be merged into one destructuring.AgentContent.tsx: When sidebar is collapsed in top-navbar mode, both a PanelRightClose icon and an animated Menu hamburger icon render as separate toggle buttons. Worth a brief comment explaining the UX intent.
Positives
- Clean separation of concerns: Agent page, chat, side panel, and navbar are well-structured
- Good loading state management with the
isInitializingcomposite check andundefinedvsnullsession distinction - Migration properly inserts the
'agents'sidebar icon after'assistants' activeTopicOrSessionremoval is thorough — no stale references remain- Shared component extraction (
AddButton) is a nice cleanup
src/renderer/src/pages/agents/components/AgentChatNavbar/AgentContent.tsx
Show resolved
Hide resolved
Prevent unnecessary re-initialization by using a ref to track activeSessionIdMap. This ensures the useEffect dependency array remains stable and only triggers when needed.
There was a problem hiding this comment.
Overall direction looks good: separating Agents into a dedicated module/page makes the information architecture much clearer and removes a lot of mixed Assistant/Agent state from the home flow.
I left one inline comment for a likely regression: the old shortcut handler was removed from , but I could not find an equivalent registration under the new page path. As written, this seems likely to break for creating a new agent session on the dedicated Agents page.
Once that shortcut path is restored, this refactor looks in good shape to merge.
SiinXu
left a comment
There was a problem hiding this comment.
LGTM — clean separation of Agent into its own module. Reviewed the key concerns raised by DeJeune and cherry-ai-bot:
isInitializingguard: Fixed. All rendering branches inAgentChat.tsxare now mutually exclusive — spinner and chat content cannot render simultaneously.setActiveAgentIddependency stability: Fixed at the hook level —useAgentSessionInitializernow uses a ref foractiveSessionIdMap, keepinginitializeAgentSessionreferentially stable.- Migration 202 log: Fixed. Correctly logs
'migrate 202 success'. Cmd/Ctrl+Nshortcut regression: Fixed per EurFelux's reply.
Non-blocking nit: useAgentClient() (not modified in this PR) creates a new AgentApiClient instance on every render without useMemo. This makes client referentially unstable, cascading through useAgentSessionInitializer → setActiveAgentId → AgentPage useEffect deps. The activeSessionIdMapRef guard prevents actual infinite loops, but the unnecessary callback re-creation is wasteful. Consider wrapping in useMemo([host, port, apiKey]) in a follow-up.
AgentPage previously only checked apiServer.enabled config, which didn't handle cases where the server was enabled but failed to start at runtime. Now uses useApiServer hook to check actual running state with three guards: not enabled → warning, loading → spinner, not running → error alert. Also removes redundant apiServerRunning check from AgentChat since AgentPage now guards it at the parent level. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: icarus <eurfelux@gmail.com>
- Add loading spinner during initialization - Show "create agent" alert when no agents exist - Separate loading states for agents, agent selection, and session creation - Fix layout structure for better responsiveness - Update useAgents hook to return undefined data instead of empty array fallback







What this PR does
Before this PR:
Agent and Assistant were mixed in a single
UnifiedListin the home page sidebar. Users had difficulty discovering the Agent entry. The two have fundamentally different data models (Redux vs SQLite), interaction patterns (topic vs session), and component hierarchies, yet shared the same UI components and Redux state (activeTopicOrSession).After this PR:
Agent is separated into an independent module with its own sidebar entry, route (
/agents), page, navbar, and side panel. The home page only handles Assistants. Navigation between the two is handled via sidebar icons and routes, not Redux state.Fixes #13329
Why we need it and why it was done in this way
The following tradeoffs were made:
AgentSettingsTabwas moved topages/agents/and is used by theAgentChatNavbar/Tools/SettingsButtondrawer.Unified*components were renamed toAssistant*(viagit mv) rather than just removing agent code, to make naming accurate and improve readability.activeTopicOrSessionwas removed from Redux runtime store entirely, replaced by route-based detection where needed, avoiding stale state issues.The following alternatives were considered:
UnifiedListwith a filter — rejected because the data models and interaction patterns are too different, leading to excessive conditional logic.Breaking changes
None. This is an internal UI refactoring. The Redux migration (v200 → v201) automatically adds the
'agents'sidebar icon to existing user configurations.Special notes for your reviewer
New directory structure —
pages/agents/:AgentPage.tsx— Top-level page with apiServer.enabled guard (early return with alert when server disabled)AgentChat.tsx— Chat area with loading state management (Spin during initialization, alerts for select/create states)AgentNavbar.tsx— Top navbar for left-sidebar layout modeAgentSidePanel.tsx— Left panel with agent list and sessions tabsAgentSettingsTab.tsx— Moved from home, used by AgentChatNavbar settings drawercomponents/AgentChatNavbar/— Mirrorshome/components/ChatNavBar/structure:index.tsx— Sidebar toggle buttons + content wrapperAgentContent.tsx— Agent → Session → Model → Workspace breadcrumb navigationTools/— Agent-specific toolbar withSettingsButton(usesAgentSettingsTab)OpenExternalAppButton.tsx,SessionWorkspaceMeta.tsx— AgentContent-only componentscomponents/— Migrated agent-only components:AgentItem,AgentSessionInputbar,AgentSessionMessages,SelectAgentBaseModelButton,SessionItem,SessionsHook consolidation:
useActiveAgenthooks into one athooks/agents/useActiveAgent— now returns both{ agent, error, isLoading, setActiveAgentId }home/Tabs/hooks/useActiveAgent.tsLoading state improvements:
AgentPagetop-level guard prevents all child components from rendering when apiServer is disabledAgentChattracksisInitializingcovering: server starting → agents loading → agent loading → session initializing → auto-select pendinguseAgentSessionInitializernow distinguishesundefined(not initialized) vsnull(initialized, no sessions) inactiveSessionIdMap, preventing premature "create session" alertsShared component extraction:
AddButtonmoved fromhome/Tabs/components/torenderer/src/components/(used by both pages)Checklist
Release note