Skip to content

fix: resolve chat UI locking up after AssemblyAI API error - #5

Merged
mo-tunn merged 3 commits into
mo-tunn:mainfrom
melut42:fix/chat-input-unclickable
Apr 21, 2026
Merged

fix: resolve chat UI locking up after AssemblyAI API error#5
mo-tunn merged 3 commits into
mo-tunn:mainfrom
melut42:fix/chat-input-unclickable

Conversation

@melut42

@melut42 melut42 commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Summary

When users encountered an API or connection error (e.g., invalid API Key) while using AssemblyAI, the chat input ("Ask anything...") area would completely lock up and become unclickable/untypable. Two main root causes for this issue were identified and fixed:

  1. Invisible error notifications (Toast and Error Banner) were consuming clicks in the background due to CSS (pointer-events).
  2. The recording (isRecording) and AI processing (isStreaming) states were getting stuck after API or WebSocket errors, permanently disabling the UI buttons.

User-Visible Changes

  • Error notifications (toast/banner) will no longer block clicks to the chat input box underneath them after they fade out.
  • Clicking anywhere in the empty space of the chat area will now automatically focus the chat input box (textarea).
  • The interface will no longer permanently lock up if an invalid API key is entered or the connection drops. Clicking or focusing on the chat input will automatically reset any stuck states.
  • If the AI response gets stuck for 60 seconds, the buttons and interface will be automatically re-enabled.

Technical Details

  • style.css: Added pointer-events: none; to the .toast.hidden and .error-banner.hidden classes.
  • main.js: Added a !resp.ok check to the AssemblyAI token fetch process to throw a proper error instead of HTML during auth failures.
  • ptt.js: Added onerror and onclose handlers to the WebSocket connection to ensure doCleanup and stopPTT are executed on connection drops. Applied state force-reset in the catch block.
  • messaging.js: Fixed a bug where the send button would remain permanently disabled during invalid mode checks. Added a 60-second timeout (safety net) to the sendMessage flow.
  • bootstrap.js: Established a fallback mechanism by listening to the textarea focus event to clear any stuck isStreaming and isRecording states.

Validation Performed

  • Triggered an error by providing an invalid AssemblyAI API key.
  • Verified that the "Ask anything" input box could be clicked and typed into seamlessly after the error notification appeared and faded out.
  • Manually threw an error during the PTT (microphone) process and confirmed the application recovered gracefully.

melut42 and others added 2 commits April 18, 2026 13:52
…uting

- getPanelPosition(): clamp saved panel coords against the display they
  belong to instead of always clamping to primary workArea; falls back to
  primary only when no display contains the saved position (e.g. monitor
  was disconnected)

- createWidgetWindow(): spawn widget on the display where the mouse cursor
  is at launch time instead of always using primary display

- positionWidgetBottomRight(): resolve the display the widget is currently
  on via getDisplayNearestPoint() so bottom-right anchor is relative to
  the correct monitor

- set-widget-height IPC handler: clamp widget height against the workArea
  of the display the widget occupies, not the primary display

- DEFAULT_SYSTEM_PROMPT: add MULTI-SCREEN RULE instructing the AI to
  append :screenN to POINT tags when multiple screenshots are present,
  ensuring resolveTargetDisplay() selects the correct display instead of
  falling back to primary every time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@mo-tunn mo-tunn left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix attempt and the detailed write-up. I found a few issues that should be addressed before merge:

  1. State-reset race condition on textarea focus (high impact)
    renderer/js/panel/bootstrap.js resets isStreaming to false on textInput focus without aborting the in-flight request. This can re-enable UI while a response is still streaming, allowing overlapping requests and inconsistent UI/session state.

  2. 60s timeout forces idle state without cancelling the backend stream (medium impact)
    renderer/js/panel/messaging.js safety timeout also flips UI to idle and re-enables send, but does not abort the active request. A legitimate slow response can still be in progress while user sends another message.

  3. Multi-monitor position logic still rejects valid negative coordinates (medium impact)
    main.js:getPanelPosition() treats saved coordinates < 0 as invalid and falls back to primary display defaults. This breaks common multi-monitor layouts where displays on the left/top have negative coordinates.

Please fix these and I’ll re-review.

@mo-tunn mo-tunn added the bug Something isn't working label Apr 19, 2026
- Fix focus race condition by aborting backend stream via api.invoke on text input focus.

- Abort active AI request via api.invoke when 60-second safety timeout triggers.

- Allow negative coordinates in getPanelPosition for complete multi-monitor support.
@melut42

melut42 commented Apr 20, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all requested changes:

Fixed textarea focus race condition by aborting in-flight requests before resetting UI state

Fixed 60-second timeout to abort active backend streams before re-enabling input

Fixed multi-monitor positioning by allowing valid negative coordinates instead of treating them as invalid

Ready for re-review.

@melut42
melut42 requested a review from mo-tunn April 20, 2026 11:56
@mo-tunn
mo-tunn merged commit 13cfe0d into mo-tunn:main Apr 21, 2026
4 checks passed
@melut42
melut42 deleted the fix/chat-input-unclickable branch April 21, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants