| 2026-10-10 |

synapse: a reaction continues its conversation, and the request becomes a record
...
Every Synapse event used to open its own service session, so two messages of
one Telegram chat landed in two unrelated chats. The dispatcher now returns a
`session_key` — derived from the payload according to the user's routing
document — and a later event carrying the same key joins the session that
opened it, within `reaction_session_ttl_minutes` of idle time (0 restores the
old always-fresh behaviour). A session that is still running is never joined:
`create_run` overwrites `state.run`, so a second run would orphan the first
one's subscribers — a busy thread gets a fresh session instead. When the
dispatcher names a different profile for the event, the session's profile is
switched through `set_profile`, never through `save()`, which does not rewrite
`name` or `profile_id`: the thread keeps its name and its history.
What the user reads in the transcript is now only the request. The event
record is a system message (`metadata.source == "synapse_event"`) drawn by a
new SynapseEventNotice.vue in the visual language of the recall badge, and the
framing plus the JSON envelope become a hidden user turn written once, on the
first event of a thread — not on every one. The instructions from Settings
reach the model through a new `current_reaction_instructions` ContextVar and
the `[Reaction session]` block of the system prompt, so they appear in no
transcript at all. The stored system record still has to reach the model, so
ContextBuilder's allowlist becomes `_LLM_SYSTEM_SOURCES = {task_note,
synapse_event}`.
The dispatcher gets a document of its own — how to route, rather than what to
do — stored beside the reaction instructions, versioned separately, and edited
in its own field in the settings panel. `synapse_instruction_versions` gains a
`doc` discriminator, so existing rows keep `'reaction'` and their history
verbatim. The new columns are added by `_MIGRATE`, and the index over `doc`
lives there too: `_DDL` runs first, so an index over a column the migration has
not added yet kills the whole batch on an existing database — which is what
the prod database is. A guard test keeps it that way.
Tests: 1776 passed, 1 skipped (backend), 242 passed (webclient, 28 files).
Eugene Sukhodolskiy
committed
14 hours ago
|

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-07 |
webclient: hold the chat at the bottom when a stream ends
...
The list was pinned per streaming delta, but the last things to land arrive
after that final pin: the stats/rating footer, which renders only once
msg.done is set, and the copy buttons attached to code blocks after render.
Nothing re-clamped afterwards — the length watcher never fires (the message
stays in the array) and the landing loop only runs when a session opens — so
the view was left short of the bottom, looking like it had scrolled up.
Re-clamp through the same settle window the landing uses when streaming goes
true -> false, unless the user has scrolled up or a session is loading.
This addresses the late-layout half of the problem; the row is still remounted
when msg.id becomes h_<n>, which is the other source of a jump.
Eugene Sukhodolskiy
committed
3 days ago
|
| 2026-10-06 |
webclient: remove session list dividers, 42px sidebar logo, truncate long file names in preview pill
Eugene Sukhodolskiy
committed
4 days ago
|
webclient: tool-count badge, kit-styled content card, thinking corner gap, chat top gap, drop duplicate reconnect notice
Eugene Sukhodolskiy
committed
4 days ago
|
webclient + navi: session title click-to-rename; empty rename regenerates via LLM
Eugene Sukhodolskiy
committed
4 days ago
|
webclient: polish batch — caps off, kit badge/chip in header+input, search clear closes, mobile full-bleed input, settings centered
...
- chat-header-title and sidebar logo span: remove forced uppercase
- profile badge -> GnBadge (variant per profile: secretary secondary,
server_admin warning, developer info); custom box styles dropped
- pending file pill -> GnChip (icon + removable); image thumb stays
app-owned (no kit image-preview component) but on kit surface look
- sidebar search clear button now also closes the field
- input-row: no yellow focus ring; on mobile full-screen width, no
borders, inner padding carries the breathing room
- sidebar footer: without-hover removed from gear/admin/logout buttons
— kit hover returns
- settings: header and body centered, max-width 1200px
Eugene Sukhodolskiy
committed
4 days ago
|
| 2026-10-05 |
webclient: replace vue-virtual-scroller with plain content-visibility rendering
...
The virtual scroller's measurement states duplicated item views (parked
copies at translateY(-9999) alongside working ones), which made tool/plan/
thinking cards unclickable and the chat flicker. Both chat messages and
the session sidebar are now plain v-for lists; off-screen rows skip
render/paint via content-visibility: auto, keeping long sessions cheap
without the scroller engine. Library removed from dependencies.
Eugene Sukhodolskiy
committed
5 days ago
|
webclient: reconnect banner -> GnAlert (kit warning styling)
Eugene Sukhodolskiy
committed
5 days ago
|
webclient: W4 — chat empty state -> GnEmptyState, card modal -> GnModal
...
- ChatArea: .empty-chat custom icon+text -> GnEmptyState card
(keep .empty-chat wrapper only for centering)
- CardGrid: inline Teleport modal (overlay/close/scroll bespoke chrome
removed) -> GnModal; .card-modal/.card-modal-title class names kept
inside the new DOM (test contract); kit header slot renders the title
- WelcomeScreen: typography aligned to kit (30px h1, 14px base),
profile cards get -radius-md, dead .profile-icon style dropped
- CardGrid test: mount with the kit plugin (GnModal resolves),
two nextTicks for the post-flush open watcher
Verified: vitest 111 passed, build OK, welcome screenshot unchanged
(modal/empty-state visually checked after final build)
Eugene Sukhodolskiy
committed
5 days ago
|
webclient: W3 — migrate settings/sidebar/chip surfaces onto kit components
...
- AppSidebar: hand-styled <select> -> GnSelect (options computed from the
profiles store); the ~60-line bespoke select styling in app.scss is now
three compact overrides collapsing GnSelect's form chrome for the slim
sidebar row
- ApiKeysPanel: bespoke grid-table -> GnTable with cell slots (monospace
key prefix, formatted dates, revoke GnIconButton in actions); loading
state -> GnLoader; no-auth callout -> GnAlert(variant=warning)
- NotificationSettingsPanel: unsupported-browser callout -> GnAlert(info)
- SettingsView: header -> GnPageHeader (compact) with sidebar toggle in
#actions
- ShowTokenModal: token field -> GnInputGroup + GnCopyButton (drops the
bespoke copy/useCopy wiring)
- QueuedMessagesChip: .task-chip div -> GnChip (icon prop)
Verified: vitest 111 passed, build OK, screenshots of / and #settings
Eugene Sukhodolskiy
committed
5 days ago
|

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
|

webclient: Backgrounds tab in artifacts panel + task toasts
...
- new Backgrounds tab: task list (running first, badges, per-tool icons)
with a detail view (status, timestamps, sub-agent tokens, result/progress)
- GET /sessions/{id}/tasks snapshot endpoint: task_update events are not
replayed on reconnect, so the client fetches the task list on session
load/reload; live task_update entries are merged on top (chat.fetchTasks)
- terminal task_update no longer removes the entry — it marks it finished
so the tab shows recent completions; _terminalTaskIds still blocks
resurrection by a late running update
- toasts for background task start / finish (info / success / error) in
the WS dispatch; silent for other sessions and unknown terminal ids
- persistent background-tasks chip removed (replaced by the tab); only
the queued-messages chip stays
- fix invisible status text in terminal detail rows: filled .status-*
backgrounds now scope to .terminal-status-badge only
Eugene Sukhodolskiy
committed
5 days ago
|
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
5 days 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
5 days ago
|
| 2026-09-26 |
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
14 days ago
|
| 2026-05-25 |

Fix 19 issues found in full codebase review
...
Backend:
- Stop session auth bypass: require auth for owned sessions, reject anonymous with 401
- upload_file: stream chunks directly to disk instead of buffering in RAM
- MCP config: validate name against path traversal regex
- auth deps: cleanup stale refresh locks periodically
- auth routes: expire mobile auth states after 10 min to prevent unbounded growth
- compressor: meta-summarize existing summaries before compression; preserve assistant content when tool_calls present; rewrite hard_truncate to keep whole turns
- orchestrator: configurable WS replay buffer size; async cleanup/remove_websocket/clear_busy; fix run_recall ContextVar order to avoid deadlock on _build_agent failure; await cleanup in finally
- agent: persist image_msg in session.messages; remove archived messages from session after archive; remove duplicate StreamStopped yield on tool stop
- websocket: try/except around create_task with cleanup on failure; await remove_websocket
Frontend:
- App.vue: hashchange listener lifecycle in onMounted/onUnmounted
- MessageList.vue: passive scroll, flash timeout cleanup, archive scroll snapshot
- InputBar.vue: 300 ms debounce on draft save to localStorage
- SessionList.vue: remove :key from DynamicScroller to avoid remount jitter
Tests: 422 passed, 1 skipped
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 25 May
|
Add archive message pagination, configurable WS replay buffer
...
Backend:
- Add archive_threshold to Session model and getSession response
- Add next_before_seq to archive endpoint for cursor pagination
- Make WS replay buffer size configurable via WS_REPLAY_BUFFER_SIZE
Webclient:
- Add getArchivedMessages API function
- Add archive pagination state and loadArchivedMessages to chat store
- MessageList: auto-load older messages on scroll-to-top with scroll
position preservation and loading spinner
Docs: update config.md with new env vars
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 25 May
|
| 2026-05-16 |
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
|
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 |
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
|
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
|
| 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-29 |

Stability fixes batch — tech debt review 2026-04-29
...
Critical:
- Concurrent WS run race guard (#1)
- Tool task cancellation on generator teardown (#2)
- StopAsyncIteration kills fallback chain (#3)
- Session loading race with _lastLoadId guard (#4)
- ContentCard .match() crash on non-string result (#5)
- Image data type guard in buildMessageList (#6)
High:
- Cap WS replay buffer at 500 events (#7)
- Deduplicate memory extraction task with asyncio.Lock (#9)
- TTL-based fallback blacklisting (5 min) (#10)
- Subagent tool exception isolation (#11)
- Inline image size/count validation on WS (#12)
- Clean up orphaned file on DB insert failure (#13)
- Deep watch streamingMsg for auto-scroll (#14)
- WS_SCHEME wss:// support for HTTPS (#15)
- Sending guard against duplicate message sends (#16)
- Global unhandledrejection listener in API layer (#17)
Medium:
- Cap planning_logs at 20 entries (#22)
- Store cleanup_loop task reference (#23)
- BaseException → Exception in _run_with_sentinel (#24)
- Propagate SystemExit in agent loop (#25)
- Configurable output_reserve_tokens (#26)
- Always reloadSession on session_sync (#30)
- FIFO queue for confirm dialogs (#31)
- Reset body.overflow on ImageLightbox unmount (#32)
- try/finally in fallback copy (#33)
- _isConnecting guard in WS send() (#34)
Low:
- Lazy-init deps.py singletons (#36)
- Replace __import__ with direct imports (#38)
- Preserve token count 0 in ollama.py (#39)
- Clear orphaned streamingMsg on reconnect reload (#43)
- Escape single quote in UserMessage (#44)
- Polyfill-free findLast replacement (#48)
- Match <table> tags with attributes in markdown (#49)
- Attach copy buttons only when msg.done (#50)
- Fix hasMeta falsy-0 bug (#53)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
on 29 Apr
|
| 2026-04-17 |
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
|