| 2026-05-24 |
Fix link deduplication in ArtifactsPanel — three root causes
...
1. normalizeUrlForDedup returned only pathname, so https://a.com/foo
and https://b.com/foo shared key /foo. Now uses host+pathname
(with www stripped).
2. Trailing punctuation was stripped for display but not before dedup,
so https://example.com/path. and https://example.com/path got
different keys /path. vs /path. Now stripTrailingPunctuation() runs
before normalizeUrlForDedup().
3. Fragile before==='(' skip logic for markdown hrefs replaced with
precise protectedRanges tracking — bare URLs whose match falls inside
a recorded markdown href range are skipped regardless of spacing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
Add MCP health check loop, auto-reconnect, and system toast notifications
...
Backend:
- McpManager: keep all configured servers in the pool even if connect()
fails at startup; health-check loop (30s) tries to reconnect dead servers
and verifies live ones with list_tools()
- McpManager: set_on_server_connected callback re-registers tools when a
dead server comes back online
- McpClient: add mark_disconnected() for silent drop detection
- McpStatusTool: skip list_tools() for disconnected servers
- Orchestrator: broadcast mcp_status_update to all WebSocket sessions
- New event type McpStatusUpdate with server_name, status, tool_count
Webclient:
- useWebSocket: handle mcp_status_update → toast.success/toast.error
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
Remove redundant success toast on token creation — modal is enough
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
Fix ApiKeysPanel by removing GnTable wrapper — required columns/rows props were missing
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
Show copied checkmark on token copy button for 1.5s
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
Fix settings route switching and document API token system
...
- App.vue: make route reactive via ref + getRouteFromHash() so
#settings toggles work without page reload
- docs/api_tokens.md: new comprehensive API token auth doc
- docs/api.md: add /api-tokens REST endpoints
- docs/auth.md: add token flow architecture diagram and resolution order
- docs/websocket.md: add auth section with cookie vs query-param token
- docs/architecture.md: update to AgentSessionOrchestrator + ToolContext
- docs/tools.md: add gnexus-creds MCP tools
- docs/index.md: link to api_tokens.md
- Rebuild webclient dist
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
Apply review fixes to API token auth system
...
Backend:
- navi/auth/deps.py: replace 3 DB round-trips with single JOIN query for
token resolution; update last_used_at still separate (best-effort)
- navi/api/routes/api_tokens.py: replace asyncpg-specific "UPDATE 1"
string check with RETURNING id fetchrow; increase token_prefix from
8 to 12 chars for better visual identification; add security notes
- tests/unit/auth/test_api_tokens.py: update tests for JOIN query and
RETURNING-based revoke
Frontend:
- webclient/src/components/settings/ShowTokenModal.vue: new modal that
shows the plain token in a readonly field with copy button and
explicit warning — replaces the transient toast notification
- webclient/src/components/settings/ApiKeysPanel.vue: use ShowTokenModal
- webclient/src/composables/useWebSocket.js: add security comment about
localStorage XSS risk and query param log exposure
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|

