| 2026-10-05 |
webclient: virtualized message list (DynamicScroller)
...
- MessageList rewritten on vue-virtual-scroller DynamicScroller; only rows
near the viewport mount (session switch 650-730ms longtask / DOM 31645 ->
110-165ms / DOM 1-2.5k, zero freezes)
- scroller is keyed by session id: message ids repeat across sessions, so
teardown drops the measured-size cache on switch
- convergeToBottom watches the bottom hold for a bounded window after
landing (lazy row measurements nudge scrollHeight late); yields to wheel/
pointer/touch input instead of scroll-position heuristics, which the
scroller's own adjustments would trip
- renderMarkdown gets a byte-capped LRU memo so markdown remount cost is
amortized while virtualized rows recycle
- removed dead .message-list/.message-list-inner styles
Eugene Sukhodolskiy
committed
6 hours ago
|
webclient: session-list polish from review pass
...
- documentTitle: persistent nameById map — names for sessions beyond the
loaded list page (list only holds ~30); map filled by fetches and
loadSession meta, never wiped by later refetches
- createSession: placeholder inserted at the position the server list
would give it (after pinned run, last_active desc) so refetch no
longer visibly moves the new row
- SessionItem: skip empty .session-icons wrapper when no icons
- drawer breakpoint made exclusive (-sidebar-drawer 1280 -> 1279.98):
viewport of exactly 1280px now gets the desktop sidebar
Eugene Sukhodolskiy
committed
7 hours ago
|
webclient: loading indicators where the UI looked frozen
...
- session open: centered spinner in MessageList while chat.loading
- image paste/drop: imagesProcessing counter (chat store, shared);
FilePreviewStrip shows spinner placeholder tiles where the resized
previews will land
- file upload: indeterminate sliding bar instead of the fake static 60%
- send → run start gap: "Sending…" hint with spinner, cleared on
stream_start / message_queued / stream end / error / session switch
- content-card images: skeleton with spinner until @load (reset on src
change); wrapper keeps min-height while the img is empty
vitest 96 passed.
Eugene Sukhodolskiy
committed
8 hours ago
|
| 2026-09-26 |
e2e fixes: tasks tool in profiles, bg timeout lift, stepIcon fix, queue semantics docs
...
E2E findings addressed:
- tasks tool was registered but not in any profile's tools.agent.native —
added to all six profiles (agent could not check/wait/cancel bg tasks)
- detached terminal/code_exec/ssh_exec runs without explicit timeout are
lifted to 300s: foreground defaults (20/30/60s) marked long commands
'completed' with partial output while the process still ran
- ToolCard.vue: define stepIcon(status) — template referenced it but the
function was missing (render crash on task_update step)
- message_queued reachability documented: WS read loop is sequential, the
queue path is only reachable from a second socket/headless recall
Eugene Sukhodolskiy
committed
9 days ago
|
webclient: background task chip, id-first tool matching, queued badge
...
- toolIndex (tool_call_id → card): exact matching for parallel batches and
late events after stream_end; legacy name+pending fallback kept
- bare tool_call synthesizes a card so results are never lost
- task_update: backgroundTasks chip above composer + steps appended to the
spawning tool card (parent_tool_call_id binding)
- message_queued badge, terminal_opened dispatch
- new BackgroundTasksChip component, task_update step rendering in ToolCard
Eugene Sukhodolskiy
committed
9 days ago
|
webclient: code blocks span full message width in flex markdown container
Eugene Sukhodolskiy
committed
9 days ago
|
| 2026-07-13 |
renderers: colour diff line numbers + read line numbers, keep content neutral
...
Standard for diff and read output: the line number (and the +/- marker for
diffs) is the coloured anchor; the content itself reads plainly.
diff: "{num} {marker} {content}" with num+marker in the marker colour
(green/red), content neutral. Fixed the number-column regex to "^( +)(\d+)|"
so files with more than 9 lines (width > 1) still match — the old
single-space pattern silently fell back to whole-line colouring.
read: "{num}: {content}" with the number in the accent colour, content
neutral (was dim number).
Applied to both clients: the TUI diff/filesystem renderers and the webclient
ToolCard (renderDiff / renderRead). The model-facing text from the server is
unchanged — this is display-only.
Eugene Sukhodolskiy
committed
on 13 Jul
|
| 2026-05-15 |

