Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(site): move pinned indicator to LiveStreamTailContent level
The indicator lived inside PinnedStreamingContent which only
handles the live stream. When content got committed to the
conversation timeline during a long turn, the streaming output
would shrink or unmount, and the indicator vanished.

Move the indicator to LiveStreamTailContent, which renders at
the bottom of the chat after all historical messages. It now
persists for the entire active turn regardless of how many
messages get committed during that turn. The StreamingOutput
still shows the capped activity area with fade, but the
indicator itself is one level up.
  • Loading branch information
tracyjohnsonux committed May 12, 2026
commit 7b8f2901f2072ef3c17f72f672428b8390b13d17
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useQuery } from "react-query";
import { Link } from "react-router";
import type { UrlTransform } from "streamdown";
import { preferenceSettings } from "#/api/queries/users";
import type * as TypesGen from "#/api/typesGenerated";
import { Alert, AlertDescription } from "#/components/Alert/Alert";
import { Button } from "#/components/Button/Button";
Expand All @@ -17,7 +19,7 @@ import {
type useChatStore,
} from "./chatStore";
import { deriveLiveStatus, type LiveStatusModel } from "./liveStatusModel";
import { StreamingOutput } from "./StreamingOutput";
import { PinnedThinkingIndicator, StreamingOutput } from "./StreamingOutput";
import { buildStreamTools } from "./streamState";
import type { MergedTool, StreamState } from "./types";

Expand Down Expand Up @@ -55,17 +57,28 @@ export const LiveStreamTailContent = ({
urlTransform,
mcpServers,
}: LiveStreamTailContentProps) => {
const prefQuery = useQuery(preferenceSettings());
const thinkingDisplayMode = prefQuery.data?.thinking_display_mode || "auto";
const shouldRenderStreamSection = shouldRenderStreamingSection(liveStatus);
const terminalStatus = liveStatus.phase === "failed" ? liveStatus : null;
const usageLimitStatus =
terminalStatus?.kind === "usage_limit" ? terminalStatus : null;
const shouldRenderEmptyState =
isTranscriptEmpty && liveStatus.phase === "idle";

// In pinned mode, the indicator shows for the entire active
// turn at this level so it persists even when streaming
// content gets committed to the conversation timeline.
const isPinnedActive =
thinkingDisplayMode === "pinned" &&
liveStatus.phase !== "idle" &&
liveStatus.phase !== "failed";

if (
!shouldRenderEmptyState &&
!shouldRenderStreamSection &&
!terminalStatus
!terminalStatus &&
!isPinnedActive
) {
return null;
}
Expand Down Expand Up @@ -104,6 +117,7 @@ export const LiveStreamTailContent = ({
) : terminalStatus ? (
<ChatStatusCallout status={terminalStatus} />
) : null}
{isPinnedActive && <PinnedThinkingIndicator />}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,8 @@ const PINNED_FADE_MASK = {
* Pinned thinking indicator shown at the bottom of the streaming
* output. Stays fixed while activity streams above it.
*/
const PinnedThinkingIndicator: FC<{ fading?: boolean }> = ({
fading = false,
}) => (
<div
className="flex w-full items-center gap-2 border-t border-border/50 pt-2 text-content-secondary transition-opacity duration-300"
style={{ opacity: fading ? 0 : 1 }}
>
export const PinnedThinkingIndicator: FC = () => (
<div className="flex w-full items-center gap-2 border-t border-border/50 pt-2 text-content-secondary">
<Shimmer as="span" className="text-[13px] leading-relaxed">
Thinking...
</Shimmer>
Expand Down Expand Up @@ -127,34 +122,27 @@ const PinnedStreamingContent: FC<{

return (
<div className="space-y-3">
{/* Fixed-height box: all content scrolls inside, indicator
anchored at bottom. Height never changes so
"Thinking..." never moves. */}
{isAgentWorking && (
<div className="flex h-48 flex-col">
<div
ref={scrollRef}
className="min-h-0 flex-1 overflow-y-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
style={PINNED_FADE_MASK}
>
{visibleBlocks.length > 0 && (
<div className="space-y-3">
<BlockList
blocks={visibleBlocks}
tools={streamTools}
keyPrefix="stream"
isStreaming={isStreaming}
subagentTitles={subagentTitles}
subagentVariants={subagentVariants}
subagentStatusOverrides={subagentStatusOverrides}
urlTransform={urlTransform}
mcpServers={mcpServers}
/>
</div>
)}
</div>
<div className="shrink-0">
<PinnedThinkingIndicator />
{/* Capped scroll area: streaming content scrolls here.
The pinned indicator lives in LiveStreamTailContent
so it persists across message commits. */}
{isAgentWorking && visibleBlocks.length > 0 && (
<div
ref={scrollRef}
className="max-h-48 overflow-y-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
style={PINNED_FADE_MASK}
>
<div className="space-y-3">
<BlockList
blocks={visibleBlocks}
tools={streamTools}
keyPrefix="stream"
isStreaming={isStreaming}
subagentTitles={subagentTitles}
subagentVariants={subagentVariants}
subagentStatusOverrides={subagentStatusOverrides}
urlTransform={urlTransform}
mcpServers={mcpServers}
/>
</div>
</div>
)}
Expand Down
Loading