Add API token auth system for headless/micro clients
...
Backend:
- navi/auth/_ddl.py: add api_tokens table with boot-time migration
- navi/auth/deps.py: _resolve_user now falls back to X-Api-Token header
and ?api_token query param for WebSocket auth
- navi/auth/__init__.py: add ApiToken pydantic model
- navi/api/routes/api_tokens.py: CRUD endpoints (POST/GET/DELETE)
- navi/main.py: wire api_tokens router
Frontend:
- webclient/src/App.vue: add #settings hash routing
- webclient/src/components/settings/: SettingsView, ApiKeysPanel,
CreateKeyModal with copy-to-clipboard flow
- webclient/src/api/index.js: token CRUD API functions
- webclient/src/stores/apiTokens.js: Pinia store
- webclient/src/components/sidebar/AppSidebar.vue: settings link
- webclient/src/composables/useWebSocket.js: append ?api_token= when
localStorage token is present
Tests:
- tests/unit/auth/test_api_tokens.py: 10 unit tests covering token
resolution (header + query param), revoke, missing/revoked tokens,
orphan users, and CRUD endpoints
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 24 May
|
| 2026-05-22 |
Fix link deduplication in ArtifactsPanel
...
Normalize URLs by pathname (lowercased, no query/hash, no trailing
slash) so the same file reached via different query params or
absolute/relative forms is counted once.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 22 May
|
| 2026-05-21 |
ArtifactsPanel: two-pass link extraction — markdown links win over bare URLs
...
Markdown links carry a title/caption, so they should always take priority
over bare URLs during deduplication. Previously a bare URL from a newer
message could shadow an older markdown link. Now markdown links are
scanned in a separate first pass, so they always win the dedup race.
Eugene Sukhodolskiy
committed
on 21 May
|
ArtifactsPanel: strip trailing punctuation from URLs for dedup
...
Bare URLs sometimes pick up a trailing ) or . from surrounding markdown
(e.g. model writes a link inside parentheses). The normalizeUrlForDedup()
helper strips trailing punctuation before checking the seen Set so
https://a/b and https://a/b) are treated as the same link.
Eugene Sukhodolskiy
committed
on 21 May
|
| 2026-05-16 |
Add legacy redirect for session files and fix STL viewer error handling
...
- Add /sessions/{id}/files/{filename} → /api/sessions/{id}/files/{filename}
redirect in main.py for backward compatibility with old persisted URLs
- Fix STL viewer: wrap all renderer-dependent code in `if (renderer)`
to prevent cascading errors when WebGL is unavailable
- Rebuild dist
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 May
|
Fix SyntaxError: Illegal return statement in STL viewer
...
The previous fix replaced `throw err` with `return` inside a module,
but top-level `return` is a SyntaxError in ES modules.
Reverted to `throw err` — the error message is already shown on screen,
so the user still gets a graceful fallback even though the error appears
in the console.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 May
|
Fix session file URLs (add /api prefix) and WebGL error handling in STL viewer
...
Backend:
- _file_url in content_store.py now returns /api/sessions/... instead of /sessions/...
- share_file.py URL construction updated to include /api
- content_publish.py docstring updated to reflect correct endpoint
Frontend:
- contentLinks.js: avoid double /api prefix in dev mode when backend already returns it
- stl.html: replace throw err with return after showing WebGL fallback message
- Rebuild dist
Tests:
- Update expected URLs in test_content_store.py and test_share_file.py
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 May
|
Extract ContextCompressor, fix STL viewer, expand test suite, add architecture audit docs
...
- Extract ContextCompressor from agent.py (Step 1 of god-object refactor)
- Add retry + hard-truncate fallback logic to ContextCompressor
- Add unit tests: agent loop (14), compressor (18), KV store (8),
auth encrypt (3), auth deps (13), todo/scratchpad/image_view/memory
- Fix WebGL STL viewer: allow-same-origin sandbox + graceful fallback
- Add CompressionStarted event and client-side compression notice
- Add docs/architecture_weak_spots.md and plan_01_god_object_agent.md
- Update test_events.py and test_agent_context_size.py for new logic
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 16 May
|
| 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
|
fix(webclient): add missing updatePreview and updateName in sessions store
...
updatePreview and updateName were referenced in the store's return object
but never defined, causing ReferenceError at runtime after build.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
Refactor: move tool helper modules into _internal subpackage
...
Moves non-tool infrastructure out of navi/tools/ root so that only
actual tool classes live there:
base.py → _internal/base.py
loader.py → _internal/loader.py
middleware.py → _internal/middleware.py
logging_middleware.py → _internal/logging_middleware.py
_time_parser.py → _internal/time_parser.py
All imports updated across core/, api/, mcp/, tools/, and tests/.
No proxy files remain in navi/tools/ root.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 15 May
|
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 |
Rebuild dist for spinner overlay fix
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search spinner overlay on magnifying-glass icon
...
- Replace opacity-based hiding with display:none on .input-group-addon > i.
Move spinner pseudo-element to nested &::after inside .input-group-addon
with display:block + margin:auto for reliable centering.
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for search bug fixes
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search spinner overlay, scroller reset, highlight leak
...
- AppSidebar: use i.ph selector + !important for spinner overlay on
input-group-addon icon. Add transition for smooth fade.
- SessionList: simplify DynamicScroller :key to 'search'/'all' only,
removing sessions.length to prevent scroll reset on fetchMore.
- SessionList: pass empty searchQuery when searchActive is false,
preventing stale highlights in normal session list.
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for final search UX polish
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
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
|
Rebuild dist for search UX fixes
...
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
|
Rebuild dist for search flash and highlight fixes
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Fix search flash for assistant messages, move spinner, hide highlights
...
- MessageList: pass isFlashing prop to UserMessage/AssistantMessage instead
of applying msg-flash on wrapper div. scrollToMessage now uses rawIndices
to map backend match_index to grouped message index.
- UserMessage: add isFlashing prop, apply msg-flash to msg-user-bubble
- AssistantMessage: add isFlashing prop, apply msg-flash to msg-assistant-content
- ChatStore: add rawIndices to built messages (user, summary, assistant)
- AppSidebar: move spinner into sessions-label, remove from search field
- SessionList: accept searchOpen prop, pass empty searchQuery when closed
so highlights disappear after selecting a session
- Tests pass (51/51)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|
Rebuild dist for search UX polish
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 14 May
|