Studio: prevent long reasoning from jumping the chat on completion (#7388)
This commit is contained in:
parent
dffea2af27
commit
b9d92c41b3
2 changed files with 28 additions and 1 deletions
|
|
@ -346,6 +346,7 @@ const ReasoningGroupImpl: ReasoningGroupComponent = ({
|
|||
|
||||
const [manualOpen, setManualOpen] = useState(false);
|
||||
const [dismissedWhileStreaming, setDismissedWhileStreaming] = useState(false);
|
||||
const [retainStreamingHeight, setRetainStreamingHeight] = useState(false);
|
||||
const [duration, setDuration] = useState<number>(0);
|
||||
const startTimeRef = useRef<number | null>(null);
|
||||
|
||||
|
|
@ -368,6 +369,17 @@ const ReasoningGroupImpl: ReasoningGroupComponent = ({
|
|||
}
|
||||
}, [isReasoningStreaming]);
|
||||
|
||||
// Keep the streaming height cap until the automatic close finishes. Removing
|
||||
// it on the completion frame expands long reasoning to its full height before
|
||||
// the collapsible can close, which makes the entire chat jump.
|
||||
useEffect(() => {
|
||||
const timeout = window.setTimeout(
|
||||
() => setRetainStreamingHeight(isReasoningStreaming),
|
||||
isReasoningStreaming ? 0 : ANIMATION_DURATION,
|
||||
);
|
||||
return () => window.clearTimeout(timeout);
|
||||
}, [isReasoningStreaming]);
|
||||
|
||||
// Open while streaming (unless dismissed), or once manually opened.
|
||||
const isOpen = (isReasoningStreaming && !dismissedWhileStreaming) || manualOpen;
|
||||
const variant = isOpen ? "outline" : "ghost";
|
||||
|
|
@ -378,6 +390,9 @@ const ReasoningGroupImpl: ReasoningGroupComponent = ({
|
|||
if (isReasoningStreaming) {
|
||||
setDismissedWhileStreaming(!open);
|
||||
} else {
|
||||
if (open) {
|
||||
setRetainStreamingHeight(false);
|
||||
}
|
||||
setManualOpen(open);
|
||||
}
|
||||
},
|
||||
|
|
@ -407,7 +422,9 @@ const ReasoningGroupImpl: ReasoningGroupComponent = ({
|
|||
aria-busy={isReasoningStreaming}
|
||||
streaming={isReasoningStreaming}
|
||||
>
|
||||
<ReasoningText streaming={isReasoningStreaming}>
|
||||
<ReasoningText
|
||||
streaming={isReasoningStreaming || retainStreamingHeight}
|
||||
>
|
||||
{children}
|
||||
</ReasoningText>
|
||||
</ReasoningContent>
|
||||
|
|
|
|||
|
|
@ -75,6 +75,16 @@ def test_response_model_badge_is_user_configurable_and_rendered_once_per_message
|
|||
assert 'className="min-w-0 flex-1"' in reasoning_src
|
||||
|
||||
|
||||
def test_reasoning_keeps_streaming_height_cap_through_automatic_collapse():
|
||||
src = REASONING_TSX.read_text()
|
||||
|
||||
assert "const [retainStreamingHeight, setRetainStreamingHeight]" in src
|
||||
assert "setRetainStreamingHeight(false)" in src
|
||||
assert "setRetainStreamingHeight(isReasoningStreaming)" in src
|
||||
assert "isReasoningStreaming ? 0 : ANIMATION_DURATION" in src
|
||||
assert "streaming={isReasoningStreaming || retainStreamingHeight}" in src
|
||||
|
||||
|
||||
def test_response_details_metadata_is_persisted_without_backend_schema_change():
|
||||
src = ADAPTER_TS.read_text()
|
||||
assert "interface ResponseDetailsMetadata" in src
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue