| 2026-10-10 |

webclient: the chat area in en, uk and ru
...
The fifth area of the interface translation. The chat screen now builds its
text through t(): the header (the rename tooltip, the sidebar toggle, the
artifacts toggle, and the recall banner with its Cancel and Skip next
buttons), the list around it (the connection-lost banner and its Retry, and —
unreachable for now — the empty state), the input bar (the sending notice, the
paperclip, the placeholder, Send and Stop generation), the attachment strip
(its alt text and its remove button), the message list (Loading older
messages… and the scroll-to-bottom tooltip) and the queued-messages chip. Also
four toasts the WebSocket composable raises — background task started /
finished, MCP server connected / disconnected — and the compression notice's
own pending text.
26 new slugs in all three dictionaries:
- 20 in chat.* — the header and recall banner, the input bar, the attachment
strip, the queued chip and the empty state;
- 4 in toast.* — the two background-task and the two MCP toasts;
- 2 in common.* — task and toolsCount.
Four details worth knowing:
- The recall banner used to read the server's call_type enum out loud
("Scheduled once recall at …"). The word is now a slug
(chat.recallOnce / chat.recallRecurring / chat.recallImmediate), so it agrees
with the sentence around it — Russian and Ukrainian both change the
adjective's gender and the preposition, which a bare enum cannot.
- The banner's time was formatted with the browser's locale; it now formats
against locale.value, so the date follows the interface language rather than
the machine.
- The queued chip counted with `count === 1 ? '' : 's'`. It is now a dictionary
plural driven by {n}, which is what Russian and Ukrainian need — "1
сообщение", "2 сообщения", "5 сообщений".
- toolsCount moved from messages.* to common.*: the tool-count badge in the
assistant message and the MCP-connected toast both render it, so the same
word lives in the vocabulary area instead of twice under two areas.
docs/i18n.md records the move.
The English values are verbatim the literals the code hard-coded, so the
English interface is unchanged and no test needed editing.
Checked live in Chromium against the built bundle on the dev backend, all
three languages: the header title, the input placeholder, both input-row
buttons, the recall banner and its buttons, twelve message rows and the
attachment's alt and remove — read fresh for each language by picking it in
Settings first — with a scan of the page's text, titles, aria-labels, alt texts
and placeholders for a slug that leaked into the interface as the pass
condition.
Two states a saved session cannot be put into are covered by a throwaway mount
instead, and the file was removed again: the streaming input bar (Sending…,
Stop generation) and the queued chip, plus the recall words and the toast
titles, printed in Russian — "1 сообщение в очереди" / "2 сообщения" /
"5 сообщений".
The connection-lost banner never appears in this harness: with no socket token
the server refuses the socket and the client never exhausts its retries inside
the test's window, on the current build and on HEAD's alike. It is covered by
the existing tests/unit/composables/useWebSocket.test.js and by reading
ChatArea.vue; the same goes for chat.nothingOpen / chat.startConversation,
which App.vue's WelcomeScreen shadows before ChatArea can render its own empty
state — the branch is dead today and keeps its slugs for when it is not.
Eugene Sukhodolskiy
committed
1 day ago
|
| 2026-10-06 |
webclient + navi: session title click-to-rename; empty rename regenerates via LLM
Eugene Sukhodolskiy
committed
4 days ago
|
| 2026-10-05 |

webclient: retokenize styles onto gn-ui-kit v1.0 CSS variables
...
All ~165 legacy var() usages (--color-*, --surface*, --accent*, --border,
--text*) with hex fallbacks and ~150 raw hex literals across app.scss and
24 scoped style blocks are swapped to the kit's --gn-* tokens per the
intent of the old fallback values:
- accent/primary/teal (#7aa2f7/#4ec9b0) -> --gn-color-secondary
- amber/orange highlights -> --gn-color-accent
- text greys -> --gn-color-text-{light,medium,dark}
- panels -> --gn-surface-panel; elevated tints -> color-mix over panel
- translucent overlays -> color-mix(in srgb, ..., transparent)
Deliberately literal: terminal deep bg #0f0f14 (darker than any token)
and the content-card image badge teal #89dceb (kit has no teal). File
type badges keep a categorical palette via nearest kit tokens.
Dead "UI kit overrides" block halved: kit 1.0 dropped hover icon
rotation, so only the app-owned chevron open-state flip remains.
Verified: vitest 111 passed, build OK, dev render matches W1 baseline
Eugene Sukhodolskiy
committed
5 days ago
|
| 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
|
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-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-12 |
Fix Phosphor icon class on GnButton/GnIconButton usages.
...
gnexus-ui-kit's iconNode() does not prepend the base `ph` class
when the icon string starts with `ph-`; it only keeps the string
as-is. All icon props must include the base class explicitly:
`icon="ph ph-sidebar"` instead of `icon="ph-sidebar"`.
Updated 15 icon bindings across 9 components.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 12 May
|
Wire gnexus-ui-kit v0.2.0 Vue 3 adapter and migrate Wave 1 components.
...
- Update vendor/gnexus-ui-kit to v0.2.0 (Vue components + composables)
- Add Vite aliases for gnexus-ui-kit/vue and gnexus-ui-kit/css
- Install GnexusUiVue plugin in main.js + GnToastProvider in App.vue
- Migrate ProfileBadge → GnBadge
- Migrate ErrorMessage → GnAlert
- Migrate ConfirmDialog → GnConfirmDialog
- Migrate raw <button> elements → GnButton / GnIconButton in:
WelcomeScreen, LoginScreen, ChatArea, ChatHeader, AppSidebar,
ArtifactsPanel, UserMessage, AssistantMessage, SelectionToolbar
Build and tests pass (51/51).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 12 May
|
| 2026-04-30 |
Improve content publishing UX
Eugene Sukhodolskiy
committed
on 30 Apr
|
| 2026-04-16 |
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
|