fix(recall): stabilize scheduled callback system and improve UX
...
Backend fixes:
- stop_session now stops headless recall runs via _busy_sessions dict
- _fire_recall sets user ContextVars so tools work correctly
- MaxIterationsReached treated as success, not failure
- skip_next_recall uses GREATEST(trigger_at, now) for overdue recalls
- schedule_recall rejects past trigger times
- timezone offset double-adjustment fixed for aware datetimes
- _fire_recall registers _AgentRun for reconnect/replay support
- session_sync race with stream_start fixed
Frontend improvements:
- Recall banner moved to ChatHeader with live Cancel/Skip buttons
- Recall messages styled with is_recall flag and badge
- Real-time recall updates via WebSocket (recall_update events)
- Recall filter moved to sessions-header as toggle button
- Session list shows clock icon for sessions with pending recall
- Empty state messages for empty/filtered session lists
- Fixed missing api import in ChatHeader.vue
Tests:
- Updated scheduler_loop tests for _busy_sessions dict change
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
| 2026-05-14 |
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
|
Polish session search UX: GnSearchField, spinner, flash timing
...
- AppSidebar: use GnSearchField from gnexus-ui-kit, spinner during search,
search toggle button always visible in sessions-header, hide search on select
- MessageList: fix msg-flash timing — make content visible before scrolling,
extend flash duration to 2.5s with background + brightness
- CSS: enhance msg-flash keyframe animation
- 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
|
Compact and improve tool/thinking/plan card UX
...
- ToolCard: remove emoji header, collapse Arguments behind <details>,
render results with structured JSON (color-coded values) or markdown
detection for string outputs.
- SubagentStep: mirror ToolCard compact layout with same helpers.
- AssistantMessage: fold tool lists when >3 tools — show last 3 + summary
bar with count and toggle icon-button; TransitionGroup for smooth
expand/collapse animations.
- Plan card: switch accent color from info to secondary, compact sizing.
- Thinking card: compact sizing, remove bottom margin.
- app.scss: add details::details-content animation, fix nested chevron
rotation in subagent steps, adjust margins and input-bar padding.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Markdown images: adaptive 3-column grid, lightbox modal, and broken-image handling
...
- useMarkdown.js: custom marked renderer wraps images in clickable links with
inline onerror for broken-image detection
- app.scss: .msg-assistant-content becomes flex-wrap container; image paragraphs
sized to 3-per-row via calc((100% - 16px) / 3); images are square via
aspect-ratio: 1 / 1 and object-fit: cover
- ImageLightbox.vue: rewritten with proper gnexus-ui-kit .modal/.modal-dialog
DOM structure; broken images show error placeholder inside modal
- AssistantMessage.vue: attachImageLightbox() wired after v-html render
- Broken images: .is-broken class prevents lightbox click; CSS shows 🖼️ icon
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
| 2026-05-13 |
Persist uploaded files in messages, live file tree updates, and UI polish
...
Backend:
- Add `files` field to `Message` model so uploaded file metadata survives page refresh
- Pass `files` through websocket handler → `agent.run_stream` / `agent.run`
- `list_tools`: make `profile_id` required; return error instead of all-tools fallback
Webclient:
- Call `fetchFiles()` after successful file upload for immediate Files tab update
- Live refresh file tree on filesystem (write/edit/append/mkdir/rm/cp/mv), terminal, and code_exec tool calls
- Add manual refresh button (desktop) and pull-to-refresh (mobile) to Files tab
- Fix live link updates: move regex creation inside per-message loop to avoid lastIndex state leak
- Restore full profile name text next to avatar in ChatHeader; hide avatar in header
- Fix mobile ArtifactsPanel: collapse tab text labels so close button fits with 3 tabs
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 13 May
|
| 2026-05-11 |
Add deterministic line-based file editing (edit_lines), rating UI fix, and session refresh
...
- filesystem.py: add edit_lines action (deterministic line ops via operations array)
+ numbered param for read (1-based line numbers in output)
+ clarify four editing modes in tool description
- chat.js: fix rating IDs for streaming messages (assign h_ ID on stream_end)
- SessionList.vue: mobile pull-to-refresh with PTR_THRESHOLD=80
- AppSidebar.vue: desktop refresh button next to Conversations header
- planning.py: knowledge source assessment in Phase 1
- debug panel: MCP servers tab + resolved tools per profile
- NAVI.md: reposition as neutral quick-reference
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 11 May
|
| 2026-04-30 |
Improve artifacts workspace controls
Eugene Sukhodolskiy
committed
on 30 Apr
|
Restore original scrollbar appearance
Eugene Sukhodolskiy
committed
on 30 Apr
|
Normalize scrollbar styling
Eugene Sukhodolskiy
committed
on 30 Apr
|
Improve content publishing UX
Eugene Sukhodolskiy
committed
on 30 Apr
|
| 2026-04-24 |
Add discuss profile; responsive WelcomeScreen for 6+ profiles
...
- New 'discuss' profile: creative Q&A and idea discussion, temp=1.0,
planning phase 3 only, tools: web_search/view, scratchpad, reflect,
memory, image_view, todo
- WelcomeScreen mobile: 2-column grid for profile cards, compact logo
(row layout with subtitle on second line), reduced padding/gaps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 Apr
|
Reduce WelcomeScreen padding to 15px on mobile
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 Apr
|
WelcomeScreen polish, root-path fix, docs update
...
- Move mobile sidebar button to top-left corner (no header bar backdrop)
- Show WelcomeScreen on / with no hash instead of auto-loading first session
- Docs: document Ollama multi-server fallback, model priority lists, OLLAMA_BACKENDS_FILE
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 Apr
|
| 2026-04-20 |

