From 74f17f61ec6ba7a46d8c4b077e7a4034b5ea84a0 Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Sun, 28 Dec 2025 01:41:27 +0530 Subject: [PATCH] feat: Enhance agent system prompt with `write_todos` examples, and apply minor code formatting across connector pages and hooks. --- .../app/agents/new_chat/system_prompt.py | 21 ++++++++- .../add/airtable-connector/page.tsx | 2 +- .../add/google-calendar-connector/page.tsx | 5 ++- .../add/google-gmail-connector/page.tsx | 2 +- .../connectors/add/luma-connector/page.tsx | 2 +- .../add/webcrawler-connector/page.tsx | 2 +- surfsense_web/components/sidebar/nav-main.tsx | 45 ++++++++++--------- .../components/sidebar/nav-notes.tsx | 8 ++-- surfsense_web/hooks/use-logs.ts | 7 ++- 9 files changed, 57 insertions(+), 37 deletions(-) diff --git a/surfsense_backend/app/agents/new_chat/system_prompt.py b/surfsense_backend/app/agents/new_chat/system_prompt.py index ae4f96fdd..695d62bfb 100644 --- a/surfsense_backend/app/agents/new_chat/system_prompt.py +++ b/surfsense_backend/app/agents/new_chat/system_prompt.py @@ -123,7 +123,6 @@ You have access to the following tools: * content: Description of the task (required) * status: "pending", "in_progress", or "completed" (required) - The tool automatically adds IDs and formats the output for the UI. - - Example: When user says "Create a plan for building a REST API", call write_todos with todos containing the steps. - User: "Fetch all my notes and what's in them?" @@ -189,6 +188,26 @@ You have access to the following tools: - User: "Break down how to build a REST API into steps" - Call: `write_todos(todos=[{"content": "Design API endpoints and data models", "status": "in_progress"}, {"content": "Set up server framework and routing", "status": "pending"}, {"content": "Implement CRUD operations", "status": "pending"}, {"content": "Add authentication and error handling", "status": "pending"}])` - Then provide detailed explanations for each step + +- User: "Help me plan my trip to Japan" + - Call: `write_todos(todos=[{"content": "Research best time to visit and book flights", "status": "in_progress"}, {"content": "Plan itinerary for cities to visit", "status": "pending"}, {"content": "Book accommodations", "status": "pending"}, {"content": "Prepare travel documents and currency", "status": "pending"}])` + - Then provide travel preparation guidance + +- User: "Break down how to learn guitar" + - Call: `write_todos(todos=[{"content": "Learn basic chords and finger positioning", "status": "in_progress"}, {"content": "Practice strumming patterns", "status": "pending"}, {"content": "Learn to read tabs and sheet music", "status": "pending"}, {"content": "Master simple songs", "status": "pending"}])` + - Then provide learning milestones and tips + +- User: "Plan my workout routine for the week" + - Call: `write_todos(todos=[{"content": "Monday: Upper body strength training", "status": "in_progress"}, {"content": "Tuesday: Cardio and core workout", "status": "pending"}, {"content": "Wednesday: Rest or light stretching", "status": "pending"}, {"content": "Thursday: Lower body strength training", "status": "pending"}, {"content": "Friday: Full body HIIT session", "status": "pending"}])` + - Then provide exercise details and tips + +- User: "Help me organize my home renovation project" + - Call: `write_todos(todos=[{"content": "Define scope and create budget", "status": "in_progress"}, {"content": "Research and hire contractors", "status": "pending"}, {"content": "Obtain necessary permits", "status": "pending"}, {"content": "Order materials and fixtures", "status": "pending"}, {"content": "Execute renovation phases", "status": "pending"}])` + - Then provide detailed renovation guidance + +- User: "What steps should I take to start a podcast?" + - Call: `write_todos(todos=[{"content": "Define podcast concept and target audience", "status": "in_progress"}, {"content": "Set up recording equipment and software", "status": "pending"}, {"content": "Plan episode structure and content", "status": "pending"}, {"content": "Record and edit first episodes", "status": "pending"}, {"content": "Choose hosting platform and publish", "status": "pending"}])` + - Then provide podcast launch guidance """ diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/airtable-connector/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/airtable-connector/page.tsx index 950ea5fcd..890497310 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/airtable-connector/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/airtable-connector/page.tsx @@ -30,7 +30,7 @@ export default function AirtableConnectorPage() { const [isConnecting, setIsConnecting] = useState(false); const [doesConnectorExist, setDoesConnectorExist] = useState(false); - const { refetch : fetchConnectors } = useAtomValue(connectorsAtom); + const { refetch: fetchConnectors } = useAtomValue(connectorsAtom); useEffect(() => { fetchConnectors().then((data) => { diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-calendar-connector/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-calendar-connector/page.tsx index fdee2b55b..21f7a31d6 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-calendar-connector/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-calendar-connector/page.tsx @@ -32,13 +32,14 @@ export default function GoogleCalendarConnectorPage() { const [isConnecting, setIsConnecting] = useState(false); const [doesConnectorExist, setDoesConnectorExist] = useState(false); - const { refetch : fetchConnectors } = useAtomValue(connectorsAtom); + const { refetch: fetchConnectors } = useAtomValue(connectorsAtom); useEffect(() => { fetchConnectors().then((data) => { const connectors = data.data || []; const connector = connectors.find( - (c: SearchSourceConnector) => c.connector_type === EnumConnectorName.GOOGLE_CALENDAR_CONNECTOR + (c: SearchSourceConnector) => + c.connector_type === EnumConnectorName.GOOGLE_CALENDAR_CONNECTOR ); if (connector) { setDoesConnectorExist(true); diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-gmail-connector/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-gmail-connector/page.tsx index 8beef0e4b..d99c35fac 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-gmail-connector/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/google-gmail-connector/page.tsx @@ -32,7 +32,7 @@ export default function GoogleGmailConnectorPage() { const [isConnecting, setIsConnecting] = useState(false); const [doesConnectorExist, setDoesConnectorExist] = useState(false); - const { refetch : fetchConnectors } = useAtomValue(connectorsAtom); + const { refetch: fetchConnectors } = useAtomValue(connectorsAtom); useEffect(() => { fetchConnectors().then((data) => { diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/luma-connector/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/luma-connector/page.tsx index 29354263b..e253b6a01 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/luma-connector/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/luma-connector/page.tsx @@ -67,7 +67,7 @@ export default function LumaConnectorPage() { }, }); - const { refetch : fetchConnectors } = useAtomValue(connectorsAtom); + const { refetch: fetchConnectors } = useAtomValue(connectorsAtom); useEffect(() => { fetchConnectors().then((data) => { diff --git a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/webcrawler-connector/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/webcrawler-connector/page.tsx index 4a63244b8..5423cd94f 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/connectors/add/webcrawler-connector/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/connectors/add/webcrawler-connector/page.tsx @@ -55,7 +55,7 @@ export default function WebcrawlerConnectorPage() { const [isSubmitting, setIsSubmitting] = useState(false); const [doesConnectorExist, setDoesConnectorExist] = useState(false); - const { refetch : fetchConnectors } = useAtomValue(connectorsAtom); + const { refetch: fetchConnectors } = useAtomValue(connectorsAtom); const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom); // Initialize the form diff --git a/surfsense_web/components/sidebar/nav-main.tsx b/surfsense_web/components/sidebar/nav-main.tsx index ddb700ff3..420b1e172 100644 --- a/surfsense_web/components/sidebar/nav-main.tsx +++ b/surfsense_web/components/sidebar/nav-main.tsx @@ -58,30 +58,33 @@ export function NavMain({ items, onSourcesExpandedChange }: NavMainProps) { }; // Check if an item is active based on pathname - const isItemActive = useCallback((item: NavItem): boolean => { - if (!pathname) return false; + const isItemActive = useCallback( + (item: NavItem): boolean => { + if (!pathname) return false; - // For items without sub-items, check if pathname matches or starts with the URL - if (!item.items?.length) { - // Chat item: active ONLY when on new-chat page without a specific chat ID - // (i.e., exactly /dashboard/{id}/new-chat, not /dashboard/{id}/new-chat/123) - if (item.url.includes("/new-chat")) { - // Match exactly the new-chat base URL (ends with /new-chat) - return pathname.endsWith("/new-chat"); + // For items without sub-items, check if pathname matches or starts with the URL + if (!item.items?.length) { + // Chat item: active ONLY when on new-chat page without a specific chat ID + // (i.e., exactly /dashboard/{id}/new-chat, not /dashboard/{id}/new-chat/123) + if (item.url.includes("/new-chat")) { + // Match exactly the new-chat base URL (ends with /new-chat) + return pathname.endsWith("/new-chat"); + } + // Logs item: active when on logs page + if (item.url.includes("/logs")) { + return pathname.includes("/logs"); + } + // Check exact match or prefix match + return pathname === item.url || pathname.startsWith(`${item.url}/`); } - // Logs item: active when on logs page - if (item.url.includes("/logs")) { - return pathname.includes("/logs"); - } - // Check exact match or prefix match - return pathname === item.url || pathname.startsWith(`${item.url}/`); - } - // For items with sub-items (like Sources), check if any sub-item URL matches - return item.items.some( - (subItem) => pathname === subItem.url || pathname.startsWith(subItem.url) - ); - }, [pathname]); + // For items with sub-items (like Sources), check if any sub-item URL matches + return item.items.some( + (subItem) => pathname === subItem.url || pathname.startsWith(subItem.url) + ); + }, + [pathname] + ); // Memoize items to prevent unnecessary re-renders const memoizedItems = useMemo(() => items, [items]); diff --git a/surfsense_web/components/sidebar/nav-notes.tsx b/surfsense_web/components/sidebar/nav-notes.tsx index a808eeebe..a4b34e10d 100644 --- a/surfsense_web/components/sidebar/nav-notes.tsx +++ b/surfsense_web/components/sidebar/nav-notes.tsx @@ -80,11 +80,9 @@ export function NavNotes({ const [isAllNotesSidebarOpen, setIsAllNotesSidebarOpen] = useState(false); // Poll for active reindexing tasks to show inline loading indicators - const { summary } = useLogsSummary( - searchSpaceId ? Number(searchSpaceId) : 0, - 24, - { refetchInterval: 2000 } - ); + const { summary } = useLogsSummary(searchSpaceId ? Number(searchSpaceId) : 0, 24, { + refetchInterval: 2000, + }); // Create a Set of document IDs that are currently being reindexed const reindexingDocumentIds = useMemo(() => { diff --git a/surfsense_web/hooks/use-logs.ts b/surfsense_web/hooks/use-logs.ts index 643222c0c..41b2660e5 100644 --- a/surfsense_web/hooks/use-logs.ts +++ b/surfsense_web/hooks/use-logs.ts @@ -139,10 +139,9 @@ export function useLogsSummary( enabled: !!searchSpaceId, staleTime: 3 * 60 * 1000, // Enable refetch interval for document processing indicator polling - refetchInterval: options.refetchInterval && options.refetchInterval > 0 - ? options.refetchInterval - : undefined, + refetchInterval: + options.refetchInterval && options.refetchInterval > 0 ? options.refetchInterval : undefined, }); return { summary, loading, error, refreshSummary: refetch }; -} \ No newline at end of file +}