diff --git a/packages/app/src/app/index.tsx b/packages/app/src/app/index.tsx
index dd643fcfd..35bc25d39 100644
--- a/packages/app/src/app/index.tsx
+++ b/packages/app/src/app/index.tsx
@@ -1,4 +1,4 @@
-import { View, ActivityIndicator, Text } from "react-native";
+import { View, ActivityIndicator } from "react-native";
import { useState, useCallback, useMemo, useRef, useEffect } from "react";
import { useFocusEffect } from "@react-navigation/native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
@@ -19,7 +19,8 @@ export default function HomeScreen() {
const {
agents: aggregatedAgents,
isInitialLoad,
- isRevalidating
+ isRevalidating,
+ refreshAll,
} = useAggregatedAgents();
const [showCreateModal, setShowCreateModal] = useState(false);
const [showImportModal, setShowImportModal] = useState(false);
@@ -123,16 +124,11 @@ export default function HomeScreen() {
) : hasAgents ? (
-
-
-
- {isRevalidating && (
-
-
- Reconnecting...
-
- )}
-
+
) : (
({
alignItems: "center",
justifyContent: "center",
},
- revalidatingBadge: {
- position: "absolute",
- top: 8,
- right: 8,
- flexDirection: "row",
- alignItems: "center",
- gap: 8,
- paddingHorizontal: 12,
- paddingVertical: 6,
- backgroundColor: theme.colors.muted,
- borderRadius: 16,
- opacity: 0.9,
- },
- revalidatingText: {
- fontSize: 12,
- color: theme.colors.mutedForeground,
- },
}));
diff --git a/packages/app/src/components/agent-list.tsx b/packages/app/src/components/agent-list.tsx
index 580464d06..03b5ee47b 100644
--- a/packages/app/src/components/agent-list.tsx
+++ b/packages/app/src/components/agent-list.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable, FlatList, Modal, type ListRenderItem } from "react-native";
+import { View, Text, Pressable, FlatList, Modal, RefreshControl, type ListRenderItem } from "react-native";
import { useCallback, useState } from "react";
import { router } from "expo-router";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
@@ -11,9 +11,11 @@ import { buildAgentNavigationKey, startNavigationTiming } from "@/utils/navigati
interface AgentListProps {
agents: AggregatedAgent[];
+ isRefreshing?: boolean;
+ onRefresh?: () => void;
}
-export function AgentList({ agents }: AgentListProps) {
+export function AgentList({ agents, isRefreshing = false, onRefresh }: AgentListProps) {
const { theme } = useUnistyles();
const [actionAgent, setActionAgent] = useState(null);
const actionSession = useDaemonSession(actionAgent?.serverId, {
@@ -150,6 +152,16 @@ export function AgentList({ agents }: AgentListProps) {
renderItem={renderAgentItem}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
+ refreshControl={
+ onRefresh ? (
+
+ ) : undefined
+ }
/>
void;
initializeAgent: (params: { agentId: string; requestId?: string }) => void;
refreshAgent: (params: { agentId: string; requestId?: string }) => void;
+ refreshSession: () => void;
cancelAgentRun: (agentId: string) => void;
sendAgentMessage: (
agentId: string,
@@ -1589,6 +1590,17 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
return targetPath;
}, [updateExplorerState, ws]);
+ const refreshSession = useCallback(() => {
+ console.log(`[Session] Manual refresh requested for ${serverId}`);
+ ws.send({
+ type: "session",
+ message: {
+ type: "load_conversation_request",
+ conversationId: ws.conversationId ?? "",
+ },
+ });
+ }, [ws, serverId]);
+
// Cleanup on unmount
useEffect(() => {
return () => {
@@ -1610,6 +1622,7 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
restartServer,
initializeAgent,
refreshAgent,
+ refreshSession,
cancelAgentRun,
deleteAgent,
sendAgentMessage,
@@ -1632,6 +1645,7 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
restartServer,
initializeAgent,
refreshAgent,
+ refreshSession,
cancelAgentRun,
deleteAgent,
sendAgentMessage,
@@ -1656,6 +1670,7 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
restartServer,
initializeAgent,
refreshAgent,
+ refreshSession,
cancelAgentRun,
sendAgentMessage,
sendAgentAudio,
@@ -1674,6 +1689,7 @@ export function SessionProvider({ children, serverUrl, serverId }: SessionProvid
restartServer,
initializeAgent,
refreshAgent,
+ refreshSession,
cancelAgentRun,
sendAgentMessage,
sendAgentAudio,
diff --git a/packages/app/src/hooks/use-aggregated-agents.ts b/packages/app/src/hooks/use-aggregated-agents.ts
index 8ccbd2c5b..be5cf791a 100644
--- a/packages/app/src/hooks/use-aggregated-agents.ts
+++ b/packages/app/src/hooks/use-aggregated-agents.ts
@@ -1,4 +1,4 @@
-import { useMemo } from "react";
+import { useMemo, useCallback } from "react";
import { useDaemonConnections } from "@/contexts/daemon-connections-context";
import { useSessionStore } from "@/stores/session-store";
import type { AgentDirectoryEntry } from "@/types/agent-directory";
@@ -13,13 +13,24 @@ export interface AggregatedAgentsResult {
isLoading: boolean;
isInitialLoad: boolean;
isRevalidating: boolean;
+ refreshAll: () => void;
}
export function useAggregatedAgents(): AggregatedAgentsResult {
const { connectionStates } = useDaemonConnections();
const sessions = useSessionStore((state) => state.sessions);
- return useMemo(() => {
+ const refreshAll = useCallback(() => {
+ console.log('[useAggregatedAgents] Manual refresh triggered for all sessions');
+ for (const [serverId, session] of Object.entries(sessions)) {
+ if (session?.methods?.refreshSession) {
+ console.log(`[useAggregatedAgents] Refreshing session ${serverId}`);
+ session.methods.refreshSession();
+ }
+ }
+ }, [sessions]);
+
+ const result = useMemo(() => {
const allAgents: AggregatedAgent[] = [];
// Derive agent directory from all sessions
@@ -124,4 +135,9 @@ export function useAggregatedAgents(): AggregatedAgentsResult {
isRevalidating,
};
}, [sessions, connectionStates]);
+
+ return {
+ ...result,
+ refreshAll,
+ };
}
diff --git a/packages/app/src/hooks/use-daemon-session.ts b/packages/app/src/hooks/use-daemon-session.ts
index f0d852354..fe9c1d2b5 100644
--- a/packages/app/src/hooks/use-daemon-session.ts
+++ b/packages/app/src/hooks/use-daemon-session.ts
@@ -30,6 +30,7 @@ export type DaemonSession = SessionState & {
restartServer: (reason?: string) => void;
initializeAgent: (params: { agentId: string; requestId?: string }) => void;
refreshAgent: (params: { agentId: string; requestId?: string }) => void;
+ refreshSession: () => void;
cancelAgentRun: (agentId: string) => void;
sendAgentMessage: (
agentId: string,
diff --git a/packages/app/src/stores/session-store.ts b/packages/app/src/stores/session-store.ts
index 48f75af5c..08707f7c5 100644
--- a/packages/app/src/stores/session-store.ts
+++ b/packages/app/src/stores/session-store.ts
@@ -169,6 +169,7 @@ export interface SessionState {
restartServer: (reason?: string) => void;
initializeAgent: (params: { agentId: string; requestId?: string }) => void;
refreshAgent: (params: { agentId: string; requestId?: string }) => void;
+ refreshSession: () => void;
cancelAgentRun: (agentId: string) => void;
sendAgentMessage: (
agentId: string,