Autonomous reasoning improvements: budget, anchoring, anti-stall, validation
...
- AgentProfile: per-profile thinking mechanics flags (think_enabled,
iteration_budget_enabled, goal_anchoring, anti_stall, step_validation,
planning_reflect, adaptive_replan) — all profiles updated in config.json
- Iteration budget: inject remaining iterations into context so model knows
when to wrap up; urgency levels at ≤7 and ≤3 remaining
- Goal anchoring: inject original goal + todo state every N iterations to
prevent drift on long tasks
- Anti-stall: two signals — no todo progress for N iterations, or identical
tool calls repeated N times; warning injected into context
- Todo step validation: marking done requires a validation field describing
how result was verified; failed gets a soft nudge with tip for re-planning
- stream_complete: add think param to base class, ollama and openai backends
- Summarizer: raise max_tokens 1024→3000, expand system prompt with
user-preferences section and verbatim-value instructions
- Compression card: persist to session.messages (is_compression flag on
Message), show expandable summary in webclient with markdown body
- ToolResult.to_message_content: always include output on failure so
tracebacks and error details reach the model (fixes silent Error: None)
- Developer profile: fix subagent profile secretary→developer, add write_tool
to subagent_tools, clarify write_tool vs filesystem in system prompt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 20 Apr
|
| 2026-04-17 |

