refactor: improve AI event handling and conflict display in chat
- AI fetches events on-demand via callbacks for better efficiency - Add conflict detection with warning display when proposing overlapping events - Improve event search and display in chat interface - Load full chat history for display while limiting AI context
This commit is contained in:
52
CLAUDE.md
52
CLAUDE.md
@@ -266,10 +266,10 @@ src/
|
||||
│ ├── index.ts # Re-exports GPTAdapter
|
||||
│ └── utils/ # Shared AI utilities (provider-agnostic)
|
||||
│ ├── index.ts # Re-exports
|
||||
│ ├── eventFormatter.ts # formatExistingEvents() for system prompt
|
||||
│ ├── eventFormatter.ts # Re-exports formatDate/Time/DateTime from shared
|
||||
│ ├── systemPrompt.ts # buildSystemPrompt() - German calendar assistant prompt
|
||||
│ ├── toolDefinitions.ts # TOOL_DEFINITIONS - provider-agnostic tool specs
|
||||
│ └── toolExecutor.ts # executeToolCall() - handles getDay, proposeCreate/Update/Delete, searchEvents
|
||||
│ └── toolExecutor.ts # executeToolCall() - handles getDay, proposeCreate/Update/Delete, searchEvents, getEventsInRange
|
||||
├── utils/
|
||||
│ ├── jwt.ts # signToken(), verifyToken() - NOT USED YET (no JWT)
|
||||
│ ├── password.ts # hash(), compare() using bcrypt
|
||||
@@ -325,10 +325,12 @@ src/
|
||||
- `CalendarEvent`: id, userId, title, description?, startTime, endTime, note?, isRecurring?, recurrenceRule?, exceptionDates?
|
||||
- `ExpandedEvent`: Extends CalendarEvent with occurrenceStart, occurrenceEnd (for recurring event instances)
|
||||
- `ChatMessage`: id, conversationId, sender ('user' | 'assistant'), content, proposedChanges?
|
||||
- `ProposedEventChange`: id, action ('create' | 'update' | 'delete'), eventId?, event?, updates?, respondedAction?, deleteMode?, occurrenceDate?
|
||||
- `ProposedEventChange`: id, action ('create' | 'update' | 'delete'), eventId?, event?, updates?, respondedAction?, deleteMode?, occurrenceDate?, conflictingEvents?
|
||||
- Each proposal has unique `id` (e.g., "proposal-0") for individual confirm/reject
|
||||
- `respondedAction` tracks user response per proposal (not per message)
|
||||
- `deleteMode` ('single' | 'future' | 'all') and `occurrenceDate` for recurring event deletion
|
||||
- `conflictingEvents` contains events that overlap with the proposed time (for conflict warnings)
|
||||
- `ConflictingEvent`: title, startTime, endTime - simplified event info for conflict display
|
||||
- `RecurringDeleteMode`: 'single' | 'future' | 'all' - delete modes for recurring events
|
||||
- `DeleteRecurringEventDTO`: mode, occurrenceDate? - DTO for recurring event deletion
|
||||
- `Conversation`: id, userId, createdAt?, updatedAt? (messages loaded separately via lazy loading)
|
||||
@@ -342,6 +344,39 @@ src/
|
||||
- `Day`: "Monday" | "Tuesday" | ... | "Sunday"
|
||||
- `Month`: "January" | "February" | ... | "December"
|
||||
|
||||
### AI Context Architecture
|
||||
|
||||
The AI assistant fetches calendar data on-demand rather than receiving pre-loaded events. This reduces token usage significantly.
|
||||
|
||||
**AIContext Interface:**
|
||||
```typescript
|
||||
interface AIContext {
|
||||
userId: string;
|
||||
conversationHistory: ChatMessage[]; // Last 20 messages for context
|
||||
currentDate: Date;
|
||||
// Callbacks for on-demand data fetching:
|
||||
fetchEventsInRange: (start: Date, end: Date) => Promise<ExpandedEvent[]>;
|
||||
searchEvents: (query: string) => Promise<CalendarEvent[]>;
|
||||
fetchEventById: (eventId: string) => Promise<CalendarEvent | null>;
|
||||
}
|
||||
```
|
||||
|
||||
**Available AI Tools:**
|
||||
- `getDay` - Calculate relative dates (e.g., "next Friday")
|
||||
- `getCurrentDateTime` - Get current timestamp
|
||||
- `proposeCreateEvent` - Propose new event (includes automatic conflict detection)
|
||||
- `proposeUpdateEvent` - Propose event modification
|
||||
- `proposeDeleteEvent` - Propose event deletion (supports recurring delete modes)
|
||||
- `searchEvents` - Search events by title (returns IDs for update/delete)
|
||||
- `getEventsInRange` - Load events for a date range (for "what's today?" queries)
|
||||
|
||||
**Conflict Detection:**
|
||||
When creating events, `toolExecutor` automatically:
|
||||
1. Fetches events for the target day via `fetchEventsInRange`
|
||||
2. Checks for time overlaps using `occurrenceStart/occurrenceEnd` (important for recurring events)
|
||||
3. Returns `conflictingEvents` array in the proposal for UI display
|
||||
4. Adds ⚠️ warning to tool result so AI can inform user
|
||||
|
||||
### Database Abstraction
|
||||
|
||||
The repository pattern allows swapping databases:
|
||||
@@ -402,7 +437,6 @@ The decorator uses a Proxy to intercept method calls lazily, preserves sync/asyn
|
||||
**Log Summarization:**
|
||||
The `@Logged` decorator automatically summarizes large arguments to keep logs readable:
|
||||
- `conversationHistory` → `"[5 messages]"`
|
||||
- `existingEvents` → `"[3 events]"`
|
||||
- `proposedChanges` → logged in full (for debugging AI issues)
|
||||
- Long strings (>100 chars) → truncated
|
||||
- Arrays → `"[Array(n)]"`
|
||||
@@ -474,9 +508,11 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- `MongoChatRepository`: Full CRUD implemented (getConversationsByUser, createConversation, getMessages with cursor pagination, createMessage, updateMessage, updateProposalResponse, updateProposalEvent)
|
||||
- `ChatRepository` interface: updateMessage(), updateProposalResponse(), updateProposalEvent() for per-proposal tracking
|
||||
- `GPTAdapter`: Full implementation with OpenAI GPT (gpt-4o-mini model), function calling for calendar operations, collects multiple proposals per response
|
||||
- `ai/utils/`: Provider-agnostic shared utilities (systemPrompt, toolDefinitions, toolExecutor, eventFormatter)
|
||||
- `ai/utils/systemPrompt`: Includes RRULE documentation - AI knows to create separate events when times differ by day, warns AI not to put RRULE in description field
|
||||
- `ai/utils/toolDefinitions`: proposeUpdateEvent supports `isRecurring` and `recurrenceRule` parameters for adding UNTIL or modifying recurrence
|
||||
- `ai/utils/`: Provider-agnostic shared utilities (systemPrompt, toolDefinitions, toolExecutor)
|
||||
- `ai/utils/systemPrompt`: AI fetches events on-demand (no pre-loaded context), includes RRULE documentation, warns AI not to put RRULE in description field, instructs AI not to show event IDs to users
|
||||
- `ai/utils/toolDefinitions`: proposeUpdateEvent supports `isRecurring` and `recurrenceRule` parameters, getEventsInRange tool for on-demand event loading
|
||||
- `ai/utils/toolExecutor`: Async execution, conflict detection uses `occurrenceStart/occurrenceEnd` for recurring events, returns `conflictingEvents` in proposals
|
||||
- `MongoEventRepository`: Includes `searchByTitle()` for case-insensitive title search
|
||||
- `utils/recurrenceExpander`: Handles RRULE parsing, strips `RRULE:` prefix if present (AI may include it), filters out exceptionDates
|
||||
- `logging/`: Structured logging with pino, pino-http middleware, @Logged decorator
|
||||
- All repositories and GPTAdapter decorated with @Logged for automatic method logging
|
||||
@@ -538,7 +574,7 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- `ModalBase`: Reusable modal wrapper with backdrop (absolute-positioned behind card), uses CardBase internally - provides click-outside-to-close, Android back button support, and proper scrolling on Android
|
||||
- `EventCardBase`: Event card with date/time/recurring icons - uses CardBase for structure
|
||||
- `EventCard`: Uses EventCardBase + edit/delete buttons (TouchableOpacity with delayPressIn for scroll-friendly touch handling)
|
||||
- `ProposedEventCard`: Uses EventCardBase + confirm/reject/edit buttons for chat proposals, displays green highlighted text for new changes ("Neue Ausnahme: [date]" for single delete, "Neues Ende: [date]" for UNTIL updates). Edit button allows modifying proposals before confirming.
|
||||
- `ProposedEventCard`: Uses EventCardBase + confirm/reject/edit buttons for chat proposals, displays green highlighted text for new changes ("Neue Ausnahme: [date]" for single delete, "Neues Ende: [date]" for UNTIL updates), shows yellow conflict warnings when proposed time overlaps with existing events. Edit button allows modifying proposals before confirming.
|
||||
- `DeleteEventModal`: Delete confirmation modal using ModalBase - shows three options for recurring events (single/future/all), simple confirm for non-recurring
|
||||
- `EventOverlay` (in calendar.tsx): Day events overlay using ModalBase - shows EventCards for selected day
|
||||
- `Themes.tsx`: Theme definitions with THEMES object (defaultLight, defaultDark) including all color tokens (textPrimary, borderPrimary, eventIndicator, secondaryBg, shadowColor, etc.)
|
||||
|
||||
Reference in New Issue
Block a user