-
Notifications
You must be signed in to change notification settings - Fork 77
fix(web): apply PR #32009 review feedback #32010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -248,6 +248,11 @@ export function ChatPage() { | |
| const inputRef = useRef<HTMLTextAreaElement | null>(null); | ||
| const messagesRef = useRef<DisplayMessage[]>(messages); | ||
| messagesRef.current = messages; | ||
| // Populated by `chat-route-content.tsx` right after the render-boundary | ||
| // `useMemo(() => sanitizeDisplayMessages(messages))`. Owned here so | ||
| // `useChatDebugApi` (mounted in this component) can read the same array | ||
| // the UI is rendering without re-running the pipeline. | ||
|
Comment on lines
+251
to
+254
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete |
||
| const sanitizedMessagesRef = useRef<DisplayMessage[]>([]); | ||
| // Owned here so `useChatDebugApi` (also called from this component) can | ||
| // read scroll geometry directly via `transcriptRef.current.getScrollElement()`. | ||
| // Threaded down to ChatRouteContent through the `refs` prop and bound on | ||
|
|
@@ -891,6 +896,7 @@ export function ChatPage() { | |
| // by which point initialization is complete. | ||
| useChatDebugApi({ | ||
| messagesRef, | ||
| sanitizedMessagesRef, | ||
| transcriptRef, | ||
| streamContextRef, | ||
| streamRef, | ||
|
|
@@ -1559,6 +1565,7 @@ export function ChatPage() { | |
| refs: { | ||
| inputRef, | ||
| messagesRef, | ||
| sanitizedMessagesRef, | ||
| activeConversationIdRef, | ||
| assistantIdRef, | ||
| streamContextRef, | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -218,6 +218,13 @@ export interface AvatarData { | |||||||
| export interface ChatRouteRefs { | ||||||||
| inputRef: RefObject<HTMLTextAreaElement | null>; | ||||||||
| messagesRef: MutableRefObject<DisplayMessage[]>; | ||||||||
| /** | ||||||||
| * Mirror of the post-`sanitizeDisplayMessages` array, populated below right | ||||||||
| * after the render-boundary `useMemo`. Read by `useChatDebugApi`'s `tail()` | ||||||||
| * so DevTools sees exactly what the transcript renders without re-running | ||||||||
| * the sanitize pipeline. | ||||||||
| */ | ||||||||
|
Comment on lines
+221
to
+226
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Delete |
||||||||
| sanitizedMessagesRef: MutableRefObject<DisplayMessage[]>; | ||||||||
| activeConversationIdRef: MutableRefObject<string | null>; | ||||||||
| assistantIdRef: MutableRefObject<string | null>; | ||||||||
| streamContextRef: MutableRefObject<StreamContext | null>; | ||||||||
|
|
@@ -503,6 +510,7 @@ export function ChatRouteContent({ | |||||||
| const { | ||||||||
| inputRef, | ||||||||
| messagesRef, | ||||||||
| sanitizedMessagesRef, | ||||||||
| activeConversationIdRef: _activeConversationIdRef, | ||||||||
| assistantIdRef: _assistantIdRef, | ||||||||
| streamContextRef, | ||||||||
|
|
@@ -780,15 +788,19 @@ export function ChatRouteContent({ | |||||||
| // transcript renders (timestamp sort, blank/phantom row filter, duplicate | ||||||||
| // trailing assistant drop). See `sanitize-display-messages.ts` for the | ||||||||
| // rationale and removal triggers for each sub-step. | ||||||||
| const sortedMessages = useMemo( | ||||||||
| const sanitizedMessages = useMemo( | ||||||||
| () => sanitizeDisplayMessages(messages), | ||||||||
| [messages], | ||||||||
| ); | ||||||||
|
|
||||||||
| // Mirror into a ref so `useChatDebugApi`'s `tail()` can read what the | ||||||||
| // UI is actually rendering without re-running the pipeline. | ||||||||
|
Comment on lines
795
to
+797
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| sanitizedMessagesRef.current = sanitizedMessages; | ||||||||
|
|
||||||||
| const transcriptItems = useMemo( | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. introduce another ref to track transcript items |
||||||||
| () => | ||||||||
| buildTranscriptItems({ | ||||||||
| messages: sortedMessages, | ||||||||
| messages: sanitizedMessages, | ||||||||
| pendingSecret: pendingSecret | ||||||||
| ? { requestId: pendingSecret.requestId } | ||||||||
| : null, | ||||||||
|
|
@@ -812,7 +824,7 @@ export function ChatRouteContent({ | |||||||
| showOnboardingChoice, | ||||||||
| }), | ||||||||
| [ | ||||||||
| sortedMessages, | ||||||||
| sanitizedMessages, | ||||||||
| pendingSecret, | ||||||||
| pendingConfirmation, | ||||||||
| inlineConfirmationAttached, | ||||||||
|
|
@@ -1325,7 +1337,7 @@ export function ChatRouteContent({ | |||||||
| <SlackChannelFooter | ||||||||
| assistantId={assistantId ?? undefined} | ||||||||
| conversation={activeConversation} | ||||||||
| messages={sortedMessages} | ||||||||
| messages={sanitizedMessages} | ||||||||
| /> | ||||||||
| ); | ||||||||
|
|
||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| // ----------------------------------------------------------------------------- | ||
| // sanitizeDisplayMessages — single home for "this shouldn't be necessary, | ||
| // but is" frontend cleanup applied to DisplayMessage[] before the transcript | ||
| // renders (and before `window._vellumDebug.chat.tail()` returns). | ||
| // renders. | ||
| // | ||
| // Every sub-method below patches over an upstream issue. They are SHORT TERM | ||
| // and should be removed as the assistant backend stabilises the corresponding | ||
|
|
@@ -13,25 +13,15 @@ | |
| import { sortedByTimestamp } from "@/domains/chat/utils/message-sorting.js"; | ||
| import type { DisplayMessage } from "@/domains/chat/types/types.js"; | ||
|
|
||
| /** | ||
| * Apply every render-boundary hack to `messages` in a fixed order and return | ||
| * a new array (never mutates the input). | ||
| * | ||
| * Pipeline: | ||
| * 1. `sortByTimestamp` (Hack #1) | ||
| * 2. `removeInvalidMessages` (Hack #2) | ||
| * 3. `removeDuplicateTrailingAssistant` (Hack #3) | ||
| * | ||
| * Each step is independent — removing any one when the corresponding upstream | ||
| * bug is fixed is a one-line edit. | ||
| */ | ||
| export function sanitizeDisplayMessages( | ||
| messages: DisplayMessage[], | ||
| ): DisplayMessage[] { | ||
| let result = sortByTimestamp(messages); | ||
| result = removeInvalidMessages(result); | ||
| result = removeDuplicateTrailingAssistant(result); | ||
| return result; | ||
| const pipeline = [ | ||
| sortedByTimestamp, | ||
| removeInvalidMessages, | ||
| removeDuplicateTrailingAssistant, | ||
| ]; | ||
| return pipeline.reduce((msgs, step) => step(msgs), messages); | ||
| } | ||
|
|
||
| // ----------------------------------------------------------------------------- | ||
|
|
@@ -53,9 +43,7 @@ export function sanitizeDisplayMessages( | |
| // SHORT TERM until: the assistant backend merges multi-row clusters | ||
| // server-side so the client never sees the fragmented rows. | ||
| // ----------------------------------------------------------------------------- | ||
| function sortByTimestamp(messages: DisplayMessage[]): DisplayMessage[] { | ||
| return sortedByTimestamp(messages); | ||
| } | ||
| // (Implementation: `sortedByTimestamp`, imported at the top.) | ||
|
Comment on lines
-56
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok we are using this in reconcileMessages, which we plan to cleanup, simplify, and remove in another convo. for now, let's add back the wrapper method we had here until we are ready to delete reconcileMessages |
||
|
|
||
| // ----------------------------------------------------------------------------- | ||
| // Hack #2 — drop blank / phantom user rows | ||
|
|
@@ -66,12 +54,12 @@ function sortByTimestamp(messages: DisplayMessage[]): DisplayMessage[] { | |
| // user rows even when their parent `tool_use` lives on a previous page | ||
| // (to avoid permanent data loss). The daemon's renderer then drops the | ||
| // orphan `tool_result` block, leaving a blank user bubble on the wire. | ||
| // - The daemon synthesises tool calls with `toolName === "unknown"` when a | ||
| // - The assistant synthesises tool calls with `toolName === "unknown"` when a | ||
| // `tool_result` has no matching `tool_use`. Those arrive as empty user | ||
| // messages whose only payload is a list of "unknown" tools and would | ||
| // otherwise render as a confusing "Used unknown" chip (ATL-659). | ||
| // otherwise render as a confusing "Used unknown" chip. | ||
| // | ||
| // SHORT TERM until: the daemon stops emitting orphan `tool_result` rows and | ||
| // SHORT TERM until: the assistant stops emitting orphan `tool_result` rows and | ||
| // phantom unknown-tool placeholders at history boundaries. | ||
| // ----------------------------------------------------------------------------- | ||
| function removeInvalidMessages(messages: DisplayMessage[]): DisplayMessage[] { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this ref anymore?