| 2026-05-15 |
Add self-recall (scheduled callback) system
...
Core features:
- schedule_recall tool: once/recurring/immediate callbacks
- manage_recall tool: cancel/skip/list scheduled recalls
- Natural-language time parser (ISO, relative, "tomorrow at 09:00")
- PostgreSQL-backed RecallScheduler with lazy pool init
- Background recall_scheduler_loop with asyncio.Semaphore(3)
- _busy_sessions guard prevents user messages during headless runs
- Agent.run() preserves thinking field for session history visibility
- API endpoints: GET/DELETE/POST for session recall, admin list
- Frontend: recall badge, filter, cancel/skip in sidebar and chat header
- Tests: parser, scheduler CRUD, tools, API, scheduler loop (53 tests)
- Manuals: schedule_recall.md and manage_recall.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
| 2026-05-14 |
Final search UX polish: focus, cache, spinner opacity, scroller key
...
- AppSidebar: auto-focus input when search opens via querySelector.
Spinner icon now hides via opacity:0 instead of visibility:hidden.
- SessionsStore: add searchCache ref + restoreSearch(). Cache stores last
search results (items, hasMore, nextOffset) so reopening search avoids
re-fetching when query hasn't changed.
- SessionList: add :key on DynamicScroller to force recreate when switching
between search/normal mode, fixes pinned item spacing bug.
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search spinner placement, msg-flash disappearance, results cleanup
...
- AppSidebar: spinner moved inside GnSearchField input-group-addon via CSS
(:deep .input-group-addon overlay). Removed spinner from sessions-label.
- AppSidebar: closeSearch and handleSelect now call sessionsStore.exitSearch()
and reload normal session list, so search results disappear after selection.
toggleSearch restores previous query and re-activates search on reopen.
- CSS msg-flash: removed animation-fill-mode:both and background-color:transparent
from keyframes, so message bubble keeps its original background after flash.
- SessionsStore: added exitSearch() method (preserves query, disables active flag).
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Add session search across messages with backend + frontend
...
Backend:
- GET /sessions now accepts `search` query param
- _session_summary computes match_indices and match_preview from messages
- pg_session_store: messages ILIKE added to search_list and count_all
- In-memory store: search_list also filters by message content
Frontend:
- AppSidebar: search toggle icon + debounced input, Ctrl+K shortcut
- SessionItem: highlight matching text, show match_preview from search
- SessionList: pass searchQuery to SessionItem
- SessionsStore: searchQuery/searchActive state, setSearch/clearSearch
- API layer: getSessions accepts search param
- MessageList: scroll to target message + brightness flash animation
- ChatStore: loadSession accepts targetMessageIndex, scrollToMessageIndex ref
- CSS: msg-flash keyframe animation in app.scss
- Tests updated for new getSessions signature
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
| 2026-05-02 |
Paginate session list loading
Eugene Sukhodolskiy
committed
on 2 May
|
| 2026-04-16 |

Add session name generation via LLM
...
Backend:
- Session model gets name: str | None field
- SQLite migration: ADD COLUMN name TEXT
- PostgreSQL: ADD COLUMN IF NOT EXISTS name TEXT (applied on pool init)
- SessionStore: add set_name() abstract method, implemented in all stores
- navi/core/name_generator.py: LLM worker that reads user messages and
returns a 3–6 word title or None if content isn't substantial yet
- POST /sessions/{id}/generate-name endpoint: fires LLM, saves and
returns name; skips if session already named or has no user messages
- GET /sessions and GET /sessions/{id} now include name field
Client:
- api.generateSessionName(id) — calls the new endpoint
- sessions store: updateName(id, name) mutation
- chat store: after stream_end, _tryGenerateName() runs fire-and-forget;
skips silently if session already has a name or if request fails
- SessionItem already displays session.name (falls back to id prefix)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Migrate to Vue webclient; rename old client to old_webclient
...
- client/ → old_webclient/ (vanilla JS client preserved as reference)
- webclient/ — new Vue 3 + Pinia webclient (source + dist build)
- vite.config.js: outDir changed to webclient/dist/
- main.py: serve /assets and /images from webclient/dist/,
index.html from webclient/dist/index.html
- .gitignore: exclude webclient/node_modules/, include webclient/dist/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|