Skip to content

fix(desktop): guard composer mutations when the composer core isn't bound (#49903) - #51728

Merged
teknium1 merged 1 commit into
mainfrom
fix/desktop-composer-not-available-49903
Jun 24, 2026
Merged

fix(desktop): guard composer mutations when the composer core isn't bound (#49903)#51728
teknium1 merged 1 commit into
mainfrom
fix/desktop-composer-not-available-49903

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

The desktop composer no longer throws Uncaught Error: Composer is not available at startup, and the input stays interactive after upgrading to v0.17.0. Fixes #49903.

Root cause: assistant-ui's composer mutators (setText/send/…) throw Composer is not available when the thread's composer core isn't bound yet (@assistant-ui/core composer-runtime.ts). The read path (useAuiState(s => s.composer.text)) is null-safe, but the writes are not. ChatBar pushes draft text via aui.composer().setText() from mount-time effects (draft restore → loadIntoComposer, clearDraft, external inserts). The v0.17.0 popout refactor (#49488) widened the unbound window by moving the composer out of the contain wrapper into a sibling of the thread, so the throw began surfacing as an uncaught error that wedged the input — emitted twice (initial mount + session-resolve), matching the report's back-to-back errors.

Changes

  • apps/desktop/src/app/chat/composer/index.tsx: add a setComposerText helper that wraps aui.composer().setText() in a try/catch swallowing the unbound-core throw; route all 9 setText call sites through it. The contentEditable DOM + draftRef already hold the text and the draft⇄editor sync re-applies it once the core attaches, so the draft is never lost — only the premature state push is skipped.
  • composer-text-guard.test.tsx: regression test — the guard absorbs the throw at startup (no uncaught error, input usable) and writes through once the core is bound.

Validation

Before After
Startup with unbound composer core uncaught Composer is not available, input dead guard no-ops, input stays usable
Composer core bound setText applied setText applied (unchanged)
  • npm run typecheck (apps/desktop): clean
  • npm run --prefix apps/desktop build: ✓ built
  • vitest run composer-text-guard.test.tsx: 2/2 passed

Infographic

Composer Mutation Guard

…ound

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
@teknium1
teknium1 merged commit 281a439 into main Jun 24, 2026
21 checks passed
@teknium1
teknium1 deleted the fix/desktop-composer-not-available-49903 branch June 24, 2026 06:47
@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) P2 Medium — degraded but workaround exists labels Jun 24, 2026
pai-scaffolde pushed a commit to pai-scaffolde/hermes-agent that referenced this pull request Jun 28, 2026
…ound (NousResearch#51728)

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (NousResearch#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (NousResearch#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…ound (NousResearch#51728)

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (NousResearch#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (NousResearch#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
…ound (NousResearch#51728)

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (NousResearch#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (NousResearch#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
…ound (NousResearch#51728)

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (NousResearch#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (NousResearch#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
…ound (NousResearch#51728)

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (NousResearch#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (NousResearch#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
…ound (NousResearch#51728)

The desktop composer threw an uncaught "Composer is not available" at
startup and the input went unresponsive (NousResearch#49903). assistant-ui's composer
mutators (setText/send/…) throw when the thread's composer core isn't bound
yet; the read path is null-safe but the writes are not. ChatBar pushes draft
text via aui.composer().setText() from mount-time effects (draft restore,
clearDraft, external inserts), and the v0.17.0 popout refactor (NousResearch#49488)
widened the unbound window by moving the composer out of the contain wrapper
into a sibling of the thread — so the throw surfaced as an uncaught error
that wedged the input.

Wrap every composer mutation in a setComposerText helper that swallows the
unbound-core throw. The contentEditable DOM + draftRef already hold the text
and the draft-editor sync re-applies it once the core attaches, so the draft
is never lost — only the premature state push is skipped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(desktop): v0.17.0 throws "Uncaught Error: Composer is not available" — input becomes unresponsive after upgrade

2 participants