Skip to main content Molecule AI is now Enter OS →
Molecule AI
Blog

Engineering

Four canvas chat improvements: cross-device sync, free multi-send, session reset, and auto-grow

Canvas chat now syncs across devices, supports follow-ups during generation, and surfaces the agent's current operation.

By Molecules AI Engineering 4 min read

Four canvas chat improvements began rolling out in molecule-core PR #2700, with follow-up fixes landing in subsequent PRs. Each one was a standalone request; the initial batch landed together because they touched overlapping files.

Cross-device sync

Before this change, messages you typed in the canvas on one device didn’t appear on another device in the same session. The agent’s replies synced fine (they go through the activity broadcast), but user messages were local-only — they lived in the originating tab’s React state and never traveled.

The fix adds USER_MESSAGE and SESSION_RESET to the platform’s WebSocket event taxonomy. After a user message is durably committed server-side, the backend fans it out to all connected sessions for that workspace. Each device receives the event and appends the message using id-based deduplication — the originating device’s optimistic render collapses the echo (same message ID, same slot), while other devices append a fresh copy. The result: the chat history on every open tab stays in lockstep regardless of which device you typed from.

Free multi-send

Previously, the canvas input was locked while an agent response was in flight. You could see the “thinking” indicator and nothing else; the textarea and send button were both disabled until the reply landed.

This was a conservative UX choice, but it created friction for workflows where you want to refine a request mid-flight, add context while a long-running agent is working, or queue up a follow-up before the first reply arrives.

PR #2700 removed the “sending” guard from the textarea, send button, and attach button UI elements. A follow-up fix (PR #2726) completed the implementation: the original useChatSend.sendMessage still early-returned on || sending and held the re-entrancy guard across the entire agent-reply wait, silently dropping any follow-up message sent before the first reply landed. PR #2726 drops that gate and releases the guard the moment the POST is dispatched rather than waiting for the reply. Both fixes are now merged; follow-up messages no longer block each other.

The hook still tracks in-flight state (so the “thinking” indicator works correctly) and double-fires of the same message are still prevented. File upload stays gated: sequential wire uploads can’t be parallelized safely, so the attach button remains disabled while a file is uploading.

Both the client-side send and the server-side idle watchdog now use a 30-minute ceiling. PR #2727 raised the server watchdog; PR #2731 completed the picture by aligning the canvas-side send timeout in useChatSend.ts to match. The window where the client could time out on a long but still-live agent turn is closed.

New-session soft boundary

“New session” creates a soft boundary in the chat history — a marker that tells the UI where the current session starts — without deleting any messages. Messages before the marker stay in the database and can be recovered; the visible history simply resets to the boundary point.

The backend stores a chat_session_started_at timestamp per workspace. A “New session” action rotates that timestamp to now and broadcasts a SESSION_RESET event to all connected devices, so they clear in lockstep. The history endpoint filters to rows after the marker timestamp, with an optional before_ts cursor still composing correctly for pagination.

The boundary is non-destructive by design: pre-marker rows are preserved, the column is nullable so pre-update workspaces read history unchanged, and the schema migration is idempotent.

Auto-expanding textarea

The input textarea now grows as you type: it resets to zero height on each keystroke, expands to its scrollHeight, and caps at approximately six lines. Text past the cap scrolls within the field. On send, it resets to a single row.

IME-safe Enter / Shift+Enter / paste handling is preserved — the auto-grow logic runs on change, not on keydown, so it doesn’t interfere with composition events or multi-line paste.

Why these four together

The four changes share a common thread: reducing places where the canvas imposes an artificial wait or forces an awkward context switch. Cross-device sync removes the “which tab did I type that in?” problem. Free multi-send removes the “wait, now I can type” moment. New-session gives you a clean slate without losing history. Auto-grow removes the scroll-within-a-tiny-box problem for longer prompts.

None of them are high-drama engineering — the changes are incremental and deliberately conservative (non-destructive session reset, backwards-compatible migration, same guard for same-message double-fires). The value is cumulative: the canvas becomes a place you can stay in, rather than a place you manage around.

For teams building on Molecule AI, these improvements apply to all workspace types — whether your workspace runs Claude Code, Codex, Hermes, or an external runtime. Cross-device sync, session reset, auto-grow, and multi-send (including the follow-up fix) are in the current platform image; no SDK or configuration change is needed.

Sources: molecule-core PR #2700 (feat/2697-canvas-chat-ux), PR #2715 (USER_MESSAGE dedup), PR #2718 (textarea baseline reset), PR #2720 (thinking indicator), PR #2726 (true multi-send), PR #2727 (server-side idle watchdog 30m), PR #2731 (client-side send timeout 30m).