| 2026-04-09 |

Client UX: profile-filtered sessions, draft persistence, stream safety
...
- Profile selector now filters session list: only sessions of the selected
profile are shown; switching profile opens the most recent session for
that profile (or empty state if none exist)
- openSession() syncs profileSelect to the opened session's profile so
the list always reflects what's on screen
- Session items no longer show redundant profile name (list is filtered)
- Bug fix: switching sessions while streaming now calls abandonStream()
before ws.disconnect() — resets state without touching DOM, preventing
WS onClose from calling finishStream() on the wrong session
- Textarea no longer disabled during streaming — only the Send button is
locked; user can type the next message while model is still responding
- Draft auto-saved to localStorage per session on every keystroke, restored
on session switch, cleared on send — survives page refresh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 9 Apr
|
| 2026-04-08 |
Add context token counter: 64k default, live UI display
...
- config: ollama_num_ctx default 8192 → 65536
- LLMChunk: add prompt_tokens / completion_tokens fields
- OllamaBackend.stream: populate token counts from final chunk
(prompt_eval_count + eval_count when chunk.done)
- StreamEnd: add context_tokens and max_context_tokens
- Agent.run_stream: capture token counts, pass to StreamEnd
- websocket: include context_tokens / max_context_tokens in stream_end
- index.html: split chat-header into title span + token-counter span
- sidebar.js: updateChatHeader targets #chat-header-title, not innerHTML
- app.js: updateTokenCounter() shows "X/Y (Z%) tokens", colors:
gray <50%, amber 50–79%, red ≥80%
- style.css: .token-counter, .warn, .danger styles
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Client review fixes: bug fix, dead code, deduplication, CSS vars
...
- renderPreviewStrip: fix index-capture bug (splice by value, not index)
- api.js: remove dead sendMessage (messaging goes via WebSocket only)
- utils.js: extract shared esc() and timeLabel() from chat.js + sidebar.js
- enrichSession: remove unnecessary async/Promise.all wrapper
- style.css: thinking-card colors moved to CSS variables in :root
- WsClient: remove unused #sessionId field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Pin sessions + larger code font
...
Server:
- Session.pinned field (bool, default False)
- SqliteSessionStore: ALTER TABLE migration for existing DBs, set_pinned(),
ORDER BY pinned DESC, last_active DESC
- PATCH /sessions/{id}/pin endpoint
Client:
- Pin/unpin button appears on hover (📌/📍)
- Pinned sessions get blue left border and always-visible pin icon
- Local sort mirrors server sort (pinned first)
- Code blocks font-size bumped from 0.82em to 0.9em
Eugene Sukhodolskiy
committed
on 8 Apr
|
Persistent sessions and client module refactor
...
Server:
- SqliteSessionStore replaces InMemorySessionStore as default backend
- Sessions survive server restarts (stored in navi.db)
- DB_PATH configurable via .env
Client:
- Split monolithic app.js into ES modules:
js/api.js — REST calls
js/ws.js — WebSocket wrapper (WsClient class)
js/chat.js — message area DOM helpers
js/sidebar.js — session list and header helpers
js/app.js — state, wiring, boot
- Active session persisted in localStorage — restored on page reload
Eugene Sukhodolskiy
committed
on 8 Apr
|