| 2026-04-08 |
Switch all profiles to gemma4:e4b-it-q8_0
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|

Separate display history from LLM context; formalize worker system
...
Architecture change:
- session.messages: full display history, never modified by compression
- session.context: what the LLM sees, may be compressed by workers
- System messages go only into context (not display history)
- Image injections (synthetic) go only into context
- User/assistant/tool messages go into both
SQLite: add context column with backward-compat migration
(empty context → initialized from messages on load)
Workers (navi/workers/):
- Worker ABC + WorkerContext + WorkerResult (base.py)
- CompressionWorker: compresses session.context when above threshold
- build_default_workers() returns [CompressionWorker()]
- Agent accepts workers list, runs them after StreamEnd
- Workers injected via deps.py get_workers() (lru_cached singleton)
- WebSocket agent construction also receives workers
Compressor: compress_context() now takes context[], not messages[]
Config: context_keep_recent 6 → 10
Agent: _run_workers() collects events from all workers and yields them
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|

Add context compression: rolling summarization when context fills up
...
Mechanism:
- After streaming ends, if context_tokens >= threshold (80% of num_ctx),
compress old turns into a summary message using the same LLM
- Partition: keep system msg + last N turns verbatim (default 6);
everything older goes to the summarizer
- Tool call groups (assistant + tool results) never split across boundary
- Existing summary messages folded into new compression pass — no stack growth
- Summary stored as Message(role=user, is_summary=True) after system msg
- On failure: logged, session left unchanged (non-fatal)
New files:
- navi/core/compressor.py: should_compress, partition_messages,
compress_session (pure logic, testable without agent)
New config (navi/config.py):
- context_compression_enabled: bool = True
- context_compression_threshold: float = 0.80
- context_keep_recent: int = 6
- context_summary_temperature: float = 0.3
New agent event: ContextCompressed(messages_before, messages_after)
Message.is_summary: bool field marks compressed history blocks
Client:
- context_compressed WS event → subtle inline notice in message list
- loadHistory: is_summary messages rendered as collapsible summary cards
- style.css: .summary-card, .compression-notice
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Token counter: hide on session switch, hide when no data
...
Reset counter to hidden on openSession() — prevents stale token
data from previous session showing when switching. Also hide when
stream_end arrives without token info.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
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
|
Server review fixes: profile model routing, sorting, datetime, cleanup
...
- LLMBackend.complete/stream: add model param; OllamaBackend uses it
over self.model, enabling per-profile model selection
- BackendRegistry.get(): remove unused model param
- Agent: pass profile.model to complete() and stream()
- Profiles: correct model to gemma4:e2b-it-q8_0 (was leftover e4b)
- InMemorySessionStore.list_all(): fix sort (pinned+newest first,
was pinned+oldest) — now consistent with SQLite ORDER BY
- session.py, sqlite_session_store.py: datetime.utcnow() →
datetime.now(timezone.utc) (deprecated since Python 3.12)
- _base_options(): accept temperature param, remove dead default
- deps.py: rename _registries → get_registries (public API)
- websocket.py: update import accordingly
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
|
Update .gitignore: ignore tmp files and tool data files
...
Add .tmp, task_manager.json, tools/*_data.json (runtime data written
by user tools like user_notes). Remove brain_kb.py (broken syntax).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Add project docs, tool manuals, and initial user tools
...
- CLAUDE.md: comprehensive project reference for Claude Code sessions
- manuals/write_tool.md: full format reference with working example
- tools/_template.py: canonical module-level tool format
- tools/enabled.json: auto-include list (get_current_datetime, user_notes)
- get_current_datetime, user_notes: first Navi-written tools
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Add thinking blocks UI: collapsible reasoning display
...
Thinking card appears on first thinking_delta, auto-collapses on
thinking_end. Re-openable like tool cards. Blue color scheme to
distinguish from regular tool results.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Wire self-extension tools into all profiles; improve tool descriptions
...
All profiles now include write_tool, list_tools, tool_manual, reload_tools.
User tools from enabled.json merged in at runtime via Agent._tool_list().
Built-in tool descriptions rewritten to be more LLM-actionable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Add self-extension tool system: write_tool, list_tools, tool_manual
...
- loader.py: module-level format (name/description/parameters/execute)
preferred, class-based as fallback; isolated errors per file
- write_tool: validates + writes tools/name.py, reloads registry,
adds to tools/enabled.json in one call
- list_tools: live tool list from registry (prevents hallucination)
- tool_manual: serves manuals/*.md or auto-generates from schema
- reload_tools: hot-reload without server restart
- registry: registry injection pattern for tools that need it;
_builtin_names set to guard against reload overwriting builtins
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|
Add thinking/reasoning streaming support
...
Enable Ollama think param and stream reasoning chunks to client.
New agent events: ThinkingDelta, ThinkingEnd. Config gains ollama_think
and ollama_num_ctx settings. WebSocket protocol updated accordingly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 8 Apr
|

Add multimodal image support and client UX improvements
...
Server:
- Add ImageViewTool (load image from file/URL, returns base64)
- Add images field to Message model with created_at timestamp
- Agent run/run_stream accept images param; inject image messages after image_view tool calls
- WebSocket handler accepts images array from client, strips data URI prefix
- All profiles include image_view tool
- Fix tool call serialization (model_dump mode=json for datetime)
- Add no-store cache headers for static files
Client:
- Image attachment: file picker button + clipboard paste + preview strip with remove
- Images rendered in chat bubbles; loaded from history
- Tool cards rebuilt as div+CSS toggle (fixes details/overflow-hidden collapse bug)
- Tool cards appear before response bubble (lazy bubble creation on first stream_delta)
- Typing indicator persists through tool calls, removed only when text starts streaming
- Tool cards restored from history on page reload
- Message timestamps stored via created_at field, shown correctly in history
- Session ID reflected in URL hash for bookmarking; restored on page load
- Remove localStorage session tracking (server last_active used instead)
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
|
Markdown rendering, syntax highlighting, tool card accordion
...
- marked.js (v12) renders assistant messages as markdown
- highlight.js (v11) highlights code blocks with atom-one-dark theme
- During streaming: raw text; on stream_end: rendered to markdown
- Tool cards redesigned as <details> accordions:
- Shows tool name, icon, success/fail indicator
- Click to expand: arguments grid + scrollable result pre
- Slide-in animation on open
Eugene Sukhodolskiy
committed
on 8 Apr
|
sessions list: include preview from last message
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
|
ssh_exec: accept credentials directly as tool parameters
...
host, username, password, port, key_path are now first-class parameters.
No config file needed — user can pass creds in the chat message.
Ad-hoc connections skip host key verification by default.
Named connections in ssh_hosts.json still work as a shortcut.
Eugene Sukhodolskiy
committed
on 8 Apr
|
Fix SSH password auth: disable key lookup when password is configured
...
asyncssh tried ~/.ssh/* keys before the password, causing PermissionDenied
on hosts that only accept password auth. Now when 'password' is set and no
'client_keys', key auth is disabled entirely.
Eugene Sukhodolskiy
committed
on 8 Apr
|
Fix system prompts: explicitly instruct model to use ssh_exec tool
...
Without explicit mention in the prompt the model assumed it had to
establish SSH connections itself and refused. Now each tool is listed
with a direct instruction to use it without hesitation.
Eugene Sukhodolskiy
committed
on 8 Apr
|
Filesystem tool: unrestricted mode by default
...
FS_ALLOWED_PATHS=* (default) allows any path, consistent with terminal.
Path check is now lazy (per-request) instead of module-level,
so config is always fresh after restart.
~ expansion added.
Eugene Sukhodolskiy
committed
on 8 Apr
|
Unrestricted terminal mode and SSH tool
...
- Terminal: TERMINAL_ALLOWED_COMMANDS=* (default) runs via shell,
supports pipes, redirects, subshells; allowlist mode still available
- FS_ALLOWED_PATHS expanded to cover /home /etc /var /opt
- New ssh_exec tool: execute commands on remote hosts via asyncssh,
supports named connections (ssh_hosts.json) and inline user@host
- ssh_hosts.json gitignored, ssh_hosts.json.example added as reference
- ssh_exec added to server_admin and smart_home profiles
Eugene Sukhodolskiy
committed
on 8 Apr
|
Dark theme and session delete
...
- Switch to dark color palette via CSS custom properties
- Delete button appears on hover for each session item
- Deleting active session resets chat to empty state
Eugene Sukhodolskiy
committed
on 8 Apr
|
Add web chat client
...
- Single-page chat UI served as static files from FastAPI
- Sidebar with profile selector, new chat button, session list
- WebSocket streaming: shows tool calls and text deltas in real time
- Typing indicator, streaming cursor, auto-resize textarea
- Session history loads on switch
Eugene Sukhodolskiy
committed
on 8 Apr
|
Initial implementation of the agent system core
...
- FastAPI server with REST API and WebSocket streaming
- Modular LLM backend abstraction (Ollama implemented, OpenAI stub)
- Tool system: web_search (ddgs), filesystem, http_request, code_exec, terminal
- Agent profiles: smart_home, server_admin, secretary
- Tool-calling loop with concurrent tool execution
- In-memory session store with SessionStore ABC for future persistence
- Registry pattern for tools, profiles, and backends
- Orchestrator stub as foundation for multi-agent scenarios
Eugene Sukhodolskiy
committed
on 8 Apr
|
| 2026-04-07 |
|