Skip to content

Commit 76d89f5

Browse files
authored
fix(site): add bottom spacing for sources-only assistant messages (#24202)
Closes CODAGT-123 Assistant messages containing only source parts (no markdown or reasoning) were missing the bottom spacer that normally fills the gap left by the hidden action bar, causing them to sit flush against the next user bubble. The existing fallback spacer guarded on `Boolean(parsed.reasoning)`, so it only fired for thinking-only replies. Replace that guard with the broader `hasRenderableContent` flag (which covers blocks, tools, and sources) and extract a named `needsAssistantBottomSpacer` boolean so future content types inherit consistent spacing without re-reading compound conditions. Adds a `SourcesOnlyAssistantSpacing` Storybook story mirroring the existing `ThinkingOnlyAssistantSpacing` pattern for regression coverage.
1 parent 1a3a92b commit 76d89f5

2 files changed

Lines changed: 64 additions & 6 deletions

File tree

site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.stories.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,3 +939,59 @@ export const ThinkingOnlyAssistantSpacing: Story = {
939939
expect(canvas.getByText("Any progress?")).toBeInTheDocument();
940940
},
941941
};
942+
943+
/**
944+
* Regression: sources-only assistant messages must have consistent
945+
* bottom spacing before the next user bubble. A spacer div fills the
946+
* gap that would normally come from the hidden action bar.
947+
*/
948+
export const SourcesOnlyAssistantSpacing: Story = {
949+
args: {
950+
...defaultArgs,
951+
parsedMessages: buildMessages([
952+
{
953+
...baseMessage,
954+
id: 1,
955+
role: "user",
956+
content: [{ type: "text", text: "Can you share your sources?" }],
957+
},
958+
{
959+
...baseMessage,
960+
id: 2,
961+
role: "assistant",
962+
content: [
963+
{
964+
type: "source",
965+
url: "https://example.com/docs",
966+
title: "Documentation",
967+
},
968+
{
969+
type: "source",
970+
url: "https://example.com/api",
971+
title: "API Reference",
972+
},
973+
],
974+
},
975+
{
976+
...baseMessage,
977+
id: 3,
978+
role: "user",
979+
content: [{ type: "text", text: "Thanks!" }],
980+
},
981+
]),
982+
},
983+
play: async ({ canvasElement }) => {
984+
const canvas = within(canvasElement);
985+
expect(canvas.getByText("Can you share your sources?")).toBeInTheDocument();
986+
expect(canvas.getByText("Thanks!")).toBeInTheDocument();
987+
await userEvent.click(
988+
canvas.getByRole("button", { name: /searched 2 results/i }),
989+
);
990+
expect(
991+
canvas.getByRole("link", { name: "Documentation" }),
992+
).toBeInTheDocument();
993+
expect(
994+
canvas.getByRole("link", { name: "API Reference" }),
995+
).toBeInTheDocument();
996+
},
997+
};

site/src/pages/AgentsPage/components/ChatConversation/ConversationTimeline.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,11 @@ const ChatMessageItem = memo<{
516516
userInlineContent.length > 0 || Boolean(parsed.markdown?.trim());
517517
const hasFileBlocks = userFileBlocks.length > 0;
518518
const hasCopyableContent = Boolean(parsed.markdown.trim());
519+
const needsAssistantBottomSpacer =
520+
!hideActions &&
521+
!isUser &&
522+
!hasCopyableContent &&
523+
(Boolean(parsed.reasoning) || parsed.sources.length > 0);
519524

520525
const conversationItemProps: { role: "user" | "assistant" } = {
521526
role: isUser ? "user" : "assistant",
@@ -670,12 +675,9 @@ const ChatMessageItem = memo<{
670675
</div>
671676
)}
672677
{/* Spacer for assistant messages without an action bar
673-
(e.g. thinking-only) so they have consistent bottom
674-
padding before the next user bubble. */}
675-
{!hideActions &&
676-
!isUser &&
677-
!hasCopyableContent &&
678-
Boolean(parsed.reasoning) && <div className="min-h-6" />}
678+
(e.g. reasoning-only or sources-only) so they have
679+
consistent bottom padding before the next user bubble. */}
680+
{needsAssistantBottomSpacer && <div className="min-h-6" />}
679681
{previewImage && (
680682
<ImageLightbox
681683
src={previewImage}

0 commit comments

Comments
 (0)