Add CalDAV calendar integration, LLM-suggested tags, and settings refinements
- CalDAV integration: per-user calendar config, create/list/search events via caldav library, LLM tools for calendar operations from chat - LLM-suggested tags: new tag_suggestions service prompts LLM with existing tags and note content to suggest 3-5 relevant tags; exposed via API endpoints (suggest-tags, append-tag); integrated into editor views (suggest button + clickable pills) and chat tool calls (pills in ToolCallCard with one-click apply) - Settings/model UI refinements, generation task improvements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+22
-8
@@ -12,7 +12,7 @@
|
||||
> Include file-level details in the commit body when the change is non-trivial.
|
||||
|
||||
## Last Updated
|
||||
2026-02-14 — Phase 7: LLM tool calling (create tasks, create notes, search notes from chat)
|
||||
2026-02-15 — Phase 8: CalDAV calendar integration, LLM-suggested tags, settings/model UI refinements
|
||||
|
||||
## Project Overview
|
||||
Fabled Assistant is a self-hosted note-taking and task-tracking application with
|
||||
@@ -212,7 +212,7 @@ for AI-assisted features.
|
||||
```
|
||||
fabledassistant/
|
||||
├── summary.md # This file — canonical project context
|
||||
├── pyproject.toml # Python project config
|
||||
├── pyproject.toml # Python project config (deps include caldav, icalendar)
|
||||
├── Dockerfile # Multi-stage build (Node → Python)
|
||||
├── docker-compose.yml # Dev compose (app, PostgreSQL, Ollama)
|
||||
├── docker-compose.prod.yml # Production stack (Docker Swarm, secrets, network isolation)
|
||||
@@ -253,7 +253,7 @@ fabledassistant/
|
||||
│ │ ├── auth.py # /api/auth blueprint: register, login, logout, me, status, password reset, invitation registration
|
||||
│ │ ├── admin.py # /api/admin blueprint: backup, restore, user management, registration toggle, invitations, base URL, SMTP (admin only)
|
||||
│ │ ├── chat.py # /api/chat blueprint: conversations CRUD, SSE message streaming (all @login_required)
|
||||
│ │ ├── notes.py # /api/notes CRUD + wikilinks + backlinks (all @login_required)
|
||||
│ │ ├── notes.py # /api/notes CRUD + wikilinks + backlinks + tag suggestions (all @login_required)
|
||||
│ │ ├── tasks.py # /api/tasks CRUD + PATCH status (all @login_required)
|
||||
│ │ └── settings.py # /api/settings GET/PUT — per-user settings (@login_required)
|
||||
│ ├── services/
|
||||
@@ -264,7 +264,9 @@ fabledassistant/
|
||||
│ │ ├── chat.py # Conversation CRUD with user_id isolation, add_message, save/summarize as note (LLM-titled, chat-tagged)
|
||||
│ │ ├── generation_buffer.py # In-memory SSE event buffer with cancel_event, reconnect support, auto-cleanup; supports chat (int keys) and assist (string keys)
|
||||
│ │ ├── generation_task.py # Background asyncio tasks: run_generation (chat, DB flush, titles, tool loop) + run_assist_generation (lightweight, no DB)
|
||||
│ │ ├── tools.py # LLM tool definitions (create_task, create_note, search_notes) + execute_tool dispatcher
|
||||
│ │ ├── tools.py # LLM tool definitions (create_task, create_note, search_notes, CalDAV events) + execute_tool dispatcher
|
||||
│ │ ├── tag_suggestions.py # LLM-powered tag suggestions: suggest_tags() builds prompt with existing tags, calls generate_completion, parses JSON response
|
||||
│ │ ├── caldav.py # CalDAV integration: create/list/search calendar events via caldav library (per-user config from settings)
|
||||
│ │ ├── settings.py # Settings CRUD with user_id isolation: get_setting, set_setting, set_settings_batch, get_all_settings
|
||||
│ │ ├── logging.py # App logging: log_audit, log_usage, log_error, get_logs, get_log_stats, delete_old_logs, start_log_retention_loop
|
||||
│ │ ├── email.py # SMTP email service: get_smtp_config, is_smtp_configured, send_email, send_test_email
|
||||
@@ -320,10 +322,10 @@ fabledassistant/
|
||||
│ │ ├── HomeView.vue # Actionable dashboard: overdue, due today, due this week, high priority, in progress tasks; recent chats with inline chat input; recently edited notes; model warming on mount
|
||||
│ │ ├── SettingsView.vue # Settings page: assistant name, model catalog, data export/restore (admin)
|
||||
│ │ ├── NotesListView.vue # Note list: search, sort, tag filter pills, pagination
|
||||
│ │ ├── NoteEditorView.vue # Create/edit: Tiptap editor, sticky toolbar, AI Assist panel (bottom 1/3), Ctrl+S, unsaved guard
|
||||
│ │ ├── NoteEditorView.vue # Create/edit: Tiptap editor, sticky toolbar, AI Assist panel (bottom 1/3), LLM tag suggestions, Ctrl+S, unsaved guard
|
||||
│ │ ├── NoteViewerView.vue # Markdown render, wikilink auto-create, convert-to-task, backlinks, table of contents sidebar
|
||||
│ │ ├── TasksListView.vue # Task list: search, status/priority filters, sort, pagination
|
||||
│ │ ├── TaskEditorView.vue # Create/edit task: Tiptap editor, sticky toolbar, AI Assist panel, Ctrl+S, dirty guard
|
||||
│ │ ├── TaskEditorView.vue # Create/edit task: Tiptap editor, sticky toolbar, AI Assist panel, LLM tag suggestions, Ctrl+S, dirty guard
|
||||
│ │ └── TaskViewerView.vue # Task detail: rendered markdown, badges, convert-to-note, backlinks, table of contents sidebar
|
||||
│ ├── components/
|
||||
│ │ ├── LogsView.vue # Admin log viewer: stats summary, category/search/date filters, paginated table with expandable detail rows
|
||||
@@ -331,7 +333,7 @@ fabledassistant/
|
||||
│ │ ├── ChatPanel.vue # Slide-out chat panel (right side overlay, receives contextNoteId prop), bubble-style messages, floating dark input, note picker, context pills with promote/exclude
|
||||
│ │ ├── ModelSelector.vue # Model dropdown (v-model pattern): fetches installed + running models, hot/cold indicators
|
||||
│ │ ├── DashboardChatInput.vue # Inline chat bar: ModelSelector + note picker + textarea + send button; emits submit event
|
||||
│ │ ├── ToolCallCard.vue # Compact card for tool call results (created task/note link, search results, errors)
|
||||
│ │ ├── ToolCallCard.vue # Compact card for tool call results (created task/note link, search results, errors) + suggested tag pills with apply-on-click
|
||||
│ │ ├── ChatMessage.vue # Message bubble: markdown rendering, tool call cards, configurable assistant name label, "Save as Note" action on assistant messages
|
||||
│ │ ├── NoteCard.vue # Card with rendered markdown preview (v-html), TagPill, tag-click emit, hover edit button
|
||||
│ │ ├── TaskCard.vue # Card with rendered preview (body not description), StatusBadge (clickable), PriorityBadge, due date, tags, hover edit button
|
||||
@@ -372,6 +374,8 @@ fabledassistant/
|
||||
| GET | `/api/notes` | List notes (params: `q`, `tag`, `sort`, `order`, `limit`, `offset`; defaults to `is_task=false` — plain notes only; `?is_task=true` for tasks, `?all=true` for everything) |
|
||||
| POST | `/api/notes` | Create note (body: `{title, body, status?, priority?, due_date?}` — tags auto-extracted) |
|
||||
| GET | `/api/notes/tags` | List all tags from notes table (param: `q` for filter) |
|
||||
| POST | `/api/notes/suggest-tags` | LLM-suggest tags for content (body: `{title, body}`, returns `{suggested_tags: [...]}`) |
|
||||
| POST | `/api/notes/:id/append-tag` | Append `#tag` to note body (body: `{tag}`, returns updated note) |
|
||||
| GET | `/api/notes/by-title?title=...` | Resolve note by exact title (case-insensitive) |
|
||||
| POST | `/api/notes/resolve-title` | Get-or-create note by title (for wikilink clicks) |
|
||||
| GET | `/api/notes/:id` | Get single note (response includes `is_task`, `status`, `priority`, `due_date`) |
|
||||
@@ -542,6 +546,15 @@ When adding a new migration, follow these conventions:
|
||||
components (linked titles for created items, search result lists). SSE emits `tool_call` events
|
||||
for real-time rendering during streaming. System prompt includes today's date for relative date
|
||||
resolution. Graceful degradation: models without tool support respond normally.
|
||||
- **CalDAV calendar integration:** Per-user CalDAV settings (URL, username, password, calendar name).
|
||||
LLM tools: `create_event`, `list_events`, `search_events`. Runs synchronous caldav library calls
|
||||
in asyncio executor. Settings UI for CalDAV configuration.
|
||||
- **LLM-suggested tags:** Backend service (`tag_suggestions.py`) prompts LLM with existing user tags
|
||||
and note content, returns 3-5 relevant tag suggestions. Tags already in body are filtered out.
|
||||
Exposed via `POST /api/notes/suggest-tags` and `POST /api/notes/:id/append-tag`. Integrated in:
|
||||
(1) Editor views — "Suggest tags" button shows clickable pills that insert `#tag` into body;
|
||||
(2) Chat tool calls — `create_note`/`create_task` results include `suggested_tags`, rendered as
|
||||
pills in ToolCallCard with one-click apply via append-tag API.
|
||||
|
||||
### Authentication & User Management
|
||||
- Session cookie auth with bcrypt, first-user-is-admin, orphaned data claiming
|
||||
@@ -594,9 +607,10 @@ When adding a new migration, follow these conventions:
|
||||
- To reset database: `docker compose down -v && docker compose up --build`
|
||||
|
||||
## Backlog
|
||||
- Tagging/labeling system with LLM-suggested tags
|
||||
- Calendar/timeline view for tasks
|
||||
- Import/export (Markdown files, JSON)
|
||||
- Email integration (read/send emails from chat via IMAP/SMTP tools)
|
||||
- Web search support (LLM tool to search the web and summarize results)
|
||||
- Application-level rate limiting on auth endpoints
|
||||
- Security headers middleware (CSP, X-Frame-Options, etc.) — currently handled at reverse proxy level
|
||||
- Session invalidation on user deletion
|
||||
|
||||
Reference in New Issue
Block a user