refactor(chat): clean up the deployed chat surface - #6220
Conversation
Eight-angle cleanup pass over the full contents of the chat surface and the speech code that survived the voice-mode removal. Dead code - enforceChatRateLimit: added for the TTS relay in #6212, orphaned when #6215 deleted that route. Zero consumers. - ChatToolCallStatus, ChatErrorType, and six unused CHAT_ERROR_MESSAGES keys (only GENERIC_ERROR and CHAT_UNAVAILABLE are read). - scrollToMessage was declared and destructured by ChatMessageContainer but never used in its body; removing the prop also made the scrollToShowOnlyMessage branch unreachable, since the sole caller passed true. - permissionState and the language prop on useSpeechToText: both write-only across the repo. - The image branch in ChatFileDownload's renderIcon returned the same DefaultFileIcon at the same size as the fallback. - chatKeys.status/detail: aliases of deploymentKeys nothing imported, and misleading since they root under a different key namespace. Redundant state - password-auth and email-auth each kept a boolean in lockstep with `errors.length > 0`; email-auth also validated on every keystroke and then immediately hid the result. - file-download tracked hover in state to drive one opacity class; now group-hover. Verified emcn Button sets no `group` class of its own. Memoization - ChatMessageContainer's memo() could never bail: chat.tsx passes an inline arrow for scrollToBottom and displayMessages is a fresh array. Four of the five things that re-render ChatClient are its props anyway, so the memo is dropped rather than propped up. - ClientChatMessage keeps its memo — it blocks markdown re-parsing — but loses the custom comparator, which compared proxies (a key:status fingerprint, files by length) and ignored attachments and type entirely. Default shallow compare on its single prop is both simpler and stricter. - Six useCallbacks whose consumers are native DOM handlers or inline arrows, so nothing observed their identity. Effects - The scroll listener attached in an effect keyed on [chatConfig, authRequired] — values it never reads, standing in for "the container has mounted". It now attaches via a ref callback, so it no longer re-attaches on every config refetch. Design system and a11y - z-[100] -> z-[var(--z-dropdown)] (same value), shadow-lg -> shadow-medium, list styles from inline style to Tailwind classes, hover: -> hover-hover: on touch-reachable targets, Check sourced from emcn alongside its Duplicate pair. - Accessible names on the remove-attachment, stop, and send buttons, which announced only as "button". - Dropped a keyboard handler on a role='group' div with no tabIndex, where target === currentTarget was unreachable, and the Tooltip Provider wrappers and delayDuration, which emcn documents as no-op passthroughs.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Scroll and layout ( Components — Removes Design / a11y — Dead code — Removes Speech — Reviewed by Cursor Bugbot for commit 0f1f509. Configure here. |
Greptile SummaryThis PR simplifies the deployed chat surface without intending broader behavioral changes.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported Markdown list-marker regression is corrected by effective Tailwind list utilities.
|
| Filename | Overview |
|---|---|
| apps/sim/app/(interfaces)/chat/components/message/components/markdown-renderer.tsx | Replaces inline list styles with equivalent Tailwind utilities; the previously reported missing-marker regression is fixed. |
| apps/sim/app/(interfaces)/chat/[identifier]/chat.tsx | Refactors scroll-listener attachment to a callback ref and simplifies scrolling callbacks. |
| apps/sim/app/(interfaces)/chat/components/input/input.tsx | Removes redundant wrappers and callback memoization while adding accessible labels to icon-only controls. |
| apps/sim/app/(interfaces)/chat/components/message/message.tsx | Simplifies message memoization and adopts the shared keyboard-activation helper. |
| apps/sim/hooks/use-speech-to-text.ts | Removes unused speech-to-text state and parameters without changing the retained transcription flow. |
Reviews (2): Last reviewed commit: "fix(chat): restore markdown list markers" | Re-trigger Greptile
The design-system pass swapped inline `listStyleType` for Tailwind classes, but the edit that added `list-disc`/`list-decimal` silently did not apply while the one removing the inline style did. With Preflight setting `list-style: none`, every bullet and number in an assistant response disappeared. `list-item` on the `li` sets display only, not the marker type.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0f1f509. Configure here.
Summary
Eight-angle cleanup pass (effects, state, memo, callback, React Query, url-state, emcn, comments) run over the full contents of the deployed chat surface and the speech code that survived the voice-mode removal — not just a diff.
Dead code
enforceChatRateLimit— added for the TTS relay in fix(security): meter and throttle the deployed-chat TTS relay #6212, orphaned when chore(chat): remove deployed-chat voice mode #6215 deleted that route. Zero consumers.ChatToolCallStatus,ChatErrorType, and six unusedCHAT_ERROR_MESSAGESkeys (onlyGENERIC_ERRORandCHAT_UNAVAILABLEare read).scrollToMessagewas declared and destructured byChatMessageContainerbut never used in its body. Removing the prop also made thescrollToShowOnlyMessagebranch unreachable, since the one caller passedtrue.permissionStateand thelanguageprop onuseSpeechToText— both write-only across the repo.ChatFileDownload'srenderIconreturned the sameDefaultFileIconat the same size as the fallback.chatKeys.status/detail— aliases nothing imported, and misleading since they root under['deployments', …]rather thanchatKeys.all.Redundant state
password-authandemail-autheach kept a boolean in lockstep witherrors.length > 0;email-authalso validated on every keystroke and then immediately hid the result.file-downloadtracked hover in state to drive one opacity class →group-hover. Verified emcnButtonsets nogroupclass of its own.Memoization
ChatMessageContainer'smemo()could never bail:chat.tsxpasses an inline arrow forscrollToBottomanddisplayMessagesis a fresh array. Four of the five things that re-renderChatClientare its props anyway, so the memo is dropped rather than propped up.ClientChatMessagekeeps its memo — it blocks markdown re-parsing during streaming — but loses the custom comparator, which compared proxies (akey:statusfingerprint,filesby length) and ignoredattachmentsandtypeentirely. Default shallow compare on its single prop is simpler and stricter.useCallbacks whose consumers are native DOM handlers or inline arrows.Effects
[chatConfig, authRequired]— values it never reads, standing in for "the container has mounted". Now a ref callback, so it no longer re-attaches on every config refetch.Design system / a11y
z-[100]→z-[var(--z-dropdown)](identical value),shadow-lg→shadow-medium, inline list styles → Tailwind,hover:→hover-hover:on touch-reachable targets,Checksourced from emcn alongside itsDuplicatepair.role='group'div with notabIndex(sotarget === currentTargetwas unreachable), plus theTooltip.Providerwrappers anddelayDuration, which emcn documents as no-op passthroughs.Needs a visual check
The scroll-listener change is the one behavioral risk. Please verify on a deployed chat: scroll up mid-conversation → jump-to-bottom button appears; click it → re-pins and hides; stream a reply while scrolled away → does not auto-follow.
shadow-lg→shadow-mediumis a small deliberate shadow change on the jump-to-bottom pill.Deliberately not included
useSpeechToTextfetching server state in an effect intouseState— should become auseQuery, but its only consumer is the workspace home input, and the render path is hydration-sensitive. Wants its own PR.useUpdateChatdoesn't invalidatedeploymentKeys.info/versions/deployedState, though the PATCH can trigger a redeploy (api/chat/manage/[id]/route.tscallsperformFullDeploy).useCreateChatinvalidates for exactly this reason. Left out because it changes deployment-panel behavior I can't verify here — worth its own PR.border-purple-500drag state,text-purple-500audio icon, off-scaletext-sm/text-lg, the stop glyph → emcnSquare, and consolidating the two chat auth screens onto the shared(auth)/componentskit (which would shrink headings 40px → 32px).Type of Change
Testing
1153 tests pass across chat, speech, settings, hooks and rate-limiter. Typecheck clean on
apps/sim. Lint warnings in scope unchanged from staging's baseline (2). No behavior change intended except the two items called out above.Checklist