From acea622a0fe51318d0fc4cb632ca0e9f6c190a6b Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Thu, 30 Jul 2026 11:33:45 +0200 Subject: [PATCH] fix: AI loop prevention (no tools on last iteration), calendar button first, mail filter in toolbar, AI folder rename query invalidation --- app/plugins/builtins/ai_assistant/services.py | 7 ++- frontend/src/components/ai/SessionList.tsx | 7 ++- frontend/src/pages/Calendar.tsx | 50 ++++++++-------- frontend/src/pages/Mail.tsx | 58 ++++++++++++------- 4 files changed, 73 insertions(+), 49 deletions(-) diff --git a/app/plugins/builtins/ai_assistant/services.py b/app/plugins/builtins/ai_assistant/services.py index 3fbab66..e4cc272 100644 --- a/app/plugins/builtins/ai_assistant/services.py +++ b/app/plugins/builtins/ai_assistant/services.py @@ -451,9 +451,12 @@ async def stream_chat( # Agent loop: LLM → tool calls → execute → feed back → repeat max_iterations = 5 for iteration in range(max_iterations): - # Add tools to params if available - if tool_schemas: + # Add tools to params if available, but NOT on the last iteration + # to force the LLM to give a final answer instead of looping + if tool_schemas and iteration < max_iterations - 1: params["tools"] = tool_schemas + elif "tools" in params: + del params["tools"] # Stream LLM response collected_content = "" diff --git a/frontend/src/components/ai/SessionList.tsx b/frontend/src/components/ai/SessionList.tsx index 78e0902..02daf20 100644 --- a/frontend/src/components/ai/SessionList.tsx +++ b/frontend/src/components/ai/SessionList.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState, useRef, useCallback } from 'react'; import clsx from 'clsx'; +import { useQueryClient } from '@tanstack/react-query'; import { fetchSessions, createSession, deleteSession, updateSession, fetchFolders, createFolder, deleteFolder, updateFolder, @@ -261,6 +262,7 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class const [dragSessionId, setDragSessionId] = useState(null); const [dragFolderId, setDragFolderId] = useState(null); const [contextMenu, setContextMenu] = useState(null); + const queryClient = useQueryClient(); const loadData = async () => { try { @@ -287,7 +289,10 @@ export function SessionList({ activeSessionId, onSelectSession, isSidebar, class if (!newName) return; try { if (type === 'session') await updateSession(id, { title: newName }); - else await updateFolder(id, { name: newName }); + else { + await updateFolder(id, { name: newName }); + queryClient.invalidateQueries({ queryKey: ['ai', 'folders'] }); + } loadData(); } catch (e) { setError(e instanceof Error ? e.message : 'Rename failed'); } }; diff --git a/frontend/src/pages/Calendar.tsx b/frontend/src/pages/Calendar.tsx index d3ef1b5..aee1689 100644 --- a/frontend/src/pages/Calendar.tsx +++ b/frontend/src/pages/Calendar.tsx @@ -327,6 +327,31 @@ export function CalendarPage() { useEffect(() => { const items = [ + // New appointment — ganz links + { + id: 'new-appointment', + plugin: 'calendar', + label: t('calendar.newAppointment'), + group: 'actions', + onClick: () => { + openWindow({ + title: t('calendar.newAppointment'), + type: 'appointment-create', + component: AppointmentEditForm, + componentProps: { + entry: null, + prefillDate: null, + calendars, + defaultCalendarId: activeCalendarId, + onSaved: handleSaved, + onDeleted: handleDeleted, + }, + }); + }, + icon: ( + + ), + }, // Navigation group { id: 'nav-prev', @@ -384,31 +409,6 @@ export function CalendarPage() { onSelect: (value: string) => setViewMode(value as CalendarViewMode), onClick: () => {}, }, - // Actions group - { - id: 'new-appointment', - plugin: 'calendar', - label: t('calendar.newAppointment'), - group: 'actions', - onClick: () => { - openWindow({ - title: t('calendar.newAppointment'), - type: 'appointment-create', - component: AppointmentEditForm, - componentProps: { - entry: null, - prefillDate: null, - calendars, - defaultCalendarId: activeCalendarId, - onSaved: handleSaved, - onDeleted: handleDeleted, - }, - }); - }, - icon: ( - - ), - }, { id: 'ics-import', plugin: 'calendar', diff --git a/frontend/src/pages/Mail.tsx b/frontend/src/pages/Mail.tsx index 4121cf1..3b4dac2 100644 --- a/frontend/src/pages/Mail.tsx +++ b/frontend/src/pages/Mail.tsx @@ -594,6 +594,43 @@ export function MailPage() { onSearch: handleSearch, onClick: () => {}, }, + // FilterPanel — SavedFilterBar + TagSelector + { + id: 'filter-panel', + plugin: 'mail', + label: 'Filter', + type: 'custom' as const, + group: 'filter', + customComponent: ( + { + if (criteria.search !== undefined) handleSearch(criteria.search); + if (criteria.sortBy) setSortBy(criteria.sortBy as 'date' | 'from' | 'subject'); + if (criteria.sortOrder) setSortOrder(criteria.sortOrder as 'asc' | 'desc'); + }} + /> + ), + onClick: () => {}, + }, + { + id: 'tag-filter', + plugin: 'mail', + label: 'Tags', + type: 'custom' as const, + group: 'filter', + customComponent: ( + + ), + onClick: () => {}, + }, { id: 'compose', plugin: 'mail', @@ -814,27 +851,6 @@ export function MailPage() { className="border-r border-secondary-200 bg-white" data-testid="mail-list-pane" > - {/* Saved filter bar + tag selector */} -
- { - if (criteria.search !== undefined) handleSearch(criteria.search); - if (criteria.sortBy) setSortBy(criteria.sortBy as 'date' | 'from' | 'subject'); - if (criteria.sortOrder) setSortOrder(criteria.sortOrder as 'asc' | 'desc'); - }} - /> -
- -
-