Route subagent planning events into spawn_agent card in the UI
...
Previously PlanningStatus/PlanReady had no is_subagent flag, so subagent
planning spinners and plan cards rendered as top-level Navi planning UI.
Backend:
- Add is_subagent field to PlanningStatus and PlanReady events
- _run_planning accepts is_subagent param, passes it through all yields
- run_ephemeral calls _run_planning with is_subagent=True
- websocket.py forwards is_subagent in planning_status and plan_ready messages
Frontend (chat.js):
- onPlanningStatus: if is_subagent, set planningLabel on the last spawn_agent
card instead of msg.statusLabel
- onPlanReady: if is_subagent, push plan into spawn card steps and clear
planningLabel; otherwise behave as before
Frontend (ToolCard.vue):
- Render subagent-planning-indicator (spinner + label) when planningLabel set
- Render plan cards inside subagent steps using the same plan-card pattern
Also includes leftover session changes: spawn_agent default 40 in description
and manual, updated manual content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
Webclient UI improvements + backend fixes
...
Webclient:
- Draft persistence across page refreshes (localStorage, reactive watch)
- Image lightbox modal using UI kit classes on thumbnail click
- Copy button on user and assistant messages
- Selection reply toolbar: select assistant text → quote inserted into input
- User message rendering: proper HTML escaping, styled blockquote for > replies
- Markdown table fix: preprocessor to inject missing separator rows
- Planning status labels (rebuild dist)
Backend:
- Developer profile: enable subagent delegation, increase max_iterations to 35
- share_file: updated description + manual with absolute path requirement and URL sharing
- persona.txt: instructions for quote replies and GFM table format
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 17 Apr
|
| 2026-04-16 |
Fix metrics: net token delta, subagent aggregation, ContextBar always visible
...
- run_stream: track _prev_tokens baseline before turn loop; compute net
token cost as (context_tokens - prev) + subagent_tokens for per-message cost
- run_stream: intercept SubagentComplete in sink drain loop to accumulate
subagent token and tool-call counts into the parent turn's totals
- run_ephemeral: already emitting SubagentComplete (from prior session)
- msg-meta-row: remove margin-left:auto from .msg-meta-time so time
groups inline with elapsed/tools/tokens instead of floating right
- ContextBar: remove v-if guard so bar is always visible (not only after
first LLM response with token data)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
Add response metrics: elapsed time, tool calls, token count
...
Server:
- Message model: elapsed_seconds, tool_call_count, token_count fields
(display-only, excluded from LLM context via exclude_none)
- StreamEnd event: carries same three fields
- agent.run_stream: tracks turn start time, counts ToolEvent completions,
writes metrics onto the final assistant Message before saving to DB
- WebSocket: forwards metrics in stream_end payload
Client:
- chat.onStreamEnd: attaches elapsed_seconds, tool_call_count, token_count
to the streaming message on completion
- buildMessageList: scans each assistant group for metrics from history
- AssistantMessage: renders .msg-meta-row below the response —
timer icon + Xs · wrench icon + N tools · coins icon + Nk tokens · time
(each item only shown if present; time pushed right via margin-left: auto)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
webclient: UI density improvements for session names and header
...
Sidebar:
- session-name: 12px → 13px (more prominent with real names)
- session-preview: 13px → 12px, clamp 2 → 3 lines (more content visible)
- session-actions buttons: 26×26px, gap 2px (narrower, more room for info)
Chat header (mobile):
- chat-header-info: column layout on mobile so title and profile badge
stack vertically (flex-direction: column; align-items: flex-start)
ContextBar:
- Recomposed to single row: [track] [pct%]
- Track 100px → 60px, height 5px → 4px
- Full token counts moved to title attribute (hover tooltip)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
webclient: remove 'Planning' label from wait indicator; add scroll-to-bottom button
...
- Waiting indicator now shows only a spinner (text was misleading — model
doesn't always plan before responding)
- Add floating scroll-to-bottom button that appears when scrolled >200px
from bottom, disappears when near bottom; smooth fade+slide transition;
positioned bottom-right (under thumb on mobile)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|
webclient: reduce message-list horizontal padding to 10px on mobile
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 Apr
|