feat: add sub-agents section to agent info menu

Added a "Sub-Agents" section to the agent info menu dropdown that:
- Queries session store for agents where parentAgentId matches current agent
- Displays child agents as clickable menu items with chevron icons
- Shows "No sub-agents" when the agent has no children
- Navigates to child agent screen when tapped

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mohamed Boudra
2025-12-21 17:25:02 +00:00
parent 11afd22858
commit cdc17006da
2 changed files with 97 additions and 2 deletions

View File

@@ -14,7 +14,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useReanimatedKeyboardAnimation } from "react-native-keyboard-controller";
import ReanimatedAnimated, { useAnimatedStyle, useSharedValue } from "react-native-reanimated";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { MoreVertical, GitBranch, Folder, RotateCcw, PlusCircle, Download } from "lucide-react-native";
import { MoreVertical, GitBranch, Folder, RotateCcw, PlusCircle, Download, Users, ChevronRight } from "lucide-react-native";
import { BackHeader } from "@/components/headers/back-header";
import { AgentStreamView } from "@/components/agent-stream-view";
import { AgentInputArea } from "@/components/agent-input-area";
@@ -153,6 +153,20 @@ function AgentScreenContent({ serverId, agentId, onBack }: AgentScreenContentPro
resolvedAgentId ? state.sessions[serverId]?.agents?.get(resolvedAgentId) : undefined
);
// Select child agents (agents where parentAgentId === current agentId)
const childAgents = useSessionStore((state) => {
if (!resolvedAgentId) return [];
const agents = state.sessions[serverId]?.agents;
if (!agents) return [];
const children: Array<{ id: string; title: string | null }> = [];
for (const [id, a] of agents) {
if (a.parentAgentId === resolvedAgentId) {
children.push({ id, title: a.title });
}
}
return children;
});
// Select only the specific stream state - use stable empty array to avoid infinite loop
const streamItemsRaw = useSessionStore((state) =>
resolvedAgentId ? state.sessions[serverId]?.agentStreamState?.get(resolvedAgentId) : undefined
@@ -439,6 +453,20 @@ function AgentScreenContent({ serverId, agentId, onBack }: AgentScreenContentPro
setShowImportAgentModal(false);
}, []);
const handleNavigateToChildAgent = useCallback(
(childAgentId: string) => {
handleCloseMenu();
router.push({
pathname: "/agent/[serverId]/[agentId]",
params: {
serverId: serverId,
agentId: childAgentId,
},
});
},
[handleCloseMenu, router, serverId]
);
const createAgentModal = (
<CreateAgentModal
isVisible={showCreateAgentModal}
@@ -585,6 +613,36 @@ function AgentScreenContent({ serverId, agentId, onBack }: AgentScreenContentPro
<View style={styles.menuDivider} />
{/* Sub-Agents Section */}
<View style={styles.menuSubAgentsSection}>
<View style={styles.menuSubAgentsHeader}>
<Users size={16} color={theme.colors.mutedForeground} />
<Text style={styles.menuSubAgentsLabel}>Sub-Agents</Text>
</View>
{childAgents.length === 0 ? (
<Text style={styles.menuSubAgentsEmpty}>No sub-agents</Text>
) : (
childAgents.map((child) => (
<Pressable
key={child.id}
onPress={() => handleNavigateToChildAgent(child.id)}
style={styles.menuSubAgentItem}
>
<Text
style={styles.menuSubAgentText}
numberOfLines={1}
ellipsizeMode="tail"
>
{child.title || "Untitled Agent"}
</Text>
<ChevronRight size={16} color={theme.colors.mutedForeground} />
</Pressable>
))
)}
</View>
<View style={styles.menuDivider} />
<Pressable onPress={handleViewChanges} style={styles.menuItem}>
<GitBranch size={20} color={theme.colors.foreground} />
<Text style={styles.menuItemText}>View Changes</Text>
@@ -830,4 +888,40 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.foreground,
fontWeight: theme.fontWeight.normal,
},
menuSubAgentsSection: {
gap: theme.spacing[1],
},
menuSubAgentsHeader: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
paddingHorizontal: theme.spacing[1],
paddingBottom: theme.spacing[1],
},
menuSubAgentsLabel: {
fontSize: theme.fontSize.xs,
color: theme.colors.mutedForeground,
letterSpacing: 0.5,
textTransform: "uppercase",
},
menuSubAgentsEmpty: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
},
menuSubAgentItem: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingVertical: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
borderRadius: theme.borderRadius.md,
},
menuSubAgentText: {
fontSize: theme.fontSize.sm,
color: theme.colors.foreground,
flex: 1,
marginRight: theme.spacing[2],
},
}));

View File

@@ -324,7 +324,7 @@ Files requiring modification:
- Run typecheck after changes.
- **Done (2025-12-21 21:45)**: Added filter in `use-aggregated-agents.ts:66-68` to skip agents with `parentAgentId` when building the aggregated agents list. Also included `parentAgentId` in the aggregated agent object. Typecheck passes.
- [ ] **Implement**: Add sub-agents section to agent info menu.
- [x] **Implement**: Add sub-agents section to agent info menu.
- In `[agentId].tsx:536`, add a "Sub-Agents" section to the menu
- Query the session store for agents where `parentAgentId === currentAgentId`
@@ -332,6 +332,7 @@ Files requiring modification:
- Tapping a child agent navigates to that agent's screen
- Show "No sub-agents" if none exist
- Run typecheck after changes.
- **Done (2025-12-21 22:00)**: Added Sub-Agents section to agent info menu in `[agentId].tsx`. Added `childAgents` selector to query agents with matching `parentAgentId`. Added `handleNavigateToChildAgent` callback for navigation. UI shows "No sub-agents" when empty, or clickable list of child agents with chevron icons. Typecheck passes.
- [ ] **Test**: Verify parent/child hierarchy end-to-end.