Add persistent context sidebar, note title fix, and expanded tool suite
Context sidebar + note title:
- ChatView: replace ephemeral context pills with a persistent right-panel sidebar;
auto-found notes accumulate across turns; attached note shows with pin icon;
× button excludes a note from future auto-search; hidden on mobile
- routes/chat.py: batch-fetch note titles via get_notes_by_ids() and inject
context_note_title into each message dict at conversation load time
- notes.py: add get_notes_by_ids() batch fetch helper
- types/chat.ts: add context_note_title field to Message interface
- stores/chat.ts: sendMessage accepts optional 5th arg contextNoteTitle,
included in optimistic user message
- ChatMessage.vue: context badge shows note title instead of 'Note #N'
Expanded LLM tool suite (all with intent router rules + ToolCallCard display):
- delete_note / delete_task: permanent delete with user confirmation (write tool),
type-safe (refuse to delete wrong type), clears note context cache on success
- get_note: fetch full note body by query (search_notes returns only 200-char preview)
- list_notes: browse notes by recency/keyword/tags with limit; notes only
- update_note: add tags + tag_mode (replace/add/remove) parameters
- search_notes: add optional type filter ("note" | "task")
- search_todos (CalDAV): keyword-filter todos, companion to list_todos
- caldav.py: add search_todos() built on top of list_todos()
- generation_task.py: register new tools in _WRITE_TOOLS, _TOOL_LABELS, _TOOL_ACTIONS
- llm.py: update available actions list and guidance in system prompt
- intent.py: routing rules for all new tools
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+24
-11
@@ -12,7 +12,7 @@
|
||||
> Include file-level details in the commit body when the change is non-trivial.
|
||||
|
||||
## Last Updated
|
||||
2026-02-18 — Phase 11: streaming status transparency UX + model load state indicator
|
||||
2026-02-19 — Phase 12: persistent context sidebar, note title in chat, expanded tool suite
|
||||
|
||||
## Project Overview
|
||||
Fabled Assistant is a self-hosted note-taking and task-tracking application with
|
||||
@@ -207,6 +207,7 @@ for AI-assisted features.
|
||||
- `context_note_id` tracks which note was attached as context when message was sent
|
||||
- `tool_calls` stores an array of tool call records `[{function, arguments, result, status}]` for assistant messages that used tools
|
||||
- `to_dict()` returns: `id`, `conversation_id`, `role`, `content`, `status`, `context_note_id`, `tool_calls`, `created_at`
|
||||
- `context_note_title` is NOT a DB column — it is synthesised at query time in `get_conversation_route` via a batch `get_notes_by_ids()` lookup and injected into the message dict so the frontend can display the note title without a separate fetch
|
||||
|
||||
## Project Structure (Current)
|
||||
```
|
||||
@@ -265,9 +266,9 @@ fabledassistant/
|
||||
│ │ ├── 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, intent routing + tool loop) + run_assist_generation (lightweight, no DB)
|
||||
│ │ ├── intent.py # Intent routing: classify_intent() makes fast non-streaming LLM call to detect tool intent before streaming
|
||||
│ │ ├── tools.py # LLM tool definitions (create_task, create_note, update_note, list_tasks, search_notes, full CalDAV suite incl. update_todo) + execute_tool dispatcher
|
||||
│ │ ├── tools.py # LLM tool definitions (create/delete note+task, update_note w/tag management, get_note, list_notes, search_notes w/type filter, list_tasks, full CalDAV suite incl. search_todos) + 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: full event lifecycle (create/list/search/update/delete), todos (create/list/complete/delete), list_calendars, timezone (ZoneInfo), reminders (VALARM), attendees, multi-calendar search
|
||||
│ │ ├── caldav.py # CalDAV integration: full event lifecycle (create/list/search/update/delete), todos (create/list/search/update/complete/delete), list_calendars, timezone (ZoneInfo), reminders (VALARM), attendees, multi-calendar search
|
||||
│ │ ├── 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,7 +321,7 @@ fabledassistant/
|
||||
│ │ ├── RegisterView.vue # Register form with password confirmation; shows "closed" message when registration disabled
|
||||
│ │ ├── RegisterInviteView.vue # Invitation-based registration: validates token, creates account with pre-set email
|
||||
│ │ ├── UserManagementView.vue # Admin user management: registration toggle, invitations (send/revoke), user list with delete
|
||||
│ │ ├── ChatView.vue # Dedicated /chat page: responsive sidebar (overlay on mobile), bubble messages, note picker, context pills, model selector in header
|
||||
│ │ ├── ChatView.vue # Dedicated /chat page: responsive sidebar (overlay on mobile), bubble messages, note picker, persistent context sidebar (right panel, hidden mobile), model selector in header
|
||||
│ │ ├── 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
|
||||
@@ -335,7 +336,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) + suggested tag pills with apply-on-click
|
||||
│ │ ├── ToolCallCard.vue # Compact card for tool call results (created/deleted task/note, note content, notes list, search results, CalDAV events/todos, 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
|
||||
@@ -542,7 +543,12 @@ When adding a new migration, follow these conventions:
|
||||
- Background generation with `GenerationBuffer` (in-memory SSE fan-out, `Last-Event-ID` reconnect, 60s cleanup)
|
||||
- Stop generation with partial content preservation
|
||||
- Note-aware context building: current note + keyword search for related notes + URL fetching
|
||||
- Context pills with promote/exclude controls; note picker (paperclip) in chat input
|
||||
- **Persistent context sidebar:** Right panel in ChatView accumulates auto-found notes across turns.
|
||||
Manually attached note appears with 📌 pin, clears after send. × excludes from future auto-search.
|
||||
Hidden on mobile (≤768px). Replaces old ephemeral context pills in the message stream.
|
||||
- Note picker (paperclip) in chat input; attached note title passed to store for optimistic render.
|
||||
`context_note_title` synthesised server-side at conversation load via batch `get_notes_by_ids()`;
|
||||
message badge shows note title instead of "Note #N".
|
||||
- LLM-generated conversation titles (re-generated every 10th message)
|
||||
- Save assistant messages as notes (LLM-titled, chat-tagged); summarize conversations
|
||||
- Dedicated `/chat` page with responsive sidebar + slide-out chat panel from header
|
||||
@@ -573,12 +579,17 @@ When adding a new migration, follow these conventions:
|
||||
Full tool suite:
|
||||
- `create_task` / `create_note` — create new items
|
||||
- `update_note` — edit note content (replace/append) AND update task fields: `status`, `priority`,
|
||||
`due_date`; finds by exact title first, falls back to fuzzy search; prevents duplicate notes
|
||||
`due_date`, `tags` (with `tag_mode`: replace/add/remove); finds by exact title first, falls back to fuzzy search
|
||||
- `delete_note` / `delete_task` — permanently delete (require user confirmation via confirm UI;
|
||||
validates type so delete_note won't delete a task and vice versa; clears note context cache)
|
||||
- `get_note` — retrieve full note body by title/keyword (search_notes only returns 200-char preview)
|
||||
- `list_notes` — browse notes by recency/keyword/tags with configurable limit; notes only (use list_tasks for tasks)
|
||||
- `list_tasks` — filter tasks by `status`, `priority`, `due_before`, `due_after`, `limit`;
|
||||
backed by `list_notes(is_task=True)`; enables "overdue tasks", "high priority", "in progress" queries
|
||||
- `search_notes` — keyword search across notes and tasks
|
||||
- `search_notes` — keyword search across notes and tasks; optional `type: "note"|"task"` filter
|
||||
- Full CalDAV suite: `create_event`, `list_events`, `search_events`, `update_event`, `delete_event`,
|
||||
`list_calendars`, `create_todo`, `list_todos`, `update_todo`, `complete_todo`, `delete_todo`
|
||||
`list_calendars`, `create_todo`, `list_todos`, `search_todos`, `update_todo`, `complete_todo`, `delete_todo`
|
||||
(`search_todos` keyword-filters the todo list — companion to `list_todos`)
|
||||
- **Streaming status transparency:** The backend emits `status` SSE events at each pipeline stage
|
||||
so the user always sees what's happening instead of a blank progress dot. Stages:
|
||||
(1) `"Analyzing your request..."` before intent classification; (2) human-readable tool label
|
||||
@@ -597,11 +608,13 @@ When adding a new migration, follow these conventions:
|
||||
Dedicated intent model configurable via `OLLAMA_INTENT_MODEL` env var or per-user `intent_model`
|
||||
setting — allows a smaller/faster model for routing while the main model handles responses.
|
||||
Intent router rules cover: update/delete events, CalDAV todos, time-period → list_events (not
|
||||
search_events), update_note vs create_note disambiguation, reminder_minutes conversion.
|
||||
search_events), update_note vs create_note disambiguation, reminder_minutes conversion,
|
||||
delete_note vs delete_task disambiguation, get_note for "read/show me this note", list_notes for
|
||||
"browse/list notes", tag management via update_note (tag_mode add/remove), search_todos.
|
||||
- **CalDAV calendar integration:** Per-user CalDAV settings (URL, username, password, calendar name, timezone).
|
||||
LLM tools: `create_event` (all_day, recurrence, timezone, reminder_minutes, attendees, calendar_name),
|
||||
`list_events`, `search_events`, `update_event`, `delete_event`, `list_calendars`,
|
||||
`create_todo`, `list_todos`, `complete_todo`, `delete_todo`.
|
||||
`create_todo`, `list_todos`, `search_todos`, `update_todo`, `complete_todo`, `delete_todo`.
|
||||
All-day events use iCalendar DATE values; recurrence uses RRULE (e.g. `FREQ=YEARLY`).
|
||||
VALARM components added for reminders. Attendees via mailto: vCalAddress.
|
||||
Multi-calendar search: when no specific calendar configured, all calendars are scanned.
|
||||
|
||||
Reference in New Issue
Block a user